รองรับขนาดหน้าหน่วยความจำขนาด 16 KB

ในอดีต Android รองรับเฉพาะหน้าหน่วยความจำขนาด 4 KB ซึ่งได้ เพิ่มประสิทธิภาพหน่วยความจำของระบบสำหรับปริมาณหน่วยความจำทั้งหมดโดยเฉลี่ยที่ อุปกรณ์ Android มักจะมี ตั้งแต่ Android 15 เป็นต้นไป AOSP จะรองรับ อุปกรณ์ที่กำหนดค่าให้ใช้หน้าขนาด 16 KB (อุปกรณ์ 16 KB) หากแอปใช้ไลบรารี NDK ไม่ว่าจะโดยตรงหรือโดยอ้อมผ่าน SDK คุณจะต้องสร้างแอปใหม่เพื่อให้ทำงานในอุปกรณ์ที่มีขนาด 16 KB เหล่านี้ได้

เนื่องจากผู้ผลิตอุปกรณ์ยังคงสร้างอุปกรณ์ที่มีหน่วยความจำจริง (RAM) มากขึ้น อุปกรณ์จำนวนมากเหล่านี้จะใช้ขนาดหน้า 16 KB (และในที่สุดก็จะใหญ่ขึ้น) เพื่อเพิ่มประสิทธิภาพของอุปกรณ์ การเพิ่มการรองรับอุปกรณ์ที่มีขนาดหน้า 16 KB จะช่วยให้แอปของคุณทำงานบนอุปกรณ์เหล่านี้ได้ และช่วยให้แอปได้รับประโยชน์จากการปรับปรุงประสิทธิภาพที่เกี่ยวข้อง หากไม่มีการคอมไพล์ใหม่ แอปจะใช้ไม่ได้ในอุปกรณ์แบบ 16 KB ใน Android รุ่นต่อๆ ไป

เราได้ให้คำแนะนำเกี่ยวกับวิธีตรวจสอบว่าแอปได้รับผลกระทบหรือไม่ วิธีสร้างแอปใหม่ (หากมี) และวิธีทดสอบแอปในสภาพแวดล้อมแบบ 16 KB โดยใช้โปรแกรมจำลอง (รวมถึงอิมเมจระบบ Android 15 สำหรับ Android Emulator) เพื่อช่วยให้คุณเพิ่มการรองรับแอปได้

ข้อกำหนดด้านความเข้ากันได้ของ Google Play

เพื่อให้มั่นใจว่าแอปของคุณจะทำงานได้อย่างถูกต้องใน Android เวอร์ชันล่าสุด แอปทั้งหมดที่กำหนดเป้าหมายเป็น Android 15 (ระดับ API 35) ขึ้นไปต้องรองรับหน้าหน่วยความจำขนาด 16 KB ในอุปกรณ์ 64 บิตบน Google Play ตั้งแต่วันที่ 1 กุมภาพันธ์ 2027 เป็นต้นไป หากการอัปเดตแอปของคุณไม่รองรับหน้าหน่วยความจำขนาด 16 KB คุณจะเผยแพร่การอัปเดตเหล่านี้ไม่ได้

คำเตือนจาก Google Play Console ว่าการอัปเดตแอปต้องรองรับหน้าหน่วยความจำขนาด 16 KB ภายในวันที่ 1 กุมภาพันธ์ 2027
รูปที่ 1 คำเตือนเกี่ยวกับความเข้ากันได้ของ Google Play Console

ประโยชน์และประสิทธิภาพที่เพิ่มขึ้น

อุปกรณ์ที่กำหนดค่าหน้าเว็บขนาด 16 KB จะใช้หน่วยความจำโดยเฉลี่ยมากกว่าเล็กน้อย แต่ปรับปรุงประสิทธิภาพการทำงานได้หลากหลายสำหรับทั้งระบบและแอป ดังนี้

  • เวลาเปิดแอปลดลงขณะที่ระบบมีภาระเกี่ยวกับหน่วยความจำ: ลดลงโดยเฉลี่ย 3.16% โดยการปรับปรุงที่เห็นได้ชัดมากขึ้น (สูงสุด 30%) สำหรับบางแอปที่เราทดสอบ
  • การลดพลังงานในระหว่างการเปิดแอป: ลดลง 4.56% โดยเฉลี่ย
  • การเปิดตัวกล้องเร็วขึ้น: Hot Start เร็วขึ้น 4.48% โดยเฉลี่ย และ Cold Start เร็วขึ้น 6.60% โดยเฉลี่ย
  • ปรับปรุงเวลาในการบูตระบบ: เร็วขึ้น 8% (ประมาณ 950 มิลลิวินาที) โดยเฉลี่ย

การปรับปรุงเหล่านี้อิงตามการทดสอบขั้นต้นของเรา และผลลัพธ์ในอุปกรณ์จริงอาจแตกต่างกัน เราจะให้การวิเคราะห์เพิ่มเติมเกี่ยวกับโอกาสในการได้ผู้ใช้ใหม่สำหรับแอปขณะที่เราทำการทดสอบต่อไป

ตรวจสอบว่าแอปของคุณได้รับผลกระทบหรือไม่

หากแอปใช้โค้ดเนทีฟ คุณควรสร้างแอปใหม่ ให้รองรับอุปกรณ์ขนาด 16 KB หากไม่แน่ใจว่าแอปใช้โค้ดเนทีฟหรือไม่ คุณสามารถใช้ APK Analyzer เพื่อระบุว่ามีโค้ดเนทีฟหรือไม่ จากนั้นตรวจสอบการจัดแนวของส่วน ELF สำหรับไลบรารีที่ใช้ร่วมกันที่คุณพบ Android Studio ยังมีฟีเจอร์ที่จะช่วยให้คุณตรวจหาปัญหาการจัดแนวโดยอัตโนมัติได้ด้วย

หากแอปใช้เฉพาะโค้ดที่เขียนในภาษาโปรแกรม Java หรือ Kotlin ซึ่งรวมถึงไลบรารีหรือ SDK ทั้งหมด แสดงว่าแอปของคุณรองรับอุปกรณ์ขนาด 16 KB อยู่แล้ว อย่างไรก็ตาม เราขอแนะนำให้คุณทดสอบแอปในสภาพแวดล้อมแบบ 16 KB เพื่อยืนยันว่าไม่มีการถดถอยที่ไม่คาดคิดในลักษณะการทำงานของแอป

แอปของคุณใช้โค้ดแบบเนทีฟหรือไม่

แอปของคุณใช้โค้ดแบบเนทีฟหากตรงกับข้อใดข้อหนึ่งต่อไปนี้

  • แอปของคุณใช้โค้ด C/C++ (เนทีฟ) หากแอปใช้ Android NDK แสดงว่าแอปใช้โค้ดแบบเนทีฟ
  • แอปของคุณลิงก์กับไลบรารีแบบเนทีฟหรือทรัพยากร Dependency ของบุคคลที่สาม (เช่น SDK) ที่ใช้ไลบรารีหรือทรัพยากร Dependency ดังกล่าว
  • แอปของคุณสร้างโดยเครื่องมือสร้างแอปของบุคคลที่สามที่ใช้ไลบรารีแบบเนทีฟในอุปกรณ์

