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

Commit 9cdcfd74 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Track active AttributionSources, and finish chains on death" into...

Merge "Track active AttributionSources, and finish chains on death" into sc-dev am: a4d18e76 am: 4e897cb0

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15312052

Change-Id: I336dd00509a58d0d8bf1eb7b8fd0c67d557a26fc
parents 8632467b 4e897cb0
Loading
Loading
Loading
Loading
+68 −5
Original line number Diff line number Diff line
@@ -172,6 +172,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
import java.util.WeakHashMap;
@@ -180,6 +181,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiFunction;

@@ -219,6 +221,10 @@ public class PermissionManagerService extends IPermissionManager.Stub {
    /** If the permission of the value is granted, so is the key */
    private static final Map<String, String> FULLER_PERMISSION_MAP = new HashMap<>();

    /** Map of IBinder -> Running AttributionSource */
    private static final ConcurrentHashMap<IBinder, RegisteredAttribution>
            sRunningAttributionSources = new ConcurrentHashMap<>();

    static {
        FULLER_PERMISSION_MAP.put(Manifest.permission.ACCESS_COARSE_LOCATION,
                Manifest.permission.ACCESS_FINE_LOCATION);
@@ -5555,8 +5561,15 @@ public class PermissionManagerService extends IPermissionManager.Stub {

        @Override
        public void finishDataDelivery(int op,
                @NonNull AttributionSourceState attributionSourceState, boolean fromDataSource) {
            finishDataDelivery(mContext, op, attributionSourceState,
                    fromDataSource);
        }

        private static void finishDataDelivery(Context context, int op,
                @NonNull AttributionSourceState attributionSourceState, boolean fromDatasource) {
            Objects.requireNonNull(attributionSourceState);
            AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);

            if (op == AppOpsManager.OP_NONE) {
                return;
@@ -5573,7 +5586,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
                // If the call is from a datasource we need to vet only the chain before it. This
                // way we can avoid the datasource creating an attribution context for every call.
                if (!(fromDatasource && current.asState() == attributionSourceState)
                        && next != null && !current.isTrusted(mContext)) {
                        && next != null && !current.isTrusted(context)) {
                    return;
                }

@@ -5589,20 +5602,20 @@ public class PermissionManagerService extends IPermissionManager.Stub {
                        ? current : next;

                if (selfAccess) {
                    final String resolvedPackageName = resolvePackageName(mContext, accessorSource);
                    final String resolvedPackageName = resolvePackageName(context, accessorSource);
                    if (resolvedPackageName == null) {
                        return;
                    }
                    mAppOpsManager.finishOp(accessorSource.getToken(), op,
                    appOpsManager.finishOp(accessorSource.getToken(), op,
                            accessorSource.getUid(), resolvedPackageName,
                            accessorSource.getAttributionTag());
                } else {
                    final AttributionSource resolvedAttributionSource =
                            resolveAttributionSource(mContext, accessorSource);
                            resolveAttributionSource(context, accessorSource);
                    if (resolvedAttributionSource.getPackageName() == null) {
                        return;
                    }
                    mAppOpsManager.finishProxyOp(AppOpsManager.opToPublicName(op),
                    appOpsManager.finishProxyOp(AppOpsManager.opToPublicName(op),
                            resolvedAttributionSource, skipCurrentFinish);
                }

@@ -5610,6 +5623,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
                    return;
                }

                RegisteredAttribution registered =
                        sRunningAttributionSources.remove(current.getToken());
                if (registered != null) {
                    registered.unregister();
                }
                current = next;
            }
        }
@@ -5827,6 +5845,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
                    }
                }

                if (startDataDelivery) {
                    RegisteredAttribution registered = new RegisteredAttribution(context, op,
                            current, fromDatasource);
                    sRunningAttributionSources.put(current.getToken(), registered);
                }

                if (next == null || next.getNext() == null) {
                    return PermissionChecker.PERMISSION_GRANTED;
                }
@@ -6153,4 +6177,43 @@ public class PermissionManagerService extends IPermissionManager.Stub {
                    attributionSource));
        }
    }

    private static final class RegisteredAttribution {
        private final DeathRecipient mDeathRecipient;
        private final IBinder mToken;
        private final AtomicBoolean mFinished;

        RegisteredAttribution(Context context, int op, AttributionSource source,
                boolean fromDatasource) {
            mFinished = new AtomicBoolean(false);
            mDeathRecipient = () -> {
                if (unregister()) {
                    PermissionCheckerService
                            .finishDataDelivery(context, op, source.asState(), fromDatasource);
                }
            };
            mToken = source.getToken();
            if (mToken != null) {
                try {
                    mToken.linkToDeath(mDeathRecipient, 0);
                } catch (RemoteException e) {
                    mDeathRecipient.binderDied();
                }
            }
        }

        public boolean unregister() {
            if (mFinished.compareAndSet(false, true)) {
                try {
                    if (mToken != null) {
                        mToken.unlinkToDeath(mDeathRecipient, 0);
                    }
                } catch (NoSuchElementException e) {
                    // do nothing
                }
                return true;
            }
            return false;
        }
    }
}