Allocate isolated UID ranges for app zygote and its children.
Introduce a new range of app-zygote isolated UIDs, [90000..98999].
For each app that uses an application Zygote, allocate a range of
100 isolated UIDs. The application Zygote for an app will get a
UID out of that range, and all other children that are forked
from that zygote will get a UID from the same range.
Bug: 111434506
Test: app Zygote and its children run in the new range of
isolated UIDs (with SELinux disabled). New set of
tests for UID allocators pass.
Change-Id: I7a6883a5ddb95683932c93ea77f4e52d8f37fa4f
diff --git a/core/java/android/os/AppZygote.java b/core/java/android/os/AppZygote.java
index 2275693..40cbaf7 100644
--- a/core/java/android/os/AppZygote.java
+++ b/core/java/android/os/AppZygote.java
@@ -34,6 +34,8 @@
public class AppZygote {
private static final String LOG_TAG = "AppZygote";
+ private final int mZygoteUid;
+
private final Object mLock = new Object();
/**
@@ -45,8 +47,9 @@
private final ApplicationInfo mAppInfo;
- public AppZygote(ApplicationInfo appInfo) {
+ public AppZygote(ApplicationInfo appInfo, int zygoteUid) {
mAppInfo = appInfo;
+ mZygoteUid = zygoteUid;
}
/**
@@ -94,8 +97,8 @@
mZygote = Process.zygoteProcess.startChildZygote(
"com.android.internal.os.AppZygoteInit",
mAppInfo.processName + "_zygote",
- mAppInfo.uid,
- mAppInfo.uid,
+ mZygoteUid,
+ mZygoteUid,
null, // gids
0, // runtimeFlags
"app_zygote", // seInfo
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 938b23c..ee56e3d 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -205,6 +205,24 @@
public static final int LAST_APPLICATION_UID = 19999;
/**
+ * First uid used for fully isolated sandboxed processes spawned from an app zygote
+ * @hide
+ */
+ public static final int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000;
+
+ /**
+ * Number of UIDs we allocate per application zygote
+ * @hide
+ */
+ public static final int NUM_UIDS_PER_APP_ZYGOTE = 100;
+
+ /**
+ * Last uid used for fully isolated sandboxed processes spawned from an app zygote
+ * @hide
+ */
+ public static final int LAST_APP_ZYGOTE_ISOLATED_UID = 98999;
+
+ /**
* First uid used for fully isolated sandboxed processes (with no permissions of their own)
* @hide
*/
@@ -650,7 +668,8 @@
/** {@hide} */
public static final boolean isIsolated(int uid) {
uid = UserHandle.getAppId(uid);
- return uid >= FIRST_ISOLATED_UID && uid <= LAST_ISOLATED_UID;
+ return (uid >= FIRST_ISOLATED_UID && uid <= LAST_ISOLATED_UID)
+ || (uid >= FIRST_APP_ZYGOTE_ISOLATED_UID && uid <= LAST_APP_ZYGOTE_ISOLATED_UID);
}
/**
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index f8feb7b..ad8a4d5 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -138,8 +138,7 @@
*/
public static boolean isIsolated(int uid) {
if (uid > 0) {
- final int appId = getAppId(uid);
- return appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID;
+ return Process.isIsolated(uid);
} else {
return false;
}
@@ -294,9 +293,14 @@
sb.append('u');
sb.append(getUserId(uid));
final int appId = getAppId(uid);
- if (appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID) {
- sb.append('i');
- sb.append(appId - Process.FIRST_ISOLATED_UID);
+ if (isIsolated(appId)) {
+ if (appId > Process.FIRST_ISOLATED_UID) {
+ sb.append('i');
+ sb.append(appId - Process.FIRST_ISOLATED_UID);
+ } else {
+ sb.append("ai");
+ sb.append(appId - Process.FIRST_APP_ZYGOTE_ISOLATED_UID);
+ }
} else if (appId >= Process.FIRST_APPLICATION_UID) {
sb.append('a');
sb.append(appId - Process.FIRST_APPLICATION_UID);
@@ -330,9 +334,14 @@
pw.print('u');
pw.print(getUserId(uid));
final int appId = getAppId(uid);
- if (appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID) {
- pw.print('i');
- pw.print(appId - Process.FIRST_ISOLATED_UID);
+ if (isIsolated(appId)) {
+ if (appId > Process.FIRST_ISOLATED_UID) {
+ pw.print('i');
+ pw.print(appId - Process.FIRST_ISOLATED_UID);
+ } else {
+ pw.print("ai");
+ pw.print(appId - Process.FIRST_APP_ZYGOTE_ISOLATED_UID);
+ }
} else if (appId >= Process.FIRST_APPLICATION_UID) {
pw.print('a');
pw.print(appId - Process.FIRST_APPLICATION_UID);
diff --git a/core/java/com/android/internal/os/WebViewZygoteInit.java b/core/java/com/android/internal/os/WebViewZygoteInit.java
index 2c8e66d..0b329d7 100644
--- a/core/java/com/android/internal/os/WebViewZygoteInit.java
+++ b/core/java/com/android/internal/os/WebViewZygoteInit.java
@@ -121,7 +121,6 @@
public static void main(String argv[]) {
Log.i(TAG, "Starting WebViewZygoteInit");
-
WebViewZygoteServer server = new WebViewZygoteServer();
ChildZygoteInit.runZygoteServer(server, argv);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e171736..bc21610 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1943,7 +1943,8 @@
synchronized (this) {
ProcessRecord app = mProcessList.newProcessRecordLocked(info, info.processName,
false,
- 0);
+ 0,
+ false);
app.setPersistent(true);
app.pid = MY_PID;
app.getWindowProcessController().setPid(MY_PID);
@@ -7407,7 +7408,7 @@
}
if (app == null) {
- app = mProcessList.newProcessRecordLocked(info, customProcess, isolated, 0);
+ app = mProcessList.newProcessRecordLocked(info, customProcess, isolated, 0, false);
mProcessList.updateLruProcessLocked(app, false, null);
updateOomAdjLocked();
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 896452b..9898d06 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -19,8 +19,6 @@
import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
import static android.app.ActivityThread.PROC_START_SEQ_IDENT;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AUTO;
-import static android.os.Process.FIRST_ISOLATED_UID;
-import static android.os.Process.LAST_ISOLATED_UID;
import static android.os.Process.SYSTEM_UID;
import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
import static android.os.Process.getFreeMemory;
@@ -83,6 +81,7 @@
import android.util.LongSparseArray;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.StatsLog;
import android.view.Display;
@@ -112,6 +111,7 @@
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.BitSet;
import java.util.List;
/**
@@ -368,11 +368,126 @@
final ArrayMap<AppZygote, ArrayList<ProcessRecord>> mAppZygoteProcesses =
new ArrayMap<AppZygote, ArrayList<ProcessRecord>>();
+ final class IsolatedUidRange {
+ @VisibleForTesting
+ public final int mFirstUid;
+ @VisibleForTesting
+ public final int mLastUid;
+
+ @GuardedBy("ProcessList.this.mService")
+ private final SparseBooleanArray mUidUsed = new SparseBooleanArray();
+
+ @GuardedBy("ProcessList.this.mService")
+ private int mNextUid;
+
+ IsolatedUidRange(int firstUid, int lastUid) {
+ mFirstUid = firstUid;
+ mLastUid = lastUid;
+ mNextUid = firstUid;
+ }
+
+ @GuardedBy("ProcessList.this.mService")
+ int allocateIsolatedUidLocked(int userId) {
+ int uid;
+ int stepsLeft = (mLastUid - mFirstUid + 1);
+ for (int i = 0; i < stepsLeft; ++i) {
+ if (mNextUid < mFirstUid || mNextUid > mLastUid) {
+ mNextUid = mFirstUid;
+ }
+ uid = UserHandle.getUid(userId, mNextUid);
+ mNextUid++;
+ if (!mUidUsed.get(uid, false)) {
+ mUidUsed.put(uid, true);
+ return uid;
+ }
+ }
+ return -1;
+ }
+
+ @GuardedBy("ProcessList.this.mService")
+ void freeIsolatedUidLocked(int uid) {
+ // Strip out userId
+ final int appId = UserHandle.getAppId(uid);
+ mUidUsed.delete(appId);
+ }
+ };
+
/**
- * Counter for assigning isolated process uids, to avoid frequently reusing the
- * same ones.
+ * A class that allocates ranges of isolated UIDs per application, and keeps track of them.
*/
- int mNextIsolatedProcessUid = 0;
+ final class IsolatedUidRangeAllocator {
+ private final int mFirstUid;
+ private final int mNumUidRanges;
+ private final int mNumUidsPerRange;
+ /**
+ * We map the uid range [mFirstUid, mFirstUid + mNumUidRanges * mNumUidsPerRange)
+ * back to an underlying bitset of [0, mNumUidRanges) and allocate out of that.
+ */
+ @GuardedBy("ProcessList.this.mService")
+ private final BitSet mAvailableUidRanges;
+ @GuardedBy("ProcessList.this.mService")
+ private final ProcessMap<IsolatedUidRange> mAppRanges = new ProcessMap<IsolatedUidRange>();
+
+ IsolatedUidRangeAllocator(int firstUid, int lastUid, int numUidsPerRange) {
+ mFirstUid = firstUid;
+ mNumUidsPerRange = numUidsPerRange;
+ mNumUidRanges = (lastUid - firstUid + 1) / numUidsPerRange;
+ mAvailableUidRanges = new BitSet(mNumUidRanges);
+ // Mark all as available
+ mAvailableUidRanges.set(0, mNumUidRanges);
+ }
+
+ @GuardedBy("ProcessList.this.mService")
+ IsolatedUidRange getIsolatedUidRangeLocked(ApplicationInfo info) {
+ return mAppRanges.get(info.processName, info.uid);
+ }
+
+ @GuardedBy("ProcessList.this.mService")
+ IsolatedUidRange getOrCreateIsolatedUidRangeLocked(ApplicationInfo info) {
+ IsolatedUidRange range = getIsolatedUidRangeLocked(info);
+ if (range == null) {
+ int uidRangeIndex = mAvailableUidRanges.nextSetBit(0);
+ if (uidRangeIndex < 0) {
+ // No free range
+ return null;
+ }
+ mAvailableUidRanges.clear(uidRangeIndex);
+ int actualUid = mFirstUid + uidRangeIndex * mNumUidsPerRange;
+ range = new IsolatedUidRange(actualUid, actualUid + mNumUidsPerRange - 1);
+ mAppRanges.put(info.processName, info.uid, range);
+ }
+ return range;
+ }
+
+ @GuardedBy("ProcessList.this.mService")
+ void freeUidRangeLocked(ApplicationInfo info) {
+ // Find the UID range
+ IsolatedUidRange range = mAppRanges.get(info.processName, info.uid);
+ if (range != null) {
+ // Map back to starting uid
+ final int uidRangeIndex = (range.mFirstUid - mFirstUid) / mNumUidsPerRange;
+ // Mark it as available in the underlying bitset
+ mAvailableUidRanges.set(uidRangeIndex);
+ // And the map
+ mAppRanges.remove(info.processName, info.uid);
+ }
+ }
+ }
+
+ /**
+ * The available isolated UIDs for processes that are not spawned from an application zygote.
+ */
+ @VisibleForTesting
+ IsolatedUidRange mGlobalIsolatedUids = new IsolatedUidRange(Process.FIRST_ISOLATED_UID,
+ Process.LAST_ISOLATED_UID);
+
+ /**
+ * An allocator for isolated UID ranges for apps that use an application zygote.
+ */
+ @VisibleForTesting
+ IsolatedUidRangeAllocator mAppIsolatedUidRangeAllocator =
+ new IsolatedUidRangeAllocator(Process.FIRST_APP_ZYGOTE_ISOLATED_UID,
+ Process.LAST_APP_ZYGOTE_ISOLATED_UID, Process.NUM_UIDS_PER_APP_ZYGOTE);
/**
* Processes that are being forcibly torn down.
@@ -1527,12 +1642,20 @@
if (zygoteProcesses.size() == 0) { // Only remove if no longer in use now
mAppZygotes.remove(appInfo.processName, appInfo.uid);
mAppZygoteProcesses.remove(appZygote);
+ mAppIsolatedUidRangeAllocator.freeUidRangeLocked(appInfo);
appZygote.stopZygote();
}
}
@GuardedBy("mService")
private void removeProcessFromAppZygoteLocked(final ProcessRecord app) {
+ // Free the isolated uid for this process
+ final IsolatedUidRange appUidRange =
+ mAppIsolatedUidRangeAllocator.getIsolatedUidRangeLocked(app.info);
+ if (appUidRange != null) {
+ appUidRange.freeIsolatedUidLocked(app.uid);
+ }
+
final AppZygote appZygote = mAppZygotes.get(app.info.processName, app.info.uid);
if (appZygote != null) {
ArrayList<ProcessRecord> zygoteProcesses = mAppZygoteProcesses.get(appZygote);
@@ -1550,7 +1673,12 @@
AppZygote appZygote = mAppZygotes.get(app.info.processName, app.info.uid);
final ArrayList<ProcessRecord> zygoteProcessList;
if (appZygote == null) {
- appZygote = new AppZygote(app.info);
+ final int userId = UserHandle.getUserId(app.info.uid);
+ final IsolatedUidRange uidRange =
+ mAppIsolatedUidRangeAllocator.getIsolatedUidRangeLocked(app.info);
+ // Allocate an isolated UID out of this range for the Zygote itself
+ final int zygoteIsolatedUid = uidRange.allocateIsolatedUidLocked(userId);
+ appZygote = new AppZygote(app.info, zygoteIsolatedUid);
mAppZygotes.put(app.info.processName, app.info.uid, appZygote);
zygoteProcessList = new ArrayList<ProcessRecord>();
mAppZygoteProcesses.put(appZygote, zygoteProcessList);
@@ -1701,8 +1829,9 @@
? hostingName.flattenToShortString() : null;
if (app == null) {
+ final boolean fromAppZygote = "app_zygote".equals(hostingType);
checkSlow(startTime, "startProcess: creating new process record");
- app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
+ app = newProcessRecordLocked(info, processName, isolated, isolatedUid, fromAppZygote);
if (app == null) {
Slog.w(TAG, "Failed making new process record for "
+ processName + "/" + info.uid + " isolated=" + isolated);
@@ -2075,29 +2204,31 @@
}
@GuardedBy("mService")
+ private IsolatedUidRange getOrCreateIsolatedUidRangeLocked(ApplicationInfo info,
+ boolean fromAppZygote) {
+ if (!fromAppZygote) {
+ // Allocate an isolated UID from the global range
+ return mGlobalIsolatedUids;
+ } else {
+ return mAppIsolatedUidRangeAllocator.getOrCreateIsolatedUidRangeLocked(info);
+ }
+ }
+
+ @GuardedBy("mService")
final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
- boolean isolated, int isolatedUid) {
+ boolean isolated, int isolatedUid, boolean fromAppZygote) {
String proc = customProcess != null ? customProcess : info.processName;
final int userId = UserHandle.getUserId(info.uid);
int uid = info.uid;
if (isolated) {
if (isolatedUid == 0) {
- int stepsLeft = LAST_ISOLATED_UID - FIRST_ISOLATED_UID + 1;
- while (true) {
- if (mNextIsolatedProcessUid < FIRST_ISOLATED_UID
- || mNextIsolatedProcessUid > LAST_ISOLATED_UID) {
- mNextIsolatedProcessUid = FIRST_ISOLATED_UID;
- }
- uid = UserHandle.getUid(userId, mNextIsolatedProcessUid);
- mNextIsolatedProcessUid++;
- if (mIsolatedProcesses.indexOfKey(uid) < 0) {
- // No process for this uid, use it.
- break;
- }
- stepsLeft--;
- if (stepsLeft <= 0) {
- return null;
- }
+ IsolatedUidRange uidRange = getOrCreateIsolatedUidRangeLocked(info, fromAppZygote);
+ if (uidRange == null) {
+ return null;
+ }
+ uid = uidRange.allocateIsolatedUidLocked(userId);
+ if (uid == -1) {
+ return null;
}
} else {
// Special case for startIsolatedProcess (internal only), where
@@ -2165,9 +2296,10 @@
old.uidRecord = null;
}
mIsolatedProcesses.remove(uid);
+ mGlobalIsolatedUids.freeIsolatedUidLocked(uid);
// Remove the (expected) ProcessRecord from the app zygote
final ProcessRecord record = expecting != null ? expecting : old;
- if (record != null && record.isolated) {
+ if (record != null && record.appZygote) {
removeProcessFromAppZygoteLocked(record);
}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 6f0a562..0d0824a 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -76,6 +76,7 @@
private final ActivityManagerService mService; // where we came from
final ApplicationInfo info; // all about the first app in the process
final boolean isolated; // true if this is a special isolated process
+ final boolean appZygote; // true if this is forked from the app zygote
final int uid; // uid of process; may be different from 'info' if isolated
final int userId; // user of process.
final String processName; // name of the process
@@ -559,6 +560,8 @@
mService = _service;
info = _info;
isolated = _info.uid != _uid;
+ appZygote = (UserHandle.getAppId(_uid) >= Process.FIRST_APP_ZYGOTE_ISOLATED_UID
+ && UserHandle.getAppId(_uid) <= Process.LAST_APP_ZYGOTE_ISOLATED_UID);
uid = _uid;
userId = UserHandle.getUserId(_uid);
processName = _processName;
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index ea0e095..6a10ff4 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -71,6 +71,8 @@
import androidx.test.filters.SmallTest;
import com.android.server.AppOpsService;
+import com.android.server.am.ProcessList.IsolatedUidRange;
+import com.android.server.am.ProcessList.IsolatedUidRangeAllocator;
import com.android.server.wm.ActivityTaskManagerService;
import org.junit.After;
@@ -294,6 +296,113 @@
}
}
+ private void validateAppZygoteIsolatedUidRange(IsolatedUidRange uidRange) {
+ assertNotNull(uidRange);
+ assertTrue(uidRange.mFirstUid >= Process.FIRST_APP_ZYGOTE_ISOLATED_UID
+ && uidRange.mFirstUid <= Process.LAST_APP_ZYGOTE_ISOLATED_UID);
+ assertTrue(uidRange.mLastUid >= Process.FIRST_APP_ZYGOTE_ISOLATED_UID
+ && uidRange.mLastUid <= Process.LAST_APP_ZYGOTE_ISOLATED_UID);
+ assertTrue(uidRange.mLastUid > uidRange.mFirstUid
+ && ((uidRange.mLastUid - uidRange.mFirstUid + 1)
+ == Process.NUM_UIDS_PER_APP_ZYGOTE));
+ }
+
+ private void verifyUidRangesNoOverlap(IsolatedUidRange uidRange1, IsolatedUidRange uidRange2) {
+ IsolatedUidRange lowRange = uidRange1.mFirstUid <= uidRange2.mFirstUid ? uidRange1 : uidRange2;
+ IsolatedUidRange highRange = lowRange == uidRange1 ? uidRange2 : uidRange1;
+
+ assertTrue(highRange.mFirstUid > lowRange.mLastUid);
+ }
+
+ @Test
+ public void testIsolatedUidRangeAllocator() {
+ final IsolatedUidRangeAllocator allocator = mAms.mProcessList.mAppIsolatedUidRangeAllocator;
+
+ // Create initial range
+ ApplicationInfo appInfo = new ApplicationInfo();
+ appInfo.processName = "com.android.test.app";
+ appInfo.uid = 10000;
+ final IsolatedUidRange range = allocator.getOrCreateIsolatedUidRangeLocked(appInfo);
+ validateAppZygoteIsolatedUidRange(range);
+ verifyIsolatedUidAllocator(range);
+
+ // Create a second range
+ ApplicationInfo appInfo2 = new ApplicationInfo();
+ appInfo2.processName = "com.android.test.app2";
+ appInfo2.uid = 10001;
+ IsolatedUidRange range2 = allocator.getOrCreateIsolatedUidRangeLocked(appInfo2);
+ validateAppZygoteIsolatedUidRange(range2);
+ verifyIsolatedUidAllocator(range2);
+
+ // Verify ranges don't overlap
+ verifyUidRangesNoOverlap(range, range2);
+
+ // Free range, reallocate and verify
+ allocator.freeUidRangeLocked(appInfo2);
+ range2 = allocator.getOrCreateIsolatedUidRangeLocked(appInfo2);
+ validateAppZygoteIsolatedUidRange(range2);
+ verifyUidRangesNoOverlap(range, range2);
+ verifyIsolatedUidAllocator(range2);
+
+ // Free both, then try to allocate the maximum number of UID ranges
+ allocator.freeUidRangeLocked(appInfo);
+ allocator.freeUidRangeLocked(appInfo2);
+
+ int maxNumUidRanges = (Process.LAST_APP_ZYGOTE_ISOLATED_UID
+ - Process.FIRST_APP_ZYGOTE_ISOLATED_UID + 1) / Process.NUM_UIDS_PER_APP_ZYGOTE;
+ for (int i = 0; i < maxNumUidRanges; i++) {
+ appInfo = new ApplicationInfo();
+ appInfo.uid = 10000 + i;
+ appInfo.processName = "com.android.test.app" + Integer.toString(i);
+ IsolatedUidRange uidRange = allocator.getOrCreateIsolatedUidRangeLocked(appInfo);
+ validateAppZygoteIsolatedUidRange(uidRange);
+ verifyIsolatedUidAllocator(uidRange);
+ }
+
+ // Try to allocate another one and make sure it fails
+ appInfo = new ApplicationInfo();
+ appInfo.uid = 9000;
+ appInfo.processName = "com.android.test.app.failed";
+ IsolatedUidRange failedRange = allocator.getOrCreateIsolatedUidRangeLocked(appInfo);
+
+ assertNull(failedRange);
+ }
+
+ public void verifyIsolatedUid(ProcessList.IsolatedUidRange range, int uid) {
+ assertTrue(uid >= range.mFirstUid && uid <= range.mLastUid);
+ }
+
+ public void verifyIsolatedUidAllocator(ProcessList.IsolatedUidRange range) {
+ int uid = range.allocateIsolatedUidLocked(0);
+ verifyIsolatedUid(range, uid);
+
+ int uid2 = range.allocateIsolatedUidLocked(0);
+ verifyIsolatedUid(range, uid2);
+ assertTrue(uid2 != uid);
+
+ // Free both
+ range.freeIsolatedUidLocked(uid);
+ range.freeIsolatedUidLocked(uid2);
+
+ // Allocate the entire range
+ for (int i = 0; i < (range.mLastUid - range.mFirstUid + 1); ++i) {
+ uid = range.allocateIsolatedUidLocked(0);
+ verifyIsolatedUid(range, uid);
+ }
+
+ // Ensure the next one fails
+ uid = range.allocateIsolatedUidLocked(0);
+ assertEquals(uid, -1);
+ }
+
+ @Test
+ public void testGlobalIsolatedUidAllocator() {
+ final IsolatedUidRange globalUidRange = mAms.mProcessList.mGlobalIsolatedUids;
+ assertEquals(globalUidRange.mFirstUid, Process.FIRST_ISOLATED_UID);
+ assertEquals(globalUidRange.mLastUid, Process.LAST_ISOLATED_UID);
+ verifyIsolatedUidAllocator(globalUidRange);
+ }
+
@Test
public void testBlockStateForUid() {
final UidRecord uidRec = new UidRecord(TEST_UID, null /* atmInternal */);