@@ -215,16 +215,31 @@ async def _repair_avd_system_image_if_needed(avd_name: str, sdk_root: Path) -> b
215215 if not package :
216216 return False
217217
218+ def _is_system_image_dir_valid (path : Path ) -> bool :
219+ """
220+ Emulator needs a fully formed system-image package, not just a folder.
221+ package.xml is the key marker; *.img files indicate extracted payload.
222+ """
223+ if not path .exists () or not path .is_dir ():
224+ return False
225+ package_xml = path / "package.xml"
226+ if not package_xml .exists ():
227+ return False
228+ if any (path .glob ("*.img" )):
229+ return True
230+ # Some packages include nested image files; accept if known metadata exists.
231+ source_properties = path / "source.properties"
232+ return source_properties .exists ()
233+
218234 expected_dir = sdk_root / package .replace (";" , "/" )
219- if expected_dir . exists () and expected_dir . is_dir ( ):
235+ if _is_system_image_dir_valid ( expected_dir ):
220236 return False
221237
222238 sdkmanager = _find_sdkmanager (sdk_root )
223239 if not sdkmanager :
224240 return False
225241
226- if debug :
227- print (f"[installer][emulator] Repairing missing system image for '{ avd_name } ': { package } " )
242+ print (f"[installer][emulator] Repairing invalid/missing system image for '{ avd_name } ': { package } " )
228243
229244 loop = asyncio .get_event_loop ()
230245 if _is_windows ():
@@ -259,9 +274,46 @@ async def _repair_avd_system_image_if_needed(avd_name: str, sdk_root: Path) -> b
259274 )
260275
261276 if not success :
277+ print (f"[installer][emulator] System image repair install command failed for package: { package } " )
262278 return False
263279
264- return expected_dir .exists () and expected_dir .is_dir ()
280+ # If package still looks invalid, force reinstall by uninstalling first on macOS.
281+ if _is_darwin () and not _is_system_image_dir_valid (expected_dir ):
282+ env = _build_android_process_env (sdk_root )
283+ uninstall_cmd = [str (sdkmanager ), f"--sdk_root={ sdk_root } " , "--uninstall" , package ]
284+ install_cmd = [str (sdkmanager ), f"--sdk_root={ sdk_root } " , package ]
285+ try :
286+ print (f"[installer][emulator] Retrying repair via uninstall+install for package: { package } " )
287+ await loop .run_in_executor (
288+ None ,
289+ lambda : subprocess .run (
290+ uninstall_cmd ,
291+ capture_output = True ,
292+ text = True ,
293+ timeout = 600 ,
294+ env = env
295+ )
296+ )
297+ await loop .run_in_executor (
298+ None ,
299+ lambda : subprocess .run (
300+ install_cmd ,
301+ capture_output = True ,
302+ text = True ,
303+ timeout = 1800 ,
304+ env = env
305+ )
306+ )
307+ except Exception as e :
308+ print (f"[installer][emulator] uninstall+install repair failed: { e } " )
309+ return False
310+
311+ repaired = _is_system_image_dir_valid (expected_dir )
312+ if repaired :
313+ print (f"[installer][emulator] System image repair succeeded for package: { package } " )
314+ else :
315+ print (f"[installer][emulator] System image directory is still invalid after repair: { expected_dir } " )
316+ return repaired
265317
266318
267319def _get_host_arch () -> str :
@@ -491,8 +543,16 @@ async def _attempt_launch(cmd: list[str], wait_seconds: int, attempt_label: str)
491543 if returncode is not None and _is_darwin ():
492544 launch_hint = _read_file_tail (log_path ).lower ()
493545 if "not a valid directory" in launch_hint and "system-images" in launch_hint :
494- if debug :
495- print ("[installer][emulator] Launch failed due missing system-image directory. Attempting auto-repair." )
546+ print ("[installer][emulator] Launch failed due invalid system-image directory. Attempting auto-repair." )
547+ await send_response ({
548+ "action" : "status" ,
549+ "data" : {
550+ "category" : "AndroidEmulator" ,
551+ "name" : avd_name ,
552+ "status" : "installing" ,
553+ "comment" : "Repairing Android system image for this emulator..." ,
554+ }
555+ })
496556 repaired = await _repair_avd_system_image_if_needed (avd_name , sdk_root )
497557 if repaired :
498558 await _wait_for_avd_disk_ready (avd_name , timeout_seconds = 12 )
0 commit comments