From 183bb9b2cf5cff34e2d837f6d21acfe2dd7ae919 Mon Sep 17 00:00:00 2001 From: gautam-jain-dev Date: Wed, 5 Aug 2026 16:40:19 +0530 Subject: [PATCH 1/2] feat: make the adb server port configurable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver always talked to adb on 5037. ADB.createADB() was called without options in six places, so appium-adb fell back to its default, and the appium:adbPort capability that callers already send was discarded — sessions logged it under "capabilities were provided, but are not recognized". Anyone running an adb server on another port (multiple servers on one machine, a sandboxed CI agent, a device farm host with per-device servers) could not use this driver. The port now comes from, in order: the appium:adbPort capability, the CDP_ADB_PORT environment variable, then adb's default of 5037. The environment variable is not redundant. The skip-welcome-* scripts run as separate processes launched via `appium driver run`, so they never see the session's capabilities; without it the browser setup would use the requested port while the onboarding walkthrough silently used 5037. Each script now also passes the resolved port into its UiAutomator2 session, so both halves address the same adb server. Co-Authored-By: Claude Fable 5 --- scripts/brave.js | 5 ++++- scripts/duckduckgo.js | 5 ++++- scripts/edge.js | 5 ++++- scripts/opera.js | 5 ++++- scripts/samsung.js | 5 ++++- src/adb.js | 20 +++++++++++++++++--- src/driver.js | 6 +++++- 7 files changed, 42 insertions(+), 9 deletions(-) diff --git a/scripts/brave.js b/scripts/brave.js index aaee196..18760cd 100755 --- a/scripts/brave.js +++ b/scripts/brave.js @@ -2,6 +2,7 @@ import { AndroidUiautomator2Driver } from 'appium-uiautomator2-driver'; import { ADB } from 'appium-adb'; +import { resolveAdbPort } from '../src/adb.js'; import log from '../src/logger.js'; import { waitForCondition } from 'asyncbox'; @@ -18,7 +19,8 @@ const common = { }; async function skipWelcomeBrave() { - const adb = await ADB.createADB(); + const adbPort = resolveAdbPort(); + const adb = await ADB.createADB({ adbPort }); await adb.adbExec(['shell', 'pm', 'clear', 'com.brave.browser']); // Suppress the first-run Welcome walkthrough (honored on emulators/debuggable builds; // harmless no-op elsewhere, where the UI walkthrough below still handles it) @@ -30,6 +32,7 @@ async function skipWelcomeBrave() { const caps = { platformName: "Android", "appium:automationName": "UiAutomator2", + "appium:adbPort": adbPort, "appium:deviceName": "Android Device", "appium:appPackage": "com.brave.browser", "appium:appActivity": "com.google.android.apps.chrome.Main", diff --git a/scripts/duckduckgo.js b/scripts/duckduckgo.js index 4eb0ae2..85e1029 100755 --- a/scripts/duckduckgo.js +++ b/scripts/duckduckgo.js @@ -2,6 +2,7 @@ import { AndroidUiautomator2Driver } from 'appium-uiautomator2-driver'; import { ADB } from 'appium-adb'; +import { resolveAdbPort } from '../src/adb.js'; import log from '../src/logger.js'; import { waitForCondition } from 'asyncbox'; @@ -18,12 +19,14 @@ const common = { }; async function skipWelcomeDuckDuckGo() { - const adb = await ADB.createADB(); + const adbPort = resolveAdbPort(); + const adb = await ADB.createADB({ adbPort }); await adb.adbExec(['shell', 'pm', 'clear', 'com.duckduckgo.mobile.android']); const driver = new AndroidUiautomator2Driver(); const caps = { platformName: "Android", "appium:automationName": "UiAutomator2", + "appium:adbPort": adbPort, "appium:deviceName": "Android Device", "appium:appPackage": "com.duckduckgo.mobile.android", "appium:appActivity": "com.duckduckgo.app.browser.BrowserActivity", diff --git a/scripts/edge.js b/scripts/edge.js index b32fe28..1aa0135 100755 --- a/scripts/edge.js +++ b/scripts/edge.js @@ -2,6 +2,7 @@ import { AndroidUiautomator2Driver } from 'appium-uiautomator2-driver'; import { ADB } from 'appium-adb'; +import { resolveAdbPort } from '../src/adb.js'; import log from '../src/logger.js'; import { waitForCondition } from 'asyncbox'; @@ -18,12 +19,14 @@ const common = { }; async function skipWelcomeEdge() { - const adb = await ADB.createADB(); + const adbPort = resolveAdbPort(); + const adb = await ADB.createADB({ adbPort }); await adb.adbExec(['shell', 'pm', 'clear', edge.pkg]); const driver = new AndroidUiautomator2Driver(); const caps = { platformName: "Android", "appium:automationName": "UiAutomator2", + "appium:adbPort": adbPort, "appium:deviceName": "Android Device", "appium:appPackage": edge.pkg, "appium:appActivity": edge.activity, diff --git a/scripts/opera.js b/scripts/opera.js index a6b36f0..9eda233 100755 --- a/scripts/opera.js +++ b/scripts/opera.js @@ -2,6 +2,7 @@ import { AndroidUiautomator2Driver } from 'appium-uiautomator2-driver'; import { ADB } from 'appium-adb'; +import { resolveAdbPort } from '../src/adb.js'; import log from '../src/logger.js'; import { waitForCondition } from 'asyncbox'; @@ -18,13 +19,15 @@ const common = { }; async function skipWelcomeOpera() { - const adb = await ADB.createADB(); + const adbPort = resolveAdbPort(); + const adb = await ADB.createADB({ adbPort }); await adb.adbExec(['shell', 'pm', 'clear', 'com.opera.browser']); //await adb.startApp(Object.assign({}, opera, common)); const driver = new AndroidUiautomator2Driver(); const caps = { platformName: "Android", "appium:automationName": "UiAutomator2", + "appium:adbPort": adbPort, "appium:deviceName": "Android Device", "appium:appPackage": "com.opera.browser", "appium:appActivity": "com.opera.android.BrowserActivity", diff --git a/scripts/samsung.js b/scripts/samsung.js index a37e54c..388f37c 100755 --- a/scripts/samsung.js +++ b/scripts/samsung.js @@ -2,6 +2,7 @@ import { AndroidUiautomator2Driver } from 'appium-uiautomator2-driver'; import { ADB } from 'appium-adb'; +import { resolveAdbPort } from '../src/adb.js'; import log from '../src/logger.js'; import { waitForCondition } from 'asyncbox'; @@ -18,12 +19,14 @@ const common = { }; async function skipWelcomeSamsung() { - const adb = await ADB.createADB(); + const adbPort = resolveAdbPort(); + const adb = await ADB.createADB({ adbPort }); await adb.adbExec(['shell', 'pm', 'clear', samsung.pkg]); const driver = new AndroidUiautomator2Driver(); const caps = { platformName: "Android", "appium:automationName": "UiAutomator2", + "appium:adbPort": adbPort, "appium:deviceName": "Android Device", "appium:appPackage": samsung.pkg, "appium:appActivity": samsung.activity, diff --git a/src/adb.js b/src/adb.js index 94ee16d..e7aa915 100644 --- a/src/adb.js +++ b/src/adb.js @@ -1,4 +1,4 @@ -import { ADB, getSdkRootFromEnv } from 'appium-adb'; +import { ADB, DEFAULT_ADB_PORT, getSdkRootFromEnv } from 'appium-adb'; import { fs } from '@appium/support'; import getPort from 'get-port'; import log from './logger'; @@ -16,14 +16,28 @@ const DEVTOOLS_SOCKET_MAP = { terrance: 'com.sec.android.app.sbrowser_devtools_remote', }; -export async function getAdb() { +/** + * Resolve the adb server port: explicit value wins, then CDP_ADB_PORT (used by + * the skip-welcome scripts, which run as separate processes and receive no + * capabilities), then adb's default. + */ +export function resolveAdbPort(adbPort) { + const candidate = adbPort ?? process.env.CDP_ADB_PORT; + const port = parseInt(candidate, 10); + return Number.isInteger(port) && port > 0 ? port : DEFAULT_ADB_PORT; +} + +export async function getAdb(adbPort) { try { if (!adb) { - adb = await ADB.createADB(); + const port = resolveAdbPort(adbPort); + log.info(`Using adb server port ${port}`); + adb = await ADB.createADB({ adbPort: port }); } } catch (e) { console.log(e); } + return adb; } export async function requireSdkRoot() { diff --git a/src/driver.js b/src/driver.js index 7dd86fc..9596eab 100644 --- a/src/driver.js +++ b/src/driver.js @@ -19,6 +19,10 @@ class AppiumCDPDriver extends BaseDriver { presence: true, isString: true, }, + adbPort: { + isNumber: false, + presence: false, + }, }; } @@ -26,7 +30,7 @@ class AppiumCDPDriver extends BaseDriver { console.log(await getConfig('local')); const res = await super.createSession(w3cCaps); const browser = w3cCaps.alwaysMatch['browserName']; - await getAdb(); + await getAdb(w3cCaps.alwaysMatch['appium:adbPort']); let port; if (browser === 'duckduckgo') { await startApplication(browser); From aeab0ffedc9710d279c2525b8fdb8224bbc2d245 Mon Sep 17 00:00:00 2001 From: gautam-jain-dev Date: Wed, 5 Aug 2026 16:45:18 +0530 Subject: [PATCH 2/2] test: cover adb port resolution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Locks in the default: with no capability and no environment variable — every existing caller — the port stays 5037, and any unusable value falls back to it rather than producing a broken -P argument. Co-Authored-By: Claude Fable 5 --- test/adb-port.spec.js | 51 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 test/adb-port.spec.js diff --git a/test/adb-port.spec.js b/test/adb-port.spec.js new file mode 100644 index 0000000..2921d80 --- /dev/null +++ b/test/adb-port.spec.js @@ -0,0 +1,51 @@ +const { expect } = require('chai'); +const { resolveAdbPort } = require('../build/src/adb.js'); + +const DEFAULT = 5037; + +describe('resolveAdbPort', function () { + let previous; + + beforeEach(function () { + previous = process.env.CDP_ADB_PORT; + delete process.env.CDP_ADB_PORT; + }); + + afterEach(function () { + if (previous === undefined) { + delete process.env.CDP_ADB_PORT; + } else { + process.env.CDP_ADB_PORT = previous; + } + }); + + it('defaults to 5037 when nothing is supplied', function () { + expect(resolveAdbPort(undefined)).to.equal(DEFAULT); + }); + + it('defaults to 5037 for unusable values', function () { + for (const value of [null, '', 'abc', 0, -1]) { + expect(resolveAdbPort(value)).to.equal(DEFAULT); + } + }); + + it('accepts the capability as a number or a string', function () { + expect(resolveAdbPort(5038)).to.equal(5038); + expect(resolveAdbPort('5038')).to.equal(5038); + }); + + it('falls back to CDP_ADB_PORT when no capability is given', function () { + process.env.CDP_ADB_PORT = '5040'; + expect(resolveAdbPort(undefined)).to.equal(5040); + }); + + it('prefers the capability over the environment variable', function () { + process.env.CDP_ADB_PORT = '5040'; + expect(resolveAdbPort(5041)).to.equal(5041); + }); + + it('ignores an unusable environment variable', function () { + process.env.CDP_ADB_PORT = 'nope'; + expect(resolveAdbPort(undefined)).to.equal(DEFAULT); + }); +});