-
Notifications
You must be signed in to change notification settings - Fork 642
Use Device Encrypted storage context for locked state #7477
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Use Device Encrypted storage context for locked state #7477
Conversation
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. |
@mrober could you PTAL? |
appContext | ||
} | ||
return deContext.dataStoreFile(fileName).also { | ||
prepDataStoreFile(it) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The prepDataStoreFile thing didn't work, we can just remove this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to keep it, since it contains validations to check if the parent path is a directory or not and also delete it if it is not a directory
|
||
private fun produceFile(appContext: Context, fileName: String): File { | ||
val deContext = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { | ||
appContext.createDeviceProtectedStorageContext() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any consequences to using the DE storage permanently? After the device is unlocked, should there be some flow to move to CE storage?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any consequences to using the DE storage permanently?
Some research:
Reduced Security | This is the most critical consequence. Data in DE storage is encrypted, but the key is tied to the device hardware, not the user's PIN, password, or pattern. If a malicious actor gains physical access to the device and can bypass the lock screen through a software vulnerability (or has advanced forensic tools), they may be able to extract the contents of DE storage. In contrast, Credential Encrypted (CE) storage would remain safely encrypted.
No Real Performance Benefit | After the device is unlocked, there is no performance advantage to using DE storage over CE storage. Both are simply mounted file systems. The only benefit of DE storage is its availability before the first unlock.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After the device is unlocked, should there be some flow to move to CE storage?
We can use a "data handoff" strategy:
-
On Boot (Before Unlock): Use createDeviceProtectedStorageContext() to write essential, non-sensitive data required for immediate operation.
-
After User Unlocks: The Android system sends a broadcast action,
ACTION_USER_UNLOCKED
. -
Once the SDK receives the ACTION_USER_UNLOCKED broadcast
• Read the temporary data from DE storage.
• Migrate or merge this data into your main data store located in the now-accessible CE storage.
• FIND A WAY TO NOTIFY DATASTORE TO USE THE NEW LOCATION
• Delete the temporary data from DE storage to ensure it's not left behind.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Research update:
A DataStore instance is fundamentally tied to the file it was created with. The file path is provided once during initialization (via the produceFile lambda in your code) and is considered immutable for the lifetime of that singleton DataStore object.
The "correct approach" might be to use 2 instances of DataStores, one for DE and other for CE, after receiving the ACTION_USER_UNLOCKED
broadcast
The app is attempting to create the
firebaseSessions
directory inside the app's private files directory, and the operating system is denying this request.Android has security measures to protect app data when the device is locked. If the device has just been rebooted and the user has not unlocked it for the first time, the app's private storage is encrypted and completely inaccessible. This is known as
Credential Encrypted (CE) storage
.The Problem: The code is likely running before the user has unlocked their device. This can happen if a background job, a broadcast receiver, or a foreground service starts immediately on boot. When
FirebaseSessionsComponent
is initialized under these conditions, it tries to create theDataStore
file in an encrypted, inaccessible location. The file system denies the request, resulting inAccessDeniedException
.The Solution: Use Device Encrypted (DE) storage for data that must be accessed before the first user unlock. The
androidx.datastore
library has direct support for this. Instead of appContext.dataStoreFile(...), We need to use a context that is aware ofDevice Encrypted
storage.By using
createDeviceProtectedStorageContext()
, I am explicitly telling the system to place this file in a location that is available even when the device is locked. This is the standard and recommended way to handle file access required before the user unlocks their phone.