Skip to content

Commit 606f1af

Browse files
committed
Add support for SDKExtension
1 parent cae5ace commit 606f1af

File tree

14 files changed

+148
-15
lines changed

14 files changed

+148
-15
lines changed

.github/workflows/main.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ jobs:
3939
api-level: 35
4040
target: google_apis
4141
arch: x86_64
42+
- os: ubuntu-latest
43+
api-level: 34
44+
target: android-automotive
45+
arch: x86_64
46+
sdk-extension: 9
4247

4348
steps:
4449
- name: checkout
@@ -85,6 +90,7 @@ jobs:
8590
api-level: ${{ matrix.api-level }}
8691
target: ${{ matrix.target }}
8792
arch: ${{ matrix.arch }}
93+
sdk-extension: ${{ matrix.sdk-extension }}
8894
profile: Galaxy Nexus
8995
cores: 2
9096
sdcard-path-or-size: 100M
@@ -102,6 +108,7 @@ jobs:
102108
api-level: ${{ matrix.api-level }}
103109
target: ${{ matrix.target }}
104110
arch: ${{ matrix.arch }}
111+
sdk-extension: ${{ matrix.sdk-extension }}
105112
profile: Galaxy Nexus
106113
cores: 2
107114
ram-size: 2048M

.github/workflows/manually.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ on:
1010
description: 'API level of the platform and system image'
1111
required: true
1212
default: '34'
13+
sdk-extension:
14+
description: 'SDK extension of a given api level'
1315
target:
1416
description: 'target of the system image - default, google_apis, google_apis_playstore, aosp_atd, google_atd, android-wear, android-wear-cn, android-tv, google-tv, andrdoid-automotive, android-automotive-playstore or android-desktop'
1517
required: true
@@ -68,6 +70,7 @@ jobs:
6870
api-level: ${{ github.event.inputs.api-level }}
6971
target: ${{ github.event.inputs.target }}
7072
arch: ${{ github.event.inputs.arch }}
73+
sdk-extension: ${{ github.event.inputs.sdk-extension }}
7174
profile: Galaxy Nexus
7275
emulator-options: ${{ github.event.inputs.emulator-options }}
7376
emulator-build: ${{ github.event.inputs.emulator-build }}

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,31 @@ jobs:
119119
script: ./gradlew connectedCheck
120120
```
121121
122+
If you need a specific [SDKExtension](https://developer.android.com/guide/sdk-extensions)
123+
124+
```yml
125+
jobs:
126+
test:
127+
runs-on: ubuntu-latest
128+
steps:
129+
- name: checkout
130+
uses: actions/checkout@v4
131+
132+
- name: Enable KVM
133+
run: |
134+
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
135+
sudo udevadm control --reload-rules
136+
sudo udevadm trigger --name-match=kvm
137+
138+
- name: run tests
139+
uses: reactivecircus/android-emulator-runner@v2
140+
with:
141+
api-level: 34
142+
sdk-extension: 9
143+
target: android-automotive
144+
script: ./gradlew connectedCheck
145+
```
146+
122147
We can significantly reduce emulator startup time by setting up AVD snapshot caching:
123148
124149
1. add a `gradle/actions/setup-gradle@v4` step for caching Gradle, more details see [#229](https://github.com/ReactiveCircus/android-emulator-runner/issues/229)
@@ -180,6 +205,7 @@ jobs:
180205
| **Input** | **Required** | **Default** | **Description** |
181206
|-|-|-|-|
182207
| `api-level` | Required | N/A | API level of the platform system image - e.g. 23 for Android Marshmallow, 29 for Android 10. **Minimum API level supported is 15**. |
208+
| `sdk-extension` | Optional | N/A | SDK extension of a given api level - e.g. 9 for Android API 34 it will translate to 34-ext9. Check https://developer.android.com/guide/sdk-extensions for more details. `-ext` should not be part of the input, **the input should be an integer**. |
183209
| `target` | Optional | `default` | Target of the system image - `default`, `google_apis`, `playstore`, `android-wear`, `android-wear-cn`, `android-tv`, `google-tv`, `aosp_atd`, `google_atd`, `andrdoid-automotive`, `android-automotive-playstore` or `android-desktop`. Note that `aosp_atd` and `google_atd` currently require the following: `api-level: 30`, `arch: x86` or `arch: arm64-v8` and `channel: canary`. |
184210
| `arch` | Optional | `x86` | CPU architecture of the system image - `x86`, `x86_64` or `arm64-v8a`. Note that `x86_64` image is only available for API 21+. `arm64-v8a` images require Android 4.2+ and are limited to fewer API levels (e.g. 30). |
185211
| `profile` | Optional | N/A | Hardware profile used for creating the AVD - e.g. `Nexus 6`. For a list of all profiles available, run `avdmanager list device`. |
@@ -243,5 +269,6 @@ These are some of the open-source projects using (or used) **Android Emulator Ru
243269
- [ACRA/acra](https://github.com/ACRA/acra/blob/master/.github/workflows/test.yml)
244270
- [bitfireAT/davx5-ose](https://github.com/bitfireAT/davx5-ose/blob/dev-ose/.github/workflows/test-dev.yml)
245271
- [robolectric/robolectric](https://github.com/robolectric/robolectric/blob/master/.github/workflows/tests.yml)
272+
- [home-assistant/android](https://github.com/home-assistant/android/blob/master/.github/workflows/pr.yml)
246273

247274
If you are using **Android Emulator Runner** and want your project included in the list, please feel free to open a pull request.

__tests__/input-validator.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,36 @@ describe('api-level validator tests', () => {
4444
});
4545
});
4646

47+
describe('sdk-extension validator tests', () => {
48+
it('Empty sdk-extension is acceptable, means default', () => {
49+
const func = () => {
50+
validator.checkSDKExtension('');
51+
};
52+
expect(func).not.toThrow();
53+
});
54+
55+
it('Throws if sdk-extension is not a number', () => {
56+
const func = () => {
57+
validator.checkSDKExtension('-ext9');
58+
};
59+
expect(func).toThrowError(`Unexpected SDKExtension: '-ext9'.`);
60+
});
61+
62+
it('Throws if sdk-extension is not an integer', () => {
63+
const func = () => {
64+
validator.checkSDKExtension('9.1');
65+
};
66+
expect(func).toThrowError(`Unexpected SDKExtension: '9.1'.`);
67+
});
68+
69+
it('Validates successfully with valid sdk-extension', () => {
70+
const func1 = () => {
71+
validator.checkSDKExtension('1');
72+
};
73+
expect(func1).not.toThrow();
74+
});
75+
});
76+
4777
describe('target validator tests', () => {
4878
it('Throws if target is unknown', () => {
4979
const func = () => {

action-types.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
inputs:
22
api-level:
33
type: integer
4+
sdk-extension:
5+
type: integer
46
target:
57
type: enum
68
allowed-values:

action.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ inputs:
88
api-level:
99
description: 'API level of the platform and system image - e.g. 23 for Android Marshmallow, 29 for Android 10'
1010
required: true
11+
sdk-extension:
12+
description: 'SDK extension of a given api level - e.g. 9 for Android API 34 it will translate to 34-ext9. Check https://developer.android.com/guide/sdk-extensions for more details. `-ext` should not be part of the input, the input should be an integer.'
13+
required: false
1114
target:
1215
description: 'target of the system image - default, google_apis, google_apis_playstore, aosp_atd, google_atd, android-wear, android-wear-cn, android-tv, google-tv, andrdoid-automotive, android-automotive-playstore or android-desktop'
1316
default: 'default'

lib/emulator-manager.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,18 @@ const fs = __importStar(require("fs"));
3838
/**
3939
* Creates and launches a new AVD instance with the specified configurations.
4040
*/
41-
function launchEmulator(apiLevel, target, arch, profile, cores, ramSize, heapSize, sdcardPathOrSize, diskSize, avdName, forceAvdCreation, emulatorBootTimeout, port, emulatorOptions, disableAnimations, disableSpellChecker, disableLinuxHardwareAcceleration, enableHardwareKeyboard) {
41+
function launchEmulator(apiLevel, sdkExtension, target, arch, profile, cores, ramSize, heapSize, sdcardPathOrSize, diskSize, avdName, forceAvdCreation, emulatorBootTimeout, port, emulatorOptions, disableAnimations, disableSpellChecker, disableLinuxHardwareAcceleration, enableHardwareKeyboard) {
4242
return __awaiter(this, void 0, void 0, function* () {
4343
try {
4444
console.log(`::group::Launch Emulator`);
45+
const apiTag = sdkExtension ? `${apiLevel}-ext${sdkExtension}` : `${apiLevel}`;
4546
// create a new AVD if AVD directory does not already exist or forceAvdCreation is true
4647
const avdPath = `${process.env.ANDROID_AVD_HOME}/${avdName}.avd`;
4748
if (!fs.existsSync(avdPath) || forceAvdCreation) {
4849
const profileOption = profile.trim() !== '' ? `--device '${profile}'` : '';
4950
const sdcardPathOrSizeOption = sdcardPathOrSize.trim() !== '' ? `--sdcard '${sdcardPathOrSize}'` : '';
5051
console.log(`Creating AVD.`);
51-
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}"`);
52+
yield exec.exec(`sh -c \\"echo no | avdmanager create avd --force -n "${avdName}" --abi '${target}/${arch}' --package 'system-images;android-${apiTag};${target};${arch}' ${profileOption} ${sdcardPathOrSizeOption}"`);
5253
}
5354
if (cores) {
5455
yield exec.exec(`sh -c \\"printf 'hw.cpu.ncore=${cores}\n' >> ${process.env.ANDROID_AVD_HOME}/"${avdName}".avd"/config.ini`);

lib/input-validator.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
11
"use strict";
22
Object.defineProperty(exports, "__esModule", { value: true });
3-
exports.checkDiskSize = exports.checkEmulatorBuild = exports.checkEnableHardwareKeyboard = exports.checkDisableLinuxHardwareAcceleration = exports.checkDisableSpellchecker = exports.checkDisableAnimations = exports.checkPort = exports.checkForceAvdCreation = exports.checkChannel = exports.checkArch = exports.checkTarget = exports.checkApiLevel = exports.PREVIEW_API_LEVELS = exports.MAX_PORT = exports.MIN_PORT = exports.VALID_CHANNELS = exports.VALID_ARCHS = exports.VALID_TARGETS = exports.MIN_API_LEVEL = void 0;
3+
exports.checkDiskSize = exports.checkEmulatorBuild = exports.checkEnableHardwareKeyboard = exports.checkDisableLinuxHardwareAcceleration = exports.checkDisableSpellchecker = exports.checkDisableAnimations = exports.checkPort = exports.checkForceAvdCreation = exports.checkChannel = exports.checkArch = exports.checkTarget = exports.checkSDKExtension = exports.checkApiLevel = exports.PREVIEW_API_LEVELS = exports.MAX_PORT = exports.MIN_PORT = exports.VALID_CHANNELS = exports.VALID_ARCHS = exports.VALID_TARGETS = exports.MIN_API_LEVEL = void 0;
44
exports.MIN_API_LEVEL = 15;
5-
exports.VALID_TARGETS = ['default', 'google_apis', 'aosp_atd', 'google_atd', 'google_apis_playstore', 'android-wear', 'android-wear-cn', 'android-tv', 'google-tv', 'andrdoid-automotive', 'android-automotive-playstore', 'android-desktop'];
5+
exports.VALID_TARGETS = [
6+
'default',
7+
'google_apis',
8+
'aosp_atd',
9+
'google_atd',
10+
'google_apis_playstore',
11+
'android-wear',
12+
'android-wear-cn',
13+
'android-tv',
14+
'google-tv',
15+
'andrdoid-automotive',
16+
'android-automotive-playstore',
17+
'android-desktop'
18+
];
619
exports.VALID_ARCHS = ['x86', 'x86_64', 'arm64-v8a'];
720
exports.VALID_CHANNELS = ['stable', 'beta', 'dev', 'canary'];
821
exports.MIN_PORT = 5554;
@@ -19,6 +32,15 @@ function checkApiLevel(apiLevel) {
1932
}
2033
}
2134
exports.checkApiLevel = checkApiLevel;
35+
function checkSDKExtension(sdkExtension) {
36+
// SDK extension can be empty - the default value
37+
if (sdkExtension) {
38+
if (isNaN(Number(sdkExtension)) || !Number.isInteger(Number(sdkExtension))) {
39+
throw new Error(`Unexpected SDKExtension: '${sdkExtension}'.`);
40+
}
41+
}
42+
}
43+
exports.checkSDKExtension = checkSDKExtension;
2244
function checkTarget(target) {
2345
if (!exports.VALID_TARGETS.includes(target)) {
2446
throw new Error(`Value for input.target '${target}' is unknown. Supported options: ${exports.VALID_TARGETS}.`);

lib/main.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ function run() {
6565
const apiLevel = core.getInput('api-level', { required: true });
6666
(0, input_validator_1.checkApiLevel)(apiLevel);
6767
console.log(`API level: ${apiLevel}`);
68+
// SDK extension
69+
const sdkExtension = core.getInput('sdk-extension');
70+
(0, input_validator_1.checkSDKExtension)(sdkExtension);
71+
if (sdkExtension) {
72+
console.log(`SDK extension: ${sdkExtension}`);
73+
}
6874
// target of the system image
6975
const targetInput = core.getInput('target');
7076
const target = targetInput == 'playstore' ? 'google_apis_playstore' : targetInput;
@@ -179,7 +185,7 @@ function run() {
179185
}));
180186
console.log(`::endgroup::`);
181187
// install SDK
182-
yield (0, sdk_installer_1.installAndroidSdk)(apiLevel, target, arch, channelId, emulatorBuild, ndkVersion, cmakeVersion);
188+
yield (0, sdk_installer_1.installAndroidSdk)(apiLevel, sdkExtension, target, arch, channelId, emulatorBuild, ndkVersion, cmakeVersion);
183189
// execute pre emulator launch script if set
184190
if (preEmulatorLaunchScripts !== undefined) {
185191
console.log(`::group::Run pre emulator launch script`);
@@ -198,7 +204,7 @@ function run() {
198204
console.log(`::endgroup::`);
199205
}
200206
// launch an emulator
201-
yield (0, emulator_manager_1.launchEmulator)(apiLevel, target, arch, profile, cores, ramSize, heapSize, sdcardPathOrSize, diskSize, avdName, forceAvdCreation, emulatorBootTimeout, port, emulatorOptions, disableAnimations, disableSpellchecker, disableLinuxHardwareAcceleration, enableHardwareKeyboard);
207+
yield (0, emulator_manager_1.launchEmulator)(apiLevel, sdkExtension, target, arch, profile, cores, ramSize, heapSize, sdcardPathOrSize, diskSize, avdName, forceAvdCreation, emulatorBootTimeout, port, emulatorOptions, disableAnimations, disableSpellchecker, disableLinuxHardwareAcceleration, enableHardwareKeyboard);
202208
// execute the custom script
203209
try {
204210
// move to custom working directory if set

lib/sdk-installer.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,13 @@ const CMDLINE_TOOLS_URL_LINUX = 'https://dl.google.com/android/repository/comman
4646
* Installs & updates the Android SDK for the macOS platform, including SDK platform for the chosen API level, latest build tools, platform tools, Android Emulator,
4747
* and the system image for the chosen API level, CPU arch, and target.
4848
*/
49-
function installAndroidSdk(apiLevel, target, arch, channelId, emulatorBuild, ndkVersion, cmakeVersion) {
49+
function installAndroidSdk(apiLevel, sdkExtension, target, arch, channelId, emulatorBuild, ndkVersion, cmakeVersion) {
5050
return __awaiter(this, void 0, void 0, function* () {
5151
try {
5252
console.log(`::group::Install Android SDK`);
5353
const isOnMac = process.platform === 'darwin';
5454
const isArm = process.arch === 'arm64';
55+
const apiTag = sdkExtension ? `${apiLevel}-ext${sdkExtension}` : `${apiLevel}`;
5556
const cmdlineToolsPath = `${process.env.ANDROID_HOME}/cmdline-tools`;
5657
if (!fs.existsSync(cmdlineToolsPath)) {
5758
console.log('Installing new cmdline-tools.');
@@ -68,7 +69,7 @@ function installAndroidSdk(apiLevel, target, arch, channelId, emulatorBuild, ndk
6869
// accept all Android SDK licenses
6970
yield exec.exec(`sh -c \\"yes | sdkmanager --licenses > /dev/null"`);
7071
console.log('Installing latest build tools, platform tools, and platform.');
71-
yield exec.exec(`sh -c \\"sdkmanager --install 'build-tools;${BUILD_TOOLS_VERSION}' platform-tools 'platforms;android-${apiLevel}'> /dev/null"`);
72+
yield exec.exec(`sh -c \\"sdkmanager --install 'build-tools;${BUILD_TOOLS_VERSION}' platform-tools 'platforms;android-${apiTag}'> /dev/null"`);
7273
console.log('Installing latest emulator.');
7374
yield exec.exec(`sh -c \\"sdkmanager --install emulator --channel=${channelId} > /dev/null"`);
7475
if (emulatorBuild) {
@@ -95,7 +96,7 @@ function installAndroidSdk(apiLevel, target, arch, channelId, emulatorBuild, ndk
9596
yield io.rmRF('emulator.zip');
9697
}
9798
console.log('Installing system images.');
98-
yield exec.exec(`sh -c \\"sdkmanager --install 'system-images;android-${apiLevel};${target};${arch}' --channel=${channelId} > /dev/null"`);
99+
yield exec.exec(`sh -c \\"sdkmanager --install 'system-images;android-${apiTag};${target};${arch}' --channel=${channelId} > /dev/null"`);
99100
if (ndkVersion) {
100101
console.log(`Installing NDK ${ndkVersion}.`);
101102
yield exec.exec(`sh -c \\"sdkmanager --install 'ndk;${ndkVersion}' --channel=${channelId} > /dev/null"`);

0 commit comments

Comments
 (0)