การเปลี่ยนแปลงลักษณะการทำงานของ Android 7.0

นอกจากฟีเจอร์และความสามารถใหม่ๆ แล้ว Android 7.0 ยังมีการเปลี่ยนแปลงลักษณะการทำงานของระบบและ API ที่หลากหลายด้วย เอกสารนี้จะไฮไลต์การเปลี่ยนแปลงที่สำคัญบางอย่างที่คุณควรทำความเข้าใจและพิจารณาในแอป

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

แบตเตอรี่และหน่วยความจำ

Android 7.0 มีการเปลี่ยนแปลงลักษณะการทำงานของระบบที่มุ่งปรับปรุงระยะเวลาการใช้งานแบตเตอรี่ของอุปกรณ์และลดการใช้ RAM การเปลี่ยนแปลงเหล่านี้อาจส่งผลต่อสิทธิ์เข้าถึงทรัพยากรระบบของแอป รวมถึงวิธีที่แอปโต้ตอบกับแอปอื่นๆ โดยใช้ Intent โดยนัยบางอย่าง

Doze

โหมด Doze ซึ่งเปิดตัวใน Android 6.0 (ระดับ API 23) ช่วยยืดระยะเวลาการใช้งานแบตเตอรี่โดยเลื่อนกิจกรรมของ CPU และกิจกรรมเครือข่ายออกไปเมื่อผู้ใช้ไม่ได้เสียบปลั๊กอุปกรณ์ ไม่ได้เคลื่อนย้าย และปิดหน้าจอไว้ Android 7.0 ได้ปรับปรุงโหมด Doze เพิ่มเติมโดยใช้ชุดย่อยของข้อจำกัด CPU และเครือข่ายขณะที่ไม่ได้เสียบปลั๊กอุปกรณ์และปิดหน้าจอไว้ แต่ไม่จำเป็นต้องอยู่นิ่ง เช่น เมื่อโทรศัพท์มือถืออยู่ในกระเป๋าของผู้ใช้

ภาพแสดงวิธีที่ Doze ใช้การจำกัดกิจกรรมของระบบในระดับแรกเพื่อปรับปรุงระยะเวลาการใช้งานแบตเตอรี่

รูปที่ 1 ภาพแสดงวิธีที่ Doze ใช้ข้อจำกัดกิจกรรมของระบบระดับแรกเพื่อปรับปรุงระยะเวลาการใช้งานแบตเตอรี่

เมื่ออุปกรณ์ใช้พลังงานจากแบตเตอรี่และหน้าจอปิดเป็นระยะเวลาหนึ่ง อุปกรณ์จะเข้าสู่โหมด Doze และใช้ข้อจำกัดชุดย่อยชุดแรก ซึ่งจะปิดการเข้าถึงเครือข่ายของแอป รวมถึงเลื่อนงานและการซิงค์ออกไป หากอุปกรณ์อยู่กับที่เป็นระยะเวลาหนึ่งหลังจากเข้าสู่โหมด Doze ระบบจะใช้ข้อจำกัดที่เหลือของโหมด Doze กับ PowerManager.WakeLock, การปลุก AlarmManager, GPS และการสแกน Wi-Fi ไม่ว่าจะใช้ข้อจำกัดโหมด Doze บางส่วนหรือทั้งหมด ระบบจะปลุกอุปกรณ์เพื่อเข้าสู่ช่วงเวลาบำรุงรักษาสั้นๆ ซึ่งในระหว่างนั้นแอปพลิเคชันจะได้รับอนุญาตให้เข้าถึงเครือข่ายและสามารถดำเนินการงาน/การซิงค์ที่เลื่อนออกไปได้

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

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

โปรดทราบว่าการเปิดหน้าจอหรือเสียบปลั๊กอุปกรณ์จะเป็นการออกจากโหมด Doze และนำข้อจำกัดในการประมวลผลเหล่านี้ออก ลักษณะการทำงานเพิ่มเติมนี้ไม่ส่งผลต่อคำแนะนำและแนวทางปฏิบัติแนะนำในการปรับแอปให้เข้ากับโหมด Doze เวอร์ชันก่อนหน้าที่เปิดตัวใน Android 6.0 (ระดับ API 23) ตามที่กล่าวถึงในการเพิ่มประสิทธิภาพสำหรับโหมด Doze และสแตนด์บายแอป คุณยังคงควรทำตามคำแนะนำเหล่านั้น เช่น การใช้ Firebase Cloud Messaging (FCM) เพื่อส่งและรับข้อความ และเริ่มวางแผนการอัปเดตเพื่อรองรับลักษณะการทำงานเพิ่มเติมของโหมด Doze

Project Svelte: การเพิ่มประสิทธิภาพในเบื้องหลัง

Android 7.0 นำการกระจายข้อมูลแบบไม่เจาะจงปลายทาง 3 รายการออกเพื่อช่วยเพิ่มประสิทธิภาพทั้งการใช้หน่วยความจำและการใช้พลังงาน การเปลี่ยนแปลงนี้จำเป็นเนื่องจากการกระจายข้อมูลแบบไม่เจาะจงปลายทางมักจะเริ่มแอปที่ลงทะเบียนเพื่อฟังการกระจายข้อมูลในเบื้องหลัง การนำการออกอากาศเหล่านี้ออกจะช่วยปรับปรุงประสิทธิภาพของอุปกรณ์และประสบการณ์ของผู้ใช้ได้อย่างมาก

อุปกรณ์เคลื่อนที่มีการเปลี่ยนแปลงการเชื่อมต่อบ่อยครั้ง เช่น เมื่อสลับไปมาระหว่าง Wi-Fi กับอินเทอร์เน็ตมือถือ ปัจจุบัน แอปสามารถตรวจสอบการเปลี่ยนแปลงในการเชื่อมต่อได้โดยการลงทะเบียนตัวรับสัญญาณสำหรับการกระจายข้อมูลแบบไม่เจาะจงปลายทาง CONNECTIVITY_ACTION ในไฟล์ Manifest เนื่องจากมีแอปจำนวนมากที่ลงทะเบียนเพื่อรับการออกอากาศนี้ สวิตช์เครือข่ายเพียงครั้งเดียวจึงอาจทำให้แอปทั้งหมดตื่นขึ้นมาและประมวลผลการออกอากาศพร้อมกัน

