From ce7fc422912918e6bbe933c47fb3729ec67f34ac Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Mon, 29 Mar 2021 09:11:47 -0700 Subject: [PATCH] Allow clients to register for listening to changes in capabilities. Clients can register for listening to changes in procstates and if they are only interested in knowing if the procstate crosses a certain threshold, they can specify a "cutpoint" and they will only get a callback if the procstate crosses that "cutpoint" but clients cannot use this if they are also interested in changes in capabilities. So, add a way for clients to use the "cutpoint" facility and also listen to changes in capabilities. Bug: 177641226 Test: atest services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java Test: atest services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java Test: atest ./tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java Change-Id: I1198e602ca81382975500b10f930dacfd16919e3 --- core/java/android/app/ActivityManager.java | 3 ++ core/proto/android/app/activitymanager.proto | 2 + .../server/activitymanagerservice.proto | 1 + .../com/android/server/am/OomAdjuster.java | 3 ++ .../server/am/UidObserverController.java | 34 +++++++++----- .../java/com/android/server/am/UidRecord.java | 3 ++ .../net/NetworkPolicyManagerService.java | 9 ++-- .../server/am/ActivityManagerServiceTest.java | 46 +++++++++++++------ .../server/am/UidObserverControllerTest.java | 15 +++++- 9 files changed, 87 insertions(+), 29 deletions(-) diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 36c66e5c34147..db42803ac9f9f 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -794,6 +794,9 @@ public class ActivityManager { /** @hide Flag for registerUidObserver: report uid cached state has changed. */ public static final int UID_OBSERVER_CACHED = 1<<4; + /** @hide Flag for registerUidObserver: report uid capability has changed. */ + public static final int UID_OBSERVER_CAPABILITY = 1<<5; + /** @hide Mode for {@link IActivityManager#isAppStartModeDisabled}: normal free-to-run operation. */ public static final int APP_START_MODE_NORMAL = 0; diff --git a/core/proto/android/app/activitymanager.proto b/core/proto/android/app/activitymanager.proto index ead7e1633c56b..a21d1d4f0a853 100644 --- a/core/proto/android/app/activitymanager.proto +++ b/core/proto/android/app/activitymanager.proto @@ -33,4 +33,6 @@ enum UidObserverFlag { UID_OBSERVER_FLAG_ACTIVE = 4; // report uid cached state has changed, original value is 1 << 4 UID_OBSERVER_FLAG_CACHED = 5; + // report uid capability has changed, original value is 1 << 5 + UID_OBSERVER_FLAG_CAPABILITY = 6; } diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto index 74a37cadc54c5..17dc4589d402b 100644 --- a/core/proto/android/server/activitymanagerservice.proto +++ b/core/proto/android/server/activitymanagerservice.proto @@ -778,6 +778,7 @@ message UidRecordProto { CHANGE_ACTIVE = 2; CHANGE_CACHED = 3; CHANGE_UNCACHED = 4; + CHANGE_CAPABILITY = 5; } repeated Change last_reported_changes = 8; optional int32 num_procs = 9; diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 8ad11d161cdca..614cfd366e10a 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -1328,6 +1328,9 @@ public final class OomAdjuster { || uidRec.getSetProcState() == PROCESS_STATE_NONEXISTENT) { uidChange |= isCached ? UidRecord.CHANGE_CACHED : UidRecord.CHANGE_UNCACHED; } + if (uidRec.getSetCapability() != uidRec.getCurCapability()) { + uidChange |= UidRecord.CHANGE_CAPABILITY; + } uidRec.setSetProcState(uidRec.getCurProcState()); uidRec.setSetCapability(uidRec.getCurCapability()); uidRec.setSetAllowListed(uidRec.isCurAllowListed()); diff --git a/services/core/java/com/android/server/am/UidObserverController.java b/services/core/java/com/android/server/am/UidObserverController.java index df65ee6e3a280..c1bfe25618b20 100644 --- a/services/core/java/com/android/server/am/UidObserverController.java +++ b/services/core/java/com/android/server/am/UidObserverController.java @@ -147,6 +147,9 @@ public class UidObserverController { if ((currentChange & UidRecord.CHANGE_GONE) != 0) { currentChange &= ~(UidRecord.CHANGE_ACTIVE | UidRecord.CHANGE_CACHED); } + if ((pendingChange & UidRecord.CHANGE_CAPABILITY) != 0) { + currentChange |= UidRecord.CHANGE_CAPABILITY; + } return currentChange; } @@ -285,12 +288,9 @@ public class UidObserverController { reg.mLastProcStates.delete(item.uid); } } else { + boolean doReport = false; if ((reg.mWhich & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) { - if (DEBUG_UID_OBSERVERS) { - Slog.i(TAG_UID_OBSERVERS, "UID CHANGED uid=" + item.uid - + ": " + item.procState + ": " + item.capability); - } - boolean doReport = true; + doReport = true; if (reg.mCutpoint >= ActivityManager.MIN_PROCESS_STATE) { final int lastState = reg.mLastProcStates.get(item.uid, ActivityManager.PROCESS_STATE_UNKNOWN); @@ -302,13 +302,20 @@ public class UidObserverController { doReport = item.procState != PROCESS_STATE_NONEXISTENT; } } - if (doReport) { - if (reg.mLastProcStates != null) { - reg.mLastProcStates.put(item.uid, item.procState); - } - observer.onUidStateChanged(item.uid, item.procState, - item.procStateSeq, item.capability); + } + if ((reg.mWhich & ActivityManager.UID_OBSERVER_CAPABILITY) != 0) { + doReport |= (change & UidRecord.CHANGE_CAPABILITY) != 0; + } + if (doReport) { + if (DEBUG_UID_OBSERVERS) { + Slog.i(TAG_UID_OBSERVERS, "UID CHANGED uid=" + item.uid + + ": " + item.procState + ": " + item.capability); } + if (reg.mLastProcStates != null) { + reg.mLastProcStates.put(item.uid, item.procState); + } + observer.onUidStateChanged(item.uid, item.procState, + item.procStateSeq, item.capability); } } final int duration = (int) (SystemClock.uptimeMillis() - start); @@ -428,12 +435,14 @@ public class UidObserverController { ActivityManager.UID_OBSERVER_ACTIVE, ActivityManager.UID_OBSERVER_GONE, ActivityManager.UID_OBSERVER_PROCSTATE, + ActivityManager.UID_OBSERVER_CAPABILITY, }; private static final int[] PROTO_ENUMS = new int[]{ ActivityManagerProto.UID_OBSERVER_FLAG_IDLE, ActivityManagerProto.UID_OBSERVER_FLAG_ACTIVE, ActivityManagerProto.UID_OBSERVER_FLAG_GONE, ActivityManagerProto.UID_OBSERVER_FLAG_PROCSTATE, + ActivityManagerProto.UID_OBSERVER_FLAG_CAPABILITY, }; UidObserverRegistration(int uid, @NonNull String pkg, int which, int cutpoint) { @@ -462,6 +471,9 @@ public class UidObserverController { if ((mWhich & ActivityManager.UID_OBSERVER_GONE) != 0) { pw.print(" GONE"); } + if ((mWhich & ActivityManager.UID_OBSERVER_CAPABILITY) != 0) { + pw.print(" CAP"); + } if ((mWhich & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) { pw.print(" STATE"); pw.print(" (cut="); diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java index 2fb662f5ee69b..4ba59faea9ec2 100644 --- a/services/core/java/com/android/server/am/UidRecord.java +++ b/services/core/java/com/android/server/am/UidRecord.java @@ -122,6 +122,7 @@ public final class UidRecord { static final int CHANGE_ACTIVE = 1<<2; static final int CHANGE_CACHED = 1<<3; static final int CHANGE_UNCACHED = 1<<4; + static final int CHANGE_CAPABILITY = 1<<5; // Keep the enum lists in sync private static int[] ORIG_ENUMS = new int[] { @@ -130,6 +131,7 @@ public final class UidRecord { CHANGE_ACTIVE, CHANGE_CACHED, CHANGE_UNCACHED, + CHANGE_CAPABILITY, }; private static int[] PROTO_ENUMS = new int[] { UidRecordProto.CHANGE_GONE, @@ -137,6 +139,7 @@ public final class UidRecord { UidRecordProto.CHANGE_ACTIVE, UidRecordProto.CHANGE_CACHED, UidRecordProto.CHANGE_UNCACHED, + UidRecordProto.CHANGE_CAPABILITY, }; // UidObserverController is the only thing that should modify this. diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 40eefca096b9d..ba20f04d9515c 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -912,10 +912,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); try { - // TODO: There shouldn't be a need to receive callback for all changes. - mActivityManager.registerUidObserver(mUidObserver, - ActivityManager.UID_OBSERVER_PROCSTATE|ActivityManager.UID_OBSERVER_GONE, - ActivityManager.PROCESS_STATE_UNKNOWN, "android"); + final int changes = ActivityManager.UID_OBSERVER_PROCSTATE + | ActivityManager.UID_OBSERVER_GONE + | ActivityManager.UID_OBSERVER_CAPABILITY; + mActivityManager.registerUidObserver(mUidObserver, changes, + NetworkPolicyManager.FOREGROUND_THRESHOLD_STATE, "android"); mNetworkManager.registerObserver(mAlertObserver); } catch (RemoteException e) { // ignored; both services live in system_server 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 f31400853060d..3c7511e0d5e8d 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java @@ -68,6 +68,7 @@ import android.os.Message; import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; +import android.util.IntArray; import androidx.test.filters.MediumTest; import androidx.test.filters.SmallTest; @@ -117,7 +118,8 @@ public class ActivityManagerServiceTest { UidRecord.CHANGE_GONE, UidRecord.CHANGE_GONE | UidRecord.CHANGE_IDLE, UidRecord.CHANGE_IDLE, - UidRecord.CHANGE_ACTIVE + UidRecord.CHANGE_ACTIVE, + UidRecord.CHANGE_CAPABILITY, }; private static PackageManagerInternal sPackageManagerInternal; @@ -517,8 +519,10 @@ public class ActivityManagerServiceTest { ActivityManager.UID_OBSERVER_GONE, ActivityManager.UID_OBSERVER_IDLE, ActivityManager.UID_OBSERVER_ACTIVE, + ActivityManager.UID_OBSERVER_CAPABILITY, ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_ACTIVE | ActivityManager.UID_OBSERVER_IDLE + | ActivityManager.UID_OBSERVER_CAPABILITY }; final IUidObserver[] observers = new IUidObserver.Stub[changesToObserve.length]; for (int i = 0; i < observers.length; ++i) { @@ -542,7 +546,16 @@ public class ActivityManagerServiceTest { ActivityManager.PROCESS_STATE_NONEXISTENT, ActivityManager.PROCESS_STATE_CACHED_EMPTY, ActivityManager.PROCESS_STATE_CACHED_ACTIVITY, - ActivityManager.PROCESS_STATE_TOP + ActivityManager.PROCESS_STATE_TOP, + ActivityManager.PROCESS_STATE_TOP, + }; + final int[] capabilitiesForPendingUidRecords = { + ActivityManager.PROCESS_CAPABILITY_ALL, + ActivityManager.PROCESS_CAPABILITY_NONE, + ActivityManager.PROCESS_CAPABILITY_NONE, + ActivityManager.PROCESS_CAPABILITY_NONE, + ActivityManager.PROCESS_CAPABILITY_NONE, + ActivityManager.PROCESS_CAPABILITY_NETWORK, }; final Map changeItems = new HashMap<>(); for (int i = 0; i < changesForPendingUidRecords.length; ++i) { @@ -551,6 +564,7 @@ public class ActivityManagerServiceTest { pendingChange.uid = i; pendingChange.procState = procStatesForPendingUidRecords[i]; pendingChange.procStateSeq = i; + pendingChange.capability = capabilitiesForPendingUidRecords[i]; changeItems.put(changesForPendingUidRecords[i], pendingChange); addPendingUidChange(pendingChange); } @@ -595,20 +609,26 @@ public class ActivityManagerServiceTest { verify(observer).onUidGone(changeItem.uid, changeItem.ephemeral); }); } - if ((changeToObserve & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) { + if ((changeToObserve & ActivityManager.UID_OBSERVER_PROCSTATE) != 0 + || (changeToObserve & ActivityManager.UID_OBSERVER_CAPABILITY) != 0) { // Observer listens to uid procState changes, so change items corresponding to // UidRecord.CHANGE_PROCSTATE or UidRecord.CHANGE_IDLE or UidRecord.CHANGE_ACTIVE // needs to be delivered to this observer. - final int[] changesToVerify = { - UidRecord.CHANGE_PROCSTATE, - UidRecord.CHANGE_ACTIVE, - UidRecord.CHANGE_IDLE - }; - verifyObserverReceivedChanges(observerToTest, changesToVerify, changeItems, + final IntArray changesToVerify = new IntArray(); + if ((changeToObserve & ActivityManager.UID_OBSERVER_PROCSTATE) == 0) { + changesToVerify.add(UidRecord.CHANGE_CAPABILITY); + } else { + changesToVerify.add(UidRecord.CHANGE_PROCSTATE); + changesToVerify.add(UidRecord.CHANGE_ACTIVE); + changesToVerify.add(UidRecord.CHANGE_IDLE); + changesToVerify.add(UidRecord.CHANGE_CAPABILITY); + } + verifyObserverReceivedChanges(observerToTest, changesToVerify.toArray(), + changeItems, (observer, changeItem) -> { verify(observer).onUidStateChanged(changeItem.uid, changeItem.procState, changeItem.procStateSeq, - ActivityManager.PROCESS_CAPABILITY_NONE); + changeItem.capability); }); } // Verify there are no other callbacks for this observer. @@ -710,11 +730,11 @@ public class ActivityManagerServiceTest { ActivityManager.PROCESS_STATE_CACHED_EMPTY, ActivityManager.PROCESS_STATE_CACHED_ACTIVITY, ActivityManager.PROCESS_STATE_SERVICE, - ActivityManager.PROCESS_STATE_RECEIVER + ActivityManager.PROCESS_STATE_RECEIVER, }; final ArrayList pendingItemsForUids = - new ArrayList<>(changesForPendingItems.length); - for (int i = 0; i < changesForPendingItems.length; ++i) { + new ArrayList<>(procStatesForPendingItems.length); + for (int i = 0; i < procStatesForPendingItems.length; ++i) { final ChangeRecord item = new ChangeRecord(); item.uid = i; item.change = changesForPendingItems[i]; 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 1de5f6f005d17..0db118d3db47d 100644 --- a/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java @@ -18,6 +18,7 @@ package com.android.server.am; import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL; import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION; +import static android.app.ActivityManager.PROCESS_CAPABILITY_NETWORK; import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE; import static android.app.ActivityManager.PROCESS_STATE_CACHED_RECENT; import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; @@ -109,6 +110,7 @@ public class UidObserverControllerTest { @Test public void testMergeWithPendingChange() { + // Map of expectedChange -> {(currentChange, pendingChange)} final SparseArray> changesToVerify = new SparseArray<>(); changesToVerify.put(UidRecord.CHANGE_ACTIVE, @@ -127,6 +129,8 @@ public class UidObserverControllerTest { Pair.create(UidRecord.CHANGE_GONE, UidRecord.CHANGE_ACTIVE)); changesToVerify.put(UidRecord.CHANGE_GONE, Pair.create(UidRecord.CHANGE_GONE, UidRecord.CHANGE_CACHED)); + changesToVerify.put(UidRecord.CHANGE_PROCSTATE | UidRecord.CHANGE_CAPABILITY, + Pair.create(UidRecord.CHANGE_PROCSTATE, UidRecord.CHANGE_CAPABILITY)); for (int i = 0; i < changesToVerify.size(); ++i) { final int expectedChange = changesToVerify.keyAt(i); @@ -149,7 +153,8 @@ public class UidObserverControllerTest { ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_ACTIVE, PROCESS_STATE_IMPORTANT_FOREGROUND, TEST_PKG2, TEST_UID2); final IUidObserver observer2 = mock(IUidObserver.Stub.class); - registerObserver(observer2, ActivityManager.UID_OBSERVER_PROCSTATE, + registerObserver(observer2, + ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_CAPABILITY, PROCESS_STATE_SERVICE, TEST_PKG3, TEST_UID3); mUidObserverController.dispatchUidsChanged(); @@ -177,6 +182,14 @@ public class UidObserverControllerTest { verifyNoMoreInteractions(observer1); verifyNoMoreInteractions(observer2); + addPendingChange(TEST_UID1, UidRecord.CHANGE_PROCSTATE | UidRecord.CHANGE_CAPABILITY, + PROCESS_STATE_RECEIVER, 111, PROCESS_CAPABILITY_NETWORK, false); + mUidObserverController.dispatchUidsChanged(); + verify(observer2).onUidStateChanged(TEST_UID1, PROCESS_STATE_RECEIVER, + 111, PROCESS_CAPABILITY_NETWORK); + verifyNoMoreInteractions(observer1); + verifyNoMoreInteractions(observer2); + unregisterObserver(observer1); addPendingChange(TEST_UID1, UidRecord.CHANGE_PROCSTATE, PROCESS_STATE_TOP,