summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSoonil Nagarkar <sooniln@google.com>2020-01-23 18:06:31 -0800
committerSoonil Nagarkar <sooniln@google.com>2020-01-23 18:06:31 -0800
commit980ce6a7418dc4fea14dcbe076ad7970557e89c2 (patch)
treebf3bdf041e4b2d3cdbf1daaab42cd026d4b897a6
parentb20cfac061163449e1ba846f94f1164335ed1685 (diff)
Add DPM API to request location provider enable
DPM can currently control the master location toggle, but cannot influence the behavior of individual providers. This adds an API for DPM (or other privileged entities) to request a provider to turn itself on. Practically, this is necessary to allow DPM to control network location, which may be gated by additional consents. This change also renames some internal location code to make clearer the distinction between provider enabled and provider allowed: enabled = location on && allowed Bug: 136219903 Test: CTS tests to be added Change-Id: I05f03c976428f0f5a8a2cf627a84dc9e2baf3e67
-rw-r--r--api/current.txt1
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java43
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl1
-rw-r--r--location/java/android/location/LocationManager.java2
-rw-r--r--location/java/android/location/LocationManagerInternal.java44
-rw-r--r--location/java/com/android/internal/location/ILocationProvider.aidl2
-rw-r--r--location/java/com/android/internal/location/ILocationProviderManager.aidl2
-rw-r--r--location/lib/api/current.txt7
-rw-r--r--location/lib/java/com/android/location/provider/LocationProviderBase.java75
-rw-r--r--packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java2
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java122
-rw-r--r--services/core/java/com/android/server/location/AbstractLocationProvider.java47
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java2
-rw-r--r--services/core/java/com/android/server/location/LocationProviderProxy.java12
-rw-r--r--services/core/java/com/android/server/location/MockProvider.java17
-rw-r--r--services/core/java/com/android/server/location/MockableLocationProvider.java6
-rw-r--r--services/core/java/com/android/server/location/PassiveProvider.java2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java17
18 files changed, 296 insertions, 108 deletions
diff --git a/api/current.txt b/api/current.txt
index c05034744ac8..92915a6351bd 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6917,6 +6917,7 @@ package android.app.admin {
method public boolean removeOverrideApn(@NonNull android.content.ComponentName, int);
method public boolean removeUser(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
method public boolean requestBugreport(@NonNull android.content.ComponentName);
+ method public void requestSetLocationProviderAllowed(@NonNull android.content.ComponentName, @NonNull String, boolean);
method @Deprecated public boolean resetPassword(String, int);
method public boolean resetPasswordWithToken(@NonNull android.content.ComponentName, String, byte[], int);
method @Nullable public java.util.List<android.app.admin.NetworkEvent> retrieveNetworkLogs(@Nullable android.content.ComponentName, long);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index fa9dd274488f..e33e01ef4f58 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -8847,6 +8847,49 @@ public class DevicePolicyManager {
}
/**
+ * Called by device owners to request a location provider to change its allowed state. For a
+ * provider to be enabled requires both that the master location setting is enabled, and that
+ * the provider itself is allowed. Most location providers are always allowed. Some location
+ * providers may have user consents or terms and conditions that must be accepted, or some other
+ * type of blocker before they are allowed however. Every location provider is responsible for
+ * its own allowed state.
+ *
+ * <p>This method requests that a location provider change its allowed state. For providers that
+ * are always allowed and have no state to change, this will have no effect. If the provider
+ * does require some consent, terms and conditions, or other blocking state, using this API
+ * implies that the device owner is agreeing/disagreeing to any consents, terms and conditions,
+ * etc, and the provider should make a best effort to adjust it's allowed state accordingly.
+ *
+ * <p>Location providers are generally only responsible for the current user, and callers must
+ * assume that this method will only affect provider state for the current user. Callers are
+ * responsible for tracking current user changes and re-updating provider state as necessary.
+ *
+ * <p>While providers are expected to make a best effort to honor this request, it is not a
+ * given that all providers will support such a request. If a provider does change its state as
+ * a result of this request, that may happen asynchronously after some delay. Test location
+ * providers set through {@link android.location.LocationManager#addTestProvider} will respond
+ * to this request to aide in testing.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with
+ * @param provider A location provider as listed by
+ * {@link android.location.LocationManager#getAllProviders()}
+ * @param providerAllowed Whether the location provider is being requested to enable or disable
+ * itself
+ * @throws SecurityException if {@code admin} is not a device owner.
+ */
+ public void requestSetLocationProviderAllowed(@NonNull ComponentName admin,
+ @NonNull String provider, boolean providerAllowed) {
+ throwIfParentInstance("requestSetLocationProviderAllowed");
+ if (mService != null) {
+ try {
+ mService.requestSetLocationProviderAllowed(admin, provider, providerAllowed);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
* Called by profile or device owners to update {@link android.provider.Settings.Secure}
* settings. Validation that the value of the setting is in the correct form for the setting
* type should be performed by the caller.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 3d6bf9db5535..49f2e57396f2 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -270,6 +270,7 @@ interface IDevicePolicyManager {
boolean isLockdownAdminConfiguredNetworks(in ComponentName who);
void setLocationEnabled(in ComponentName who, boolean locationEnabled);
+ void requestSetLocationProviderAllowed(in ComponentName who, in String provider, boolean providerAllowed);
boolean setTime(in ComponentName who, long millis);
boolean setTimeZone(in ComponentName who, String timeZone);
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 687535c3304b..0c5fe787bbbc 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -74,7 +74,7 @@ import java.util.function.Consumer;
* still return location results, but the exact location will be obfuscated to a coarse level of
* accuracy.
*/
-@SuppressWarnings({"deprecation", "DeprecatedIsStillUsed"})
+@SuppressWarnings({"deprecation"})
@SystemService(Context.LOCATION_SERVICE)
@RequiresFeature(PackageManager.FEATURE_LOCATION)
public class LocationManager {
diff --git a/location/java/android/location/LocationManagerInternal.java b/location/java/android/location/LocationManagerInternal.java
new file mode 100644
index 000000000000..44d9d2372665
--- /dev/null
+++ b/location/java/android/location/LocationManagerInternal.java
@@ -0,0 +1,44 @@
+/*
+ * 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 android.location;
+
+
+import android.annotation.NonNull;
+
+/**
+ * Location manager local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class LocationManagerInternal {
+
+ /**
+ * Requests that a provider change its allowed state. A provider may or may not honor this
+ * request, and if the provider does change its state as a result, that may happen
+ * asynchronously after some delay.
+ *
+ * <p>Setting a provider's state to allowed implies that any consents or terms and conditions
+ * that may be necessary to allow the provider are agreed to. Setting a providers state to
+ * disallowed implies that any consents or terms and conditions have their agreement revoked.
+ *
+ * @param provider A location provider as listed by {@link LocationManager#getAllProviders()}
+ * @param allowed Whether the location provider is being requested to allow or disallow
+ * itself
+ * @throws IllegalArgumentException if provider is null
+ */
+ public abstract void requestSetProviderAllowed(@NonNull String provider, boolean allowed);
+}
diff --git a/location/java/com/android/internal/location/ILocationProvider.aidl b/location/java/com/android/internal/location/ILocationProvider.aidl
index 4246c6cd1004..b7817ff1e1fc 100644
--- a/location/java/com/android/internal/location/ILocationProvider.aidl
+++ b/location/java/com/android/internal/location/ILocationProvider.aidl
@@ -37,4 +37,6 @@ interface ILocationProvider {
@UnsupportedAppUsage
oneway void sendExtraCommand(String command, in Bundle extras);
+
+ oneway void requestSetAllowed(boolean allowed);
}
diff --git a/location/java/com/android/internal/location/ILocationProviderManager.aidl b/location/java/com/android/internal/location/ILocationProviderManager.aidl
index 85e18ba5ec4b..439039148773 100644
--- a/location/java/com/android/internal/location/ILocationProviderManager.aidl
+++ b/location/java/com/android/internal/location/ILocationProviderManager.aidl
@@ -29,7 +29,7 @@ interface ILocationProviderManager {
void onSetAdditionalProviderPackages(in List<String> packageNames);
@UnsupportedAppUsage
- void onSetEnabled(boolean enabled);
+ void onSetAllowed(boolean allowed);
@UnsupportedAppUsage
void onSetProperties(in ProviderProperties properties);
diff --git a/location/lib/api/current.txt b/location/lib/api/current.txt
index 5471bea549f4..49fcaabe981a 100644
--- a/location/lib/api/current.txt
+++ b/location/lib/api/current.txt
@@ -9,18 +9,21 @@ package com.android.location.provider {
public abstract class LocationProviderBase {
ctor public LocationProviderBase(String, com.android.location.provider.ProviderPropertiesUnbundled);
method public android.os.IBinder getBinder();
- method @RequiresApi(android.os.Build.VERSION_CODES.Q) public boolean isEnabled();
+ method @RequiresApi(android.os.Build.VERSION_CODES.R) public boolean isAllowed();
+ method @Deprecated @RequiresApi(android.os.Build.VERSION_CODES.Q) public boolean isEnabled();
method @Deprecated protected void onDisable();
method @Deprecated protected void onDump(java.io.FileDescriptor, java.io.PrintWriter, String[]);
method @Deprecated protected void onEnable();
method @Deprecated protected int onGetStatus(android.os.Bundle);
method @Deprecated protected long onGetStatusUpdateTime();
method protected void onInit();
+ method protected void onRequestSetAllowed(boolean);
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 @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setAdditionalProviderPackages(java.util.List<java.lang.String>);
- method @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setEnabled(boolean);
+ method @RequiresApi(android.os.Build.VERSION_CODES.R) public void setAllowed(boolean);
+ method @Deprecated @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setEnabled(boolean);
method @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setProperties(com.android.location.provider.ProviderPropertiesUnbundled);
field public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation";
field public static final String FUSED_PROVIDER = "fused";
diff --git a/location/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java
index fc7bff3c6dab..f67d08e045e2 100644
--- a/location/lib/java/com/android/location/provider/LocationProviderBase.java
+++ b/location/lib/java/com/android/location/provider/LocationProviderBase.java
@@ -92,7 +92,7 @@ public abstract class LocationProviderBase {
// write locked on mBinder, read lock is optional depending on atomicity requirements
@Nullable private volatile ILocationProviderManager mManager;
private volatile ProviderProperties mProperties;
- private volatile boolean mEnabled;
+ private volatile boolean mAllowed;
private final ArrayList<String> mAdditionalProviderPackages;
public LocationProviderBase(String tag, ProviderPropertiesUnbundled properties) {
@@ -104,7 +104,7 @@ public abstract class LocationProviderBase {
mManager = null;
mProperties = properties.getProviderProperties();
- mEnabled = true;
+ mAllowed = true;
mAdditionalProviderPackages = new ArrayList<>(0);
}
@@ -113,35 +113,44 @@ public abstract class LocationProviderBase {
}
/**
- * Sets whether this provider is currently enabled or not. Note that this is specific to the
+ * @deprecated Use {@link #setAllowed(boolean)} instead.
+ */
+ @Deprecated
+ @RequiresApi(VERSION_CODES.Q)
+ public void setEnabled(boolean enabled) {
+ setAllowed(enabled);
+ }
+
+ /**
+ * Sets whether this provider is currently allowed or not. Note that this is specific to the
* provider only, and is not related to global location settings. This is a hint to the Location
* Manager that this provider will generally be unable to fulfill incoming requests. This
- * provider may still receive callbacks to onSetRequest while not enabled, and must decide
+ * provider may still receive callbacks to onSetRequest while not allowed, and must decide
* whether to attempt to satisfy those requests or not.
*
- * Some guidelines: providers should set their own enabled/disabled status based only on state
- * "owned" by that provider. For instance, providers should not take into account the state of
- * the location master setting when setting themselves enabled or disabled, as this state is not
- * owned by a particular provider. If a provider requires some additional user consent that is
- * particular to the provider, this should be use to set the enabled/disabled state. If the
- * provider proxies to another provider, the child provider's enabled/disabled state should be
- * taken into account in the parent's enabled/disabled state. For most providers, it is expected
- * that they will be always enabled.
+ * <p>Some guidelines: providers should set their own allowed/disallowed status based only on
+ * state "owned" by that provider. For instance, providers should not take into account the
+ * state of the location master setting when setting themselves allowed or disallowed, as this
+ * state is not owned by a particular provider. If a provider requires some additional user
+ * consent that is particular to the provider, this should be use to set the allowed/disallowed
+ * state. If the provider proxies to another provider, the child provider's allowed/disallowed
+ * state should be taken into account in the parent's allowed state. For most providers, it is
+ * expected that they will be always allowed.
*/
- @RequiresApi(VERSION_CODES.Q)
- public void setEnabled(boolean enabled) {
+ @RequiresApi(VERSION_CODES.R)
+ public void setAllowed(boolean allowed) {
synchronized (mBinder) {
- if (mEnabled == enabled) {
+ if (mAllowed == allowed) {
return;
}
- mEnabled = enabled;
+ mAllowed = allowed;
}
ILocationProviderManager manager = mManager;
if (manager != null) {
try {
- manager.onSetEnabled(mEnabled);
+ manager.onSetAllowed(mAllowed);
} catch (RemoteException | RuntimeException e) {
Log.w(mTag, e);
}
@@ -193,12 +202,20 @@ public abstract class LocationProviderBase {
}
/**
- * Returns true if this provider has been set as enabled. This will be true unless explicitly
- * set otherwise.
+ * @deprecated Use {@link #isAllowed()} instead.
*/
+ @Deprecated
@RequiresApi(VERSION_CODES.Q)
public boolean isEnabled() {
- return mEnabled;
+ return isAllowed();
+ }
+
+ /**
+ * Returns true if this provider is allowed. Providers start as allowed on construction.
+ */
+ @RequiresApi(VERSION_CODES.R)
+ public boolean isAllowed() {
+ return mAllowed;
}
/**
@@ -285,6 +302,17 @@ public abstract class LocationProviderBase {
return false;
}
+ /**
+ * Invoked when the system wishes to request that the provider sets its allowed state as
+ * desired. This implies that the caller is providing/retracting consent for any terms and
+ * conditions or consents associated with the provider.
+ *
+ * <p>It is generally only necessary to override this function if the provider has some barriers
+ * or gates for enabling/disabling itself, in which case this function should handle those
+ * appropriately. A provider that is always allowed has no need to override this function.
+ */
+ protected void onRequestSetAllowed(boolean allowed) {}
+
private final class Service extends ILocationProvider.Stub {
@Override
@@ -295,7 +323,7 @@ public abstract class LocationProviderBase {
manager.onSetAdditionalProviderPackages(mAdditionalProviderPackages);
}
manager.onSetProperties(mProperties);
- manager.onSetEnabled(mEnabled);
+ manager.onSetAllowed(mAllowed);
} catch (RemoteException e) {
Log.w(mTag, e);
}
@@ -315,5 +343,10 @@ public abstract class LocationProviderBase {
public void sendExtraCommand(String command, Bundle extras) {
onSendExtraCommand(command, extras);
}
+
+ @Override
+ public void requestSetAllowed(boolean allowed) {
+ onRequestSetAllowed(allowed);
+ }
}
}
diff --git a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
index 33126510bc53..d1a379afa25e 100644
--- a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
+++ b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
@@ -205,7 +205,7 @@ public class FusedLocationServiceTest {
}
@Override
- public void onSetEnabled(boolean enabled) {
+ public void onSetAllowed(boolean allowed) {
}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index de0b6fcbd4ae..3b6ff26d5f03 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -52,6 +52,7 @@ import android.location.ILocationListener;
import android.location.ILocationManager;
import android.location.Location;
import android.location.LocationManager;
+import android.location.LocationManagerInternal;
import android.location.LocationRequest;
import android.location.LocationTime;
import android.os.Binder;
@@ -133,11 +134,12 @@ public class LocationManagerService extends ILocationManager.Stub {
*/
public static class Lifecycle extends SystemService {
- private LocationManagerService mService;
+ private final LocationManagerService mService;
public Lifecycle(Context context) {
super(context);
mService = new LocationManagerService(context);
+ LocalServices.addService(LocationManagerInternal.class, mService.new LocalService());
}
@Override
@@ -465,7 +467,7 @@ public class LocationManagerService extends ILocationManager.Stub {
mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
for (LocationProviderManager manager : mProviderManagers) {
- manager.onUseableChangedLocked(userId);
+ manager.onEnabledChangedLocked(userId);
}
}
@@ -633,10 +635,10 @@ public class LocationManagerService extends ILocationManager.Stub {
for (LocationProviderManager manager : mProviderManagers) {
// update LOCATION_PROVIDERS_ALLOWED for best effort backwards compatibility
mSettingsStore.setLocationProviderAllowed(manager.getName(),
- manager.isUseable(newUserId), newUserId);
+ manager.isEnabled(newUserId), newUserId);
- manager.onUseableChangedLocked(oldUserId);
- manager.onUseableChangedLocked(newUserId);
+ manager.onEnabledChangedLocked(oldUserId);
+ manager.onEnabledChangedLocked(newUserId);
}
}
@@ -650,22 +652,22 @@ public class LocationManagerService extends ILocationManager.Stub {
// acquiring mLock makes operations on mProvider atomic, but is otherwise unnecessary
protected final MockableLocationProvider mProvider;
- // useable state for parent user ids, no entry implies false. location state is only kept
+ // enabled state for parent user ids, no entry implies false. location state is only kept
// for parent user ids, the location state for a profile user id is assumed to be the same
// as for the parent. if querying this structure, ensure that the user id being used is a
// parent id or the results may be incorrect.
@GuardedBy("mLock")
- private final SparseArray<Boolean> mUseable;
+ private final SparseArray<Boolean> mEnabled;
private LocationProviderManager(String name) {
mName = name;
- mUseable = new SparseArray<>(1);
+ mEnabled = new SparseArray<>(1);
// initialize last since this lets our reference escape
mProvider = new MockableLocationProvider(mContext, mLock, this);
- // we can assume all users start with unuseable location state since the initial state
- // of all providers is disabled. no need to initialize mUseable further.
+ // we can assume all users start with disabled location state since the initial state
+ // of all providers is disabled. no need to initialize mEnabled further.
}
public String getName() {
@@ -693,13 +695,13 @@ public class LocationManagerService extends ILocationManager.Stub {
return mProvider.getState().properties;
}
- public void setMockProviderEnabled(boolean enabled) {
+ public void setMockProviderAllowed(boolean enabled) {
synchronized (mLock) {
if (!mProvider.isMock()) {
throw new IllegalArgumentException(mName + " provider is not a test provider");
}
- mProvider.setMockProviderEnabled(enabled);
+ mProvider.setMockProviderAllowed(enabled);
}
}
@@ -760,7 +762,7 @@ public class LocationManagerService extends ILocationManager.Stub {
return;
}
- if (!GPS_PROVIDER.equals(mName) || !isUseable()) {
+ if (!GPS_PROVIDER.equals(mName) || !isEnabled()) {
Slog.w(TAG, "reportLocationBatch() called without user permission");
return;
}
@@ -771,30 +773,33 @@ public class LocationManagerService extends ILocationManager.Stub {
@GuardedBy("mLock")
@Override
public void onStateChanged(State oldState, State newState) {
- if (oldState.enabled != newState.enabled) {
+ if (oldState.allowed != newState.allowed) {
// it would be more correct to call this for all users, but we know this can
// only affect the current user since providers are disabled for non-current
// users
- onUseableChangedLocked(mUserInfoStore.getCurrentUserId());
+ onEnabledChangedLocked(mUserInfoStore.getCurrentUserId());
}
}
- public boolean isUseable() {
- return isUseable(mUserInfoStore.getCurrentUserId());
+ public void requestSetAllowed(boolean allowed) {
+ mProvider.requestSetAllowed(allowed);
}
- public boolean isUseable(int userId) {
+ public boolean isEnabled() {
+ return isEnabled(mUserInfoStore.getCurrentUserId());
+ }
+
+ public boolean isEnabled(int userId) {
synchronized (mLock) {
// normalize user id to always refer to parent since profile state is always the
// same as parent state
userId = mUserInfoStore.getParentUserId(userId);
-
- return mUseable.get(userId, Boolean.FALSE);
+ return mEnabled.get(userId, Boolean.FALSE);
}
}
@GuardedBy("mLock")
- public void onUseableChangedLocked(int userId) {
+ public void onEnabledChangedLocked(int userId) {
if (userId == UserHandle.USER_NULL) {
// only used during initialization - we don't care about the null user
return;
@@ -804,36 +809,36 @@ public class LocationManagerService extends ILocationManager.Stub {
// as parent state
userId = mUserInfoStore.getParentUserId(userId);
- // if any property that contributes to "useability" here changes state, it MUST result
- // in a direct or indrect call to onUseableChangedLocked. this allows the provider to
+ // if any property that contributes to "enabled" here changes state, it MUST result
+ // in a direct or indrect call to onEnabledChangedLocked. this allows the provider to
// guarantee that it will always eventually reach the correct state.
- boolean useable = (userId == mUserInfoStore.getCurrentUserId())
- && mSettingsStore.isLocationEnabled(userId) && mProvider.getState().enabled;
+ boolean enabled = (userId == mUserInfoStore.getCurrentUserId())
+ && mSettingsStore.isLocationEnabled(userId) && mProvider.getState().allowed;
- if (useable == isUseable(userId)) {
+ if (enabled == isEnabled(userId)) {
return;
}
- mUseable.put(userId, useable);
+ mEnabled.put(userId, enabled);
if (D) {
- Log.d(TAG, "[u" + userId + "] " + mName + " provider useable = " + useable);
+ Log.d(TAG, "[u" + userId + "] " + mName + " provider enabled = " + enabled);
}
// fused and passive provider never get public updates for legacy reasons
if (!FUSED_PROVIDER.equals(mName) && !PASSIVE_PROVIDER.equals(mName)) {
// update LOCATION_PROVIDERS_ALLOWED for best effort backwards compatibility
- mSettingsStore.setLocationProviderAllowed(mName, useable, userId);
+ mSettingsStore.setLocationProviderAllowed(mName, enabled, userId);
Intent intent = new Intent(LocationManager.PROVIDERS_CHANGED_ACTION)
.putExtra(LocationManager.EXTRA_PROVIDER_NAME, mName)
- .putExtra(LocationManager.EXTRA_PROVIDER_ENABLED, useable)
+ .putExtra(LocationManager.EXTRA_PROVIDER_ENABLED, enabled)
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
}
- if (!useable) {
+ if (!enabled) {
// If any provider has been disabled, clear all last locations for all
// providers. This is to be on the safe side in case a provider has location
// derived from this disabled provider.
@@ -841,7 +846,7 @@ public class LocationManagerService extends ILocationManager.Stub {
mLastLocationCoarseInterval.clear();
}
- updateProviderUseableLocked(this);
+ updateProviderEnabledLocked(this);
}
public void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) {
@@ -854,10 +859,10 @@ public class LocationManagerService extends ILocationManager.Stub {
pw.increaseIndent();
- boolean useable = isUseable();
- pw.println("useable=" + useable);
- if (!useable) {
- pw.println("enabled=" + mProvider.getState().enabled);
+ boolean enabled = isEnabled();
+ pw.println("enabled=" + enabled);
+ if (!enabled) {
+ pw.println("allowed=" + mProvider.getState().allowed);
}
pw.println("properties=" + mProvider.getState().properties);
@@ -1009,7 +1014,7 @@ public class LocationManagerService extends ILocationManager.Stub {
if (manager == null) {
continue;
}
- if (!manager.isUseable() && !isSettingsExemptLocked(updateRecord)) {
+ if (!manager.isEnabled() && !isSettingsExemptLocked(updateRecord)) {
continue;
}
@@ -1425,7 +1430,7 @@ public class LocationManagerService extends ILocationManager.Stub {
if (FUSED_PROVIDER.equals(name)) {
continue;
}
- if (enabledOnly && !manager.isUseable()) {
+ if (enabledOnly && !manager.isEnabled()) {
continue;
}
if (criteria != null
@@ -1467,8 +1472,8 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@GuardedBy("mLock")
- private void updateProviderUseableLocked(LocationProviderManager manager) {
- boolean useable = manager.isUseable();
+ private void updateProviderEnabledLocked(LocationProviderManager manager) {
+ boolean enabled = manager.isEnabled();
ArrayList<Receiver> deadReceivers = null;
@@ -1486,7 +1491,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
// Sends a notification message to the receiver
- if (!record.mReceiver.callProviderEnabledLocked(manager.getName(), useable)) {
+ if (!record.mReceiver.callProviderEnabledLocked(manager.getName(), enabled)) {
if (deadReceivers == null) {
deadReceivers = new ArrayList<>();
}
@@ -1553,7 +1558,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
final boolean isBatterySaverDisablingLocation = shouldThrottleRequests
|| (isForegroundOnlyMode && !record.mIsForegroundUid);
- if (!manager.isUseable() || isBatterySaverDisablingLocation) {
+ if (!manager.isEnabled() || isBatterySaverDisablingLocation) {
if (isSettingsExemptLocked(record)) {
providerRequest.setLocationSettingsIgnored(true);
providerRequest.setLowPowerMode(false);
@@ -1970,7 +1975,7 @@ public class LocationManagerService extends ILocationManager.Stub {
oldRecord.disposeLocked(false);
}
- if (!manager.isUseable() && !isSettingsExemptLocked(record)) {
+ if (!manager.isEnabled() && !isSettingsExemptLocked(record)) {
// Notify the listener that updates are currently disabled - but only if the request
// does not ignore location settings
receiver.callProviderEnabledLocked(name, false);
@@ -2082,7 +2087,7 @@ public class LocationManagerService extends ILocationManager.Stub {
return null;
}
- if (!manager.isUseable()) {
+ if (!manager.isEnabled()) {
return null;
}
@@ -2204,7 +2209,7 @@ public class LocationManagerService extends ILocationManager.Stub {
synchronized (mLock) {
LocationProviderManager manager = getLocationProviderManager(location.getProvider());
- if (manager == null || !manager.isUseable()) {
+ if (manager == null || !manager.isEnabled()) {
return false;
}
@@ -2491,7 +2496,7 @@ public class LocationManagerService extends ILocationManager.Stub {
synchronized (mLock) {
LocationProviderManager manager = getLocationProviderManager(providerName);
- return manager != null && manager.isUseable(userId);
+ return manager != null && manager.isEnabled(userId);
}
}
@@ -2549,8 +2554,8 @@ public class LocationManagerService extends ILocationManager.Stub {
long now = SystemClock.elapsedRealtime();
- // only update last location for locations that come from useable providers
- if (manager.isUseable()) {
+ // only update last location for locations that come from enabled providers
+ if (manager.isEnabled()) {
updateLastLocationLocked(location, manager.getName());
}
@@ -2560,7 +2565,7 @@ public class LocationManagerService extends ILocationManager.Stub {
if (lastLocationCoarseInterval == null) {
lastLocationCoarseInterval = new Location(location);
- if (manager.isUseable()) {
+ if (manager.isEnabled()) {
mLastLocationCoarseInterval.put(manager.getName(), lastLocationCoarseInterval);
}
}
@@ -2593,7 +2598,7 @@ public class LocationManagerService extends ILocationManager.Stub {
Receiver receiver = r.mReceiver;
boolean receiverDead = false;
- if (!manager.isUseable() && !isSettingsExemptLocked(r)) {
+ if (!manager.isEnabled() && !isSettingsExemptLocked(r)) {
continue;
}
@@ -2812,7 +2817,7 @@ public class LocationManagerService extends ILocationManager.Stub {
throw new IllegalArgumentException("provider doesn't exist: " + provider);
}
- manager.setMockProviderEnabled(enabled);
+ manager.setMockProviderAllowed(enabled);
}
@Override
@@ -2946,4 +2951,19 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
}
+
+ private class LocalService extends LocationManagerInternal {
+
+ @Override
+ public void requestSetProviderAllowed(String provider, boolean allowed) {
+ Preconditions.checkArgument(provider != null, "invalid null provider");
+
+ synchronized (mLock) {
+ LocationProviderManager manager = getLocationProviderManager(provider);
+ if (manager != null) {
+ manager.requestSetAllowed(allowed);
+ }
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/location/AbstractLocationProvider.java b/services/core/java/com/android/server/location/AbstractLocationProvider.java
index ed6a759409d4..5afa48a2b34d 100644
--- a/services/core/java/com/android/server/location/AbstractLocationProvider.java
+++ b/services/core/java/com/android/server/location/AbstractLocationProvider.java
@@ -79,9 +79,9 @@ public abstract class AbstractLocationProvider {
Collections.emptySet());
/**
- * The provider's enabled state.
+ * The provider's allowed state.
*/
- public final boolean enabled;
+ public final boolean allowed;
/**
* The provider's properties.
@@ -93,18 +93,18 @@ public abstract class AbstractLocationProvider {
*/
public final Set<String> providerPackageNames;
- private State(boolean enabled, ProviderProperties properties,
+ private State(boolean allowed, ProviderProperties properties,
Set<String> providerPackageNames) {
- this.enabled = enabled;
+ this.allowed = allowed;
this.properties = properties;
this.providerPackageNames = Objects.requireNonNull(providerPackageNames);
}
- private State withEnabled(boolean enabled) {
- if (enabled == this.enabled) {
+ private State withAllowed(boolean allowed) {
+ if (allowed == this.allowed) {
return this;
} else {
- return new State(enabled, properties, providerPackageNames);
+ return new State(allowed, properties, providerPackageNames);
}
}
@@ -112,7 +112,7 @@ public abstract class AbstractLocationProvider {
if (properties.equals(this.properties)) {
return this;
} else {
- return new State(enabled, properties, providerPackageNames);
+ return new State(allowed, properties, providerPackageNames);
}
}
@@ -120,7 +120,7 @@ public abstract class AbstractLocationProvider {
if (providerPackageNames.equals(this.providerPackageNames)) {
return this;
} else {
- return new State(enabled, properties, providerPackageNames);
+ return new State(allowed, properties, providerPackageNames);
}
}
@@ -133,13 +133,13 @@ public abstract class AbstractLocationProvider {
return false;
}
State state = (State) o;
- return enabled == state.enabled && properties == state.properties
+ return allowed == state.allowed && properties == state.properties
&& providerPackageNames.equals(state.providerPackageNames);
}
@Override
public int hashCode() {
- return Objects.hash(enabled, properties, providerPackageNames);
+ return Objects.hash(allowed, properties, providerPackageNames);
}
}
@@ -259,10 +259,10 @@ public abstract class AbstractLocationProvider {
}
/**
- * The current enabled state of this provider.
+ * The current allowed state of this provider.
*/
- protected boolean isEnabled() {
- return mInternalState.get().state.enabled;
+ protected boolean isAllowed() {
+ return mInternalState.get().state.allowed;
}
/**
@@ -281,10 +281,10 @@ public abstract class AbstractLocationProvider {
}
/**
- * Call this method to report a change in provider enabled/disabled status.
+ * Call this method to report a change in provider allowed status.
*/
- protected void setEnabled(boolean enabled) {
- setState(state -> state.withEnabled(enabled));
+ protected void setAllowed(boolean allowed) {
+ setState(state -> state.withAllowed(allowed));
}
/**
@@ -358,6 +358,19 @@ public abstract class AbstractLocationProvider {
protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {}
/**
+ * Requests a provider to enable itself for the given user id.
+ */
+ public final void requestSetAllowed(boolean allowed) {
+ // all calls into the provider must be moved onto the provider thread to prevent deadlock
+ mExecutor.execute(() -> onRequestSetAllowed(allowed));
+ }
+
+ /**
+ * Always invoked on the provider executor.
+ */
+ protected void onRequestSetAllowed(boolean allowed) {}
+
+ /**
* Dumps debug or log information. May be invoked from any thread.
*/
public abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args);
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 15cf190952d1..306e1e3afcd7 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -729,7 +729,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}, UserHandle.USER_ALL);
setProperties(PROPERTIES);
- setEnabled(true);
+ setAllowed(true);
}
/**
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index 805b018a8f45..cf299fe9bb2a 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -97,8 +97,8 @@ public class LocationProviderProxy extends AbstractLocationProvider {
// executed on binder thread
@Override
- public void onSetEnabled(boolean enabled) {
- setEnabled(enabled);
+ public void onSetAllowed(boolean allowed) {
+ setAllowed(allowed);
}
// executed on binder thread
@@ -169,6 +169,14 @@ public class LocationProviderProxy extends AbstractLocationProvider {
}
@Override
+ public void onRequestSetAllowed(boolean allowed) {
+ mServiceWatcher.runOnBinder(binder -> {
+ ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
+ service.requestSetAllowed(allowed);
+ });
+ }
+
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("service=" + mServiceWatcher);
}
diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java
index 60c9fc12c201..bcec8b12b371 100644
--- a/services/core/java/com/android/server/location/MockProvider.java
+++ b/services/core/java/com/android/server/location/MockProvider.java
@@ -42,9 +42,9 @@ public class MockProvider extends AbstractLocationProvider {
setProperties(properties);
}
- /** Sets the enabled state of this mock provider. */
- public void setProviderEnabled(boolean enabled) {
- setEnabled(enabled);
+ /** Sets the allowed state of this mock provider. */
+ public void setProviderAllowed(boolean allowed) {
+ setAllowed(allowed);
}
/** Sets the location to report for this mock provider. */
@@ -56,10 +56,15 @@ public class MockProvider extends AbstractLocationProvider {
}
@Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("last mock location=" + mLocation);
+ public void onSetRequest(ProviderRequest request) {}
+
+ @Override
+ protected void onRequestSetAllowed(boolean allowed) {
+ setAllowed(allowed);
}
@Override
- public void onSetRequest(ProviderRequest request) {}
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("last mock location=" + mLocation);
+ }
}
diff --git a/services/core/java/com/android/server/location/MockableLocationProvider.java b/services/core/java/com/android/server/location/MockableLocationProvider.java
index f50dfe7edbb7..18615f87609f 100644
--- a/services/core/java/com/android/server/location/MockableLocationProvider.java
+++ b/services/core/java/com/android/server/location/MockableLocationProvider.java
@@ -170,13 +170,13 @@ public class MockableLocationProvider extends AbstractLocationProvider {
}
/**
- * Sets the mock provider implementation's enabled state. Will throw an exception if the mock
+ * Sets the mock provider implementation's allowed state. Will throw an exception if the mock
* provider is not currently the active implementation.
*/
- public void setMockProviderEnabled(boolean enabled) {
+ public void setMockProviderAllowed(boolean allowed) {
synchronized (mOwnerLock) {
Preconditions.checkState(isMock());
- mMockProvider.setProviderEnabled(enabled);
+ mMockProvider.setProviderAllowed(allowed);
}
}
/**
diff --git a/services/core/java/com/android/server/location/PassiveProvider.java b/services/core/java/com/android/server/location/PassiveProvider.java
index b33877069d70..ef157a39fa28 100644
--- a/services/core/java/com/android/server/location/PassiveProvider.java
+++ b/services/core/java/com/android/server/location/PassiveProvider.java
@@ -56,7 +56,7 @@ public class PassiveProvider extends AbstractLocationProvider {
mReportLocation = false;
setProperties(PROPERTIES);
- setEnabled(true);
+ setAllowed(true);
}
@Override
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b6953f6e3e36..5dc5d4e37662 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -177,6 +177,7 @@ import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.location.LocationManager;
+import android.location.LocationManagerInternal;
import android.media.AudioManager;
import android.media.IAudioService;
import android.net.ConnectivityManager;
@@ -315,7 +316,6 @@ import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
-import java.util.stream.Collectors;
/**
* Implementation of the device policy APIs.
@@ -2049,6 +2049,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return mContext.getSystemService(LocationManager.class);
}
+ LocationManagerInternal getLocationManagerInternal() {
+ return LocalServices.getService(LocationManagerInternal.class);
+ }
+
IWindowManager getIWindowManager() {
return IWindowManager.Stub
.asInterface(ServiceManager.getService(Context.WINDOW_SERVICE));
@@ -11534,6 +11538,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
+ public void requestSetLocationProviderAllowed(ComponentName who, String provider,
+ boolean providerAllowed) {
+ Objects.requireNonNull(who, "ComponentName is null");
+ enforceDeviceOwner(who);
+
+ mInjector.binderWithCleanCallingIdentity(
+ () -> mInjector.getLocationManagerInternal().requestSetProviderAllowed(provider,
+ providerAllowed));
+ }
+
+ @Override
public boolean setTime(ComponentName who, long millis) {
Objects.requireNonNull(who, "ComponentName is null in setTime");
enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(who);