Merge "Camera / UidObserver: Add the ability to subscribe to specific UIDs" into udc-dev am: 3fac471cfc am: ad0d693cf6
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/22829760 Change-Id: I2d57f8f345dd453b22b52b377fa2641bd2de5ca0 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -102,6 +102,43 @@ interface IActivityManager {
|
||||
void registerUidObserver(in IUidObserver observer, int which, int cutpoint,
|
||||
String callingPackage);
|
||||
void unregisterUidObserver(in IUidObserver observer);
|
||||
|
||||
/**
|
||||
* Registers a UidObserver with a uid filter.
|
||||
*
|
||||
* @param observer The UidObserver implementation to register.
|
||||
* @param which A bitmask of events to observe. See ActivityManager.UID_OBSERVER_*.
|
||||
* @param cutpoint The cutpoint for onUidStateChanged events. When the state crosses this
|
||||
* threshold in either direction, onUidStateChanged will be called.
|
||||
* @param callingPackage The name of the calling package.
|
||||
* @param uids A list of uids to watch. If all uids are to be watched, use
|
||||
* registerUidObserver instead.
|
||||
* @throws RemoteException
|
||||
* @return Returns A binder token identifying the UidObserver registration.
|
||||
*/
|
||||
IBinder registerUidObserverForUids(in IUidObserver observer, int which, int cutpoint,
|
||||
String callingPackage, in int[] uids);
|
||||
|
||||
/**
|
||||
* Adds a uid to the list of uids that a UidObserver will receive updates about.
|
||||
*
|
||||
* @param observerToken The binder token identifying the UidObserver registration.
|
||||
* @param callingPackage The name of the calling package.
|
||||
* @param uid The uid to watch.
|
||||
* @throws RemoteException
|
||||
*/
|
||||
void addUidToObserver(in IBinder observerToken, String callingPackage, int uid);
|
||||
|
||||
/**
|
||||
* Removes a uid from the list of uids that a UidObserver will receive updates about.
|
||||
*
|
||||
* @param observerToken The binder token identifying the UidObserver registration.
|
||||
* @param callingPackage The name of the calling package.
|
||||
* @param uid The uid to stop watching.
|
||||
* @throws RemoteException
|
||||
*/
|
||||
void removeUidFromObserver(in IBinder observerToken, String callingPackage, int uid);
|
||||
|
||||
boolean isUidActive(int uid, String callingPackage);
|
||||
@JavaPassthrough(annotation=
|
||||
"@android.annotation.RequiresPermission(allOf = {android.Manifest.permission.PACKAGE_USAGE_STATS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}, conditional = true)")
|
||||
|
||||
@@ -7511,7 +7511,31 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
"registerUidObserver");
|
||||
}
|
||||
mUidObserverController.register(observer, which, cutpoint, callingPackage,
|
||||
Binder.getCallingUid());
|
||||
Binder.getCallingUid(), /*uids*/null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a UidObserver with a uid filter.
|
||||
*
|
||||
* @param observer The UidObserver implementation to register.
|
||||
* @param which A bitmask of events to observe. See ActivityManager.UID_OBSERVER_*.
|
||||
* @param cutpoint The cutpoint for onUidStateChanged events. When the state crosses this
|
||||
* threshold in either direction, onUidStateChanged will be called.
|
||||
* @param callingPackage The name of the calling package.
|
||||
* @param uids A list of uids to watch. If all uids are to be watched, use
|
||||
* registerUidObserver instead.
|
||||
* @throws RemoteException
|
||||
* @return Returns A binder token identifying the UidObserver registration.
|
||||
*/
|
||||
@Override
|
||||
public IBinder registerUidObserverForUids(IUidObserver observer, int which, int cutpoint,
|
||||
String callingPackage, int[] uids) {
|
||||
if (!hasUsageStatsPermission(callingPackage)) {
|
||||
enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
|
||||
"registerUidObserver");
|
||||
}
|
||||
return mUidObserverController.register(observer, which, cutpoint, callingPackage,
|
||||
Binder.getCallingUid(), uids);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -7519,6 +7543,40 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
mUidObserverController.unregister(observer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a uid to the list of uids that a UidObserver will receive updates about.
|
||||
*
|
||||
* @param observerToken The binder token identifying the UidObserver registration.
|
||||
* @param callingPackage The name of the calling package.
|
||||
* @param uid The uid to watch.
|
||||
* @throws RemoteException
|
||||
*/
|
||||
@Override
|
||||
public void addUidToObserver(IBinder observerToken, String callingPackage, int uid) {
|
||||
if (!hasUsageStatsPermission(callingPackage)) {
|
||||
enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
|
||||
"registerUidObserver");
|
||||
}
|
||||
mUidObserverController.addUidToObserver(observerToken, uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a uid from the list of uids that a UidObserver will receive updates about.
|
||||
*
|
||||
* @param observerToken The binder token identifying the UidObserver registration.
|
||||
* @param callingPackage The name of the calling package.
|
||||
* @param uid The uid to stop watching.
|
||||
* @throws RemoteException
|
||||
*/
|
||||
@Override
|
||||
public void removeUidFromObserver(IBinder observerToken, String callingPackage, int uid) {
|
||||
if (!hasUsageStatsPermission(callingPackage)) {
|
||||
enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
|
||||
"registerUidObserver");
|
||||
}
|
||||
mUidObserverController.removeUidFromObserver(observerToken, uid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUidActive(int uid, String callingPackage) {
|
||||
if (!hasUsageStatsPermission(callingPackage)) {
|
||||
@@ -18613,7 +18671,7 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
int which, int cutpoint, @NonNull String callingPackage) {
|
||||
mNetworkPolicyUidObserver = observer;
|
||||
mUidObserverController.register(observer, which, cutpoint, callingPackage,
|
||||
Binder.getCallingUid());
|
||||
Binder.getCallingUid(), /*uids*/null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -27,7 +27,9 @@ import android.app.ActivityManager;
|
||||
import android.app.ActivityManagerProto;
|
||||
import android.app.IUidObserver;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteCallbackList;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
@@ -43,6 +45,8 @@ import com.android.server.am.ActivityManagerServiceDumpProcessesProto.UidObserve
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
|
||||
public class UidObserverController {
|
||||
/** If a UID observer takes more than this long, send a WTF. */
|
||||
@@ -79,14 +83,19 @@ public class UidObserverController {
|
||||
mValidateUids = new ActiveUids(null /* service */, false /* postChangesToAtm */);
|
||||
}
|
||||
|
||||
void register(@NonNull IUidObserver observer, int which, int cutpoint,
|
||||
@NonNull String callingPackage, int callingUid) {
|
||||
IBinder register(@NonNull IUidObserver observer, int which, int cutpoint,
|
||||
@NonNull String callingPackage, int callingUid, @Nullable int[] uids) {
|
||||
IBinder token = new Binder("UidObserver-" + callingPackage + "-"
|
||||
+ UUID.randomUUID().toString());
|
||||
|
||||
synchronized (mLock) {
|
||||
mUidObservers.register(observer, new UidObserverRegistration(callingUid,
|
||||
callingPackage, which, cutpoint,
|
||||
ActivityManager.checkUidPermission(INTERACT_ACROSS_USERS_FULL, callingUid)
|
||||
== PackageManager.PERMISSION_GRANTED));
|
||||
== PackageManager.PERMISSION_GRANTED, uids, token));
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
void unregister(@NonNull IUidObserver observer) {
|
||||
@@ -95,6 +104,42 @@ public class UidObserverController {
|
||||
}
|
||||
}
|
||||
|
||||
void addUidToObserver(@NonNull IBinder observerToken, int uid) {
|
||||
synchronized (mLock) {
|
||||
int i = mUidObservers.beginBroadcast();
|
||||
while (i-- > 0) {
|
||||
var reg = (UidObserverRegistration) mUidObservers.getBroadcastCookie(i);
|
||||
if (reg.getToken().equals(observerToken)) {
|
||||
reg.addUid(uid);
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
Slog.e(TAG_UID_OBSERVERS, "Unable to find UidObserver by token");
|
||||
}
|
||||
}
|
||||
mUidObservers.finishBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
void removeUidFromObserver(@NonNull IBinder observerToken, int uid) {
|
||||
synchronized (mLock) {
|
||||
int i = mUidObservers.beginBroadcast();
|
||||
while (i-- > 0) {
|
||||
var reg = (UidObserverRegistration) mUidObservers.getBroadcastCookie(i);
|
||||
if (reg.getToken().equals(observerToken)) {
|
||||
reg.removeUid(uid);
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
Slog.e(TAG_UID_OBSERVERS, "Unable to find UidObserver by token");
|
||||
}
|
||||
}
|
||||
mUidObservers.finishBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
int enqueueUidChange(@Nullable ChangeRecord currentRecord, int uid, int change, int procState,
|
||||
int procAdj, long procStateSeq, int capability, boolean ephemeral) {
|
||||
synchronized (mLock) {
|
||||
@@ -257,6 +302,10 @@ public class UidObserverController {
|
||||
final ChangeRecord item = mActiveUidChanges[j];
|
||||
final long start = SystemClock.uptimeMillis();
|
||||
final int change = item.change;
|
||||
// Is the observer watching this uid?
|
||||
if (!reg.isWatchingUid(item.uid)) {
|
||||
continue;
|
||||
}
|
||||
// Does the user have permission? Don't send a non user UID change otherwise
|
||||
if (UserHandle.getUserId(item.uid) != UserHandle.getUserId(reg.mUid)
|
||||
&& !reg.mCanInteractAcrossUsers) {
|
||||
@@ -450,6 +499,8 @@ public class UidObserverController {
|
||||
private final int mWhich;
|
||||
private final int mCutpoint;
|
||||
private final boolean mCanInteractAcrossUsers;
|
||||
private final IBinder mToken;
|
||||
private int[] mUids;
|
||||
|
||||
/**
|
||||
* Total # of callback calls that took more than {@link #SLOW_UID_OBSERVER_THRESHOLD_MS}.
|
||||
@@ -481,16 +532,94 @@ public class UidObserverController {
|
||||
};
|
||||
|
||||
UidObserverRegistration(int uid, @NonNull String pkg, int which, int cutpoint,
|
||||
boolean canInteractAcrossUsers) {
|
||||
boolean canInteractAcrossUsers, @Nullable int[] uids, @NonNull IBinder token) {
|
||||
this.mUid = uid;
|
||||
this.mPkg = pkg;
|
||||
this.mWhich = which;
|
||||
this.mCutpoint = cutpoint;
|
||||
this.mCanInteractAcrossUsers = canInteractAcrossUsers;
|
||||
|
||||
if (uids != null) {
|
||||
this.mUids = uids.clone();
|
||||
Arrays.sort(this.mUids);
|
||||
} else {
|
||||
this.mUids = null;
|
||||
}
|
||||
|
||||
this.mToken = token;
|
||||
|
||||
mLastProcStates = cutpoint >= ActivityManager.MIN_PROCESS_STATE
|
||||
? new SparseIntArray() : null;
|
||||
}
|
||||
|
||||
boolean isWatchingUid(int uid) {
|
||||
if (mUids == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return Arrays.binarySearch(mUids, uid) != -1;
|
||||
}
|
||||
|
||||
void addUid(int uid) {
|
||||
if (mUids == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int[] temp = mUids;
|
||||
mUids = new int[temp.length + 1];
|
||||
boolean inserted = false;
|
||||
for (int i = 0; i < temp.length; i++) {
|
||||
if (!inserted) {
|
||||
if (temp[i] < uid) {
|
||||
mUids[i] = temp[i];
|
||||
} else if (temp[i] == uid) {
|
||||
// Duplicate uid, no-op and fallback to the previous array
|
||||
mUids = temp;
|
||||
return;
|
||||
} else {
|
||||
mUids[i] = uid;
|
||||
mUids[i + 1] = temp[i];
|
||||
inserted = true;
|
||||
}
|
||||
} else {
|
||||
mUids[i + 1] = temp[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (!inserted) {
|
||||
mUids[temp.length] = uid;
|
||||
}
|
||||
}
|
||||
|
||||
void removeUid(int uid) {
|
||||
if (mUids == null || mUids.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int[] temp = mUids;
|
||||
mUids = new int[temp.length - 1];
|
||||
boolean removed = false;
|
||||
for (int i = 0; i < temp.length; i++) {
|
||||
if (!removed) {
|
||||
if (temp[i] == uid) {
|
||||
removed = true;
|
||||
} else if (i == temp.length - 1) {
|
||||
// Uid not found, no-op and fallback to the previous array
|
||||
mUids = temp;
|
||||
return;
|
||||
} else {
|
||||
mUids[i] = temp[i];
|
||||
}
|
||||
} else {
|
||||
mUids[i - 1] = temp[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IBinder getToken() {
|
||||
return mToken;
|
||||
}
|
||||
|
||||
void dump(@NonNull PrintWriter pw, @NonNull IUidObserver observer) {
|
||||
pw.print(" ");
|
||||
UserHandle.formatUid(pw, mUid);
|
||||
|
||||
@@ -217,7 +217,8 @@ public class UidObserverControllerTest {
|
||||
private void registerObserver(IUidObserver observer, int which, int cutpoint,
|
||||
String callingPackage, int callingUid) {
|
||||
when(observer.asBinder()).thenReturn((IBinder) observer);
|
||||
mUidObserverController.register(observer, which, cutpoint, callingPackage, callingUid);
|
||||
mUidObserverController.register(observer, which, cutpoint, callingPackage, callingUid,
|
||||
/*uids*/null);
|
||||
Mockito.reset(observer);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user