@@ -17,6 +17,59 @@ import type { SDK } from './sdk';
1717
1818const modulePrefix = 'native-run:android:utils:run' ;
1919
20+ export async function findAvailableEmulatorPort ( devices : readonly Device [ ] , start = 5554 , end = 5584 ) : Promise < number > {
21+ const debug = Debug ( `${ modulePrefix } :${ findAvailableEmulatorPort . name } ` ) ;
22+ const usedPorts = new Set < number > ( ) ;
23+
24+ for ( const d of devices ) {
25+ const m = d . serial . match ( / ^ e m u l a t o r - ( \d + ) $ / ) ;
26+ if ( m ) {
27+ usedPorts . add ( Number ( m [ 1 ] ) ) ;
28+ }
29+ }
30+
31+ for ( let port = start ; port <= end ; port += 2 ) {
32+ if ( ! usedPorts . has ( port ) ) {
33+ debug ( 'Available emulator port found: %d' , port ) ;
34+ return port ;
35+ }
36+ }
37+
38+ debug ( 'No available emulator ports found in range %d-%d; defaulting to 5554' , start , end ) ;
39+ return 5554 ;
40+ }
41+
42+ export function isLikelyEmulator ( device : Device ) : boolean {
43+ const serialEmu = / ^ e m u l a t o r - ( \d + ) $ / ;
44+
45+ if ( serialEmu . test ( device . serial ) ) {
46+ return true ;
47+ }
48+
49+ if ( device . type === 'emulator' ) {
50+ return true ;
51+ }
52+
53+ const props = device . properties || { } ;
54+ const deviceProp = ( props [ 'device' ] || '' ) . toLowerCase ( ) ;
55+ const productProp = ( props [ 'product' ] || '' ) . toLowerCase ( ) ;
56+ const model = ( device . model || '' ) . toLowerCase ( ) ;
57+
58+ if ( deviceProp . startsWith ( 'emu' ) || deviceProp . includes ( 'generic' ) ) {
59+ return true ;
60+ }
61+
62+ if ( productProp . includes ( 'sdk_gphone' ) || productProp . includes ( 'google_sdk' ) ) {
63+ return true ;
64+ }
65+
66+ if ( model . includes ( 'android_sdk' ) || model . includes ( 'sdk_gphone' ) ) {
67+ return true ;
68+ }
69+
70+ return false ;
71+ }
72+
2073export async function selectDeviceByTarget (
2174 sdk : SDK ,
2275 devices : readonly Device [ ] ,
@@ -34,7 +87,7 @@ export async function selectDeviceByTarget(
3487 return device ;
3588 }
3689
37- const emulatorDevices = devices . filter ( ( d ) => d . type === 'emulator' ) ;
90+ const emulatorDevices = devices . filter ( isLikelyEmulator ) ;
3891
3992 const pairAVD = async ( emulator : Device ) : Promise < [ Device , AVD | undefined ] > => {
4093 let avd : AVD | undefined ;
@@ -65,7 +118,9 @@ export async function selectDeviceByTarget(
65118
66119 if ( avd ) {
67120 debug ( 'AVD found by ID: %s' , avd . id ) ;
68- const device = await runEmulator ( sdk , avd , 5554 ) ; // TODO: 5554 will not always be available at this point
121+ const port = await findAvailableEmulatorPort ( devices ) ;
122+ debug ( 'Using emulator port: %d' , port ) ;
123+ const device = await runEmulator ( sdk , avd , port ) ;
69124 debug ( 'Emulator ready, running avd: %s on %s' , avd . id , device . serial ) ;
70125
71126 return device ;
0 commit comments