ในทำนองเดียวกัน ใน Android เวอร์ชันก่อนหน้า แอปสามารถลงทะเบียนเพื่อรับการออกอากาศ ACTION_NEW_PICTURE และ ACTION_NEW_VIDEO โดยนัยจากแอปอื่นๆ เช่น กล้อง เมื่อผู้ใช้ถ่ายภาพด้วยแอปกล้องถ่ายรูป แอปเหล่านี้จะเริ่มทำงานเพื่อประมวลผลการออกอากาศ

เพื่อบรรเทาปัญหาเหล่านี้ Android 7.0 จึงใช้การเพิ่มประสิทธิภาพต่อไปนี้

  • แอปที่กำหนดเป้าหมายเป็น Android 7.0 (ระดับ API 24) ขึ้นไปจะไม่ได้รับการออกอากาศ CONNECTIVITY_ACTION หากประกาศ Broadcast Receiver ในไฟล์ Manifest แอปจะยังคงได้รับการออกอากาศ CONNECTIVITY_ACTION หากลงทะเบียน BroadcastReceiver ด้วย Context.registerReceiver() และบริบทนั้นยังคงถูกต้อง
  • ระบบจะไม่ส่งการประกาศ ACTION_NEW_PICTURE หรือ ACTION_NEW_VIDEO อีกต่อไป การเพิ่มประสิทธิภาพนี้ส่งผลต่อแอปทั้งหมด ไม่ใช่เฉพาะแอปที่กำหนดเป้าหมายเป็น Android 7.0

หากแอปของคุณใช้ Intent เหล่านี้ คุณควรนำทรัพยากร Dependency ออกโดยเร็วที่สุดเพื่อให้กำหนดเป้าหมายอุปกรณ์ Android 7.0 ได้อย่างเหมาะสม เฟรมเวิร์ก Android มีโซลูชันหลายอย่างเพื่อลดความจำเป็นในการใช้การกระจายข้อมูลแบบไม่เจาะจงปลายทางเหล่านี้ ตัวอย่างเช่น JobScheduler API มีกลไกที่มีประสิทธิภาพในการกำหนดเวลาการทำงานของเครือข่ายเมื่อเป็นไปตามเงื่อนไขที่ระบุ เช่น การเชื่อมต่อกับเครือข่ายที่ไม่มีการวัดปริมาณอินเทอร์เน็ต คุณยังใช้ JobScheduler เพื่อตอบสนองต่อการเปลี่ยนแปลงใน Content Provider ได้ด้วย

ดูข้อมูลเพิ่มเติมเกี่ยวกับการเพิ่มประสิทธิภาพเบื้องหลังใน Android 7.0 (ระดับ API 24) และวิธีปรับแอปได้ที่การเพิ่มประสิทธิภาพเบื้องหลัง

การเปลี่ยนแปลงสิทธิ์

Android 7.0 มีการเปลี่ยนแปลงสิทธิ์ที่อาจส่งผลต่อแอปของคุณ

การเปลี่ยนแปลงสิทธิ์ของระบบไฟล์

เพื่อปรับปรุงความปลอดภัยของไฟล์ส่วนตัว ไดเรกทอรีส่วนตัวของแอปที่กำหนดเป้าหมายเป็น Android 7.0 ขึ้นไปจึงมีการจำกัดการเข้าถึง (0700) การตั้งค่านี้จะป้องกันการรั่วไหลของข้อมูลเมตาของไฟล์ส่วนตัว เช่น ขนาดหรือการมีอยู่ของไฟล์ การเปลี่ยนแปลงสิทธิ์นี้มีผลข้างเคียงหลายประการ ดังนี้

  • เจ้าของไม่ควรผ่อนปรนสิทธิ์ในไฟล์ของไฟล์ส่วนตัวอีกต่อไป และการพยายามดำเนินการดังกล่าวโดยใช้ MODE_WORLD_READABLE และ/หรือ MODE_WORLD_WRITEABLE จะทริกเกอร์ SecurityException

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

  • การส่ง URI file:// นอกโดเมนแพ็กเกจอาจทำให้ผู้รับมีเส้นทางที่เข้าถึงไม่ได้ ดังนั้น การพยายามส่ง file:// URI จะทริกเกอร์ FileUriExposedException วิธีที่แนะนำในการแชร์เนื้อหาของไฟล์ส่วนตัวคือการใช้ FileProvider
  • DownloadManager จะแชร์ไฟล์ที่จัดเก็บแบบส่วนตัวตามชื่อไฟล์ไม่ได้อีกต่อไป แอปพลิเคชันเดิมอาจมีเส้นทางที่เข้าถึงไม่ได้เมื่อเข้าถึง COLUMN_LOCAL_FILENAME แอปที่กำหนดเป้าหมายเป็น Android 7.0 ขึ้นไปจะเรียกใช้ SecurityException เมื่อพยายามเข้าถึง COLUMN_LOCAL_FILENAME แอปพลิเคชันเดิมที่ตั้งค่าตำแหน่งการดาวน์โหลดเป็นตำแหน่งสาธารณะโดยใช้ DownloadManager.Request.setDestinationInExternalFilesDir() หรือ DownloadManager.Request.setDestinationInExternalPublicDir() จะยังคงเข้าถึงเส้นทางใน COLUMN_LOCAL_FILENAME ได้ แต่เราไม่แนะนำให้ใช้วิธีนี้ วิธีที่แนะนำในการเข้าถึงไฟล์ที่ DownloadManager แสดงคือการใช้ ContentResolver.openFileDescriptor()