ระบุไลบรารีแบบเนทีฟโดยใช้ตัววิเคราะห์ APK

ตัววิเคราะห์ APK เป็นเครื่องมือที่ช่วยให้คุณประเมินแง่มุมต่างๆ ของ APK ที่สร้างขึ้นได้ วิธีตรวจสอบว่าแอปของคุณใช้โค้ดแบบเนทีฟหรือไม่ (ไม่ว่าจะรองรับขนาดหน้า 16 KB หรือไม่ก็ตาม)

  1. เปิด Android Studio แล้วคลิกไฟล์ > เปิด แล้วเลือกโปรเจ็กต์ใดก็ได้
  2. จากแถบเมนู ให้คลิก Build > Analyze APK...

    ตัวเลือกเมนู Build ของ Studio เพื่อเปิดตัววิเคราะห์ APK
  3. เลือก APK ที่ต้องการวิเคราะห์

  4. ดูในโฟลเดอร์ lib ซึ่งโฮสต์ไฟล์ออบเจ็กต์ที่แชร์ (.so) หากมี หากมีไฟล์ออบเจ็กต์ที่แชร์อยู่ แสดงว่าแอปใช้โค้ดแบบเนทีฟ คอลัมน์การจัดแนวจะแสดงข้อความเตือนสำหรับไฟล์ที่มีปัญหาเกี่ยวกับการจัดแนว หากไม่มีไฟล์ออบเจ็กต์ที่ใช้ร่วมกันหรือไม่มีโฟลเดอร์ lib แสดงว่าแอปไม่ได้ใช้โค้ดแบบเนทีฟ

    มุมมองตัววิเคราะห์ APK ที่แสดงว่ามีไฟล์ออบเจ็กต์ที่แชร์อยู่

ตรวจหาปัญหาการจัดแนวด้วยการตรวจสอบอัตโนมัติ

Android Studio จะเตือนคุณล่วงหน้าหากไลบรารีหรือ APK ที่สร้างไว้ล่วงหน้าไม่เป็นไปตามข้อกำหนด 16 KB ใช้เครื่องมือตัววิเคราะห์ APK เพื่อตรวจสอบว่าไลบรารีใดที่ต้องอัปเดตหรือต้องทำการเปลี่ยนแปลงโค้ดหรือไม่

การแจ้งเตือนของ Studio เกี่ยวกับปัญหาการจัดแนวในโปรเจ็กต์

Lint ใน Android Studio ยังไฮไลต์ไลบรารีแบบเนทีฟที่ไม่ได้จัดเรียงตามรูปแบบความจำขนาด 16 KB ด้วย

คำเตือน Linter ของ Studio เกี่ยวกับไลบรารีแบบเนทีฟที่ไม่ได้จัดแนว

ตรวจสอบการจัดเรียงของกลุ่ม ELF สำหรับไลบรารีที่ใช้ร่วมกัน

สำหรับคลังที่ใช้ร่วมกัน ให้ตรวจสอบว่ากลุ่ม ELF ของคลังที่ใช้ร่วมกันได้รับการจัดวางอย่างเหมาะสมโดยใช้การจัดวาง ELF ขนาด 16 KB

ใช้ตัววิเคราะห์ APK (แนะนำ)

วิธีที่ง่ายที่สุดในการยืนยันการจัดแนวคลังที่ใช้ร่วมกันคือใช้ตัววิเคราะห์ APK ใน Android Studio หากไฟล์ออบเจ็กต์ที่แชร์ไม่ได้จัดแนว 16 KB คอลัมน์การจัดแนวจะแสดงข้อความเตือน

ใช้สคริปต์ check_elf_alignment.sh (Linux หรือ macOS)

หากคุณกำลังพัฒนาบน Linux หรือ macOS และต้องการใช้สคริปต์ คุณสามารถใช้สคริปต์ check_elf_alignment.sh ได้ดังนี้

  1. บันทึกสคริปต์ check_elf_alignment.sh ลงในไฟล์

  2. เรียกใช้สคริปต์ในไฟล์ APK ของแอปโดยทำดังนี้

    check_elf_alignment.sh APK_NAME.apk
    

    สคริปต์จะแสดงผล ALIGNED หรือ UNALIGNED สำหรับคลังที่ใช้ร่วมกัน arm64-v8a ทั้งหมด

  3. หากไลบรารีที่ใช้ร่วมกัน arm64-v8a หรือ x86_64 มีUNALIGNED คุณจะต้องอัปเดตแพ็กเกจสำหรับไลบรารีเหล่านั้น จากนั้นคอมไพล์แอปใหม่และทดสอบอีกครั้งโดยทำตามขั้นตอนในส่วนนี้

ใช้เครื่องมือบรรทัดคำสั่งโดยตรง

ทำตามขั้นตอนต่อไปนี้เพื่อตรวจสอบการจัดแนวของเซกเมนต์ ELF โดยใช้เครื่องมือบรรทัดคำสั่งโดยตรง

  1. ตรวจสอบว่าได้ติดตั้งเครื่องมือสร้าง Android SDK เวอร์ชัน 35.0.0 ขึ้นไปและ Android NDK โดยใช้เครื่องมือจัดการ SDK ใน Android Studio หรือเครื่องมือบรรทัดคำสั่ง sdkmanager
  2. แตกไฟล์ APK ของแอปโดยทำดังนี้

    Linux หรือ macOS

    unzip APK_NAME.apk -d /tmp/my_apk_out
    

    Windows (PowerShell)

    Expand-Archive -Path .\APK_NAME.apk -DestinationPath ~\tmp\my_apk_out
    
  3. ในไดเรกทอรีชั่วคราวที่คุณแตกไฟล์ APK ให้ตรวจสอบเนื้อหาของไดเรกทอรี lib เพื่อหาไฟล์ออบเจ็กต์ที่แชร์ (.so) ไฟล์เหล่านี้เป็นไฟล์ออบเจ็กต์ที่ใช้ร่วมกันแบบเดียวกับที่คุณเห็นขณะระบุไลบรารีแบบเนทีฟโดยใช้ตัววิเคราะห์ APK เรียกใช้คำสั่งต่อไปนี้ในไฟล์ออบเจ็กต์ที่ใช้ร่วมกันแต่ละไฟล์

    Linux หรือ macOS

    SDK_ROOT_LOCATION/Android/sdk/ndk/NDK_VERSION/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-objdump -p SHARED_OBJECT_FILE.so | grep LOAD
    

    Windows (PowerShell)

    SDK_ROOT_LOCATION\Android\sdk\ndk\NDK_VERSION\toolchains\llvm\prebuilt\windows-x86_64\bin\llvm-objdump.exe -p SHARED_OBJECT_FILE.so | Select-String -Pattern "LOAD"
    

    โดย SDK_ROOT_LOCATION คือเส้นทางไปยังไดเรกทอรีที่คุณติดตั้ง Android SDK, SHARED_OBJECT_FILE คือชื่อไฟล์ออบเจ็กต์ที่ใช้ร่วมกันที่คุณกำลังตรวจสอบ และ NDK_VERSION คือเวอร์ชันของ Android NDK ที่คุณติดตั้ง (เช่น 28.0.12433566) ผลลัพธ์จะมีลักษณะดังต่อไปนี้สำหรับแต่ละไฟล์ที่คุณตรวจสอบ

    LOAD off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**14
    LOAD off    0x0000000000042a90 vaddr 0x0000000000043a90 paddr 0x0000000000043a90 align 2**14
    LOAD off    0x0000000000046230 vaddr 0x0000000000048230 paddr 0x0000000000048230 align 2**14
    
  4. ตรวจสอบบรรทัดเอาต์พุตเพื่อให้แน่ใจว่ากลุ่มการโหลดไม่มีค่าต่ำกว่า 2**14 หากเซกเมนต์การโหลดมีค่าเป็น 2**13, 2**12 หรือต่ำกว่า คุณจะต้องอัปเดตแพ็กเกจสำหรับไลบรารีเหล่านั้น จากนั้นคอมไพล์แอปใหม่และทดสอบอีกครั้งโดยทำตามขั้นตอนในส่วนนี้

  5. ถัดไป ให้เรียกใช้เครื่องมือบรรทัดคำสั่ง zipalign ในไฟล์ APK ของแอป

    Linux หรือ macOS

    SDK_ROOT_LOCATION/Android/sdk/build-tools/35.0.0/zipalign -v -c -P 16 4 APK_NAME.apk
    

    Windows (PowerShell)

    SDK_ROOT_LOCATION\Android\sdk\build-tools\35.0.0\zipalign.exe -v -c -P 16 4 APK_NAME.apk
    

    โดย SDK_ROOT_LOCATION คือเส้นทางไปยังไดเรกทอรีที่คุณติดตั้ง Android SDK และ APK_NAME คือชื่อไฟล์ APK ของแอป บรรทัดสุดท้ายของเอาต์พุตจะระบุว่า "Verification successful" หากคลังที่ใช้ร่วมกันทั้งหมดสอดคล้องกันอย่างถูกต้อง

    หากการยืนยันไม่สำเร็จ คุณจะต้องปรับไลบรารีที่ใช้ร่วมกันบางรายการให้สอดคล้องกัน ดังนั้นคุณจะต้องอัปเดตแพ็กเกจสำหรับไลบรารีเหล่านั้น จากนั้นคอมไพล์แอปอีกครั้งและทดสอบอีกครั้งโดยทำตามขั้นตอนในส่วนนี้

