Merge "Add location settings piercing in emergencies"
This commit is contained in:
committed by
Android (Google) Code Review
commit
0ef34932e3
@@ -3210,12 +3210,14 @@ package android.location {
|
||||
method public int getQuality();
|
||||
method public float getSmallestDisplacement();
|
||||
method public android.os.WorkSource getWorkSource();
|
||||
method public boolean isLocationSettingsIgnored();
|
||||
method public boolean isLowPowerMode();
|
||||
method public android.location.LocationRequest setExpireAt(long);
|
||||
method public android.location.LocationRequest setExpireIn(long);
|
||||
method public android.location.LocationRequest setFastestInterval(long);
|
||||
method public void setHideFromAppOps(boolean);
|
||||
method public android.location.LocationRequest setInterval(long);
|
||||
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest setLocationSettingsIgnored(boolean);
|
||||
method public android.location.LocationRequest setLowPowerMode(boolean);
|
||||
method public android.location.LocationRequest setNumUpdates(int);
|
||||
method public android.location.LocationRequest setProvider(String);
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package android.location;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SystemApi;
|
||||
import android.annotation.UnsupportedAppUsage;
|
||||
import android.os.Build;
|
||||
@@ -161,6 +163,7 @@ public final class LocationRequest implements Parcelable {
|
||||
private WorkSource mWorkSource = null;
|
||||
@UnsupportedAppUsage
|
||||
private boolean mHideFromAppOps = false; // True if this request shouldn't be counted by AppOps
|
||||
private boolean mLocationSettingsIgnored = false;
|
||||
|
||||
@UnsupportedAppUsage
|
||||
private String mProvider = LocationManager.FUSED_PROVIDER;
|
||||
@@ -261,6 +264,7 @@ public final class LocationRequest implements Parcelable {
|
||||
mWorkSource = src.mWorkSource;
|
||||
mHideFromAppOps = src.mHideFromAppOps;
|
||||
mLowPowerMode = src.mLowPowerMode;
|
||||
mLocationSettingsIgnored = src.mLocationSettingsIgnored;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -374,6 +378,32 @@ public final class LocationRequest implements Parcelable {
|
||||
return mLowPowerMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that user location settings be ignored in order to satisfy this request. This API
|
||||
* is only for use in extremely rare scenarios where it is appropriate to ignore user location
|
||||
* settings, such as a user initiated emergency (dialing 911 for instance).
|
||||
*
|
||||
* @param locationSettingsIgnored Whether to ignore location settings
|
||||
* @return the same object, so that setters can be chained
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
|
||||
@SystemApi
|
||||
public LocationRequest setLocationSettingsIgnored(boolean locationSettingsIgnored) {
|
||||
mLocationSettingsIgnored = locationSettingsIgnored;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if location settings will be ignored in order to satisfy this request.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public boolean isLocationSettingsIgnored() {
|
||||
return mLocationSettingsIgnored;
|
||||
}
|
||||
|
||||
/**
|
||||
* Explicitly set the fastest interval for location updates, in
|
||||
* milliseconds.
|
||||
|
||||
@@ -67,7 +67,6 @@ import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.PowerManager;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
@@ -88,7 +87,6 @@ import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.content.PackageMonitor;
|
||||
import com.android.internal.location.ProviderProperties;
|
||||
import com.android.internal.location.ProviderRequest;
|
||||
import com.android.internal.os.BackgroundThread;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.DumpUtils;
|
||||
import com.android.internal.util.Preconditions;
|
||||
@@ -248,7 +246,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
public LocationManagerService(Context context) {
|
||||
super();
|
||||
mContext = context;
|
||||
mHandler = BackgroundThread.getHandler();
|
||||
mHandler = FgThread.getHandler();
|
||||
|
||||
// Let the package manager query which are the default location
|
||||
// providers as they get certain permissions granted by default.
|
||||
@@ -975,7 +973,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
public void onReportLocation(Location location) {
|
||||
// no security check necessary because this is coming from an internal-only interface
|
||||
// move calls coming from below LMS onto a different thread to avoid deadlock
|
||||
runInternal(() -> {
|
||||
mHandler.post(() -> {
|
||||
synchronized (mLock) {
|
||||
handleLocationChangedLocked(location, this);
|
||||
}
|
||||
@@ -986,7 +984,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
@Override
|
||||
public void onReportLocation(List<Location> locations) {
|
||||
// move calls coming from below LMS onto a different thread to avoid deadlock
|
||||
runInternal(() -> {
|
||||
mHandler.post(() -> {
|
||||
synchronized (mLock) {
|
||||
LocationProvider gpsProvider = getLocationProviderLocked(GPS_PROVIDER);
|
||||
if (gpsProvider == null || !gpsProvider.isUseableLocked()) {
|
||||
@@ -1012,7 +1010,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
@Override
|
||||
public void onSetEnabled(boolean enabled) {
|
||||
// move calls coming from below LMS onto a different thread to avoid deadlock
|
||||
runInternal(() -> {
|
||||
mHandler.post(() -> {
|
||||
synchronized (mLock) {
|
||||
if (enabled == mEnabled) {
|
||||
return;
|
||||
@@ -1134,16 +1132,6 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
mUseable = false;
|
||||
updateProviderUseableLocked(this);
|
||||
}
|
||||
|
||||
// binder transactions coming from below LMS (ie location providers) need to be moved onto
|
||||
// a different thread to avoid potential deadlock as code reenters the location providers
|
||||
private void runInternal(Runnable runnable) {
|
||||
if (Looper.myLooper() == mHandler.getLooper()) {
|
||||
runnable.run();
|
||||
} else {
|
||||
mHandler.post(runnable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MockLocationProvider extends LocationProvider {
|
||||
@@ -1299,7 +1287,11 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
// are high power (has a high power provider with an interval under a threshold).
|
||||
for (UpdateRecord updateRecord : mUpdateRecords.values()) {
|
||||
LocationProvider provider = getLocationProviderLocked(updateRecord.mProvider);
|
||||
if (provider == null || !provider.isUseableLocked()) {
|
||||
if (provider == null) {
|
||||
continue;
|
||||
}
|
||||
if (!provider.isUseableLocked()
|
||||
&& !updateRecord.mRealRequest.isLocationSettingsIgnored()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1981,14 +1973,22 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
|
||||
if (records != null) {
|
||||
for (UpdateRecord record : records) {
|
||||
if (isCurrentProfileLocked(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
|
||||
// Sends a notification message to the receiver
|
||||
if (!record.mReceiver.callProviderEnabledLocked(provider.getName(), useable)) {
|
||||
if (deadReceivers == null) {
|
||||
deadReceivers = new ArrayList<>();
|
||||
}
|
||||
deadReceivers.add(record.mReceiver);
|
||||
if (!isCurrentProfileLocked(
|
||||
UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// requests that ignore location settings will never provider notifications
|
||||
if (record.mRealRequest.isLocationSettingsIgnored()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Sends a notification message to the receiver
|
||||
if (!record.mReceiver.callProviderEnabledLocked(provider.getName(), useable)) {
|
||||
if (deadReceivers == null) {
|
||||
deadReceivers = new ArrayList<>();
|
||||
}
|
||||
deadReceivers.add(record.mReceiver);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2028,39 +2028,47 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
|
||||
if (provider.isUseableLocked() && records != null && !records.isEmpty()) {
|
||||
if (records != null && !records.isEmpty()) {
|
||||
// initialize the low power mode to true and set to false if any of the records requires
|
||||
providerRequest.lowPowerMode = true;
|
||||
for (UpdateRecord record : records) {
|
||||
if (isCurrentProfileLocked(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
|
||||
if (checkLocationAccess(
|
||||
record.mReceiver.mIdentity.mPid,
|
||||
record.mReceiver.mIdentity.mUid,
|
||||
record.mReceiver.mIdentity.mPackageName,
|
||||
record.mReceiver.mAllowedResolutionLevel)) {
|
||||
LocationRequest locationRequest = record.mRealRequest;
|
||||
long interval = locationRequest.getInterval();
|
||||
if (!isCurrentProfileLocked(
|
||||
UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
|
||||
continue;
|
||||
}
|
||||
if (!checkLocationAccess(
|
||||
record.mReceiver.mIdentity.mPid,
|
||||
record.mReceiver.mIdentity.mUid,
|
||||
record.mReceiver.mIdentity.mPackageName,
|
||||
record.mReceiver.mAllowedResolutionLevel)) {
|
||||
continue;
|
||||
}
|
||||
if (!provider.isUseableLocked()
|
||||
&& !record.mRealRequest.isLocationSettingsIgnored()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
|
||||
if (!record.mIsForegroundUid) {
|
||||
interval = Math.max(interval, backgroundThrottleInterval);
|
||||
}
|
||||
if (interval != locationRequest.getInterval()) {
|
||||
locationRequest = new LocationRequest(locationRequest);
|
||||
locationRequest.setInterval(interval);
|
||||
}
|
||||
}
|
||||
LocationRequest locationRequest = record.mRealRequest;
|
||||
long interval = locationRequest.getInterval();
|
||||
|
||||
record.mRequest = locationRequest;
|
||||
providerRequest.locationRequests.add(locationRequest);
|
||||
if (!locationRequest.isLowPowerMode()) {
|
||||
providerRequest.lowPowerMode = false;
|
||||
}
|
||||
if (interval < providerRequest.interval) {
|
||||
providerRequest.reportLocation = true;
|
||||
providerRequest.interval = interval;
|
||||
}
|
||||
if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
|
||||
if (!record.mIsForegroundUid) {
|
||||
interval = Math.max(interval, backgroundThrottleInterval);
|
||||
}
|
||||
if (interval != locationRequest.getInterval()) {
|
||||
locationRequest = new LocationRequest(locationRequest);
|
||||
locationRequest.setInterval(interval);
|
||||
}
|
||||
}
|
||||
|
||||
record.mRequest = locationRequest;
|
||||
providerRequest.locationRequests.add(locationRequest);
|
||||
if (!locationRequest.isLowPowerMode()) {
|
||||
providerRequest.lowPowerMode = false;
|
||||
}
|
||||
if (interval < providerRequest.interval) {
|
||||
providerRequest.reportLocation = true;
|
||||
providerRequest.interval = interval;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2328,6 +2336,10 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
Manifest.permission.UPDATE_APP_OPS_STATS, null);
|
||||
}
|
||||
if (request.isLocationSettingsIgnored()) {
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
Manifest.permission.WRITE_SECURE_SETTINGS, null);
|
||||
}
|
||||
boolean callerHasLocationHardwarePermission =
|
||||
mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
|
||||
== PERMISSION_GRANTED;
|
||||
@@ -2397,12 +2409,14 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
oldRecord.disposeLocked(false);
|
||||
}
|
||||
|
||||
if (provider.isUseableLocked()) {
|
||||
applyRequirementsLocked(name);
|
||||
} else {
|
||||
// Notify the listener that updates are currently disabled
|
||||
if (!provider.isUseableLocked() && !request.isLocationSettingsIgnored()) {
|
||||
// Notify the listener that updates are currently disabled - but only if the request
|
||||
// does not ignore location settings
|
||||
receiver.callProviderEnabledLocked(name, false);
|
||||
}
|
||||
|
||||
applyRequirementsLocked(name);
|
||||
|
||||
// Update the monitoring here just in case multiple location requests were added to the
|
||||
// same receiver (this request may be high power and the initial might not have been).
|
||||
receiver.updateMonitoring(true);
|
||||
@@ -3002,26 +3016,29 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!provider.isPassiveLocked()) {
|
||||
// notify passive provider of the new location
|
||||
mPassiveProvider.updateLocation(location);
|
||||
// only notify passive provider and update last location for locations that come from
|
||||
// useable providers
|
||||
if (provider.isUseableLocked()) {
|
||||
if (!provider.isPassiveLocked()) {
|
||||
mPassiveProvider.updateLocation(location);
|
||||
}
|
||||
}
|
||||
|
||||
if (D) Log.d(TAG, "incoming location: " + location);
|
||||
long now = SystemClock.elapsedRealtime();
|
||||
updateLastLocationLocked(location, provider.getName());
|
||||
// mLastLocation should have been updated from the updateLastLocationLocked call above.
|
||||
Location lastLocation = mLastLocation.get(provider.getName());
|
||||
if (lastLocation == null) {
|
||||
Log.e(TAG, "handleLocationChangedLocked() updateLastLocation failed");
|
||||
return;
|
||||
if (provider.isUseableLocked()) {
|
||||
updateLastLocationLocked(location, provider.getName());
|
||||
}
|
||||
|
||||
// Update last known coarse interval location if enough time has passed.
|
||||
Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider.getName());
|
||||
Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(
|
||||
provider.getName());
|
||||
if (lastLocationCoarseInterval == null) {
|
||||
lastLocationCoarseInterval = new Location(location);
|
||||
mLastLocationCoarseInterval.put(provider.getName(), lastLocationCoarseInterval);
|
||||
|
||||
if (provider.isUseableLocked()) {
|
||||
mLastLocationCoarseInterval.put(provider.getName(), lastLocationCoarseInterval);
|
||||
}
|
||||
}
|
||||
long timeDiffNanos = location.getElapsedRealtimeNanos()
|
||||
- lastLocationCoarseInterval.getElapsedRealtimeNanos();
|
||||
@@ -3052,6 +3069,10 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
Receiver receiver = r.mReceiver;
|
||||
boolean receiverDead = false;
|
||||
|
||||
if (!provider.isUseableLocked() && !r.mRealRequest.isLocationSettingsIgnored()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int receiverUserId = UserHandle.getUserId(receiver.mIdentity.mUid);
|
||||
if (!isCurrentProfileLocked(receiverUserId)
|
||||
&& !isLocationProviderLocked(receiver.mIdentity.mUid)) {
|
||||
@@ -3087,7 +3108,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
|
||||
notifyLocation = coarseLocation; // use coarse location
|
||||
} else {
|
||||
notifyLocation = lastLocation; // use fine location
|
||||
notifyLocation = location; // use fine location
|
||||
}
|
||||
if (notifyLocation != null) {
|
||||
Location lastLoc = r.mLastFixBroadcast;
|
||||
|
||||
Reference in New Issue
Block a user