Skip to content

Commit cc854dc

Browse files
committed
Support Android devices without 'whoami'
Not clear how many of these there are, but there's at least one Android Studio emulator image (API 22) that doesn't include this, and it's easy to work around.
1 parent 0427184 commit cc854dc

File tree

1 file changed

+12
-12
lines changed

1 file changed

+12
-12
lines changed

src/interceptors/android/adb-commands.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -170,34 +170,34 @@ export async function getRootCommand(adbClient: Adb.DeviceClient): Promise<RootC
170170
const rootTestScriptPath = `${ANDROID_TEMP}/htk-root-test.sh`;
171171

172172
try {
173-
// Just running 'whoami' doesn't fully check certain tricky cases around how the root commands
174-
// handle multiple arguments etc. Pushing & running this script is an accurate test of which
175-
// root mechanisms will actually work on this device:
173+
// Just running 'id' doesn't fully check certain tricky cases around how the root commands handle
174+
// multiple arguments etc. N.b. whoami also doesn't exist on older devices. Pushing & running
175+
// this script is an accurate test of which root mechanisms will actually work on this device:
176176
let rootTestCommand = ['sh', rootTestScriptPath];
177177
try {
178178
await pushFile(adbClient, stringAsStream(`
179179
set -e # Fail on error
180-
whoami # Log the current user name, to confirm if we're root
180+
id # Log the current user details, to confirm if we're root
181181
`), rootTestScriptPath, 0o444);
182182
} catch (e) {
183183
console.log(`Couldn't write root test script to ${rootTestScriptPath}`, e);
184-
// Ok, so we can't write the test script, but let's still test for root via whoami directly,
184+
// Ok, so we can't write the test script, but let's still test for root directly,
185185
// because maybe if we get root then that won't be a problem
186-
rootTestCommand = ['whoami'];
186+
rootTestCommand = ['id'];
187187
}
188188

189-
// Run our whoami script with each of the possible root commands
189+
// Run our root test script with each of the possible root commands
190190
const rootCheckResults = await Promise.all(
191191
runAsRootCommands.map((runAsRoot) =>
192192
run(adbClient, runAsRoot(...rootTestCommand), { timeout: 1000 })
193193
.catch((e: any) => console.log(e.message ?? e))
194-
.then((whoami) => ({ cmd: runAsRoot, whoami }))
194+
.then((result) => ({ cmd: runAsRoot, result }))
195195
)
196196
)
197197

198-
// Filter to just commands that successfully printed 'root'
198+
// Filter to just commands that successfully printed 'uid=0(root)'
199199
const validRootCommands = rootCheckResults
200-
.filter((result) => (result.whoami || '').trim() === 'root')
200+
.filter((result) => (result.result || '').includes('uid=0(root)'))
201201
.map((result) => result.cmd);
202202

203203
if (validRootCommands.length >= 1) return validRootCommands[0];
@@ -214,11 +214,11 @@ export async function getRootCommand(adbClient: Adb.DeviceClient): Promise<RootC
214214
// they're still here, and wait a few seconds for them to come back if not.
215215

216216
await delay(500); // Wait, since they may not disconnect immediately
217-
const whoami = await waitUntil(250, 10, (): Promise<string | false> => {
217+
const idResult = await waitUntil(250, 10, (): Promise<string | false> => {
218218
return run(adbClient, rootTestCommand, { timeout: 1000 }).catch(() => false)
219219
}).catch(console.log);
220220

221-
return (whoami || '').trim() === 'root'
221+
return (idResult || '').includes('uid=0(root)')
222222
? (...cmd: string[]) => cmd // All commands now run as root
223223
: undefined; // Still not root, no luck.
224224
} catch (e) {

0 commit comments

Comments
 (0)