การแชร์ไฟล์ระหว่างแอป

สำหรับแอปที่กำหนดเป้าหมายเป็น Android 7.0 เฟรมเวิร์ก Android จะบังคับใช้นโยบาย API StrictMode ที่ห้ามไม่ให้เปิดเผย URI file:// นอกแอป หาก Intent ที่มี URI ของไฟล์ออกจากแอป แอปจะทำงานไม่สำเร็จโดยมีข้อยกเว้น FileUriExposedException

หากต้องการแชร์ไฟล์ระหว่างแอปพลิเคชัน คุณควรส่ง URI content:// และให้สิทธิ์เข้าถึงชั่วคราวใน URI วิธีที่ง่ายที่สุดในการให้สิทธิ์นี้คือการใช้คลาส FileProvider ดูข้อมูลเพิ่มเติมเกี่ยวกับสิทธิ์และการแชร์ไฟล์ได้ที่หัวข้อการแชร์ไฟล์

การปรับปรุงการเข้าถึง

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

การซูมหน้าจอ

Android 7.0 ช่วยให้ผู้ใช้ตั้งค่าขนาดการแสดงผลซึ่งจะขยายหรือย่อองค์ประกอบทั้งหมดบนหน้าจอได้ จึงช่วยปรับปรุงการช่วยเหลือพิเศษของอุปกรณ์สำหรับผู้ใช้ที่มีสายตาเลือนราง ผู้ใช้ไม่สามารถซูมหน้าจอเกินความกว้างหน้าจอขั้นต่ำที่ sw320dp ซึ่งเป็นความกว้างของ Nexus 4 ซึ่งเป็นโทรศัพท์ขนาดกลางที่พบได้ทั่วไป

หน้าจอแสดงขนาดการแสดงผลที่ไม่ได้ซูมของอุปกรณ์ที่ใช้อิมเมจระบบ Android 7.0
หน้าจอแสดงผลของการเพิ่มขนาดการแสดงผลของอุปกรณ์ที่ใช้ภาพระบบ Android 7.0

รูปที่ 3 หน้าจอทางด้านขวาแสดงผลของการเพิ่มขนาดการแสดงผลของอุปกรณ์ที่ใช้ภาพระบบ Android 7.0

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

  • หากแอปกำหนดเป้าหมายเป็น API ระดับ 23 หรือต่ำกว่า ระบบจะหยุดกระบวนการเบื้องหลังทั้งหมดโดยอัตโนมัติ ซึ่งหมายความว่าหากผู้ใช้ออกจากแอปดังกล่าวเพื่อเปิดหน้าจอการตั้งค่าและเปลี่ยนการตั้งค่าขนาดการแสดงผล ระบบจะปิดแอปในลักษณะเดียวกับที่ทำในสถานการณ์ที่หน่วยความจำเหลือน้อย หากแอปมีกระบวนการทำงานอยู่เบื้องหน้า ระบบจะแจ้งกระบวนการเหล่านั้นเกี่ยวกับการเปลี่ยนแปลงการกำหนดค่าตามที่อธิบายไว้ในการจัดการการเปลี่ยนแปลงรันไทม์ เช่นเดียวกับกรณีที่การวางแนวของอุปกรณ์มีการเปลี่ยนแปลง
  • หากแอปกำหนดเป้าหมายเป็น Android 7.0 กระบวนการทั้งหมด (เบื้องหน้าและเบื้องหลัง) จะได้รับแจ้งการเปลี่ยนแปลงการกำหนดค่าตามที่อธิบายไว้ในการจัดการการเปลี่ยนแปลงรันไทม์

แอปส่วนใหญ่ไม่จำเป็นต้องทำการเปลี่ยนแปลงใดๆ เพื่อรองรับฟีเจอร์นี้ หากแอปเป็นไปตามแนวทางปฏิบัติแนะนำของ Android สิ่งที่ต้องตรวจสอบเป็นการเฉพาะมีดังนี้

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

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

  • หลีกเลี่ยงการระบุขนาดด้วยหน่วย px เนื่องจากไม่ได้ปรับขนาดตามความหนาแน่นของหน้าจอ แต่ให้ระบุขนาดด้วยหน่วยความหนาแน่นของพิกเซลอิสระ (dp) แทน

การตั้งค่าการมองเห็นในวิซาร์ดการตั้งค่า

Android 7.0 มีการตั้งค่าการมองเห็นในหน้าจอต้อนรับ ซึ่งผู้ใช้สามารถตั้งค่าการช่วยเหลือพิเศษต่อไปนี้ในอุปกรณ์ใหม่ได้ ได้แก่ ท่าทางการขยาย, ขนาดแบบอักษร, ขนาดการแสดงผล และ TalkBack การเปลี่ยนแปลงนี้จะเพิ่มระดับการมองเห็นข้อบกพร่องที่เกี่ยวข้องกับการตั้งค่าหน้าจอต่างๆ หากต้องการประเมินผลกระทบของฟีเจอร์นี้ คุณควรทดสอบแอปโดยเปิดใช้การตั้งค่าเหล่านี้ คุณดูการตั้งค่าได้ในส่วนการตั้งค่า > การช่วยเหลือพิเศษ

แอป NDK ที่ลิงก์กับไลบรารีแพลตฟอร์ม

ตั้งแต่ Android 7.0 เป็นต้นไป ระบบจะป้องกันไม่ให้แอปเชื่อมโยงแบบไดนามิกกับไลบรารีที่ไม่ใช่ NDK ซึ่งอาจทำให้แอปขัดข้อง การเปลี่ยนแปลงลักษณะการทำงานนี้มีจุดประสงค์เพื่อสร้างประสบการณ์การใช้งานแอปที่สอดคล้องกันในการอัปเดตแพลตฟอร์มและอุปกรณ์ต่างๆ แม้ว่าโค้ดของคุณอาจไม่ได้ลิงก์กับไลบรารีส่วนตัว แต่ก็เป็นไปได้ว่าไลบรารีแบบคงที่ของบุคคลที่สามในแอปอาจลิงก์อยู่ ดังนั้นนักพัฒนาแอปทุกคนควรตรวจสอบให้แน่ใจว่าแอปของตนไม่ขัดข้องในอุปกรณ์ที่ใช้ Android 7.0 หากแอปใช้โค้ดแบบเนทีฟ คุณควรใช้เฉพาะ NDK API สาธารณะเท่านั้น

