Initial file-based encryption public APIs.

Define two explicit directories where device-encrypted and
credential-encrypted data will be stored.  Third-party apps only
need access to the device-encrypted directory, so that's the only
API exposed for now.

General cleanup in how ApplicationInfo details are derived.

Bug: 22358539
Change-Id: If0a0108721a4aa1c3052b4912e08604bbf24e1ae
diff --git a/api/current.txt b/api/current.txt
index 73b522f..d330dad 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7739,6 +7739,7 @@
     method public final android.content.res.ColorStateList getColorStateList(int);
     method public abstract android.content.ContentResolver getContentResolver();
     method public abstract java.io.File getDatabasePath(java.lang.String);
+    method public abstract java.io.File getDeviceEncryptedFilesDir();
     method public abstract java.io.File getDir(java.lang.String, int);
     method public final android.graphics.drawable.Drawable getDrawable(int);
     method public abstract java.io.File getExternalCacheDir();
@@ -7921,6 +7922,7 @@
     method public java.io.File getCodeCacheDir();
     method public android.content.ContentResolver getContentResolver();
     method public java.io.File getDatabasePath(java.lang.String);
+    method public java.io.File getDeviceEncryptedFilesDir();
     method public java.io.File getDir(java.lang.String, int);
     method public java.io.File getExternalCacheDir();
     method public java.io.File[] getExternalCacheDirs();
@@ -31932,6 +31934,7 @@
     method public java.io.File getCodeCacheDir();
     method public android.content.ContentResolver getContentResolver();
     method public java.io.File getDatabasePath(java.lang.String);
+    method public java.io.File getDeviceEncryptedFilesDir();
     method public java.io.File getDir(java.lang.String, int);
     method public java.io.File getExternalCacheDir();
     method public java.io.File[] getExternalCacheDirs();
diff --git a/api/system-current.txt b/api/system-current.txt
index 87932ac..f101856 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -7980,7 +7980,9 @@
     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 getCredentialEncryptedFilesDir();
     method public abstract java.io.File getDatabasePath(java.lang.String);
+    method public abstract java.io.File getDeviceEncryptedFilesDir();
     method public abstract java.io.File getDir(java.lang.String, int);
     method public final android.graphics.drawable.Drawable getDrawable(int);
     method public abstract java.io.File getExternalCacheDir();
@@ -8170,7 +8172,9 @@
     method public java.lang.ClassLoader getClassLoader();
     method public java.io.File getCodeCacheDir();
     method public android.content.ContentResolver getContentResolver();
+    method public java.io.File getCredentialEncryptedFilesDir();
     method public java.io.File getDatabasePath(java.lang.String);
+    method public java.io.File getDeviceEncryptedFilesDir();
     method public java.io.File getDir(java.lang.String, int);
     method public java.io.File getExternalCacheDir();
     method public java.io.File[] getExternalCacheDirs();
@@ -34237,7 +34241,9 @@
     method public java.lang.ClassLoader getClassLoader();
     method public java.io.File getCodeCacheDir();
     method public android.content.ContentResolver getContentResolver();
+    method public java.io.File getCredentialEncryptedFilesDir();
     method public java.io.File getDatabasePath(java.lang.String);
+    method public java.io.File getDeviceEncryptedFilesDir();
     method public java.io.File getDir(java.lang.String, int);
     method public java.io.File getExternalCacheDir();
     method public java.io.File[] getExternalCacheDirs();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index a74f528..b3d6382 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4834,13 +4834,7 @@
         // Continue loading instrumentation.
         if (ii != null) {
             final ApplicationInfo instrApp = new ApplicationInfo();
-            instrApp.packageName = ii.packageName;
-            instrApp.sourceDir = ii.sourceDir;
-            instrApp.publicSourceDir = ii.publicSourceDir;
-            instrApp.splitSourceDirs = ii.splitSourceDirs;
-            instrApp.splitPublicSourceDirs = ii.splitPublicSourceDirs;
-            instrApp.dataDir = ii.dataDir;
-            instrApp.nativeLibraryDir = ii.nativeLibraryDir;
+            ii.copyTo(instrApp);
 
             final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
                     appContext.getClassLoader(), false, true, false);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index fca5567..bc7c3d0 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -443,6 +443,22 @@
     }
 
     @Override
