briefcase icon indicating copy to clipboard operation
briefcase copied to clipboard

Use a stronger verification for the existence of an Android emulator system image

Open rmartin16 opened this issue 1 year ago • 4 comments

Describe the bug

As shown in https://github.com/beeware/briefcase/issues/1893, the current check in Briefcase for the existence of a system image is too weak. It only confirms an assumed filesystem path exists to verify a system image has been previously downloaded and is available.

In at least some failure modes, this filesystem path can exist while the system image is not wholly available. This failure mode will be quite difficult for users without Android SDK knowledge to recover from since Briefcase will attempt to use the system image with avdmanager to create an AVD...which will fail:

           >>> Running Command:                                                                                                                                    subprocess.py:827
           >>>     'C:\Users\user\AppData\Local\BeeWare\briefcase\Cache\tools\android_sdk\cmdline-tools\12.0\bin\avdmanager.bat' --verbose create avd --name     subprocess.py:827
           beePhone --abi x86_64 --package 'system-images;android-31;default;x86_64' --device pixel                                                                                 
           >>> Working Directory:                                                                                                                                  subprocess.py:827
           >>>     d:\temp\beeware\myapp                                                                                                                         subprocess.py:827
           >>> Environment Overrides:                                                                                                                              subprocess.py:827
           >>>     ANDROID_HOME=C:\Users\user\AppData\Local\BeeWare\briefcase\Cache\tools\android_sdk                                                            subprocess.py:827
           >>>     ANDROID_SDK_ROOT=C:\Users\user\AppData\Local\BeeWare\briefcase\Cache\tools\android_sdk                                                        subprocess.py:827
           >>>     JAVA_HOME=C:\Users\user\AppData\Local\BeeWare\briefcase\Cache\tools\java17                                                                    subprocess.py:827
           >>>     XDG_CONFIG_HOME=None                                                                                                                            subprocess.py:827
[22:11:24] >>> Command Output:                                                                                                                                     subprocess.py:827
           >>>     Loading local repository...                                                                                                                     subprocess.py:827
           >>>     [=========                              ] 25% Loading local repository...                                                                       subprocess.py:827
           >>>     [=========                              ] 25% Fetch remote repository...                                                                        subprocess.py:827
           >>>     [=======================================] 100% Fetch remote repository...                                                                       subprocess.py:827
           >>>                                                                                                                                                     subprocess.py:827
           >>>     Error: Package path is not valid. Valid system image paths are:                                                                                 subprocess.py:827
           >>>     null                                                                                                                                            subprocess.py:827
           >>> Return code: 1                                                                                                                                      subprocess.py:827
           Creating Android emulator beePhone... errored                                                                                                         android_sdk.py:1188

Steps to reproduce

The error can be manufactured by simply deleting the contents of the system image directory within the Android SDK and then attempting to use Briefcase to create a new AVD to run with the emulator.

Expected behavior

Briefcase's check for a system image should align with avdmanager's conclusion about the availability of a system image. My guess is avdmanager is using a check similar to below to ensure a specific system image is available.

> ~/.cache/briefcase/tools/android_sdk/cmdline-tools/12.0/bin/sdkmanager --list_installed
[=======================================] 100% Fetch remote repository...       
Installed packages:
  Path                                    | Version | Description                    | Location                               
  -------                                 | ------- | -------                        | -------                                
  emulator                                | 34.2.15 | Android Emulator               | emulator                               
  platform-tools                          | 35.0.1  | Android SDK Platform-Tools     | platform-tools                         
  system-images;android-31;default;x86_64 | 5       | Intel x86_64 Atom System Image | system-images/android-31/default/x86_64

Ideally, though, perhaps, we'd have a more machine-parseable version of this output...

Screenshots

No response

Environment

  • Operating System: Win 11
  • Python version: 3.11
  • Software versions:
    • Briefcase: 0.3.19

Logs

https://github.com/user-attachments/files/16073483/briefcase.2024_07_02-22_11_24.run.log

Additional context

No response

rmartin16 avatar Jul 03 '24 16:07 rmartin16

Agreed; more broadly, we should probably have checksum validation for any download where we're in a position to provide it (especially the stub binaries and support packages)

freakboy3742 avatar Jul 11 '24 08:07 freakboy3742

especially the stub binaries and support packages

This would definitely be a good first start; as we are leveraging GitHub for attesting PyPI package artifacts, we could probably do the same here to verify authenticity and integrity of Briefcase's artifacts. And Standalone Python may be amenable to a PR to publish attestations as well.

rmartin16 avatar Jul 11 '24 23:07 rmartin16

In at least some failure modes, this filesystem path can exist while the system image is not wholly available.

The download is very large and is likely to be interrupted, so this is quite a common failure mode. It happened to at least 2 people at PyCon US this year, and there's no way for them to recover without expert help.

My guess is avdmanager is using a check similar to below to ensure a specific system image is available.

> ~/.cache/briefcase/tools/android_sdk/cmdline-tools/12.0/bin/sdkmanager --list_installed

~~I think we actually used to do this in an older version of Briefcase, but we've since reduced the number of sdkmanager calls because they were relatively slow.~~ Actually no, it looks like we only ever passed the --list_installed output through for debug logging, we never actually parsed it.

Maybe we can replicate whatever sdkmanager does to check for the system image being fully installed, e.g. I think there might be a metadata file which doesn't get written until the installation succeeds.

mhsmith avatar May 21 '25 14:05 mhsmith

To clarify the scope here - the goal is to:

  1. Add a utility method to the Android SDK integration tooling that can invoke sdkmanager --list_installed, and get back a list of installed APIs (possibly filtering that list of APIs to only include system images)
  2. Integrate a check that the required system image is available before trying to create an AVD with that system image.

There is some overlap with #737 - that ticket also requires parsing the list of installed system images so that the list of available options can be presented to the user. That ticket potentially also involves parsing the same list, but of available images, so that the user can choose a base image that isn't currently installed.

freakboy3742 avatar Jul 08 '25 23:07 freakboy3742