ตรวจสอบแฟล็กความปลอดภัยของ RELRO

เพื่อลดการใช้ประโยชน์จากช่องโหว่ด้านความปลอดภัย Linker สมัยใหม่จะใช้แฟล็ก Relocation Read-Only (RELRO) เพื่อทำให้ส่วนเป้าหมายการย้ายตำแหน่ง (เช่น .got และ .data.rel.ro) ของไฟล์ออบเจ็กต์ที่แชร์เป็นแบบอ่านอย่างเดียวหลังจากการย้ายตำแหน่งแบบไดนามิกเสร็จสมบูรณ์ เปิดใช้แฟล็ก RELRO ในบิลด์

เมื่อ GNU_RELRO แชร์กลุ่ม LOAD ที่เขียนได้กับข้อมูลที่เขียนได้ที่ตามมา (เช่น .data หรือ .bss) ที่อยู่สิ้นสุดของกลุ่ม GNU_RELRO (VirtAddr + MemSiz) ต้องจัดแนว 16 KB (0x4000) มิฉะนั้น เมื่อ Android Linker ทำเครื่องหมายหน้าขนาด 16 KB ที่มีส่วนท้ายของ GNU_RELRO เป็นแบบอ่านอย่างเดียว ข้อมูลที่เขียนได้ที่อยู่ติดกันซึ่งอยู่ในส่วนที่เหลือของหน้าขนาด 16 KB เดียวกันนั้นจะกลายเป็นแบบอ่านอย่างเดียวด้วย ซึ่งจะทำให้แอปขัดข้องขณะรันไทม์โดยมีข้อผิดพลาดในการแบ่งกลุ่ม (SIGSEGV) เมื่อมีการเขียนข้อมูลนั้น ซึ่งมักเกิดขึ้นหากไฟล์ .so สร้างขึ้นด้วย Toolchain ของ NDK r27 และต่ำกว่าโดยไม่ได้เปิดใช้แฟล็กที่เกี่ยวข้อง

คุณสามารถใช้ตัววิเคราะห์ APK ใน Android Studio เพื่อตรวจสอบสถานะการจัดเรียง RELRO ของไฟล์ออบเจ็กต์ที่แชร์ได้โดยตรง

ตัววิเคราะห์ APK ใน Android Studio แสดงการจัดวาง RELRO สำหรับไลบรารีแบบเนทีฟ

ใช้เครื่องมือบรรทัดคำสั่ง

หากต้องการตรวจสอบการจัดข้อความด้วยตนเองหรือต้องการทำให้กระบวนการเป็นแบบอัตโนมัติ ให้ทำตามขั้นตอนต่อไปนี้

ขั้นตอนที่ 1: ตรวจสอบส่วนหัวของโปรแกรม

เรียกใช้คำสั่งต่อไปนี้ในไฟล์ออบเจ็กต์ที่แชร์แต่ละไฟล์ (ใน Linux ให้แทนที่ darwin-x86_64 ด้วย linux-x86_64)

Linux หรือ macOS

SDK_ROOT_LOCATION/Android/sdk/ndk/NDK_VERSION/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-readelf -Wl SHARED_OBJECT_FILE.so | grep 'LOAD\|RELRO\|Type'

Windows (PowerShell)

SDK_ROOT_LOCATION\Android\sdk\ndk\NDK_VERSION\toolchains\llvm\prebuilt\windows-x86_64\bin\llvm-readelf.exe -Wl SHARED_OBJECT_FILE.so | Select-String -Pattern 'LOAD|RELRO|Type'

ระบบจะพิมพ์สตริง GNU_RELRO หากมีกลุ่ม RELRO

ขั้นตอนที่ 2: ยืนยันการปฏิบัติตามข้อกำหนด 16 KB สำหรับ RELRO

ไฟล์ออบเจ็กต์ที่แชร์จะเป็นไปตามข้อกำหนด 16 KB สำหรับ RELRO หากเป็นไปตามเงื่อนไขข้อใดข้อหนึ่งต่อไปนี้

  1. ไม่มีส่วน GNU_RELRO ในส่วนหัวของโปรแกรม
  2. ที่อยู่สิ้นสุดของ GNU_RELRO มีการจัดแนว 16 KB: ผลรวมของที่อยู่เสมือน (VirtAddr) และขนาดหน่วยความจำ (MemSiz) หารด้วย 16 KB (0x4000) จะเหลือเศษ (โมดูโล) เป็นศูนย์: (VirtAddr + MemSiz) % 0x4000 == 0
  3. ไม่มีข้อมูลที่เขียนได้ตามหลัง GNU_RELRO ในกลุ่ม LOAD เดียวกัน: GNU_RELRO ใช้พื้นที่ที่เหลือทั้งหมดของกลุ่ม LOAD ที่มีอยู่ (หมายถึง LOAD.VirtAddr + LOAD.MemSiz == RELRO.VirtAddr + RELRO.MemSiz) ดังนั้น จึงไม่มีส่วน .data หรือ .bss ที่เขียนได้แชร์หน้าต่อท้าย

ตัวอย่าง