+    public File getDeviceEncryptedFilesDir() {
+        if (mPackageInfo != null) {
+            return mPackageInfo.getDeviceEncryptedDataDirFile();
+        }
+        throw new RuntimeException("Not supported in system context");
+    }
+
+    @Override
+    public File getCredentialEncryptedFilesDir() {
+        if (mPackageInfo != null) {
+            return mPackageInfo.getCredentialEncryptedDataDirFile();
+        }
+        throw new RuntimeException("Not supported in system context");
+    }
+
+    @Override
     public File getNoBackupFilesDir() {
         synchronized (mSync) {
             if (mNoBackupFilesDir == null) {
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index c2bf28a..8b7abb7 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -31,6 +31,7 @@
 import android.content.res.CompatibilityInfo;
 import android.content.res.Resources;
 import android.os.Bundle;
+import android.os.FileUtils;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Process;
@@ -93,6 +94,8 @@
     private final String mDataDir;
     private final String mLibDir;
     private final File mDataDirFile;
+    private final File mDeviceEncryptedDataDirFile;
+    private final File mCredentialEncryptedDataDirFile;
     private final ClassLoader mBaseClassLoader;
     private final boolean mSecurityViolation;
     private final boolean mIncludeCode;
@@ -139,7 +142,9 @@
         mOverlayDirs = aInfo.resourceDirs;
         mSharedLibraries = aInfo.sharedLibraryFiles;
         mDataDir = aInfo.dataDir;
-        mDataDirFile = mDataDir != null ? new File(mDataDir) : null;
+        mDataDirFile = FileUtils.newFileOrNull(mDataDir);
+        mDeviceEncryptedDataDirFile = FileUtils.newFileOrNull(aInfo.deviceEncryptedDataDir);
+        mCredentialEncryptedDataDirFile = FileUtils.newFileOrNull(aInfo.credentialEncryptedDataDir);
         mLibDir = aInfo.nativeLibraryDir;
         mBaseClassLoader = baseLoader;
         mSecurityViolation = securityViolation;
@@ -192,6 +197,8 @@
         mSharedLibraries = null;
         mDataDir = null;
         mDataDirFile = null;
+        mDeviceEncryptedDataDirFile = null;
+        mCredentialEncryptedDataDirFile = null;
         mLibDir = null;
         mBaseClassLoader = null;
         mSecurityViolation = false;
@@ -539,6 +546,14 @@
         return mDataDirFile;
     }
 
+    public File getDeviceEncryptedDataDirFile() {
+        return mDeviceEncryptedDataDirFile;
+    }
+
+    public File getCredentialEncryptedDataDirFile() {
+        return mCredentialEncryptedDataDirFile;
+    }
+
     public AssetManager getAssets(ActivityThread mainThread) {
         return getResources(mainThread).getAssets();
     }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 3f02f17..a0102b6 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -724,6 +724,27 @@
     public abstract File getFilesDir();
 
     /**
+     * Return the filesystem directory for storing device-encrypted private app
+     * data. Files stored in this location are typically encrypted with a key
+     * tied to the physical device, and they can be accessed whenever the device
+     * has booted successfully, both <em>before and after</em> the user has
+     * entered their credentials (such as a lock pattern or PIN).
+     */
+    public abstract File getDeviceEncryptedFilesDir();
+
+    /**
+     * Return the filesystem directory for storing credential-encrypted private
+     * app data. Files stored in this location are typically encrypted with a
+     * key tied to user credentials, and they can be accessed
+     * <em>only after</em> the user has entered their credentials (such as a
+     * lock pattern or PIN).
+     *
+     * @hide
+     */
+    @SystemApi
+    public abstract File getCredentialEncryptedFilesDir();
+
+    /**
      * Returns the absolute path to the directory on the filesystem similar to
      * {@link #getFilesDir()}. The difference is that files placed under this
      * directory will be excluded from automatic backup to remote storage. See
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 8359edf..bec1b37 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -204,6 +204,18 @@
     }
 
     @Override
+    public File getDeviceEncryptedFilesDir() {
+        return mBase.getDeviceEncryptedFilesDir();
+    }
+
+    /** {@hide} */
+    @SystemApi
+    @Override
+    public File getCredentialEncryptedFilesDir() {
+        return mBase.getCredentialEncryptedFilesDir();
+    }
+
+    @Override
     public File getNoBackupFilesDir() {
         return mBase.getNoBackupFilesDir();
     }
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 914945b..6bc2ac3 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -19,8 +19,10 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
+import android.os.Environment;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Printer;
 
@@ -459,6 +461,14 @@
     public static final int PRIVATE_FLAG_HAS_DOMAIN_URLS = 1<<4;
 
     /**
+     * When set, default data storage directory for given app is pointed at
+     * device-encrypted location.
+     *
+     * @hide
+     */
+    public static final int PRIVATE_FLAG_DEVICE_ENCRYPTED = 1 << 5;
+
+    /**
      * Private/hidden flags. See {@code PRIVATE_FLAG_...} constants.
      * {@hide}
      */
@@ -549,11 +559,15 @@
     public String[] sharedLibraryFiles;
     
     /**
-     * Full path to a directory assigned to the package for its persistent
-     * data.
+     * Full path to a directory assigned to the package for its persistent data.
      */
     public String dataDir;
 
+    /** {@hide} */
+    public String deviceEncryptedDataDir;
+    /** {@hide} */
+    public String credentialEncryptedDataDir;
+
     /**
      * Full path to the directory where native JNI libraries are stored.
      */
@@ -690,6 +704,8 @@
             pw.println(prefix + "seinfo=" + seinfo);
         }
         pw.println(prefix + "dataDir=" + dataDir);
+        pw.println(prefix + "deviceEncryptedDataDir=" + deviceEncryptedDataDir);
+        pw.println(prefix + "credentialEncryptedDataDir=" + credentialEncryptedDataDir);
         if (sharedLibraryFiles != null) {
             pw.println(prefix + "sharedLibraryFiles=" + Arrays.toString(sharedLibraryFiles));
         }
@@ -776,6 +792,8 @@
         seinfo = orig.seinfo;
         sharedLibraryFiles = orig.sharedLibraryFiles;
         dataDir = orig.dataDir;
+        deviceEncryptedDataDir = orig.deviceEncryptedDataDir;
+        credentialEncryptedDataDir = orig.credentialEncryptedDataDir;
         uid = orig.uid;
         targetSdkVersion = orig.targetSdkVersion;
         versionCode = orig.versionCode;
@@ -789,7 +807,6 @@
         fullBackupContent = orig.fullBackupContent;
     }
 
