Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2c1ba9a9 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Make BackupManager encryption aware.

Backup requires both CE and DE storage to be available, so delay
spinning up the backup system until the user is unlocked, since
that's when CE storage becomes available.  Note that devices without
FBE immediately transition USER_SYSTEM into the unlocked state,
since their CE is always available.

Offer to backup and restore files under both CE and DE.  Since DE
is effectively the same as CE, most logic is simply duplicated for
now, but it could be simplified in the future.  Since system apps
can force their default storage location to DE, we always build
explicit CE and DE paths.

Add getDataDir() to give clean access to the top-level private data
directory, but disclaim that apps shouldn't create files there.

Bug: 26279618
Change-Id: Ic34a4b330223725db93b1d0f5c9dffc88002c61f
parent 18026642
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -8006,6 +8006,7 @@ package android.content {
    method public final int getColor(int);
    method public final android.content.res.ColorStateList getColorStateList(int);
    method public abstract android.content.ContentResolver getContentResolver();
    method public abstract java.io.File getDataDir();
    method public abstract java.io.File getDatabasePath(java.lang.String);
    method public abstract java.io.File getDir(java.lang.String, int);
    method public final android.graphics.drawable.Drawable getDrawable(int);
@@ -8198,6 +8199,7 @@ package android.content {
    method public java.lang.ClassLoader getClassLoader();
    method public java.io.File getCodeCacheDir();
    method public android.content.ContentResolver getContentResolver();
    method public java.io.File getDataDir();
    method public java.io.File getDatabasePath(java.lang.String);
    method public java.io.File getDir(java.lang.String, int);
    method public java.io.File getExternalCacheDir();
@@ -37632,6 +37634,7 @@ package android.test.mock {
    method public java.lang.ClassLoader getClassLoader();
    method public java.io.File getCodeCacheDir();
    method public android.content.ContentResolver getContentResolver();
    method public java.io.File getDataDir();
    method public java.io.File getDatabasePath(java.lang.String);
    method public java.io.File getDir(java.lang.String, int);
    method public java.io.File getExternalCacheDir();
+3 −0
Original line number Diff line number Diff line
@@ -8297,6 +8297,7 @@ package android.content {
    method public final int getColor(int);
    method public final android.content.res.ColorStateList getColorStateList(int);
    method public abstract android.content.ContentResolver getContentResolver();
    method public abstract java.io.File getDataDir();
    method public abstract java.io.File getDatabasePath(java.lang.String);
    method public abstract java.io.File getDir(java.lang.String, int);
    method public final android.graphics.drawable.Drawable getDrawable(int);
@@ -8499,6 +8500,7 @@ package android.content {
    method public java.lang.ClassLoader getClassLoader();
    method public java.io.File getCodeCacheDir();
    method public android.content.ContentResolver getContentResolver();
    method public java.io.File getDataDir();
    method public java.io.File getDatabasePath(java.lang.String);
    method public java.io.File getDir(java.lang.String, int);
    method public java.io.File getExternalCacheDir();
@@ -40380,6 +40382,7 @@ package android.test.mock {
    method public java.lang.ClassLoader getClassLoader();
    method public java.io.File getCodeCacheDir();
    method public android.content.ContentResolver getContentResolver();
    method public java.io.File getDataDir();
    method public java.io.File getDatabasePath(java.lang.String);
    method public java.io.File getDir(java.lang.String, int);
    method public java.io.File getExternalCacheDir();
+3 −0
Original line number Diff line number Diff line
@@ -8009,6 +8009,7 @@ package android.content {
    method public final int getColor(int);
    method public final android.content.res.ColorStateList getColorStateList(int);
    method public abstract android.content.ContentResolver getContentResolver();
    method public abstract java.io.File getDataDir();
    method public abstract java.io.File getDatabasePath(java.lang.String);
    method public abstract java.io.File getDir(java.lang.String, int);
    method public final android.graphics.drawable.Drawable getDrawable(int);
@@ -8202,6 +8203,7 @@ package android.content {
    method public java.lang.ClassLoader getClassLoader();
    method public java.io.File getCodeCacheDir();
    method public android.content.ContentResolver getContentResolver();
    method public java.io.File getDataDir();
    method public java.io.File getDatabasePath(java.lang.String);
    method public java.io.File getDir(java.lang.String, int);
    method public java.io.File getExternalCacheDir();
@@ -37647,6 +37649,7 @@ package android.test.mock {
    method public java.lang.ClassLoader getClassLoader();
    method public java.io.File getCodeCacheDir();
    method public android.content.ContentResolver getContentResolver();
    method public java.io.File getDataDir();
    method public java.io.File getDatabasePath(java.lang.String);
    method public java.io.File getDir(java.lang.String, int);
    method public java.io.File getExternalCacheDir();
+9 −8
Original line number Diff line number Diff line
@@ -460,7 +460,7 @@ class ContextImpl extends Context {
    private File getPreferencesDir() {
        synchronized (mSync) {
            if (mPreferencesDir == null) {
                mPreferencesDir = new File(getDataDirFile(), "shared_prefs");
                mPreferencesDir = new File(getDataDir(), "shared_prefs");
            }
            return ensurePrivateDirExists(mPreferencesDir);
        }
@@ -525,7 +525,7 @@ class ContextImpl extends Context {
    public File getFilesDir() {
        synchronized (mSync) {
            if (mFilesDir == null) {
                mFilesDir = new File(getDataDirFile(), "files");
                mFilesDir = new File(getDataDir(), "files");
            }
            return ensurePrivateDirExists(mFilesDir);
        }
@@ -535,7 +535,7 @@ class ContextImpl extends Context {
    public File getNoBackupFilesDir() {
        synchronized (mSync) {
            if (mNoBackupFilesDir == null) {
                mNoBackupFilesDir = new File(getDataDirFile(), "no_backup");
                mNoBackupFilesDir = new File(getDataDir(), "no_backup");
            }
            return ensurePrivateDirExists(mNoBackupFilesDir);
        }
@@ -587,7 +587,7 @@ class ContextImpl extends Context {
    public File getCacheDir() {
        synchronized (mSync) {
            if (mCacheDir == null) {
                mCacheDir = new File(getDataDirFile(), "cache");
                mCacheDir = new File(getDataDir(), "cache");
            }
            return ensurePrivateDirExists(mCacheDir);
        }
@@ -597,7 +597,7 @@ class ContextImpl extends Context {
    public File getCodeCacheDir() {
        synchronized (mSync) {
            if (mCodeCacheDir == null) {
                mCodeCacheDir = new File(getDataDirFile(), "code_cache");
                mCodeCacheDir = new File(getDataDir(), "code_cache");
            }
            return ensurePrivateDirExists(mCodeCacheDir);
        }
@@ -724,7 +724,7 @@ class ContextImpl extends Context {
                if ("android".equals(getPackageName())) {
                    mDatabasesDir = new File("/data/system");
                } else {
                    mDatabasesDir = new File(getDataDirFile(), "databases");
                    mDatabasesDir = new File(getDataDir(), "databases");
                }
            }
            return ensurePrivateDirExists(mDatabasesDir);
@@ -1920,7 +1920,8 @@ class ContextImpl extends Context {
        return mDisplayAdjustments;
    }

    private File getDataDirFile() {
    @Override
    public File getDataDir() {
        if (mPackageInfo != null) {
            File res = null;
            if (isCredentialEncryptedStorage()) {
@@ -1947,7 +1948,7 @@ class ContextImpl extends Context {
    public File getDir(String name, int mode) {
        checkMode(mode);
        name = "app_" + name;
        File file = makeFilename(getDataDirFile(), name);
        File file = makeFilename(getDataDir(), name);
        if (!file.exists()) {
            file.mkdir();
            setFilePermissionsFromMode(file.getPath(), mode,
+118 −34
Original line number Diff line number Diff line
@@ -308,14 +308,31 @@ public abstract class BackupAgent extends ContextWrapper {
        final String packageName = getPackageName();
        final ApplicationInfo appInfo = getApplicationInfo();

        String rootDir = new File(appInfo.dataDir).getCanonicalPath();
        String filesDir = getFilesDir().getCanonicalPath();
        String nobackupDir = getNoBackupFilesDir().getCanonicalPath();
        String databaseDir = getDatabasePath("foo").getParentFile().getCanonicalPath();
        String sharedPrefsDir = getSharedPrefsFile("foo").getParentFile().getCanonicalPath();
        String cacheDir = getCacheDir().getCanonicalPath();
        String codeCacheDir = getCodeCacheDir().getCanonicalPath();
        String libDir = (appInfo.nativeLibraryDir != null)
        // System apps have control over where their default storage context
        // is pointed, so we're always explicit when building paths.
        final Context ceContext = createCredentialEncryptedStorageContext();
        final String rootDir = ceContext.getDataDir().getCanonicalPath();
        final String filesDir = ceContext.getFilesDir().getCanonicalPath();
        final String noBackupDir = ceContext.getNoBackupFilesDir().getCanonicalPath();
        final String databaseDir = ceContext.getDatabasePath("foo").getParentFile()
                .getCanonicalPath();
        final String sharedPrefsDir = ceContext.getSharedPreferencesPath("foo").getParentFile()
                .getCanonicalPath();
        final String cacheDir = ceContext.getCacheDir().getCanonicalPath();
        final String codeCacheDir = ceContext.getCodeCacheDir().getCanonicalPath();

        final Context deContext = createDeviceEncryptedStorageContext();
        final String deviceRootDir = deContext.getDataDir().getCanonicalPath();
        final String deviceFilesDir = deContext.getFilesDir().getCanonicalPath();
        final String deviceNoBackupDir = deContext.getNoBackupFilesDir().getCanonicalPath();
        final String deviceDatabaseDir = deContext.getDatabasePath("foo").getParentFile()
                .getCanonicalPath();
        final String deviceSharedPrefsDir = deContext.getSharedPreferencesPath("foo")
                .getParentFile().getCanonicalPath();
        final String deviceCacheDir = deContext.getCacheDir().getCanonicalPath();
        final String deviceCodeCacheDir = deContext.getCodeCacheDir().getCanonicalPath();

        final String libDir = (appInfo.nativeLibraryDir != null)
                ? new File(appInfo.nativeLibraryDir).getCanonicalPath()
                : null;

@@ -325,30 +342,48 @@ public abstract class BackupAgent extends ContextWrapper {
        final ArraySet<String> traversalExcludeSet = new ArraySet<String>();

        // Add the directories we always exclude.
        traversalExcludeSet.add(filesDir);
        traversalExcludeSet.add(noBackupDir);
        traversalExcludeSet.add(databaseDir);
        traversalExcludeSet.add(sharedPrefsDir);
        traversalExcludeSet.add(cacheDir);
        traversalExcludeSet.add(codeCacheDir);
        traversalExcludeSet.add(nobackupDir);

        traversalExcludeSet.add(deviceFilesDir);
        traversalExcludeSet.add(deviceNoBackupDir);
        traversalExcludeSet.add(deviceDatabaseDir);
        traversalExcludeSet.add(deviceSharedPrefsDir);
        traversalExcludeSet.add(deviceCacheDir);
        traversalExcludeSet.add(deviceCodeCacheDir);

        if (libDir != null) {
            traversalExcludeSet.add(libDir);
        }

        traversalExcludeSet.add(databaseDir);
        traversalExcludeSet.add(sharedPrefsDir);
        traversalExcludeSet.add(filesDir);

        // Root dir first.
        applyXmlFiltersAndDoFullBackupForDomain(
                packageName, FullBackup.ROOT_TREE_TOKEN, manifestIncludeMap,
                manifestExcludeSet, traversalExcludeSet, data);
        traversalExcludeSet.add(rootDir);

        applyXmlFiltersAndDoFullBackupForDomain(
                packageName, FullBackup.DEVICE_ROOT_TREE_TOKEN, manifestIncludeMap,
                manifestExcludeSet, traversalExcludeSet, data);
        traversalExcludeSet.add(deviceRootDir);

        // Data dir next.
        traversalExcludeSet.remove(filesDir);
        applyXmlFiltersAndDoFullBackupForDomain(
                packageName, FullBackup.DATA_TREE_TOKEN, manifestIncludeMap,
                packageName, FullBackup.FILES_TREE_TOKEN, manifestIncludeMap,
                manifestExcludeSet, traversalExcludeSet, data);
        traversalExcludeSet.add(filesDir);

        traversalExcludeSet.remove(deviceFilesDir);
        applyXmlFiltersAndDoFullBackupForDomain(
                packageName, FullBackup.DEVICE_FILES_TREE_TOKEN, manifestIncludeMap,
                manifestExcludeSet, traversalExcludeSet, data);
        traversalExcludeSet.add(deviceFilesDir);

        // Database directory.
        traversalExcludeSet.remove(databaseDir);
        applyXmlFiltersAndDoFullBackupForDomain(
@@ -356,6 +391,12 @@ public abstract class BackupAgent extends ContextWrapper {
                manifestExcludeSet, traversalExcludeSet, data);
        traversalExcludeSet.add(databaseDir);

        traversalExcludeSet.remove(deviceDatabaseDir);
        applyXmlFiltersAndDoFullBackupForDomain(
                packageName, FullBackup.DEVICE_DATABASE_TREE_TOKEN, manifestIncludeMap,
                manifestExcludeSet, traversalExcludeSet, data);
        traversalExcludeSet.add(deviceDatabaseDir);

        // SharedPrefs.
        traversalExcludeSet.remove(sharedPrefsDir);
        applyXmlFiltersAndDoFullBackupForDomain(
@@ -363,6 +404,12 @@ public abstract class BackupAgent extends ContextWrapper {
                manifestExcludeSet, traversalExcludeSet, data);
        traversalExcludeSet.add(sharedPrefsDir);

        traversalExcludeSet.remove(deviceSharedPrefsDir);
        applyXmlFiltersAndDoFullBackupForDomain(
                packageName, FullBackup.DEVICE_SHAREDPREFS_TREE_TOKEN, manifestIncludeMap,
                manifestExcludeSet, traversalExcludeSet, data);
        traversalExcludeSet.add(deviceSharedPrefsDir);

        // getExternalFilesDir() location associated with this app.  Technically there should
        // not be any files here if the app does not properly have permission to access
        // external storage, but edge cases happen. fullBackupFileTree() catches
@@ -445,27 +492,49 @@ public abstract class BackupAgent extends ContextWrapper {
     */
    public final void fullBackupFile(File file, FullBackupDataOutput output) {
        // Look up where all of our various well-defined dir trees live on this device
        String mainDir;
        String filesDir;
        String nbFilesDir;
        String dbDir;
        String spDir;
        String cacheDir;
        String codeCacheDir;
        String libDir;
        final String rootDir;
        final String filesDir;
        final String nbFilesDir;
        final String dbDir;
        final String spDir;
        final String cacheDir;
        final String codeCacheDir;
        final String deviceRootDir;
        final String deviceFilesDir;
        final String deviceNbFilesDir;
        final String deviceDbDir;
        final String deviceSpDir;
        final String deviceCacheDir;
        final String deviceCodeCacheDir;
        final String libDir;

        String efDir = null;
        String filePath;

        ApplicationInfo appInfo = getApplicationInfo();

        try {
            mainDir = new File(appInfo.dataDir).getCanonicalPath();
            filesDir = getFilesDir().getCanonicalPath();
            nbFilesDir = getNoBackupFilesDir().getCanonicalPath();
            dbDir = getDatabasePath("foo").getParentFile().getCanonicalPath();
            spDir = getSharedPrefsFile("foo").getParentFile().getCanonicalPath();
            cacheDir = getCacheDir().getCanonicalPath();
            codeCacheDir = getCodeCacheDir().getCanonicalPath();
            // System apps have control over where their default storage context
            // is pointed, so we're always explicit when building paths.
            final Context ceContext = createCredentialEncryptedStorageContext();
            rootDir = ceContext.getDataDir().getCanonicalPath();
            filesDir = ceContext.getFilesDir().getCanonicalPath();
            nbFilesDir = ceContext.getNoBackupFilesDir().getCanonicalPath();
            dbDir = ceContext.getDatabasePath("foo").getParentFile().getCanonicalPath();
            spDir = ceContext.getSharedPreferencesPath("foo").getParentFile().getCanonicalPath();
            cacheDir = ceContext.getCacheDir().getCanonicalPath();
            codeCacheDir = ceContext.getCodeCacheDir().getCanonicalPath();

            final Context deContext = createDeviceEncryptedStorageContext();
            deviceRootDir = deContext.getDataDir().getCanonicalPath();
            deviceFilesDir = deContext.getFilesDir().getCanonicalPath();
            deviceNbFilesDir = deContext.getNoBackupFilesDir().getCanonicalPath();
            deviceDbDir = deContext.getDatabasePath("foo").getParentFile().getCanonicalPath();
            deviceSpDir = deContext.getSharedPreferencesPath("foo").getParentFile()
                    .getCanonicalPath();
            deviceCacheDir = deContext.getCacheDir().getCanonicalPath();
            deviceCodeCacheDir = deContext.getCodeCacheDir().getCanonicalPath();

            libDir = (appInfo.nativeLibraryDir == null)
                    ? null
                    : new File(appInfo.nativeLibraryDir).getCanonicalPath();
@@ -489,8 +558,11 @@ public abstract class BackupAgent extends ContextWrapper {

        if (filePath.startsWith(cacheDir)
                || filePath.startsWith(codeCacheDir)
                || filePath.startsWith(libDir)
                || filePath.startsWith(nbFilesDir)) {
                || filePath.startsWith(nbFilesDir)
                || filePath.startsWith(deviceCacheDir)
                || filePath.startsWith(deviceCodeCacheDir)
                || filePath.startsWith(deviceNbFilesDir)
                || filePath.startsWith(libDir)) {
            Log.w(TAG, "lib, cache, code_cache, and no_backup files are not backed up");
            return;
        }
@@ -504,11 +576,23 @@ public abstract class BackupAgent extends ContextWrapper {
            domain = FullBackup.SHAREDPREFS_TREE_TOKEN;
            rootpath = spDir;
        } else if (filePath.startsWith(filesDir)) {
            domain = FullBackup.DATA_TREE_TOKEN;
            domain = FullBackup.FILES_TREE_TOKEN;
            rootpath = filesDir;
        } else if (filePath.startsWith(mainDir)) {
        } else if (filePath.startsWith(rootDir)) {
            domain = FullBackup.ROOT_TREE_TOKEN;
            rootpath = mainDir;
            rootpath = rootDir;
        } else if (filePath.startsWith(deviceDbDir)) {
            domain = FullBackup.DEVICE_DATABASE_TREE_TOKEN;
            rootpath = deviceDbDir;
        } else if (filePath.startsWith(deviceSpDir)) {
            domain = FullBackup.DEVICE_SHAREDPREFS_TREE_TOKEN;
            rootpath = deviceSpDir;
        } else if (filePath.startsWith(deviceFilesDir)) {
            domain = FullBackup.DEVICE_FILES_TREE_TOKEN;
            rootpath = deviceFilesDir;
        } else if (filePath.startsWith(deviceRootDir)) {
            domain = FullBackup.DEVICE_ROOT_TREE_TOKEN;
            rootpath = deviceRootDir;
        } else if ((efDir != null) && filePath.startsWith(efDir)) {
            domain = FullBackup.MANAGED_EXTERNAL_TREE_TOKEN;
            rootpath = efDir;
Loading