|
| 1 | +#!/usr/bin/env bash |
| 2 | +# |
| 3 | +# SPDX-License-Identifier: Apache-2.0 |
| 4 | +# |
| 5 | +# Copyright (C) 2024, ARM Limited and contributors. |
| 6 | +# |
| 7 | +# Licensed under the Apache License, Version 2.0 (the "License"); you may |
| 8 | +# not use this file except in compliance with the License. |
| 9 | +# You may obtain a copy of the License at |
| 10 | +# |
| 11 | +# http://www.apache.org/licenses/LICENSE-2.0 |
| 12 | +# |
| 13 | +# Unless required by applicable law or agreed to in writing, software |
| 14 | +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| 15 | +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 16 | +# See the License for the specific language governing permissions and |
| 17 | +# limitations under the License. |
| 18 | +# |
| 19 | +# Forked from https://github.com/ARM-software/lisa/blob/main/install_base.sh |
| 20 | +# |
| 21 | + |
| 22 | +# shellcheck disable=SC2317 |
| 23 | + |
| 24 | +# Read standard /etc/os-release file and extract the needed field lsb_release |
| 25 | +# binary is not installed on all distro, but that file is found pretty much |
| 26 | +# anywhere. |
| 27 | +read_os_release() { |
| 28 | + local field_name=${1} |
| 29 | + # shellcheck source=/etc/os-release |
| 30 | + (source /etc/os-release &> /dev/null && printf "%s" "${!field_name}") |
| 31 | +} |
| 32 | + |
| 33 | +# Test the value of a field in /etc/os-release |
| 34 | +test_os_release() { |
| 35 | + local field_name=${1} |
| 36 | + local value=${2} |
| 37 | + |
| 38 | + if [[ "$(read_os_release "${field_name}")" == "${value}" ]]; then |
| 39 | + return 0 |
| 40 | + else |
| 41 | + return 1 |
| 42 | + fi |
| 43 | +} |
| 44 | + |
| 45 | +function set_host_arch |
| 46 | +{ |
| 47 | + # Google ABI type for Arm platforms |
| 48 | + HOST_ARCH="arm64-v8a" |
| 49 | + |
| 50 | + local machine |
| 51 | + machine=$(uname -m) |
| 52 | + if [[ "${machine}" == "x86"* ]]; then |
| 53 | + HOST_ARCH=${machine} |
| 54 | + fi |
| 55 | +} |
| 56 | + |
| 57 | +ANDROID_HOME="$(dirname "${0}")/android-sdk-linux" |
| 58 | +export ANDROID_HOME |
| 59 | +export ANDROID_USER_HOME="${ANDROID_HOME}/.android" |
| 60 | + |
| 61 | +mkdir -p "${ANDROID_HOME}/cmdline-tools" |
| 62 | + |
| 63 | +CMDLINE_VERSION=${CMDLINE_VERSION:-"11076708"} |
| 64 | + |
| 65 | +cleanup_android_home() { |
| 66 | + echo "Cleaning up Android SDK: ${ANDROID_HOME}" |
| 67 | + rm -rf "${ANDROID_HOME}" |
| 68 | + mkdir -p "${ANDROID_HOME}/cmdline-tools" |
| 69 | +} |
| 70 | + |
| 71 | +install_android_sdk_manager() { |
| 72 | + echo "Installing Android SDK manager ..." |
| 73 | + |
| 74 | + # URL taken from "Command line tools only": https://developer.android.com/studio |
| 75 | + local url="https://dl.google.com/android/repository/commandlinetools-linux-${CMDLINE_VERSION}_latest.zip" |
| 76 | + |
| 77 | + echo "Downloading Android SDK manager from: $url" |
| 78 | + wget -qO- "${url}" | bsdtar -xf- -C "${ANDROID_HOME}/cmdline-tools" |
| 79 | + |
| 80 | + echo "Moving commandlinetools to cmdline-tools/latest..." |
| 81 | + # First, clear cmdline-tools/latest if it exists. |
| 82 | + rm -rf "${ANDROID_HOME}/cmdline-tools/latest" |
| 83 | + mv "${ANDROID_HOME}/cmdline-tools/cmdline-tools" "${ANDROID_HOME}/cmdline-tools/latest" |
| 84 | + |
| 85 | + chmod +x -R "${ANDROID_HOME}/cmdline-tools/latest/bin" |
| 86 | + |
| 87 | + yes | (call_android_sdkmanager --licenses || true) |
| 88 | + |
| 89 | + echo "Creating the link to skins directory..." |
| 90 | + readlink "${ANDROID_HOME}/skins" > /dev/null 2>&1 || ln -sf "../skins" "${ANDROID_HOME}/skins" |
| 91 | +} |
| 92 | + |
| 93 | +# Android SDK is picky on Java version, so we need to set JAVA_HOME manually. |
| 94 | +# In most distributions, Java is installed under /usr/lib/jvm so use that. |
| 95 | +# according to the distribution |
| 96 | +ANDROID_SDK_JAVA_VERSION=17 |
| 97 | +find_java_home() { |
| 98 | + _JAVA_BIN=$(find -L /usr/lib/jvm -path "*${ANDROID_SDK_JAVA_VERSION}*/bin/java" -not -path '*/jre/bin/*' -print -quit) |
| 99 | + _JAVA_HOME=$(dirname "${_JAVA_BIN}")/../ |
| 100 | + |
| 101 | + echo "Found JAVA_HOME=${_JAVA_HOME}" |
| 102 | +} |
| 103 | + |
| 104 | +call_android_sdk() { |
| 105 | + local tool="${ANDROID_HOME}/cmdline-tools/latest/bin/${1}" |
| 106 | + shift |
| 107 | + JAVA_HOME=${_JAVA_HOME} "${tool}" "$@" |
| 108 | +} |
| 109 | + |
| 110 | +call_android_sdkmanager() { |
| 111 | + call_android_sdk sdkmanager "$@" |
| 112 | +} |
| 113 | + |
| 114 | +call_android_avdmanager() { |
| 115 | + call_android_sdk avdmanager "$@" |
| 116 | +} |
| 117 | + |
| 118 | +# Needs install_android_sdk_manager first |
| 119 | +install_android_tools() { |
| 120 | + yes | call_android_sdkmanager --verbose --channel=0 --install "platform-tools" |
| 121 | + yes | call_android_sdkmanager --verbose --channel=0 --install "platforms;android-31" |
| 122 | + yes | call_android_sdkmanager --verbose --channel=0 --install "platforms;android-33" |
| 123 | + yes | call_android_sdkmanager --verbose --channel=0 --install "platforms;android-34" |
| 124 | + yes | call_android_sdkmanager --verbose --channel=0 --install "system-images;android-31;google_apis;${HOST_ARCH}" |
| 125 | + yes | call_android_sdkmanager --verbose --channel=0 --install "system-images;android-33;android-desktop;${HOST_ARCH}" |
| 126 | + yes | call_android_sdkmanager --verbose --channel=0 --install "system-images;android-34;google_apis;${HOST_ARCH}" |
| 127 | +} |
| 128 | + |
| 129 | +create_android_vds() { |
| 130 | + local vd_name |
| 131 | + |
| 132 | + vd_name="devlib-p6-12" |
| 133 | + echo "Creating virtual device \"${vd_name}\" (Pixel 6 - Android 12)..." |
| 134 | + echo no | call_android_avdmanager -s create avd -n "${vd_name}" -k "system-images;android-31;google_apis;${HOST_ARCH}" --skin pixel_6 -b "${HOST_ARCH}" -f |
| 135 | + |
| 136 | + vd_name="devlib-p6-14" |
| 137 | + echo "Creating virtual device \"${vd_name}\" (Pixel 6 - Android 14)..." |
| 138 | + echo no | call_android_avdmanager -s create avd -n "${vd_name}" -k "system-images;android-34;google_apis;${HOST_ARCH}" --skin pixel_6 -b "${HOST_ARCH}" -f |
| 139 | + |
| 140 | + vd_name="devlib-chromeos" |
| 141 | + echo "Creating virtual device \"${vd_name}\" (ChromeOS - Android 13, Pixel tablet)..." |
| 142 | + echo no | call_android_avdmanager -s create avd -n "${vd_name}" -k "system-images;android-33;android-desktop;${HOST_ARCH}" --skin pixel_tablet -b "${HOST_ARCH}" -f |
| 143 | +} |
| 144 | + |
| 145 | +install_apt() { |
| 146 | + echo "Installing apt packages..." |
| 147 | + local apt_cmd=(DEBIAN_FRONTEND=noninteractive apt-get) |
| 148 | + sudo "${apt_cmd[@]}" update |
| 149 | + if [[ $unsupported_distro == 1 ]]; then |
| 150 | + for package in "${apt_packages[@]}"; do |
| 151 | + if ! sudo "${apt_cmd[@]}" install -y "$package"; then |
| 152 | + echo "Failed to install $package on that distribution" >&2 |
| 153 | + fi |
| 154 | + done |
| 155 | + else |
| 156 | + sudo "${apt_cmd[@]}" install -y "${apt_packages[@]}" || exit $? |
| 157 | + fi |
| 158 | +} |
| 159 | + |
| 160 | +install_pacman() { |
| 161 | + echo "Installing pacman packages..." |
| 162 | + sudo pacman -Sy --needed --noconfirm "${pacman_packages[@]}" || exit $? |
| 163 | +} |
| 164 | + |
| 165 | +# APT-based distributions like Ubuntu or Debian |
| 166 | +apt_packages=( |
| 167 | + cpu-checker |
| 168 | + libarchive-tools |
| 169 | + wget |
| 170 | + unzip |
| 171 | + qemu-user-static |
| 172 | +) |
| 173 | + |
| 174 | +# pacman-based distributions like Archlinux or its derivatives |
| 175 | +pacman_packages=( |
| 176 | + libarchive |
| 177 | + qemu-user-static |
| 178 | +) |
| 179 | + |
| 180 | +# Detection based on the package-manager, so that it works on derivatives of |
| 181 | +# distributions we expect. Matching on distro name would prevent that. |
| 182 | +if which apt-get &>/dev/null; then |
| 183 | + install_functions+=(install_apt) |
| 184 | + package_manager='apt-get' |
| 185 | + expected_distro="Ubuntu" |
| 186 | + |
| 187 | +elif which pacman &>/dev/null; then |
| 188 | + install_functions+=(install_pacman) |
| 189 | + package_manager="pacman" |
| 190 | + expected_distro="Arch Linux" |
| 191 | +else |
| 192 | + echo "The package manager of distribution $(read_os_release NAME) is not supported, will only install distro-agnostic code" |
| 193 | +fi |
| 194 | + |
| 195 | +if [[ -n "${package_manager}" ]] && ! test_os_release NAME "${expected_distro}"; then |
| 196 | + unsupported_distro=1 |
| 197 | + echo |
| 198 | + echo "INFO: the distribution seems based on ${package_manager} but is not ${expected_distro}, some package names might not be right" |
| 199 | + echo |
| 200 | +else |
| 201 | + unsupported_distro=0 |
| 202 | +fi |
| 203 | + |
| 204 | +usage() { |
| 205 | + echo "Usage: ${0} [--help] [--cleanup-android-sdk] [--install-android-tools] |
| 206 | + [--install-android-platform-tools] [--create-avds] [--install-all]" |
| 207 | + cat << EOF |
| 208 | +
|
| 209 | +Install distribution packages and other bits required by Android emulator. |
| 210 | +Archlinux and Ubuntu are supported, although derivative distributions will |
| 211 | +probably work as well. |
| 212 | +
|
| 213 | +--install-android-platform-tools is not needed when using |
| 214 | +--install-android-tools, but has the advantage of not needing a Java |
| 215 | +installation and is quicker to install. |
| 216 | +EOF |
| 217 | +} |
| 218 | + |
| 219 | +# Defaults to --install-all if no option is given |
| 220 | +if [[ -z "$*" ]]; then |
| 221 | + args=("--install-all") |
| 222 | +else |
| 223 | + args=("$@") |
| 224 | +fi |
| 225 | + |
| 226 | +set_host_arch |
| 227 | + |
| 228 | +# Use conditional fall-through ;;& to all matching all branches with |
| 229 | +# --install-all |
| 230 | +for arg in "${args[@]}"; do |
| 231 | + # We need this flag since *) does not play well with fall-through ;;& |
| 232 | + handled=0 |
| 233 | + case "$arg" in |
| 234 | + |
| 235 | + "--cleanup-android-sdk") |
| 236 | + install_functions+=(cleanup_android_home) |
| 237 | + handled=1 |
| 238 | + ;;& |
| 239 | + |
| 240 | + "--install-android-tools" | "--install-all") |
| 241 | + install_functions+=( |
| 242 | + find_java_home |
| 243 | + install_android_sdk_manager |
| 244 | + install_android_tools |
| 245 | + ) |
| 246 | + apt_packages+=(openjdk-"${ANDROID_SDK_JAVA_VERSION}"-jre openjdk-"${ANDROID_SDK_JAVA_VERSION}"-jdk) |
| 247 | + pacman_packages+=(jre"${ANDROID_SDK_JAVA_VERSION}"-openjdk jdk"${ANDROID_SDK_JAVA_VERSION}"-openjdk) |
| 248 | + handled=1; |
| 249 | + ;;& |
| 250 | + |
| 251 | + "--create-avds" | "--install-all") |
| 252 | + install_functions+=( |
| 253 | + find_java_home |
| 254 | + install_android_sdk_manager |
| 255 | + install_android_tools |
| 256 | + create_android_vds |
| 257 | + ) |
| 258 | + handled=1 |
| 259 | + ;;& |
| 260 | + |
| 261 | + "--help") |
| 262 | + usage |
| 263 | + exit 0 |
| 264 | + ;;& |
| 265 | + |
| 266 | + *) |
| 267 | + if [[ ${handled} != 1 ]]; then |
| 268 | + echo "Unrecognised argument: ${arg}" |
| 269 | + usage |
| 270 | + exit 2 |
| 271 | + fi |
| 272 | + ;; |
| 273 | + esac |
| 274 | +done |
| 275 | + |
| 276 | +# In order in which they will be executed if specified in command line |
| 277 | +ordered_functions=( |
| 278 | + # Distro package managers before anything else, so all the basic |
| 279 | + # pre-requisites are there |
| 280 | + install_apt |
| 281 | + install_pacman |
| 282 | + |
| 283 | + find_java_home |
| 284 | + # cleanup must be done BEFORE installing |
| 285 | + cleanup_android_home |
| 286 | + install_android_sdk_manager |
| 287 | + install_android_tools |
| 288 | + create_android_vds |
| 289 | +) |
| 290 | + |
| 291 | +# Remove duplicates in the list |
| 292 | +# shellcheck disable=SC2207 |
| 293 | +install_functions=($(echo "${install_functions[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')) |
| 294 | + |
| 295 | +# Call all the hooks in the order of available_functions |
| 296 | +ret=0 |
| 297 | +for f in "${ordered_functions[@]}"; do |
| 298 | + for func in "${install_functions[@]}"; do |
| 299 | + if [[ ${func} == "${f}" ]]; then |
| 300 | + # If one hook returns non-zero, we keep going but return an overall failure code. |
| 301 | + ${func}; _ret=$? |
| 302 | + if [[ $_ret != 0 ]]; then |
| 303 | + ret=${_ret} |
| 304 | + echo "Stage ${func} failed with exit code ${ret}" >&2 |
| 305 | + else |
| 306 | + echo "Stage ${func} succeeded" >&2 |
| 307 | + fi |
| 308 | + fi |
| 309 | + done |
| 310 | +done |
| 311 | + |
| 312 | +exit $ret |
| 313 | + |
| 314 | +# vim: set tabstop=4 shiftwidth=4 textwidth=80 expandtab: |
0 commit comments