اندروید ۷.۰ در حالت بوت مستقیم و امن اجرا میشود، زمانی که دستگاه روشن شده باشد اما کاربر قفل دستگاه را باز نکرده باشد. برای پشتیبانی از این قابلیت، سیستم دو مکان ذخیرهسازی برای دادهها فراهم میکند:
- فضای ذخیرهسازی رمزگذاریشدهی اعتبارنامه ، که محل ذخیرهسازی پیشفرض است و تنها پس از باز کردن قفل دستگاه توسط کاربر در دسترس قرار میگیرد.
- حافظه رمزگذاری شده دستگاه ، که یک مکان ذخیرهسازی است که هم در حالت بوت مستقیم و هم پس از باز کردن قفل دستگاه توسط کاربر در دسترس است.
به طور پیشفرض، برنامهها در حالت بوت مستقیم اجرا نمیشوند. اگر برنامه شما نیاز به انجام کاری در حالت بوت مستقیم دارد، میتوانید اجزای برنامه را برای اجرا در این حالت ثبت کنید. برخی از موارد استفاده رایج برای برنامههایی که نیاز به اجرا در حالت بوت مستقیم دارند عبارتند از:
- برنامههایی که اعلانهای زمانبندیشده دارند، مانند برنامههای ساعت زنگدار.
- برنامههایی که اعلانهای مهم کاربر را ارائه میدهند، مانند برنامههای پیامکی.
- برنامههایی که خدمات دسترسی ارائه میدهند، مانند Talkback.
اگر برنامه شما نیاز دارد که هنگام اجرا در حالت بوت مستقیم به دادهها دسترسی داشته باشد، از فضای ذخیرهسازی رمزگذاریشده دستگاه استفاده کنید. فضای ذخیرهسازی رمزگذاریشده دستگاه شامل دادههایی است که با کلیدی رمزگذاری شدهاند که فقط پس از انجام یک بوت تأییدشده موفق توسط دستگاه در دسترس قرار میگیرد.
برای دادههایی که باید با یک کلید مرتبط با اعتبارنامههای کاربر، مانند پین یا رمز عبور، رمزگذاری شوند، از فضای ذخیرهسازی رمزگذاریشده اعتبارنامه استفاده کنید. فضای ذخیرهسازی رمزگذاریشده اعتبارنامه پس از باز کردن قفل دستگاه توسط کاربر و تا زمانی که دستگاه را مجدداً راهاندازی کند، در دسترس است. اگر کاربر پس از باز کردن قفل دستگاه، صفحه قفل را فعال کند، فضای ذخیرهسازی رمزگذاریشده اعتبارنامه همچنان در دسترس خواهد بود.
درخواست دسترسی برای اجرا در طول بوت مستقیم
برنامهها قبل از اینکه بتوانند در حالت بوت مستقیم اجرا شوند یا به فضای ذخیرهسازی رمزگذاریشده دستگاه دسترسی پیدا کنند، باید اجزای خود را در سیستم ثبت کنند. برنامهها با علامتگذاری اجزا به عنوان آگاه از رمزگذاری ، در سیستم ثبت میشوند. برای علامتگذاری مؤلفه خود به عنوان آگاه از رمزگذاری، ویژگی android:directBootAware در مانیفست خود روی true تنظیم کنید.
اجزای آگاه از رمزگذاری میتوانند برای دریافت پیام پخش ACTION_LOCKED_BOOT_COMPLETED از سیستم هنگام راهاندازی مجدد دستگاه، ثبت نام کنند. در این مرحله، فضای ذخیرهسازی رمزگذاری شده دستگاه در دسترس است و مؤلفه شما میتواند وظایفی را که باید در حالت بوت مستقیم اجرا شوند، مانند راهاندازی یک زنگ زمانبندی شده، اجرا کند.
قطعه کد زیر مثالی از نحوه ثبت یک BroadcastReceiver به عنوان رمزگذاری آگاه و اضافه کردن یک فیلتر intent برای ACTION_LOCKED_BOOT_COMPLETED در مانیفست برنامه است:
<receiver android:directBootAware="true" > ... <intent-filter> <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" /> </intent-filter> </receiver>
پس از اینکه کاربر قفل دستگاه را باز کرد، همه اجزا میتوانند به حافظه رمزگذاری شده دستگاه و همچنین حافظه رمزگذاری شده اطلاعات احراز هویت دسترسی داشته باشند.
دسترسی به فضای ذخیرهسازی رمزگذاریشده دستگاه
برای دسترسی به فضای ذخیرهسازی رمزگذاریشدهی دستگاه، با فراخوانی Context.createDeviceProtectedStorageContext() یک نمونهی دوم Context ایجاد کنید. تمام فراخوانیهای API ذخیرهسازی که با استفاده از این context انجام میشوند، به فضای ذخیرهسازی رمزگذاریشدهی دستگاه دسترسی پیدا میکنند. مثال زیر به فضای ذخیرهسازی رمزگذاریشدهی دستگاه دسترسی پیدا کرده و یک فایل دادهی برنامهی موجود را باز میکند:
کاتلین
val directBootContext: Context = appContext.createDeviceProtectedStorageContext() // Access appDataFilename that lives in device encrypted storage val inStream: InputStream = directBootContext.openFileInput(appDataFilename) // Use inStream to read content...
جاوا
Context directBootContext = appContext.createDeviceProtectedStorageContext(); // Access appDataFilename that lives in device encrypted storage FileInputStream inStream = directBootContext.openFileInput(appDataFilename); // Use inStream to read content...
از فضای ذخیرهسازی رمزگذاریشدهی دستگاه فقط برای اطلاعاتی استفاده کنید که باید در حالت بوت مستقیم قابل دسترسی باشند. از فضای ذخیرهسازی رمزگذاریشدهی دستگاه به عنوان یک فضای ذخیرهسازی رمزگذاریشدهی عمومی استفاده نکنید. برای اطلاعات خصوصی کاربر یا دادههای رمزگذاریشدهای که در حالت بوت مستقیم مورد نیاز نیستند، از فضای ذخیرهسازی رمزگذاریشدهی اعتبارنامهای استفاده کنید.
از باز شدن قفل کاربر مطلع شوید
وقتی کاربر پس از راهاندازی مجدد، قفل دستگاه را باز میکند، برنامه شما میتواند به فضای ذخیرهسازی رمزگذاریشدهی اعتبارنامهها دسترسی پیدا کند و از سرویسهای سیستمی معمولی که به اعتبارنامههای کاربر وابسته هستند، استفاده کند.
برای اینکه وقتی کاربر پس از راهاندازی مجدد دستگاه، قفل آن را باز میکند، مطلع شوید، یک BroadcastReceiver از یک کامپوننت در حال اجرا ثبت کنید تا به پیامهای اعلان باز شدن قفل گوش دهد. وقتی کاربر پس از بوت شدن، دستگاه را باز میکند:
- اگر برنامه شما فرآیندهای پیشزمینهای دارد که نیاز به اعلان فوری دارند، به پیام
ACTION_USER_UNLOCKEDگوش دهید. - اگر برنامه شما فقط از فرآیندهای پسزمینهای استفاده میکند که میتوانند روی یک اعلان تأخیردار عمل کنند، به پیام
ACTION_BOOT_COMPLETEDگوش دهید.
اگر کاربر قفل دستگاه را باز کرده باشد، میتوانید با فراخوانی تابع UserManager.isUserUnlocked() موضوع را متوجه شوید.
انتقال دادههای موجود
اگر کاربری دستگاه خود را برای استفاده از حالت بوت مستقیم بهروزرسانی کند، ممکن است دادههایی از قبل وجود داشته باشد که نیاز به انتقال به فضای ذخیرهسازی رمزگذاریشده دستگاه داشته باشند. از Context.moveSharedPreferencesFrom() و Context.moveDatabaseFrom() استفاده کنید، به طوری که زمینه مقصد به عنوان فراخوانیکننده متد و زمینه منبع به عنوان آرگومان باشد تا تنظیمات و دادههای پایگاه داده بین فضای ذخیرهسازی رمزگذاریشده اعتبارنامه و فضای ذخیرهسازی رمزگذاریشده دستگاه منتقل شوند.
اطلاعات خصوصی کاربر، مانند رمزهای عبور یا توکنهای مجوز، را از حافظه رمزگذاریشده اعتبارنامه به حافظه رمزگذاریشده دستگاه منتقل نکنید. هنگام تصمیمگیری در مورد اینکه چه دادههای دیگری را باید به حافظه رمزگذاریشده دستگاه منتقل کنید، از بهترین قضاوت خود استفاده کنید. در برخی سناریوها، ممکن است لازم باشد مجموعههای جداگانهای از دادهها را در دو حافظه رمزگذاریشده مدیریت کنید.
برنامهی رمزگذاری آگاهانهی خود را آزمایش کنید
برنامهی رمزگذاریشدهی خود را با فعال بودن حالت بوت مستقیم آزمایش کنید.
اکثر دستگاههایی که نسخههای اخیر اندروید را اجرا میکنند، هر زمان که یک اعتبارنامه قفل صفحه (پین، الگو یا رمز عبور) تنظیم شده باشد، حالت بوت مستقیم را فعال میکنند. به طور خاص، این مورد در مورد همه دستگاههایی که از رمزگذاری مبتنی بر فایل استفاده میکنند، صدق میکند. برای بررسی اینکه آیا دستگاهی از رمزگذاری مبتنی بر فایل استفاده میکند، دستور shell زیر را اجرا کنید:
adb shell getprop ro.crypto.type
اگر خروجی file باشد، رمزگذاری مبتنی بر فایل در دستگاه فعال است.
در دستگاههایی که به طور پیشفرض از رمزگذاری مبتنی بر فایل استفاده نمیکنند، ممکن است گزینههای دیگری برای آزمایش حالت بوت مستقیم وجود داشته باشد:
برخی از دستگاههایی که از رمزگذاری کامل دیسک (
ro.crypto.type=block) استفاده میکنند و اندروید ۷.۰ تا اندروید ۱۲ را اجرا میکنند، میتوانند به رمزگذاری مبتنی بر فایل تبدیل شوند. دو روش برای انجام این کار وجود دارد:- در دستگاه، اگر گزینههای توسعهدهندگان را فعال نکردهاید، با رفتن به تنظیمات > درباره تلفن و هفت بار ضربه زدن روی شماره ساخت (Build number) ، این گزینه را فعال کنید. سپس به تنظیمات > گزینههای توسعهدهندگان بروید و تبدیل به رمزگذاری فایل (Convert to file encryption) را انتخاب کنید.
- روش دیگر، اجرای دستورات shell زیر است:
adb reboot-bootloaderfastboot --wipe-and-use-fbe
هشدار: هر دو روش تبدیل به رمزگذاری مبتنی بر فایل، تمام دادههای کاربر روی دستگاه را پاک میکند.
دستگاههایی که اندروید ۱۳ یا پایینتر را اجرا میکنند، از حالت بوت مستقیم «شبیهسازیشده» پشتیبانی میکنند که از مجوزهای فایل برای شبیهسازی اثرات قفل و باز کردن قفل فایلهای رمزگذاریشده استفاده میکند. فقط در حین توسعه از حالت شبیهسازیشده استفاده کنید؛ این کار میتواند باعث از دست رفتن دادهها شود. برای فعال کردن حالت بوت مستقیم شبیهسازیشده، یک الگوی قفل روی دستگاه تنظیم کنید، در صورت درخواست صفحه راهاندازی امن هنگام تنظیم الگوی قفل، «نه ممنون» را انتخاب کنید و سپس دستور shell زیر را اجرا کنید:
adb shell sm set-emulate-fbe true
برای خاموش کردن حالت بوت مستقیم شبیهسازی شده، دستور shell زیر را اجرا کنید:
adb shell sm set-emulate-fbe false
اجرای هر یک از این دستورات باعث ریبوت شدن دستگاه میشود.
بررسی وضعیت رمزگذاری خطمشی دستگاه
برنامههای مدیریت دستگاه میتوانند از DevicePolicyManager.getStorageEncryptionStatus() برای بررسی وضعیت رمزگذاری فعلی دستگاه استفاده کنند.
اگر برنامه شما سطح API پایینتر از اندروید ۷.۰ (API 24) را هدف قرار دهد، getStorageEncryptionStatus() در صورتی که دستگاه از رمزگذاری کامل دیسک یا رمزگذاری مبتنی بر فایل با بوت مستقیم استفاده کند، ENCRYPTION_STATUS_ACTIVE را برمیگرداند. در هر دو مورد، دادهها همیشه در حالت استراحت رمزگذاری شده ذخیره میشوند.
اگر برنامه شما برای اندروید ۷.۰ (API 24) یا بالاتر طراحی شده باشد، تابع getStorageEncryptionStatus() در صورتی که دستگاه از رمزگذاری کامل دیسک استفاده کند، مقدار ENCRYPTION_STATUS_ACTIVE را برمیگرداند. اگر دستگاه از رمزگذاری مبتنی بر فایل با بوت مستقیم استفاده کند، ENCRYPTION_STATUS_ACTIVE_PER_USER برمیگرداند.
اگر یک برنامه مدیریت دستگاه میسازید که اندروید ۷.۰ را هدف قرار میدهد، حتماً ENCRYPTION_STATUS_ACTIVE و ENCRYPTION_STATUS_ACTIVE_PER_USER را بررسی کنید تا مشخص شود که آیا دستگاه رمزگذاری شده است یا خیر.
نمونههای کد اضافی
نمونه DirectBoot ، کاربرد APIهای مطرحشده در این صفحه را بیشتر نشان میدهد.