summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2015-04-08 21:02:14 -0700
committerJeff Sharkey <jsharkey@android.com>2015-04-10 00:24:03 -0700
commitb9f3674c11ed9c89b80a69f728cbc5f540b2ecde (patch)
treebef6b7bbd6eb34aa933aa137056a39cac46854aa /core
parentd119e52050aecffbc66f14d2e2af5e873211a6de (diff)
downloadframeworks_base-b9f3674c11ed9c89b80a69f728cbc5f540b2ecde.zip
frameworks_base-b9f3674c11ed9c89b80a69f728cbc5f540b2ecde.tar.gz
frameworks_base-b9f3674c11ed9c89b80a69f728cbc5f540b2ecde.tar.bz2
Support moving apps to expanded storage.
Start deriving the data path for apps based on the volume UUID where the app lives. This path is used for all higher-level APIs, giving us a clean place to switch app storage. When parsing a package, keep track of the volume UUID where it lives and update PackageSetting once installed. For now continue treating moves as installs, but we'll eventually clean this up to avoid the additional dexopt pass. Wire up move to use the new installd command to move private data between devices. Cache LoadedApk only for the current user, since otherwise the data dir points at the wrong path. Bug: 19993667 Change-Id: I53336e3b147d5fd3130e6800869af172b628da37
Diffstat (limited to 'core')
-rw-r--r--core/java/android/app/ActivityThread.java19
-rw-r--r--core/java/android/app/LoadedApk.java6
-rw-r--r--core/java/android/content/pm/PackageManager.java18
-rw-r--r--core/java/android/content/pm/PackageParser.java18
-rw-r--r--core/tests/coretests/src/android/content/pm/PackageManagerTests.java8
5 files changed, 44 insertions, 25 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index ed05321..ed7d11b 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -220,6 +220,7 @@ public final class ActivityThread {
// which means this lock gets held while the activity and window managers
// holds their own lock. Thus you MUST NEVER call back into the activity manager
// or window manager or anything that depends on them while holding this lock.
+ // These LoadedApk are only valid for the userId that we're running as.
final ArrayMap<String, WeakReference<LoadedApk>> mPackages
= new ArrayMap<String, WeakReference<LoadedApk>>();
final ArrayMap<String, WeakReference<LoadedApk>> mResourcePackages
@@ -1705,13 +1706,18 @@ public final class ActivityThread {
public final LoadedApk getPackageInfo(String packageName, CompatibilityInfo compatInfo,
int flags, int userId) {
+ final boolean differentUser = (UserHandle.myUserId() != userId);
synchronized (mResourcesManager) {
WeakReference<LoadedApk> ref;
- if ((flags&Context.CONTEXT_INCLUDE_CODE) != 0) {
+ if (differentUser) {
+ // Caching not supported across users
+ ref = null;
+ } else if ((flags & Context.CONTEXT_INCLUDE_CODE) != 0) {
ref = mPackages.get(packageName);
} else {
ref = mResourcePackages.get(packageName);
}
+
LoadedApk packageInfo = ref != null ? ref.get() : null;
//Slog.i(TAG, "getPackageInfo " + packageName + ": " + packageInfo);
//if (packageInfo != null) Slog.i(TAG, "isUptoDate " + packageInfo.mResDir
@@ -1791,13 +1797,18 @@ public final class ActivityThread {
private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
ClassLoader baseLoader, boolean securityViolation, boolean includeCode,
boolean registerPackage) {
+ final boolean differentUser = (UserHandle.myUserId() != UserHandle.getUserId(aInfo.uid));
synchronized (mResourcesManager) {
WeakReference<LoadedApk> ref;
- if (includeCode) {
+ if (differentUser) {
+ // Caching not supported across users
+ ref = null;
+ } else if (includeCode) {
ref = mPackages.get(aInfo.packageName);
} else {
ref = mResourcePackages.get(aInfo.packageName);
}
+
LoadedApk packageInfo = ref != null ? ref.get() : null;
if (packageInfo == null || (packageInfo.mResources != null
&& !packageInfo.mResources.getAssets().isUpToDate())) {
@@ -1816,7 +1827,9 @@ public final class ActivityThread {
getSystemContext().mPackageInfo.getClassLoader());
}
- if (includeCode) {
+ if (differentUser) {
+ // Caching not supported across users
+ } else if (includeCode) {
mPackages.put(aInfo.packageName,
new WeakReference<LoadedApk>(packageInfo));
} else {
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 83c6c2b..9604789 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -18,7 +18,6 @@ package android.app;
import android.text.TextUtils;
import android.util.ArrayMap;
-
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -46,6 +45,7 @@ import android.util.SparseArray;
import android.view.DisplayAdjustments;
import android.view.Display;
import android.os.SystemProperties;
+
import dalvik.system.VMRuntime;
import java.io.File;
@@ -136,10 +136,6 @@ public final class LoadedApk {
mSplitAppDirs = aInfo.splitSourceDirs;
mSplitResDirs = aInfo.uid == myUid ? aInfo.splitSourceDirs : aInfo.splitPublicSourceDirs;
mOverlayDirs = aInfo.resourceDirs;
- if (!UserHandle.isSameUser(aInfo.uid, myUid) && !Process.isIsolated()) {
- aInfo.dataDir = PackageManager.getDataDirForUser(UserHandle.getUserId(myUid),
- mPackageName);
- }
mSharedLibraries = aInfo.sharedLibraryFiles;
mDataDir = aInfo.dataDir;
mDataDirFile = mDataDir != null ? new File(mDataDir) : null;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 303b709..491fc94 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -44,6 +44,7 @@ import android.os.Environment;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.storage.VolumeInfo;
+import android.text.TextUtils;
import android.util.AndroidException;
import com.android.internal.util.ArrayUtils;
@@ -4149,16 +4150,19 @@ public abstract class PackageManager {
public abstract @NonNull PackageInstaller getPackageInstaller();
/**
- * Returns the data directory for a particular user and package, given the uid of the package.
- * @param uid uid of the package, including the userId and appId
- * @param packageName name of the package
- * @return the user-specific data directory for the package
+ * Returns the data directory for a particular package and user.
+ *
* @hide
*/
- public static String getDataDirForUser(int userId, String packageName) {
+ public static File getDataDirForUser(String volumeUuid, String packageName, int userId) {
// TODO: This should be shared with Installer's knowledge of user directory
- return Environment.getDataDirectory().toString() + "/user/" + userId
- + "/" + packageName;
+ final File base;
+ if (TextUtils.isEmpty(volumeUuid)) {
+ base = Environment.getDataDirectory();
+ } else {
+ base = new File("/mnt/expand/" + volumeUuid);
+ }
+ return new File(base, "user/" + userId + "/" + packageName);
}
/**
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 7523675..763a017 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -111,6 +111,9 @@ public class PackageParser {
/** File name in an APK for the Android manifest. */
private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
+ /** Path prefix for apps on expanded storage */
+ private static final String MNT_EXPAND = "/mnt/expand/";
+
/** @hide */
public static class NewPermissionInfo {
public final String name;
@@ -860,6 +863,12 @@ public class PackageParser {
throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();
+ String volumeUuid = null;
+ if (apkPath.startsWith(MNT_EXPAND)) {
+ final int end = apkPath.indexOf('/', MNT_EXPAND.length());
+ volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);
+ }
+
mParseError = PackageManager.INSTALL_SUCCEEDED;
mArchiveSourcePath = apkFile.getAbsolutePath();
@@ -882,6 +891,7 @@ public class PackageParser {
apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
}
+ pkg.volumeUuid = volumeUuid;
pkg.baseCodePath = apkPath;
pkg.mSignatures = null;
@@ -4206,6 +4216,8 @@ public class PackageParser {
// TODO: work towards making these paths invariant
+ public String volumeUuid;
+
/**
* Path where this package was found on disk. For monolithic packages
* this is path to single base APK file; for cluster packages this is
@@ -4727,7 +4739,8 @@ public class PackageParser {
ApplicationInfo ai = new ApplicationInfo(p.applicationInfo);
if (userId != 0) {
ai.uid = UserHandle.getUid(userId, ai.uid);
- ai.dataDir = PackageManager.getDataDirForUser(userId, ai.packageName);
+ ai.dataDir = PackageManager.getDataDirForUser(ai.volumeUuid, ai.packageName, userId)
+ .getAbsolutePath();
}
if ((flags & PackageManager.GET_META_DATA) != 0) {
ai.metaData = p.mAppMetaData;
@@ -4755,7 +4768,8 @@ public class PackageParser {
ai = new ApplicationInfo(ai);
if (userId != 0) {
ai.uid = UserHandle.getUid(userId, ai.uid);
- ai.dataDir = PackageManager.getDataDirForUser(userId, ai.packageName);
+ ai.dataDir = PackageManager.getDataDirForUser(ai.volumeUuid, ai.packageName, userId)
+ .getAbsolutePath();
}
if (state.stopped) {
ai.flags |= ApplicationInfo.FLAG_STOPPED;
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index a59581b..279bfbf 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -576,14 +576,6 @@ public class PackageManagerTests extends AndroidTestCase {
fail(pkgName + " shouldnt be installed");
} catch (NameNotFoundException e) {
}
-
- UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- List<UserInfo> users = um.getUsers();
- for (UserInfo user : users) {
- String dataDir = PackageManager.getDataDirForUser(user.id, pkgName);
- assertFalse("Application data directory should not exist: " + dataDir,
- new File(dataDir).exists());
- }
}
class InstallParams {