Skip to content

Commit 226f262

Browse files
committed
Merge branch 'main' into release/v2
* main: Prepare for release 2.17.0. Update test fixture dependencies. Add option to toggle Linux hardware acceleration Bump hosted-git-info from 2.8.8 to 2.8.9 Bump lodash from 4.17.19 to 4.17.21
2 parents 599839e + 4342116 commit 226f262

15 files changed

+78
-24
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Change Log
22

3+
## v2.17.0
4+
5+
* Add option to toggle Linux hardware acceleration - [#154](https://github.com/ReactiveCircus/android-emulator-runner/pull/154) @stevestotter
6+
37
## v2.16.0
48

59
* Avoid wrapping script code in quotes - [#134](https://github.com/ReactiveCircus/android-emulator-runner/pull/134) @hostilefork

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ A GitHub Action for installing, configuring and running hardware-accelerated And
99
The old ARM-based emulators were slow and are no longer supported by Google. The modern Intel Atom (x86 and x86_64) emulators require hardware acceleration (HAXM on Mac & Windows, QEMU on Linux) from the host to run fast. This presents a challenge on CI as to be able to run hardware accelerated emulators within a docker container, **KVM** must be supported by the host VM which isn't the case for cloud-based CI providers due to infrastructural limits. If you want to learn more about this, here's an article I wrote: [Running Android Instrumented Tests on CI](https://dev.to/ychescale9/running-android-emulators-on-ci-from-bitrise-io-to-github-actions-3j76).
1010

1111
The **macOS** VM provided by **GitHub Actions** has **HAXM** installed so we are able to create a new AVD instance, launch an emulator with hardware acceleration, and run our Android
12-
tests directly on the VM.
12+
tests directly on the VM. You can also achieve this on a self-hosted Linux runner, but it will need to be on a compatible instance that allows you to enable KVM - for example AWS EC2 Bare Metal instances.
1313

1414
This action automates the process by doing the following:
1515

@@ -98,6 +98,7 @@ jobs:
9898
| `emulator-options` | Optional | See below | Command-line options used when launching the emulator (replacing all default options) - e.g. `-no-window -no-snapshot -camera-back emulated`. |
9999
| `disable-animations` | Optional | `true` | Whether to disable animations - `true` or `false`. |
100100
| `disable-spellchecker` | Optional | `false` | Whether to disable spellchecker - `true` or `false`. |
101+
| `disable-linux-hw-accel` | Optional | `true` | Whether to disable hardware acceleration on Linux machines - `true` or `false`. Note that this is true by default as Github-hosted Linux runners do not support hardware acceleration. |
101102
| `emulator-build` | Optional | N/A | Build number of a specific version of the emulator binary to use e.g. `6061023` for emulator v29.3.0.0. |
102103
| `working-directory` | Optional | `./` | A custom working directory - e.g. `./android` if your root Gradle project is under the `./android` sub-directory within your repository. |
103104
| `ndk` | Optional | N/A | Version of NDK to install - e.g. `21.0.6113669` |
@@ -108,7 +109,7 @@ Default `emulator-options`: `-no-window -gpu swiftshader_indirect -no-snapshot -
108109

109110
## Can I use this action on Linux VMs?
110111

111-
The short answer is yes but it's expected to be a much worse experience (on some newer API levels it might not work at all) than running it on macOS.
112+
The short answer is yes but on Github-hosted Linux runners it's expected to be a much worse experience (on some newer API levels it might not work at all) than running it on macOS. You can get it running much faster on self-hosted Linux runners but only if the underlying instances support KVM (which most don't).
112113

113114
For a longer answer please refer to [this issue](https://github.com/ReactiveCircus/android-emulator-runner/issues/46).
114115

__tests__/input-validator.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,27 @@ describe('disable-spellchecker validator tests', () => {
124124
});
125125
});
126126

127+
describe('disable-linux-hw-accel validator tests', () => {
128+
it('Throws if disable-linux-hw-accel is not a boolean', () => {
129+
const func = () => {
130+
validator.checkDisableLinuxHardwareAcceleration('yes');
131+
};
132+
expect(func).toThrowError(`Input for input.disable-linux-hw-accel should be either 'true' or 'false'.`);
133+
});
134+
135+
it('Validates successfully if disable-linux-hw-accel is either true or false', () => {
136+
const func1 = () => {
137+
validator.checkDisableLinuxHardwareAcceleration('true');
138+
};
139+
expect(func1).not.toThrow();
140+
141+
const func2 = () => {
142+
validator.checkDisableLinuxHardwareAcceleration('false');
143+
};
144+
expect(func2).not.toThrow();
145+
});
146+
});
147+
127148
describe('emulator-build validator tests', () => {
128149
it('Throws if emulator-build is not a number', () => {
129150
const func = () => {

action.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ inputs:
3333
disable-spellchecker:
3434
description: Whether to disable spellchecker - `true` or `false`.
3535
default: 'false'
36+
disable-linux-hw-accel:
37+
description: Whether to disable hardware acceleration on Linux machines - `true` or `false`.
38+
default: 'true'
3639
emulator-build:
3740
description: 'build number of a specific version of the emulator binary to use - e.g. `6061023` for emulator v29.3.0.0'
3841
working-directory:

lib/emulator-manager.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ const EMULATOR_BOOT_TIMEOUT_SECONDS = 600;
3434
/**
3535
* Creates and launches a new AVD instance with the specified configurations.
3636
*/
37-
function launchEmulator(apiLevel, target, arch, profile, cores, sdcardPathOrSize, avdName, emulatorOptions, disableAnimations, disableSpellChecker) {
37+
function launchEmulator(apiLevel, target, arch, profile, cores, sdcardPathOrSize, avdName, emulatorOptions, disableAnimations, disableSpellChecker, disableLinuxHardwareAcceleration) {
3838
return __awaiter(this, void 0, void 0, function* () {
3939
// create a new AVD
4040
const profileOption = profile.trim() !== '' ? `--device '${profile}'` : '';
@@ -46,8 +46,9 @@ function launchEmulator(apiLevel, target, arch, profile, cores, sdcardPathOrSize
4646
}
4747
// start emulator
4848
console.log('Starting emulator.');
49-
// turn off hardware acceleration on Linux
50-
if (process.platform === 'linux') {
49+
//turn off hardware acceleration on Linux
50+
if (process.platform === 'linux' && disableLinuxHardwareAcceleration) {
51+
console.log('Disabling Linux hardware acceleration.');
5152
emulatorOptions += ' -accel off';
5253
}
5354
yield exec.exec(`sh -c \\"${process.env.ANDROID_SDK_ROOT}/emulator/emulator -avd "${avdName}" ${emulatorOptions} &"`, [], {

lib/input-validator.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use strict";
22
Object.defineProperty(exports, "__esModule", { value: true });
3-
exports.checkEmulatorBuild = exports.checkDisableSpellchecker = exports.checkDisableAnimations = exports.checkArch = exports.checkTarget = exports.checkApiLevel = exports.VALID_ARCHS = exports.VALID_TARGETS = exports.MIN_API_LEVEL = void 0;
3+
exports.checkEmulatorBuild = exports.checkDisableLinuxHardwareAcceleration = exports.checkDisableSpellchecker = exports.checkDisableAnimations = exports.checkArch = exports.checkTarget = exports.checkApiLevel = exports.VALID_ARCHS = exports.VALID_TARGETS = exports.MIN_API_LEVEL = void 0;
44
exports.MIN_API_LEVEL = 15;
55
exports.VALID_TARGETS = ['default', 'google_apis', 'google_apis_playstore'];
66
exports.VALID_ARCHS = ['x86', 'x86_64', 'arm64-v8a'];
@@ -37,6 +37,12 @@ function checkDisableSpellchecker(disableSpellchecker) {
3737
}
3838
}
3939
exports.checkDisableSpellchecker = checkDisableSpellchecker;
40+
function checkDisableLinuxHardwareAcceleration(disableLinuxHardwareAcceleration) {
41+
if (!isValidBoolean(disableLinuxHardwareAcceleration)) {
42+
throw new Error(`Input for input.disable-linux-hw-accel should be either 'true' or 'false'.`);
43+
}
44+
}
45+
exports.checkDisableLinuxHardwareAcceleration = checkDisableLinuxHardwareAcceleration;
4046
function checkEmulatorBuild(emulatorBuild) {
4147
if (isNaN(Number(emulatorBuild)) || !Number.isInteger(Number(emulatorBuild))) {
4248
throw new Error(`Unexpected emulator build: '${emulatorBuild}'.`);

lib/main.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@ function run() {
8585
input_validator_1.checkDisableSpellchecker(disableSpellcheckerInput);
8686
const disableSpellchecker = disableSpellcheckerInput === 'true';
8787
console.log(`disable spellchecker: ${disableSpellchecker}`);
88+
// disable linux hardware acceleration
89+
const disableLinuxHardwareAccelerationInput = core.getInput('disable-linux-hw-accel');
90+
input_validator_1.checkDisableLinuxHardwareAcceleration(disableLinuxHardwareAccelerationInput);
91+
const disableLinuxHardwareAcceleration = disableLinuxHardwareAccelerationInput === 'true';
92+
console.log(`disable Linux hardware acceleration: ${disableLinuxHardwareAcceleration}`);
8893
// emulator build
8994
const emulatorBuildInput = core.getInput('emulator-build');
9095
if (emulatorBuildInput) {
@@ -120,7 +125,7 @@ function run() {
120125
// install SDK
121126
yield sdk_installer_1.installAndroidSdk(apiLevel, target, arch, emulatorBuild, ndkVersion, cmakeVersion);
122127
// launch an emulator
123-
yield emulator_manager_1.launchEmulator(apiLevel, target, arch, profile, cores, sdcardPathOrSize, avdName, emulatorOptions, disableAnimations, disableSpellchecker);
128+
yield emulator_manager_1.launchEmulator(apiLevel, target, arch, profile, cores, sdcardPathOrSize, avdName, emulatorOptions, disableAnimations, disableSpellchecker, disableLinuxHardwareAcceleration);
124129
// execute the custom script
125130
try {
126131
// move to custom working directory if set

package-lock.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/emulator-manager.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ export async function launchEmulator(
1515
avdName: string,
1616
emulatorOptions: string,
1717
disableAnimations: boolean,
18-
disableSpellChecker: boolean
18+
disableSpellChecker: boolean,
19+
disableLinuxHardwareAcceleration: boolean
1920
): Promise<void> {
2021
// create a new AVD
2122
const profileOption = profile.trim() !== '' ? `--device '${profile}'` : '';
@@ -32,8 +33,9 @@ export async function launchEmulator(
3233
// start emulator
3334
console.log('Starting emulator.');
3435

35-
// turn off hardware acceleration on Linux
36-
if (process.platform === 'linux') {
36+
//turn off hardware acceleration on Linux
37+
if (process.platform === 'linux' && disableLinuxHardwareAcceleration) {
38+
console.log('Disabling Linux hardware acceleration.');
3739
emulatorOptions += ' -accel off';
3840
}
3941

src/input-validator.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ export function checkDisableSpellchecker(disableSpellchecker: string): void {
3535
}
3636
}
3737

38+
export function checkDisableLinuxHardwareAcceleration(disableLinuxHardwareAcceleration: string): void {
39+
if (!isValidBoolean(disableLinuxHardwareAcceleration)) {
40+
throw new Error(`Input for input.disable-linux-hw-accel should be either 'true' or 'false'.`);
41+
}
42+
}
43+
3844
export function checkEmulatorBuild(emulatorBuild: string): void {
3945
if (isNaN(Number(emulatorBuild)) || !Number.isInteger(Number(emulatorBuild))) {
4046
throw new Error(`Unexpected emulator build: '${emulatorBuild}'.`);

src/main.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as core from '@actions/core';
22
import { installAndroidSdk } from './sdk-installer';
3-
import { checkApiLevel, checkTarget, checkArch, checkDisableAnimations, checkEmulatorBuild, checkDisableSpellchecker } from './input-validator';
3+
import { checkApiLevel, checkTarget, checkArch, checkDisableAnimations, checkEmulatorBuild, checkDisableSpellchecker, checkDisableLinuxHardwareAcceleration } from './input-validator';
44
import { launchEmulator, killEmulator } from './emulator-manager';
55
import * as exec from '@actions/exec';
66
import { parseScript } from './script-parser';
@@ -67,6 +67,12 @@ async function run() {
6767
const disableSpellchecker = disableSpellcheckerInput === 'true';
6868
console.log(`disable spellchecker: ${disableSpellchecker}`);
6969

70+
// disable linux hardware acceleration
71+
const disableLinuxHardwareAccelerationInput = core.getInput('disable-linux-hw-accel');
72+
checkDisableLinuxHardwareAcceleration(disableLinuxHardwareAccelerationInput);
73+
const disableLinuxHardwareAcceleration = disableLinuxHardwareAccelerationInput === 'true';
74+
console.log(`disable Linux hardware acceleration: ${disableLinuxHardwareAcceleration}`);
75+
7076
// emulator build
7177
const emulatorBuildInput = core.getInput('emulator-build');
7278
if (emulatorBuildInput) {
@@ -108,7 +114,7 @@ async function run() {
108114
await installAndroidSdk(apiLevel, target, arch, emulatorBuild, ndkVersion, cmakeVersion);
109115

110116
// launch an emulator
111-
await launchEmulator(apiLevel, target, arch, profile, cores, sdcardPathOrSize, avdName, emulatorOptions, disableAnimations, disableSpellchecker);
117+
await launchEmulator(apiLevel, target, arch, profile, cores, sdcardPathOrSize, avdName, emulatorOptions, disableAnimations, disableSpellchecker, disableLinuxHardwareAcceleration);
112118

113119
// execute the custom script
114120
try {

test-fixture/app/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ android {
2626
dependencies {
2727
implementation fileTree(dir: 'libs', include: ['*.jar'])
2828
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
29-
implementation 'androidx.appcompat:appcompat:1.2.0'
30-
implementation 'androidx.core:core-ktx:1.3.2'
29+
implementation 'androidx.appcompat:appcompat:1.3.0'
30+
implementation 'androidx.core:core-ktx:1.5.0'
3131
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
3232
testImplementation 'junit:junit:4.13'
3333
androidTestImplementation 'androidx.test.ext:junit:1.1.2'

test-fixture/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
// Top-level build file where you can add configuration options common to all sub-projects/modules.
22

33
buildscript {
4-
ext.kotlin_version = '1.4.21'
4+
ext.kotlin_version = '1.5.10'
55
repositories {
66
google()
77
jcenter()
88
}
99
dependencies {
10-
classpath 'com.android.tools.build:gradle:4.1.1'
10+
classpath 'com.android.tools.build:gradle:4.2.1'
1111
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
1212

1313
// NOTE: Do not place your application dependencies here; they belong

test-fixture/gradle.properties

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
org.gradle.parallel=true
22
org.gradle.configureondemand=true
33
org.gradle.caching=true
4-
org.gradle.vfs.watch=true
54

65
# Enable Kotlin incremental compilation
76
kotlin.incremental=true

test-fixture/gradle/wrapper/gradle-wrapper.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
33
distributionPath=wrapper/dists
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists
6-
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
6+
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.1-bin.zip

0 commit comments

Comments
 (0)