Merge "Rename AppOpsCollector -> OnOpNotedCallback" into rvc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
b73aa1e008
@@ -162,7 +162,7 @@ import java.util.function.Supplier;
|
||||
* might also make sense inside of a single app if the access is forwarded between two features of
|
||||
* the app.
|
||||
*
|
||||
* <p>An app can register an {@link AppOpsCollector} to get informed about what accesses the
|
||||
* <p>An app can register an {@link OnOpNotedCallback} to get informed about what accesses the
|
||||
* system is tracking for it. As each runtime permission has an associated app-op this API is
|
||||
* particularly useful for an app that want to find unexpected private data accesses.
|
||||
*/
|
||||
@@ -206,16 +206,16 @@ public class AppOpsManager {
|
||||
|
||||
private static final Object sLock = new Object();
|
||||
|
||||
/** Current {@link AppOpsCollector}. Change via {@link #setNotedAppOpsCollector} */
|
||||
/** Current {@link OnOpNotedCallback}. Change via {@link #setOnOpNotedCallback} */
|
||||
@GuardedBy("sLock")
|
||||
private static @Nullable AppOpsCollector sNotedAppOpsCollector;
|
||||
private static @Nullable OnOpNotedCallback sOnOpNotedCallback;
|
||||
|
||||
/**
|
||||
* Additional collector that collect accesses and forwards a few of them them via
|
||||
* {@link IAppOpsService#reportRuntimeAppOpAccessMessageAndGetConfig}.
|
||||
*/
|
||||
private static AppOpsCollector sMessageCollector =
|
||||
new AppOpsCollector() {
|
||||
private static OnOpNotedCallback sMessageCollector =
|
||||
new OnOpNotedCallback() {
|
||||
@Override
|
||||
public void onNoted(@NonNull SyncNotedAppOp op) {
|
||||
reportStackTraceIfNeeded(op);
|
||||
@@ -7800,8 +7800,8 @@ public class AppOpsManager {
|
||||
*/
|
||||
private void collectNotedOpForSelf(int op, @Nullable String featureId) {
|
||||
synchronized (sLock) {
|
||||
if (sNotedAppOpsCollector != null) {
|
||||
sNotedAppOpsCollector.onSelfNoted(new SyncNotedAppOp(op, featureId));
|
||||
if (sOnOpNotedCallback != null) {
|
||||
sOnOpNotedCallback.onSelfNoted(new SyncNotedAppOp(op, featureId));
|
||||
}
|
||||
}
|
||||
sMessageCollector.onSelfNoted(new SyncNotedAppOp(op, featureId));
|
||||
@@ -7950,8 +7950,8 @@ public class AppOpsManager {
|
||||
synchronized (sLock) {
|
||||
for (int code = notedAppOps.nextSetBit(0); code != -1;
|
||||
code = notedAppOps.nextSetBit(code + 1)) {
|
||||
if (sNotedAppOpsCollector != null) {
|
||||
sNotedAppOpsCollector.onNoted(new SyncNotedAppOp(code, featureId));
|
||||
if (sOnOpNotedCallback != null) {
|
||||
sOnOpNotedCallback.onNoted(new SyncNotedAppOp(code, featureId));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7964,33 +7964,45 @@ public class AppOpsManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new {@link AppOpsCollector}.
|
||||
* Set a new {@link OnOpNotedCallback}.
|
||||
*
|
||||
* <p>There can only ever be one collector per process. If there currently is a collector
|
||||
* registered, it will be unregistered.
|
||||
* <p>There can only ever be one collector per process. If there currently is another callback
|
||||
* set, this will fail.
|
||||
*
|
||||
* <p><b>Only appops related to dangerous permissions are collected.</b>
|
||||
* @param asyncExecutor executor to execute {@link OnOpNotedCallback#onAsyncNoted} on, {@code
|
||||
* null} to unset
|
||||
* @param callback listener to set, {@code null} to unset
|
||||
*
|
||||
* @param collector The collector to set or {@code null} to unregister.
|
||||
* @throws IllegalStateException If another callback is already registered
|
||||
*/
|
||||
public void setNotedAppOpsCollector(@Nullable AppOpsCollector collector) {
|
||||
public void setOnOpNotedCallback(@Nullable @CallbackExecutor Executor asyncExecutor,
|
||||
@Nullable OnOpNotedCallback callback) {
|
||||
Preconditions.checkState((callback == null) == (asyncExecutor == null));
|
||||
|
||||
synchronized (sLock) {
|
||||
if (sNotedAppOpsCollector != null) {
|
||||
if (callback == null) {
|
||||
Preconditions.checkState(sOnOpNotedCallback != null,
|
||||
"No callback is currently registered");
|
||||
|
||||
try {
|
||||
mService.stopWatchingAsyncNoted(mContext.getPackageName(),
|
||||
sNotedAppOpsCollector.mAsyncCb);
|
||||
sOnOpNotedCallback.mAsyncCb);
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
sNotedAppOpsCollector = collector;
|
||||
sOnOpNotedCallback = null;
|
||||
} else {
|
||||
Preconditions.checkState(sOnOpNotedCallback == null,
|
||||
"Another callback is already registered");
|
||||
|
||||
callback.mAsyncExecutor = asyncExecutor;
|
||||
sOnOpNotedCallback = callback;
|
||||
|
||||
if (sNotedAppOpsCollector != null) {
|
||||
List<AsyncNotedAppOp> missedAsyncOps = null;
|
||||
try {
|
||||
mService.startWatchingAsyncNoted(mContext.getPackageName(),
|
||||
sNotedAppOpsCollector.mAsyncCb);
|
||||
sOnOpNotedCallback.mAsyncCb);
|
||||
missedAsyncOps = mService.extractAsyncOps(mContext.getPackageName());
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowFromSystemServer();
|
||||
@@ -8000,10 +8012,9 @@ public class AppOpsManager {
|
||||
int numMissedAsyncOps = missedAsyncOps.size();
|
||||
for (int i = 0; i < numMissedAsyncOps; i++) {
|
||||
final AsyncNotedAppOp asyncNotedAppOp = missedAsyncOps.get(i);
|
||||
if (sNotedAppOpsCollector != null) {
|
||||
sNotedAppOpsCollector.getAsyncNotedExecutor().execute(
|
||||
() -> sNotedAppOpsCollector.onAsyncNoted(
|
||||
asyncNotedAppOp));
|
||||
if (sOnOpNotedCallback != null) {
|
||||
sOnOpNotedCallback.getAsyncNotedExecutor().execute(
|
||||
() -> sOnOpNotedCallback.onAsyncNoted(asyncNotedAppOp));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8011,27 +8022,50 @@ public class AppOpsManager {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO moltmann: Remove
|
||||
/**
|
||||
* @return {@code true} iff the process currently is currently collecting noted appops.
|
||||
* Will be removed before R ships, leave it just to not break apps immediately.
|
||||
*
|
||||
* @see #setNotedAppOpsCollector(AppOpsCollector)
|
||||
* @removed
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static boolean isCollectingNotedAppOps() {
|
||||
return sNotedAppOpsCollector != null;
|
||||
@SystemApi
|
||||
@Deprecated
|
||||
public void setNotedAppOpsCollector(@Nullable AppOpsCollector collector) {
|
||||
synchronized (sLock) {
|
||||
if (collector != null) {
|
||||
if (isListeningForOpNoted()) {
|
||||
setOnOpNotedCallback(null, null);
|
||||
}
|
||||
setOnOpNotedCallback(new HandlerExecutor(Handler.getMain()), collector);
|
||||
} else if (sOnOpNotedCallback != null) {
|
||||
setOnOpNotedCallback(null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback an app can {@link #setNotedAppOpsCollector register} to monitor the app-ops the
|
||||
* system has tracked for it. I.e. each time any app calls {@link #noteOp} or {@link #startOp}
|
||||
* one of the callback methods of this object is called.
|
||||
* @return {@code true} iff the process currently is currently collecting noted appops.
|
||||
*
|
||||
* <p><b>There will be a callback for all app-ops related to runtime permissions, but not
|
||||
* @see #setOnOpNotedCallback
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static boolean isListeningForOpNoted() {
|
||||
return sOnOpNotedCallback != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback an app can {@link #setOnOpNotedCallback set} to monitor the app-ops the
|
||||
* system has tracked for it. I.e. each time any app calls {@link #noteOp} or {@link #startOp}
|
||||
* one of a method of this object is called.
|
||||
*
|
||||
* <p><b>There will be a call for all app-ops related to runtime permissions, but not
|
||||
* necessarily for all other app-ops.
|
||||
*
|
||||
* <pre>
|
||||
* setNotedAppOpsCollector(new AppOpsCollector() {
|
||||
* setOnOpNotedCallback(getMainExecutor(), new OnOpNotedCallback() {
|
||||
* ArraySet<Pair<String, String>> opsNotedForThisProcess = new ArraySet<>();
|
||||
*
|
||||
* private synchronized void addAccess(String op, String accessLocation) {
|
||||
@@ -8056,24 +8090,36 @@ public class AppOpsManager {
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @see #setNotedAppOpsCollector
|
||||
* @see #setOnOpNotedCallback
|
||||
*/
|
||||
public abstract static class AppOpsCollector {
|
||||
public abstract static class OnOpNotedCallback {
|
||||
private @NonNull Executor mAsyncExecutor;
|
||||
|
||||
/** Callback registered with the system. This will receive the async notes ops */
|
||||
private final IAppOpsAsyncNotedCallback mAsyncCb = new IAppOpsAsyncNotedCallback.Stub() {
|
||||
@Override
|
||||
public void opNoted(AsyncNotedAppOp op) {
|
||||
Objects.requireNonNull(op);
|
||||
|
||||
getAsyncNotedExecutor().execute(() -> onAsyncNoted(op));
|
||||
long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
getAsyncNotedExecutor().execute(() -> onAsyncNoted(op));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// TODO moltmann: Remove
|
||||
/**
|
||||
* Will be removed before R ships.
|
||||
*
|
||||
* @return The executor for the system to use when calling {@link #onAsyncNoted}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public @NonNull Executor getAsyncNotedExecutor() {
|
||||
return new HandlerExecutor(Handler.getMain());
|
||||
protected @NonNull Executor getAsyncNotedExecutor() {
|
||||
return mAsyncExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -8083,7 +8129,7 @@ public class AppOpsManager {
|
||||
* <p>Called on the calling thread before the API returns. This allows the app to e.g.
|
||||
* collect stack traces to figure out where the access came from.
|
||||
*
|
||||
* @param op The op noted
|
||||
* @param op op noted
|
||||
*/
|
||||
public abstract void onNoted(@NonNull SyncNotedAppOp op);
|
||||
|
||||
@@ -8093,7 +8139,7 @@ public class AppOpsManager {
|
||||
* <p>This is very similar to {@link #onNoted} only that the tracking was not caused by the
|
||||
* API provider in a separate process, but by one in the app's own process.
|
||||
*
|
||||
* @param op The op noted
|
||||
* @param op op noted
|
||||
*/
|
||||
public abstract void onSelfNoted(@NonNull SyncNotedAppOp op);
|
||||
|
||||
@@ -8105,14 +8151,30 @@ public class AppOpsManager {
|
||||
* guaranteed. Due to how async calls work in Android this might even be delivered slightly
|
||||
* before the private data is delivered to the app.
|
||||
*
|
||||
* <p>If the app is not running or no {@link AppOpsCollector} is registered a small amount
|
||||
* of noted app-ops are buffered and then delivered as soon as a collector is registered.
|
||||
* <p>If the app is not running or no {@link OnOpNotedCallback} is registered a small amount
|
||||
* of noted app-ops are buffered and then delivered as soon as a listener is registered.
|
||||
*
|
||||
* @param asyncOp The op noted
|
||||
* @param asyncOp op noted
|
||||
*/
|
||||
public abstract void onAsyncNoted(@NonNull AsyncNotedAppOp asyncOp);
|
||||
}
|
||||
|
||||
// TODO moltmann: Remove
|
||||
/**
|
||||
* Will be removed before R ships, leave it just to not break apps immediately.
|
||||
*
|
||||
* @removed
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@Deprecated
|
||||
public abstract static class AppOpsCollector extends OnOpNotedCallback {
|
||||
public @NonNull Executor getAsyncNotedExecutor() {
|
||||
return new HandlerExecutor(Handler.getMain());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate a stack trace used for noted app-ops logging.
|
||||
*
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.app;
|
||||
|
||||
import android.annotation.CurrentTimeMillisLong;
|
||||
import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
@@ -27,10 +28,11 @@ import com.android.internal.util.Preconditions;
|
||||
|
||||
/**
|
||||
* When an {@link AppOpsManager#noteOp(String, int, String, String, String) app-op is noted} and the
|
||||
* app the app-op is noted for has a {@link AppOpsManager.AppOpsCollector} registered the note-event
|
||||
* needs to be delivered to the collector. Usually this is done via an {@link SyncNotedAppOp}, but
|
||||
* in some cases this is not possible. In this case an {@link AsyncNotedAppOp} is send to the system
|
||||
* server and then forwarded to the {@link AppOpsManager.AppOpsCollector} in the app.
|
||||
* app the app-op is noted for has a {@link AppOpsManager.OnOpNotedCallback} registered the
|
||||
* note-event needs to be delivered to the callback. Usually this is done via an
|
||||
* {@link SyncNotedAppOp}, but in some cases this is not possible. In this case an
|
||||
* {@link AsyncNotedAppOp} is send to the system server and then forwarded to the
|
||||
* {@link AppOpsManager.OnOpNotedCallback} in the app.
|
||||
*/
|
||||
@Immutable
|
||||
@DataClass(genEqualsHashCode = true,
|
||||
@@ -53,7 +55,7 @@ public final class AsyncNotedAppOp implements Parcelable {
|
||||
private final @NonNull String mMessage;
|
||||
|
||||
/** Milliseconds since epoch when the op was noted */
|
||||
private final @IntRange(from = 0) long mTime;
|
||||
private final @CurrentTimeMillisLong long mTime;
|
||||
|
||||
/**
|
||||
* @return Op that was noted.
|
||||
@@ -70,7 +72,7 @@ public final class AsyncNotedAppOp implements Parcelable {
|
||||
|
||||
|
||||
|
||||
// Code below generated by codegen v1.0.14.
|
||||
// Code below generated by codegen v1.0.15.
|
||||
//
|
||||
// DO NOT MODIFY!
|
||||
// CHECKSTYLE:OFF Generated code
|
||||
@@ -104,7 +106,7 @@ public final class AsyncNotedAppOp implements Parcelable {
|
||||
@IntRange(from = 0) int notingUid,
|
||||
@Nullable String featureId,
|
||||
@NonNull String message,
|
||||
@IntRange(from = 0) long time) {
|
||||
@CurrentTimeMillisLong long time) {
|
||||
this.mOpCode = opCode;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
IntRange.class, null, mOpCode,
|
||||
@@ -119,8 +121,7 @@ public final class AsyncNotedAppOp implements Parcelable {
|
||||
NonNull.class, null, mMessage);
|
||||
this.mTime = time;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
IntRange.class, null, mTime,
|
||||
"from", 0);
|
||||
CurrentTimeMillisLong.class, null, mTime);
|
||||
|
||||
onConstructed();
|
||||
}
|
||||
@@ -153,7 +154,7 @@ public final class AsyncNotedAppOp implements Parcelable {
|
||||
* Milliseconds since epoch when the op was noted
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @IntRange(from = 0) long getTime() {
|
||||
public @CurrentTimeMillisLong long getTime() {
|
||||
return mTime;
|
||||
}
|
||||
|
||||
@@ -240,8 +241,7 @@ public final class AsyncNotedAppOp implements Parcelable {
|
||||
NonNull.class, null, mMessage);
|
||||
this.mTime = time;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
IntRange.class, null, mTime,
|
||||
"from", 0);
|
||||
CurrentTimeMillisLong.class, null, mTime);
|
||||
|
||||
onConstructed();
|
||||
}
|
||||
@@ -261,10 +261,10 @@ public final class AsyncNotedAppOp implements Parcelable {
|
||||
};
|
||||
|
||||
@DataClass.Generated(
|
||||
time = 1583375913345L,
|
||||
codegenVersion = "1.0.14",
|
||||
time = 1583866178330L,
|
||||
codegenVersion = "1.0.15",
|
||||
sourceFile = "frameworks/base/core/java/android/app/AsyncNotedAppOp.java",
|
||||
inputSignatures = "private final @android.annotation.IntRange(from=0L) int mOpCode\nprivate final @android.annotation.IntRange(from=0L) int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.IntRange(from=0L) long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nprivate void onConstructed()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)")
|
||||
inputSignatures = "private final @android.annotation.IntRange(from=0L) int mOpCode\nprivate final @android.annotation.IntRange(from=0L) int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.CurrentTimeMillisLong long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nprivate void onConstructed()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)")
|
||||
@Deprecated
|
||||
private void __metadata() {}
|
||||
|
||||
|
||||
@@ -28,9 +28,9 @@ import com.android.internal.util.DataClass;
|
||||
* Description of an app-op that was noted for the current process.
|
||||
*
|
||||
* <p>This is either delivered after a
|
||||
* {@link AppOpsManager.AppOpsCollector#onNoted(SyncNotedAppOp) two way binder call} or
|
||||
* {@link AppOpsManager.OnOpNotedCallback#onNoted(SyncNotedAppOp) two way binder call} or
|
||||
* when the app
|
||||
* {@link AppOpsManager.AppOpsCollector#onSelfNoted(SyncNotedAppOp) notes an app-op for
|
||||
* {@link AppOpsManager.OnOpNotedCallback#onSelfNoted(SyncNotedAppOp) notes an app-op for
|
||||
* itself}.
|
||||
*/
|
||||
@Immutable
|
||||
|
||||
@@ -526,7 +526,7 @@ public final class BinderProxy implements IBinder {
|
||||
final AppOpsManager.PausedNotedAppOpsCollection prevCollection =
|
||||
AppOpsManager.pauseNotedAppOpsCollection();
|
||||
|
||||
if ((flags & FLAG_ONEWAY) == 0 && AppOpsManager.isCollectingNotedAppOps()) {
|
||||
if ((flags & FLAG_ONEWAY) == 0 && AppOpsManager.isListeningForOpNoted()) {
|
||||
flags |= FLAG_COLLECT_NOTED_APP_OPS;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user