diff options
Diffstat (limited to 'core/java/android')
| -rw-r--r-- | core/java/android/app/AppOpsManager.java | 146 | ||||
| -rw-r--r-- | core/java/android/app/AsyncNotedAppOp.java | 30 | ||||
| -rw-r--r-- | core/java/android/app/SyncNotedAppOp.java | 4 | ||||
| -rw-r--r-- | core/java/android/os/BinderProxy.java | 2 |
4 files changed, 122 insertions, 60 deletions
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index e2ecf85b7af8..eeb5d4122cc7 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -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 + /** + * Will be removed before R ships, leave it just to not break apps immediately. + * + * @removed + * + * @hide + */ + @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); + } + } + } + /** * @return {@code true} iff the process currently is currently collecting noted appops. * - * @see #setNotedAppOpsCollector(AppOpsCollector) + * @see #setOnOpNotedCallback * * @hide */ - public static boolean isCollectingNotedAppOps() { - return sNotedAppOpsCollector != null; + public static boolean isListeningForOpNoted() { + return sOnOpNotedCallback != null; } /** - * Callback an app can {@link #setNotedAppOpsCollector register} to monitor the app-ops the + * 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 the callback methods of this object is called. + * one of a method of this object is called. * - * <p><b>There will be a callback for all app-ops related to runtime permissions, but not + * <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. * diff --git a/core/java/android/app/AsyncNotedAppOp.java b/core/java/android/app/AsyncNotedAppOp.java index c2b2063062b5..4d955dbe8703 100644 --- a/core/java/android/app/AsyncNotedAppOp.java +++ b/core/java/android/app/AsyncNotedAppOp.java @@ -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() {} diff --git a/core/java/android/app/SyncNotedAppOp.java b/core/java/android/app/SyncNotedAppOp.java index aa11b9510c94..13b90ca6ced1 100644 --- a/core/java/android/app/SyncNotedAppOp.java +++ b/core/java/android/app/SyncNotedAppOp.java @@ -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 diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java index dd3f9fdc3ec0..20e5f243163f 100644 --- a/core/java/android/os/BinderProxy.java +++ b/core/java/android/os/BinderProxy.java @@ -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; } |
