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

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

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

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

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

Doze

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

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

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

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

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

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

โปรดทราบว่าการเปิดใช้งานหน้าจอหรือเสียบปลั๊กอุปกรณ์จะออกจากโหมดสลีปและนำข้อจำกัดการประมวลผลเหล่านี้ออก ลักษณะการทำงานเพิ่มเติมนี้ไม่มีผลกับคําแนะนําและแนวทางปฏิบัติแนะนําในการปรับแอปให้เข้ากับ 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หากประกาศตัวรับการออกอากาศในไฟล์ Manifest แอปจะยังคงรับCONNECTIVITY_ACTIONการออกอากาศหากลงทะเบียนBroadcastReceiverกับ Context.registerReceiver() และบริบทนั้นยังคงใช้งานได้
  • ระบบจะไม่ส่งการออกอากาศ ACTION_NEW_PICTURE หรือ ACTION_NEW_VIDEO อีกต่อไป การเพิ่มประสิทธิภาพนี้มีผลกับแอปทั้งหมด ไม่ใช่เฉพาะแอปที่กำหนดเป้าหมายเป็น Android 7.0 เท่านั้น

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

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

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

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

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

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

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

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

  • การส่ง URI file:// นอกโดเมนของแพ็กเกจอาจทำให้ผู้รับมีเส้นทางที่เข้าถึงไม่ได้ ดังนั้น การพยายามส่ง URI file:// จะทริกเกอร์ 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 จะบังคับใช้StrictModeนโยบาย API ที่ห้ามแสดง URI file:// ภายนอกแอป หาก Intent ที่มี URI ไฟล์ออกจากแอป แอปจะดำเนินการไม่สําเร็จพร้อมข้อยกเว้น FileUriExposedException

หากต้องการแชร์ไฟล์ระหว่างแอปพลิเคชัน คุณควรส่ง content:// URI และมอบสิทธิ์เข้าถึงชั่วคราวใน 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 ของแพลตฟอร์มส่วนตัวด้วยวิธีต่อไปนี้

  • แอปของคุณเข้าถึงคลังแพลตฟอร์มส่วนตัวโดยตรง คุณควรอัปเดตแอปให้รวมสำเนาของไลบรารีเหล่านั้นไว้เอง หรือใช้ 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 เป้าหมาย การเข้าถึงรันไทม์ผ่านตัวลิงก์แบบไดนามิก ลักษณะการทํางานของ 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.0DK ช่วยให้คุณสร้างรายการไลบรารีที่แชร์ซึ่งลิงก์แบบไดนามิกทั้งหมดของไฟล์ .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 ต่อไปนี้
    #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 มีวิธีการมากมายที่โดยปกติแล้วจะส่งผลต่ออุปกรณ์ทั้งเครื่องจะทำงานต่างออกไปหากอุปกรณ์มีโปรไฟล์งานติดตั้งที่มีการทดสอบการทำงานแยกต่างหาก วิธีการเหล่านี้จะมีผลกับโปรไฟล์งานเท่านั้น โดยไม่ส่งผลต่อทั้งอุปกรณ์ (ดูรายการวิธีการทั้งหมดได้ใน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 ที่ชัดแจ้งอาจเห็นการเปลี่ยนแปลงในอนุกรมเวอร์ชัน UID เริ่มต้น ซึ่งจะก่อให้เกิดข้อยกเว้นเมื่อพยายามทำการดีซีเรียลไลซ์อินสแตนซ์ของคลาสที่มีการเรียงลำดับในเวอร์ชันก่อนหน้า หรือเรียงลำดับโดยแอปที่กำหนดเป้าหมายเป็นเวอร์ชันก่อนหน้า ข้อความแสดงข้อผิดพลาดจะมีลักษณะดังนี้

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 เลิกใช้งานแล้ว เนื่องจากอัลกอริทึม SHA1PRNG เพียงอัลกอริทึมเดียวของผู้ให้บริการนี้ไม่มีประสิทธิภาพในการเข้ารหัส แอปจะใช้ SHA1PRNG เพื่อดึงข้อมูลคีย์ (ที่ไม่ปลอดภัย) ไม่ได้อีกต่อไป เนื่องจากผู้ให้บริการนี้ไม่มีให้บริการแล้ว ดูข้อมูลเพิ่มเติมได้ที่บล็อกโพสต์เลิกใช้งานผู้ให้บริการ "Crypto" ด้านความปลอดภัยใน Android N