ตัวอย่างต่อไปนี้แสดงวิธีประเมินเอาต์พุต llvm-readelf สำหรับการกำหนดค่า GNU_RELRO ต่างๆ

ตัวอย่างที่ 1: ไฟล์ .so ที่ไม่สอดคล้องกัน (ไม่เป็นไปตามข้อกำหนด)

ในตัวอย่างนี้ GNU_RELRO แชร์ส่วน RW LOAD กับข้อมูลที่เขียนได้ที่ตามมา และที่อยู่สิ้นสุดไม่ใช่จำนวนทวีคูณของ 0x4000:

Type           Offset   VirtAddr           PhysAddr           FileSiz MemSiz  Flg Align
LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x0cfaf0 0x0cfaf0 R E 0x4000
LOAD           0x0cfaf0 0x00000000000dfaf0 0x00000000000dfaf0 0x02510 0x04510 RW  0x4000
GNU_RELRO      0x0cfaf0 0x00000000000dfaf0 0x00000000000dfaf0 0x01510 0x01510 R   0x1
  • สูตร: (VirtAddr + MemSiz) % 0x4000 == 0
  • ผลลัพธ์: (0xdfaf0 + 0x01510) % 0x4000 = 0xE1000 % 0x4000 == 0x1000

เนื่องจาก 0x1000 ไม่ใช่ 0 และส่วน LOAD ที่มีอยู่ยังคงผ่าน 0xE1000 (สิ้นสุดที่ 0xdfaf0 + 0x04510 = 0xE4000) ไฟล์ .so นี้จึงไม่เป็นไปตามข้อกำหนด 16 KB ในอุปกรณ์ขนาด 16 KB ตัวลิงก์จะปัดเศษช่วงการป้องกัน RELRO เป็นขอบเขตหน้าขนาด 16 KB โดยทำเครื่องหมาย 0xDC000 (ตัวแบ่งหน้าก่อนหน้า) ถึง 0xE4000 เป็นแบบอ่านอย่างเดียว อย่างไรก็ตาม ส่วน .data และ .bss ที่เขียนได้ของไฟล์ .so อยู่ในช่วงย่อยตั้งแต่ 0xE1000 ถึง 0xE4000 ซึ่งส่งผลให้เกิดข้อผิดพลาดในการแบ่งกลุ่มเมื่อแก้ไขขณะรันไทม์ สร้างไฟล์ .so นี้ใหม่ตามที่อธิบายไว้ในส่วนคอมไพล์แอปโดยใช้การจัดวาง ELF ขนาด 16 KB

ตัวอย่างที่ 2: ไฟล์ .so ที่จัดเรียงแล้วซึ่งมีกลุ่ม RELRO (เป็นไปตามข้อกำหนด)

ในตัวอย่างนี้ จุดสิ้นสุดของกลุ่ม GNU_RELRO อยู่ที่ขอบเขตหน้าขนาด 16 KB

Type           Offset   VirtAddr           PhysAddr           FileSiz MemSiz  Flg Align
LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x0cfaf0 0x0cfaf0 R E 0x4000
LOAD           0x0cfaf0 0x00000000000dfaf0 0x00000000000dfaf0 0x01510 0x03510 RW  0x4000
GNU_RELRO      0x0cfaf0 0x00000000000dfaf0 0x00000000000dfaf0 0x00510 0x00510 R   0x1
  • สูตร: (VirtAddr + MemSiz) % 0x4000 == 0
  • ผลลัพธ์: (0xdfaf0 + 0x00510) % 0x4000 = 0xE0000 % 0x4000 == 0

เนื่องจากเศษที่เหลือคือ 0 การป้องกัน RELRO จึงสิ้นสุดลงอย่างสมบูรณ์ที่ขอบเขตหน้า 0xE0000 โดยไม่ส่งผลกระทบต่อข้อมูลที่เขียนได้ซึ่งเริ่มต้นที่ 0xE0000

ตัวอย่างที่ 3: ไฟล์ .so ที่ไม่มีกลุ่ม RELRO (เป็นไปตามข้อกำหนด)
Type           Offset   VirtAddr           PhysAddr           FileSiz MemSiz  Flg Align
LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x000680 0x000680 R E 0x4000
LOAD           0x000680 0x0000000000004680 0x0000000000004680 0x0001d8 0x0001d8 RW  0x4000

ไฟล์ .so นี้ไม่มีกลุ่ม GNU_RELRO ดังนั้นปัญหาขอบเขตหน้า RELRO จึงไม่มีผล (แม้ว่าจะยังคงแนะนำให้เปิดใช้ RELRO เพื่อความปลอดภัย)

ตัวอย่างที่ 4: GNU_RELRO ในกลุ่ม LOAD ของตัวเอง (เป็นไปตามนโยบาย)

ในตัวอย่างนี้ GNU_RELRO ไม่ได้สิ้นสุดที่ขอบเขต 16 KB แต่ยังคงเป็นไปตามข้อกำหนดเนื่องจากไม่มีข้อมูลที่เขียนได้ตามมาในกลุ่ม LOAD เดียวกัน

Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x000680 0x000680 R E 0x4000
LOAD           0x000680 0x0000000000004680 0x0000000000004680 0x0001d8 0x000980 RW  0x4000
GNU_RELRO      0x000680 0x0000000000004680 0x0000000000004680 0x0001d8 0x000980 R   0x1
  • สูตร: (VirtAddr + MemSiz) % 0x4000 == 0
  • ผลลัพธ์: (0x4680 + 0x0980) % 0x4000 = 0x5000 % 0x4000 == 0x1000

แม้ว่า 0x1000 จะไม่ใช่ 0 แต่ไฟล์ .so นี้ก็ยังคงเป็นไปตามข้อกำหนด 16 KB เมื่อเปรียบเทียบ GNU_RELRO กับกลุ่ม LOAD ที่มีอยู่ (รายการ LOAD ที่ 2) จะเห็นว่าทั้ง 2 รายการเริ่มต้นที่ VirtAddr 0x4680 และสิ้นสุดที่ที่อยู่เดียวกัน (0x4680 + 0x0980 = 0x5000)

เนื่องจากทั้งกลุ่ม LOAD มีเฉพาะข้อมูล RELRO จึงไม่มีข้อมูล .data หรือ .bss ที่เขียนได้ในช่วงย่อยตั้งแต่ 0x5000 ถึง 0x8000 (ไลบรารีไม่มีข้อมูลที่เขียนได้ซึ่งไม่ใช่ RELRO หรือกลุ่ม LOAD ที่เขียนได้ที่ตามมาจะเริ่มต้นที่ขอบเขตหน้า 16 KB แยกต่างหากที่ 0x8000 หรือมากกว่านั้น) การป้องกันแบบอ่านอย่างเดียวของ Linker จะไม่ทับซ้อนกับข้อมูลที่เขียนได้ ดังนั้นจึงไม่เกิดข้อผิดพลาดในการแบ่งกลุ่ม

สร้างแอปที่รองรับอุปกรณ์ที่ใช้หน้าหน่วยความจำขนาด 16 KB