-
     public String toString() {
         return "ApplicationInfo{"
             + Integer.toHexString(System.identityHashCode(this))
@@ -829,6 +846,8 @@
         dest.writeString(seinfo);
         dest.writeStringArray(sharedLibraryFiles);
         dest.writeString(dataDir);
+        dest.writeString(deviceEncryptedDataDir);
+        dest.writeString(credentialEncryptedDataDir);
         dest.writeInt(uid);
         dest.writeInt(targetSdkVersion);
         dest.writeInt(versionCode);
@@ -881,6 +900,8 @@
         seinfo = source.readString();
         sharedLibraryFiles = source.readStringArray();
         dataDir = source.readString();
+        deviceEncryptedDataDir = source.readString();
+        credentialEncryptedDataDir = source.readString();
         uid = source.readInt();
         targetSdkVersion = source.readInt();
         versionCode = source.readInt();
@@ -925,7 +946,30 @@
                 FLAG_SUPPORTS_SMALL_SCREENS | FLAG_RESIZEABLE_FOR_SCREENS |
                 FLAG_SUPPORTS_SCREEN_DENSITIES | FLAG_SUPPORTS_XLARGE_SCREENS);
     }
-    
+
+    /** {@hide} */
+    public void initForUser(int userId) {
+        uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
+
+        if ("android".equals(packageName)) {
+            dataDir = Environment.getDataSystemDirectory().getAbsolutePath();
+            return;
+        }
+
+        deviceEncryptedDataDir = Environment
+                .getDataUserDeviceEncryptedPackageDirectory(volumeUuid, userId, packageName)
+                .getAbsolutePath();
+        credentialEncryptedDataDir = Environment
+                .getDataUserCredentialEncryptedPackageDirectory(volumeUuid, userId, packageName)
+                .getAbsolutePath();
+
+        if ((privateFlags & PRIVATE_FLAG_DEVICE_ENCRYPTED) != 0) {
+            dataDir = deviceEncryptedDataDir;
+        } else {
+            dataDir = credentialEncryptedDataDir;
+        }
+    }
+
     /**
      * @hide
      */
