Hỗ trợ chế độ Khởi động trực tiếp

Android 7.0 chạy ở chế độ Khởi động trực tiếp (Direct Boot), an toàn khi thiết bị đã bật nguồn nhưng người dùng chưa mở khoá thiết bị. Để hỗ trợ chế độ khởi động này, hệ thống cung cấp 2 vị trí lưu trữ cho dữ liệu, đó là:

  • Bộ nhớ được mã hoá dành cho thông tin đăng nhập, đây là vị trí lưu trữ mặc định và chỉ có sẵn sau khi người dùng mở khoá thiết bị.
  • Bộ nhớ được mã hoá của thiết bị, đây là vị trí lưu trữ có sẵn cả trong chế độ Khởi động trực tiếp và sau khi người dùng mở khoá thiết bị.

Theo mặc định, các ứng dụng không chạy trong chế độ Khởi động trực tiếp. Nếu ứng dụng của bạn cần thực hiện hành động trong chế độ Khởi động trực tiếp, thì bạn có thể đăng ký các thành phần ứng dụng để chạy trong chế độ này. Dưới đây là một số trường hợp sử dụng phổ biến cho các ứng dụng cần chạy trong chế độ Khởi động trực tiếp:

  • Các ứng dụng có thông báo theo lịch, chẳng hạn như ứng dụng đồng hồ báo thức.
  • Các ứng dụng cung cấp thông báo quan trọng cho người dùng, chẳng hạn như ứng dụng SMS.
  • Các ứng dụng cung cấp dịch vụ hỗ trợ tiếp cận, chẳng hạn như TalkBack.

Nếu ứng dụng của bạn cần truy cập vào dữ liệu trong khi chạy ở chế độ Khởi động trực tiếp, hãy sử dụng bộ nhớ được mã hoá của thiết bị. Bộ nhớ được mã hoá của thiết bị chứa dữ liệu được mã hoá bằng một khoá chỉ có sẵn sau khi thiết bị xác minh quy trình khởi động thành công.

Đối với dữ liệu phải được mã hoá bằng một khoá liên kết với thông tin đăng nhập người dùng, chẳng hạn như mã PIN hoặc mật khẩu, hãy sử dụng bộ nhớ được mã hoá dành cho thông tin đăng nhập. Bộ nhớ được mã hoá dành cho thông tin đăng nhập sẽ có sẵn sau khi người dùng mở khoá thiết bị thành công và cho đến khi người dùng khởi động lại thiết bị. Nếu người dùng bật màn hình khoá sau khi mở khoá thiết bị, thì bộ nhớ được mã hoá dành cho thông tin đăng nhập sẽ vẫn có sẵn.

Yêu cầu quyền truy cập để chạy trong quá trình Khởi động trực tiếp

Ứng dụng phải đăng ký các thành phần với hệ thống thì mới có thể chạy trong chế độ Khởi động trực tiếp hoặc truy cập vào bộ nhớ được mã hoá của thiết bị. Ứng dụng đăng ký với hệ thống bằng cách đánh dấu các thành phần là có khả năng nhận biết quá trình mã hoá. Để đánh dấu thành phần là có khả năng nhận biết quá trình mã hoá, hãy đặt thuộc tính android:directBootAware thành true trong tệp kê khai.

Các thành phần có khả năng nhận biết quá trình mã hoá có thể đăng ký nhận thông báo phát đi ACTION_LOCKED_BOOT_COMPLETED từ hệ thống khi thiết bị được khởi động lại. Tại thời điểm này, bộ nhớ được mã hoá của thiết bị vẫn có sẵn và thành phần của bạn có thể thực thi các tác vụ cần chạy trong chế độ Khởi động trực tiếp, chẳng hạn như kích hoạt chuông báo đã lên lịch.

Đoạn mã sau đây là ví dụ minh hoạ cho cách đăng ký một BroadcastReceiver là có khả năng nhận biết quá trình mã hoá và thêm một bộ lọc ý định cho ACTION_LOCKED_BOOT_COMPLETED trong tệp kê khai ứng dụng:

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

Sau khi người dùng mở khoá thiết bị, tất cả các thành phần đều có thể truy cập vào cả bộ nhớ được mã hoá của thiết bị lẫn bộ nhớ được mã hoá dành cho thông tin đăng nhập.