หากแอปใช้โค้ดแบบเนทีฟ ให้ทำตามขั้นตอนที่ระบุไว้ในส่วนต่อไปนี้เพื่อให้แน่ใจว่าแอปของคุณรองรับอุปกรณ์ขนาด 16 KB

  1. อัปเดตการสร้างแพ็กเกจของคลังที่ใช้ร่วมกัน
  2. คอมไพล์แอปโดยใช้การจัดวาง ELF ขนาด 16 KB
  3. แก้ไขโค้ดและแก้ปัญหาเกี่ยวกับรันไทม์
  4. เพิ่มประสิทธิภาพตัวจัดสรรการจัดสรรหน่วยความจำที่กำหนดเอง (หากมี)
  5. ตรวจสอบ SDK เพื่อดูการรองรับขนาด 16 KB

อัปเดตการสร้างแพ็กเกจของคลังที่ใช้ร่วมกัน

อัปเกรดเป็น AGP เวอร์ชัน 8.5.1 ขึ้นไปและใช้ไลบรารีที่ใช้ร่วมกันที่ไม่ได้บีบอัด

ใช้ bundletool เพื่อยืนยันการจัดแนวซิป

หากต้องการดูการจัดแนวของแพ็กเกจ ให้ใช้คำสั่งต่อไปนี้

bundletool dump config --bundle=<my .aab>  | grep alignment

หากเห็น PAGE_ALIGNMENT_16K แสดงว่า Bundle ของคุณขอการจัดเรียงไฟล์ ZIP ขนาด 16 KB หากเห็น PAGE_ALIGNMENT_4K แสดงว่าคำสั่งนี้กำหนดให้ APK ที่สร้างจาก AAB นี้มีไฟล์ .so ที่จัดแนว 4 KB ในไฟล์ ZIP

AGP เวอร์ชัน 8.5.1 ขึ้นไป

อุปกรณ์ขนาด 16 KB ต้องใช้แอปที่มาพร้อมกับคลังที่ใช้ร่วมกันที่ไม่ได้บีบอัดเพื่อจัดวางคลังที่ใช้ร่วมกันเหล่านั้นในขอบเขตที่จัดวางด้วย zip ขนาด 16 KB โดยคุณจะต้องอัปเกรดเป็นปลั๊กอิน Android Gradle (AGP) เวอร์ชัน 8.5.1 ขึ้นไป ดูรายละเอียดเกี่ยวกับกระบวนการอัปเกรดได้ที่ส่วนผู้ช่วยอัปเกรดปลั๊กอิน Android Gradle

AGP เวอร์ชัน 8.5 หรือต่ำกว่า

หากอัปเกรด AGP เป็นเวอร์ชัน 8.5.1 ขึ้นไปไม่ได้ คุณสามารถเปลี่ยนไปใช้คลังที่ใช้ร่วมกันแบบบีบอัดแทนได้ อัปเดตการกำหนดค่า Gradle เพื่อให้ Gradle บีบอัดคลังที่ใช้ร่วมกันเมื่อสร้างแพ็กเกจแอปเพื่อหลีกเลี่ยงปัญหาการติดตั้งแอปที่มีคลังที่ใช้ร่วมกันที่ไม่ได้จัดวาง

ดึงดูด

เพิ่มตัวเลือกต่อไปนี้ในไฟล์ build.gradle

android {
  ...
  packagingOptions {
      jniLibs {
        useLegacyPackaging true
      }
  }
}

Kotlin

เพิ่มตัวเลือกต่อไปนี้ในไฟล์ build.gradle.kts

android {
  ...
  packagingOptions {
      jniLibs {
        useLegacyPackaging = true
      }
  }
}
AGP เวอร์ชัน 8.0 หรือต่ำกว่า

หากใช้ AGP เวอร์ชัน 8.0 หรือต่ำกว่า คุณจะต้องปิดใช้ตัวเลือกไลบรารีแบบเนทีฟที่ไม่ได้บีบอัดสำหรับ App Bundle ในไฟล์ gradle.properties ด้วย โดยทำดังนี้

android.bundle.enableUncompressedNativeLibs=false

คอมไพล์แอปโดยใช้การจัดวาง ELF ขนาด 16 KB

อุปกรณ์ขนาด 16 KB กำหนดให้ต้องจัดวางเซกเมนต์ ELF ของคลังที่ใช้ร่วมกันอย่างเหมาะสมโดยใช้การจัดวาง ELF ขนาด 16 KB เพื่อให้แอปทำงานได้

สำหรับนักพัฒนาเกม หากเกมของคุณทำงานบนเกมเอนจิน Unity โปรดดูคู่มือ Unity หากเกมของคุณทำงานบนเกมเอนจิน Unreal โปรดดูคู่มือ Unreal สำหรับเกมเอนจินแบบเนทีฟ โปรดอ่านคู่มือนี้ต่อ

หากต้องการคอมไพล์แอปโดยใช้การจัดแนว ELF ขนาด 16 KB ให้ทำตามขั้นตอนในส่วนใดส่วนหนึ่งต่อไปนี้ โดยขึ้นอยู่กับเวอร์ชันของ Android NDK ที่คุณใช้

Android NDK r28 ขึ้นไป

NDK เวอร์ชัน r28 ขึ้นไปจะคอมไพล์แบบจัดวางขนาด 16 KB โดยค่าเริ่มต้น

Android NDK r27 และต่ำกว่า

หากต้องการรองรับการคอมไพล์คลังที่ใช้ร่วมกันซึ่งจัดเรียงขนาด 16 KB ด้วย Android NDK เวอร์ชัน r27 หรือต่ำกว่า ให้ใช้แฟล็ก Linker ต่อไปนี้

-Wl,-z,max-page-size=16384
-Wl,-z,common-page-size=16384

วิธีอัปเดตไฟล์การกำหนดค่าระบบบิลด์มีดังนี้

ndk-build

หากใช้ ndk-build ให้อัปเดต Android.mk เพื่อเปิดใช้การจัดแนว ELF ขนาด 16 KB ดังนี้

LOCAL_LDFLAGS += -Wl,-z,max-page-size=16384 -Wl,-z,common-page-size=16384

CMake

หากใช้ CMake ให้อัปเดต CMakeLists.txt เพื่อเปิดใช้การจัดแนว ELF ขนาด 16 KB ดังนี้

target_link_options(${CMAKE_PROJECT_NAME} PRIVATE
    "-Wl,-z,max-page-size=16384"
    "-Wl,-z,common-page-size=16384"
)

แก้ไขโค้ดและแก้ปัญหาเกี่ยวกับรันไทม์

แม้ว่าแอปจะจัดแนวขนาด 16 KB แล้ว แต่แอปอาจพบข้อผิดพลาดหากตำแหน่งในโค้ดถือว่าอุปกรณ์ใช้ขนาดหน้าเว็บที่เฉพาะเจาะจง วิธีหลีกเลี่ยงปัญหามีดังนี้ ทำตามขั้นตอนต่อไปนี้

  1. นำทรัพยากร Dependency ที่ฮาร์ดโค้ดซึ่งอ้างอิงค่าคงที่ PAGE_SIZE หรืออินสแตนซ์ในตรรกะโค้ดที่ถือว่าขนาดหน้าเว็บของอุปกรณ์คือ 4 KB (4096) ออก

    โปรดใช้ getpagesize() หรือ sysconf(_SC_PAGESIZE) แทน

  2. มองหาการใช้งาน mmap() และ API อื่นๆ ที่ต้องใช้อาร์กิวเมนต์ที่จัดแนวหน้า และแทนที่ด้วยทางเลือกอื่นหากจำเป็น

