| #!/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 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 |