summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java1
-rw-r--r--services/core/java/com/android/server/am/UidObserverController.java68
-rw-r--r--services/core/java/com/android/server/am/UidRecord.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java18
-rw-r--r--services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java62
5 files changed, 95 insertions, 58 deletions
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f0c9845424c6..79a660a48540 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -14872,6 +14872,7 @@ public class ActivityManagerService extends IActivityManager.Stub
change |= UidRecord.CHANGE_IDLE;
}
final int enqueuedChange = mUidObserverController.enqueueUidChange(
+ uidRec == null ? null : uidRec.pendingChange,
uid, change, procState, procStateSeq, capability, ephemeral);
if (uidRec != null) {
uidRec.lastReportedChange = enqueuedChange;
diff --git a/services/core/java/com/android/server/am/UidObserverController.java b/services/core/java/com/android/server/am/UidObserverController.java
index b3488c3850b5..b3150d1489bb 100644
--- a/services/core/java/com/android/server/am/UidObserverController.java
+++ b/services/core/java/com/android/server/am/UidObserverController.java
@@ -20,6 +20,8 @@ import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
import static com.android.server.am.ActivityManagerService.TAG_UID_OBSERVERS;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerProto;
import android.app.IUidObserver;
@@ -29,7 +31,6 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.Slog;
-import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.proto.ProtoOutputStream;
import android.util.proto.ProtoUtils;
@@ -53,7 +54,7 @@ public class UidObserverController {
final RemoteCallbackList<IUidObserver> mUidObservers = new RemoteCallbackList<>();
@GuardedBy("mLock")
- private final SparseArray<ChangeRecord> mPendingUidChanges = new SparseArray<>();
+ private final ArrayList<ChangeRecord> mPendingUidChanges = new ArrayList<>();
@GuardedBy("mLock")
private final ArrayList<ChangeRecord> mAvailUidChanges = new ArrayList<>();
@@ -71,27 +72,27 @@ public class UidObserverController {
private static final boolean VALIDATE_UID_STATES = true;
private final ActiveUids mValidateUids;
- UidObserverController(Handler handler) {
+ UidObserverController(@NonNull Handler handler) {
mHandler = handler;
mValidateUids = new ActiveUids(null /* service */, false /* postChangesToAtm */);
}
- void register(IUidObserver observer, int which, int cutpoint, String callingPackage,
- int callingUid) {
+ void register(@NonNull IUidObserver observer, int which, int cutpoint,
+ @NonNull String callingPackage, int callingUid) {
synchronized (mLock) {
mUidObservers.register(observer, new UidObserverRegistration(callingUid,
callingPackage, which, cutpoint));
}
}
- void unregister(IUidObserver observer) {
+ void unregister(@NonNull IUidObserver observer) {
synchronized (mLock) {
mUidObservers.unregister(observer);
}
}
- int enqueueUidChange(int uid, int change, int procState, long procStateSeq,
- int capability, boolean ephemeral) {
+ int enqueueUidChange(@Nullable ChangeRecord currentRecord, int uid, int change, int procState,
+ long procStateSeq, int capability, boolean ephemeral) {
synchronized (mLock) {
if (mPendingUidChanges.size() == 0) {
if (DEBUG_UID_OBSERVERS) {
@@ -100,10 +101,11 @@ public class UidObserverController {
mHandler.post(mDispatchRunnable);
}
- ChangeRecord changeRecord = mPendingUidChanges.get(uid);
- if (changeRecord == null) {
- changeRecord = getOrCreateChangeRecordLocked();
- mPendingUidChanges.put(uid, changeRecord);
+ final ChangeRecord changeRecord = currentRecord != null
+ ? currentRecord : getOrCreateChangeRecordLocked();
+ if (!changeRecord.isPending) {
+ changeRecord.isPending = true;
+ mPendingUidChanges.add(changeRecord);
} else {
change = mergeWithPendingChange(change, changeRecord.change);
}
@@ -119,7 +121,7 @@ public class UidObserverController {
}
}
- SparseArray<ChangeRecord> getPendingUidChangesForTest() {
+ ArrayList<ChangeRecord> getPendingUidChangesForTest() {
return mPendingUidChanges;
}
@@ -175,7 +177,10 @@ public class UidObserverController {
mActiveUidChanges = new ChangeRecord[numUidChanges];
}
for (int i = 0; i < numUidChanges; i++) {
- mActiveUidChanges[i] = mPendingUidChanges.valueAt(i);
+ final ChangeRecord changeRecord = mPendingUidChanges.get(i);
+ mActiveUidChanges[i] = getOrCreateChangeRecordLocked();
+ changeRecord.copyTo(mActiveUidChanges[i]);
+ changeRecord.isPending = false;
}
mPendingUidChanges.clear();
if (DEBUG_UID_OBSERVERS) {
@@ -216,13 +221,15 @@ public class UidObserverController {
synchronized (mLock) {
for (int j = 0; j < numUidChanges; j++) {
- mAvailUidChanges.add(mActiveUidChanges[j]);
+ final ChangeRecord changeRecord = mActiveUidChanges[j];
+ changeRecord.isPending = false;
+ mAvailUidChanges.add(changeRecord);
}
}
}
- private void dispatchUidsChangedForObserver(IUidObserver observer,
- UidObserverRegistration reg, int changesSize) {
+ private void dispatchUidsChangedForObserver(@NonNull IUidObserver observer,
+ @NonNull UidObserverRegistration reg, int changesSize) {
if (observer == null) {
return;
}
@@ -318,7 +325,7 @@ public class UidObserverController {
return mValidateUids.get(uid);
}
- void dump(PrintWriter pw, String dumpPackage) {
+ void dump(@NonNull PrintWriter pw, @Nullable String dumpPackage) {
synchronized (mLock) {
final int count = mUidObservers.getRegisteredCallbackCount();
boolean printed = false;
@@ -353,7 +360,7 @@ public class UidObserverController {
}
}
- void dumpDebug(ProtoOutputStream proto, String dumpPackage) {
+ void dumpDebug(@NonNull ProtoOutputStream proto, @Nullable String dumpPackage) {
synchronized (mLock) {
final int count = mUidObservers.getRegisteredCallbackCount();
for (int i = 0; i < count; i++) {
@@ -366,23 +373,34 @@ public class UidObserverController {
}
}
- boolean dumpValidateUids(PrintWriter pw, String dumpPackage, int dumpAppId,
- String header, boolean needSep) {
+ boolean dumpValidateUids(@NonNull PrintWriter pw, @Nullable String dumpPackage, int dumpAppId,
+ @NonNull String header, boolean needSep) {
return mValidateUids.dump(pw, dumpPackage, dumpAppId, header, needSep);
}
- void dumpValidateUidsProto(ProtoOutputStream proto, String dumpPackage,
+ void dumpValidateUidsProto(@NonNull ProtoOutputStream proto, @Nullable String dumpPackage,
int dumpAppId, long fieldId) {
mValidateUids.dumpProto(proto, dumpPackage, dumpAppId, fieldId);
}
static final class ChangeRecord {
+ public boolean isPending;
public int uid;
public int change;
public int procState;
public int capability;
public boolean ephemeral;
public long procStateSeq;
+
+ void copyTo(@NonNull ChangeRecord changeRecord) {
+ changeRecord.isPending = isPending;
+ changeRecord.uid = uid;
+ changeRecord.change = change;
+ changeRecord.procState = procState;
+ changeRecord.capability = capability;
+ changeRecord.ephemeral = ephemeral;
+ changeRecord.procStateSeq = procStateSeq;
+ }
}
private static final class UidObserverRegistration {
@@ -416,7 +434,7 @@ public class UidObserverController {
ActivityManagerProto.UID_OBSERVER_FLAG_PROCSTATE,
};
- UidObserverRegistration(int uid, String pkg, int which, int cutpoint) {
+ UidObserverRegistration(int uid, @NonNull String pkg, int which, int cutpoint) {
this.mUid = uid;
this.mPkg = pkg;
this.mWhich = which;
@@ -425,7 +443,7 @@ public class UidObserverController {
? new SparseIntArray() : null;
}
- void dump(PrintWriter pw, IUidObserver observer) {
+ void dump(@NonNull PrintWriter pw, @NonNull IUidObserver observer) {
pw.print(" ");
UserHandle.formatUid(pw, mUid);
pw.print(" ");
@@ -460,7 +478,7 @@ public class UidObserverController {
}
}
- void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ void dumpDebug(@NonNull ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
proto.write(UidObserverRegistrationProto.UID, mUid);
proto.write(UidObserverRegistrationProto.PACKAGE, mPkg);
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index dfd6149cfcb7..f1945ede7237 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -27,6 +27,7 @@ import android.util.proto.ProtoOutputStream;
import android.util.proto.ProtoUtils;
import com.android.internal.annotations.GuardedBy;
+import com.android.server.am.UidObserverController.ChangeRecord;
/**
* Overall information about a uid that has actively running processes.
@@ -107,6 +108,9 @@ public final class UidRecord {
UidRecordProto.CHANGE_UNCACHED,
};
+ // UidObserverController is the only thing that should modify this.
+ final ChangeRecord pendingChange = new ChangeRecord();
+
int lastReportedChange;
public UidRecord(int _uid) {
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 faf7169a68c7..241b5a9523b1 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -68,7 +68,6 @@ import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
-import android.util.SparseArray;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.MediumTest;
@@ -834,12 +833,13 @@ public class ActivityManagerServiceTest {
// Reset the current state
mHandler.reset();
clearPendingUidChanges();
+ uidRecord.pendingChange.isPending = false;
mAms.enqueueUidChangeLocked(uidRecord, -1, changeToDispatch);
// Verify that pendingChange is updated correctly.
- final ChangeRecord pendingChange = getPendingChange(uidRecord.uid);
- assertNotNull(pendingChange);
+ final ChangeRecord pendingChange = uidRecord.pendingChange;
+ assertTrue(pendingChange.isPending);
assertEquals(TEST_UID, pendingChange.uid);
assertEquals(expectedProcState, pendingChange.procState);
assertEquals(TEST_PROC_STATE_SEQ1, pendingChange.procStateSeq);
@@ -923,22 +923,16 @@ public class ActivityManagerServiceTest {
mAms.mProcessList.mActiveUids.clear();
}
- private ChangeRecord getPendingChange(int uid) {
- final SparseArray<ChangeRecord> pendingChanges =
- mAms.mUidObserverController.getPendingUidChangesForTest();
- return pendingChanges.get(uid);
- }
-
private void addPendingUidChange(ChangeRecord record) {
- mAms.mUidObserverController.getPendingUidChangesForTest().put(record.uid, record);
+ mAms.mUidObserverController.getPendingUidChangesForTest().add(record);
}
private void addPendingUidChanges(ArrayList<ChangeRecord> changes) {
- final SparseArray<ChangeRecord> pendingChanges =
+ final ArrayList<ChangeRecord> pendingChanges =
mAms.mUidObserverController.getPendingUidChangesForTest();
for (int i = 0; i < changes.size(); ++i) {
final ChangeRecord record = changes.get(i);
- pendingChanges.put(record.uid, record);
+ pendingChanges.add(record);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java
index 57c581ea132f..1de5f6f005d1 100644
--- a/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java
@@ -31,6 +31,7 @@ import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
@@ -51,6 +52,9 @@ import com.android.server.am.UidObserverController.ChangeRecord;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
@SmallTest
public class UidObserverControllerTest {
@@ -66,36 +70,41 @@ public class UidObserverControllerTest {
@Before
public void setUp() {
- mUidObserverController = new UidObserverController(Mockito.mock(Handler.class));
+ MockitoAnnotations.initMocks(this);
+ mUidObserverController = new UidObserverController(mock(Handler.class));
}
@Test
public void testEnqueueUidChange() {
- int change = mUidObserverController.enqueueUidChange(TEST_UID1, UidRecord.CHANGE_ACTIVE,
- PROCESS_STATE_FOREGROUND_SERVICE, PROCESS_CAPABILITY_ALL, 0, false);
+ int change = mUidObserverController.enqueueUidChange(null, TEST_UID1,
+ UidRecord.CHANGE_ACTIVE, PROCESS_STATE_FOREGROUND_SERVICE,
+ PROCESS_CAPABILITY_ALL, 0, false);
assertEquals("expected=ACTIVE,actual=" + changeToStr(change),
UidRecord.CHANGE_ACTIVE, change);
assertPendingChange(TEST_UID1, UidRecord.CHANGE_ACTIVE, PROCESS_STATE_FOREGROUND_SERVICE,
- PROCESS_CAPABILITY_ALL, 0, false);
- assertNull(getPendingChange(TEST_UID2));
-
- change = mUidObserverController.enqueueUidChange(TEST_UID2, UidRecord.CHANGE_CACHED,
- PROCESS_STATE_CACHED_RECENT, PROCESS_CAPABILITY_NONE, 99, true);
+ PROCESS_CAPABILITY_ALL, 0, false, null);
+ final ChangeRecord record1 = getLatestPendingChange(TEST_UID1);
+ assertNull(getLatestPendingChange(TEST_UID2));
+
+ final ChangeRecord record2 = new ChangeRecord();
+ change = mUidObserverController.enqueueUidChange(record2, TEST_UID2,
+ UidRecord.CHANGE_CACHED, PROCESS_STATE_CACHED_RECENT, PROCESS_CAPABILITY_NONE,
+ 99, true);
assertEquals("expected=ACTIVE,actual=" + changeToStr(change),
UidRecord.CHANGE_CACHED, change);
assertPendingChange(TEST_UID1, UidRecord.CHANGE_ACTIVE, PROCESS_STATE_FOREGROUND_SERVICE,
- PROCESS_CAPABILITY_ALL, 0, false);
+ PROCESS_CAPABILITY_ALL, 0, false, null);
assertPendingChange(TEST_UID2, UidRecord.CHANGE_CACHED, PROCESS_STATE_CACHED_RECENT,
- PROCESS_CAPABILITY_NONE, 99, true);
+ PROCESS_CAPABILITY_NONE, 99, true, record2);
- change = mUidObserverController.enqueueUidChange(TEST_UID1, UidRecord.CHANGE_UNCACHED,
- PROCESS_STATE_TOP, PROCESS_CAPABILITY_ALL, 0, false);
+ change = mUidObserverController.enqueueUidChange(record1, TEST_UID1,
+ UidRecord.CHANGE_UNCACHED, PROCESS_STATE_TOP, PROCESS_CAPABILITY_ALL, 0, false);
assertEquals("expected=ACTIVE|UNCACHED,actual=" + changeToStr(change),
UidRecord.CHANGE_ACTIVE | UidRecord.CHANGE_UNCACHED, change);
assertPendingChange(TEST_UID1, UidRecord.CHANGE_ACTIVE | UidRecord.CHANGE_UNCACHED,
- PROCESS_STATE_TOP, PROCESS_CAPABILITY_ALL, 0, false);
+ PROCESS_STATE_TOP, PROCESS_CAPABILITY_ALL, 0, false, record1);
assertPendingChange(TEST_UID2, UidRecord.CHANGE_CACHED, PROCESS_STATE_CACHED_RECENT,
- PROCESS_CAPABILITY_NONE, 99, true);
+ PROCESS_CAPABILITY_NONE, 99, true, record2);
}
@Test
@@ -135,11 +144,11 @@ public class UidObserverControllerTest {
addPendingChange(TEST_UID1, UidRecord.CHANGE_ACTIVE | UidRecord.CHANGE_PROCSTATE,
PROCESS_STATE_TOP, 0, PROCESS_CAPABILITY_ALL, false);
- final IUidObserver observer1 = Mockito.mock(IUidObserver.Stub.class);
+ final IUidObserver observer1 = mock(IUidObserver.Stub.class);
registerObserver(observer1,
ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_ACTIVE,
PROCESS_STATE_IMPORTANT_FOREGROUND, TEST_PKG2, TEST_UID2);
- final IUidObserver observer2 = Mockito.mock(IUidObserver.Stub.class);
+ final IUidObserver observer2 = mock(IUidObserver.Stub.class);
registerObserver(observer2, ActivityManager.UID_OBSERVER_PROCSTATE,
PROCESS_STATE_SERVICE, TEST_PKG3, TEST_UID3);
@@ -209,13 +218,16 @@ public class UidObserverControllerTest {
record.procStateSeq = procStateSeq;
record.capability = capability;
record.ephemeral = ephemeral;
- mUidObserverController.getPendingUidChangesForTest().put(uid, record);
+ mUidObserverController.getPendingUidChangesForTest().add(record);
}
private void assertPendingChange(int uid, int change, int procState, long procStateSeq,
- int capability, boolean ephemeral) {
- final ChangeRecord record = getPendingChange(uid);
+ int capability, boolean ephemeral, ChangeRecord expectedRecord) {
+ final ChangeRecord record = getLatestPendingChange(uid);
assertNotNull(record);
+ if (expectedRecord != null) {
+ assertEquals(expectedRecord, record);
+ }
assertEquals(change, record.change);
assertEquals(procState, record.procState);
assertEquals(procStateSeq, record.procStateSeq);
@@ -223,8 +235,16 @@ public class UidObserverControllerTest {
assertEquals(ephemeral, record.ephemeral);
}
- private ChangeRecord getPendingChange(int uid) {
- return mUidObserverController.getPendingUidChangesForTest().get(uid);
+ private ChangeRecord getLatestPendingChange(int uid) {
+ final ArrayList<ChangeRecord> changeRecords = mUidObserverController
+ .getPendingUidChangesForTest();
+ for (int i = changeRecords.size() - 1; i >= 0; --i) {
+ final ChangeRecord record = changeRecords.get(i);
+ if (record.uid == uid) {
+ return record;
+ }
+ }
+ return null;
}
private static String changeToStr(int change) {