ในบางกรณี หากแอปใช้ PAGE_SIZE เป็นค่าที่สะดวกซึ่งไม่ได้เชื่อมโยงกับขนาดหน้าเว็บที่สำคัญ การดำเนินการนี้จะไม่ทำให้แอปขัดข้องเมื่อใช้ในโหมด 16 KB อย่างไรก็ตาม หากส่งค่านี้ไปยังเคอร์เนลด้วย mmap โดยไม่มี MAP_FIXED เคอร์เนลจะยังคงใช้ทั้งหน้า ซึ่งทำให้สิ้นเปลืองหน่วยความจำบางส่วน ด้วยเหตุผลเหล่านี้ ระบบจึงไม่กำหนด PAGE_SIZE เมื่อเปิดใช้โหมด 16 KB ใน NDK r27 ขึ้นไป

หากแอปของคุณใช้ PAGE_SIZE ในลักษณะนี้และไม่เคยส่งค่านี้ไปยังเคอร์เนลโดยตรง ให้สร้างตัวแปรใหม่ที่มีชื่อใหม่เพื่อแสดงว่าตัวแปรนี้ใช้เพื่อวัตถุประสงค์อื่นและไม่ได้แสดงหน้าหน่วยความจำจริง แทนที่จะใช้ PAGE_SIZE

เพิ่มประสิทธิภาพตัวจัดสรรการจัดสรรหน่วยความจำที่กำหนดเอง

ในระบบ 16 KB หน่วยความจำกายภาพที่เล็กที่สุดที่ระบบปฏิบัติการจัดสรรจะมีขนาดใหญ่กว่าระบบ 4 KB ถึง 4 เท่า หากตัวจัดสรรที่กำหนดเองได้รับการออกแบบตามสมมติฐาน 4 KB ตัวจัดสรรอาจกระจายออบเจ็กต์ขนาดเล็กไปยังหน้าขนาด 16 KB หลายหน้าและเก็บหน่วยความจำว่างไว้โดยไม่จำเป็น ซึ่งอาจเพิ่มการใช้งานหน่วยความจำจริง (RSS) อย่างมากและลดประสิทธิภาพของ Swap ที่บีบอัด (ZRAM)

หากโค้ดของคุณจัดการพูลหน่วยความจำของตัวเอง ให้ทำตามคำแนะนำต่อไปนี้

1. หลีกเลี่ยงเกณฑ์ไบต์ที่ฮาร์ดโค้ดเพื่อเพิ่มพื้นที่หน่วยความจำ

ตัวจัดสรรจำนวนมากใช้ขีดจำกัดไบต์คงที่เพื่อตัดสินใจว่าจะปล่อยหน่วยความจำกลับไปยังระบบปฏิบัติการโดยใช้ madvise(MADV_DONTNEED) เมื่อใด (เช่น ปล่อยหน่วยความจำเฉพาะเมื่อออบเจ็กต์ที่ใช้งานอยู่ใช้พื้นที่น้อยกว่า 8 KB)

ในระบบ 16 KB แม้แต่ออบเจ็กต์ที่ทำงานอยู่ขนาด 16 ไบต์เพียงรายการเดียวก็ตรึงหน้าขนาด 16 KB ทั้งหน้า (ซึ่งมากกว่า 8 KB) ด้วยเหตุนี้ จึงไม่ถึงเกณฑ์การปล่อย และ Allocator จะไม่คืนหน่วยความจำที่ไม่ได้ใช้โดยรอบให้กับเคอร์เนล

สิ่งที่ต้องทำ: อย่าใช้ค่าคงที่ไบต์ที่ฮาร์ดโค้ดสำหรับฮิวริสติกการปล่อยหน้าเว็บ ปรับขนาดเกณฑ์การปล่อยแบบไดนามิกที่รันไทม์ตามขนาดหน้าจริงโดยใช้ sysconf(_SC_PAGESIZE)

2. เติมหน้าเว็บที่ใช้แล้วก่อน (การจัดสรรแบบหนาแน่นก่อน)

หากตัวจัดสรรจัดสรรหน่วยความจำตามลำดับเข้าก่อนออกก่อน (FIFO) หรือแบบวนรอบ (Round-Robin) การจัดสรรใหม่จะกระจายไปทั่วหน้าขนาด 16 KB ที่มีข้อมูลอยู่บางส่วน ออบเจ็กต์เดียวในหน้าจะเก็บข้อมูลขนาด 16 KB ทั้งหมดไว้ใน RAM จริง

สิ่งที่ต้องทำ: จัดสรรออบเจ็กต์ใหม่จากหน้าหรือ Slab ที่เต็ม (หนาแน่น) ที่สุดก่อนเสมอ ก่อนที่จะแตะหน้าว่างหรือหน้าที่มีการใช้งานน้อย การมุ่งเน้นการจัดสรรใหม่ในหน้าที่ไม่สะอาดอยู่แล้วจะช่วยให้หน้าที่มีการใช้งานน้อยลดลงเหลือออบเจ็กต์ที่ใช้งานอยู่เป็น 0 โดยธรรมชาติ เพื่อให้สามารถปล่อยหน้าขนาด 16 KB ทั้งหน้าไปยังระบบปฏิบัติการได้

3. จัดแนวพูลหน่วยความจำให้เป็น 16 KB และรักษาขนาดพูลให้อยู่ในระดับปานกลาง

ช่วงหลายหน้าที่ออกแบบมาสำหรับระบบขนาด 4 KB อาจมีหน่วยความจำที่ไม่ได้ใช้งานมากเกินไปในเคอร์เนลขนาด 16 KB นอกจากนี้ คลาสขนาดที่หารด้วย 16 KB ไม่ลงตัวจะทำให้เกิดการกระจาย Fragment ที่ส่วนท้ายของแต่ละหน้า

สิ่งที่ต้องทำ

  • ตรวจสอบว่าพูลหน่วยความจำ ขอบเขต Slab และการจัดแนวบัฟเฟอร์ทั้งหมดเป็นจำนวนเท่าที่แน่นอนของขนาดหน้าเว็บรันไทม์
  • ประเมินขนาดช่วงหลายหน้าสำหรับคลาสออบเจ็กต์ขนาดเล็กอีกครั้งเพื่อหลีกเลี่ยงการจัดสรร Slab ขนาดใหญ่เกินไปซึ่งจะดักจับหน่วยความจำที่ไม่มีการใช้งาน

4. ปล่อยหน่วยความจำกายภาพสำหรับบัฟเฟอร์ขนาดใหญ่ที่แคชไว้ทันที

ตัวจัดสรรที่กำหนดเองมักจะแคชบัฟเฟอร์ขนาดใหญ่ (> 64 KB) ในพูลในหน่วยความจำเพื่อให้สามารถนำกลับมาใช้ใหม่ได้โดยไม่ต้องเสียค่าใช้จ่ายเพิ่มเติมสำหรับการเรียกใช้ระบบ mmap หรือ munmap อย่างไรก็ตาม การเก็บรักษาบัฟเฟอร์ที่สกปรกเหล่านี้ไว้ในหน่วยความจำจะทำให้ RAM จริงเสียไปหลายเมกะไบต์ขณะรอตัวจับเวลาการขับออก