diff --git a/core/java/android/content/pm/InstrumentationInfo.java b/core/java/android/content/pm/InstrumentationInfo.java
index dab0caf..44bdf4e 100644
--- a/core/java/android/content/pm/InstrumentationInfo.java
+++ b/core/java/android/content/pm/InstrumentationInfo.java
@@ -57,11 +57,15 @@
     public String[] splitPublicSourceDirs;
 
     /**
-     * Full path to a directory assigned to the package for its persistent
-     * data.
+     * Full path to a directory assigned to the package for its persistent data.
      */
     public String dataDir;
 
+    /** {@hide} */
+    public String deviceEncryptedDataDir;
+    /** {@hide} */
+    public String credentialEncryptedDataDir;
+
     /**
      * Full path to the directory where the native JNI libraries are stored.
      * 
@@ -85,7 +89,11 @@
         targetPackage = orig.targetPackage;
         sourceDir = orig.sourceDir;
         publicSourceDir = orig.publicSourceDir;
+        splitSourceDirs = orig.splitSourceDirs;
+        splitPublicSourceDirs = orig.splitPublicSourceDirs;
         dataDir = orig.dataDir;
+        deviceEncryptedDataDir = orig.deviceEncryptedDataDir;
+        credentialEncryptedDataDir = orig.credentialEncryptedDataDir;
         nativeLibraryDir = orig.nativeLibraryDir;
         handleProfiling = orig.handleProfiling;
         functionalTest = orig.functionalTest;
@@ -106,7 +114,11 @@
         dest.writeString(targetPackage);
         dest.writeString(sourceDir);
         dest.writeString(publicSourceDir);
+        dest.writeStringArray(splitSourceDirs);
+        dest.writeStringArray(splitPublicSourceDirs);
         dest.writeString(dataDir);
+        dest.writeString(deviceEncryptedDataDir);
+        dest.writeString(credentialEncryptedDataDir);
         dest.writeString(nativeLibraryDir);
         dest.writeInt((handleProfiling == false) ? 0 : 1);
         dest.writeInt((functionalTest == false) ? 0 : 1);
@@ -127,9 +139,26 @@
         targetPackage = source.readString();
         sourceDir = source.readString();
         publicSourceDir = source.readString();
+        splitSourceDirs = source.readStringArray();
+        splitPublicSourceDirs = source.readStringArray();
         dataDir = source.readString();
+        deviceEncryptedDataDir = source.readString();
+        credentialEncryptedDataDir = source.readString();
         nativeLibraryDir = source.readString();
         handleProfiling = source.readInt() != 0;
         functionalTest = source.readInt() != 0;
     }
+
+    /** {@hide} */
+    public void copyTo(ApplicationInfo ai) {
+        ai.packageName = packageName;
+        ai.sourceDir = sourceDir;
+        ai.publicSourceDir = publicSourceDir;
+        ai.splitSourceDirs = splitSourceDirs;
+        ai.splitPublicSourceDirs = splitPublicSourceDirs;
+        ai.dataDir = dataDir;
+        ai.deviceEncryptedDataDir = deviceEncryptedDataDir;
+        ai.credentialEncryptedDataDir = credentialEncryptedDataDir;
+        ai.nativeLibraryDir = nativeLibraryDir;
+    }
 }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 5d73b06..20e76d6 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -4875,9 +4875,7 @@
 
         // Make shallow copy so we can store the metadata/libraries safely
         ApplicationInfo ai = new ApplicationInfo(p.applicationInfo);
-        ai.uid = UserHandle.getUid(userId, ai.uid);
-        ai.dataDir = Environment.getDataUserPackageDirectory(ai.volumeUuid, userId, ai.packageName)
-                .getAbsolutePath();
+        ai.initForUser(userId);
         if ((flags & PackageManager.GET_META_DATA) != 0) {
             ai.metaData = p.mAppMetaData;
         }
@@ -4902,9 +4900,7 @@
         // This is only used to return the ResolverActivity; we will just always
         // make a copy.
         ai = new ApplicationInfo(ai);