แอปของคุณอาจพยายามเข้าถึง API แพลตฟอร์มส่วนตัวได้ 3 วิธี ดังนี้

  • แอปของคุณเข้าถึงไลบรารีแพลตฟอร์มส่วนตัวโดยตรง คุณควรอัปเดตแอปให้มีสำเนาของไลบรารีเหล่านั้นเป็นของตัวเอง หรือใช้ NDK API สาธารณะ
  • แอปของคุณใช้ไลบรารีของบุคคลที่สามที่เข้าถึงไลบรารีแพลตฟอร์มส่วนตัว แม้ว่าคุณจะแน่ใจว่าแอปไม่ได้เข้าถึงไลบรารีส่วนตัวโดยตรง แต่ก็ควรทดสอบแอปสำหรับสถานการณ์นี้ด้วย
  • แอปของคุณอ้างอิงถึงไลบรารีที่ไม่ได้รวมอยู่ใน APK ตัวอย่างเช่น กรณีนี้อาจเกิดขึ้นหากคุณพยายามใช้สำเนา OpenSSL ของคุณเอง แต่ลืมรวมไว้กับ APK ของแอป แอปอาจทำงานได้ตามปกติในแพลตฟอร์ม Android เวอร์ชันที่มี libcrypto.so อย่างไรก็ตาม แอปอาจขัดข้องใน Android เวอร์ชันใหม่ๆ ที่ไม่มีไลบรารีนี้ (เช่น Android 6.0 ขึ้นไป) วิธีแก้ไขปัญหานี้คือตรวจสอบว่าคุณรวมไลบรารีที่ไม่ใช่ NDK ทั้งหมดไว้กับ APK

แอปไม่ควรใช้ไลบรารีแบบเนทีฟที่ไม่ได้รวมอยู่ใน NDK เนื่องจากไลบรารีดังกล่าวอาจมีการเปลี่ยนแปลงหรือถูกนำออกระหว่าง Android เวอร์ชันต่างๆ การเปลี่ยนจาก OpenSSL เป็น BoringSSL เป็นตัวอย่างหนึ่งของการเปลี่ยนแปลงดังกล่าว นอกจากนี้ เนื่องจากไม่มีข้อกำหนดด้านความเข้ากันได้สำหรับไลบรารีแพลตฟอร์มที่ไม่ได้รวมอยู่ใน NDK อุปกรณ์แต่ละเครื่องจึงอาจให้ความเข้ากันได้ในระดับที่แตกต่างกัน

เพื่อลดผลกระทบที่ข้อจำกัดนี้อาจมีต่อแอปที่เผยแพร่อยู่ในปัจจุบัน ชุดไลบรารีที่มีการใช้งานอย่างมาก เช่น libandroid_runtime.so, libcutils.so, libcrypto.so และ libssl.so จะเข้าถึงได้ชั่วคราวใน Android 7.0 (API ระดับ 24) สำหรับแอปที่กำหนดเป้าหมายเป็น API ระดับ 23 หรือต่ำกว่า หากแอปโหลดไลบรารีเหล่านี้ ไลบรารี logcat จะสร้างคำเตือนและข้อความโทสต์จะปรากฏในอุปกรณ์เป้าหมายเพื่อแจ้งให้คุณทราบ หากเห็นคำเตือนเหล่านี้ คุณควรอัปเดตแอปให้รวมสำเนาของไลบรารีเหล่านั้นไว้ด้วย หรือใช้เฉพาะ NDK API สาธารณะเท่านั้น แพลตฟอร์ม Android เวอร์ชันในอนาคตอาจจำกัดการใช้ไลบรารีส่วนตัวทั้งหมดและทำให้แอปขัดข้อง

แอปทั้งหมดจะสร้างข้อผิดพลาดขณะรันไทม์เมื่อเรียกใช้ API ที่ไม่ใช่แบบสาธารณะหรือเข้าถึงได้ชั่วคราว ผลลัพธ์คือทั้ง System.loadLibrary และ dlopen(3) จะแสดงผลเป็น NULL และอาจทำให้แอปขัดข้อง คุณควรตรวจสอบโค้ดของแอปเพื่อนำการใช้ API ของแพลตฟอร์มส่วนตัวออก และทดสอบแอปอย่างละเอียดโดยใช้อุปกรณ์หรือโปรแกรมจำลองที่ใช้ Android 7.0 (ระดับ API 24) หากไม่แน่ใจว่าแอปใช้ไลบรารีส่วนตัวหรือไม่ คุณสามารถตรวจสอบ logcat เพื่อระบุข้อผิดพลาดขณะรันไทม์ได้

ตารางต่อไปนี้อธิบายลักษณะการทำงานที่คุณควรคาดหวังว่าจะได้เห็นจากแอป โดยขึ้นอยู่กับการใช้ไลบรารีแบบเนทีฟส่วนตัวและระดับ API เป้าหมาย (android:targetSdkVersion)