Truy cập vào bộ nhớ được mã hoá của thiết bị

Để truy cập vào bộ nhớ được mã hoá của thiết bị, hãy tạo một thực thể Context thứ hai bằng cách gọi Context.createDeviceProtectedStorageContext(). Tất cả các lệnh gọi API bộ nhớ được thực hiện thông qua ngữ cảnh này đều truy cập được vào bộ nhớ được mã hoá của thiết bị. Ví dụ sau đây truy cập vào bộ nhớ được mã hoá của thiết bị và mở một tệp dữ liệu ứng dụng hiện có:

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...

Chỉ sử dụng bộ nhớ được mã hoá của thiết bị cho những thông tin phải truy cập được trong chế độ Khởi động trực tiếp. Không sử dụng bộ nhớ được mã hoá của thiết bị làm bộ nhớ được mã hoá đa năng. Đối với thông tin riêng tư của người dùng hoặc các dữ liệu đã mã hoá không cần đến trong chế độ Khởi động trực tiếp, hãy sử dụng bộ nhớ được mã hoá dành cho thông tin đăng nhập.

Nhận thông báo về việc mở khoá của người dùng

Khi người dùng mở khoá thiết bị sau khi khởi động lại, ứng dụng của bạn có thể chuyển sang truy cập vào bộ nhớ được mã hoá dành cho thông tin đăng nhập và sử dụng các dịch vụ hệ thống thông thường phụ thuộc vào thông tin đăng nhập của người dùng.

Để nhận thông báo khi người dùng mở khoá thiết bị sau khi khởi động lại, hãy đăng ký BroadcastReceiver từ một thành phần đang chạy để theo dõi các nội dung thông báo mở khoá. Khi người dùng mở khoá thiết bị sau khi khởi động:

  • Nếu ứng dụng của bạn có các quy trình trên nền trước cần thông báo ngay, hãy theo dõi thông báo ACTION_USER_UNLOCKED.
  • Nếu ứng dụng của bạn chỉ dùng các tiến trình nền có khả năng hoạt động dựa trên một thông báo bị trễ, hãy theo dõi thông báo ACTION_BOOT_COMPLETED.

Nếu người dùng đã mở khoá thiết bị, thì bạn có thể biết được điều này bằng cách gọi UserManager.isUserUnlocked().

Di chuyển dữ liệu hiện có

Nếu một người dùng cập nhật thiết bị để sử dụng chế độ Khởi động trực tiếp, thì có thể bạn có dữ liệu hiện có cần được di chuyển sang bộ nhớ được mã hoá của thiết bị. Sử dụng Context.moveSharedPreferencesFrom()Context.moveDatabaseFrom(), với ngữ cảnh đích làm lệnh gọi phương thức và ngữ cảnh nguồn làm đối số, để di chuyển dữ liệu trong cơ sở dữ liệu và lựa chọn ưu tiên qua lại giữa bộ nhớ được mã hoá dành cho thông tin đăng nhập và bộ nhớ được mã hoá của thiết bị.

Không di chuyển thông tin riêng tư của người dùng, chẳng hạn như mật khẩu hoặc mã thông báo uỷ quyền, từ bộ nhớ được mã hoá dành cho thông tin đăng nhập sang bộ nhớ được mã hoá của thiết bị. Hãy suy xét thật kỹ lưỡng khi quyết định những dữ liệu nào khác sẽ cần di chuyển sang bộ nhớ được mã hoá của thiết bị. Trong một số trường hợp, bạn có thể cần quản lý các tập dữ liệu riêng biệt trong 2 bộ nhớ được mã hoá này.

Kiểm thử ứng dụng có khả năng nhận biết quá trình mã hoá

Hãy kiểm thử ứng dụng có khả năng nhận biết quá trình mã hoá của bạn khi chế độ Khởi động trực tiếp được bật.

Hầu hết thiết bị chạy các phiên bản Android mới đây đều bật chế độ Khởi động trực tiếp bất cứ khi nào thông tin đăng nhập màn hình khoá (mã PIN, hình mở khoá hoặc mật khẩu) được đặt. Cụ thể, trường hợp này áp dụng trên mọi thiết bị sử dụng phương thức mã hoá dựa trên tệp. Để kiểm tra xem một thiết bị có dùng phương thức mã hoá dựa trên tệp hay không, hãy chạy lệnh shell sau đây:

adb shell getprop ro.crypto.type

Nếu dữ liệu đầu ra là file, tức là thiết bị đã bật phương thức mã hoá dựa trên tệp.

Trên các thiết bị theo mặc định không sử dụng phương thức mã hoá dựa trên tệp, có thể có các lựa chọn khác để kiểm thử chế độ Khởi động trực tiếp:

  • Một số thiết bị sử dụng phương thức mã hoá toàn bộ đĩa (ro.crypto.type=block) và đang chạy phiên bản Android từ Android 7.0 cho đến Android 12 có thể được chuyển đổi sang phương thức mã hoá dựa trên tệp. Có 2 cách để thực hiện việc này:

      Cảnh báo: Cả hai cách chuyển đổi sang phương thức mã hoá dựa trên tệp đều sẽ xoá sạch mọi dữ liệu người dùng trên thiết bị.

    • Trên thiết bị, hãy bật Tuỳ chọn cho nhà phát triển nếu bạn chưa làm vậy bằng cách chuyển đến phần Cài đặt > Giới thiệu về điện thoại rồi nhấn vào Số bản dựng 7 lần. Sau đó, hãy chuyển đến phần Cài đặt > Tuỳ chọn cho nhà phát triển rồi chọn Chuyển đổi sang mã hoá tệp.
    • Hoặc, chạy các lệnh shell sau đây:
      adb reboot-bootloader
      fastboot --wipe-and-use-fbe
      
  • Các thiết bị chạy Android 13 trở xuống hỗ trợ chế độ Khởi động trực tiếp "được mô phỏng". Chế độ này sử dụng các quyền truy cập tệp để mô phỏng tác động của việc khoá và mở khoá tệp đã mã hoá. Chỉ sử dụng chế độ được mô phỏng trong quá trình phát triển; chế độ này có thể gây mất dữ liệu. Để bật chế độ Khởi động trực tiếp được mô phỏng, hãy đặt một hình mở khoá trên thiết bị, chọn "Không, cảm ơn" nếu được nhắc hiển thị một màn hình khởi động an toàn khi thiết lập hình mở khoá, sau đó chạy lệnh shell sau đây:

    adb shell sm set-emulate-fbe true
    

    Để tắt chế độ Khởi động trực tiếp được mô phỏng, hãy chạy lệnh shell sau đây:

    adb shell sm set-emulate-fbe false
    

    Việc chạy một trong các lệnh này sẽ khiến thiết bị khởi động lại.

Kiểm tra trạng thái mã hoá của chính sách thiết bị

Các ứng dụng quản trị thiết bị có thể dùng DevicePolicyManager.getStorageEncryptionStatus() để kiểm tra trạng thái mã hoá hiện tại của thiết bị.

Nếu ứng dụng của bạn nhắm đến một cấp độ API thấp hơn Android 7.0 (API 24), thì getStorageEncryptionStatus() sẽ trả về ENCRYPTION_STATUS_ACTIVE nếu thiết bị đang sử dụng phương thức mã hoá toàn bộ đĩa hoặc phương thức mã hoá dựa trên tệp với chế độ Khởi động trực tiếp. Trong cả hai trường hợp này, dữ liệu luôn được lưu trữ và được mã hoá khi lưu trữ.

Nếu ứng dụng của bạn nhắm đến Android 7.0 (API 24) trở lên, thì getStorageEncryptionStatus() sẽ trả về ENCRYPTION_STATUS_ACTIVE nếu thiết bị đang sử dụng phương thức mã hoá toàn bộ đĩa. ENCRYPTION_STATUS_ACTIVE_PER_USER sẽ được trả về nếu thiết bị đang sử dụng phương thức mã hoá dựa trên tệp với chế độ Khởi động trực tiếp.

Nếu bạn tạo một ứng dụng quản trị thiết bị nhắm đến Android 7.0, hãy nhớ kiểm tra cả ENCRYPTION_STATUS_ACTIVEENCRYPTION_STATUS_ACTIVE_PER_USER để xác định xem thiết bị có được mã hoá hay không.

Mã mẫu khác

Mẫu DirectBoot minh hoạ thêm về cách sử dụng các API được trình bày trên trang này.