-        ai.uid = UserHandle.getUid(userId, ai.uid);
-        ai.dataDir = Environment.getDataUserPackageDirectory(ai.volumeUuid, userId, ai.packageName)
-                .getAbsolutePath();
+        ai.initForUser(userId);
         if (state.stopped) {
             ai.flags |= ApplicationInfo.FLAG_STOPPED;
         } else {
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index f346fe7..53627fc 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -35,6 +35,7 @@
     private static final String ENV_ANDROID_ROOT = "ANDROID_ROOT";
     private static final String ENV_ANDROID_DATA = "ANDROID_DATA";
     private static final String ENV_ANDROID_STORAGE = "ANDROID_STORAGE";
+    private static final String ENV_DOWNLOAD_CACHE = "DOWNLOAD_CACHE";
     private static final String ENV_OEM_ROOT = "OEM_ROOT";
     private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT";
 
@@ -53,11 +54,10 @@
     private static final File DIR_ANDROID_ROOT = getDirectory(ENV_ANDROID_ROOT, "/system");
     private static final File DIR_ANDROID_DATA = getDirectory(ENV_ANDROID_DATA, "/data");
     private static final File DIR_ANDROID_STORAGE = getDirectory(ENV_ANDROID_STORAGE, "/storage");
+    private static final File DIR_DOWNLOAD_CACHE = getDirectory(ENV_DOWNLOAD_CACHE, "/cache");
     private static final File DIR_OEM_ROOT = getDirectory(ENV_OEM_ROOT, "/oem");
     private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor");
 
-    private static final String SYSTEM_PROPERTY_EFS_ENABLED = "persist.security.efs.enabled";
-
     private static UserEnvironment sCurrentUser;
     private static boolean sUserRequired;
 
@@ -164,34 +164,16 @@
         return DIR_VENDOR_ROOT;
     }
 
-    /**
-     * Gets the system directory available for secure storage.
-     * If Encrypted File system is enabled, it returns an encrypted directory (/data/secure/system).
-     * Otherwise, it returns the unencrypted /data/system directory.
-     * @return File object representing the secure storage system directory.
-     * @hide
-     */
+    /** {@hide} */
+    @Deprecated
     public static File getSystemSecureDirectory() {
-        if (isEncryptedFilesystemEnabled()) {
-            return new File(SECURE_DATA_DIRECTORY, "system");
-        } else {
-            return new File(DATA_DIRECTORY, "system");
-        }
+        return getDataSystemDirectory();
     }
 
-    /**
-     * Gets the data directory for secure storage.
-     * If Encrypted File system is enabled, it returns an encrypted directory (/data/secure).
-     * Otherwise, it returns the unencrypted /data directory.
-     * @return File object representing the data directory for secure storage.
-     * @hide
-     */
+    /** {@hide} */
+    @Deprecated
     public static File getSecureDataDirectory() {
-        if (isEncryptedFilesystemEnabled()) {
-            return SECURE_DATA_DIRECTORY;
-        } else {
-            return DATA_DIRECTORY;
-        }
+        return getDataDirectory();
     }
 
     /**
@@ -202,7 +184,7 @@
      * @hide
      */
     public static File getUserSystemDirectory(int userId) {
-        return new File(new File(getSystemSecureDirectory(), "users"), Integer.toString(userId));
+        return new File(new File(getDataSystemDirectory(), "users"), Integer.toString(userId));
     }
 
     /**
@@ -217,62 +199,93 @@
     }
 
     /**
-     * Returns whether the Encrypted File System feature is enabled on the device or not.
-     * @return <code>true</code> if Encrypted File System feature is enabled, <code>false</code>
-     * if disabled.
-     * @hide
-     */
-    public static boolean isEncryptedFilesystemEnabled() {
-        return SystemProperties.getBoolean(SYSTEM_PROPERTY_EFS_ENABLED, false);
-    }
-
-    private static final File DATA_DIRECTORY
-            = getDirectory("ANDROID_DATA", "/data");
-
-    /**
-     * @hide
-     */
-    private static final File SECURE_DATA_DIRECTORY
-            = getDirectory("ANDROID_SECURE_DATA", "/data/secure");
-
-    private static final File DOWNLOAD_CACHE_DIRECTORY = getDirectory("DOWNLOAD_CACHE", "/cache");
-
-    /**
      * Return the user data directory.
      */
     public static File getDataDirectory() {
-        return DATA_DIRECTORY;
+        return DIR_ANDROID_DATA;
     }
 
     /** {@hide} */
     public static File getDataDirectory(String volumeUuid) {
         if (TextUtils.isEmpty(volumeUuid)) {
-            return new File("/data");
+            return DIR_ANDROID_DATA;
         } else {
             return new File("/mnt/expand/" + volumeUuid);
         }
     }
 
     /** {@hide} */
