summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java4
-rw-r--r--services/core/java/com/android/server/pm/Installer.java16
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java64
-rw-r--r--services/core/java/com/android/server/pm/Settings.java18
9 files changed, 110 insertions, 61 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 {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7193384..ebf1930 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -19608,8 +19608,8 @@ public final class ActivityManagerService extends ActivityManagerNative
if (info == null) return null;
ApplicationInfo newInfo = new ApplicationInfo(info);
newInfo.uid = applyUserId(info.uid, userId);
- newInfo.dataDir = USER_DATA_DIR + userId + "/"
- + info.packageName;
+ newInfo.dataDir = PackageManager.getDataDirForUser(info.volumeUuid, info.packageName,
+ userId).getAbsolutePath();
return newInfo;
}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index ce31f98..a32363d 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -261,6 +261,22 @@ public final class Installer extends SystemService {
return mInstaller.execute(builder.toString());
}
+ public int moveUserDataDirs(String fromUuid, String toUuid, String packageName, int appId,
+ String seinfo) {
+ StringBuilder builder = new StringBuilder("mvuserdata");
+ builder.append(' ');
+ builder.append(escapeNull(fromUuid));
+ builder.append(' ');
+ builder.append(escapeNull(toUuid));
+ builder.append(' ');
+ builder.append(packageName);
+ builder.append(' ');
+ builder.append(appId);
+ builder.append(' ');
+ builder.append(seinfo);
+ return mInstaller.execute(builder.toString());
+ }
+
@Deprecated
public int clearUserData(String name, int userId) {
return clearUserData(null, name, userId);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f5042ed..9465682 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -51,6 +51,7 @@ import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATIO
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
import static android.content.pm.PackageManager.MOVE_EXTERNAL_MEDIA;
import static android.content.pm.PackageManager.MOVE_FAILED_DOESNT_EXIST;
+import static android.content.pm.PackageManager.MOVE_FAILED_INTERNAL_ERROR;
import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING;
import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
import static android.content.pm.PackageManager.MOVE_INTERNAL;
@@ -71,7 +72,6 @@ import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
import android.Manifest;
-import org.xmlpull.v1.XmlPullParser;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
@@ -202,6 +202,7 @@ import com.android.server.Watchdog;
import com.android.server.pm.Settings.DatabaseVersion;
import com.android.server.storage.DeviceStorageMonitorInternal;
+import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
import java.io.BufferedInputStream;
@@ -2597,8 +2598,8 @@ public class PackageManagerService extends IPackageManager.Stub {
pkg.applicationInfo.packageName = packageName;
pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY;
pkg.applicationInfo.privateFlags = ps.pkgPrivateFlags;
- pkg.applicationInfo.dataDir =
- getDataPathForPackage(packageName, 0).getPath();
+ pkg.applicationInfo.dataDir = PackageManager.getDataDirForUser(ps.volumeUuid,
+ packageName, userId).getAbsolutePath();
pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString;
pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString;
}
@@ -5103,6 +5104,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
// Set application objects path explicitly.
+ pkg.applicationInfo.volumeUuid = pkg.volumeUuid;
pkg.applicationInfo.setCodePath(pkg.codePath);
pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath);
pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths);
@@ -5510,20 +5512,6 @@ public class PackageManagerService extends IPackageManager.Stub {
return true;
}
- private File getDataPathForPackage(String packageName, int userId) {
- /*
- * Until we fully support multiple users, return the directory we
- * previously would have. The PackageManagerTests will need to be
- * revised when this is changed back..
- */
- if (userId == 0) {
- return new File(mAppDataDir, packageName);
- } else {
- return new File(mUserAppDataDir.getAbsolutePath() + File.separator + userId
- + File.separator + packageName);
- }
- }
-
private int createDataDirsLI(String packageName, int uid, String seinfo) {
int[] users = sUserManager.getUserIds();
int res = mInstaller.install(packageName, uid, uid, seinfo);
@@ -6043,7 +6031,8 @@ public class PackageManagerService extends IPackageManager.Stub {
} else {
// This is a normal package, need to make its data directory.
- dataPath = getDataPathForPackage(pkg.packageName, 0);
+ dataPath = PackageManager.getDataDirForUser(pkg.volumeUuid, pkg.packageName,
+ UserHandle.USER_OWNER);
boolean uidError = false;
if (dataPath.exists()) {
@@ -10136,6 +10125,7 @@ public class PackageManagerService extends IPackageManager.Stub {
pkg.splitCodePaths);
// Reflect the rename in app info
+ pkg.applicationInfo.volumeUuid = pkg.volumeUuid;
pkg.applicationInfo.setCodePath(pkg.codePath);
pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath);
pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths);
@@ -10426,6 +10416,7 @@ public class PackageManagerService extends IPackageManager.Stub {
pkg.splitCodePaths);
// Reflect the rename in app info
+ pkg.applicationInfo.volumeUuid = pkg.volumeUuid;
pkg.applicationInfo.setCodePath(pkg.codePath);
pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath);
pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths);
@@ -10684,7 +10675,8 @@ public class PackageManagerService extends IPackageManager.Stub {
String pkgName = pkg.packageName;
if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
- boolean dataDirExists = getDataPathForPackage(pkg.packageName, 0).exists();
+ final boolean dataDirExists = PackageManager.getDataDirForUser(volumeUuid, pkgName,
+ UserHandle.USER_OWNER).exists();
synchronized(mPackages) {
if (mSettings.mRenamedPackages.containsKey(pkgName)) {
// A package with the same name is already installed, though
@@ -11056,7 +11048,6 @@ public class PackageManagerService extends IPackageManager.Stub {
res.pkg = newPackage;
mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_COMPLETE);
mSettings.setInstallerPackageName(pkgName, installerPackageName);
- mSettings.setVolumeUuid(pkgName, volumeUuid);
res.returnCode = PackageManager.INSTALL_SUCCEEDED;
//to update install status
mSettings.writeLPr();
@@ -14175,11 +14166,12 @@ public class PackageManagerService extends IPackageManager.Stub {
boolean andData, final IPackageMoveObserver observer) throws PackageManagerException {
final UserHandle user = new UserHandle(UserHandle.getCallingUserId());
- File codeFile = null;
- String installerPackageName = null;
- String packageAbiOverride = null;
-
- // TOOD: move app private data before installing
+ final String currentVolumeUuid;
+ final File codeFile;
+ final String installerPackageName;
+ final String packageAbiOverride;
+ final int appId;
+ final String seinfo;
// reader
synchronized (mPackages) {
@@ -14201,9 +14193,31 @@ public class PackageManagerService extends IPackageManager.Stub {
pkg.mOperationPending = true;
+ currentVolumeUuid = ps.volumeUuid;
codeFile = new File(pkg.codePath);
installerPackageName = ps.installerPackageName;
packageAbiOverride = ps.cpuAbiOverrideString;
+ appId = UserHandle.getAppId(pkg.applicationInfo.uid);
+ seinfo = pkg.applicationInfo.seinfo;
+ }
+
+ if (andData) {
+ Slog.d(TAG, "Moving " + packageName + " private data from " + currentVolumeUuid + " to "
+ + volumeUuid);
+ synchronized (mInstallLock) {
+ if (mInstaller.moveUserDataDirs(currentVolumeUuid, volumeUuid, packageName, appId,
+ seinfo) != 0) {
+ synchronized (mPackages) {
+ final PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg != null) {
+ pkg.mOperationPending = false;
+ }
+ }
+
+ throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
+ "Failed to move private data");
+ }
+ }
}
final IPackageInstallObserver2 installObserver = new IPackageInstallObserver2.Stub() {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index bfcc3db..c068934 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -344,13 +344,6 @@ final class Settings {
}
}
- void setVolumeUuid(String pkgName, String volumeUuid) {
- PackageSetting p = mPackages.get(pkgName);
- if (p != null) {
- p.setVolumeUuid(volumeUuid);
- }
- }
-
SharedUserSetting getSharedUserLPw(String name,
int pkgFlags, int pkgPrivateFlags, boolean create) {
SharedUserSetting s = mSharedUsers.get(name);
@@ -693,19 +686,26 @@ final class Settings {
p.pkg = pkg;
// pkg.mSetEnabled = p.getEnabled(userId);
// pkg.mSetStopped = p.getStopped(userId);
+ final String volumeUuid = pkg.applicationInfo.volumeUuid;
final String codePath = pkg.applicationInfo.getCodePath();
final String resourcePath = pkg.applicationInfo.getResourcePath();
final String legacyNativeLibraryPath = pkg.applicationInfo.nativeLibraryRootDir;
+ // Update volume if needed
+ if (!Objects.equals(volumeUuid, p.volumeUuid)) {
+ Slog.w(PackageManagerService.TAG, "Volume for " + p.pkg.packageName +
+ " changing from " + p.volumeUuid + " to " + volumeUuid);
+ p.volumeUuid = volumeUuid;
+ }
// Update code path if needed
if (!Objects.equals(codePath, p.codePathString)) {
- Slog.w(PackageManagerService.TAG, "Code path for pkg : " + p.pkg.packageName +
+ Slog.w(PackageManagerService.TAG, "Code path for " + p.pkg.packageName +
" changing from " + p.codePathString + " to " + codePath);
p.codePath = new File(codePath);
p.codePathString = codePath;
}
//Update resource path if needed
if (!Objects.equals(resourcePath, p.resourcePathString)) {
- Slog.w(PackageManagerService.TAG, "Resource path for pkg : " + p.pkg.packageName +
+ Slog.w(PackageManagerService.TAG, "Resource path for " + p.pkg.packageName +
" changing from " + p.resourcePathString + " to " + resourcePath);
p.resourcePath = new File(resourcePath);
p.resourcePathString = resourcePath;