Merge "Rename AppOpsCollector -> OnOpNotedCallback" into rvc-dev

This commit is contained in:
Philip P. Moltmann
2020-03-10 21:03:21 +00:00
committed by Android (Google) Code Review
6 changed files with 139 additions and 72 deletions

View File

@@ -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.
*

View File

@@ -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() {}

View File

@@ -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

View File

@@ -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;
}