@@ -181,18 +181,72 @@ const getFridaStream = (hostId: string, deviceClient: DeviceClient) =>
181
181
} ) ;
182
182
} ) ;
183
183
184
- export async function getAndroidFridaTargets ( adbClient : AdbClient , hostId : string ) {
185
- const deviceClient = adbClient . getDevice ( hostId ) ;
184
+ const fridaSessionCache : Record < string , {
185
+ fridaSession : FridaJs . FridaSession ,
186
+ cleanup : ( ) => void ,
187
+ timeout : NodeJS . Timeout
188
+ } > = { } ;
189
+
190
+ const FRIDA_SESSION_IDLE_TIMEOUT = 30_000 ;
191
+
192
+ function clearFridaSessionCache ( hostId : string ) {
193
+ const cached = fridaSessionCache [ hostId ] ;
194
+ if ( cached ) {
195
+ clearTimeout ( cached . timeout ) ;
196
+ cached . cleanup ( ) ;
197
+ delete fridaSessionCache [ hostId ] ;
198
+ }
199
+ }
200
+
201
+ async function getOrCreateFridaSession ( hostId : string , deviceClient : DeviceClient ) {
202
+ let cached = fridaSessionCache [ hostId ] ;
203
+ if ( cached ) {
204
+ clearTimeout ( cached . timeout ) ;
205
+ cached . timeout = setTimeout ( ( ) => clearFridaSessionCache ( hostId ) , FRIDA_SESSION_IDLE_TIMEOUT ) ;
206
+ return { fridaSession : cached . fridaSession , wasCached : true } ;
207
+ }
186
208
187
209
const fridaStream = await getFridaStream ( hostId , deviceClient ) ;
210
+ const fridaSession = await FridaJs . connect ( { stream : fridaStream } ) ;
188
211
189
- const fridaSession = await FridaJs . connect ( {
190
- stream : fridaStream
191
- } ) ;
212
+ const timeout = setTimeout ( ( ) => clearFridaSessionCache ( hostId ) , FRIDA_SESSION_IDLE_TIMEOUT ) ;
213
+ const cleanup = ( ) => fridaSession . disconnect ( )
214
+ . catch ( ( ) => { } )
215
+ . finally ( ( ) => fridaStream . destroy ( ) ) ;
216
+
217
+ fridaSessionCache [ hostId ] = {
218
+ fridaSession,
219
+ cleanup,
220
+ timeout
221
+ } ;
192
222
193
- const apps = await fridaSession . enumerateApplications ( ) ;
194
- fridaSession . disconnect ( ) . catch ( ( ) => { } ) ;
195
- return apps ;
223
+ fridaStream . on ( 'error' , cleanup ) ;
224
+ return { fridaSession, wasCached : false } ;
225
+ }
226
+
227
+ export async function getAndroidFridaTargets ( adbClient : AdbClient , hostId : string ) : Promise < Array < {
228
+ pid : number | null ;
229
+ id : string ;
230
+ name : string ;
231
+ } > > {
232
+ const deviceClient = adbClient . getDevice ( hostId ) ;
233
+
234
+ let fridaSession : FridaJs . FridaSession ;
235
+ let wasCached : boolean = false ;
236
+
237
+ try {
238
+ ( { fridaSession, wasCached } = await getOrCreateFridaSession ( hostId , deviceClient ) ) ;
239
+ const apps = await fridaSession . enumerateApplications ( ) ;
240
+ return apps ;
241
+ } catch ( e ) {
242
+ clearFridaSessionCache ( hostId ) ;
243
+ if ( wasCached ) {
244
+ // When a cached session fails, we retry with a fresh one:
245
+ return getAndroidFridaTargets ( adbClient , hostId ) ;
246
+ } else {
247
+ throw e ;
248
+ }
249
+ }
196
250
}
197
251
198
252
// Various ports which we know that certain apps use for non-HTTP traffic that we
0 commit comments