Repository: ReactiveCircus/android-emulator-runner
Pull request #254 (2022-07-11 22:50:52)

Auto detect hardware acceleration on Linux
### Description
Currently, this action disables hardware acceleration on Linux by default. This pull request adds an automatic detection of hardware acceleration on Linux. It does so by checking if /dev/kvm exists and accessible.

On GitHub hosted Linux runners, this introduces no behavior change as KVM is not supported there. However, we([BuildJet](https://buildjet.com/for-github-actions)) run a hosted GitHub Actions runner service which does support KVM on Linux. This change will help our customers to benefit from hardware acceleration on Linux.


Patch:
diff --git a/action.yml b/action.yml
index 12ae7a1..9c5b36d 100644
--- a/action.yml
+++ b/action.yml
@@ -43,8 +43,8 @@ inputs:
     description: 'whether to disable spellchecker - `true` or `false`'
     default: 'false'
   disable-linux-hw-accel:
-    description: 'whether to disable hardware acceleration on Linux machines - `true` or `false`'
-    default: 'true'
+    description: 'whether to disable hardware acceleration on Linux machines - `true` or `false` or `auto`'
+    default: 'auto'
   enable-hw-keyboard:
     description: 'whether to enable hardware keyboard - `true` or `false`.'
     default: 'false'
diff --git a/lib/input-validator.js b/lib/input-validator.js
index a7bbabe..95959a5 100644
--- a/lib/input-validator.js
+++ b/lib/input-validator.js
@@ -51,8 +51,8 @@ function checkDisableSpellchecker(disableSpellchecker) {
 }
 exports.checkDisableSpellchecker = checkDisableSpellchecker;
 function checkDisableLinuxHardwareAcceleration(disableLinuxHardwareAcceleration) {
-    if (!isValidBoolean(disableLinuxHardwareAcceleration)) {
-        throw new Error(`Input for input.disable-linux-hw-accel should be either 'true' or 'false'.`);
+    if (!(isValidBoolean(disableLinuxHardwareAcceleration) || disableLinuxHardwareAcceleration === 'auto')) {
+        throw new Error(`Input for input.disable-linux-hw-accel should be either 'true' or 'false' or 'auto'.`);
     }
 }
 exports.checkDisableLinuxHardwareAcceleration = checkDisableLinuxHardwareAcceleration;
diff --git a/lib/main.js b/lib/main.js
index 1ac0a0d..1ccc06d 100644
--- a/lib/main.js
+++ b/lib/main.js
@@ -35,14 +35,22 @@ const emulator_manager_1 = require("./emulator-manager");
 const exec = __importStar(require("@actions/exec"));
 const script_parser_1 = require("./script-parser");
 const channel_id_mapper_1 = require("./channel-id-mapper");
+const fs_1 = require("fs");
 function run() {
     return __awaiter(this, void 0, void 0, function* () {
         try {
             console.log(`::group::Configure emulator`);
+            let linuxSupportKVM = false;
             // only support running on macOS or Linux
             if (process.platform !== 'darwin') {
                 if (process.platform === 'linux') {
-                    console.warn(`You're running a Linux VM where hardware acceleration is not available. Please consider using a macOS VM instead to take advantage of native hardware acceleration support provided by HAXM.`);
+                    try {
+                        fs_1.accessSync('/dev/kvm', fs_1.constants.R_OK | fs_1.constants.W_OK);
+                        linuxSupportKVM = true;
+                    }
+                    catch (_a) {
+                        console.warn(`You're running a Linux VM where hardware acceleration is not available. Please consider using a macOS VM instead to take advantage of native hardware acceleration support provided by HAXM.`);
+                    }
                 }
                 else {
                     throw new Error('Unsupported virtual machine: please use either macos or ubuntu VM.');
@@ -102,8 +110,11 @@ function run() {
             const disableSpellchecker = disableSpellcheckerInput === 'true';
             console.log(`disable spellchecker: ${disableSpellchecker}`);
             // disable linux hardware acceleration
-            const disableLinuxHardwareAccelerationInput = core.getInput('disable-linux-hw-accel');
+            let disableLinuxHardwareAccelerationInput = core.getInput('disable-linux-hw-accel');
             input_validator_1.checkDisableLinuxHardwareAcceleration(disableLinuxHardwareAccelerationInput);
+            if (disableLinuxHardwareAccelerationInput === 'auto' && process.platform === 'linux') {
+                disableLinuxHardwareAccelerationInput = linuxSupportKVM ? 'false' : 'true';
+            }
             const disableLinuxHardwareAcceleration = disableLinuxHardwareAccelerationInput === 'true';
             console.log(`disable Linux hardware acceleration: ${disableLinuxHardwareAcceleration}`);
             // enable hardware keyboard
diff --git a/src/input-validator.ts b/src/input-validator.ts
index cdafa7f..7cf1e1b 100644
--- a/src/input-validator.ts
+++ b/src/input-validator.ts
@@ -49,8 +49,8 @@ export function checkDisableSpellchecker(disableSpellchecker: string): void {
 }
 
 export function checkDisableLinuxHardwareAcceleration(disableLinuxHardwareAcceleration: string): void {
-  if (!isValidBoolean(disableLinuxHardwareAcceleration)) {
-    throw new Error(`Input for input.disable-linux-hw-accel should be either 'true' or 'false'.`);
+  if (!(isValidBoolean(disableLinuxHardwareAcceleration) || disableLinuxHardwareAcceleration === 'auto')) {
+    throw new Error(`Input for input.disable-linux-hw-accel should be either 'true' or 'false' or 'auto'.`);
   }
 }
 
diff --git a/src/main.ts b/src/main.ts
index 13fd802..63d34c6 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -17,16 +17,23 @@ import { launchEmulator, killEmulator } from './emulator-manager';
 import * as exec from '@actions/exec';
 import { parseScript } from './script-parser';
 import { getChannelId } from './channel-id-mapper';
+import { accessSync, constants } from 'fs';
 
 async function run() {
   try {
     console.log(`::group::Configure emulator`);
+    let linuxSupportKVM = false;
     // only support running on macOS or Linux
     if (process.platform !== 'darwin') {
       if (process.platform === 'linux') {
-        console.warn(
-          `You're running a Linux VM where hardware acceleration is not available. Please consider using a macOS VM instead to take advantage of native hardware acceleration support provided by HAXM.`
-        );
+        try {
+          accessSync('/dev/kvm', constants.R_OK | constants.W_OK);
+          linuxSupportKVM = true;
+        } catch {
+          console.warn(
+            `You're running a Linux VM where hardware acceleration is not available. Please consider using a macOS VM instead to take advantage of native hardware acceleration support provided by HAXM.`
+          );
+        }
       } else {
         throw new Error('Unsupported virtual machine: please use either macos or ubuntu VM.');
       }
@@ -100,8 +107,11 @@ async function run() {
     console.log(`disable spellchecker: ${disableSpellchecker}`);
 
     // disable linux hardware acceleration
-    const disableLinuxHardwareAccelerationInput = core.getInput('disable-linux-hw-accel');
+    let disableLinuxHardwareAccelerationInput = core.getInput('disable-linux-hw-accel');
     checkDisableLinuxHardwareAcceleration(disableLinuxHardwareAccelerationInput);
+    if (disableLinuxHardwareAccelerationInput === 'auto' && process.platform === 'linux') {
+      disableLinuxHardwareAccelerationInput = linuxSupportKVM ? 'false' : 'true';
+    }
     const disableLinuxHardwareAcceleration = disableLinuxHardwareAccelerationInput === 'true';
     console.log(`disable Linux hardware acceleration: ${disableLinuxHardwareAcceleration}`);
 


Test patch:
diff --git a/__tests__/input-validator.test.ts b/__tests__/input-validator.test.ts
index 5c52a2c..ba7e20e 100644
--- a/__tests__/input-validator.test.ts
+++ b/__tests__/input-validator.test.ts
@@ -211,10 +211,10 @@ describe('disable-linux-hw-accel validator tests', () => {
     const func = () => {
       validator.checkDisableLinuxHardwareAcceleration('yes');
     };
-    expect(func).toThrowError(`Input for input.disable-linux-hw-accel should be either 'true' or 'false'.`);
+    expect(func).toThrowError(`Input for input.disable-linux-hw-accel should be either 'true' or 'false' or 'auto'.`);
   });
 
-  it('Validates successfully if disable-linux-hw-accel is either true or false', () => {
+  it('Validates successfully if disable-linux-hw-accel is either true or false or auto', () => {
     const func1 = () => {
       validator.checkDisableLinuxHardwareAcceleration('true');
     };
@@ -224,6 +224,11 @@ describe('disable-linux-hw-accel validator tests', () => {
       validator.checkDisableLinuxHardwareAcceleration('false');
     };
     expect(func2).not.toThrow();
+
+    const func3 = () => {
+      validator.checkDisableLinuxHardwareAcceleration('auto');
+    };
+    expect(func3).not.toThrow();
   });
 });