@@ -3,6 +3,7 @@ import * as path from 'path';
33import * as adb from 'adbkit' ;
44
55import { reportError } from '../../error-tracking' ;
6+ import { delay } from '../../util' ;
67
78export const ANDROID_TEMP = '/data/local/tmp' ;
89export const SYSTEM_CA_PATH = '/system/etc/security/cacerts' ;
@@ -63,6 +64,15 @@ export const getConnectedDevices = batchCalls(async (adbClient: adb.AdbClient) =
6364 }
6465} ) ;
6566
67+ async function waitUntilAvailable ( adbClient : adb . AdbClient , deviceId : string , tries : number ) {
68+ while ( tries > 0 && ! ( await getConnectedDevices ( adbClient ) ) . includes ( deviceId ) ) {
69+ tries = tries - 1 ;
70+ await delay ( 500 ) ;
71+ }
72+
73+ if ( tries <= 0 ) throw new Error ( `Device ${ deviceId } not available via ADB` ) ;
74+ }
75+
6676export function stringAsStream ( input : string ) {
6777 const contentStream = new stream . Readable ( ) ;
6878 contentStream . _read = ( ) => { } ;
@@ -116,7 +126,12 @@ export async function getRootCommand(adbClient: adb.AdbClient, deviceId: string)
116126 // If no explicit root commands are available, try to restart adb in root
117127 // mode instead. If this works, *all* commands will run as root.
118128 // We prefer explicit "su" calls if possible, to limit access & side effects.
119- await adbClient . root ( deviceId ) . catch ( ( ) => console . log ) ;
129+ await adbClient . root ( deviceId ) . catch ( console . log ) ;
130+
131+ // Sometimes switching to root can disconnect ADB devices, so double-check
132+ // they're still here, and wait a few seconds for them to come back if not.
133+ await waitUntilAvailable ( adbClient , deviceId , 10 ) ;
134+
120135 const whoami = await run ( adbClient , deviceId , [ 'whoami' ] ) . catch ( console . log ) ;
121136
122137 return ( whoami || '' ) . trim ( ) === 'root'
0 commit comments