diff options
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); |