+    public static File getDataSystemDirectory() {
+        return new File(getDataDirectory(), "system");
+    }
+
+    /** {@hide} */
+    public static File getDataSystemCredentialEncryptedDirectory() {
+        return new File(getDataDirectory(), "system_ce");
+    }
+
+    /** {@hide} */
+    public static File getDataSystemCredentialEncryptedDirectory(int userId) {
+        return new File(getDataSystemCredentialEncryptedDirectory(), String.valueOf(userId));
+    }
+
+    /** {@hide} */
     public static File getDataAppDirectory(String volumeUuid) {
         return new File(getDataDirectory(volumeUuid), "app");
     }
 
     /** {@hide} */
+    @Deprecated
     public static File getDataUserDirectory(String volumeUuid) {
+        return getDataUserCredentialEncryptedDirectory(volumeUuid);
+    }
+
+    /** {@hide} */
+    @Deprecated
+    public static File getDataUserDirectory(String volumeUuid, int userId) {
+        return getDataUserCredentialEncryptedDirectory(volumeUuid, userId);
+    }
+
+    /** {@hide} */
+    @Deprecated
+    public static File getDataUserPackageDirectory(String volumeUuid, int userId,
+            String packageName) {
+        return getDataUserCredentialEncryptedPackageDirectory(volumeUuid, userId, packageName);
+    }
+
+    /** {@hide} */
+    public static File getDataUserCredentialEncryptedDirectory(String volumeUuid) {
         return new File(getDataDirectory(volumeUuid), "user");
     }
 
     /** {@hide} */