สิ่งที่ต้องทำ: เก็บช่วงที่อยู่หน่วยความจำเสมือนที่สงวนไว้สำหรับการนำกลับมาใช้ใหม่อย่างรวดเร็ว แต่ให้เรียกใช้ madvise(..., MADV_DONTNEED) หรือ madvise(..., MADV_FREE) ทันทีเมื่อส่งคืนบัฟเฟอร์ไปยังแคช ระบบปฏิบัติการจะเรียกคืน RAM จริงทันที ขณะที่แอปยังคงใช้ที่อยู่เสมือนซ้ำได้ทันทีโดยไม่ต้องจัดสรรใหม่

5. ล้างหน่วยความจำเมื่อว่างแทนที่จะล้างเมื่อมีการจัดสรรสำหรับการบีบอัด ZRAM

Android ใช้การสลับแบบบีบอัด (ZRAM) เพื่อเก็บแอปที่ทำงานอยู่เบื้องหลังไว้ในหน่วยความจำ ในอุปกรณ์ขนาด 16 KB หากหน้าเว็บมีออบเจ็กต์ที่ใช้งานอยู่แม้เพียงรายการเดียว หน้าเว็บขนาด 16 KB ทั้งหน้าจะยังคงอยู่หรือถูกสลับไปยัง ZRAM ข้อมูลขยะที่เหลืออยู่ (เช่น พอยน์เตอร์และสตริงที่ไม่มีการใช้งาน) ในส่วนที่ว่างก่อนหน้านี้ของหน้าเว็บนั้นจะบีบอัดได้ไม่ดีนัก

หาก Allocator ของคุณล้างหน่วยความจำ (เช่น เพื่อความปลอดภัยหรือการจัดสรรที่เริ่มต้นเป็น 0) ให้พิจารณาล้างเมื่อยกเลิกการจัดสรร (free()) แทนที่จะล้างเมื่อจัดสรร

  • หน้าเว็บที่ปักหมุดไว้ใช้ทรัพยากรน้อยลง: หน่วยความจำที่ไม่มีการใช้งานในหน้าเว็บขนาด 16 KB ที่มีข้อมูลอยู่บางส่วนจะถูกบีบอัดจนแทบไม่เหลืออะไรเลยใน ZRAM ดังนั้นหน้าเว็บที่ปักหมุดไว้จึงไม่ทำให้พื้นที่ Swap จริงสูญเปล่า
  • ค่าใช้จ่ายเพิ่มเติมของแคชต่ำสุด: ในขณะที่เรียกใช้ free() หน่วยความจำจะทำงานในแคช CPU อยู่แล้ว ซึ่งจะช่วยหลีกเลี่ยงการไม่พบแคชเพิ่มเติมในภายหลัง

สรุปคำแนะนำ

พื้นที่ คำแนะนำ ผลกระทบที่คาดหวัง
เกณฑ์การล้างข้อมูล ปรับขนาดเกณฑ์การเผยแพร่แบบไดนามิกโดยใช้ sysconf(_SC_PAGESIZE) ป้องกันไม่ให้ตรรกะการเผยแพร่เกิดการติดตายอย่างถาวร
ลำดับการจัดสรร จัดสรรจากหน้าหรือ Slab ที่หนาแน่นที่สุด (เกือบเต็ม) ก่อน ลดหน่วยความจำที่ใช้ (RSS) โดยการรวมออบเจ็กต์ที่ใช้งานอยู่เข้าด้วยกัน
การกำหนดขนาดช่วง จัดคลาสขนาดให้สอดคล้องกับจำนวนเท่าของ 16 KB และหลีกเลี่ยง Slab ที่มีขนาดใหญ่เกินไป กำจัดการกระจาย Fragment ของหน้าส่วนท้ายและลดหน่วยความจำที่ไม่ได้ใช้
แคชบัฟเฟอร์ เรียกใช้ madvise(MADV_DONTNEED) ทันทีเมื่อแคชบัฟเฟอร์ขนาดใหญ่ กำจัด RAM ที่ไม่ได้ใช้งานซึ่งทำให้เครื่องช้าลง ขณะเดียวกันก็ยังคงใช้หน่วยความจำเสมือนได้อย่างรวดเร็ว
Swap / ZRAM ล้างหน่วยความจำใน free() แทนการจัดสรร ปรับปรุงอัตราส่วนการบีบอัด ZRAM เพื่อให้หน้าเว็บที่ปักหมุดใช้ทรัพยากรน้อยลง

ตรวจสอบ SDK เพื่อดูการรองรับขนาด 16 KB

SDK จำนวนมากเข้ากันได้กับขนาดหน้า 16 KB โดยเฉพาะอย่างยิ่งหากคุณสร้างขึ้นเองหรือใช้เวอร์ชันที่สร้างไว้ล่วงหน้าล่าสุด อย่างไรก็ตาม เนื่องจาก SDK ที่สร้างไว้ล่วงหน้าหรือ SDK บางเวอร์ชันไม่รองรับขนาด 16 KB คุณจึงควรตรวจสอบเว็บไซต์ของผู้ให้บริการ SDK แต่ละรายเพื่อดูว่าควรใช้เวอร์ชันใดกับขนาด 16 KB

ทดสอบแอปในสภาพแวดล้อมแบบ 16 KB

หลังจากสร้างแอปที่รองรับอุปกรณ์ขนาด 16 KB แล้ว คุณจะต้องทดสอบแอปในสภาพแวดล้อมขนาด 16 KB เพื่อดูว่าแอปมีปัญหาการถดถอยหรือไม่ โดยทำตามขั้นตอนต่อไปนี้

  1. ตั้งค่า Android 15 SDK ขึ้นไป

  2. ตั้งค่าสภาพแวดล้อมการทดสอบอย่างใดอย่างหนึ่งต่อไปนี้

  3. เริ่มอุปกรณ์ทดสอบ แล้วเรียกใช้คำสั่งต่อไปนี้เพื่อยืนยันว่าอุปกรณ์ใช้สภาพแวดล้อม 16 KB

    adb shell getconf PAGE_SIZE
    

    คำสั่งควรแสดงผลค่าเป็น 16384

  4. เรียกใช้คำสั่ง zipalign ต่อไปนี้เพื่อยืนยันว่าแอปของคุณจัดแนวแบบ 16 KB โดยที่ APK_NAME คือชื่อไฟล์ APK ของแอป

    zipalign -c -P 16 -v 4 APK_NAME.apk
    
  5. ทดสอบแอปอย่างละเอียด โดยเน้นที่ส่วนที่อาจได้รับผลกระทบจากการเปลี่ยนอินสแตนซ์โค้ดที่อ้างอิงขนาดหน้าเว็บที่เฉพาะเจาะจง

ตั้งค่าโปรแกรมจำลองของ Android ด้วยอิมเมจระบบแบบ 16 KB

