diff --git a/lib/emulator-manager.js b/lib/emulator-manager.js index 8dd880dc..564c812d 100644 --- a/lib/emulator-manager.js +++ b/lib/emulator-manager.js @@ -35,55 +35,64 @@ const EMULATOR_BOOT_TIMEOUT_SECONDS = 600; /** * Creates and launches a new AVD instance with the specified configurations. */ -function launchEmulator(apiLevel, target, arch, profile, cores, ramSize, sdcardPathOrSize, avdName, forceAvdCreation, emulatorOptions, disableAnimations, disableSpellChecker, disableLinuxHardwareAcceleration, enableHardwareKeyboard) { +function launchEmulator(apiLevel, target, arch, profile, cores, ramSize, sdcardPathOrSize, diskSize, avdName, forceAvdCreation, emulatorOptions, disableAnimations, disableSpellChecker, disableLinuxHardwareAcceleration, enableHardwareKeyboard) { return __awaiter(this, void 0, void 0, function* () { - // create a new AVD if AVD directory does not already exist or forceAvdCreation is true - const avdPath = `${process.env.ANDROID_AVD_HOME}/${avdName}.avd`; - if (!fs.existsSync(avdPath) || forceAvdCreation) { - const profileOption = profile.trim() !== '' ? `--device '${profile}'` : ''; - const sdcardPathOrSizeOption = sdcardPathOrSize.trim() !== '' ? `--sdcard '${sdcardPathOrSize}'` : ''; - console.log(`Creating AVD.`); - yield exec.exec(`sh -c \\"echo no | avdmanager create avd --force -n "${avdName}" --abi '${target}/${arch}' --package 'system-images;android-${apiLevel};${target};${arch}' ${profileOption} ${sdcardPathOrSizeOption}"`); - } - if (cores) { - yield exec.exec(`sh -c \\"printf 'hw.cpu.ncore=${cores}\n' >> ${process.env.ANDROID_AVD_HOME}/"${avdName}".avd"/config.ini`); - } - if (ramSize) { - yield exec.exec(`sh -c \\"printf 'hw.ramSize=${ramSize}\n' >> ${process.env.ANDROID_AVD_HOME}/"${avdName}".avd"/config.ini`); - } - if (enableHardwareKeyboard) { - yield exec.exec(`sh -c \\"printf 'hw.keyboard=yes\n' >> ${process.env.ANDROID_AVD_HOME}/"${avdName}".avd"/config.ini`); - } - //turn off hardware acceleration on Linux - if (process.platform === 'linux' && disableLinuxHardwareAcceleration) { - console.log('Disabling Linux hardware acceleration.'); - emulatorOptions += ' -accel off'; - } - // start emulator - console.log('Starting emulator.'); - yield exec.exec(`sh -c \\"${process.env.ANDROID_SDK_ROOT}/emulator/emulator -avd "${avdName}" ${emulatorOptions} &"`, [], { - listeners: { - stderr: (data) => { - if (data.toString().includes('invalid command-line parameter')) { - throw new Error(data.toString()); + try { + console.log(`::group::Launch Emulator`); + // create a new AVD if AVD directory does not already exist or forceAvdCreation is true + const avdPath = `${process.env.ANDROID_AVD_HOME}/${avdName}.avd`; + if (!fs.existsSync(avdPath) || forceAvdCreation) { + const profileOption = profile.trim() !== '' ? `--device '${profile}'` : ''; + const sdcardPathOrSizeOption = sdcardPathOrSize.trim() !== '' ? `--sdcard '${sdcardPathOrSize}'` : ''; + console.log(`Creating AVD.`); + yield exec.exec(`sh -c \\"echo no | avdmanager create avd --force -n "${avdName}" --abi '${target}/${arch}' --package 'system-images;android-${apiLevel};${target};${arch}' ${profileOption} ${sdcardPathOrSizeOption}"`); + } + if (cores) { + yield exec.exec(`sh -c \\"printf 'hw.cpu.ncore=${cores}\n' >> ${process.env.ANDROID_AVD_HOME}/"${avdName}".avd"/config.ini`); + } + if (ramSize) { + yield exec.exec(`sh -c \\"printf 'hw.ramSize=${ramSize}\n' >> ${process.env.ANDROID_AVD_HOME}/"${avdName}".avd"/config.ini`); + } + if (enableHardwareKeyboard) { + yield exec.exec(`sh -c \\"printf 'hw.keyboard=yes\n' >> ${process.env.ANDROID_AVD_HOME}/"${avdName}".avd"/config.ini`); + } + if (diskSize) { + yield exec.exec(`sh -c \\"printf 'disk.dataPartition.size=${diskSize}\n' >> ${process.env.ANDROID_AVD_HOME}/"${avdName}".avd"/config.ini`); + } + //turn off hardware acceleration on Linux + if (process.platform === 'linux' && disableLinuxHardwareAcceleration) { + console.log('Disabling Linux hardware acceleration.'); + emulatorOptions += ' -accel off'; + } + // start emulator + console.log('Starting emulator.'); + yield exec.exec(`sh -c \\"${process.env.ANDROID_SDK_ROOT}/emulator/emulator -avd "${avdName}" ${emulatorOptions} &"`, [], { + listeners: { + stderr: (data) => { + if (data.toString().includes('invalid command-line parameter')) { + throw new Error(data.toString()); + } } } + }); + // wait for emulator to complete booting + yield waitForDevice(); + yield exec.exec(`adb shell input keyevent 82`); + if (disableAnimations) { + console.log('Disabling animations.'); + yield exec.exec(`adb shell settings put global window_animation_scale 0.0`); + yield exec.exec(`adb shell settings put global transition_animation_scale 0.0`); + yield exec.exec(`adb shell settings put global animator_duration_scale 0.0`); + } + if (disableSpellChecker) { + yield exec.exec(`adb shell settings put secure spell_checker_enabled 0`); + } + if (enableHardwareKeyboard) { + yield exec.exec(`adb shell settings put secure show_ime_with_hard_keyboard 0`); } - }); - // wait for emulator to complete booting - yield waitForDevice(); - yield exec.exec(`adb shell input keyevent 82`); - if (disableAnimations) { - console.log('Disabling animations.'); - yield exec.exec(`adb shell settings put global window_animation_scale 0.0`); - yield exec.exec(`adb shell settings put global transition_animation_scale 0.0`); - yield exec.exec(`adb shell settings put global animator_duration_scale 0.0`); } - if (disableSpellChecker) { - yield exec.exec(`adb shell settings put secure spell_checker_enabled 0`); - } - if (enableHardwareKeyboard) { - yield exec.exec(`adb shell settings put secure show_ime_with_hard_keyboard 0`); + finally { + console.log(`::endgroup::`); } }); } @@ -94,11 +103,15 @@ exports.launchEmulator = launchEmulator; function killEmulator() { return __awaiter(this, void 0, void 0, function* () { try { + console.log(`::group::Terminate Emulator`); yield exec.exec(`adb -s emulator-5554 emu kill`); } catch (error) { console.log(error.message); } + finally { + console.log(`::endgroup::`); + } }); } exports.killEmulator = killEmulator; diff --git a/lib/input-validator.js b/lib/input-validator.js index 2dcda715..a7bbabe4 100644 --- a/lib/input-validator.js +++ b/lib/input-validator.js @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.checkEmulatorBuild = exports.checkEnableHardwareKeyboard = exports.checkDisableLinuxHardwareAcceleration = exports.checkDisableSpellchecker = exports.checkDisableAnimations = exports.checkForceAvdCreation = exports.checkChannel = exports.checkArch = exports.checkTarget = exports.checkApiLevel = exports.VALID_CHANNELS = exports.VALID_ARCHS = exports.VALID_TARGETS = exports.MIN_API_LEVEL = void 0; +exports.checkDiskSize = exports.checkEmulatorBuild = exports.checkEnableHardwareKeyboard = exports.checkDisableLinuxHardwareAcceleration = exports.checkDisableSpellchecker = exports.checkDisableAnimations = exports.checkForceAvdCreation = exports.checkChannel = exports.checkArch = exports.checkTarget = exports.checkApiLevel = exports.VALID_CHANNELS = exports.VALID_ARCHS = exports.VALID_TARGETS = exports.MIN_API_LEVEL = void 0; exports.MIN_API_LEVEL = 15; exports.VALID_TARGETS = ['default', 'google_apis', 'aosp_atd', 'google_atd', 'google_apis_playstore', 'android-wear', 'android-wear-cn', 'android-tv', 'google-tv']; exports.VALID_ARCHS = ['x86', 'x86_64', 'arm64-v8a']; @@ -71,3 +71,20 @@ exports.checkEmulatorBuild = checkEmulatorBuild; function isValidBoolean(value) { return value === 'true' || value === 'false'; } +function checkDiskSize(diskSize) { + // Disk size can be empty - the default value + if (diskSize) { + // Can also be number of bytes + if (isNaN(Number(diskSize)) || !Number.isInteger(Number(diskSize))) { + // Disk size can have a size multiplier at the end K, M or G + const diskSizeUpperCase = diskSize.toUpperCase(); + if (diskSizeUpperCase.endsWith('K') || diskSizeUpperCase.endsWith('M') || diskSizeUpperCase.endsWith('G')) { + const diskSizeNoModifier = diskSize.slice(0, -1); + if (0 == diskSizeNoModifier.length || isNaN(Number(diskSizeNoModifier)) || !Number.isInteger(Number(diskSizeNoModifier))) { + throw new Error(`Unexpected disk size: '${diskSize}'.`); + } + } + } + } +} +exports.checkDiskSize = checkDiskSize; diff --git a/lib/main.js b/lib/main.js index 2a274461..59e6aca0 100644 --- a/lib/main.js +++ b/lib/main.js @@ -38,6 +38,7 @@ const channel_id_mapper_1 = require("./channel-id-mapper"); function run() { return __awaiter(this, void 0, void 0, function* () { try { + console.log(`::group::Configure emulator`); // only support running on macOS or Linux if (process.platform !== 'darwin') { if (process.platform === 'linux') { @@ -73,6 +74,9 @@ function run() { // SD card path or size used for creating the AVD const sdcardPathOrSize = core.getInput('sdcard-path-or-size'); console.log(`SD card path or size: ${sdcardPathOrSize}`); + const diskSize = core.getInput('disk-size'); + input_validator_1.checkDiskSize(diskSize); + console.log(`Disk size: ${diskSize}`); // custom name used for creating the AVD const avdName = core.getInput('avd-name'); console.log(`AVD name: ${avdName}`); @@ -141,10 +145,11 @@ function run() { scripts.forEach((script) => __awaiter(this, void 0, void 0, function* () { console.log(`${script}`); })); + console.log(`::endgroup::`); // install SDK yield sdk_installer_1.installAndroidSdk(apiLevel, target, arch, channelId, emulatorBuild, ndkVersion, cmakeVersion); // launch an emulator - yield emulator_manager_1.launchEmulator(apiLevel, target, arch, profile, cores, ramSize, sdcardPathOrSize, avdName, forceAvdCreation, emulatorOptions, disableAnimations, disableSpellchecker, disableLinuxHardwareAcceleration, enableHardwareKeyboard); + yield emulator_manager_1.launchEmulator(apiLevel, target, arch, profile, cores, ramSize, sdcardPathOrSize, diskSize, avdName, forceAvdCreation, emulatorOptions, disableAnimations, disableSpellchecker, disableLinuxHardwareAcceleration, enableHardwareKeyboard); // execute the custom script try { // move to custom working directory if set diff --git a/lib/sdk-installer.js b/lib/sdk-installer.js index d88691f9..c9c8145c 100644 --- a/lib/sdk-installer.js +++ b/lib/sdk-installer.js @@ -43,45 +43,51 @@ const CMDLINE_TOOLS_URL_LINUX = 'https://dl.google.com/android/repository/comman */ function installAndroidSdk(apiLevel, target, arch, channelId, emulatorBuild, ndkVersion, cmakeVersion) { return __awaiter(this, void 0, void 0, function* () { - const isOnMac = process.platform === 'darwin'; - if (!isOnMac) { - yield exec.exec(`sh -c \\"sudo chown $USER:$USER ${process.env.ANDROID_SDK_ROOT} -R`); + try { + console.log(`::group::Install Android SDK`); + const isOnMac = process.platform === 'darwin'; + if (!isOnMac) { + yield exec.exec(`sh -c \\"sudo chown $USER:$USER ${process.env.ANDROID_SDK_ROOT} -R`); + } + const cmdlineToolsPath = `${process.env.ANDROID_SDK_ROOT}/cmdline-tools`; + if (!fs.existsSync(cmdlineToolsPath)) { + console.log('Installing new cmdline-tools.'); + const sdkUrl = isOnMac ? CMDLINE_TOOLS_URL_MAC : CMDLINE_TOOLS_URL_LINUX; + const downloadPath = yield tc.downloadTool(sdkUrl); + yield tc.extractZip(downloadPath, cmdlineToolsPath); + yield io.mv(`${cmdlineToolsPath}/cmdline-tools`, `${cmdlineToolsPath}/latest`); + } + // add paths for commandline-tools and platform-tools + core.addPath(`${cmdlineToolsPath}/latest:${cmdlineToolsPath}/latest/bin:${process.env.ANDROID_SDK_ROOT}/platform-tools`); + // set standard AVD path + core.exportVariable('ANDROID_AVD_HOME', `${process.env.HOME}/.android/avd`); + // accept all Android SDK licenses + yield exec.exec(`sh -c \\"yes | sdkmanager --licenses > /dev/null"`); + console.log('Installing latest build tools, platform tools, and platform.'); + yield exec.exec(`sh -c \\"sdkmanager --install 'build-tools;${BUILD_TOOLS_VERSION}' platform-tools 'platforms;android-${apiLevel}' > /dev/null"`); + console.log('Installing latest emulator.'); + yield exec.exec(`sh -c \\"sdkmanager --install emulator --channel=${channelId} > /dev/null"`); + if (emulatorBuild) { + console.log(`Installing emulator build ${emulatorBuild}.`); + // TODO find out the correct download URLs for all build ids + const downloadUrlSuffix = Number(emulatorBuild.charAt(0)) > 6 ? `_x64-${emulatorBuild}` : `-${emulatorBuild}`; + yield exec.exec(`curl -fo emulator.zip https://dl.google.com/android/repository/emulator-${isOnMac ? 'darwin' : 'linux'}${downloadUrlSuffix}.zip`); + yield exec.exec(`unzip -o -q emulator.zip -d ${process.env.ANDROID_SDK_ROOT}`); + yield io.rmRF('emulator.zip'); + } + console.log('Installing system images.'); + yield exec.exec(`sh -c \\"sdkmanager --install 'system-images;android-${apiLevel};${target};${arch}' --channel=${channelId} > /dev/null"`); + if (ndkVersion) { + console.log(`Installing NDK ${ndkVersion}.`); + yield exec.exec(`sh -c \\"sdkmanager --install 'ndk;${ndkVersion}' --channel=${channelId} > /dev/null"`); + } + if (cmakeVersion) { + console.log(`Installing CMake ${cmakeVersion}.`); + yield exec.exec(`sh -c \\"sdkmanager --install 'cmake;${cmakeVersion}' --channel=${channelId} > /dev/null"`); + } } - const cmdlineToolsPath = `${process.env.ANDROID_SDK_ROOT}/cmdline-tools`; - if (!fs.existsSync(cmdlineToolsPath)) { - console.log('Installing new cmdline-tools.'); - const sdkUrl = isOnMac ? CMDLINE_TOOLS_URL_MAC : CMDLINE_TOOLS_URL_LINUX; - const downloadPath = yield tc.downloadTool(sdkUrl); - yield tc.extractZip(downloadPath, cmdlineToolsPath); - yield io.mv(`${cmdlineToolsPath}/cmdline-tools`, `${cmdlineToolsPath}/latest`); - } - // add paths for commandline-tools and platform-tools - core.addPath(`${cmdlineToolsPath}/latest:${cmdlineToolsPath}/latest/bin:${process.env.ANDROID_SDK_ROOT}/platform-tools`); - // set standard AVD path - core.exportVariable('ANDROID_AVD_HOME', `${process.env.HOME}/.android/avd`); - // accept all Android SDK licenses - yield exec.exec(`sh -c \\"yes | sdkmanager --licenses > /dev/null"`); - console.log('Installing latest build tools, platform tools, and platform.'); - yield exec.exec(`sh -c \\"sdkmanager --install 'build-tools;${BUILD_TOOLS_VERSION}' platform-tools 'platforms;android-${apiLevel}' > /dev/null"`); - console.log('Installing latest emulator.'); - yield exec.exec(`sh -c \\"sdkmanager --install emulator --channel=${channelId} > /dev/null"`); - if (emulatorBuild) { - console.log(`Installing emulator build ${emulatorBuild}.`); - // TODO find out the correct download URLs for all build ids - const downloadUrlSuffix = Number(emulatorBuild.charAt(0)) > 6 ? `_x64-${emulatorBuild}` : `-${emulatorBuild}`; - yield exec.exec(`curl -fo emulator.zip https://dl.google.com/android/repository/emulator-${isOnMac ? 'darwin' : 'linux'}${downloadUrlSuffix}.zip`); - yield exec.exec(`unzip -o -q emulator.zip -d ${process.env.ANDROID_SDK_ROOT}`); - yield io.rmRF('emulator.zip'); - } - console.log('Installing system images.'); - yield exec.exec(`sh -c \\"sdkmanager --install 'system-images;android-${apiLevel};${target};${arch}' --channel=${channelId} > /dev/null"`); - if (ndkVersion) { - console.log(`Installing NDK ${ndkVersion}.`); - yield exec.exec(`sh -c \\"sdkmanager --install 'ndk;${ndkVersion}' --channel=${channelId} > /dev/null"`); - } - if (cmakeVersion) { - console.log(`Installing CMake ${cmakeVersion}.`); - yield exec.exec(`sh -c \\"sdkmanager --install 'cmake;${cmakeVersion}' --channel=${channelId} > /dev/null"`); + finally { + console.log(`::endgroup::`); } }); }