Skip to content

Commit 618bd03

Browse files
committed
Cache Android Frida clients when querying for apps
1 parent cab36cd commit 618bd03

File tree

1 file changed

+62
-8
lines changed

1 file changed

+62
-8
lines changed

src/interceptors/frida/frida-android-integration.ts

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -181,18 +181,72 @@ const getFridaStream = (hostId: string, deviceClient: DeviceClient) =>
181181
});
182182
});
183183

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+
}
186208

187209
const fridaStream = await getFridaStream(hostId, deviceClient);
210+
const fridaSession = await FridaJs.connect({ stream: fridaStream });
188211

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+
};
192222

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+
}
196250
}
197251

198252
// Various ports which we know that certain apps use for non-HTTP traffic that we

0 commit comments

Comments
 (0)