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

Commit b2807a26 authored by Soonil Nagarkar's avatar Soonil Nagarkar
Browse files

Reorder multiplexer class hierarchy

Reorders the class hierarchy so that java classes are separate from
more android dependent classes. This allows us to move binder state
management out of the multiplexer and into the subclasses which have
more knowledge of what the appropriate state is. As a result, fixes
a wakelock bug where release() was failing due to an inappropriate
binder identity.

Also fixes up and updates javadocs on multiplexer classes.

Bug: 164572028
Test: manual + presubmits
Change-Id: I9dde695ab24c09657f856405c6c24132bdcb76d1
parent 1a1eccf5
Loading
Loading
Loading
Loading
+11 −19
Original line number Diff line number Diff line
@@ -1133,9 +1133,7 @@ public class LocationManagerService extends ILocationManager.Stub {
            return;
        }

        String dumpFilter = args.length == 0 ? null : args[0];

        ipw.println("Location Manager State:");
        ipw.print("Location Manager State:");
        ipw.increaseIndent();
        ipw.println("Elapsed Realtime: " + TimeUtils.formatDuration(SystemClock.elapsedRealtime()));

@@ -1173,28 +1171,22 @@ public class LocationManagerService extends ILocationManager.Stub {
        ipw.println("Location Providers:");
        ipw.increaseIndent();
        for (LocationProviderManager manager : mProviderManagers) {
            if (dumpFilter == null || manager.getName().equals(dumpFilter)) {
            manager.dump(fd, ipw, args);
        }
        }
        ipw.decreaseIndent();

        if (dumpFilter == null || GPS_PROVIDER.equals(dumpFilter)) {
        if (mGnssManagerService != null) {
            ipw.println("GNSS Manager:");
            ipw.increaseIndent();
            mGnssManagerService.dump(fd, ipw, args);
            ipw.decreaseIndent();
        }
        }

        if (dumpFilter == null || "geofence".equals(dumpFilter)) {
        ipw.println("Geofence Manager:");
        ipw.increaseIndent();
        mGeofenceManager.dump(fd, ipw, args);
        ipw.decreaseIndent();
    }
    }

    private class LocalService extends LocationManagerInternal {

+160 −57
Original line number Diff line number Diff line
@@ -84,7 +84,7 @@ import com.android.server.LocalServices;
import com.android.server.PendingIntentUtils;
import com.android.server.location.LocationPermissions.PermissionLevel;
import com.android.server.location.listeners.ListenerMultiplexer;
import com.android.server.location.listeners.RemovableListenerRegistration;
import com.android.server.location.listeners.RemoteListenerRegistration;
import com.android.server.location.util.AppForegroundHelper;
import com.android.server.location.util.AppForegroundHelper.AppForegroundListener;
import com.android.server.location.util.AppOpsHelper;
@@ -154,15 +154,8 @@ class LocationProviderManager extends

        @Override
        public void deliverOnLocationChanged(Location location,
                @Nullable Runnable onCompleteCallback)
                throws RemoteException {
            mListener.onLocationChanged(location,
                    onCompleteCallback == null ? null : new IRemoteCallback.Stub() {
                        @Override
                        public void sendResult(Bundle data) {
                            onCompleteCallback.run();
                        }
                    });
                @Nullable Runnable onCompleteCallback) throws RemoteException {
            mListener.onLocationChanged(location, SingleUseCallback.wrap(onCompleteCallback));
        }

        @Override
@@ -221,7 +214,7 @@ class LocationProviderManager extends
    }

    protected abstract class Registration extends
            RemovableListenerRegistration<LocationRequest, LocationTransport> {
            RemoteListenerRegistration<LocationRequest, LocationTransport> {

        @PermissionLevel protected final int mPermissionLevel;
        private final WorkSource mWorkSource;
@@ -306,11 +299,12 @@ class LocationProviderManager extends
        }

        @Override
        protected final void onInactive() {
        protected final ListenerOperation<LocationTransport> onInactive() {
            onHighPowerUsageChanged();
            if (!getRequest().getHideFromAppOps()) {
                mLocationAttributionHelper.reportLocationStop(getIdentity(), getName(), getKey());
            }
            return null;
        }

        @Override
@@ -826,6 +820,12 @@ class LocationProviderManager extends
        @GuardedBy("mLock")
        @Override
        protected void onProviderListenerRegister() {
            try {
                ((IBinder) getKey()).linkToDeath(this, 0);
            } catch (RemoteException e) {
                remove();
            }

            mExpirationRealtimeMs = getRequest().getExpirationRealtimeMs(
                    SystemClock.elapsedRealtime());

@@ -837,12 +837,6 @@ class LocationProviderManager extends
                        0, this, FgThread.getHandler(), getWorkSource());
            }

            try {
                ((IBinder) getKey()).linkToDeath(this, 0);
            } catch (RemoteException e) {
                remove();
            }

            // start listening for provider enabled/disabled events
            addEnabledListener(this);

@@ -1066,8 +1060,13 @@ class LocationProviderManager extends
            mUserInfoHelper.addListener(mUserChangedListener);
            mSettingsHelper.addOnLocationEnabledChangedListener(mLocationEnabledChangedListener);

            long identity = Binder.clearCallingIdentity();
            try {
                // initialize enabled state
                onUserStarted(UserHandle.USER_ALL);
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }
    }