ห้องสมุด ระดับ API เป้าหมาย สิทธิ์เข้าถึงรันไทม์โดยใช้ Linker แบบไดนามิก ลักษณะการทำงานของ Android 7.0 (ระดับ API 24) ลักษณะการทำงานของแพลตฟอร์ม Android ในอนาคต
NDK สาธารณะ ช่วง รองรับผู้พิการ ทำงานได้ตามที่คาดไว้ ทำงานได้ตามที่คาดไว้
ส่วนตัว (ไลบรารีส่วนตัวที่เข้าถึงได้ชั่วคราว) 23 หรือต่ำกว่า เข้าถึงได้ชั่วคราว ทำงานได้ตามที่คาดไว้ แต่คุณจะได้รับคำเตือน Logcat ข้อผิดพลาดขณะรันไทม์
ส่วนตัว (ไลบรารีส่วนตัวที่เข้าถึงได้ชั่วคราว) 24 ขึ้นไป จำกัด ข้อผิดพลาดขณะรันไทม์ ข้อผิดพลาดขณะรันไทม์
ส่วนตัว (อื่นๆ) ช่วง จำกัด ข้อผิดพลาดขณะรันไทม์ ข้อผิดพลาดขณะรันไทม์

ตรวจสอบว่าแอปใช้ไลบรารีส่วนตัวหรือไม่

logcat อาจสร้างคำเตือนหรือข้อผิดพลาดขณะรันไทม์เพื่อช่วยคุณระบุปัญหาในการโหลดไลบรารีส่วนตัว ตัวอย่างเช่น หากแอปกำหนดเป้าหมายเป็นระดับ API เป้าหมาย 23 หรือต่ำกว่า และพยายามเข้าถึงไลบรารีส่วนตัวในอุปกรณ์ที่ใช้ Android 7.0 คุณอาจเห็นคำเตือนที่คล้ายกับข้อความต่อไปนี้

03-21 17:07:51.502 31234 31234 W linker  : library "libandroid_runtime.so"
("/system/lib/libandroid_runtime.so") needed or dlopened by
"/data/app/com.popular-app.android-2/lib/arm/libapplib.so" is not accessible
for the namespace "classloader-namespace" - the access is temporarily granted
as a workaround for http://b/26394120

คำเตือน logcat เหล่านี้จะบอกคุณว่าไลบรารีใดกำลังพยายามเข้าถึง API แพลตฟอร์มส่วนตัว แต่จะไม่ทำให้แอปของคุณขัดข้อง อย่างไรก็ตาม หากแอปกำหนดเป้าหมายเป็น API ระดับ 24 ขึ้นไป logcat จะสร้างข้อผิดพลาดขณะรันไทม์ต่อไปนี้และแอปอาจขัดข้อง

java.lang.UnsatisfiedLinkError: dlopen failed: library "libcutils.so"
("/system/lib/libcutils.so") needed or dlopened by
"/system/lib/libnativeloader.so" is not accessible for the namespace
"classloader-namespace"
  at java.lang.Runtime.loadLibrary0(Runtime.java:977)
  at java.lang.System.loadLibrary(System.java:1602)

คุณอาจเห็นเอาต์พุต logcat เหล่านี้ด้วยหากแอปใช้ไลบรารีของบุคคลที่สามซึ่งลิงก์กับ API แพลตฟอร์มส่วนตัวแบบไดนามิก เครื่องมือ readelf ใน Android 7.0 NDK ช่วยให้คุณสร้างรายการไลบรารีที่ใช้ร่วมกันซึ่งลิงก์แบบไดนามิกทั้งหมดของไฟล์ .so ที่ระบุได้โดยเรียกใช้คำสั่งต่อไปนี้

aarch64-linux-android-readelf -dW libMyLibrary.so

อัปเดตแอป

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

  • หากแอปใช้ไลบรารีแพลตฟอร์มส่วนตัว คุณควรอัปเดตแอปให้มีสำเนาไลบรารีเหล่านั้นเป็นของตัวเองหรือใช้ NDK API สาธารณะ
  • หากแอปใช้ไลบรารีของบุคคลที่สามซึ่งเข้าถึงสัญลักษณ์ส่วนตัว โปรดติดต่อผู้เขียนไลบรารีเพื่ออัปเดตไลบรารี
  • ตรวจสอบว่าคุณได้รวมไลบรารีที่ไม่ใช่ NDK ทั้งหมดไว้ใน APK แล้ว
  • ใช้ฟังก์ชัน JNI มาตรฐานแทน getJavaVM และ getJNIEnv จาก libandroid_runtime.so:
    AndroidRuntime::getJavaVM -> GetJavaVM from <jni.h>
    AndroidRuntime::getJNIEnv -> JavaVM::GetEnv or
    JavaVM::AttachCurrentThread from <jni.h>.
    
  • ใช้ __system_property_get แทนสัญลักษณ์ property_get ส่วนตัวจาก libcutils.so โดยใช้ __system_property_get พร้อมกับรายการต่อไปนี้
    #include <sys/system_properties.h>

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

  • ใช้สัญลักษณ์ SSL_ctrl เวอร์ชันท้องถิ่นจาก libcrypto.so เช่น คุณควรลิงก์ libcyrpto.a แบบคงที่ในไฟล์ .so หรือรวม libcrypto.so เวอร์ชันที่ลิงก์แบบไดนามิกจาก BoringSSL/OpenSSL และรวมไว้ใน APK

Android for Work

