diff options
5 files changed, 128 insertions, 170 deletions
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index 4f58321da2f4..6f49cc42f6f6 100644 --- a/core/java/android/content/pm/PackageManagerInternal.java +++ b/core/java/android/content/pm/PackageManagerInternal.java @@ -703,6 +703,18 @@ public abstract class PackageManagerInternal { public abstract SparseArray<String> getAppsWithSharedUserIds(); /** + * Get the value of attribute android:sharedUserId for the given packageName if specified, + * otherwise {@code null}. + */ + public abstract String getSharedUserIdForPackage(@NonNull String packageName); + + /** + * Get all packages which specified the given sharedUserId as android:sharedUserId attribute + * or an empty array if no package specified it. + */ + public abstract String[] getPackagesForSharedUserId(@NonNull String sharedUserId, int userId); + + /** * Return if device is currently in a "core" boot environment, typically * used to support full-disk encryption. Only apps marked with * {@code coreApp} attribute are available. diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java index 63ff7b22f364..816a730716e1 100644 --- a/core/java/android/os/storage/StorageManagerInternal.java +++ b/core/java/android/os/storage/StorageManagerInternal.java @@ -101,9 +101,11 @@ public abstract class StorageManagerInternal { * Delete storage sandbox for the given package. * * @param packageName The package for which the sandbox needs to be destroyed. + * @param sharedUserId The sharedUserId if specified by the package. * @param userId The userId in which the sandbox needs to be destroyed. */ - public abstract void destroySandboxForApp(@NonNull String packageName, int userId); + public abstract void destroySandboxForApp(@NonNull String packageName, + @Nullable String sharedUserId, int userId); /** * @return Labels of storage volumes that are visible to the given userId. diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 858dcedd03cc..5643a6a66251 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -112,7 +112,6 @@ import android.util.TimeUtils; import android.util.Xml; import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.AppFuseMount; import com.android.internal.os.BackgroundThread; import com.android.internal.os.FuseUnavailableMountException; @@ -323,12 +322,6 @@ class StorageManagerService extends IStorageManager.Stub @GuardedBy("mPackagesLock") private final SparseArray<ArraySet<String>> mPackages = new SparseArray<>(); - @GuardedBy("mPackagesLock") - private final ArrayMap<String, Integer> mAppIds = new ArrayMap<>(); - - @GuardedBy("mPackagesLock") - private final SparseArray<String> mSandboxIds = new SparseArray<>(); - /** * List of volumes visible to any user. * TODO: may be have a map of userId -> volumes? @@ -876,13 +869,12 @@ class StorageManagerService extends IStorageManager.Stub try { mVold.reset(); - pushPackagesInfo(); // Tell vold about all existing and started users for (UserInfo user : users) { mVold.onUserAdded(user.id, user.serialNumber); } for (int userId : systemUnlockedUsers) { - mVold.onUserStarted(userId, getPackagesArrayForUser(userId)); + sendUserStartedCallback(userId); mStoraged.onUserStarted(userId); } mVold.onSecureKeyguardStateChanged(mSecureKeyguardShowing); @@ -899,7 +891,7 @@ class StorageManagerService extends IStorageManager.Stub // staging area is ready so it's ready for zygote-forked apps to // bind mount against. try { - mVold.onUserStarted(userId, getPackagesArrayForUser(userId)); + sendUserStartedCallback(userId); mStoraged.onUserStarted(userId); } catch (Exception e) { Slog.wtf(TAG, e); @@ -932,11 +924,52 @@ class StorageManagerService extends IStorageManager.Stub Slog.wtf(TAG, e); } + synchronized (mPackagesLock) { + mPackages.delete(userId); + } + synchronized (mLock) { mSystemUnlockedUsers = ArrayUtils.removeInt(mSystemUnlockedUsers, userId); } } + private void sendUserStartedCallback(int userId) throws Exception { + if (!ENABLE_ISOLATED_STORAGE) { + mVold.onUserStarted(userId, EmptyArray.STRING, EmptyArray.INT, EmptyArray.STRING); + } + + final String[] packages; + final int[] appIds; + final String[] sandboxIds; + final SparseArray<String> sharedUserIds = mPmInternal.getAppsWithSharedUserIds(); + final List<ApplicationInfo> appInfos = + mContext.getPackageManager().getInstalledApplicationsAsUser( + PackageManager.MATCH_UNINSTALLED_PACKAGES, userId); + synchronized (mPackagesLock) { + final ArraySet<String> userPackages = new ArraySet<>(); + final ArrayMap<String, Integer> packageToAppId = new ArrayMap<>(); + for (int i = appInfos.size() - 1; i >= 0; --i) { + final ApplicationInfo appInfo = appInfos.get(i); + if (appInfo.isInstantApp()) { + continue; + } + userPackages.add(appInfo.packageName); + packageToAppId.put(appInfo.packageName, UserHandle.getAppId(appInfo.uid)); + } + mPackages.put(userId, userPackages); + + packages = new String[userPackages.size()]; + appIds = new int[userPackages.size()]; + sandboxIds = new String[userPackages.size()]; + for (int i = userPackages.size() - 1; i >= 0; --i) { + packages[i] = userPackages.valueAt(i); + appIds[i] = packageToAppId.get(packages[i]); + sandboxIds[i] = getSandboxId(packages[i], sharedUserIds.get(appIds[i])); + } + } + mVold.onUserStarted(userId, packages, appIds, sandboxIds); + } + @Override public void onAwakeStateChanged(boolean isAwake) { // Ignored @@ -1454,111 +1487,12 @@ class StorageManagerService extends IStorageManager.Stub } private void start() { - collectPackagesInfo(); connect(); } - @VisibleForTesting - void collectPackagesInfo() { - if (!ENABLE_ISOLATED_STORAGE) return; - - resetPackageData(); - final SparseArray<String> sharedUserIds = mPmInternal.getAppsWithSharedUserIds(); - final int[] userIds = mUmInternal.getUserIds(); - for (int userId : userIds) { - final List<ApplicationInfo> appInfos - = mContext.getPackageManager().getInstalledApplicationsAsUser( - PackageManager.MATCH_UNINSTALLED_PACKAGES, userId); - synchronized (mPackagesLock) { - final ArraySet<String> userPackages = getAvailablePackagesForUserPL(userId); - for (int i = appInfos.size() - 1; i >= 0; --i) { - if (appInfos.get(i).isInstantApp()) { - continue; - } - final String packageName = appInfos.get(i).packageName; - userPackages.add(packageName); - - final int appId = UserHandle.getAppId(appInfos.get(i).uid); - mAppIds.put(packageName, appId); - mSandboxIds.put(appId, getSandboxId(packageName, sharedUserIds.get(appId))); - } - } - } - } - - private void resetPackageData() { - synchronized (mPackagesLock) { - mPackages.clear(); - mAppIds.clear(); - mSandboxIds.clear(); - } - } - private static String getSandboxId(String packageName, String sharedUserId) { return sharedUserId == null ? packageName : SHARED_SANDBOX_ID_PREFIX + sharedUserId; } - private void pushPackagesInfo() throws RemoteException { - if (!ENABLE_ISOLATED_STORAGE) return; - - // Arrays to fill up from {@link #mAppIds} - final String[] allPackageNames; - final int[] appIdsForPackages; - - // Arrays to fill up from {@link #mSandboxIds} - final int[] allAppIds; - final String[] sandboxIdsForApps; - synchronized (mPackagesLock) { - allPackageNames = new String[mAppIds.size()]; - appIdsForPackages = new int[mAppIds.size()]; - for (int i = mAppIds.size() - 1; i >= 0; --i) { - allPackageNames[i] = mAppIds.keyAt(i); - appIdsForPackages[i] = mAppIds.valueAt(i); - } - - allAppIds = new int[mSandboxIds.size()]; - sandboxIdsForApps = new String[mSandboxIds.size()]; - for (int i = mSandboxIds.size() - 1; i >= 0; --i) { - allAppIds[i] = mSandboxIds.keyAt(i); - sandboxIdsForApps[i] = mSandboxIds.valueAt(i); - } - } - mVold.addAppIds(allPackageNames, appIdsForPackages); - mVold.addSandboxIds(allAppIds, sandboxIdsForApps); - } - - @GuardedBy("mPackagesLock") - private ArraySet<String> getAvailablePackagesForUserPL(int userId) { - ArraySet<String> userPackages = mPackages.get(userId); - if (userPackages == null) { - userPackages = new ArraySet<>(); - mPackages.put(userId, userPackages); - } - return userPackages; - } - - private String[] getPackagesArrayForUser(int userId) { - if (!ENABLE_ISOLATED_STORAGE) return EmptyArray.STRING; - - final ArraySet<String> userPackages; - synchronized (mPackagesLock) { - userPackages = getAvailablePackagesForUserPL(userId); - if (!userPackages.isEmpty()) { - return userPackages.toArray(new String[0]); - } - } - final List<ApplicationInfo> appInfos = - mContext.getPackageManager().getInstalledApplicationsAsUser( - PackageManager.MATCH_UNINSTALLED_PACKAGES, userId); - synchronized (mPackagesLock) { - for (int i = appInfos.size() - 1; i >= 0; --i) { - if (appInfos.get(i).isInstantApp()) { - continue; - } - userPackages.add(appInfos.get(i).packageName); - } - return userPackages.toArray(new String[0]); - } - } private void connect() { IBinder binder = ServiceManager.getService("storaged"); @@ -3122,15 +3056,8 @@ class StorageManagerService extends IStorageManager.Stub throw new SecurityException("Shady looking path " + path); } - final int uid = mPmInternal.getPackageUid(packageName, - PackageManager.MATCH_UNINSTALLED_PACKAGES, userId); - final String sandboxId; - synchronized (mPackagesLock) { - sandboxId = mSandboxIds.get(UserHandle.getAppId(uid)); - } - if (uid < 0 || sandboxId == null) { - throw new IllegalArgumentException("Unknown package " + packageName); - } + final String sharedUserId = mPmInternal.getSharedUserIdForPackage(packageName); + final String sandboxId = getSandboxId(packageName, sharedUserId); final Matcher m = PATTERN_TRANSLATE.matcher(path); if (m.matches()) { @@ -3139,7 +3066,9 @@ class StorageManagerService extends IStorageManager.Stub // Does path belong to any packages belonging to this UID? If so, // they get to go straight through to legacy paths. - final String[] pkgs = mContext.getPackageManager().getPackagesForUid(uid); + final String[] pkgs = (sharedUserId == null) + ? new String[] {packageName} + : mPmInternal.getPackagesForSharedUserId(sharedUserId, userId); for (String pkg : pkgs) { if (devicePath.startsWith("Android/data/" + pkg + "/") || devicePath.startsWith("Android/media/" + pkg + "/") || @@ -3758,16 +3687,14 @@ class StorageManagerService extends IStorageManager.Stub int userId) { final String sandboxId; synchronized (mPackagesLock) { - final ArraySet<String> userPackages = getAvailablePackagesForUserPL(userId); + final ArraySet<String> userPackages = mPackages.get(userId); // If userPackages is empty, it means the user is not started yet, so no need to // do anything now. - if (userPackages.isEmpty() || userPackages.contains(packageName)) { + if (userPackages == null || userPackages.contains(packageName)) { return; } userPackages.add(packageName); - mAppIds.put(packageName, appId); sandboxId = getSandboxId(packageName, sharedUserId); - mSandboxIds.put(appId, sandboxId); } try { @@ -3778,34 +3705,21 @@ class StorageManagerService extends IStorageManager.Stub } @Override - public void destroySandboxForApp(String packageName, int userId) { + public void destroySandboxForApp(String packageName, String sharedUserId, int userId) { if (!ENABLE_ISOLATED_STORAGE) { return; } - final int appId; - final String sandboxId; + final String sandboxId = getSandboxId(packageName, sharedUserId); synchronized (mPackagesLock) { - final ArraySet<String> userPackages = getAvailablePackagesForUserPL(userId); - userPackages.remove(packageName); - appId = mAppIds.get(packageName); - sandboxId = mSandboxIds.get(appId); - - // If the package is not uninstalled in any other users, remove appId and sandboxId - // corresponding to it from the internal state. - boolean installedInAnyUser = false; - for (int i = mPackages.size() - 1; i >= 0; --i) { - if (mPackages.valueAt(i).contains(packageName)) { - installedInAnyUser = true; - break; - } - } - if (!installedInAnyUser) { - mAppIds.remove(packageName); - mSandboxIds.remove(appId); + final ArraySet<String> userPackages = mPackages.get(userId); + // If the userPackages is null, it means the user is not started but we still + // need to delete the sandbox data though. + if (userPackages != null) { + userPackages.remove(packageName); } } try { - mVold.destroySandboxForApp(packageName, appId, sandboxId, userId); + mVold.destroySandboxForApp(packageName, sandboxId, userId); } catch (Exception e) { Slog.wtf(TAG, e); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 9399ebf5b413..48cb51c35bb6 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -322,6 +322,7 @@ import dalvik.system.CloseGuard; import dalvik.system.VMRuntime; import libcore.io.IoUtils; +import libcore.util.EmptyArray; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -9540,7 +9541,8 @@ public class PackageManagerService extends IPackageManager.Stub } } if (deleteSandboxData && getStorageManagerInternal() != null) { - getStorageManagerInternal().destroySandboxForApp(pkg.packageName, realUserId); + getStorageManagerInternal().destroySandboxForApp(pkg.packageName, + pkg.mSharedUserId, realUserId); } } catch (PackageManagerException e) { // Should not happen @@ -22941,6 +22943,20 @@ public class PackageManagerService extends IPackageManager.Stub } @Override + public String getSharedUserIdForPackage(String packageName) { + synchronized (mPackages) { + return getSharedUserIdForPackageLocked(packageName); + } + } + + @Override + public String[] getPackagesForSharedUserId(String sharedUserId, int userId) { + synchronized (mPackages) { + return getPackagesForSharedUserIdLocked(sharedUserId, userId); + } + } + + @Override public boolean isOnlyCoreApps() { return PackageManagerService.this.isOnlyCoreApps(); } @@ -22952,6 +22968,7 @@ public class PackageManagerService extends IPackageManager.Stub } } + @GuardedBy("mPackages") private SparseArray<String> getAppsWithSharedUserIdsLocked() { final SparseArray<String> sharedUserIds = new SparseArray<>(); synchronized (mPackages) { @@ -22962,6 +22979,38 @@ public class PackageManagerService extends IPackageManager.Stub return sharedUserIds; } + @GuardedBy("mPackages") + private String getSharedUserIdForPackageLocked(String packageName) { + final PackageSetting ps = mSettings.mPackages.get(packageName); + return (ps != null && ps.isSharedUser()) ? ps.sharedUser.name : null; + } + + @GuardedBy("mPackages") + private String[] getPackagesForSharedUserIdLocked(String sharedUserId, int userId) { + try { + final SharedUserSetting sus = mSettings.getSharedUserLPw( + sharedUserId, 0, 0, false); + if (sus == null) { + return EmptyArray.STRING; + } + String[] res = new String[sus.packages.size()]; + final Iterator<PackageSetting> it = sus.packages.iterator(); + int i = 0; + while (it.hasNext()) { + PackageSetting ps = it.next(); + if (ps.getInstalled(userId)) { + res[i++] = ps.name; + } else { + res = ArrayUtils.removeElement(String.class, res, res[i]); + } + } + return res; + } catch (PackageManagerException e) { + // Should not happen + } + return EmptyArray.STRING; + } + @Override public void grantDefaultPermissionsToEnabledCarrierApps(String[] packageNames, int userId) { enforceSystemOrPhoneCaller("grantPermissionsToEnabledCarrierApps"); diff --git a/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java index 802253280614..e53518cca21f 100644 --- a/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java @@ -30,7 +30,6 @@ import android.os.UserManagerInternal; import android.os.storage.StorageManagerInternal; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; -import android.util.SparseArray; import org.junit.Before; import org.junit.Test; @@ -38,9 +37,6 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import java.util.ArrayList; -import java.util.List; - @SmallTest @RunWith(AndroidJUnit4.class) public class StorageManagerServiceTest { @@ -83,29 +79,14 @@ public class StorageManagerServiceTest { when(mUmi.getUserIds()).thenReturn(new int[] { 0 }); - { - final SparseArray<String> res = new SparseArray<>(); - res.put(UID_COLORS, NAME_COLORS); - when(mPmi.getAppsWithSharedUserIds()).thenReturn(res); - } - - { - final List<ApplicationInfo> res = new ArrayList<>(); - res.add(buildApplicationInfo(PKG_GREY, UID_GREY)); - res.add(buildApplicationInfo(PKG_RED, UID_COLORS)); - res.add(buildApplicationInfo(PKG_BLUE, UID_COLORS)); - when(mPm.getInstalledApplicationsAsUser(anyInt(), anyInt())).thenReturn(res); - } - - when(mPmi.getPackageUid(eq(PKG_GREY), anyInt(), anyInt())).thenReturn(UID_GREY); - when(mPmi.getPackageUid(eq(PKG_RED), anyInt(), anyInt())).thenReturn(UID_COLORS); - when(mPmi.getPackageUid(eq(PKG_BLUE), anyInt(), anyInt())).thenReturn(UID_COLORS); + when(mPmi.getSharedUserIdForPackage(eq(PKG_GREY))).thenReturn(null); + when(mPmi.getSharedUserIdForPackage(eq(PKG_RED))).thenReturn(NAME_COLORS); + when(mPmi.getSharedUserIdForPackage(eq(PKG_BLUE))).thenReturn(NAME_COLORS); - when(mPm.getPackagesForUid(eq(UID_GREY))).thenReturn(new String[] { PKG_GREY }); - when(mPm.getPackagesForUid(eq(UID_COLORS))).thenReturn(new String[] { PKG_RED, PKG_BLUE }); + when(mPmi.getPackagesForSharedUserId(eq(NAME_COLORS), anyInt())) + .thenReturn(new String[] { PKG_RED, PKG_BLUE }); mService = new StorageManagerService(mContext); - mService.collectPackagesInfo(); } @Test |