-    public static File getDataUserDirectory(String volumeUuid, int userId) {
-        return new File(getDataUserDirectory(volumeUuid), String.valueOf(userId));
+    public static File getDataUserCredentialEncryptedDirectory(String volumeUuid, int userId) {
+        return new File(getDataUserCredentialEncryptedDirectory(volumeUuid),
+                String.valueOf(userId));
     }
 
     /** {@hide} */
-    public static File getDataUserPackageDirectory(String volumeUuid, int userId,
+    public static File getDataUserCredentialEncryptedPackageDirectory(String volumeUuid, int userId,
             String packageName) {
         // TODO: keep consistent with installd
-        return new File(getDataUserDirectory(volumeUuid, userId), packageName);
+        return new File(getDataUserCredentialEncryptedDirectory(volumeUuid, userId), packageName);
+    }
+
+    /** {@hide} */
+    public static File getDataUserDeviceEncryptedDirectory(String volumeUuid) {
+        return new File(getDataDirectory(volumeUuid), "user_de");
+    }
+
+    /** {@hide} */
+    public static File getDataUserDeviceEncryptedDirectory(String volumeUuid, int userId) {
+        return new File(getDataUserDeviceEncryptedDirectory(volumeUuid), String.valueOf(userId));
+    }
+
+    /** {@hide} */
+    public static File getDataUserDeviceEncryptedPackageDirectory(String volumeUuid, int userId,
+            String packageName) {
+        // TODO: keep consistent with installd
+        return new File(getDataUserDeviceEncryptedDirectory(volumeUuid, userId), packageName);
     }
 
     /**
@@ -539,7 +552,7 @@
      * Return the download/cache content directory.
      */
     public static File getDownloadCacheDirectory() {
-        return DOWNLOAD_CACHE_DIRECTORY;
+        return DIR_DOWNLOAD_CACHE;
     }
 
     /**
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index af4c2bc..b73d81e 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -17,6 +17,7 @@
 package android.os;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.provider.DocumentsContract.Document;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -646,4 +647,8 @@
             return EMPTY;
         }
     }
+
+    public static @Nullable File newFileOrNull(@Nullable String path) {
+        return (path != null) ? new File(path) : null;
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e13d3e7..13401cd 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -20032,17 +20032,10 @@
         mUserController.unregisterUserSwitchObserver(observer);
     }
 
-    private int applyUserId(int uid, int userId) {
-        return UserHandle.getUid(userId, uid);
-    }
-
     ApplicationInfo getAppInfoForUser(ApplicationInfo info, int userId) {
         if (info == null) return null;
         ApplicationInfo newInfo = new ApplicationInfo(info);
-        newInfo.uid = applyUserId(info.uid, userId);
-        newInfo.dataDir = Environment
-                .getDataUserPackageDirectory(info.volumeUuid, userId, info.packageName)
-                .getAbsolutePath();
+        newInfo.initForUser(userId);
         return newInfo;
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index bbbe67c..11fa38c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2951,9 +2951,8 @@
                 pkg.applicationInfo.packageName = packageName;
                 pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY;
                 pkg.applicationInfo.privateFlags = ps.pkgPrivateFlags;
-                pkg.applicationInfo.dataDir = Environment
-                        .getDataUserPackageDirectory(ps.volumeUuid, userId, packageName)
-                        .getAbsolutePath();
+                pkg.applicationInfo.uid = ps.appId;
+                pkg.applicationInfo.initForUser(userId);
                 pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString;
                 pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString;
             }
@@ -6944,17 +6943,10 @@
                 pkg.applicationInfo.processName,
                 pkg.applicationInfo.uid);
 
-        File dataPath;
-        if (mPlatformPackage == pkg) {
-            // The system package is special.
-            dataPath = new File(Environment.getDataDirectory(), "system");
-
-            pkg.applicationInfo.dataDir = dataPath.getPath();
-
-        } else {
+        if (pkg != mPlatformPackage) {
             // This is a normal package, need to make its data directory.
-            dataPath = Environment.getDataUserPackageDirectory(pkg.volumeUuid,
-                    UserHandle.USER_SYSTEM, pkg.packageName);
+            final File dataPath = Environment.getDataUserCredentialEncryptedPackageDirectory(
+                    pkg.volumeUuid, UserHandle.USER_SYSTEM, pkg.packageName);
 
             boolean uidError = false;
             if (dataPath.exists()) {
@@ -7043,7 +7035,7 @@
                         }
                     }
                 }
-                pkg.applicationInfo.dataDir = dataPath.getPath();
+
                 if (mShouldRestoreconData) {
                     Slog.i(TAG, "SELinux relabeling of " + pkg.packageName + " issued.");
                     mInstaller.restoreconData(pkg.volumeUuid, pkg.packageName,
@@ -7062,15 +7054,11 @@
                     throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
                             "Unable to create data dirs [errorCode=" + ret + "]");
                 }
-
-                if (dataPath.exists()) {
-                    pkg.applicationInfo.dataDir = dataPath.getPath();
-                } else {
-                    Slog.w(TAG, "Unable to create data directory: " + dataPath);
-                    pkg.applicationInfo.dataDir = null;
-                }
             }
 
+            // Get all of our default paths setup
+            pkg.applicationInfo.initForUser(UserHandle.USER_SYSTEM);
+
             pkgSetting.uidError = uidError;
         }
 
@@ -7624,6 +7612,8 @@
                 a.info.splitSourceDirs = pkg.applicationInfo.splitSourceDirs;
                 a.info.splitPublicSourceDirs = pkg.applicationInfo.splitPublicSourceDirs;
                 a.info.dataDir = pkg.applicationInfo.dataDir;
+                a.info.deviceEncryptedDataDir = pkg.applicationInfo.deviceEncryptedDataDir;
+                a.info.credentialEncryptedDataDir = pkg.applicationInfo.credentialEncryptedDataDir;
 
                 // TODO: Update instrumentation.nativeLibraryDir as well ? Does it
                 // need other information about the application, like the ABI and what not ?
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index e09d124..4821678 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -177,6 +177,18 @@
     }
 
     @Override
+    public File getDeviceEncryptedFilesDir() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @SystemApi
+    @Override
+    public File getCredentialEncryptedFilesDir() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public File getNoBackupFilesDir() {
         throw new UnsupportedOperationException();
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 4a5702d..0fcfa78 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -1371,6 +1371,18 @@
     }
 
     @Override
+    public File getDeviceEncryptedFilesDir() {
+        // pass
+        return null;
+    }
+
+    @Override
+    public File getCredentialEncryptedFilesDir() {
+        // pass
+        return null;
+    }
+
+    @Override
     public File getNoBackupFilesDir() {
         // pass
         return null;