@@ -35,6 +35,7 @@ import {
3535 ANDROID_SNAPSHOT_HELPER_DEVICE_RETIREMENT_TIMEOUT_MS ,
3636 ANDROID_SNAPSHOT_HELPER_HOST_PROCESS_EXIT_GRACE_MS ,
3737 getAndroidSnapshotHelperSessionDeviceKey ,
38+ hasAndroidSnapshotHelperProcessEnded ,
3839 observeAndroidSnapshotHelperProcessExit ,
3940 recoverAndroidSnapshotHelperRetirement ,
4041 recordAndroidSnapshotHelperRelease ,
@@ -137,11 +138,16 @@ async function resolveAndroidSnapshotHelperSession(params: {
137138 resolved : AndroidSnapshotHelperResolvedCaptureOptions ;
138139} ) : Promise < AndroidSnapshotHelperSession | undefined > {
139140 const { deviceKey, identity, options, resolved } = params ;
140- let session = sessions . get ( deviceKey ) ;
141- if ( session && session . identity !== identity ) {
142- await stopAndroidSnapshotHelperSession ( deviceKey ) ;
143- session = undefined ;
141+ const cached = sessions . get ( deviceKey ) ;
142+ const reusable = cached !== undefined && isReusableAndroidSnapshotHelperSession ( cached , identity ) ;
143+ if ( cached && ! reusable ) {
144+ await stopAndroidSnapshotHelperSession ( deviceKey , {
145+ // A process that already exited cannot answer the forwarded port: the forward is all that is
146+ // left of it, so there is nothing to quit gracefully.
147+ force : hasAndroidSnapshotHelperProcessEnded ( cached . process ) ,
148+ } ) ;
144149 }
150+ let session = reusable ? cached : undefined ;
145151 if ( ! session ) {
146152 try {
147153 session = await startAndroidSnapshotHelperSession ( {
@@ -167,6 +173,19 @@ async function resolveAndroidSnapshotHelperSession(params: {
167173 return session ;
168174}
169175
176+ /**
177+ * A cached session is worth writing to only while it belongs to this helper build and its
178+ * instrumentation process is still running. The helper binds its session socket inside that
179+ * process, so a process that has exited has nobody left to accept on the forwarded port: the
180+ * command would die on a dead socket and fall back, instead of starting a helper that can answer.
181+ */
182+ function isReusableAndroidSnapshotHelperSession (
183+ session : AndroidSnapshotHelperSession ,
184+ identity : string ,
185+ ) : boolean {
186+ return session . identity === identity && ! hasAndroidSnapshotHelperProcessEnded ( session . process ) ;
187+ }
188+
170189async function startAndroidSnapshotHelperSession ( params : {
171190 deviceKey : string ;
172191 identity : string ;
0 commit comments