summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/pm/AppIdSettingMap.java62
-rw-r--r--services/core/java/com/android/server/pm/Settings.java94
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java55
3 files changed, 145 insertions, 66 deletions
diff --git a/services/core/java/com/android/server/pm/AppIdSettingMap.java b/services/core/java/com/android/server/pm/AppIdSettingMap.java
new file mode 100644
index 000000000000..bbef237507bf
--- /dev/null
+++ b/services/core/java/com/android/server/pm/AppIdSettingMap.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.os.Process;
+
+import com.android.server.utils.WatchedSparseArray;
+
+/**
+ * A wrapper over {@link WatchedSparseArray} that tracks the current maximum App ID.
+ */
+public class AppIdSettingMap extends WatchedSparseArray<SettingBase> {
+ private int mCurrentMaxAppId;
+
+ @Override
+ public void put(int key, SettingBase value) {
+ if (key > mCurrentMaxAppId) {
+ mCurrentMaxAppId = key;
+ }
+ super.put(key, value);
+ }
+
+ @Override
+ public AppIdSettingMap snapshot() {
+ AppIdSettingMap l = new AppIdSettingMap();
+ snapshot(l, this);
+ 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;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 021c3db35756..6ccaae148ce6 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -40,7 +40,6 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
-import android.content.pm.ComponentInfo;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
@@ -113,11 +112,9 @@ import com.android.server.pm.permission.LegacyPermissionState.PermissionState;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.PackageUserState;
import com.android.server.pm.pkg.PackageUserStateInternal;
-import com.android.server.pm.pkg.PackageUserStateUtils;
import com.android.server.pm.pkg.SuspendParams;
import com.android.server.pm.pkg.component.ParsedComponent;
import com.android.server.pm.pkg.component.ParsedIntentInfo;
-import com.android.server.pm.pkg.component.ParsedMainComponent;
import com.android.server.pm.pkg.component.ParsedPermission;
import com.android.server.pm.pkg.component.ParsedProcess;
import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
@@ -476,9 +473,9 @@ public final class Settings implements Watchable, Snappable {
@Watched
final WatchedArrayMap<String, SharedUserSetting> mSharedUsers = new WatchedArrayMap<>();
@Watched
- private final WatchedArrayList<SettingBase> mAppIds;
+ private final AppIdSettingMap mAppIds;
@Watched
- private final WatchedSparseArray<SettingBase> mOtherAppIds;
+ private final AppIdSettingMap mOtherAppIds;
// For reading/writing settings file.
@Watched
@@ -594,8 +591,8 @@ public final class Settings implements Watchable, Snappable {
mLock = new PackageManagerTracedLock();
mPackages.putAll(pkgSettings);
- mAppIds = new WatchedArrayList<>();
- mOtherAppIds = new WatchedSparseArray<>();
+ mAppIds = new AppIdSettingMap();
+ mOtherAppIds = new AppIdSettingMap();
mSystemDir = null;
mPermissions = null;
mRuntimePermissionsPersistence = null;
@@ -631,8 +628,8 @@ public final class Settings implements Watchable, Snappable {
mKeySetManagerService = new KeySetManagerService(mPackages);
mLock = lock;
- mAppIds = new WatchedArrayList<>();
- mOtherAppIds = new WatchedSparseArray<>();
+ mAppIds = new AppIdSettingMap();
+ mOtherAppIds = new AppIdSettingMap();
mPermissions = new LegacyPermissionSettings(lock);
mRuntimePermissionsPersistence = new RuntimePermissionPersistence(
runtimePermissionsPersistence, new Consumer<Integer>() {
@@ -1278,7 +1275,8 @@ public final class Settings implements Watchable, Snappable {
// Utility method that adds a PackageSetting to mPackages and
// completes updating the shared user attributes and any restored
// app link verification state
- private void addPackageSettingLPw(PackageSetting p, SharedUserSetting sharedUser) {
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ void addPackageSettingLPw(PackageSetting p, SharedUserSetting sharedUser) {
mPackages.put(p.getPackageName(), p);
if (sharedUser != null) {
SharedUserSetting existingSharedUserSetting = getSharedUserSettingLPr(p);
@@ -1301,7 +1299,7 @@ public final class Settings implements Watchable, Snappable {
p.setAppId(sharedUser.mAppId);
}
- // If the we know about this user id, we have to update it as it
+ // If we know about this user id, we have to update it as it
// has to point to the same PackageSetting instance as the package.
Object userIdPs = getSettingLPr(p.getAppId());
if (sharedUser == null) {
@@ -1366,20 +1364,13 @@ public final class Settings implements Watchable, Snappable {
}
if (appId >= Process.FIRST_APPLICATION_UID) {
- int size = mAppIds.size();
- final int index = appId - Process.FIRST_APPLICATION_UID;
- // fill the array until our index becomes valid
- while (index >= size) {
- mAppIds.add(null);
- size++;
- }
- if (mAppIds.get(index) != null) {
+ if (mAppIds.get(appId) != null) {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Adding duplicate app id: " + appId
+ " name=" + name);
return false;
}
- mAppIds.set(index, obj);
+ mAppIds.put(appId, obj);
} else {
if (mOtherAppIds.get(appId) != null) {
PackageManagerService.reportSettingsProblem(Log.WARN,
@@ -1395,9 +1386,7 @@ public final class Settings implements Watchable, Snappable {
/** Gets the setting associated with the provided App ID */
public SettingBase getSettingLPr(int appId) {
if (appId >= Process.FIRST_APPLICATION_UID) {
- final int size = mAppIds.size();
- final int index = appId - Process.FIRST_APPLICATION_UID;
- return index < size ? mAppIds.get(index) : null;
+ return mAppIds.get(appId);
} else {
return mOtherAppIds.get(appId);
}
@@ -1406,9 +1395,7 @@ public final class Settings implements Watchable, Snappable {
/** Unregisters the provided app ID. */
void removeAppIdLPw(int appId) {
if (appId >= Process.FIRST_APPLICATION_UID) {
- final int size = mAppIds.size();
- final int index = appId - Process.FIRST_APPLICATION_UID;
- if (index < size) mAppIds.set(index, null);
+ mAppIds.remove(appId);
} else {
mOtherAppIds.remove(appId);
}
@@ -1417,9 +1404,14 @@ public final class Settings implements Watchable, Snappable {
private void replaceAppIdLPw(int appId, SettingBase obj) {
if (appId >= Process.FIRST_APPLICATION_UID) {
- final int size = mAppIds.size();
- final int index = appId - Process.FIRST_APPLICATION_UID;
- if (index < size) mAppIds.set(index, obj);
+ 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);
}
@@ -4304,22 +4296,21 @@ public final class Settings implements Watchable, Snappable {
/** Returns a new AppID or -1 if we could not find an available AppID to assign */
private int acquireAndRegisterNewAppIdLPw(SettingBase obj) {
- // Let's be stupidly inefficient for now...
- final int size = mAppIds.size();
- for (int i = mFirstAvailableUid - Process.FIRST_APPLICATION_UID; i < size; i++) {
- if (mAppIds.get(i) == null) {
- mAppIds.set(i, obj);
- return Process.FIRST_APPLICATION_UID + i;
+ 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 (size > (Process.LAST_APPLICATION_UID - Process.FIRST_APPLICATION_UID)) {
+ if (nextAvailableAppId > Process.LAST_APPLICATION_UID) {
return -1;
}
- mAppIds.add(obj);
- return Process.FIRST_APPLICATION_UID + size;
+ mAppIds.put(nextAvailableAppId, obj);
+ return nextAvailableAppId;
}
public VerifierDeviceIdentity getVerifierDeviceIdentityLPw(@NonNull Computer computer) {
@@ -4354,33 +4345,6 @@ public final class Settings implements Watchable, Snappable {
return getDisabledSystemPkgLPr(enabledPackageSetting.getPackageName());
}
- boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, long flags, int userId) {
- final PackageSetting ps = mPackages.get(componentInfo.packageName);
- if (ps == null) return false;
-
- final PackageUserStateInternal userState = ps.readUserState(userId);
- return PackageUserStateUtils.isMatch(userState, componentInfo, flags);
- }
-
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- public boolean isEnabledAndMatchLPr(AndroidPackage pkg, ParsedMainComponent component,
- long flags, int userId) {
- final PackageSetting ps = mPackages.get(component.getPackageName());
- if (ps == null) return false;
-
- final PackageUserStateInternal userState = ps.readUserState(userId);
- return PackageUserStateUtils.isMatch(userState, pkg.isSystem(), pkg.isEnabled(), component,
- flags);
- }
-
- boolean isOrphaned(String packageName) {
- final PackageSetting pkg = mPackages.get(packageName);
- if (pkg == null) {
- throw new IllegalArgumentException("Unknown package: " + packageName);
- }
- return pkg.getInstallSource().isOrphaned;
- }
-
int getApplicationEnabledSettingLPr(String packageName, int userId)
throws PackageManager.NameNotFoundException {
final PackageSetting pkg = mPackages.get(packageName);
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 2b34bc2ef28d..f4ab3db3c917 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -31,11 +31,11 @@ import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
@@ -1103,6 +1103,59 @@ public class PackageManagerSettingsTests {
assertThat(countDownLatch.getCount(), is(0L));
}
+ @Test
+ public void testRegisterAndRemoveAppId() throws PackageManagerException {
+ // Test that the first new app UID should start from FIRST_APPLICATION_UID
+ final Settings settings = makeSettings();
+ final PackageSetting ps = createPackageSetting("com.foo");
+ assertTrue(settings.registerAppIdLPw(ps, false));
+ assertEquals(10000, ps.getAppId());
+ // Set up existing app IDs: 10000, 10001, 10003
+ final PackageSetting ps1 = createPackageSetting("com.foo1");
+ ps1.setAppId(10001);
+ final PackageSetting ps2 = createPackageSetting("com.foo2");
+ ps2.setAppId(10003);
+ final PackageSetting ps3 = createPackageSetting("com.foo3");
+ assertEquals(0, ps3.getAppId());
+ assertTrue(settings.registerAppIdLPw(ps1, false));
+ assertTrue(settings.registerAppIdLPw(ps2, false));
+ assertTrue(settings.registerAppIdLPw(ps3, false));
+ assertEquals(10001, ps1.getAppId());
+ assertEquals(10003, ps2.getAppId());
+ // Expecting the new one to start with the next available uid
+ assertEquals(10002, ps3.getAppId());
+ // Remove and insert a new one and the new one should not reuse the same uid
+ settings.removeAppIdLPw(10002);
+ final PackageSetting ps4 = createPackageSetting("com.foo4");
+ assertTrue(settings.registerAppIdLPw(ps4, false));
+ assertEquals(10004, ps4.getAppId());
+ // Keep adding more
+ final PackageSetting ps5 = createPackageSetting("com.foo5");
+ assertTrue(settings.registerAppIdLPw(ps5, false));
+ assertEquals(10005, ps5.getAppId());
+ // Remove the last one and the new one should use incremented uid
+ settings.removeAppIdLPw(10005);
+ final PackageSetting ps6 = createPackageSetting("com.foo6");
+ assertTrue(settings.registerAppIdLPw(ps6, false));
+ assertEquals(10006, ps6.getAppId());
+ }
+
+ /**
+ * Test replacing a PackageSetting with a SharedUserSetting in mAppIds
+ */
+ @Test
+ public void testAddPackageSetting() throws PackageManagerException {
+ final Settings settings = makeSettings();
+ final SharedUserSetting sus1 = new SharedUserSetting(
+ "TestUser", 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/);
+ sus1.mAppId = 10001;
+ final PackageSetting ps1 = createPackageSetting("com.foo");
+ ps1.setAppId(10001);
+ assertTrue(settings.registerAppIdLPw(ps1, false));
+ settings.addPackageSettingLPw(ps1, sus1);
+ assertSame(sus1, settings.getSharedUserSettingLPr(ps1));
+ }
+
private void verifyUserState(PackageUserState userState,
boolean notLaunched, boolean stopped, boolean installed) {
assertThat(userState.getEnabledState(), is(0));