@@ -1077,10 +1076,15 @@ class LocationProviderManager extends
            mSettingsHelper.removeOnLocationEnabledChangedListener(mLocationEnabledChangedListener);

            // notify and remove all listeners
            long identity = Binder.clearCallingIdentity();
            try {
                onUserStopped(UserHandle.USER_ALL);
                removeRegistrationIf(key -> true);
            mEnabledListeners.clear();
            } finally {
                Binder.restoreCallingIdentity(identity);
            }

            mEnabledListeners.clear();
            mStarted = false;
        }
    }
@@ -1141,14 +1145,26 @@ class LocationProviderManager extends
    public void setRealProvider(AbstractLocationProvider provider) {
        synchronized (mLock) {
            Preconditions.checkState(mStarted);

            long identity = Binder.clearCallingIdentity();
            try {
                mProvider.setRealProvider(provider);
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }
    }

    public void setMockProvider(@Nullable MockProvider provider) {
        synchronized (mLock) {
            Preconditions.checkState(mStarted);

            long identity = Binder.clearCallingIdentity();
            try {
                mProvider.setMockProvider(provider);
            } finally {
                Binder.restoreCallingIdentity(identity);
            }

            // when removing a mock provider, also clear any mock last locations and reset the
            // location fudger. the mock provider could have been used to infer the current
@@ -1170,7 +1186,12 @@ class LocationProviderManager extends
                throw new IllegalArgumentException(mName + " provider is not a test provider");
            }

            long identity = Binder.clearCallingIdentity();
            try {
                mProvider.setMockProviderAllowed(enabled);
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }
    }

@@ -1180,6 +1201,8 @@ class LocationProviderManager extends
                throw new IllegalArgumentException(mName + " provider is not a test provider");
            }

            long identity = Binder.clearCallingIdentity();
            try {
                String locationProvider = location.getProvider();
                if (!TextUtils.isEmpty(locationProvider) && !mName.equals(locationProvider)) {
                    // The location has an explicit provider that is different from the mock
@@ -1189,6 +1212,9 @@ class LocationProviderManager extends
                }

                mProvider.setMockProviderLocation(location);
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }
    }

