blob: 185844bf8468341e236289a3676bc4ff4439cc44 [file] [log] [blame]
#!/bin/sh
# shellcheck disable=SC2154
# Copyright (c) 2014 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.
SCRIPT="$(readlink -f "$0")"
CWD="$(dirname "${SCRIPT}")"
SCRIPT_DIR="${CWD}/init.d"
DIST_PATH="${CWD}/../dist"
COMMIT="${DIST_PATH}/commit"
COMMITS_LOG="/var/log/chameleon_commits"
INITD_DIR='/etc/init.d'
CHAMELEOND_DIR='/usr/bin'
CHAMELEOND_NAME='chameleond'
DISPLAYD_NAME='displayd'
NETWORKING_NAME='networking'
NETWORKING_DIR='network'
STREAM_SERVER_NAME='stream_server'
SCHEDULER_NAME='scheduler'
UPDATER_NAME='chameleon-updater'
LIGHTTPD_NAME='lighttpd'
TEST_DATA_DIR='/usr/share/autotest'
. "${CWD}/bundle_common"
PLATFORM="$1"
PY_VERSION="$2"
if [ "${PLATFORM}" = "raspberrypi" ] || [ "${PLATFORM}" = "x86-generic" ]; then
IS_BLUETOOTH_PEER=1
fi
[ "${PY_VERSION=}" = "python3" ] && pip_cmd=pip3 || pip_cmd=pip
# We do not want lighttpd and chameleon-updater to run on startup.
update-rc.d -f "${LIGHTTPD_NAME}" remove
update-rc.d -f "${UPDATER_NAME}" remove
die() {
[ -n "$1" ] && echo "ERROR: $1" >&2
exit 1
}
validate_package_installation() {
PACKAGE_NAME=$1
# dpkg shows installation by showing "ii" next to the entry
if ! dpkg -l ${PACKAGE_NAME} 2>&1 | grep -qE '^ii'; then
printf "Installing package %s...\n" "${PACKAGE_NAME}"
eval "apt-get update > /dev/null 2>&1"
eval "apt-get -y install ${PACKAGE_NAME} > /dev/null 2>&1"
printf "Package %s installed\n" "${PACKAGE_NAME}"
else
printf "Package %s already installed\n" "${PACKAGE_NAME}"
fi
}
validate_python_package_installation() {
PACKAGE_NAME=$1
if eval "${pip_cmd} show "${PACKAGE_NAME}" > /dev/null"; then
echo "Python package ${PACKAGE_NAME} already installed"
else
echo "Installing python package ${PACKAGE_NAME}..."
if eval "${pip_cmd} install "${PACKAGE_NAME}" > /dev/null"; then
echo "Python package ${PACKAGE_NAME} installed"
else
echo "Error: fail to install python package ${PACKAGE_NAME}"
fi
fi
}
validate_socket_installation() {
INSTALL_LOCATION="/tmp"
PACKAGE_NAME="btsocket"
SOURCE_REPO="https://chromium.googlesource.com/chromiumos/platform/btsocket"
if ! python -c "import ${PACKAGE_NAME}"; then
if [ -d "${INSTALL_LOCATION}/${PACKAGE_NAME}" ]; then
rm -rf "${INSTALL_LOCATION}/${PACKAGE_NAME}"
fi
# Clone the repo into desired location
git clone ${SOURCE_REPO} ${INSTALL_LOCATION}/${PACKAGE_NAME}
cwd=$(pwd)
if ! cd ${INSTALL_LOCATION}/${PACKAGE_NAME}; then
echo "Failed to cd into ${INSTALL_LOCATION}/${PACKAGE_NAME}"
exit
fi
python setup.py build
python setup.py install
# Return to directory we started at
cd ${cwd}
printf "Package %s installed\n" "${PACKAGE_NAME}"
else
printf "Package %s already installed\n" "${PACKAGE_NAME}"
fi
}
validate_wbs_packages_installation() {
local wbs_name="$(get_latest_wbs_bundle_name)"
local wbs_tarball="${DIST_PATH}/${wbs_name}"
# Download the latest wbs tarball.
download_cloud_file "${wbs_name}" "${DIST_PATH}"
echo "The latest ${wbs_tarball} is downloaded."
if tar xf "${wbs_tarball}" -C / > /dev/null; then
echo "Customized packages in ${wbs_name} installed"
else
echo "Error in installing customized packages in ${wbs_name}!"
fi
}
validate_audio_test_data_packages_installation() {
local data_name='audio-test-data.tar.gz'
local data_tarball="${TEST_DATA_DIR}/${data_name}"
# Download the audio-test-data tarball.
download_cloud_file "${data_name}" "${TEST_DATA_DIR}"
echo "The latest ${data_tarball} is downloaded."
if tar xf "${data_tarball}" -C "${TEST_DATA_DIR}"; then
# Give read and write permission to all the test files
chmod ugo+rw -R "${TEST_DATA_DIR}/audio-test-data/"
# If not deleted, tarball gets redownloaded to a different file name
rm -f "${data_tarball}"
echo "Customized packages in ${data_name} installed"
else
echo "Error in installing customized packages in ${data_name}!"
fi
}
provide_daemon_symlinks(){
ALT_CHAMELEON_DIR='/usr/local/bin'
SCRIPT_NAME="run_$1"
if [ ! -e "${CHAMELEOND_DIR}/${SCRIPT_NAME}" ] && \
[ -e "${ALT_CHAMELEON_DIR}/${SCRIPT_NAME}" ]; then
printf "Creating symlink for script %s\n" "${SCRIPT_NAME}"
(cd "${CHAMELEOND_DIR}" && \
ln -s "${ALT_CHAMELEON_DIR}/${SCRIPT_NAME}" "${SCRIPT_NAME}")
fi
}
create_daemon_symlinks() {
provide_daemon_symlinks "${CHAMELEOND_NAME}"
provide_daemon_symlinks "${DISPLAYD_NAME}"
provide_daemon_symlinks "${STREAM_SERVER_NAME}"
provide_daemon_symlinks "${SCHEDULER_NAME}"
}
install_daemon_and_config () {
DAEMON_NAME=$1
CONFIG_FILE="/etc/default/${DAEMON_NAME}"
DAEMON="${CHAMELEOND_DIR}/run_${DAEMON_NAME}"
if [ ! -x "${DAEMON}" ]; then
echo "Executable ${DAEMON} not existed. Install it first." 1>&2
exit 1
fi
update-rc.d -f "${DAEMON_NAME}" remove
CONFIG_TMP="$(mktemp /tmp/"${DAEMON_NAME}".XXXXXX)"
commit_hash="$(cat ${COMMIT})"
cat <<END >"${CONFIG_TMP}"
CHAMELEOND_DIR="${CHAMELEOND_DIR}"
BUNDLE_VERSION="${BUNDLE_VERSION}"
BUNDLE_COMMIT_HASH="${commit_hash}"
CHAMELEON_BOARD="${CHAMELEON_BOARD}"
END
mv -f "${CONFIG_TMP}" "${CONFIG_FILE}"
if [ "${DAEMON_NAME}" = "${CHAMELEOND_NAME}" ]; then
now="$(date -u "+%Y-%m-%d_%H:%M:%S")_UTC"
TMP_COMMITS_LOG="$(mktemp /tmp/chameleon_commits.XXXXXX)"
[ -f "${COMMITS_LOG}" ] && cp "${COMMITS_LOG}" "${TMP_COMMITS_LOG}"
echo "${commit_hash} ${now}" >> "${TMP_COMMITS_LOG}"
mv -f "${TMP_COMMITS_LOG}" "${COMMITS_LOG}"
fi
}
# For Bluetooth peer, create symlinks if daemons were installed in
# /usr/local/bin instead of /usr/bin where chameleond expects them. This seems
# to be least invasive way to resolve disagreement without either breaking fizz
# or fpga device.
if [ -n "${IS_BLUETOOTH_PEER}" ]; then
create_daemon_symlinks
CHAMELEOND_DIR="/usr/local/bin"
fi
mkdir -p "${INITD_DIR}"
install_daemon_and_config "${CHAMELEOND_NAME}"
install_daemon_and_config "${DISPLAYD_NAME}"
install_daemon_and_config "${STREAM_SERVER_NAME}"
install_daemon_and_config "${SCHEDULER_NAME}"
cp -f "${SCRIPT_DIR}/${CHAMELEOND_NAME}" "${INITD_DIR}"
update-rc.d "${CHAMELEOND_NAME}" defaults 92 8
cp -f "${SCRIPT_DIR}/${DISPLAYD_NAME}" "${INITD_DIR}"
update-rc.d "${DISPLAYD_NAME}" defaults 94 6
cp -f "${SCRIPT_DIR}/${NETWORKING_NAME}" "${INITD_DIR}"
cp -pr "${CWD}/${NETWORKING_DIR}" "/etc"
mkdir -p "/etc/${NETWORKING_DIR}/if-down.d"
mkdir -p "/etc/${NETWORKING_DIR}/if-post-down.d"
mkdir -p "/etc/${NETWORKING_DIR}/if-pre-up.d"
mkdir -p "/etc/${NETWORKING_DIR}/if-up.d"
update-rc.d "${NETWORKING_NAME}" defaults 88 12
cp -f "${SCRIPT_DIR}/${STREAM_SERVER_NAME}" "${INITD_DIR}"
update-rc.d "${STREAM_SERVER_NAME}" defaults 96 4
cp -f "${SCRIPT_DIR}/${SCHEDULER_NAME}" "${INITD_DIR}"
update-rc.d "${SCHEDULER_NAME}" defaults 98 4
cp -f "${SCRIPT_DIR}/${UPDATER_NAME}" "${INITD_DIR}"
update-rc.d "${UPDATER_NAME}" defaults 90 10
# Some custom actions if chameleon is for Bluetooth peer.
if [ "${IS_BLUETOOTH_PEER}" -eq 1 ]; then
# Install required pcakges to perfom apt-clone
validate_package_installation "apt-clone"
APT_CLONE_DIR="${CWD}/../updatable/apt-clone/${PLATFORM}/"
if [ -d "$APT_CLONE_DIR" ]; then
echo "Start updating the Linux system, and this process may take few" \
"minutes"
tar -C "$APT_CLONE_DIR" -czf \
"${CHAMELEOND_NAME}_${PLATFORM}_apt-clone.tar.gz" "./"
apt-clone restore ${CHAMELEOND_NAME}_${PLATFORM}_apt-clone.tar.gz > \
/dev/null 2>&1
echo "Listing package difference between archived backup and the" \
"system.\nUse this information to help debug test failures and" \
"resolve discrepancies."
apt-clone show-diff ${CHAMELEOND_NAME}_${PLATFORM}_apt-clone.tar.gz
else
echo "apt-clone directory for the target platform: ${PLATFORM} does" \
"not exist. Skip updating Linux."
fi
# TODO(b/183116128): Remove the following package installation after
# apt-clone proved to be stable.
# Install required packages
validate_package_installation "bluetooth"
validate_package_installation "bluez"
validate_package_installation "python-bluez"
validate_package_installation "python-dbus"
validate_package_installation "python-pyudev"
# Some required for bluetooth-tester
validate_package_installation "git"
validate_package_installation "libatlas-base-dev"
validate_package_installation "python-dev"
# Some required for bluetooth audio tests
validate_package_installation "bluez-firmware"
validate_package_installation "lsof"
validate_package_installation "ofono"
validate_package_installation "pavucontrol"
validate_package_installation "playerctl"
validate_package_installation "pulseaudio-module-bluetooth"
validate_package_installation "pulseaudio"
# Install python packages for Raspberry Pi.
validate_python_package_installation "numpy"
validate_python_package_installation "pexpect"
validate_python_package_installation "pybluez"
validate_socket_installation
# Install customized packages in wbs.tbz2 to enable wideband speech.
# These are arm binaries, so we don't install for x86-generic.
# TODO(b/156780358): Provide a way to build this from source for x86.
if [ "${PLATFORM}" = "raspberrypi" ]; then
validate_wbs_packages_installation
validate_audio_test_data_packages_installation
fi
# Update bluetooth rules in service config files
BT_ADMIN_CONF="/etc/systemd/system/bluetooth.target.wants/bluetooth.service"
BT_SRC_CONF="/lib/systemd/system/bluetooth.service"
EXEC_START="ExecStart"
EXEC_OPTS="-d -P input"
# Add bluetoothd options to admin service config
if ! grep -qie "${EXEC_START}.*${EXEC_OPTS}" "${BT_ADMIN_CONF}"; then
# Find exec line, add options to end
eval "sed -ie 's/${EXEC_START}.*/& ${EXEC_OPTS}/g' ${BT_ADMIN_CONF}"
fi
# To be safe, also edit primary service config (requires service restart)
if ! grep -qie "${EXEC_START}.*${EXEC_OPTS}" "${BT_SRC_CONF}"; then
# Find exec line, add options to end
eval "sed -ie 's/${EXEC_START}.*/& ${EXEC_OPTS}/g' ${BT_SRC_CONF}"
eval "systemctl daemon-reload"
eval "service bluetooth restart"
fi
# Create new dbus service conf if it doesn't exist
DEST_KBD_CONF="/etc/dbus-1/system.d/org.chromium.autotest.btkbservice.conf"
if [ ! -e DEST_KBD_CONF ]; then
SRC_KBD_CONF=$(eval "find . -name *btkbservice.conf | head -n 1")
# Fail early if we couldn't find source conf file
if [ -z ${SRC_KBD_CONF} ]; then
echo "Failed to install btkbservice conf file, quitting early"
exit
fi
eval "cp ${SRC_KBD_CONF} ${DEST_KBD_CONF}"
eval "chmod +r ${DEST_KBD_CONF}"
fi
# No need to install servo packages as servo is not fully supported
# in the lab yet.
# install_servo_packages
# Add pi to the bluetooth group so that pulseaudio started by pi has
# the permission to interact with bluetooth daemon.
# The Raspberry Pi has to reboot to make usermod take effect.
# Reboot is needed only when pulseaudio is installed for the first time.
if ! groups pi | grep bluetooth > /dev/null; then
usermod -a -G bluetooth pi
need_reboot=1
fi
# ofono.conf needs to be updated to allow `pi` user access
OFONO_CONF="/etc/dbus-1/system.d/ofono.conf"
TMP_CONF="/tmp/ofono.conf.tmp"
if ! grep -q 'policy user="pi"' $OFONO_CONF; then
echo "Updating $OFONO_CONF with policy user=pi"
# Clear temporary file first
echo -n > $TMP_CONF
while read -r line
do
# Insert pi user permissions right before the root policy
if echo $line | grep -q 'policy user="root"'; then
echo '<policy user="pi">' >> $TMP_CONF
echo '<allow send_destination="org.ofono" />' >> $TMP_CONF
echo '</policy>' >> $TMP_CONF
echo '' >> $TMP_CONF
fi
# Copy the remaining lines as-is so the original isn't modified
echo "$line" >> $TMP_CONF
done < "$OFONO_CONF"
cp $TMP_CONF $OFONO_CONF
fi
# Mark that this platform is used for Bluetooth peer.
if [ "${PLATFORM}" = "x86-generic" ]; then
touch /etc/btpeer
fi
if [ -n "${need_reboot}" ]; then
sleep 3 && reboot &
echo '*** Raspberry Pi will reboot itself in 3 seconds! ***'
echo 'Reboot is needed only when it is first time to intall pulseaudio.'
else
# Restart chameleond and bluetoothd to ensure fresh state.
service bluetooth restart
"${INITD_DIR}/${CHAMELEOND_NAME}" restart
# Restart pulseaudio as user pi.
pgrep pulseaudio > /dev/null && killall pulseaudio
if runuser -l pi -c "pulseaudio --start"; then
echo "pulseaudio is running"
else
echo "Failed to start pulseaudio"
exit
fi
# Restart ofono.
if service ofono restart > /dev/null; then
echo "ofono is running"
else
echo "Failed to start ofono"
exit
fi
fi
# Finished deploying raspberrypi.
exit
fi
FPGA_DIR="$(dirname "${SCRIPT}")/../updatable/${CHAMELEON_BOARD}"
FPGA_BOOT_PART=$(fdisk -l /dev/mmcblk0 | grep 'Unknown' | cut -f1 -d' ')
FPGA_FAT_PART=$(fdisk -l /dev/mmcblk0 | grep 'FAT32' | cut -f1 -d' ')
FPGA_LINUX_PART=$(fdisk -l /dev/mmcblk0 | grep 'Linux' | cut -f1 -d' ')
MOUNT_DIR='/media/mmc1'
mkdir -p "${MOUNT_DIR}"
mount "${FPGA_FAT_PART}" "${MOUNT_DIR}"
for file in 'fpga.rbf' 'socfpga.dtb' 'zImage'; do
if ! diff -q "${FPGA_DIR}/${file}" "${MOUNT_DIR}/${file}"; then
echo "Updating ${file}"
cp -f "${FPGA_DIR}/${file}" "${MOUNT_DIR}"
need_reboot=1
fi
done
umount "${MOUNT_DIR}"
mount "${FPGA_LINUX_PART}" "${MOUNT_DIR}"
MODULE_DIR="${MOUNT_DIR}/lib/modules"
file="${FPGA_DIR}/modules.tgz"
if [ -e "${file}" ]; then
new_modules_version="$(tar tf "${file}" |head -n 1)"
new_modules_version="${new_modules_version%?}"
echo "new_modules_version ${new_modules_version}"
# shellcheck disable=SC2012
current_modules_version="$(ls -1 "${MODULE_DIR}" |head -n 1)"
echo "current_modules_version ${current_modules_version}"
if [ "${new_modules_version}" != "${current_modules_version}" ]; then
echo "Updating ${file}"
rm -rf "${MODULE_DIR}"/*
tar zxvf "${file}" -C "${MODULE_DIR}"
need_reboot=1
fi
fi
umount "${MOUNT_DIR}"
file='boot-partition.img'
if ! diff -q "${FPGA_DIR}/${file}" "${FPGA_BOOT_PART}"; then
echo "Updating ${file}"
dd if="${FPGA_DIR}/${file}" of="${FPGA_BOOT_PART}" bs=512
sync
need_reboot=1
fi
if [ -n "${need_reboot}" ]; then
echo 'Reboot the board to validate the FPGA configuration...'
reboot
else
"${INITD_DIR}/${CHAMELEOND_NAME}" restart
"${INITD_DIR}/${DISPLAYD_NAME}" restart
"${INITD_DIR}/${STREAM_SERVER_NAME}" restart
"${INITD_DIR}/${SCHEDULER_NAME}" restart
if [ -e "${INITD_DIR}/${LIGHTTPD_NAME}" ]; then
"${INITD_DIR}/${LIGHTTPD_NAME}" stop
fi
fi