diff options
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) { |