Android 7.0 มีการเปลี่ยนแปลงสำหรับแอปที่กำหนดเป้าหมายเป็น Android for Work ซึ่งรวมถึงการเปลี่ยนแปลงการติดตั้งใบรับรอง การรีเซ็ตรหัสผ่าน การจัดการผู้ใช้รอง และการเข้าถึงตัวระบุอุปกรณ์ หากคุณกำลังสร้างแอปสำหรับสภาพแวดล้อม Android for Work คุณควรตรวจสอบการเปลี่ยนแปลงเหล่านี้และแก้ไขแอปตามความเหมาะสม

  • คุณต้องติดตั้งโปรแกรมติดตั้งใบรับรองที่ได้รับมอบสิทธิ์ก่อนที่ DPC จะตั้งค่าได้ สำหรับทั้งแอปโปรไฟล์และแอปเจ้าของอุปกรณ์ที่กำหนดเป้าหมายเป็น Android 7.0 (ระดับ API 24) คุณควรติดตั้งโปรแกรมติดตั้งใบรับรองที่ได้รับมอบสิทธิ์ก่อนที่เครื่องมือควบคุมนโยบายด้านอุปกรณ์ (DPC) จะเรียกใช้ DevicePolicyManager.setCertInstallerPackage() หากยังไม่ได้ติดตั้งโปรแกรมติดตั้ง ระบบจะแสดงข้อผิดพลาด IllegalArgumentException
  • ข้อจำกัดการรีเซ็ตรหัสผ่านสำหรับผู้ดูแลระบบอุปกรณ์จะมีผลกับเจ้าของโปรไฟล์แล้ว ผู้ดูแลระบบอุปกรณ์จะไม่สามารถใช้ DevicePolicyManager.resetPassword() เพื่อล้างรหัสผ่านหรือเปลี่ยนรหัสผ่านที่ตั้งไว้แล้วได้อีกต่อไป ผู้ดูแลระบบอุปกรณ์จะยังคงตั้งรหัสผ่านได้ แต่จะทำได้เฉพาะเมื่ออุปกรณ์ไม่มีรหัสผ่าน, PIN หรือรูปแบบเท่านั้น
  • เจ้าของอุปกรณ์และโปรไฟล์จะจัดการบัญชีได้แม้ว่าจะมีการตั้งค่าข้อจำกัดไว้ก็ตาม เจ้าของอุปกรณ์และเจ้าของโปรไฟล์สามารถเรียกใช้ Account Management API ได้แม้ว่าจะมีข้อจำกัดของผู้ใช้ DISALLOW_MODIFY_ACCOUNTS อยู่ก็ตาม
  • เจ้าของอุปกรณ์สามารถจัดการผู้ใช้รองได้ เมื่ออุปกรณ์ทำงานในโหมดเจ้าของอุปกรณ์ ระบบจะตั้งค่าข้อจำกัด DISALLOW_ADD_USER โดยอัตโนมัติ ซึ่งจะป้องกันไม่ให้ผู้ใช้สร้างผู้ใช้รองที่ไม่มีการจัดการ นอกจากนี้ เมธอด CreateUser() และ createAndInitializeUser() เลิกใช้งานแล้ว โดยมีเมธอด DevicePolicyManager.createAndManageUser() ใหม่มาแทนที่
  • เจ้าของอุปกรณ์จะเข้าถึงตัวระบุอุปกรณ์ได้ เจ้าของอุปกรณ์สามารถเข้าถึงที่อยู่ MAC ของ Wi-Fi ของอุปกรณ์ได้โดยใช้ DevicePolicyManager.getWifiMacAddress() หากไม่เคยเปิดใช้ Wi-Fi ในอุปกรณ์ เมธอดนี้จะแสดงผลค่าเป็น null
  • การตั้งค่าโหมดการทำงานจะควบคุมสิทธิ์เข้าถึงแอปงาน เมื่อโหมดงานปิดอยู่ ตัวเปิดระบบจะระบุว่าแอปงานไม่พร้อมใช้งานโดยเปลี่ยนเป็นสีเทา การเปิดใช้โหมดการทำงานอีกครั้งจะคืนค่าลักษณะการทำงานตามปกติ
  • เมื่อติดตั้งไฟล์ PKCS #12 ที่มีกลุ่มใบรับรองไคลเอ็นต์และคีย์ส่วนตัวที่เกี่ยวข้องจาก UI การตั้งค่า ระบบจะไม่ติดตั้งใบรับรอง CA ในกลุ่มใบรับรองลงในที่เก็บข้อมูลเข้าสู่ระบบที่เชื่อถือได้อีกต่อไป การดำเนินการนี้จะไม่ส่งผลต่อผลลัพธ์ของ KeyChain.getCertificateChain() เมื่อแอปพยายามดึงข้อมูลเชนใบรับรองไคลเอ็นต์ในภายหลัง หากจำเป็น ควรติดตั้งใบรับรอง CA ลงในที่เก็บข้อมูลเข้าสู่ระบบที่เชื่อถือได้โดยใช้ UI การตั้งค่าแยกต่างหาก โดยใช้รูปแบบที่เข้ารหัส DER ภายใต้นามสกุลไฟล์ .crt หรือ .cer
  • ตั้งแต่ Android 7.0 เป็นต้นไป ระบบจะจัดการการลงทะเบียนและการจัดเก็บลายนิ้วมือตามผู้ใช้แต่ละราย หาก Device Policy Client (DPC) ของเจ้าของโปรไฟล์กำหนดเป้าหมายเป็น API ระดับ 23 (หรือต่ำกว่า) ในอุปกรณ์ที่ใช้ Android 7.0 (API ระดับ 24) ผู้ใช้จะยังคงตั้งค่าลายนิ้วมือในอุปกรณ์ได้ แต่แอปพลิเคชันงานจะเข้าถึงลายนิ้วมือของอุปกรณ์ไม่ได้ เมื่อ DPC กำหนดเป้าหมายเป็นระดับ API เป้าหมาย 24 ขึ้นไป ผู้ใช้จะตั้งค่าลายนิ้วมือสำหรับโปรไฟล์งานโดยเฉพาะได้โดยไปที่การตั้งค่า > ความปลอดภัย > ความปลอดภัยของโปรไฟล์งาน
  • DevicePolicyManager.getStorageEncryptionStatus() จะแสดงสถานะการเข้ารหัสใหม่ ENCRYPTION_STATUS_ACTIVE_PER_USER เพื่อระบุว่าการเข้ารหัสทำงานอยู่และคีย์การเข้ารหัสเชื่อมโยงกับผู้ใช้ ระบบจะแสดงสถานะใหม่ก็ต่อเมื่อ DPC กำหนดเป้าหมายเป็น API ระดับ 24 ขึ้นไปเท่านั้น สำหรับแอปที่กำหนดเป้าหมายเป็นระดับ API ก่อนหน้า ระบบจะแสดงผล ENCRYPTION_STATUS_ACTIVE แม้ว่าคีย์การเข้ารหัสจะเจาะจงสำหรับผู้ใช้หรือโปรไฟล์ก็ตาม
  • ใน Android 7.0 เมธอดหลายรายการที่โดยปกติจะส่งผลต่อทั้งอุปกรณ์จะทำงานแตกต่างออกไปหากอุปกรณ์มีโปรไฟล์งานที่ติดตั้งพร้อมกับ Work Challenge แยกต่างหาก วิธีการเหล่านี้จะมีผลกับโปรไฟล์งานเท่านั้น แทนที่จะส่งผลต่ออุปกรณ์ทั้งเครื่อง (ดูรายการเมธอดทั้งหมดได้ในเอกสารประกอบของ DevicePolicyManager.getParentProfileInstance()) เช่น DevicePolicyManager.lockNow() จะล็อกเฉพาะโปรไฟล์งานแทนที่จะล็อกทั้งอุปกรณ์ สำหรับแต่ละเมธอดเหล่านี้ คุณสามารถรับลักษณะการทำงานเดิมได้โดยเรียกใช้เมธอดในอินสแตนซ์หลักของ DevicePolicyManager คุณสามารถรับอินสแตนซ์หลักนี้ได้โดยเรียกใช้ DevicePolicyManager.getParentProfileInstance() ตัวอย่างเช่น หากคุณเรียกใช้เมธอด lockNow() ของอินสแตนซ์หลัก อุปกรณ์ทั้งหมดจะล็อก