@@ -1279,7 +1305,7 @@ class LocationProviderManager extends
        }
    }

    public void getCurrentLocation(LocationRequest request, CallerIdentity identity,
    public void getCurrentLocation(LocationRequest request, CallerIdentity callerIdentity,
            int permissionLevel, ICancellationSignal cancellationTransport,
            ILocationCallback callback) {
        Preconditions.checkArgument(mName.equals(request.getProvider()));
@@ -1291,12 +1317,12 @@ class LocationProviderManager extends
        GetCurrentLocationListenerRegistration registration =
                new GetCurrentLocationListenerRegistration(
                        request,
                        identity,
                        callerIdentity,
                        new GetCurrentLocationTransport(callback),
                        permissionLevel);

        synchronized (mLock) {
            Location lastLocation = getLastLocation(request, identity, permissionLevel);
            Location lastLocation = getLastLocation(request, callerIdentity, permissionLevel);
            if (lastLocation != null) {
                long locationAgeMs = NANOSECONDS.toMillis(
                        SystemClock.elapsedRealtimeNanos()
@@ -1314,7 +1340,13 @@ class LocationProviderManager extends
            }

            // if last location isn't good enough then we add a location request
            long identity = Binder.clearCallingIdentity();
            try {
                addRegistration(callback.asBinder(), registration);
            } finally {
                Binder.restoreCallingIdentity(identity);
            }

            CancellationSignal cancellationSignal = CancellationSignal.fromTransport(
                    cancellationTransport);
            if (cancellationSignal != null) {
@@ -1329,48 +1361,73 @@ class LocationProviderManager extends
    }

    public void sendExtraCommand(int uid, int pid, String command, Bundle extras) {
        long identity = Binder.clearCallingIdentity();
        try {
            mProvider.sendExtraCommand(uid, pid, command, extras);
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }

    public void registerLocationRequest(LocationRequest request, CallerIdentity identity,
    public void registerLocationRequest(LocationRequest request, CallerIdentity callerIdentity,
            @PermissionLevel int permissionLevel, ILocationListener listener) {
        Preconditions.checkArgument(mName.equals(request.getProvider()));

        synchronized (mLock) {
            long identity = Binder.clearCallingIdentity();
            try {
                addRegistration(
                        listener.asBinder(),
                        new LocationListenerRegistration(
                                request,
                            identity,
                                callerIdentity,
                                new LocationListenerTransport(listener),
                                permissionLevel));
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }
    }

    public void registerLocationRequest(LocationRequest request, CallerIdentity identity,
    public void registerLocationRequest(LocationRequest request, CallerIdentity callerIdentity,
            @PermissionLevel int permissionLevel, PendingIntent pendingIntent) {
        Preconditions.checkArgument(mName.equals(request.getProvider()));

        synchronized (mLock) {
            long identity = Binder.clearCallingIdentity();
            try {
                addRegistration(
                        pendingIntent,
                        new LocationPendingIntentRegistration(
                                request,
                            identity,
                                callerIdentity,
                                new LocationPendingIntentTransport(mContext, pendingIntent),
                                permissionLevel));
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }
    }

    public void unregisterLocationRequest(ILocationListener listener) {
        synchronized (mLock) {
            long identity = Binder.clearCallingIdentity();
            try {
                removeRegistration(listener.asBinder());
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }
    }

    public void unregisterLocationRequest(PendingIntent pendingIntent) {
        synchronized (mLock) {
            long identity = Binder.clearCallingIdentity();
            try {
                removeRegistration(pendingIntent);
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }
    }

@@ -1958,4 +2015,50 @@ class LocationProviderManager extends
            }
        }
    }

    private static class SingleUseCallback extends IRemoteCallback.Stub {

        @Nullable
        public static IRemoteCallback wrap(@Nullable Runnable callback) {
            return callback == null ? null : new SingleUseCallback(callback);
        }

        @GuardedBy("this")
        @Nullable private Runnable mCallback;

        private SingleUseCallback(Runnable callback) {
            mCallback = Objects.requireNonNull(callback);
        }

        @Override
        public void sendResult(Bundle data) {
            Runnable callback;
            synchronized (this) {
                callback = mCallback;
                mCallback = null;
            }

            // prevent this callback from being run more than once - otherwise this could provide an
            // attack vector for a malicious app to break assumptions on how many times a callback
            // may be invoked, and thus crash system server.
            if (callback == null) {
                return;
            }

            long identity = Binder.clearCallingIdentity();
            try {
                callback.run();
            } catch (RuntimeException e) {
                // since this is within a oneway binder transaction there is nowhere
                // for exceptions to go - move onto another thread to crash system
                // server so we find out about it
                FgThread.getExecutor().execute(() -> {
                    throw new AssertionError(e);
                });
                throw e;
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }
    }
}
+17 −5
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationRequest;
import android.location.util.identity.CallerIdentity;
import android.os.Binder;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.WorkSource;
@@ -291,17 +292,28 @@ public class GeofenceManager extends
            @Nullable String attributionTag) {
        LocationPermissions.enforceCallingOrSelfLocationPermission(mContext, PERMISSION_FINE);

        CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
                AppOpsManager.toReceiverId(pendingIntent));
        CallerIdentity callerIdentity = CallerIdentity.fromBinder(mContext, packageName,
                attributionTag, AppOpsManager.toReceiverId(pendingIntent));

        long identity = Binder.clearCallingIdentity();
        try {
            addRegistration(new GeofenceKey(pendingIntent, geofence),
                new GeofenceRegistration(geofence, identity, pendingIntent));
                    new GeofenceRegistration(geofence, callerIdentity, pendingIntent));
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }

    /**
     * Removes the geofence associated with the PendingIntent.
     */
    public void removeGeofence(PendingIntent pendingIntent) {
        long identity = Binder.clearCallingIdentity();
        try {
            removeRegistrationIf(key -> key.getPendingIntent().equals(pendingIntent));
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }

    @Override
+16 −4
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.annotation.Nullable;
import android.location.LocationManagerInternal;
import android.location.LocationManagerInternal.ProviderEnabledListener;
import android.location.util.identity.CallerIdentity;
import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Process;
@@ -218,16 +219,27 @@ public abstract class GnssListenerMultiplexer<TRequest, TListener extends IInter
    /**
     * Adds a listener with the given identity and request.
     */
    protected void addListener(TRequest request, CallerIdentity identity, TListener listener) {
    protected void addListener(TRequest request, CallerIdentity callerIdentity,
            TListener listener) {
        long identity = Binder.clearCallingIdentity();
        try {
            addRegistration(listener.asBinder(),
                new GnssListenerRegistration(request, identity, listener));
                    new GnssListenerRegistration(request, callerIdentity, listener));
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }

    /**
     * Removes the given listener.
     */
    public void removeListener(TListener listener) {
        long identity = Binder.clearCallingIdentity();
        try {
            removeRegistration(listener.asBinder());
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }

    @Override
+20 −3
Original line number Diff line number Diff line
@@ -2022,6 +2022,21 @@ public class GnssLocationProvider extends AbstractLocationProvider implements

    @Override
    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        boolean dumpAll = false;

        int opti = 0;
        while (opti < args.length) {
            String opt = args[opti];
            if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
                break;
            }
            opti++;
            if ("-a".equals(opt)) {
                dumpAll = true;
                break;
            }
        }

        StringBuilder s = new StringBuilder();
        s.append("mStarted=").append(mStarted).append("   (changed ");
        TimeUtils.formatDuration(SystemClock.elapsedRealtime()
@@ -2053,9 +2068,11 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
            s.append("]\n");
        }
        s.append(mGnssMetrics.dumpGnssMetricsAsText());
        if (dumpAll) {
            s.append("native internal state: \n");
            s.append("  ").append(native_get_internal_state());
            s.append("\n");
        }
        pw.append(s);
    }

Loading