รองรับโหมดเปิดเครื่องโดยตรง

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

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

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

  • แอปที่มีการแจ้งเตือนตามกำหนดเวลา เช่น แอปนาฬิกาปลุก
  • แอปที่ให้การแจ้งเตือนที่สำคัญแก่ผู้ใช้ เช่น แอป SMS
  • แอปที่ให้บริการการช่วยเหลือพิเศษ เช่น TalkBack

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

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

ขอสิทธิ์เข้าถึงเพื่อเรียกใช้ระหว่างการเปิดเครื่องโดยตรง

แอปต้องลงทะเบียนคอมโพเนนต์กับระบบก่อนจึงจะทำงานในโหมด Direct Boot หรือเข้าถึงพื้นที่เก็บข้อมูลที่เข้ารหัสของอุปกรณ์ได้ แอปจะลงทะเบียนกับระบบโดยทำเครื่องหมายคอมโพเนนต์เป็นรับรู้การเข้ารหัส หากต้องการทำเครื่องหมายคอมโพเนนต์ว่ารับรู้การเข้ารหัส ให้ตั้งค่าแอตทริบิวต์ android:directBootAware เป็น true ในไฟล์ Manifest

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

ข้อมูลโค้ดต่อไปนี้เป็นตัวอย่างวิธีลงทะเบียน BroadcastReceiver เป็นแบบรับรู้การเข้ารหัส และเพิ่มตัวกรอง Intent สำหรับ ACTION_LOCKED_BOOT_COMPLETED ในไฟล์ Manifest ของแอป

<receiver
  android:directBootAware="true" >
  ...
  <intent-filter>
    <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
  </intent-filter>
</receiver>

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

เข้าถึงพื้นที่เก็บข้อมูลที่เข้ารหัสของอุปกรณ์

หากต้องการเข้าถึงพื้นที่เก็บข้อมูลที่เข้ารหัสของอุปกรณ์ ให้สร้างอินสแตนซ์ Context รายการที่ 2 โดยเรียกใช้ Context.createDeviceProtectedStorageContext() การเรียก Storage API ทั้งหมดที่ทำโดยใช้บริบทนี้จะเข้าถึงพื้นที่เก็บข้อมูลที่เข้ารหัสของอุปกรณ์ ตัวอย่างต่อไปนี้จะเข้าถึงพื้นที่เก็บข้อมูลที่เข้ารหัสของอุปกรณ์และเปิดไฟล์ข้อมูลแอปที่มีอยู่

Kotlin

val directBootContext: Context = appContext.createDeviceProtectedStorageContext()
// Access appDataFilename that lives in device encrypted storage
val inStream: InputStream = directBootContext.openFileInput(appDataFilename)
// Use inStream to read content...

Java

Context directBootContext = appContext.createDeviceProtectedStorageContext();
// Access appDataFilename that lives in device encrypted storage
FileInputStream inStream = directBootContext.openFileInput(appDataFilename);
// Use inStream to read content...

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

รับการแจ้งเตือนเมื่อผู้ใช้ปลดล็อก

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

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

  • หากแอปมีกระบวนการทำงานอยู่เบื้องหน้าที่ต้องได้รับการแจ้งเตือนทันที ให้ฟังข้อความ ACTION_USER_UNLOCKED
  • หากแอปใช้เฉพาะกระบวนการเบื้องหลังที่สามารถดำเนินการกับการแจ้งเตือนที่ล่าช้าได้ ให้รอรับข้อความ ACTION_BOOT_COMPLETED

หากผู้ใช้ปลดล็อกอุปกรณ์แล้ว คุณจะทราบได้โดยการเรียกใช้ UserManager.isUserUnlocked()

ย้ายข้อมูลที่มีอยู่

หากผู้ใช้อัปเดตอุปกรณ์เพื่อใช้โหมด Direct Boot คุณอาจมีข้อมูลเดิมที่ต้องย้ายไปยังพื้นที่เก็บข้อมูลที่เข้ารหัสของอุปกรณ์ ใช้ Context.moveSharedPreferencesFrom() และ Context.moveDatabaseFrom() โดยมีบริบทปลายทางเป็นผู้เรียกใช้เมธอดและบริบทต้นทางเป็นอาร์กิวเมนต์ เพื่อย้ายข้อมูลค่ากำหนดและฐานข้อมูลระหว่างพื้นที่เก็บข้อมูลที่เข้ารหัสด้วยข้อมูลเข้าสู่ระบบและพื้นที่เก็บข้อมูลที่เข้ารหัสด้วยอุปกรณ์

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

ทดสอบแอปที่รองรับการเข้ารหัส

ทดสอบแอปที่รับรู้การเข้ารหัสโดยเปิดใช้โหมด Direct Boot