การเก็บรักษาคำอธิบายประกอบ

Android 7.0 แก้ไขข้อบกพร่องที่ระบบละเว้นระดับการมองเห็นของคำอธิบายประกอบ ปัญหานี้ทำให้รันไทม์เข้าถึงคำอธิบายประกอบที่ไม่ควรเข้าถึงได้ ซึ่งได้แก่

  • VISIBILITY_BUILD: มีไว้ให้มองเห็นได้เฉพาะในเวลาบิลด์เท่านั้น
  • VISIBILITY_SYSTEM: มีไว้เพื่อให้มองเห็นได้ขณะรันไทม์ แต่เฉพาะกับระบบที่เกี่ยวข้องเท่านั้น

หากแอปของคุณอาศัยลักษณะการทำงานนี้ ให้เพิ่มนโยบายการเก็บรักษาลงในคำอธิบายประกอบที่ต้องพร้อมใช้งานที่รันไทม์ โดยใช้ @Retention(RetentionPolicy.RUNTIME)

การเปลี่ยนแปลงการกำหนดค่าเริ่มต้นของ TLS/SSL

Android 7.0 มีการเปลี่ยนแปลงต่อไปนี้ในการกำหนดค่า TLS/SSL เริ่มต้นที่แอปใช้สำหรับการรับส่งข้อมูล HTTPS และ TLS/SSL อื่นๆ

  • ตอนนี้ชุดการเข้ารหัส RC4 ปิดใช้อยู่
  • เปิดใช้ชุดการเข้ารหัส CHACHA20-POLY1305 แล้ว

การปิดใช้ RC4 โดยค่าเริ่มต้นอาจทำให้การเชื่อมต่อ HTTPS หรือ TLS/SSL ขัดข้องเมื่อเซิร์ฟเวอร์ไม่เจรจาต่อรองชุดการเข้ารหัสสมัยใหม่ การแก้ไขที่แนะนำคือการปรับปรุงการกำหนดค่าของเซิร์ฟเวอร์เพื่อเปิดใช้ชุดการเข้ารหัสและโปรโตคอลที่รัดกุมและทันสมัยยิ่งขึ้น โดยหลักการแล้ว ควรเปิดใช้ TLSv1.2 และ AES-GCM และควรเปิดใช้และเลือกใช้ชุดการเข้ารหัส Forward Secrecy (ECDHE)

อีกทางเลือกหนึ่งคือการแก้ไขแอปให้ใช้ SSLSocketFactory ที่กำหนดเองเพื่อสื่อสารกับเซิร์ฟเวอร์ ควรออกแบบโรงงานให้สร้างอินสแตนซ์ SSLSocket ที่เปิดใช้ชุดการเข้ารหัสบางชุดที่เซิร์ฟเวอร์กำหนดไว้นอกเหนือจากชุดการเข้ารหัสเริ่มต้น

หมายเหตุ: การเปลี่ยนแปลงเหล่านี้ไม่เกี่ยวข้องกับ WebView

แอปที่กำหนดเป้าหมายเป็น Android 7.0

การเปลี่ยนแปลงลักษณะการทำงานเหล่านี้มีผลเฉพาะกับแอปที่กำหนดเป้าหมายเป็น Android 7.0 (ระดับ API 24) ขึ้นไปเท่านั้น แอปที่คอมไพล์กับ Android 7.0 หรือตั้งค่า targetSdkVersion เป็น Android 7.0 ขึ้นไปต้องแก้ไขแอปเพื่อรองรับลักษณะการทำงานเหล่านี้อย่างเหมาะสม หากเกี่ยวข้องกับแอป

การเปลี่ยนแปลงการเรียงอันดับ

Android 7.0 (ระดับ API 24) แก้ไขข้อบกพร่องในการคำนวณ serialVersionUID เริ่มต้นซึ่งไม่ตรงกับข้อกำหนดเฉพาะ

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

local class incompatible: stream classdesc serialVersionUID = 1234, local class serialVersionUID = 4567

การแก้ไขปัญหาเหล่านี้ต้องเพิ่มช่อง serialVersionUID ลงในคลาสที่ได้รับผลกระทบซึ่งมีค่าเป็น stream classdesc serialVersionUID จากข้อความแสดงข้อผิดพลาด เช่น 1234 ในกรณีนี้ การเปลี่ยนแปลงดังกล่าวเป็นไปตามคำแนะนำแนวทางปฏิบัติแนะนำทั้งหมดสำหรับการเขียนโค้ดการเรียงลำดับข้อมูล และจะใช้ได้กับ Android ทุกเวอร์ชัน

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

