Surface API 33-37 and 16 KB-page system images#397
Merged
Conversation
Closes google#392 (Android 16 / SDK 36). emu-docker list silently dropped every API >= 33. Two collaborating issues caused it: 1. SysImgInfo set self.letter from API_LETTER_MAPPING which stopped at "32": "S"; for any newer API the codename branch fell through to self.letter = "A" ("unknown code"). 2. get_images_info filtered with `info.letter >= MIN_REL_X64` ("O"), so the "A" sentinel made every API 33+ image fail string compare and disappear from the listing. The new system-image axis introduced at API 36 -- 16 KB page-size variants -- was unhandled in three places: a. SDK XML (emu_downloads_menu): the <tag><id> element can be either google_apis or page_size_16kb, and pre-release CANARY entries carry multiple <tag> elements. The path is the only deterministic source for (sort, is_16k); the zip lives under sys-img/<sort_base>/ where sort_base strips the trailing _ps16k. b. source.properties parsing (android_release_zip.SystemImageReleaseZip): SystemImage.TagId is comma-joined for 16 KB images ("google_apis,page_size_16kb"); the previous tag()/short_tag() KeyError'd on the joined string. c. Image naming: 4 KB and 16 KB variants of the same (api, sort, abi) need distinct docker image tags; the sys-img Dockerfile carries a qemu.is_16k label so the emulator layer can detect the variant from the base-image labels. Changes: - Bump SYSIMG_REPOS to sys-img2-5.xml (matches what the SDK Manager uses; -5 is what newer API entries land in first). - Extend API_LETTER_MAPPING with 33: T, 34: U, 35: V, 36: B, 37: C. - Replace MIN_REL_I386 / MIN_REL_X64 (letter strings) with MIN_API_I386 / MIN_API_X64 (ints), and filter on a new api_major attribute parsed from the api-level string with a regex (handles "36", "36.0", "36.1", "37.0", "36x"). - Letter fallback: exact api lookup -> api_major lookup -> the api string itself (no more silent "A" filter trap). - Filter pre-release builds (<codename>: Baklava / CinnamonBun / CANARY) and ext-SDK images (api-level "36x" etc.) from the listing to keep it uncluttered. - SysImgInfo derives (sort_base, is_16k) from the path's third segment; the URL directory uses sort_base (with default -> android remap). - SystemImageReleaseZip.tag() reduces a comma-joined SystemImage.TagId to its non-page-size component; new is_16k() reports the variant. - image_name(), download_name(), and __str__ get a -ps16k / ps16k suffix for 16 KB variants in three places: SysImgInfo, SystemImageContainer (local-zip path), and EmulatorContainer. - list_all_downloads and select_image surface the ps16k variant as a trailing column / suffix so users can tell the two apart at a glance. - short_tag / short_abi tolerate unknown values via dict.get fallback, so future tag/abi additions don't crash the listing. - Dockerfile.system_image emits a qemu.is_16k LABEL so the emulator layer (which reads sys-img labels via image_labels()) can detect the 16 KB variant. - Sort key becomes (api_major, api, tag, abi, is_16k) for stable ordering with dotted api versions and ps16k siblings. - README: refresh the emu-docker list example output to include modern API levels and a ps16k row, and document the suffix and filtered categories. Tests: - Fix tests/test_emu_downloads_menu.py: resolve a stale 2023-05-18 merge conflict (the "other" half was dead duplicate code already migrated to test_platform_tools / test_retrieve_emulators / test_retrieve_images); the file shrinks from 244 KB / un-collectable to 1.5 KB and its two pytest functions now run. - Add tests/test_sysimg_info.py with 25 unit tests covering the new parser logic: API_LETTER_MAPPING for 33-37, api_major regex for "36"/"36.1"/"37.0"/"36x", letter fallback for unknown future APIs, is_preview/is_ext_sdk detection, is_16k detection from the path, URL construction for ps16k and the default->android remap, and SystemImageReleaseZip.tag()/is_16k() for every comma-joined SystemImage.TagId shape seen in the SDK XML. End-to-end verified on a podman host: - emu-docker list: 94 entries (was ~60). google_apis and google_apis_playstore go up to 37.0; ps16k variants visible alongside the 4 KB ones; no codename or ext-SDK leaks; random sample HEAD against the constructed URLs all return 200. - 4 KB build: emu-docker create ./emulator-36.6.8.zip ./sys-img-x86_64-36_r07.zip --start produced sys-36-google-x64 (4.97 GB) and 36-google-x64 (6.1 GB); container launched, adb connected, sys.boot_completed=1, ro.build.version.sdk=36, ro.build.version.release=16, ro.product.model=sdk_gphone64_x86_64. - 16 KB build: emu-docker create ./emulator-36.6.8.zip ./sys-img-x86_64-ps16k-36_r07.zip produced sys-36-google-x64-ps16k (4.96 GB) and 36-google-x64-ps16k (6.09 GB); container booted, ro.product.model=sdk_gphone16k_x86_64, getconf PAGE_SIZE=16384, ro.build.version.sdk=36, ro.build.version.release=16. Backwards compatibility: image_name() output for non-ps16k images is unchanged. All 35 tests under tests/ (excluding e2e) pass.
This was referenced May 15, 2026
Closed
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #392.
What's broken today
emu-docker listsilently caps at API 32 (Android 12L "S"). Two collaborating bugs cause it:API_LETTER_MAPPINGstops at"32": "S". For API ≥ 33 the lookup falls through toself.letter = "A"("unknown code").get_images_infofilters withinfo.letter >= MIN_REL_X64("O"). String compare"A" < "O"→ the entry is dropped silently.So every API 33+ image is invisible in
emu-docker list, and unbuildable viafind_image()lookups.The new 16 KB-page-size axis
Starting at API 36, Google publishes a second variant of each system image with a 16 KB kernel page size. The encoding shows up in three different places that all need handling:
emu_downloads_menu):<tag><id>is not reliable — for released API 36 ps16k images the tag isgoogle_apis(same as the 4 KB variant); for36.0-Baklavait'spage_size_16kb; for CANARY pre-release it's multiple<tag>elements (google_apis,page_size_16kb,ai_glasses_compatible). Only the path's third segment (system-images;<api>;<sort>;<abi>) reliably says whether it's a 16 KB variant (sort ends in_ps16k). The zip lives undersys-img/<sort_base>/wheresort_basestrips the suffix.source.propertiesinside the zip (SystemImageReleaseZip):SystemImage.TagIdis comma-joined for 16 KB variants (e.g.google_apis,page_size_16kb). The previoustag()/short_tag()KeyError'd on the joined string.qemu.is_16kLABEL on the sys-img image, the emulator layer can't detect the variant.Changes
SYSIMG_REPOStosys-img2-5.xml(matches the SDK Manager;-5is what newer API entries land in first).33: T,34: U,35: V,36: B,37: CtoAPI_LETTER_MAPPING.MIN_REL_*constants with int-basedMIN_API_*. Parseapi-level(which can be"36","36.1","37.0", or"36x"for ext-SDK) into a newapi_majorint via regex; filter on that.<codename>set: Baklava, CinnamonBun, CANARY, …) and ext-SDK images (api-level"36x","33x", …) from the listing to keep it uncluttered.SysImgInfoderives(sort_base, is_16k)from the path; URL directory usessort_base(withdefault → androidremap).SystemImageReleaseZip.tag()reduces comma-joinedSystemImage.TagIdto its non-page-size component; newis_16k()reports the variant.image_name(),download_name(),__str__get a-ps16k/ps16ksuffix in three places (SysImgInfo,SystemImageContainer,EmulatorContainer) so 4 KB and 16 KB variants of the same(api, sort, abi)coexist as distinct docker images.list_all_downloadsandselect_imagesurface theps16kvariant as a trailing column / suffix.short_tag/short_abiusedict.get()with self-fallback so future tag/abi additions don't crash the listing.Dockerfile.system_imageemits aqemu.is_16kLABEL so the emulator layer can detect the variant from base-image labels.(api_major, api, tag, abi, is_16k)for stable ordering with dotted api versions and ps16k siblings.emu-docker listexample output to include modern API levels and aps16krow; document the suffix and the filtered categories.Tests
tests/test_emu_downloads_menu.py: a 2023-05-18 merge conflict had been committed unresolved. The "other" half of the conflict (PlatformToolsTestCase,RetrieveEmulators,RetrieveImages) was dead duplicate code that had already been migrated totest_platform_tools.py/test_retrieve_emulators.py/test_retrieve_images.py; the giant lines were old XML fixtures from those classes. Resolved by keeping the HEAD half. The file goes from 244 KB / un-collectable by pytest to 1.5 KB and its twodownloadtests now run.tests/test_sysimg_info.pywith 25 unit tests covering the new parser logic:API_LETTER_MAPPINGfor 33–37,api_majorregex for"36"/"36.1"/"37.0"/"36x", letter fallback for unknown future APIs,is_preview/is_ext_sdkdetection,is_16kdetection from the path, URL construction forps16kand thedefault → androidremap, andSystemImageReleaseZip.tag()/is_16k()for every comma-joinedSystemImage.TagIdshape seen in the SDK XML.Result
emu-docker listnow returns 94 entries (was ~60). Highest API per sort:google_apis: 37.0google_apis_playstore: 37.0android: 36android-tv: 36google_atd: 36Sample of new lines:
Test plan
emu-docker list: 94 entries; APIs 33–37 visible with correct letters T/U/V/B/C; no codename or ext-SDK leaks.ps16kcolumn in the output; every constructed URL HEAD returns200(random sample of regular + ps16k + default→android).emu-docker create ./emulator-36.6.8.zip ./sys-img-x86_64-36_r07.zip --startproducedsys-36-google-x64(4.97 GB) and36-google-x64(6.1 GB); container launched, adb connected,sys.boot_completed=1,ro.build.version.sdk=36,ro.build.version.release=16,ro.product.model=sdk_gphone64_x86_64.emu-docker create ./emulator-36.6.8.zip ./sys-img-x86_64-ps16k-36_r07.zipproducedsys-36-google-x64-ps16k(4.96 GB) and36-google-x64-ps16k(6.09 GB); container booted,ro.product.model=sdk_gphone16k_x86_64,getconf PAGE_SIZE=16384(16 KB confirmed),ro.build.version.sdk=36,ro.build.version.release=16.tests/(excluding e2e) pass.Backwards compatibility
image_name()output is unchanged for every existing 4 KB image; only the new 16 KB variants get a-ps16ksuffix, so already-built / already-tagged images keep working.