diff options
12 files changed, 162 insertions, 60 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index f9403ffc3c79..0d8b729354b9 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3322,6 +3322,7 @@ package android.location { method public boolean isLocationControllerExtraPackageEnabled(); method public boolean isLocationEnabledForUser(android.os.UserHandle); method public boolean isProviderEnabledForUser(String, android.os.UserHandle); + method public boolean isProviderPackage(String); method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean registerGnssBatchedLocationCallback(long, boolean, android.location.BatchedLocationCallback, android.os.Handler); method @Deprecated public void removeGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener); method @Deprecated public void removeGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener); diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index e795b8119760..e91012fe0afe 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -85,12 +85,13 @@ interface ILocationManager boolean stopGnssBatch(); boolean injectLocation(in Location location); - // --- deprecated --- List<String> getAllProviders(); List<String> getProviders(in Criteria criteria, boolean enabledOnly); String getBestProvider(in Criteria criteria, boolean enabledOnly); ProviderProperties getProviderProperties(String provider); String getNetworkProviderPackage(); + boolean isProviderPackage(String packageName); + void setLocationControllerExtraPackage(String packageName); String getLocationControllerExtraPackage(); void setLocationControllerExtraPackageEnabled(boolean enabled); diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 63b57d166f1f..5aba22f4c6b1 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -2425,6 +2425,22 @@ public class LocationManager { } /** + * Returns true if the given package name matches a location provider package, and false + * otherwise. + * + * @hide + */ + @SystemApi + public boolean isProviderPackage(String packageName) { + try { + return mService.isProviderPackage(packageName); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + return false; + } + } + + /** * Set the extra location controller package for location services on the device. * * @hide diff --git a/location/java/com/android/internal/location/ILocationProviderManager.aidl b/location/java/com/android/internal/location/ILocationProviderManager.aidl index b1b8f0c7c3f7..79166ae3a9b0 100644 --- a/location/java/com/android/internal/location/ILocationProviderManager.aidl +++ b/location/java/com/android/internal/location/ILocationProviderManager.aidl @@ -26,6 +26,8 @@ import com.android.internal.location.ProviderProperties; */ interface ILocationProviderManager { + void onSetAdditionalProviderPackages(in List<String> packageNames); + void onSetEnabled(boolean enabled); void onSetProperties(in ProviderProperties properties); diff --git a/location/lib/api/current.txt b/location/lib/api/current.txt index c7212183a37e..67d64965ac96 100644 --- a/location/lib/api/current.txt +++ b/location/lib/api/current.txt @@ -19,6 +19,7 @@ package com.android.location.provider { method protected boolean onSendExtraCommand(@Nullable String, @Nullable android.os.Bundle); method protected abstract void onSetRequest(com.android.location.provider.ProviderRequestUnbundled, android.os.WorkSource); method public void reportLocation(android.location.Location); + method public void setAdditionalProviderPackages(java.util.List<java.lang.String>); method public void setEnabled(boolean); method public void setProperties(com.android.location.provider.ProviderPropertiesUnbundled); field public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation"; diff --git a/location/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java index 5bcec92c4fba..7cd7207c26a0 100644 --- a/location/lib/java/com/android/location/provider/LocationProviderBase.java +++ b/location/lib/java/com/android/location/provider/LocationProviderBase.java @@ -36,6 +36,8 @@ import com.android.internal.location.ProviderRequest; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; /** * Base class for location providers implemented as unbundled services. @@ -88,6 +90,7 @@ public abstract class LocationProviderBase { @Nullable private volatile ILocationProviderManager mManager; private volatile ProviderProperties mProperties; private volatile boolean mEnabled; + private final ArrayList<String> mAdditionalProviderPackages; public LocationProviderBase(String tag, ProviderPropertiesUnbundled properties) { mTag = tag; @@ -99,6 +102,7 @@ public abstract class LocationProviderBase { mManager = null; mProperties = properties.getProviderProperties(); mEnabled = true; + mAdditionalProviderPackages = new ArrayList<>(0); } public IBinder getBinder() { @@ -160,6 +164,29 @@ public abstract class LocationProviderBase { } /** + * Sets a list of additional packages that should be considered as part of this location + * provider for the purposes of generating locations. This should generally only be used when + * another package may issue location requests on behalf of this package in the course of + * providing location. This will inform location services to treat the other packages as + * location providers as well. + */ + public void setAdditionalProviderPackages(List<String> packageNames) { + synchronized (mBinder) { + mAdditionalProviderPackages.clear(); + mAdditionalProviderPackages.addAll(packageNames); + } + + ILocationProviderManager manager = mManager; + if (manager != null) { + try { + manager.onSetAdditionalProviderPackages(mAdditionalProviderPackages); + } catch (RemoteException | RuntimeException e) { + Log.w(mTag, e); + } + } + } + + /** * Returns true if this provider has been set as enabled. This will be true unless explicitly * set otherwise. */ @@ -275,6 +302,9 @@ public abstract class LocationProviderBase { public void setLocationProviderManager(ILocationProviderManager manager) { synchronized (mBinder) { try { + if (!mAdditionalProviderPackages.isEmpty()) { + manager.onSetAdditionalProviderPackages(mAdditionalProviderPackages); + } manager.onSetProperties(mProperties); manager.onSetEnabled(mEnabled); } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index a36c7c0e89b0..1165b094f319 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -114,6 +114,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -669,7 +670,7 @@ public class LocationManagerService extends ILocationManager.Stub { // create a passive location provider, which is always enabled LocationProvider passiveProviderManager = new LocationProvider(PASSIVE_PROVIDER); addProviderLocked(passiveProviderManager); - mPassiveProvider = new PassiveProvider(passiveProviderManager); + mPassiveProvider = new PassiveProvider(mContext, passiveProviderManager); passiveProviderManager.attachLocked(mPassiveProvider); if (GnssLocationProvider.isSupported()) { @@ -805,7 +806,7 @@ public class LocationManagerService extends ILocationManager.Stub { Integer.parseInt(fragments[9]) /* accuracy */); LocationProvider testProviderManager = new LocationProvider(name); addProviderLocked(testProviderManager); - new MockProvider(testProviderManager, properties); + new MockProvider(mContext, testProviderManager, properties); } } @@ -895,15 +896,12 @@ public class LocationManagerService extends ILocationManager.Stub { } @GuardedBy("mLock") - @Nullable - public String getPackageLocked() { + public List<String> getPackagesLocked() { if (mProvider == null) { - return null; - } else if (mProvider instanceof LocationProviderProxy) { - // safe to not clear binder context since this doesn't call into the actual provider - return ((LocationProviderProxy) mProvider).getConnectedPackageName(); + return Collections.emptyList(); } else { - return mContext.getPackageName(); + // safe to not clear binder context since this doesn't call into the real provider + return mProvider.getProviderPackages(); } } @@ -2172,10 +2170,8 @@ public class LocationManagerService extends ILocationManager.Stub { return true; } - for (LocationProvider provider : mProviders) { - if (callerIdentity.mPackageName.equals(provider.getPackageLocked())) { - return true; - } + if (isProviderPackage(callerIdentity.mPackageName)) { + return true; } return false; @@ -2192,10 +2188,8 @@ public class LocationManagerService extends ILocationManager.Stub { return true; } - for (LocationProvider provider : mProviders) { - if (record.mReceiver.mCallerIdentity.mPackageName.equals(provider.getPackageLocked())) { - return true; - } + if (isProviderPackage(record.mReceiver.mCallerIdentity.mPackageName)) { + return true; } return false; @@ -2571,8 +2565,8 @@ public class LocationManagerService extends ILocationManager.Stub { if (provider == null) return null; // only the current user or location providers may get location this way - if (!isCurrentProfileLocked(UserHandle.getUserId(uid)) && !isLocationProviderLocked( - uid)) { + if (!isCurrentProfileLocked(UserHandle.getUserId(uid)) && !isProviderPackage( + packageName)) { return null; } @@ -2894,7 +2888,25 @@ public class LocationManagerService extends ILocationManager.Stub { if (provider == null) { return null; } - return provider.getPackageLocked(); + List<String> packages = provider.getPackagesLocked(); + if (packages.isEmpty()) { + return null; + } else { + return packages.get(0); + } + } + } + + @Override + public boolean isProviderPackage(String packageName) { + synchronized (mLock) { + for (LocationProvider provider : mProviders) { + if (provider.getPackagesLocked().contains(packageName)) { + return true; + } + } + + return false; } } @@ -2976,28 +2988,6 @@ public class LocationManagerService extends ILocationManager.Stub { } @GuardedBy("mLock") - private boolean isLocationProviderLocked(int uid) { - if (uid == Process.SYSTEM_UID) { - return true; - } - - String[] packageNames = mPackageManager.getPackagesForUid(uid); - if (packageNames == null) { - return false; - } - for (LocationProvider provider : mProviders) { - String packageName = provider.getPackageLocked(); - if (packageName == null) { - continue; - } - if (ArrayUtils.contains(packageNames, packageName)) { - return true; - } - } - return false; - } - - @GuardedBy("mLock") private static boolean shouldBroadcastSafeLocked( Location loc, Location lastLoc, UpdateRecord record, long now) { // Always broadcast the first update @@ -3099,7 +3089,7 @@ public class LocationManagerService extends ILocationManager.Stub { int receiverUserId = UserHandle.getUserId(receiver.mCallerIdentity.mUid); if (!isCurrentProfileLocked(receiverUserId) - && !isLocationProviderLocked(receiver.mCallerIdentity.mUid)) { + && !isProviderPackage(receiver.mCallerIdentity.mPackageName)) { if (D) { Log.d(TAG, "skipping loc update for background user " + receiverUserId + " (current user: " + mCurrentUserId + ", app: " + @@ -3288,7 +3278,8 @@ public class LocationManagerService extends ILocationManager.Stub { MockLocationProvider mockProviderManager = new MockLocationProvider(name); addProviderLocked(mockProviderManager); - mockProviderManager.attachLocked(new MockProvider(mockProviderManager, properties)); + mockProviderManager.attachLocked( + new MockProvider(mContext, mockProviderManager, properties)); } finally { Binder.restoreCallingIdentity(identity); } @@ -3428,7 +3419,7 @@ public class LocationManagerService extends ILocationManager.Stub { if (provider.mProvider instanceof LocationProviderProxy) { pw.println(" " + provider.getName() + ": " + ((LocationProviderProxy) provider.mProvider) - .getConnectedPackageName()); + .getProviderPackages()); } } pw.println(" Historical Records by Provider:"); diff --git a/services/core/java/com/android/server/location/AbstractLocationProvider.java b/services/core/java/com/android/server/location/AbstractLocationProvider.java index b3f101848692..0edd17b1f777 100644 --- a/services/core/java/com/android/server/location/AbstractLocationProvider.java +++ b/services/core/java/com/android/server/location/AbstractLocationProvider.java @@ -16,6 +16,7 @@ package com.android.server.location; +import android.content.Context; import android.location.Location; import android.location.LocationProvider; import android.os.Bundle; @@ -26,6 +27,7 @@ import com.android.internal.location.ProviderRequest; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.Collections; import java.util.List; /** @@ -65,9 +67,12 @@ public abstract class AbstractLocationProvider { void onReportLocation(List<Location> locations); } + protected final Context mContext; private final LocationProviderManager mLocationProviderManager; - protected AbstractLocationProvider(LocationProviderManager locationProviderManager) { + protected AbstractLocationProvider( + Context context, LocationProviderManager locationProviderManager) { + mContext = context; mLocationProviderManager = locationProviderManager; } @@ -101,6 +106,11 @@ public abstract class AbstractLocationProvider { mLocationProviderManager.onSetProperties(properties); } + /** Returns list of packages currently associated with this provider. */ + public List<String> getProviderPackages() { + return Collections.singletonList(mContext.getPackageName()); + } + /** * Called when the location service delivers a new request for fulfillment to the provider. * Replaces any previous requests completely. diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index ab9f711b4238..b18110e80c2d 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -368,7 +368,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private int mC2KServerPort; private boolean mSuplEsEnabled = false; - private final Context mContext; private final Looper mLooper; private final LocationExtras mLocationExtras = new LocationExtras(); private final GnssStatusListenerHelper mGnssStatusListenerHelper; @@ -562,9 +561,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements public GnssLocationProvider(Context context, LocationProviderManager locationProviderManager, Looper looper) { - super(locationProviderManager); + super(context, locationProviderManager); - mContext = context; mLooper = looper; // Create a wake lock diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java index 776beb50be62..34c8786b00b3 100644 --- a/services/core/java/com/android/server/location/LocationProviderProxy.java +++ b/services/core/java/com/android/server/location/LocationProviderProxy.java @@ -16,8 +16,11 @@ package com.android.server.location; +import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; + import android.annotation.Nullable; import android.content.Context; +import android.content.pm.PackageManager; import android.location.Location; import android.location.LocationProvider; import android.os.Bundle; @@ -39,6 +42,10 @@ import com.android.server.ServiceWatcher; import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; /** * Proxy for ILocationProvider implementations. @@ -48,14 +55,21 @@ public class LocationProviderProxy extends AbstractLocationProvider { private static final String TAG = "LocationProviderProxy"; private static final boolean D = LocationManagerService.D; + // used to ensure that updates to mProviderPackages are atomic + private final Object mProviderPackagesLock = new Object(); + // used to ensure that updates to mRequest and mWorkSource are atomic private final Object mRequestLock = new Object(); - private final ServiceWatcher mServiceWatcher; - private final ILocationProviderManager.Stub mManager = new ILocationProviderManager.Stub() { // executed on binder thread @Override + public void onSetAdditionalProviderPackages(List<String> packageNames) { + LocationProviderProxy.this.onSetAdditionalProviderPackages(packageNames); + } + + // executed on binder thread + @Override public void onSetEnabled(boolean enabled) { LocationProviderProxy.this.setEnabled(enabled); } @@ -73,6 +87,11 @@ public class LocationProviderProxy extends AbstractLocationProvider { } }; + private final ServiceWatcher mServiceWatcher; + + @GuardedBy("mProviderPackagesLock") + private final CopyOnWriteArrayList<String> mProviderPackages = new CopyOnWriteArrayList<>(); + @GuardedBy("mRequestLock") @Nullable private ProviderRequest mRequest; @@ -101,7 +120,7 @@ public class LocationProviderProxy extends AbstractLocationProvider { private LocationProviderProxy(Context context, LocationProviderManager locationProviderManager, String action, int overlaySwitchResId, int defaultServicePackageNameResId, int initialPackageNamesResId) { - super(locationProviderManager); + super(context, locationProviderManager); mServiceWatcher = new ServiceWatcher(context, TAG, action, overlaySwitchResId, defaultServicePackageNameResId, initialPackageNamesResId, @@ -114,6 +133,7 @@ public class LocationProviderProxy extends AbstractLocationProvider { @Override protected void onUnbind() { + resetProviderPackages(Collections.emptyList()); setEnabled(false); setProperties(null); } @@ -131,6 +151,8 @@ public class LocationProviderProxy extends AbstractLocationProvider { ILocationProvider service = ILocationProvider.Stub.asInterface(binder); if (D) Log.d(TAG, "applying state to connected service " + mServiceWatcher); + resetProviderPackages(Collections.emptyList()); + service.setLocationProviderManager(mManager); synchronized (mRequestLock) { @@ -140,9 +162,11 @@ public class LocationProviderProxy extends AbstractLocationProvider { } } - @Nullable - public String getConnectedPackageName() { - return mServiceWatcher.getCurrentPackageName(); + @Override + public List<String> getProviderPackages() { + synchronized (mProviderPackagesLock) { + return mProviderPackages; + } } @Override @@ -193,4 +217,30 @@ public class LocationProviderProxy extends AbstractLocationProvider { service.sendExtraCommand(command, extras); }); } + + private void onSetAdditionalProviderPackages(List<String> packageNames) { + resetProviderPackages(packageNames); + } + + private void resetProviderPackages(List<String> additionalPackageNames) { + ArrayList<String> permittedPackages = new ArrayList<>(additionalPackageNames.size()); + for (String packageName : additionalPackageNames) { + try { + mContext.getPackageManager().getPackageInfo(packageName, MATCH_SYSTEM_ONLY); + permittedPackages.add(packageName); + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, mServiceWatcher + " specified unknown additional provider package: " + + packageName); + } + } + + synchronized (mProviderPackagesLock) { + mProviderPackages.clear(); + String myPackage = mServiceWatcher.getCurrentPackageName(); + if (myPackage != null) { + mProviderPackages.add(myPackage); + mProviderPackages.addAll(permittedPackages); + } + } + } } diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java index fe91c63e712b..6accad8a93a0 100644 --- a/services/core/java/com/android/server/location/MockProvider.java +++ b/services/core/java/com/android/server/location/MockProvider.java @@ -17,6 +17,7 @@ package com.android.server.location; import android.annotation.Nullable; +import android.content.Context; import android.location.Location; import android.location.LocationProvider; import android.os.Bundle; @@ -41,9 +42,9 @@ public class MockProvider extends AbstractLocationProvider { private long mStatusUpdateTime; private Bundle mExtras; - public MockProvider( + public MockProvider(Context context, LocationProviderManager locationProviderManager, ProviderProperties properties) { - super(locationProviderManager); + super(context, locationProviderManager); mEnabled = true; mLocation = null; diff --git a/services/core/java/com/android/server/location/PassiveProvider.java b/services/core/java/com/android/server/location/PassiveProvider.java index 30260b2fe14c..3a841c91399e 100644 --- a/services/core/java/com/android/server/location/PassiveProvider.java +++ b/services/core/java/com/android/server/location/PassiveProvider.java @@ -16,6 +16,7 @@ package com.android.server.location; +import android.content.Context; import android.location.Criteria; import android.location.Location; import android.os.Bundle; @@ -42,8 +43,8 @@ public class PassiveProvider extends AbstractLocationProvider { private boolean mReportLocation; - public PassiveProvider(LocationProviderManager locationProviderManager) { - super(locationProviderManager); + public PassiveProvider(Context context, LocationProviderManager locationProviderManager) { + super(context, locationProviderManager); mReportLocation = false; |