blob: 1f23718d00d077ef8f35675a9555fd730b455f6b [file] [log] [blame]
#!/bin/bash
# Copyright 2012 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
set -e
# Most projects seem to prefer having unlimited core dump.
# To disable this, override factory_setup in `board_setup_factory.sh`.
ulimit -c unlimited || true
. /usr/local/factory/sh/common.sh
FACTORY="$(dirname "$(dirname "$(readlink -f "$0")")")"
FACTORY_LOG_FILE=/var/factory/log/factory.log
SESSION_LOG_FILE=/var/log/factory-session.log
INTERACTIVE_CONSOLES=""
LOG_PROCESSES=""
BOARD_SETUP="${FACTORY}/board/board_setup_factory.sh"
# Put '/usr/local/factory/bin' at the head of PATH so that Goofy doesn't need to
# specify full path name when running factory binaries.
export PATH="/usr/local/factory/bin:${PATH}"
# Default args for Goofy.
GOOFY_ARGS=""
# Default implementation for factory_setup (no-op). May be overriden
# by board_setup_factory.sh.
factory_setup() {
true
}
# Clean up when error happens.
on_error() {
local pid
# Try to show console because stopping UI may take a while.
show_interactive_console
for pid in ${LOG_PROCESSES}; do
kill -9 "${pid}" &
done
# Show console again because stopping UI may change active console.
show_interactive_console
}
# Initialize output system (create logs and redirect output).
init_output() {
echo "Redirecting output to ${SESSION_LOG_FILE}"
exec >"${SESSION_LOG_FILE}" 2>&1
echo "New factory session: $(date +'%Y%m%d %H:%M:%s')"
# When VT is available, TTYs were reserved as:
# 1 - UI (Chrome or X)
# 2 - getty (login)
# 3 - tail -f /var/log/factory.log
# So for Goofy session, we want to print the logs in following order:
# - /dev/tty4 if available (Systems with VT)
# - /dev/console if available
local tty
for tty in /dev/tty4 /dev/console $(tty); do
if [ -c "${tty}" ] && (echo "" >>"${tty}") 2>/dev/null; then
tail -f "${SESSION_LOG_FILE}" >>"${tty}" &
LOG_PROCESSES="${LOG_PROCESSES} $!"
INTERACTIVE_CONSOLES="${INTERACTIVE_CONSOLES} ${tty}"
fi
done
trap on_error EXIT
# This should already exist, but just in case...
mkdir -p "$(dirname "${FACTORY_LOG_FILE}")"
touch "${FACTORY_LOG_FILE}"
# To help reading archived logs (not on DUT), we assume the FACTORY_LOG_FILE
# starts with /var and try to create the symlink as relative path.
ln -sf "../${FACTORY_LOG_FILE#/var/}" /var/log
# Provide the latest factory log on TTY3 if available.
local tty_log=/dev/tty3
if [ -c "${tty_log}" ]; then
setsid sh -c \
"script -afqc 'while true; do less -W +F ${FACTORY_LOG_FILE}; done' \
/dev/null <${tty_log} >${tty_log}" &
fi
}
# Try to show the interactive console if available.
show_interactive_console() {
local tty
local vt_index
for tty in ${INTERACTIVE_CONSOLES}; do
vt_index="${tty#/dev/tty}"
if [ "${vt_index}" = "${tty}" ]; then
continue
fi
if chvt "${vt_index}"; then
return
fi
done
}
# Load board-specific parameters, if any.
load_setup() {
if [ -s "${BOARD_SETUP}" ]; then
echo "Loading board-specific parameters ${BOARD_SETUP}..."
. "${BOARD_SETUP}"
fi
factory_setup
}
# Checks disk usage and abort if running out of disk space.
check_disk_usage() {
# /tmp should be mounted as tmpfs so it should be always available.
local out_dir="$(mktemp -d)"
local df_output="${out_dir}/df"
if "${FACTORY}/bin/disk_space" >"${df_output}"; then
cat "${df_output}"
rm -rf "${out_dir}"
return
fi
# Try to setup a HTTP server for Chrome to display.
local out_file="${out_dir}/index.html"
local template_file="${FACTORY}/misc/no_space.html"
mkdir -p "${out_dir}"
sed -i -e "s/ \[/\\n [/g" "${df_output}"
find /var -size +100M -print0 | xargs -0 du -sh | sort -hr >>"${df_output}"
toybox sed -e "/DISK_USAGE_INFO/r ${df_output}" "${template_file}" \
>"${out_file}"
# This should be the port specified by chrome_dev.conf.
exec busybox httpd -f -p 4012 -h "${out_dir}"
}
# Initialize system TTY.
init_tty() {
# Preventing ttyN (developer shell console) to go blank after some idle time
local tty=""
for tty in /dev/tty[2-4]; do
(setterm -cursor on -blank 0 -powerdown 0 -powersave off
>"${tty}") 2>/dev/null || true
done
}
# Initialize kernel modules and system daemons.
init_modules() {
# We disable powerd in factory image, but this folder is needed for some
# commands like power_supply_info to work.
mkdir -p /var/lib/power_manager
# Preload modules here
modprobe i2c-dev 2>/dev/null || true
}
# Initialize network settings.
init_network() {
# Make sure local loopback device is activated
ifconfig lo up
}
start_system_services() {
# 'system-services' is started by ui.conf -> session_manager -> Chrome ->
# dbus.EmitLoginPromptVisible -> boot-complete -> system-services.
# Since we start Chrome without login manager, the dbus event must be sent
# explicitly. This was done in Goofy by waiting for connection, but we've
# found that on recent systems Chrome may need system services to be ready
# before it can start entering main page, so we want to do this as early as
# possible, immediately after session manager is ready. Unfortunately there is
# no way to find that except directly looking at dbus contents.
echo "[LoginPromptVisible] Start trying to emit dbus event..."
local retries=30
while ! dbus-send --system --dest=org.chromium.SessionManager \
--print-reply /org/chromium/SessionManager \
org.chromium.SessionManagerInterface.EmitLoginPromptVisible; do
if [ "${retries}" -lt 1 ]; then
echo "[LoginPromptVisible] Timed out, trying to run in fail-safe mode..."
initctl emit login-prompt-visible || true
start -n system-services || true
return
fi
retries=$((retries - 1))
sleep 1
done
echo "[LoginPromptVisible] Event sent, system-services should start later."
}
start_factory() {
init_output
echo "
Starting factory program...
If you don't see factory window after more than one minute,
try to switch to VT2 (Ctrl-Alt-F2), log in, and check the messages by:
tail $SESSION_LOG_FILE $FACTORY_LOG_FILE
If it keeps failing, try to reset by:
factory_restart -a
"
load_setup
init_modules
init_tty
init_network
check_disk_usage
if status ui | grep -vq start; then
echo "Request to start UI..."
start -n ui &
fi
start_system_services &
# It's hard to display any messages under Frecon, and Chrome usually starts
# even when disk is full, so we want to check disk usage after UI started.
check_disk_usage
export DISPLAY=":0"
export XAUTHORITY="/home/chronos/.Xauthority"
echo "Starting Goofy... ($GOOFY_ARGS)"
echo "
--- $(date +'%Y%m%d %H:%M:%S') Starting new Goofy session ($GOOFY_ARGS) ---
Device ID: $(cat /var/factory/.device_id) " >>"$FACTORY_LOG_FILE"
# shellcheck disable=SC2086
"$FACTORY/bin/goofy" $GOOFY_ARGS >>"$FACTORY_LOG_FILE" 2>&1 &
wait
}
stop_factory() {
# Try to kill X, and any other Python scripts, five times.
echo -n "Stopping factory."
local i
# shellcheck disable=SC2034
for i in $(seq 5); do
pkill 'python' || break
sleep 1
echo -n "."
done
echo "
Factory tests terminated. To check error messages, try
tail ${SESSION_LOG_FILE} ${FACTORY_LOG_FILE}
To restart, press Ctrl-Alt-F2, log in, and type:
factory_restart
If restarting does not work, try to reset by:
factory_restart -a
"
}
main() {
case "$1" in
"start" )
start_factory "$@"
;;
"stop" )
stop_factory "$@"
;;
* )
echo "Usage: $0 [start|stop]" >&2
exit 1
;;
esac
}
main "$@"