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

Commit 5c7a3cdb authored by David Christie's avatar David Christie Committed by Android (Google) Code Review
Browse files

Merge "Add permission gated provider to access the hardware GPS directly."

parents 26d4661c b983a450
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -6252,6 +6252,7 @@ package android.location {
    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean unregisterGnssBatchedLocationCallback(@NonNull android.location.BatchedLocationCallback);
    field public static final String ACTION_ADAS_GNSS_ENABLED_CHANGED = "android.location.action.ADAS_GNSS_ENABLED_CHANGED";
    field public static final String EXTRA_ADAS_GNSS_ENABLED = "android.location.extra.ADAS_GNSS_ENABLED";
    field @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public static final String GPS_HARDWARE_PROVIDER = "gps_hardware";
  }
  public final class LocationRequest implements android.os.Parcelable {
@@ -6391,6 +6392,7 @@ package android.location.provider {
    method public void setAllowed(boolean);
    method public void setProperties(@NonNull android.location.provider.ProviderProperties);
    field public static final String ACTION_FUSED_PROVIDER = "com.android.location.service.FusedLocationProvider";
    field public static final String ACTION_GNSS_PROVIDER = "android.location.provider.action.GNSS_PROVIDER";
    field public static final String ACTION_NETWORK_PROVIDER = "com.android.location.service.v3.NetworkLocationProvider";
  }
+15 −0
Original line number Diff line number Diff line
@@ -194,6 +194,21 @@ public class LocationManager {
     */
    public static final String GPS_PROVIDER = "gps";

    /**
     * Standard name of the GNSS hardware location provider.
     *
     * <p>This provider is similar to {@link LocationManager#GPS_PROVIDER}, but it directly uses the
     * HAL GNSS implementation and doesn't go through any provider overrides that may exist. This
     * provider will only be available when the GPS_PROVIDER is overridden with a proxy using {@link
     * android.location.provider.LocationProviderBase#ACTION_GNSS_PROVIDER}, and is intended only
     * for use internally by the location provider system.
     *
     * @hide
     */
    @SystemApi
    @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
    public static final String GPS_HARDWARE_PROVIDER = "gps_hardware";

    /**
     * A special location provider for receiving locations without actively initiating a location
     * fix. This location provider is always present.
+0 −2
Original line number Diff line number Diff line
@@ -104,8 +104,6 @@ public abstract class LocationProviderBase {
    /**
     * The action the wrapping service should have in its intent filter to implement the
     * {@link android.location.LocationManager#GPS_PROVIDER}.
     *
     * @hide
     */
    public static final String ACTION_GNSS_PROVIDER =
            "android.location.provider.action.GNSS_PROVIDER";
+40 −13
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.location.LocationManager.BLOCK_PENDING_INTENT_SYSTEM_API_USAGE;
import static android.location.LocationManager.FUSED_PROVIDER;
import static android.location.LocationManager.GPS_HARDWARE_PROVIDER;
import static android.location.LocationManager.GPS_PROVIDER;
import static android.location.LocationManager.NETWORK_PROVIDER;
import static android.location.LocationRequest.LOW_POWER_EXCEPTIONS;
@@ -95,6 +96,7 @@ import android.util.IndentingPrintWriter;
import android.util.Log;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
import com.android.server.FgThread;
@@ -319,6 +321,9 @@ public class LocationManagerService extends ILocationManager.Stub implements

        for (LocationProviderManager manager : mProviderManagers) {
            if (providerName.equals(manager.getName())) {
                if (!manager.isVisibleToCaller()) {
                    return null;
                }
                return manager;
            }
        }
@@ -341,8 +346,9 @@ public class LocationManagerService extends ILocationManager.Stub implements
        }
    }

    private void addLocationProviderManager(LocationProviderManager manager,
            @Nullable AbstractLocationProvider realProvider) {
    @VisibleForTesting
    void addLocationProviderManager(
            LocationProviderManager manager, @Nullable AbstractLocationProvider realProvider) {
        synchronized (mProviderManagers) {
            Preconditions.checkState(getLocationProviderManager(manager.getName()) == null);

@@ -453,6 +459,20 @@ public class LocationManagerService extends ILocationManager.Stub implements
            }
            if (gnssProvider == null) {
                gnssProvider = mGnssManagerService.getGnssLocationProvider();
            } else {
                // If we have a GNSS provider override, add the hardware provider as a standalone
                // option for use by apps with the correct permission. Note the GNSS HAL can only
                // support a single client, so mGnssManagerService.getGnssLocationProvider() can
                // only be installed with a single provider.
                LocationProviderManager gnssHardwareManager =
                        new LocationProviderManager(
                                mContext,
                                mInjector,
                                GPS_HARDWARE_PROVIDER,
                                mPassiveManager,
                                Collections.singletonList(Manifest.permission.LOCATION_HARDWARE));
                addLocationProviderManager(
                        gnssHardwareManager, mGnssManagerService.getGnssLocationProvider());
            }

            LocationProviderManager gnssManager = new LocationProviderManager(mContext, mInjector,
@@ -629,8 +649,10 @@ public class LocationManagerService extends ILocationManager.Stub implements
    public List<String> getAllProviders() {
        ArrayList<String> providers = new ArrayList<>(mProviderManagers.size());
        for (LocationProviderManager manager : mProviderManagers) {
            if (manager.isVisibleToCaller()) {
                providers.add(manager.getName());
            }
        }
        return providers;
    }

@@ -644,16 +666,19 @@ public class LocationManagerService extends ILocationManager.Stub implements
        synchronized (mLock) {
            ArrayList<String> providers = new ArrayList<>(mProviderManagers.size());
            for (LocationProviderManager manager : mProviderManagers) {
                if (manager.isVisibleToCaller()) {
                    String name = manager.getName();
                    if (enabledOnly && !manager.isEnabled(UserHandle.getCallingUserId())) {
                        continue;
                    }
                if (criteria != null && !LocationProvider.propertiesMeetCriteria(name,
                        manager.getProperties(), criteria)) {
                    if (criteria != null
                            && !LocationProvider.propertiesMeetCriteria(
                                    name, manager.getProperties(), criteria)) {
                        continue;
                    }
                    providers.add(name);
                }
            }
            return providers;
        }
    }
@@ -1059,9 +1084,11 @@ public class LocationManagerService extends ILocationManager.Stub implements
    public void addProviderRequestListener(IProviderRequestListener listener) {
        mContext.enforceCallingOrSelfPermission(INTERACT_ACROSS_USERS, null);
        for (LocationProviderManager manager : mProviderManagers) {
            if (manager.isVisibleToCaller()) {
                manager.addProviderRequestListener(listener);
            }
        }
    }

    @Override
    public void removeProviderRequestListener(IProviderRequestListener listener) {
@@ -1649,7 +1676,7 @@ public class LocationManagerService extends ILocationManager.Stub implements
                if (provider != null && !provider.equals(manager.getName())) {
                    continue;
                }
                if (identity.equals(manager.getProviderIdentity())) {
                if (identity.equals(manager.getProviderIdentity()) && manager.isVisibleToCaller()) {
                    return true;
                }
            }
+47 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.location.provider;
import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
import static android.app.AppOpsManager.OP_MONITOR_LOCATION;
import static android.app.compat.CompatChanges.isChangeEnabled;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.location.LocationManager.DELIVER_HISTORICAL_LOCATIONS;
import static android.location.LocationManager.GPS_PROVIDER;
import static android.location.LocationManager.KEY_FLUSH_COMPLETE;
@@ -48,6 +49,7 @@ import static java.lang.Math.min;

import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.AlarmManager.OnAlarmListener;
import android.app.BroadcastOptions;
import android.app.PendingIntent;
@@ -124,6 +126,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -1362,6 +1365,10 @@ public class LocationProviderManager extends
    @GuardedBy("mMultiplexerLock")
    private final ArrayList<ProviderEnabledListener> mEnabledListeners;

    // Extra permissions required to use this provider (on top of the usual location permissions).
    // Not guarded because it's read only.
    private final Collection<String> mRequiredPermissions;

    private final CopyOnWriteArrayList<IProviderRequestListener> mProviderRequestListeners;

    protected final LocationManagerInternal mLocationManagerInternal;
@@ -1435,12 +1442,34 @@ public class LocationProviderManager extends

    public LocationProviderManager(Context context, Injector injector,
            String name, @Nullable PassiveLocationProviderManager passiveManager) {
        this(context, injector, name, passiveManager, Collections.emptyList());
    }

    /**
     * Creates a manager for a location provider (the two have a 1:1 correspondence).
     *
     * @param context Context in which the manager is running.
     * @param injector Injector to retrieve system components (useful to override in testing)
     * @param name Name of this provider (used in LocationManager APIs by client apps).
     * @param passiveManager The "passive" manager (special case provider that returns locations
     *     from all other providers).
     * @param requiredPermissions Required permissions for accessing this provider. All of the given
     *     permissions are required to access the provider. If a caller doesn't hold the correct
     *     permission, the provider will be invisible to it.
     */
    public LocationProviderManager(
            Context context,
            Injector injector,
            String name,
            @Nullable PassiveLocationProviderManager passiveManager,
            Collection<String> requiredPermissions) {
        mContext = context;
        mName = Objects.requireNonNull(name);
        mPassiveManager = passiveManager;
        mState = STATE_STOPPED;
        mEnabled = new SparseBooleanArray(2);
        mLastLocations = new SparseArray<>(2);
        mRequiredPermissions = requiredPermissions;

        mEnabledListeners = new ArrayList<>();
        mProviderRequestListeners = new CopyOnWriteArrayList<>();
@@ -1559,6 +1588,24 @@ public class LocationProviderManager extends
        }
    }

    /**
     * Returns true if this provider is visible to the current caller (whether called from a binder
     * thread or not). If a provider isn't visible, then all APIs return the same data they would if
     * the provider didn't exist (i.e. the caller can't see or use the provider).
     *
     * <p>This method doesn't require any permissions, but uses permissions to determine which
     * subset of providers are visible.
     */
    @SuppressLint("AndroidFrameworkRequiresPermission")
    public boolean isVisibleToCaller() {
        for (String permission : mRequiredPermissions) {
            if (mContext.checkCallingOrSelfPermission(permission) != PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

    public void addEnabledListener(ProviderEnabledListener listener) {
        synchronized (mMultiplexerLock) {
            Preconditions.checkState(mState != STATE_STOPPED);
Loading