diff options
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; |