อุปกรณ์ส่วนใหญ่ที่ใช้ Android เวอร์ชันล่าสุดจะเปิดใช้โหมด Direct Boot เมื่อใดก็ตามที่มีการตั้งค่าข้อมูลเข้าสู่ระบบหน้าจอล็อก (PIN, รูปแบบ หรือรหัสผ่าน) โดยเฉพาะอย่างยิ่งในอุปกรณ์ทั้งหมดที่ใช้การเข้ารหัสตามไฟล์ หากต้องการตรวจสอบว่าอุปกรณ์ใช้การเข้ารหัสตามไฟล์หรือไม่ ให้เรียกใช้คำสั่ง Shell ต่อไปนี้

adb shell getprop ro.crypto.type

หากเอาต์พุตเป็น file แสดงว่าอุปกรณ์เปิดใช้การเข้ารหัสตามไฟล์อยู่

ในอุปกรณ์ที่ไม่ได้ใช้การเข้ารหัสตามไฟล์โดยค่าเริ่มต้น อาจมีตัวเลือกอื่นๆ สำหรับการทดสอบโหมด Direct Boot ดังนี้

  • อุปกรณ์บางรุ่นที่ใช้การเข้ารหัสดิสก์เต็มรูปแบบ (ro.crypto.type=block) และใช้ Android 7.0 ถึง Android 12 สามารถแปลงเป็นการเข้ารหัสตามไฟล์ได้ ทำได้ 2 วิธีดังนี้

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

    • ในอุปกรณ์ ให้เปิดใช้ตัวเลือกสำหรับนักพัฒนาแอปหากยังไม่ได้ดำเนินการ โดยไปที่การตั้งค่า > เกี่ยวกับโทรศัพท์ แล้วแตะหมายเลขบิลด์ 7 ครั้ง จากนั้นไปที่การตั้งค่า > ตัวเลือกสำหรับนักพัฒนาแอป แล้วเลือกแปลงเป็นการเข้ารหัสไฟล์
    • หรือจะเรียกใช้คำสั่ง Shell ต่อไปนี้ก็ได้
      adb reboot-bootloader
      fastboot --wipe-and-use-fbe
      
  • อุปกรณ์ที่ใช้ Android 13 หรือต่ำกว่ารองรับโหมด Direct Boot "จำลอง" ซึ่งใช้สิทธิ์ในไฟล์เพื่อจำลองผลของการล็อกและปลดล็อกไฟล์ที่เข้ารหัส ใช้โหมดจำลองระหว่างการพัฒนาเท่านั้น เนื่องจากอาจทำให้ข้อมูลสูญหายได้ หากต้องการเปิดใช้โหมด Direct Boot ที่จำลองขึ้น ให้ตั้งค่ารูปแบบการล็อกในอุปกรณ์ เลือก "ไม่เป็นไร" หากระบบแจ้งให้ใช้หน้าจอเริ่มต้นที่ปลอดภัยเมื่อตั้งค่ารูปแบบการล็อก แล้วเรียกใช้คำสั่ง Shell ต่อไปนี้

    adb shell sm set-emulate-fbe true
    

    หากต้องการปิดโหมด Direct Boot ที่จำลองขึ้น ให้เรียกใช้คำสั่ง Shell ต่อไปนี้

    adb shell sm set-emulate-fbe false
    

    การเรียกใช้คำสั่งใดคำสั่งหนึ่งเหล่านี้จะทำให้อุปกรณ์รีบูต

ตรวจสอบสถานะการเข้ารหัสนโยบายด้านอุปกรณ์

แอปการดูแลระบบอุปกรณ์สามารถใช้ DevicePolicyManager.getStorageEncryptionStatus() เพื่อตรวจสอบสถานะการเข้ารหัสปัจจุบันของอุปกรณ์ได้

หากแอปกำหนดเป้าหมายเป็นระดับ API ที่ต่ำกว่า Android 7.0 (API 24) getStorageEncryptionStatus() จะแสดงผลเป็น ENCRYPTION_STATUS_ACTIVE หากอุปกรณ์ใช้การเข้ารหัสดิสก์เต็มรูปแบบหรือการเข้ารหัสตามไฟล์ด้วย Direct Boot ในทั้ง 2 กรณีนี้ ระบบจะจัดเก็บข้อมูลที่เข้ารหัสเมื่อไม่มีการเคลื่อนไหวเสมอ

หากแอปกำหนดเป้าหมายเป็น Android 7.0 (API 24) ขึ้นไป getStorageEncryptionStatus() จะแสดงผลเป็น ENCRYPTION_STATUS_ACTIVE หากอุปกรณ์ใช้การเข้ารหัสดิสก์เต็มรูปแบบ โดยจะแสดงผลเป็น ENCRYPTION_STATUS_ACTIVE_PER_USER หากอุปกรณ์ใช้การเข้ารหัสตามไฟล์ด้วย Direct Boot

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

ตัวอย่างโค้ดเพิ่มเติม

ตัวอย่าง DirectBoot จะสาธิตการใช้ API ที่ครอบคลุมในหน้านี้เพิ่มเติม