diff --git a/android-patches/common.gypi.patch b/android-patches/common.gypi.patch new file mode 100644 index 00000000000000..f62c7e3aa8c3da --- /dev/null +++ b/android-patches/common.gypi.patch @@ -0,0 +1,18 @@ +diff --git a/common.gypi b/common.gypi +index 5e39ad3f09..1e535f48a8 100644 +--- a/common.gypi ++++ b/common.gypi +@@ -520,11 +520,11 @@ + }], + ['_toolset=="host"', { + 'conditions': [ +- [ 'host_arch=="ia32"', { ++ [ 'host_arch=="ia32" or (target_arch=="ia32" or target_arch=="arm")', { + 'cflags': [ '-m32' ], + 'ldflags': [ '-m32' ], + }], +- [ 'host_arch=="x64"', { ++ [ 'host_arch=="x64" and (target_arch=="x64" or target_arch=="arm64")', { + 'cflags': [ '-m64' ], + 'ldflags': [ '-m64' ], + }], diff --git a/android-patches/trap-handler.h.patch b/android-patches/trap-handler.h.patch index f4f151f65261f1..9355894a01b124 100644 --- a/android-patches/trap-handler.h.patch +++ b/android-patches/trap-handler.h.patch @@ -1,26 +1,50 @@ ---- trap-handler.h 2022-08-11 09:01:23.384000000 +0800 -+++ fixed-trap-handler.h 2022-08-11 09:09:15.352000000 +0800 -@@ -17,23 +17,7 @@ +diff --git a/deps/v8/src/trap-handler/trap-handler.h b/deps/v8/src/trap-handler/trap-handler.h +index 74967a00c1..d4f3b40269 100644 +--- a/deps/v8/src/trap-handler/trap-handler.h ++++ b/deps/v8/src/trap-handler/trap-handler.h +@@ -17,45 +17,7 @@ namespace v8 { namespace internal { namespace trap_handler { - + -// X64 on Linux, Windows, MacOS, FreeBSD. -#if V8_HOST_ARCH_X64 && V8_TARGET_ARCH_X64 && \ - ((V8_OS_LINUX && !V8_OS_ANDROID) || V8_OS_WIN || V8_OS_DARWIN || \ - V8_OS_FREEBSD) -#define V8_TRAP_HANDLER_SUPPORTED true --// Arm64 (non-simulator) on Mac. --#elif V8_TARGET_ARCH_ARM64 && V8_HOST_ARCH_ARM64 && V8_OS_DARWIN +-// Arm64 (non-simulator) on Mac and Linux. +-#elif V8_TARGET_ARCH_ARM64 && V8_HOST_ARCH_ARM64 && \ +- (V8_OS_DARWIN || (V8_OS_LINUX && !V8_OS_ANDROID)) -#define V8_TRAP_HANDLER_SUPPORTED true -// Arm64 simulator on x64 on Linux, Mac, or Windows. +-// +-// The simulator case uses some inline assembly code, which cannot be +-// compiled with MSVC, so don't enable the trap handler in that case. +-// (MSVC #defines _MSC_VER, but so does Clang when targeting Windows, hence +-// the check for __clang__.) -#elif V8_TARGET_ARCH_ARM64 && V8_HOST_ARCH_X64 && \ -- (V8_OS_LINUX || V8_OS_DARWIN) +- (V8_OS_LINUX || V8_OS_DARWIN || V8_OS_WIN) && \ +- (!defined(_MSC_VER) || defined(__clang__)) +-#define V8_TRAP_HANDLER_VIA_SIMULATOR +-#define V8_TRAP_HANDLER_SUPPORTED true +-// Loong64 (non-simulator) on Linux. +-#elif V8_TARGET_ARCH_LOONG64 && V8_HOST_ARCH_LOONG64 && V8_OS_LINUX +-#define V8_TRAP_HANDLER_SUPPORTED true +-// Loong64 simulator on x64 on Linux +-#elif V8_TARGET_ARCH_LOONG64 && V8_HOST_ARCH_X64 && V8_OS_LINUX +-#define V8_TRAP_HANDLER_VIA_SIMULATOR +-#define V8_TRAP_HANDLER_SUPPORTED true +-// RISCV64 (non-simulator) on Linux. +-#elif V8_TARGET_ARCH_RISCV64 && V8_HOST_ARCH_RISCV64 && V8_OS_LINUX && \ +- !V8_OS_ANDROID +-#define V8_TRAP_HANDLER_SUPPORTED true +-// RISCV64 simulator on x64 on Linux +-#elif V8_TARGET_ARCH_RISCV64 && V8_HOST_ARCH_X64 && V8_OS_LINUX -#define V8_TRAP_HANDLER_VIA_SIMULATOR -#define V8_TRAP_HANDLER_SUPPORTED true -// Everything else is unsupported. -#else #define V8_TRAP_HANDLER_SUPPORTED false -#endif - - // Setup for shared library export. - #if defined(BUILDING_V8_SHARED) && defined(V8_OS_WIN) \ No newline at end of file + + #if V8_OS_ANDROID && V8_TRAP_HANDLER_SUPPORTED + // It would require some careful security review before the trap handler diff --git a/android-patches/v8.gyp.patch b/android-patches/v8.gyp.patch new file mode 100644 index 00000000000000..42eb16dcdedc64 --- /dev/null +++ b/android-patches/v8.gyp.patch @@ -0,0 +1,19 @@ +diff --git a/tools/v8_gypfiles/v8.gyp b/tools/v8_gypfiles/v8.gyp +index 1dd0b971d4..36b7c704dd 100644 +--- a/tools/v8_gypfiles/v8.gyp ++++ b/tools/v8_gypfiles/v8.gyp +@@ -1989,12 +1989,12 @@ + ], + }, { # 'OS!="win"' + 'conditions': [ +- ['_toolset == "host" and host_arch == "x64" or _toolset == "target" and target_arch=="x64"', { ++ ['_toolset == "host" and host_arch == "x64" and (target_arch == "x64" or target_arch == "arm64") or (_toolset == "target" and target_arch == "x64")', { + 'sources': [ + '<(V8_ROOT)/src/heap/base/asm/x64/push_registers_asm.cc', + ], + }], +- ['_toolset == "host" and host_arch == "ia32" or _toolset == "target" and target_arch=="ia32"', { ++ ['_toolset == "host" and host_arch == "x64" and (target_arch == "arm" or target_arch == "ia32") or (_toolset == "target" and target_arch == "ia32")', { + 'sources': [ + '<(V8_ROOT)/src/heap/base/asm/ia32/push_registers_asm.cc', + ], diff --git a/android_configure.py b/android_configure.py index 5cea0393f48a76..9b34f1a4ad48e4 100644 --- a/android_configure.py +++ b/android_configure.py @@ -5,9 +5,18 @@ # TODO: In next version, it will be a JSON file listing all the patches, and then it will iterate through to apply them. def patch_android(): print("- Patches List -") - print("[1] [deps/v8/src/trap-handler/trap-handler.h] related to https://github.com/nodejs/node/issues/36287") + print("[1] [common.gypi] related to cross-compiling for 32-bit architectures on 64-bit host") + print("[2] [deps/v8/src/trap-handler/trap-handler.h] related to https://github.com/nodejs/node/issues/36287") + print("[3] [tools/v8_gypfiles/v8.gyp] build correct push_registers_asm.cc when cross-compiling for 32-bit on 64-bit host") if platform.system() == "Linux": - os.system('patch -f ./deps/v8/src/trap-handler/trap-handler.h < ./android-patches/trap-handler.h.patch') + patches = [ + './android-patches/common.gypi.patch', + './android-patches/trap-handler.h.patch', + './android-patches/v8.gyp.patch', + ] + for patch in patches: + print(f"Applying patch: {patch}") + os.system('patch -p1 < ' + patch) print("\033[92mInfo: \033[0m" + "Tried to patch.") if platform.system() != "Linux" and platform.system() != "Darwin": diff --git a/test/common/index.js b/test/common/index.js index b8f5416c625e4c..7f8369c25f63bc 100644 --- a/test/common/index.js +++ b/test/common/index.js @@ -121,6 +121,7 @@ const isFreeBSD = process.platform === 'freebsd'; const isOpenBSD = process.platform === 'openbsd'; const isLinux = process.platform === 'linux'; const isMacOS = process.platform === 'darwin'; +const isAndroid = process.platform === 'android'; const isASan = process.config.variables.asan === 1; const isRiscv64 = process.arch === 'riscv64'; const isDebug = process.features.debug; @@ -891,6 +892,7 @@ const common = { isLinux, isOpenBSD, isMacOS, + isAndroid, isPi, isSunOS, isWindows, diff --git a/test/parallel/test-cluster-bind-privileged-port.js b/test/parallel/test-cluster-bind-privileged-port.js index 3ac36543a27ba8..d19786c2b455e5 100644 --- a/test/parallel/test-cluster-bind-privileged-port.js +++ b/test/parallel/test-cluster-bind-privileged-port.js @@ -26,7 +26,7 @@ const cluster = require('cluster'); const net = require('net'); const { readFileSync } = require('fs'); -if (common.isLinux) { +if (common.isLinux || common.isAndroid) { try { const unprivilegedPortStart = parseInt(readFileSync('/proc/sys/net/ipv4/ip_unprivileged_port_start')); if (unprivilegedPortStart <= 42) { diff --git a/test/parallel/test-cluster-shared-handle-bind-privileged-port.js b/test/parallel/test-cluster-shared-handle-bind-privileged-port.js index 5e04c8eea1a899..9475ae568fa157 100644 --- a/test/parallel/test-cluster-shared-handle-bind-privileged-port.js +++ b/test/parallel/test-cluster-shared-handle-bind-privileged-port.js @@ -37,7 +37,7 @@ if (process.getuid() === 0) // Some systems won't have port 42 set as a privileged port, in that // case, skip the test. -if (common.isLinux) { +if (common.isLinux || common.isAndroid) { const { readFileSync } = require('fs'); try { diff --git a/test/parallel/test-dgram-bind-fd.js b/test/parallel/test-dgram-bind-fd.js index daf7f8064bda45..76c2ce82dd2e1d 100644 --- a/test/parallel/test-dgram-bind-fd.js +++ b/test/parallel/test-dgram-bind-fd.js @@ -77,7 +77,7 @@ const BUFFER_SIZE = 4096; const sendBufferSize = socket.getSendBufferSize(); // note: linux will double the buffer size - const expectedBufferSize = common.isLinux ? + const expectedBufferSize = (common.isLinux || common.isAndroid) ? BUFFER_SIZE * 2 : BUFFER_SIZE; assert.strictEqual(recvBufferSize, expectedBufferSize); assert.strictEqual(sendBufferSize, expectedBufferSize); diff --git a/test/parallel/test-dgram-membership.js b/test/parallel/test-dgram-membership.js index ebfdaa9cb6325f..5f38a5d2d553e4 100644 --- a/test/parallel/test-dgram-membership.js +++ b/test/parallel/test-dgram-membership.js @@ -106,11 +106,12 @@ const setup = dgram.createSocket.bind(dgram, { type: 'udp4', reuseAddr: true }); // addSourceSpecificMembership with invalid groupAddress should throw { const socket = setup(); + const errCode = (common.isAndroid || common.isOpenBSD || common.isFreeBSD) ? 'ENOSYS' : 'EINVAL'; assert.throws(() => { socket.addSourceSpecificMembership(multicastAddress, '0'); }, { - code: 'EINVAL', - message: 'addSourceSpecificMembership EINVAL' + code: errCode, + message: `addSourceSpecificMembership ${errCode}` }); socket.close(); } @@ -144,11 +145,12 @@ const setup = dgram.createSocket.bind(dgram, { type: 'udp4', reuseAddr: true }); // dropSourceSpecificMembership with invalid UDP should throw { const socket = setup(); + const errCode = (common.isAndroid || common.isOpenBSD || common.isFreeBSD) ? 'ENOSYS' : 'EINVAL'; assert.throws(() => { socket.dropSourceSpecificMembership(multicastAddress, '0'); }, { - code: 'EINVAL', - message: 'dropSourceSpecificMembership EINVAL' + code: errCode, + message: `dropSourceSpecificMembership ${errCode}` }); socket.close(); } diff --git a/test/parallel/test-dgram-socket-buffer-size.js b/test/parallel/test-dgram-socket-buffer-size.js index fcc492a958215c..f6d9bda19e2041 100644 --- a/test/parallel/test-dgram-socket-buffer-size.js +++ b/test/parallel/test-dgram-socket-buffer-size.js @@ -114,7 +114,7 @@ function getExpectedError(type) { socket.setSendBufferSize(10000); // note: linux will double the buffer size - const expectedBufferSize = common.isLinux ? 20000 : 10000; + const expectedBufferSize = (common.isLinux || common.isAndroid) ? 20000 : 10000; assert.strictEqual(socket.getRecvBufferSize(), expectedBufferSize); assert.strictEqual(socket.getSendBufferSize(), expectedBufferSize); socket.close(); diff --git a/test/parallel/test-fs-readfile-eof.js b/test/parallel/test-fs-readfile-eof.js index d7f9e21c5bf158..c7ac867beaaa13 100644 --- a/test/parallel/test-fs-readfile-eof.js +++ b/test/parallel/test-fs-readfile-eof.js @@ -2,19 +2,19 @@ const common = require('../common'); if (common.isWindows || common.isAIX || common.isIBMi) - common.skip(`No /dev/stdin on ${process.platform}.`); + common.skip(`No /dev/fd/0 on ${process.platform}.`); const assert = require('assert'); const fs = require('fs/promises'); const childType = ['child-encoding', 'child-non-encoding']; if (process.argv[2] === childType[0]) { - fs.readFile('/dev/stdin', 'utf8').then((data) => { + fs.readFile('/dev/fd/0', 'utf8').then((data) => { process.stdout.write(data); }); return; } else if (process.argv[2] === childType[1]) { - fs.readFile('/dev/stdin').then((data) => { + fs.readFile('/dev/fd/0').then((data) => { process.stdout.write(data); }); return; diff --git a/test/parallel/test-fs-readfile-pipe-large.js b/test/parallel/test-fs-readfile-pipe-large.js index fa5fea3ca38826..4079cd6eddb163 100644 --- a/test/parallel/test-fs-readfile-pipe-large.js +++ b/test/parallel/test-fs-readfile-pipe-large.js @@ -4,13 +4,13 @@ const common = require('../common'); // Simulate `cat readfile.js | node readfile.js` if (common.isWindows || common.isAIX || common.isIBMi) - common.skip(`No /dev/stdin on ${process.platform}.`); + common.skip(`No /dev/fd/0 on ${process.platform}.`); const assert = require('assert'); const fs = require('fs'); if (process.argv[2] === 'child') { - fs.readFile('/dev/stdin', function(er, data) { + fs.readFile('/dev/fd/0', function(er, data) { assert.ifError(er); process.stdout.write(data); }); diff --git a/test/parallel/test-fs-readfile-pipe.js b/test/parallel/test-fs-readfile-pipe.js index 782265e8ce47b5..25087017a054df 100644 --- a/test/parallel/test-fs-readfile-pipe.js +++ b/test/parallel/test-fs-readfile-pipe.js @@ -25,13 +25,13 @@ const common = require('../common'); // Simulate `cat readfile.js | node readfile.js` if (common.isWindows || common.isAIX || common.isIBMi) - common.skip(`No /dev/stdin on ${process.platform}.`); + common.skip(`No /dev/fd/0 on ${process.platform}.`); const assert = require('assert'); const fs = require('fs'); if (process.argv[2] === 'child') { - fs.readFile('/dev/stdin', common.mustSucceed((data) => { + fs.readFile('/dev/fd/0', common.mustSucceed((data) => { process.stdout.write(data); })); return; diff --git a/test/parallel/test-fs-readfilesync-pipe-large.js b/test/parallel/test-fs-readfilesync-pipe-large.js index 60c7dccd1acaf2..ebff30d0ecc926 100644 --- a/test/parallel/test-fs-readfilesync-pipe-large.js +++ b/test/parallel/test-fs-readfilesync-pipe-large.js @@ -4,13 +4,13 @@ const common = require('../common'); // Simulate `cat readfile.js | node readfile.js` if (common.isWindows || common.isAIX || common.isIBMi) - common.skip(`No /dev/stdin on ${process.platform}.`); + common.skip(`No /dev/fd/0 on ${process.platform}.`); const assert = require('assert'); const fs = require('fs'); if (process.argv[2] === 'child') { - process.stdout.write(fs.readFileSync('/dev/stdin', 'utf8')); + process.stdout.write(fs.readFileSync('/dev/fd/0', 'utf8')); return; } diff --git a/test/parallel/test-fs-realpath-pipe.js b/test/parallel/test-fs-realpath-pipe.js index f637642ca21d67..a478657a57c55f 100644 --- a/test/parallel/test-fs-realpath-pipe.js +++ b/test/parallel/test-fs-realpath-pipe.js @@ -3,14 +3,14 @@ const common = require('../common'); if (common.isWindows || common.isAIX || common.isIBMi) - common.skip(`No /dev/stdin on ${process.platform}.`); + common.skip(`No /dev/fd/0 on ${process.platform}.`); const assert = require('assert'); const { spawnSync } = require('child_process'); for (const code of [ - `require('fs').realpath('/dev/stdin', (err, resolvedPath) => { + `require('fs').realpath('/dev/fd/0', (err, resolvedPath) => { if (err) { console.error(err); process.exit(1); @@ -20,7 +20,7 @@ for (const code of [ } });`, `try { - if (require('fs').realpathSync('/dev/stdin')) { + if (require('fs').realpathSync('/dev/fd/0')) { process.exit(2); } } catch (e) { diff --git a/test/parallel/test-process-constants-noatime.js b/test/parallel/test-process-constants-noatime.js index bd1a848ed7aa74..a4192a3a8eedf9 100644 --- a/test/parallel/test-process-constants-noatime.js +++ b/test/parallel/test-process-constants-noatime.js @@ -4,7 +4,7 @@ const common = require('../common'); const assert = require('assert'); const constants = require('fs').constants; -if (common.isLinux) { +if (common.isLinux || common.isAndroid) { assert('O_NOATIME' in constants); assert.strictEqual(constants.O_NOATIME, 0x40000); } else { diff --git a/test/sequential/test-fs-watch.js b/test/sequential/test-fs-watch.js index 8db27a79e33d0a..207021ddbf45a5 100644 --- a/test/sequential/test-fs-watch.js +++ b/test/sequential/test-fs-watch.js @@ -37,6 +37,7 @@ if (!isMainThread) { const expectFilePath = common.isWindows || common.isLinux || + common.isAndroid || common.isMacOS || common.isAIX; diff --git a/tools/v8_gypfiles/v8.gyp b/tools/v8_gypfiles/v8.gyp index f4e8dcf292d234..1dd0b971d49c1d 100644 --- a/tools/v8_gypfiles/v8.gyp +++ b/tools/v8_gypfiles/v8.gyp @@ -1322,7 +1322,7 @@ # Platforms that don't have Compare-And-Swap (CAS) support need to link atomic library # to implement atomic memory access. # Clang needs it for some atomic operations (https://clang.llvm.org/docs/Toolchain.html#atomics-library). - ['(OS=="linux" and clang==1) or (v8_current_cpu in ["mips64", "mips64el", "arm", "riscv64", "loong64"])', { + ['((OS=="linux" or OS=="android") and clang==1) or (v8_current_cpu in ["mips64", "mips64el", "ppc", "arm", "riscv64", "loong64"])', { 'link_settings': { 'libraries': ['-latomic', ], }, @@ -1466,6 +1466,7 @@ '<(V8_ROOT)/src/base/platform/platform-posix.h', '<(V8_ROOT)/src/base/platform/platform-posix-time.cc', '<(V8_ROOT)/src/base/platform/platform-posix-time.h', + '<(V8_ROOT)/src/base/platform/platform-linux.h', ], 'link_settings': { 'target_conditions': [