โปรดทราบว่าการเปลี่ยนแปลงนี้ไม่ส่งผลต่อแอปที่กำหนดเป้าหมายเป็น API ระดับ 23 หรือต่ำกว่า, คลาสที่มีช่อง serialVersionUID หรือคลาสที่มีเมธอดตัวเริ่มต้นแบบคงที่

ประเด็นสำคัญอื่นๆ

  • เมื่อแอปทำงานบน Android 7.0 แต่กำหนดเป้าหมายเป็นระดับ API ที่ต่ำกว่า และผู้ใช้เปลี่ยนขนาดการแสดงผล ระบบจะหยุดกระบวนการของแอป แอปต้องสามารถจัดการสถานการณ์นี้ได้อย่างราบรื่น มิฉะนั้น แอปจะขัดข้องเมื่อผู้ใช้กู้คืนจากรายการล่าสุด

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

    แอปที่กำหนดเป้าหมายเป็น Android 7.0 (ระดับ API 24) ขึ้นไปจะไม่ถูกปิดโดยอัตโนมัติเมื่อความหนาแน่นเปลี่ยนแปลง แต่ก็อาจยังตอบสนองต่อการเปลี่ยนแปลงการกำหนดค่าได้ไม่ดีนัก

  • แอปใน Android 7.0 ควรจัดการกับการเปลี่ยนแปลงการกำหนดค่าได้อย่างราบรื่น และไม่ควรขัดข้องเมื่อเริ่มทำงานในครั้งต่อๆ ไป คุณสามารถตรวจสอบลักษณะการทำงานของแอปได้โดยเปลี่ยนขนาดแบบอักษร (การตั้งค่า > การแสดงผล > ขนาดแบบอักษร) แล้วกู้คืนแอปจากรายการล่าสุด
  • เนื่องจากข้อบกพร่องใน Android เวอร์ชันก่อนหน้า ระบบจึงไม่ได้แจ้งว่าการเขียนไปยังซ็อกเก็ต TCP ในเทรดหลักเป็นการละเมิดโหมดเข้มงวด Android 7.0 แก้ไขข้อบกพร่องนี้แล้ว แอปที่แสดงลักษณะการทำงานนี้จะแสดง android.os.NetworkOnMainThreadException โดยทั่วไปแล้ว การดำเนินการเครือข่ายในเทรดหลักไม่ใช่แนวทางที่ดีเนื่องจากการดำเนินการเหล่านี้ มักจะมีเวลาในการตอบสนองสูงซึ่งทำให้เกิด ANR และอาการกระตุก
  • ตอนนี้เมธอดตระกูล Debug.startMethodTracing() จะจัดเก็บเอาต์พุตในไดเรกทอรีเฉพาะแพ็กเกจในพื้นที่เก็บข้อมูลที่ใช้ร่วมกันโดยค่าเริ่มต้น แทนที่จะจัดเก็บไว้ที่ระดับบนสุดของการ์ด SD ซึ่งหมายความว่าแอปไม่จำเป็นต้องขอสิทธิ์ WRITE_EXTERNAL_STORAGE เพื่อใช้ API เหล่านี้อีกต่อไป
  • ตอนนี้ API ของแพลตฟอร์มจำนวนมากเริ่มตรวจสอบเพย์โหลดขนาดใหญ่ที่ส่งผ่านธุรกรรม Binder และตอนนี้ระบบจะส่ง TransactionTooLargeExceptions อีกครั้งเป็น RuntimeExceptions แทนที่จะบันทึกหรือระงับโดยไม่แจ้งให้ทราบ ตัวอย่างที่พบบ่อยคือการจัดเก็บข้อมูลมากเกินไปใน Activity.onSaveInstanceState() ซึ่งทำให้ ActivityThread.StopInfo แสดง RuntimeException เมื่อแอปกำหนดเป้าหมายเป็น Android 7.0
  • หากแอปโพสต์งาน Runnable ไปยัง View และ View ไม่ได้แนบกับหน้าต่าง ระบบจะจัดคิวงาน Runnable ด้วย View งาน Runnable จะไม่ทำงานจนกว่า View จะแนบกับหน้าต่าง ลักษณะการทำงานนี้จะแก้ไขข้อบกพร่องต่อไปนี้
    • หากแอปโพสต์ไปยัง View จากเธรดอื่นที่ไม่ใช่เธรด UI ของหน้าต่างที่ต้องการ Runnable อาจทำงานในเธรดที่ไม่ถูกต้อง
    • หากมีการโพสต์งาน Runnable จากชุดข้อความอื่นที่ไม่ใช่ ชุดข้อความ Looper แอปอาจแสดงงาน Runnable
  • หากแอปใน Android 7.0 ที่มีสิทธิ์ DELETE_PACKAGES พยายามลบแพ็กเกจ แต่แอปอื่นได้ติดตั้งแพ็กเกจนั้นไว้ ระบบจะกำหนดให้ผู้ใช้ยืนยัน ในสถานการณ์นี้ แอปควรคาดหวังว่า STATUS_PENDING_USER_ACTION จะเป็นสถานะการแสดงผลเมื่อเรียกใช้ PackageInstaller.uninstall()
  • ผู้ให้บริการ JCA ที่ชื่อ Crypto เลิกใช้งานแล้ว เนื่องจากอัลกอริทึมเดียวของ JCA คือ SHA1PRNG มีการเข้ารหัสที่อ่อนแอ แอปจะไม่สามารถใช้ SHA1PRNG เพื่อรับคีย์ (อย่างไม่ปลอดภัย) ได้อีกต่อไป เนื่องจากผู้ให้บริการรายนี้ไม่พร้อมให้บริการอีกต่อไป ดูข้อมูลเพิ่มเติมได้ที่บล็อกโพสต์ผู้ให้บริการ "Crypto" ด้านความปลอดภัยที่เลิกใช้งานใน Android N