หากต้องการตั้งค่าสภาพแวดล้อมขนาด 16 KB โดยใช้โปรแกรมจำลองของ Android ให้ทำตามขั้นตอนต่อไปนี้

  1. ใน Android Studio ให้คลิกเครื่องมือ > เครื่องมือจัดการ SDK
  2. ในแท็บแพลตฟอร์ม SDK ให้เลือกแสดงรายละเอียดแพ็กเกจ แล้วขยายส่วน Android VanillaIceCream ขึ้นไป และเลือกอิมเมจระบบโปรแกรมจำลองต่อไปนี้อย่างใดอย่างหนึ่งหรือทั้ง 2 อย่าง โดยขึ้นอยู่กับอุปกรณ์เสมือนจริงที่คุณต้องการสร้าง

    • อิมเมจระบบ ARM 64 v8a ขนาดหน้า 16 KB เวอร์ชันทดลองของ Google APIs
    • อิมเมจระบบ Intel x86_64 Atom ขนาดหน้า 16 KB เวอร์ชันทดลองของ Google APIs
    ดาวน์โหลดอิมเมจระบบของโปรแกรมจำลองขนาด 16 KB โดยใช้เครื่องมือจัดการ SDK ใน Android Studio
  3. คลิกใช้ > ตกลงเพื่อดาวน์โหลดอิมเมจระบบที่คุณเลือก

  4. ทำตามขั้นตอนเพื่อตั้งค่าอุปกรณ์เสมือนจริงสำหรับ Android 15 และเมื่อระบบแจ้งให้เลือกอิมเมจระบบ ให้เลือกอิมเมจระบบขนาด 16 KB ที่คุณดาวน์โหลดไว้ หากระบบไม่แนะนำโดยอัตโนมัติ คุณจะดูอิมเมจระบบขนาด 16 KB ได้ในแท็บอิมเมจอื่นๆ

    ค้นหาอิมเมจโปรแกรมจำลองขนาด 16 KB ในแท็บ &quot;Other Images&quot;

เปิดโปรแกรมจำลอง

หลังจากตั้งค่าโปรแกรมจำลองของ Android และอุปกรณ์เสมือนจริงเสร็จแล้ว ให้เปิดโปรแกรมจำลองจากเมนูอุปกรณ์เป้าหมายหรือจากบรรทัดคำสั่ง

เปิดใช้โหมด 16 KB ในอุปกรณ์โดยใช้ตัวเลือกสำหรับนักพัฒนาแอป

สลับตัวเลือกสำหรับนักพัฒนาแอปบูตโดยใช้หน้าหน่วยความจำขนาด 16 KB เพื่อบูตอุปกรณ์ในโหมด 16 KB

ใน Android 15 เวอร์ชัน QPR คุณสามารถใช้ตัวเลือกสำหรับนักพัฒนาแอปที่มีในอุปกรณ์บางรุ่นเพื่อบูตอุปกรณ์ในโหมด 16 KB และทำการทดสอบในอุปกรณ์ได้ ก่อนใช้ตัวเลือกสำหรับนักพัฒนาซอฟต์แวร์ ให้ไปที่การตั้งค่า > ระบบ > การอัปเดตซอฟต์แวร์ แล้วใช้การอัปเดตที่มี

ตัวเลือกสำหรับนักพัฒนาแอปนี้พร้อมใช้งานในอุปกรณ์ต่อไปนี้

  • Pixel 8 และ 8 Pro (ที่ใช้ Android 15 QPR1 ขึ้นไป)

  • Pixel 8a (ใช้ Android 15 QPR1 ขึ้นไป)

  • Pixel 9, 9 Pro และ 9 Pro XL (ใช้ Android 15 QPR2 ขึ้นไป)

  • Pixel 9a (ใช้ Android 16 ขึ้นไป)

โหมดความเข้ากันได้แบบย้อนหลัง 16 KB

คำเตือนในโหมดเข้ากันได้กับขนาดหน้า

คำเตือนในโหมดความเข้ากันได้กับขนาดหน้า

ตัวเลือกความเข้ากันได้แบบย้อนหลัง 16 KB จะพร้อมใช้งานเมื่ออุปกรณ์ทำงานด้วยเคอร์เนล 16 KB เครื่องมือจัดการแพ็กเกจจะเรียกใช้แอปในโหมดความเข้ากันได้แบบย้อนหลังขนาด 16 KB เมื่อเป็นไปตามเงื่อนไขต่อไปนี้

  • หากแอปมีไฟล์ ELF (ที่มีนามสกุล .so) ที่มีการจัดแนวกลุ่ม LOAD ขนาด 4 KB
  • หาก APK ที่บีบอัดมีไฟล์ ELF ที่ไม่ได้บีบอัดซึ่งจัดเรียง ZIP ขนาด 4 KB

หากเครื่องมือจัดการแพ็กเกจเปิดใช้โหมดความเข้ากันได้แบบย้อนหลัง 16 KB สำหรับแอป แอปจะแสดงคำเตือนเมื่อเปิดใช้งานครั้งแรกว่ากำลังทำงานในโหมดความเข้ากันได้แบบย้อนหลัง 16 KB

โหมดความเข้ากันได้แบบย้อนหลัง 16 KB ช่วยให้แอปบางแอปทำงานได้ แต่เพื่อให้มีความน่าเชื่อถือและความเสถียรสูงสุด แอปควรได้รับการจัดแนวให้รองรับขนาดหน้า 16 KB

ในหน้าข้อมูลแอป ในส่วนขั้นสูง ให้สลับการตั้งค่าเรียกใช้แอปด้วยโหมดเข้ากันได้กับขนาดหน้าเพื่อเปิดหรือปิดใช้โหมดความเข้ากันได้แบบย้อนหลัง 16 KB สำหรับแอปที่เฉพาะเจาะจง การตั้งค่านี้จะปรากฏเฉพาะเมื่ออุปกรณ์ทำงานด้วยขนาดหน้า 16 KB

การตั้งค่าโหมดเข้ากันได้กับขนาดหน้า

การตั้งค่าโหมดเข้ากันได้กับขนาดหน้า

วิธีบังคับให้เปิดความเข้ากันได้แบบย้อนหลัง 16 KB สำหรับทุกแอปในอุปกรณ์

adb shell setprop bionic.linker.16kb.app_compat.enabled true
adb shell setprop pm.16kb.app_compat.disabled false

วิธีบังคับปิดความเข้ากันได้แบบย้อนหลัง 16 KB สำหรับทุกแอปในอุปกรณ์

adb shell setprop bionic.linker.16kb.app_compat.enabled false
adb shell setprop pm.16kb.app_compat.disabled true

ใน Android 17 คุณยังสามารถบังคับปิดความเข้ากันได้แบบย้อนหลัง 16 KB สำหรับทุกแอปและทำให้ไบนารีที่เข้ากันไม่ได้ถูกยกเลิกทันทีได้ด้วย โดยทำดังนี้

    adb shell setprop bionic.linker.16kb.app_compat.enabled fatal
    adb shell setprop pm.16kb.app_compat.disabled true

ตั้งค่าพร็อพเพอร์ตี้ android:pageSizeCompat เป็นเปิดใช้หรือปิดใช้เพื่อเปิดหรือปิดโหมดความเข้ากันได้แบบย้อนหลังสำหรับแอปที่เฉพาะเจาะจงใน AndroidManifest.xml เมื่อตั้งค่าพร็อพเพอร์ตี้นี้ แอปจะไม่แสดงคำเตือนโหมดความเข้ากันได้แบบย้อนหลังเมื่อเปิดแอป