Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 25ea5b20 authored by Liana Kazanova (xWF)'s avatar Liana Kazanova (xWF) Committed by Android (Google) Code Review
Browse files

Merge "Revert "Batch noteOperation binder calls in the client to reduce..."" into main

parents 32dc99c4 2ee44b9d
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ package android.app;
parcelable AppOpsManager.PackageOps;
parcelable AppOpsManager.NoteOpEventProxyInfo;
parcelable AppOpsManager.NoteOpEvent;
parcelable AppOpsManager.NotedOp;
parcelable AppOpsManager.OpFeatureEntry;
parcelable AppOpsManager.OpEntry;

+8 −217
Original line number Diff line number Diff line
@@ -262,24 +262,6 @@ public class AppOpsManager {

    private static final Object sLock = new Object();

    // A map that records noted times for each op.
    private final ArrayMap<NotedOp, Integer> mPendingNotedOps = new ArrayMap<>();
    private final HandlerThread mHandlerThread;
    private final Handler mHandler;
    private static final int NOTE_OP_BATCHING_DELAY_MILLIS = 1000;

    private boolean isNoteOpBatchingSupported() {
        // If noteOp is called from system server no IPC is made, hence we don't need batching.
        if (Process.myUid() == Process.SYSTEM_UID) {
            return false;
        }
        return Flags.noteOpBatchingEnabled();
    }

    private final Object mBatchedNoteOpLock = new Object();
    @GuardedBy("mBatchedNoteOpLock")
    private boolean mIsBatchedNoteOpCallScheduled = false;

    /** Current {@link OnOpNotedCallback}. Change via {@link #setOnOpNotedCallback} */
    @GuardedBy("sLock")
    private static @Nullable OnOpNotedCallback sOnOpNotedCallback;
@@ -7483,135 +7465,6 @@ public class AppOpsManager {
        };
    }

    /**
     * A NotedOp is an app op grouped in noteOp API and sent to the system server in a batch
     *
     * @hide
     */
    public static final class NotedOp implements Parcelable {
        private final @IntRange(from = 0, to = _NUM_OP - 1) int mOp;
        private final @IntRange(from = 0) int mUid;
        private final @Nullable String mPackageName;
        private final @Nullable String mAttributionTag;
        private final int mVirtualDeviceId;
        private final @Nullable String mMessage;
        private final boolean mShouldCollectAsyncNotedOp;
        private final boolean mShouldCollectMessage;

        public NotedOp(int op, int uid, @Nullable String packageName,
                @Nullable String attributionTag, int virtualDeviceId, @Nullable String message,
                boolean shouldCollectAsyncNotedOp, boolean shouldCollectMessage) {
            mOp = op;
            mUid = uid;
            mPackageName = packageName;
            mAttributionTag = attributionTag;
            mVirtualDeviceId = virtualDeviceId;
            mMessage = message;
            mShouldCollectAsyncNotedOp = shouldCollectAsyncNotedOp;
            mShouldCollectMessage = shouldCollectMessage;
        }

        NotedOp(Parcel source) {
            mOp = source.readInt();
            mUid = source.readInt();
            mPackageName = source.readString();
            mAttributionTag = source.readString();
            mVirtualDeviceId = source.readInt();
            mMessage = source.readString();
            mShouldCollectAsyncNotedOp = source.readBoolean();
            mShouldCollectMessage = source.readBoolean();
        }

        public int getOp() {
            return mOp;
        }

        public int getUid() {
            return mUid;
        }

        public @Nullable String getPackageName() {
            return mPackageName;
        }

        public @Nullable String getAttributionTag() {
            return mAttributionTag;
        }

        public int getVirtualDeviceId() {
            return mVirtualDeviceId;
        }

        public @Nullable String getMessage() {
            return mMessage;
        }

        public boolean getShouldCollectAsyncNotedOp() {
            return mShouldCollectAsyncNotedOp;
        }

        public boolean getShouldCollectMessage() {
            return mShouldCollectMessage;
        }

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(@NonNull Parcel dest, int flags) {
            dest.writeInt(mOp);
            dest.writeInt(mUid);
            dest.writeString(mPackageName);
            dest.writeString(mAttributionTag);
            dest.writeInt(mVirtualDeviceId);
            dest.writeString(mMessage);
            dest.writeBoolean(mShouldCollectAsyncNotedOp);
            dest.writeBoolean(mShouldCollectMessage);
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            NotedOp that = (NotedOp) o;
            return mOp == that.mOp && mUid == that.mUid && Objects.equals(mPackageName,
                    that.mPackageName) && Objects.equals(mAttributionTag, that.mAttributionTag)
                    && mVirtualDeviceId == that.mVirtualDeviceId && Objects.equals(mMessage,
                    that.mMessage) && Objects.equals(mShouldCollectAsyncNotedOp,
                    that.mShouldCollectAsyncNotedOp) && Objects.equals(mShouldCollectMessage,
                    that.mShouldCollectMessage);
        }

        @Override
        public int hashCode() {
            return Objects.hash(mOp, mUid, mPackageName, mAttributionTag, mVirtualDeviceId,
                    mMessage, mShouldCollectAsyncNotedOp, mShouldCollectMessage);
        }

        @Override
        public String toString() {
            return "NotedOp{" + "mOp=" + mOp + ", mUid=" + mUid + ", mPackageName=" + mPackageName
                    + ", mAttributionTag=" + mAttributionTag + ", mVirtualDeviceId="
                    + mVirtualDeviceId + ", mMessage=" + mMessage + ", mShouldCollectAsyncNotedOp="
                    + mShouldCollectAsyncNotedOp + ", mShouldCollectMessage="
                    + mShouldCollectMessage + "}";
        }


        public static final @NonNull Creator<NotedOp> CREATOR =
                new Creator<>() {
                    @Override public NotedOp createFromParcel(Parcel source) {
                        return new NotedOp(source);
                    }

                    @Override public NotedOp[] newArray(int size) {
                        return new NotedOp[size];
                    }
                };
    }

    /**
     * Computes the sum of the counts for the given flags in between the begin and
     * end UID states.
@@ -8126,9 +7979,6 @@ public class AppOpsManager {
    AppOpsManager(Context context, IAppOpsService service) {
        mContext = context;
        mService = service;
        mHandlerThread = new HandlerThread("AppOpsManager");
        mHandlerThread.start();
        mHandler = mHandlerThread.getThreadHandler();

        if (mContext != null) {
            final PackageManager pm = mContext.getPackageManager();
@@ -9465,64 +9315,7 @@ public class AppOpsManager {
                }
            }

            SyncNotedAppOp syncOp = null;
            boolean skipBinderCall = false;
            if (isNoteOpBatchingSupported()) {
                int mode = sAppOpModeCache.query(
                        new AppOpModeQuery(op, uid, packageName, virtualDeviceId, attributionTag,
                                "noteOpNoThrow"));
                // For FOREGROUND mode, we still need to make a binder call to the system service
                // to translate it to ALLOWED or IGNORED. So no batching is needed.
                if (mode != MODE_FOREGROUND) {
                    synchronized (mBatchedNoteOpLock) {
                        NotedOp notedOp = new NotedOp(op, uid, packageName, attributionTag,
                                virtualDeviceId, message, collectionMode == COLLECT_ASYNC,
                                shouldCollectMessage);

                        // Batch same noteOp calls and send them with their counters to the system
                        // service asynchronously. The time window for batching is specified in
                        // NOTE_OP_BATCHING_DELAY_MILLIS. Always allow the first noteOp call to go
                        // through binder API. Accumulate subsequent same noteOp calls during the
                        // time window in mPendingNotedOps.
                        if (!mPendingNotedOps.containsKey(notedOp)) {
                            mPendingNotedOps.put(notedOp, 0);
                        } else {
                            skipBinderCall = true;
                            mPendingNotedOps.merge(notedOp, 1, Integer::sum);
                        }

                        if (!mIsBatchedNoteOpCallScheduled) {
                            mHandler.postDelayed(() -> {
                                ArrayMap<NotedOp, Integer> pendingNotedOpsCopy;
                                synchronized(mBatchedNoteOpLock) {
                                    mIsBatchedNoteOpCallScheduled = false;
                                    pendingNotedOpsCopy =
                                            new ArrayMap<NotedOp, Integer>(mPendingNotedOps);
                                    mPendingNotedOps.clear();
                                }
                                for (int i = pendingNotedOpsCopy.size() - 1; i >= 0; i--) {
                                    if (pendingNotedOpsCopy.valueAt(i) == 0) {
                                        pendingNotedOpsCopy.removeAt(i);
                                    }
                                }
                                if (!pendingNotedOpsCopy.isEmpty()) {
                                    try {
                                        mService.noteOperationsInBatch(pendingNotedOpsCopy);
                                    } catch (RemoteException e) {
                                        throw e.rethrowFromSystemServer();
                                    }
                                }
                            }, NOTE_OP_BATCHING_DELAY_MILLIS);

                            mIsBatchedNoteOpCallScheduled = true;
                        }
                    }

                    syncOp = new SyncNotedAppOp(mode, op, attributionTag, packageName);
                }
            }

            if (!skipBinderCall) {
            SyncNotedAppOp syncOp;
            if (virtualDeviceId == Context.DEVICE_ID_DEFAULT) {
                syncOp = mService.noteOperation(op, uid, packageName, attributionTag,
                        collectionMode == COLLECT_ASYNC, message, shouldCollectMessage);
@@ -9531,8 +9324,6 @@ public class AppOpsManager {
                    virtualDeviceId, collectionMode == COLLECT_ASYNC, message,
                    shouldCollectMessage);
            }
            }

            if (syncOp.getOpMode() == MODE_ALLOWED) {
                if (collectionMode == COLLECT_SELF) {
                    collectNotedOpForSelf(syncOp);
+4 −4
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@ import com.android.internal.app.IAppOpsCallback;
import com.android.internal.util.function.DodecFunction;
import com.android.internal.util.function.HexConsumer;
import com.android.internal.util.function.HexFunction;
import com.android.internal.util.function.NonaFunction;
import com.android.internal.util.function.OctFunction;
import com.android.internal.util.function.QuadFunction;
import com.android.internal.util.function.UndecFunction;

@@ -86,9 +86,9 @@ public abstract class AppOpsManagerInternal {
         */
        SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName,
                @Nullable String featureId, int virtualDeviceId, boolean shouldCollectAsyncNotedOp,
                @Nullable String message, boolean shouldCollectMessage, int notedCount,
                @NonNull NonaFunction<Integer, Integer, String, String, Integer, Boolean, String,
                        Boolean, Integer, SyncNotedAppOp> superImpl);
                @Nullable String message, boolean shouldCollectMessage,
                @NonNull OctFunction<Integer, Integer, String, String, Integer, Boolean, String,
                        Boolean, SyncNotedAppOp> superImpl);

        /**
         * Allows overriding note proxy operation behavior.
+0 −1
Original line number Diff line number Diff line
@@ -163,5 +163,4 @@ interface IAppOpsService {
    void finishOperationForDevice(IBinder clientId, int code, int uid, String packageName,
            @nullable String attributionTag, int virtualDeviceId);
   List<AppOpsManager.PackageOps> getPackagesForOpsForDevice(in int[] ops, String persistentDeviceId);
   oneway void noteOperationsInBatch(in Map batchedNoteOps);
}
+39 −62
Original line number Diff line number Diff line
@@ -3191,7 +3191,7 @@ public class AppOpsService extends IAppOpsService.Stub {
                    resolveProxyPackageName, proxyAttributionTag, proxyVirtualDeviceId,
                    Process.INVALID_UID, null, null,
                    Context.DEVICE_ID_DEFAULT, proxyFlags, !isProxyTrusted,
                    "proxy " + message, shouldCollectMessage, 1);
                    "proxy " + message, shouldCollectMessage);
            if (proxyReturn.getOpMode() != AppOpsManager.MODE_ALLOWED) {
                return new SyncNotedAppOp(proxyReturn.getOpMode(), code, proxiedAttributionTag,
                        proxiedPackageName);
@@ -3210,20 +3210,7 @@ public class AppOpsService extends IAppOpsService.Stub {
        return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
                proxiedAttributionTag, proxiedVirtualDeviceId, proxyUid, resolveProxyPackageName,
                proxyAttributionTag, proxyVirtualDeviceId, proxiedFlags, shouldCollectAsyncNotedOp,
                message, shouldCollectMessage, 1);
    }

    @Override
    public void noteOperationsInBatch(Map batchedNoteOps) {
        for (var entry : ((Map<AppOpsManager.NotedOp, Integer>) batchedNoteOps).entrySet()) {
            AppOpsManager.NotedOp notedOp = entry.getKey();
            int notedCount = entry.getValue();
            mCheckOpsDelegateDispatcher.noteOperation(
                    notedOp.getOp(), notedOp.getUid(), notedOp.getPackageName(),
                    notedOp.getAttributionTag(), notedOp.getVirtualDeviceId(),
                    notedOp.getShouldCollectAsyncNotedOp(), notedOp.getMessage(),
                    notedOp.getShouldCollectMessage(), notedCount);
        }
                message, shouldCollectMessage);
    }

    @Override
@@ -3241,7 +3228,7 @@ public class AppOpsService extends IAppOpsService.Stub {
        }
        return mCheckOpsDelegateDispatcher.noteOperation(code, uid, packageName,
                attributionTag, Context.DEVICE_ID_DEFAULT, shouldCollectAsyncNotedOp, message,
                shouldCollectMessage, 1);
                shouldCollectMessage);
    }

    @Override
@@ -3250,12 +3237,13 @@ public class AppOpsService extends IAppOpsService.Stub {
            String message, boolean shouldCollectMessage) {
        return mCheckOpsDelegateDispatcher.noteOperation(code, uid, packageName,
                attributionTag, virtualDeviceId, shouldCollectAsyncNotedOp, message,
                shouldCollectMessage, 1);
                shouldCollectMessage);
    }

    private SyncNotedAppOp noteOperationImpl(int code, int uid, @Nullable String packageName,
            @Nullable String attributionTag, int virtualDeviceId, boolean shouldCollectAsyncNotedOp,
            @Nullable String message, boolean shouldCollectMessage, int notedCount) {
             @Nullable String attributionTag, int virtualDeviceId,
             boolean shouldCollectAsyncNotedOp, @Nullable String message,
             boolean shouldCollectMessage) {
        String resolvedPackageName;
        if (!shouldUseNewCheckOp()) {
            verifyIncomingUid(uid);
@@ -3290,14 +3278,14 @@ public class AppOpsService extends IAppOpsService.Stub {
        return noteOperationUnchecked(code, uid, resolvedPackageName, attributionTag,
                virtualDeviceId, Process.INVALID_UID, null, null,
                Context.DEVICE_ID_DEFAULT, AppOpsManager.OP_FLAG_SELF, shouldCollectAsyncNotedOp,
                message, shouldCollectMessage, notedCount);
                message, shouldCollectMessage);
    }

    private SyncNotedAppOp noteOperationUnchecked(int code, int uid, @NonNull String packageName,
            @Nullable String attributionTag, int virtualDeviceId, int proxyUid,
            String proxyPackageName, @Nullable String proxyAttributionTag, int proxyVirtualDeviceId,
            @OpFlags int flags, boolean shouldCollectAsyncNotedOp, @Nullable String message,
            boolean shouldCollectMessage, int notedCount) {
            boolean shouldCollectMessage) {
        PackageVerificationResult pvr;
        try {
            pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName);
@@ -3400,11 +3388,11 @@ public class AppOpsService extends IAppOpsService.Stub {
                    virtualDeviceId, flags, AppOpsManager.MODE_ALLOWED);

            attributedOp.accessed(proxyUid, proxyPackageName, proxyAttributionTag,
                    getPersistentId(proxyVirtualDeviceId), uidState.getState(), flags, notedCount);
                    getPersistentId(proxyVirtualDeviceId), uidState.getState(), flags);

            if (shouldCollectAsyncNotedOp) {
                collectAsyncNotedOp(uid, packageName, code, attributionTag, flags, message,
                        shouldCollectMessage, notedCount);
                        shouldCollectMessage);
            }

            return new SyncNotedAppOp(AppOpsManager.MODE_ALLOWED, code, attributionTag,
@@ -3563,7 +3551,7 @@ public class AppOpsService extends IAppOpsService.Stub {
     */
    private void collectAsyncNotedOp(int uid, @NonNull String packageName, int opCode,
            @Nullable String attributionTag, @OpFlags int flags, @NonNull String message,
            boolean shouldCollectMessage, int notedCount) {
            boolean shouldCollectMessage) {
        Objects.requireNonNull(message);

        int callingUid = Binder.getCallingUid();
@@ -3571,42 +3559,34 @@ public class AppOpsService extends IAppOpsService.Stub {
        final long token = Binder.clearCallingIdentity();
        try {
            synchronized (this) {
                Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);

                RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
                AsyncNotedAppOp asyncNotedOp = new AsyncNotedAppOp(opCode, callingUid,
                        attributionTag, message, System.currentTimeMillis());
                final boolean[] wasNoteForwarded = {false};

                if ((flags & (OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED)) != 0
                        && shouldCollectMessage) {
                    reportRuntimeAppOpAccessMessageAsyncLocked(uid, packageName, opCode,
                            attributionTag, message);
                }

                Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
                RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
                if (callbacks == null) {
                    return;
                }

                final boolean[] wasNoteForwarded = {false};
                if (Flags.rateLimitBatchedNoteOpAsyncCallbacksEnabled()) {
                    notedCount = 1;
                }

                for (int i = 0; i < notedCount; i++) {
                    AsyncNotedAppOp asyncNotedOp = new AsyncNotedAppOp(opCode, callingUid,
                            attributionTag, message, System.currentTimeMillis());
                    wasNoteForwarded[0] = false;
                if (callbacks != null) {
                    callbacks.broadcast((cb) -> {
                        try {
                            cb.opNoted(asyncNotedOp);
                            wasNoteForwarded[0] = true;
                        } catch (RemoteException e) {
                            Slog.e(TAG,
                                    "Could not forward noteOp of " + opCode + " to "
                                            + packageName
                                    "Could not forward noteOp of " + opCode + " to " + packageName
                                            + "/" + uid + "(" + attributionTag + ")", e);
                        }
                    });
                }

                if (!wasNoteForwarded[0]) {
                        ArrayList<AsyncNotedAppOp> unforwardedOps = mUnforwardedAsyncNotedOps.get(
                                key);
                    ArrayList<AsyncNotedAppOp> unforwardedOps = mUnforwardedAsyncNotedOps.get(key);
                    if (unforwardedOps == null) {
                        unforwardedOps = new ArrayList<>(1);
                        mUnforwardedAsyncNotedOps.put(key, unforwardedOps);
@@ -3618,7 +3598,6 @@ public class AppOpsService extends IAppOpsService.Stub {
                    }
                }
            }
            }
        } finally {
            Binder.restoreCallingIdentity(token);
        }
@@ -4047,7 +4026,7 @@ public class AppOpsService extends IAppOpsService.Stub {

        if (shouldCollectAsyncNotedOp && !isRestricted) {
            collectAsyncNotedOp(uid, packageName, code, attributionTag, AppOpsManager.OP_FLAG_SELF,
                    message, shouldCollectMessage, 1);
                    message, shouldCollectMessage);
        }

        return new SyncNotedAppOp(isRestricted ? MODE_IGNORED : MODE_ALLOWED, code, attributionTag,
@@ -7595,36 +7574,34 @@ public class AppOpsService extends IAppOpsService.Stub {

        public SyncNotedAppOp noteOperation(int code, int uid, String packageName,
                String attributionTag, int virtualDeviceId, boolean shouldCollectAsyncNotedOp,
                String message, boolean shouldCollectMessage, int notedCount) {
                String message, boolean shouldCollectMessage) {
            if (mPolicy != null) {
                if (mCheckOpsDelegate != null) {
                    return mPolicy.noteOperation(code, uid, packageName, attributionTag,
                            virtualDeviceId, shouldCollectAsyncNotedOp, message,
                            shouldCollectMessage, notedCount, this::noteDelegateOperationImpl
                            shouldCollectMessage, this::noteDelegateOperationImpl
                    );
                } else {
                    return mPolicy.noteOperation(code, uid, packageName, attributionTag,
                            virtualDeviceId, shouldCollectAsyncNotedOp, message,
                            shouldCollectMessage, notedCount, AppOpsService.this::noteOperationImpl
                            shouldCollectMessage, AppOpsService.this::noteOperationImpl
                    );
                }
            } else if (mCheckOpsDelegate != null) {
                return noteDelegateOperationImpl(code, uid, packageName, attributionTag,
                        virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
                        notedCount);
                        virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage);
            }
            return noteOperationImpl(code, uid, packageName, attributionTag,
                    virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
                    notedCount);
                    virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage);
        }

        private SyncNotedAppOp noteDelegateOperationImpl(int code, int uid,
                @Nullable String packageName, @Nullable String featureId, int virtualDeviceId,
                boolean shouldCollectAsyncNotedOp, @Nullable String message,
                boolean shouldCollectMessage, int notedCount) {
                boolean shouldCollectMessage) {
            return mCheckOpsDelegate.noteOperation(code, uid, packageName, featureId,
                    virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
                    notedCount, AppOpsService.this::noteOperationImpl
                    AppOpsService.this::noteOperationImpl
            );
        }

Loading