Skip to content

Commit dd75695

Browse files
committed
Handle any root-detect crashes, and clean up our script after completion
1 parent 9cdb154 commit dd75695

File tree

1 file changed

+51
-41
lines changed

1 file changed

+51
-41
lines changed

src/interceptors/android/adb-commands.ts

Lines changed: 51 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -167,57 +167,67 @@ const runAsRootCommands = [
167167
type RootCmd = (...cmd: string[]) => string[];
168168

169169
export async function getRootCommand(adbClient: Adb.DeviceClient): Promise<RootCmd | undefined> {
170-
// Just running 'whoami' doesn't fully check certain tricky cases around how the root commands
171-
// handle multiple arguments etc. Pushing & running this script is an accurate test of which
172-
// root mechanisms will actually work on this device:
173170
const rootTestScriptPath = `${ANDROID_TEMP}/htk-root-test.sh`;
174-
let rootTestCommand = ['sh', rootTestScriptPath];
171+
175172
try {
176-
await pushFile(adbClient, stringAsStream(`
177-
set -e # Fail on error
178-
whoami # Log the current user name, to confirm if we're root
179-
`), rootTestScriptPath, 0o444);
180-
} catch (e) {
181-
console.log(`Couldn't write root test script to ${rootTestScriptPath}`, e);
182-
// Ok, so we can't write the test script, but let's still test for root via whoami directly,
183-
// because maybe if we get root then that won't be a problem
184-
rootTestCommand = ['whoami'];
185-
}
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:
176+
let rootTestCommand = ['sh', rootTestScriptPath];
177+
try {
178+
await pushFile(adbClient, stringAsStream(`
179+
set -e # Fail on error
180+
whoami # Log the current user name, to confirm if we're root
181+
`), rootTestScriptPath, 0o444);
182+
} catch (e) {
183+
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,
185+
// because maybe if we get root then that won't be a problem
186+
rootTestCommand = ['whoami'];
187+
}
186188

187-
// Run our whoami script with each of the possible root commands
188-
const rootCheckResults = await Promise.all(
189-
runAsRootCommands.map((runAsRoot) =>
190-
run(adbClient, runAsRoot(...rootTestCommand), { timeout: 1000 }).catch(console.log)
191-
.then((whoami) => ({ cmd: runAsRoot, whoami }))
189+
// Run our whoami script with each of the possible root commands
190+
const rootCheckResults = await Promise.all(
191+
runAsRootCommands.map((runAsRoot) =>
192+
run(adbClient, runAsRoot(...rootTestCommand), { timeout: 1000 }).catch(console.log)
193+
.then((whoami) => ({ cmd: runAsRoot, whoami }))
194+
)
192195
)
193-
)
194196

195-
// Filter to just commands that successfully printed 'root'
196-
const validRootCommands = rootCheckResults
197-
.filter((result) => (result.whoami || '').trim() === 'root')
198-
.map((result) => result.cmd);
197+
// Filter to just commands that successfully printed 'root'
198+
const validRootCommands = rootCheckResults
199+
.filter((result) => (result.whoami || '').trim() === 'root')
200+
.map((result) => result.cmd);
199201

200-
if (validRootCommands.length >= 1) return validRootCommands[0];
202+
if (validRootCommands.length >= 1) return validRootCommands[0];
201203

202-
// If no explicit root commands are available, try to restart adb in root
203-
// mode instead. If this works, *all* commands will run as root.
204-
// We prefer explicit "su" calls if possible, to limit access & side effects.
205-
await adbClient.root().catch((e: any) => {
206-
if (isErrorLike(e) && e.message?.includes("adbd is already running as root")) return;
207-
else console.log(e);
208-
});
204+
// If no explicit root commands are available, try to restart adb in root
205+
// mode instead. If this works, *all* commands will run as root.
206+
// We prefer explicit "su" calls if possible, to limit access & side effects.
207+
await adbClient.root().catch((e: any) => {
208+
if (isErrorLike(e) && e.message?.includes("adbd is already running as root")) return;
209+
else console.log(e);
210+
});
209211

210-
// Sometimes switching to root can disconnect ADB devices, so double-check
211-
// they're still here, and wait a few seconds for them to come back if not.
212+
// Sometimes switching to root can disconnect ADB devices, so double-check
213+
// they're still here, and wait a few seconds for them to come back if not.
212214

213-
await delay(500); // Wait, since they may not disconnect immediately
214-
const whoami = await waitUntil(250, 10, (): Promise<string | false> => {
215-
return run(adbClient, rootTestCommand, { timeout: 1000 }).catch(() => false)
216-
}).catch(console.log);
215+
await delay(500); // Wait, since they may not disconnect immediately
216+
const whoami = await waitUntil(250, 10, (): Promise<string | false> => {
217+
return run(adbClient, rootTestCommand, { timeout: 1000 }).catch(() => false)
218+
}).catch(console.log);
217219

218-
return (whoami || '').trim() === 'root'
219-
? (...cmd: string[]) => cmd // All commands now run as root
220-
: undefined; // Still not root, no luck.
220+
return (whoami || '').trim() === 'root'
221+
? (...cmd: string[]) => cmd // All commands now run as root
222+
: undefined; // Still not root, no luck.
223+
} catch (e) {
224+
console.error(e);
225+
reportError('ADB root check crashed');
226+
return undefined;
227+
} finally {
228+
// Try to clean up the root test script, just to be tidy
229+
run(adbClient, ['rm', '-f', rootTestScriptPath]).catch(() => {});
230+
}
221231
}
222232

223233
export async function hasCertInstalled(

0 commit comments

Comments
 (0)