diff --git a/services/core/java/com/android/server/pm/AppIdSettingMap.java b/services/core/java/com/android/server/pm/AppIdSettingMap.java index bbef237507bfd..b41a0b8878e0a 100644 --- a/services/core/java/com/android/server/pm/AppIdSettingMap.java +++ b/services/core/java/com/android/server/pm/AppIdSettingMap.java @@ -17,46 +17,131 @@ package com.android.server.pm; import android.os.Process; +import android.util.Log; +import com.android.server.utils.WatchedArrayList; import com.android.server.utils.WatchedSparseArray; +import com.android.server.utils.Watcher; /** - * A wrapper over {@link WatchedSparseArray} that tracks the current maximum App ID. + * A wrapper over {@link WatchedArrayList} that tracks the current (app ID -> SettingBase) mapping + * for non-system apps. Also tracks system app settings in an {@link WatchedSparseArray}. */ -public class AppIdSettingMap extends WatchedSparseArray { - private int mCurrentMaxAppId; +final class AppIdSettingMap { + /** + * We use an ArrayList instead of an SparseArray for non system apps because the number of apps + * might be big, and only ArrayList gives us a constant lookup time. For a given app ID, the + * index to the corresponding SettingBase object is (appId - FIRST_APPLICATION_ID). If an app ID + * doesn't exist (i.e., app is not installed), we fill the corresponding entry with null. + */ + private WatchedArrayList mNonSystemSettings = new WatchedArrayList<>(); + private WatchedSparseArray mSystemSettings = new WatchedSparseArray<>(); + private int mFirstAvailableAppId = Process.FIRST_APPLICATION_UID; - @Override - public void put(int key, SettingBase value) { - if (key > mCurrentMaxAppId) { - mCurrentMaxAppId = key; + /** Returns true if the requested AppID was valid and not already registered. */ + public boolean registerExistingAppId(int appId, SettingBase setting, Object name) { + if (appId >= Process.FIRST_APPLICATION_UID) { + int size = mNonSystemSettings.size(); + final int index = appId - Process.FIRST_APPLICATION_UID; + // fill the array until our index becomes valid + while (index >= size) { + mNonSystemSettings.add(null); + size++; + } + if (mNonSystemSettings.get(index) != null) { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Adding duplicate app id: " + appId + + " name=" + name); + return false; + } + mNonSystemSettings.set(index, setting); + } else { + if (mSystemSettings.get(appId) != null) { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Adding duplicate shared id: " + appId + + " name=" + name); + return false; + } + mSystemSettings.put(appId, setting); } - super.put(key, value); + return true; + } + + public SettingBase getSetting(int appId) { + if (appId >= Process.FIRST_APPLICATION_UID) { + final int size = mNonSystemSettings.size(); + final int index = appId - Process.FIRST_APPLICATION_UID; + return index < size ? mNonSystemSettings.get(index) : null; + } else { + return mSystemSettings.get(appId); + } + } + + public void removeSetting(int appId) { + if (appId >= Process.FIRST_APPLICATION_UID) { + final int size = mNonSystemSettings.size(); + final int index = appId - Process.FIRST_APPLICATION_UID; + if (index < size) { + mNonSystemSettings.set(index, null); + } + } else { + mSystemSettings.remove(appId); + } + setFirstAvailableAppId(appId + 1); + } + + // This should be called (at least) whenever an application is removed + private void setFirstAvailableAppId(int uid) { + if (uid > mFirstAvailableAppId) { + mFirstAvailableAppId = uid; + } + } + + public void replaceSetting(int appId, SettingBase setting) { + if (appId >= Process.FIRST_APPLICATION_UID) { + final int size = mNonSystemSettings.size(); + final int index = appId - Process.FIRST_APPLICATION_UID; + if (index < size) { + mNonSystemSettings.set(index, setting); + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: calling replaceAppIdLpw to" + + " replace SettingBase at appId=" + appId + + " but nothing is replaced."); + } + } else { + mSystemSettings.put(appId, setting); + } + } + + /** Returns a new AppID or -1 if we could not find an available AppID to assign */ + public int acquireAndRegisterNewAppId(SettingBase obj) { + final int size = mNonSystemSettings.size(); + for (int i = mFirstAvailableAppId - Process.FIRST_APPLICATION_UID; i < size; i++) { + if (mNonSystemSettings.get(i) == null) { + mNonSystemSettings.set(i, obj); + return Process.FIRST_APPLICATION_UID + i; + } + } + + // None left? + if (size > (Process.LAST_APPLICATION_UID - Process.FIRST_APPLICATION_UID)) { + return -1; + } + + mNonSystemSettings.add(obj); + return Process.FIRST_APPLICATION_UID + size; } - @Override public AppIdSettingMap snapshot() { AppIdSettingMap l = new AppIdSettingMap(); - snapshot(l, this); + mNonSystemSettings.snapshot(l.mNonSystemSettings, mNonSystemSettings); + mSystemSettings.snapshot(l.mSystemSettings, mSystemSettings); return l; } - /** - * @return the maximum of all the App IDs that have been added to the map. 0 if map is empty. - */ - public int getCurrentMaxAppId() { - return mCurrentMaxAppId; - } - - /** - * @return the next available App ID that has not been added to the map - */ - public int getNextAvailableAppId() { - if (mCurrentMaxAppId == 0) { - // No app id has been added yet - return Process.FIRST_APPLICATION_UID; - } else { - return mCurrentMaxAppId + 1; - } + public void registerObserver(Watcher observer) { + mNonSystemSettings.registerObserver(observer); + mSystemSettings.registerObserver(observer); } } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 6ccaae148ce6e..698dbe945e6fc 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -62,7 +62,6 @@ import android.os.Handler; import android.os.Message; import android.os.PatternMatcher; import android.os.PersistableBundle; -import android.os.Process; import android.os.SELinux; import android.os.SystemClock; import android.os.Trace; @@ -408,8 +407,6 @@ public final class Settings implements Watchable, Snappable { int[] excludedUserIds; } - private static int mFirstAvailableUid = Process.FIRST_APPLICATION_UID; - /** Map from volume UUID to {@link VersionInfo} */ @Watched private final WatchedArrayMap mVersion = new WatchedArrayMap<>(); @@ -472,10 +469,8 @@ public final class Settings implements Watchable, Snappable { @Watched final WatchedArrayMap mSharedUsers = new WatchedArrayMap<>(); - @Watched + @Watched(manual = true) private final AppIdSettingMap mAppIds; - @Watched - private final AppIdSettingMap mOtherAppIds; // For reading/writing settings file. @Watched @@ -565,7 +560,6 @@ public final class Settings implements Watchable, Snappable { mCrossProfileIntentResolvers.registerObserver(mObserver); mSharedUsers.registerObserver(mObserver); mAppIds.registerObserver(mObserver); - mOtherAppIds.registerObserver(mObserver); mRenamedPackages.registerObserver(mObserver); mNextAppLinkGeneration.registerObserver(mObserver); mDefaultBrowserApp.registerObserver(mObserver); @@ -592,7 +586,6 @@ public final class Settings implements Watchable, Snappable { mLock = new PackageManagerTracedLock(); mPackages.putAll(pkgSettings); mAppIds = new AppIdSettingMap(); - mOtherAppIds = new AppIdSettingMap(); mSystemDir = null; mPermissions = null; mRuntimePermissionsPersistence = null; @@ -629,7 +622,6 @@ public final class Settings implements Watchable, Snappable { mLock = lock; mAppIds = new AppIdSettingMap(); - mOtherAppIds = new AppIdSettingMap(); mPermissions = new LegacyPermissionSettings(lock); mRuntimePermissionsPersistence = new RuntimePermissionPersistence( runtimePermissionsPersistence, new Consumer() { @@ -710,7 +702,6 @@ public final class Settings implements Watchable, Snappable { mCrossProfileIntentResolvers, r.mCrossProfileIntentResolvers); mSharedUsers.snapshot(r.mSharedUsers); mAppIds = r.mAppIds.snapshot(); - mOtherAppIds = r.mOtherAppIds.snapshot(); WatchedArrayList.snapshot( mPastSignatures, r.mPastSignatures); WatchedArrayMap.snapshot( @@ -782,7 +773,7 @@ public final class Settings implements Watchable, Snappable { SharedUserSetting s = mSharedUsers.get(name); if (s == null && create) { s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags); - s.mAppId = acquireAndRegisterNewAppIdLPw(s); + s.mAppId = mAppIds.acquireAndRegisterNewAppId(s); if (s.mAppId < 0) { // < 0 means we couldn't assign a userid; throw exception throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE, @@ -890,7 +881,7 @@ public final class Settings implements Watchable, Snappable { pkgPrivateFlags, 0 /*userId*/, usesSdkLibraries, usesSdkLibrariesVersions, usesStaticLibraries, usesStaticLibrariesVersions, mimeGroups, domainSetId); p.setAppId(uid); - if (registerExistingAppIdLPw(uid, p, name)) { + if (mAppIds.registerExistingAppId(uid, p, name)) { mPackages.put(name, p); return p; } @@ -909,7 +900,7 @@ public final class Settings implements Watchable, Snappable { } s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags); s.mAppId = uid; - if (registerExistingAppIdLPw(uid, s, name)) { + if (mAppIds.registerExistingAppId(uid, s, name)) { mSharedUsers.put(name, s); return s; } @@ -1210,11 +1201,11 @@ public final class Settings implements Watchable, Snappable { final boolean createdNew; if (p.getAppId() == 0 || forceNew) { // Assign new user ID - p.setAppId(acquireAndRegisterNewAppIdLPw(p)); + p.setAppId(mAppIds.acquireAndRegisterNewAppId(p)); createdNew = true; } else { // Add new setting to list of user IDs - createdNew = registerExistingAppIdLPw(p.getAppId(), p, p.getPackageName()); + createdNew = mAppIds.registerExistingAppId(p.getAppId(), p, p.getPackageName()); } if (p.getAppId() < 0) { PackageManagerService.reportSettingsProblem(Log.WARN, @@ -1304,11 +1295,11 @@ public final class Settings implements Watchable, Snappable { Object userIdPs = getSettingLPr(p.getAppId()); if (sharedUser == null) { if (userIdPs != null && userIdPs != p) { - replaceAppIdLPw(p.getAppId(), p); + mAppIds.replaceSetting(p.getAppId(), p); } } else { if (userIdPs != null && userIdPs != sharedUser) { - replaceAppIdLPw(p.getAppId(), sharedUser); + mAppIds.replaceSetting(p.getAppId(), sharedUser); } } } @@ -1357,73 +1348,22 @@ public final class Settings implements Watchable, Snappable { mInstallerPackages.remove(packageName); } - /** Returns true if the requested AppID was valid and not already registered. */ - private boolean registerExistingAppIdLPw(int appId, SettingBase obj, Object name) { - if (appId > Process.LAST_APPLICATION_UID) { - return false; - } - - if (appId >= Process.FIRST_APPLICATION_UID) { - if (mAppIds.get(appId) != null) { - PackageManagerService.reportSettingsProblem(Log.WARN, - "Adding duplicate app id: " + appId - + " name=" + name); - return false; - } - mAppIds.put(appId, obj); - } else { - if (mOtherAppIds.get(appId) != null) { - PackageManagerService.reportSettingsProblem(Log.WARN, - "Adding duplicate shared id: " + appId - + " name=" + name); - return false; - } - mOtherAppIds.put(appId, obj); - } - return true; - } - /** Gets the setting associated with the provided App ID */ public SettingBase getSettingLPr(int appId) { - if (appId >= Process.FIRST_APPLICATION_UID) { - return mAppIds.get(appId); - } else { - return mOtherAppIds.get(appId); - } + return mAppIds.getSetting(appId); } /** Unregisters the provided app ID. */ void removeAppIdLPw(int appId) { - if (appId >= Process.FIRST_APPLICATION_UID) { - mAppIds.remove(appId); - } else { - mOtherAppIds.remove(appId); - } - setFirstAvailableUid(appId + 1); + mAppIds.removeSetting(appId); } - - private void replaceAppIdLPw(int appId, SettingBase obj) { - if (appId >= Process.FIRST_APPLICATION_UID) { - if (appId <= mAppIds.getCurrentMaxAppId()) { - mAppIds.put(appId, obj); - } else { - PackageManagerService.reportSettingsProblem(Log.WARN, - "Error in package manager settings: calling replaceAppIdLpw to" - + " replace SettingBase at appId=" + appId - + " but nothing is replaced."); - } - } else { - mOtherAppIds.put(appId, obj); - } - } - /** * Transparently convert a SharedUserSetting into PackageSettings without changing appId. * The sharedUser passed to this method has to be {@link SharedUserSetting#isSingleUser()}. */ void convertSharedUserSettingsLPw(SharedUserSetting sharedUser) { final PackageSetting ps = sharedUser.getPackageSettings().valueAt(0); - replaceAppIdLPw(sharedUser.getAppId(), ps); + mAppIds.replaceSetting(sharedUser.getAppId(), ps); // Unlink the SharedUserSetting ps.setSharedUserAppId(INVALID_UID); @@ -4287,32 +4227,6 @@ public final class Settings implements Watchable, Snappable { } } - // This should be called (at least) whenever an application is removed - private void setFirstAvailableUid(int uid) { - if (uid > mFirstAvailableUid) { - mFirstAvailableUid = uid; - } - } - - /** Returns a new AppID or -1 if we could not find an available AppID to assign */ - private int acquireAndRegisterNewAppIdLPw(SettingBase obj) { - final int nextAvailableAppId = mAppIds.getNextAvailableAppId(); - for (int uid = mFirstAvailableUid; uid < nextAvailableAppId; uid++) { - if (mAppIds.get(uid) == null) { - mAppIds.put(uid, obj); - return uid; - } - } - - // None left? - if (nextAvailableAppId > Process.LAST_APPLICATION_UID) { - return -1; - } - - mAppIds.put(nextAvailableAppId, obj); - return nextAvailableAppId; - } - public VerifierDeviceIdentity getVerifierDeviceIdentityLPw(@NonNull Computer computer) { if (mVerifierDeviceIdentity == null) { mVerifierDeviceIdentity = VerifierDeviceIdentity.generate();