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

Commit f5c4aa12 authored by Soonil Nagarkar's avatar Soonil Nagarkar Committed by Android (Google) Code Review
Browse files

Merge "Refactor listener multiplexer"

parents 8b492aef b219baa0
Loading
Loading
Loading
Loading
+27 −2
Original line number Diff line number Diff line
@@ -124,15 +124,22 @@ public final class CallerIdentity {
                packageName, attributionTag, listenerId);
    }

    // in some tests these constants are loaded too early leading to an "incorrect" view of the
    // current pid and uid. load lazily to prevent this problem in tests.
    private static class Loader {
        private static final int MY_UID = Process.myUid();
        private static final int MY_PID = Process.myPid();
    }

    private final int mUid;

    private final int mPid;

    private final String mPackageName;

    private final @Nullable String mAttributionTag;
    @Nullable private final String mAttributionTag;

    private final @Nullable String mListenerId;
    @Nullable private final String mListenerId;

    private CallerIdentity(int uid, int pid, String packageName,
            @Nullable String attributionTag, @Nullable String listenerId) {
@@ -181,6 +188,24 @@ public final class CallerIdentity {
        return mUid == Process.SYSTEM_UID;
    }

    /** Returns true if this identity represents the same user this code is running in. */
    public boolean isMyUser() {
        return UserHandle.getUserId(mUid) == UserHandle.getUserId(Loader.MY_UID);
    }

    /** Returns true if this identity represents the same uid this code is running in. */
    public boolean isMyUid() {
        return mUid == Loader.MY_UID;
    }

    /**
     * Returns true if this identity represents the same process this code is running in. Returns
     * false if the identity process is unknown.
     */
    public boolean isMyProcess() {
        return mPid == Loader.MY_PID;
    }

    /**
     * Adds this identity to the worksource supplied, or if not worksource is supplied, creates a
     * new worksource representing this identity.
+3 −0
Original line number Diff line number Diff line
@@ -26,8 +26,10 @@ import android.app.AppOpsManager;
import android.content.Context;
import android.os.Binder;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/** Utility class for dealing with location permissions. */
public final class LocationPermissions {
@@ -49,6 +51,7 @@ public final class LocationPermissions {
     */
    public static final int PERMISSION_FINE = 2;

    @Target(ElementType.TYPE_USE)
    @IntDef({PERMISSION_NONE, PERMISSION_COARSE, PERMISSION_FINE})
    @Retention(RetentionPolicy.SOURCE)
    public @interface PermissionLevel {}
+0 −60
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.location.geofence;

import android.app.PendingIntent;
import android.location.Geofence;

import com.android.server.location.listeners.PendingIntentListenerRegistration;

import java.util.Objects;

// geofencing unfortunately allows multiple geofences under the same pending intent, even though
// this makes no real sense. therefore we manufacture an artificial key to use (pendingintent +
// geofence) instead of (pendingintent).
final class GeofenceKey  implements PendingIntentListenerRegistration.PendingIntentKey {

    private final PendingIntent mPendingIntent;
    private final Geofence mGeofence;

    GeofenceKey(PendingIntent pendingIntent, Geofence geofence) {
        mPendingIntent = Objects.requireNonNull(pendingIntent);
        mGeofence = Objects.requireNonNull(geofence);
    }

    @Override
    public PendingIntent getPendingIntent() {
        return mPendingIntent;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof GeofenceKey)) {
            return false;
        }
        GeofenceKey that = (GeofenceKey) o;
        return mPendingIntent.equals(that.mPendingIntent) && mGeofence.equals(that.mGeofence);
    }

    @Override
    public int hashCode() {
        return mPendingIntent.hashCode();
    }
}
+81 −28
Original line number Diff line number Diff line
@@ -59,8 +59,8 @@ import java.util.Objects;
 * Manages all geofences.
 */
public class GeofenceManager extends
        ListenerMultiplexer<GeofenceKey, PendingIntent, GeofenceManager.GeofenceRegistration,
                LocationRequest> implements
        ListenerMultiplexer<GeofenceManager.GeofenceKey, PendingIntent,
                GeofenceManager.GeofenceRegistration, LocationRequest> implements
        LocationListener {

    private static final String TAG = "GeofenceManager";
@@ -73,13 +73,49 @@ public class GeofenceManager extends
    private static final long MAX_LOCATION_AGE_MS = 5 * 60 * 1000L; // five minutes
    private static final long MAX_LOCATION_INTERVAL_MS = 2 * 60 * 60 * 1000; // two hours

    protected final class GeofenceRegistration extends
            PendingIntentListenerRegistration<Geofence, PendingIntent> {
    // geofencing unfortunately allows multiple geofences under the same pending intent, even though
    // this makes no real sense. therefore we manufacture an artificial key to use (pendingintent +
    // geofence) instead of (pendingintent).
    static class GeofenceKey {

        private final PendingIntent mPendingIntent;
        private final Geofence mGeofence;

        GeofenceKey(PendingIntent pendingIntent, Geofence geofence) {
            mPendingIntent = Objects.requireNonNull(pendingIntent);
            mGeofence = Objects.requireNonNull(geofence);
        }

        public PendingIntent getPendingIntent() {
            return mPendingIntent;
        }

        @Override
        public boolean equals(Object o) {
            if (o instanceof GeofenceKey) {
                GeofenceKey that = (GeofenceKey) o;
                return mPendingIntent.equals(that.mPendingIntent) && mGeofence.equals(
                        that.mGeofence);
            }

            return false;
        }

        @Override
        public int hashCode() {
            return mPendingIntent.hashCode();
        }
    }

    protected class GeofenceRegistration extends
            PendingIntentListenerRegistration<GeofenceKey, PendingIntent> {

        private static final int STATE_UNKNOWN = 0;
        private static final int STATE_INSIDE = 1;
        private static final int STATE_OUTSIDE = 2;

        private final Geofence mGeofence;
        private final CallerIdentity mIdentity;
        private final Location mCenter;
        private final PowerManager.WakeLock mWakeLock;

@@ -89,13 +125,15 @@ public class GeofenceManager extends
        // spam us, and because checking the values may be more expensive
        private boolean mPermitted;

        private @Nullable Location mCachedLocation;
        @Nullable private Location mCachedLocation;
        private float mCachedLocationDistanceM;

        protected GeofenceRegistration(Geofence geofence, CallerIdentity identity,
        GeofenceRegistration(Geofence geofence, CallerIdentity identity,
                PendingIntent pendingIntent) {
            super(geofence, identity, pendingIntent);
            super(pendingIntent);

            mGeofence = geofence;
            mIdentity = identity;
            mCenter = new Location("");
            mCenter.setLatitude(geofence.getLatitude());
            mCenter.setLongitude(geofence.getLongitude());
@@ -107,16 +145,36 @@ public class GeofenceManager extends
            mWakeLock.setWorkSource(identity.addToWorkSource(null));
        }

        public Geofence getGeofence() {
            return mGeofence;
        }

        public CallerIdentity getIdentity() {
            return mIdentity;
        }

        @Override
        public String getTag() {
            return TAG;
        }

        @Override
        protected PendingIntent getPendingIntentFromKey(GeofenceKey geofenceKey) {
            return geofenceKey.getPendingIntent();
        }

        @Override
        protected GeofenceManager getOwner() {
            return GeofenceManager.this;
        }

        @Override
        protected void onPendingIntentListenerRegister() {
        protected void onRegister() {
            super.onRegister();

            mGeofenceState = STATE_UNKNOWN;
            mPermitted = mLocationPermissionsHelper.hasLocationPermissions(PERMISSION_FINE,
                    getIdentity());
                    mIdentity);
        }

        @Override
@@ -132,7 +190,7 @@ public class GeofenceManager extends
        }

        boolean onLocationPermissionsChanged(@Nullable String packageName) {
            if (packageName == null || getIdentity().getPackageName().equals(packageName)) {
            if (packageName == null || mIdentity.getPackageName().equals(packageName)) {
                return onLocationPermissionsChanged();
            }

@@ -140,7 +198,7 @@ public class GeofenceManager extends
        }

        boolean onLocationPermissionsChanged(int uid) {
            if (getIdentity().getUid() == uid) {
            if (mIdentity.getUid() == uid) {
                return onLocationPermissionsChanged();
            }

@@ -149,7 +207,7 @@ public class GeofenceManager extends

        private boolean onLocationPermissionsChanged() {
            boolean permitted = mLocationPermissionsHelper.hasLocationPermissions(PERMISSION_FINE,
                    getIdentity());
                    mIdentity);
            if (permitted != mPermitted) {
                mPermitted = permitted;
                return true;
@@ -164,12 +222,12 @@ public class GeofenceManager extends
                mCachedLocationDistanceM = mCenter.distanceTo(mCachedLocation);
            }

            return Math.abs(getRequest().getRadius() - mCachedLocationDistanceM);
            return Math.abs(mGeofence.getRadius() - mCachedLocationDistanceM);
        }

        ListenerOperation<PendingIntent> onLocationChanged(Location location) {
            // remove expired fences
            if (getRequest().isExpired()) {
            if (mGeofence.isExpired()) {
                remove();
                return null;
            }
@@ -178,7 +236,7 @@ public class GeofenceManager extends
            mCachedLocationDistanceM = mCenter.distanceTo(mCachedLocation);

            int oldState = mGeofenceState;
            float radius = Math.max(getRequest().getRadius(), location.getAccuracy());
            float radius = Math.max(mGeofence.getRadius(), location.getAccuracy());
            if (mCachedLocationDistanceM <= radius) {
                mGeofenceState = STATE_INSIDE;
                if (oldState != STATE_INSIDE) {
@@ -206,14 +264,14 @@ public class GeofenceManager extends
                        null, null, PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
            } catch (PendingIntent.CanceledException e) {
                mWakeLock.release();
                removeRegistration(new GeofenceKey(pendingIntent, getRequest()), this);
                removeRegistration(new GeofenceKey(pendingIntent, mGeofence), this);
            }
        }

        @Override
        public String toString() {
            StringBuilder builder = new StringBuilder();
            builder.append(getIdentity());
            builder.append(mIdentity);

            ArraySet<String> flags = new ArraySet<>(1);
            if (!mPermitted) {
@@ -223,7 +281,7 @@ public class GeofenceManager extends
                builder.append(" ").append(flags);
            }

            builder.append(" ").append(getRequest());
            builder.append(" ").append(mGeofence);
            return builder.toString();
        }
    }
@@ -258,10 +316,10 @@ public class GeofenceManager extends
    protected final LocationUsageLogger mLocationUsageLogger;

    @GuardedBy("mLock")
    private @Nullable LocationManager mLocationManager;
    @Nullable private LocationManager mLocationManager;

    @GuardedBy("mLock")
    private @Nullable Location mLastLocation;
    @Nullable private Location mLastLocation;

    public GeofenceManager(Context context, Injector injector) {
        mContext = context.createAttributionContext(ATTRIBUTION_TAG);
@@ -271,11 +329,6 @@ public class GeofenceManager extends
        mLocationUsageLogger = injector.getLocationUsageLogger();
    }

    @Override
    public String getTag() {
        return TAG;
    }

    private LocationManager getLocationManager() {
        synchronized (mLock) {
            if (mLocationManager == null) {
@@ -375,7 +428,7 @@ public class GeofenceManager extends
                /* LocationRequest= */ null,
                /* hasListener= */ false,
                true,
                registration.getRequest(), true);
                registration.getGeofence(), true);
    }

    @Override
@@ -389,7 +442,7 @@ public class GeofenceManager extends
                /* LocationRequest= */ null,
                /* hasListener= */ false,
                true,
                registration.getRequest(), true);
                registration.getGeofence(), true);
    }

    @Override
@@ -417,7 +470,7 @@ public class GeofenceManager extends
        WorkSource workSource = null;
        double minFenceDistanceM = Double.MAX_VALUE;
        for (GeofenceRegistration registration : registrations) {
            if (registration.getRequest().isExpired(realtimeMs)) {
            if (registration.getGeofence().isExpired(realtimeMs)) {
                continue;
            }

+23 −8
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.location.gnss;

import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
import static com.android.server.location.gnss.GnssManagerService.TAG;

import android.annotation.Nullable;
@@ -25,6 +26,7 @@ import android.location.util.identity.CallerIdentity;
import android.os.Binder;
import android.os.IBinder;

import com.android.server.FgThread;
import com.android.server.location.gnss.hal.GnssNative;
import com.android.server.location.listeners.BinderListenerRegistration;
import com.android.server.location.listeners.ListenerMultiplexer;
@@ -45,17 +47,35 @@ public class GnssAntennaInfoProvider extends
     * Registration object for GNSS listeners.
     */
    protected class AntennaInfoListenerRegistration extends
            BinderListenerRegistration<Void, IGnssAntennaInfoListener> {
            BinderListenerRegistration<IBinder, IGnssAntennaInfoListener> {

        protected AntennaInfoListenerRegistration(CallerIdentity callerIdentity,
        private final CallerIdentity mIdentity;

        protected AntennaInfoListenerRegistration(CallerIdentity identity,
                IGnssAntennaInfoListener listener) {
            super(null, callerIdentity, listener);
            super(identity.isMyProcess() ? FgThread.getExecutor() : DIRECT_EXECUTOR, listener);
            mIdentity = identity;
        }

        @Override
        protected String getTag() {
            return TAG;
        }

        @Override
        protected GnssAntennaInfoProvider getOwner() {
            return GnssAntennaInfoProvider.this;
        }

        @Override
        protected IBinder getBinderFromKey(IBinder key) {
            return key;
        }

        @Override
        public String toString() {
            return mIdentity.toString();
        }
    }

    private final GnssNative mGnssNative;
@@ -72,11 +92,6 @@ public class GnssAntennaInfoProvider extends
        return mAntennaInfos;
    }

    @Override
    public String getTag() {
        return TAG;
    }

    public boolean isSupported() {
        return mGnssNative.isAntennaInfoSupported();
    }
Loading