Merge "Various location fixes"

This commit is contained in:
TreeHugger Robot
2020-10-06 09:41:06 +00:00
committed by Android (Google) Code Review
9 changed files with 305 additions and 257 deletions

View File

@@ -4171,7 +4171,7 @@ package android.location {
method @Deprecated @NonNull public String getProvider();
method public int getQuality();
method @Deprecated public float getSmallestDisplacement();
method @Nullable public android.os.WorkSource getWorkSource();
method @NonNull public android.os.WorkSource getWorkSource();
method public boolean isHiddenFromAppOps();
method public boolean isLocationSettingsIgnored();
method public boolean isLowPower();

View File

@@ -1729,7 +1729,7 @@ package android.location {
}
public final class LocationRequest implements android.os.Parcelable {
method @Nullable public android.os.WorkSource getWorkSource();
method @NonNull public android.os.WorkSource getWorkSource();
method public boolean isHiddenFromAppOps();
method public boolean isLocationSettingsIgnored();
method public boolean isLowPower();

View File

@@ -88,6 +88,16 @@ import java.util.function.Consumer;
@RequiresFeature(PackageManager.FEATURE_LOCATION)
public class LocationManager {
/**
* For apps targeting Android S and above, LocationRequest system APIs may not be used with
* PendingIntent location requests.
*
* @hide
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
public static final long PREVENT_PENDING_INTENT_SYSTEM_API_USAGE = 169887240L;
/**
* For apps targeting Android S and above, location clients may receive historical locations
* (from before the present time) under some circumstances.

View File

@@ -250,7 +250,7 @@ public final class LocationRequest implements Parcelable {
boolean hiddenFromAppOps,
boolean locationSettingsIgnored,
boolean lowPower,
@Nullable WorkSource workSource) {
WorkSource workSource) {
Preconditions.checkArgument(intervalMillis != PASSIVE_INTERVAL || quality == POWER_NONE);
Preconditions.checkArgument(minUpdateIntervalMillis <= intervalMillis);
@@ -265,7 +265,7 @@ public final class LocationRequest implements Parcelable {
mHideFromAppOps = hiddenFromAppOps;
mLowPower = lowPower;
mLocationSettingsIgnored = locationSettingsIgnored;
mWorkSource = workSource;
mWorkSource = Objects.requireNonNull(workSource);
}
/**
@@ -645,12 +645,15 @@ public final class LocationRequest implements Parcelable {
@SystemApi
@Deprecated
public void setWorkSource(@Nullable WorkSource workSource) {
if (workSource == null) {
workSource = new WorkSource();
}
mWorkSource = workSource;
}
/**
* Returns the work source used for power blame for this request. If null, the system is free to
* assign power blame as it deems most appropriate.
* Returns the work source used for power blame for this request. If empty, the system is free
* to assign power blame as it deems most appropriate.
*
* @return the work source used for power blame for this request
*
@@ -658,7 +661,7 @@ public final class LocationRequest implements Parcelable {
*/
@TestApi
@SystemApi
public @Nullable WorkSource getWorkSource() {
public @NonNull WorkSource getWorkSource() {
return mWorkSource;
}
@@ -1062,9 +1065,9 @@ public final class LocationRequest implements Parcelable {
}
/**
* Sets the work source to use for power blame for this location request. Defaults to null,
* which implies the system is free to assign power blame as it determines best for this
* request (which usually means blaming the owner of the location listener).
* Sets the work source to use for power blame for this location request. Defaults to an
* empty WorkSource, which implies the system is free to assign power blame as it determines
* best for this request (which usually means blaming the owner of the location listener).
*
* <p>Permissions enforcement occurs when resulting location request is actually used, not
* when this method is invoked.
@@ -1108,7 +1111,7 @@ public final class LocationRequest implements Parcelable {
mHiddenFromAppOps,
mLocationSettingsIgnored,
mLowPower,
mWorkSource);
new WorkSource(mWorkSource));
}
}
}

View File

@@ -4111,7 +4111,7 @@ package android.location {
method @Deprecated @NonNull public String getProvider();
method public int getQuality();
method @Deprecated public float getSmallestDisplacement();
method @Nullable public android.os.WorkSource getWorkSource();
method @NonNull public android.os.WorkSource getWorkSource();
method public boolean isHiddenFromAppOps();
method public boolean isLocationSettingsIgnored();
method public boolean isLowPower();

View File

@@ -111,7 +111,7 @@ public class LocationFudger {
*/
public Location createCoarse(Location fine) {
synchronized (this) {
if (fine == mCachedFineLocation) {
if (fine == mCachedFineLocation || fine == mCachedCoarseLocation) {
return mCachedCoarseLocation;
}
}

View File

@@ -17,12 +17,14 @@
package com.android.server.location;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
import static android.app.compat.CompatChanges.isChangeEnabled;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.location.LocationManager.FUSED_PROVIDER;
import static android.location.LocationManager.GPS_PROVIDER;
import static android.location.LocationManager.NETWORK_PROVIDER;
import static android.location.LocationManager.PREVENT_PENDING_INTENT_SYSTEM_API_USAGE;
import static android.location.LocationRequest.LOW_POWER_EXCEPTIONS;
import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
@@ -75,7 +77,6 @@ import android.os.WorkSource.WorkChain;
import android.stats.location.LocationStatsEnums;
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.TimeUtils;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.location.ProviderProperties;
@@ -570,7 +571,7 @@ public class LocationManagerService extends ILocationManager.Stub {
new IllegalArgumentException());
}
request = validateLocationRequest(request);
request = validateLocationRequest(request, identity);
LocationProviderManager manager = getLocationProviderManager(provider);
Preconditions.checkArgument(manager != null,
@@ -592,7 +593,21 @@ public class LocationManagerService extends ILocationManager.Stub {
// clients in the system process must have an attribution tag set
Preconditions.checkArgument(identity.getPid() != Process.myPid() || attributionTag != null);
request = validateLocationRequest(request);
// pending intents requests may not use system apis because we do not keep track if clients
// lose the relevant permissions, and thus should not get the benefit of those apis. its
// simplest to ensure these apis are simply never set for pending intent requests. the same
// does not apply for listener requests since those will have the process (including the
// listener) killed on permission removal
boolean usesSystemApi = request.isLowPower()
|| request.isHiddenFromAppOps()
|| request.isLocationSettingsIgnored()
|| !request.getWorkSource().isEmpty();
if (usesSystemApi
&& isChangeEnabled(PREVENT_PENDING_INTENT_SYSTEM_API_USAGE, identity.getUid())) {
throw new SecurityException("PendingIntent location requests may not use system APIs");
}
request = validateLocationRequest(request, identity);
LocationProviderManager manager = getLocationProviderManager(provider);
Preconditions.checkArgument(manager != null,
@@ -601,9 +616,9 @@ public class LocationManagerService extends ILocationManager.Stub {
manager.registerLocationRequest(request, identity, permissionLevel, pendingIntent);
}
private LocationRequest validateLocationRequest(LocationRequest request) {
WorkSource workSource = request.getWorkSource();
if (workSource != null && !workSource.isEmpty()) {
private LocationRequest validateLocationRequest(LocationRequest request,
CallerIdentity identity) {
if (!request.getWorkSource().isEmpty()) {
mContext.enforceCallingOrSelfPermission(
permission.UPDATE_DEVICE_STATS,
"setting a work source requires " + permission.UPDATE_DEVICE_STATS);
@@ -634,23 +649,25 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
if (request.getWorkSource() != null) {
if (request.getWorkSource().isEmpty()) {
sanitized.setWorkSource(null);
} else if (request.getWorkSource().getPackageName(0) == null) {
Log.w(TAG, "received (and ignoring) illegal worksource with no package name");
sanitized.setWorkSource(null);
} else {
List<WorkChain> workChains = request.getWorkSource().getWorkChains();
if (workChains != null && !workChains.isEmpty() && workChains.get(
0).getAttributionTag() == null) {
Log.w(TAG,
"received (and ignoring) illegal worksource with no attribution tag");
sanitized.setWorkSource(null);
}
WorkSource workSource = new WorkSource(request.getWorkSource());
if (workSource.size() > 0 && workSource.getPackageName(0) == null) {
Log.w(TAG, "received (and ignoring) illegal worksource with no package name");
workSource.clear();
} else {
List<WorkChain> workChains = workSource.getWorkChains();
if (workChains != null && !workChains.isEmpty()
&& workChains.get(0).getAttributionTag() == null) {
Log.w(TAG,
"received (and ignoring) illegal worksource with no attribution tag");
workSource.clear();
}
}
if (workSource.isEmpty()) {
identity.addToWorkSource(workSource);
}
sanitized.setWorkSource(workSource);
return sanitized.build();
}
@@ -684,15 +701,7 @@ public class LocationManagerService extends ILocationManager.Stub {
return null;
}
Location location = manager.getLastLocation(identity, permissionLevel, false);
// lastly - note app ops
if (!mInjector.getAppOpsHelper().noteOpNoThrow(LocationPermissions.asAppOp(permissionLevel),
identity)) {
return null;
}
return location;
return manager.getLastLocation(identity, permissionLevel, false);
}
@Nullable
@@ -710,7 +719,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// clients in the system process must have an attribution tag set
Preconditions.checkState(identity.getPid() != Process.myPid() || attributionTag != null);
request = validateLocationRequest(request);
request = validateLocationRequest(request, identity);
LocationProviderManager manager = getLocationProviderManager(provider);
Preconditions.checkArgument(manager != null,
@@ -727,7 +736,6 @@ public class LocationManagerService extends ILocationManager.Stub {
return null;
}
// use fine permission level to avoid creating unnecessary coarse locations
Location location = gpsManager.getLastLocationUnsafe(UserHandle.USER_ALL,
PERMISSION_FINE, false, Long.MAX_VALUE);
if (location == null) {
@@ -1116,9 +1124,8 @@ public class LocationManagerService extends ILocationManager.Stub {
return;
}
ipw.print("Location Manager State:");
ipw.println("Location Manager State:");
ipw.increaseIndent();
ipw.println("Elapsed Realtime: " + TimeUtils.formatDuration(SystemClock.elapsedRealtime()));
ipw.println("User Info:");
ipw.increaseIndent();

View File

@@ -31,6 +31,7 @@ import static android.os.PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF
import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF;
import static com.android.internal.location.ProviderRequest.EMPTY_REQUEST;
import static com.android.internal.location.ProviderRequest.INTERVAL_DISABLED;
import static com.android.server.location.LocationManagerService.D;
import static com.android.server.location.LocationManagerService.TAG;
import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
@@ -238,8 +239,7 @@ class LocationProviderManager extends
protected abstract class Registration extends RemoteListenerRegistration<LocationRequest,
LocationTransport, LocationListenerOperation> {
@PermissionLevel protected final int mPermissionLevel;
private final WorkSource mWorkSource;
private final @PermissionLevel int mPermissionLevel;
// we cache these values because checking/calculating on the fly is more expensive
private boolean mPermitted;
@@ -247,22 +247,17 @@ class LocationProviderManager extends
private LocationRequest mProviderLocationRequest;
private boolean mIsUsingHighPower;
@Nullable private Location mLastLocation = null;
private @Nullable Location mLastLocation = null;
protected Registration(LocationRequest request, CallerIdentity identity,
LocationTransport transport, @PermissionLevel int permissionLevel) {
super(Objects.requireNonNull(request), identity, transport);
Preconditions.checkArgument(permissionLevel > PERMISSION_NONE);
Preconditions.checkArgument(!request.getWorkSource().isEmpty());
mPermissionLevel = permissionLevel;
if (request.getWorkSource() != null && !request.getWorkSource().isEmpty()) {
mWorkSource = request.getWorkSource();
} else {
mWorkSource = identity.addToWorkSource(null);
}
mProviderLocationRequest = super.getRequest();
mProviderLocationRequest = request;
}
@GuardedBy("mLock")
@@ -376,6 +371,10 @@ class LocationProviderManager extends
return mLastLocation;
}
public @PermissionLevel int getPermissionLevel() {
return mPermissionLevel;
}
public final boolean isForeground() {
return mForeground;
}
@@ -389,10 +388,6 @@ class LocationProviderManager extends
return LocationProviderManager.this;
}
protected final WorkSource getWorkSource() {
return mWorkSource;
}
@GuardedBy("mLock")
private void onHighPowerUsageChanged() {
boolean isUsingHighPower = isUsingHighPower();
@@ -609,7 +604,7 @@ class LocationProviderManager extends
mWakeLock = Objects.requireNonNull(mContext.getSystemService(PowerManager.class))
.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
mWakeLock.setReferenceCounted(true);
mWakeLock.setWorkSource(getWorkSource());
mWakeLock.setWorkSource(request.getWorkSource());
}
@Override
@@ -628,7 +623,7 @@ class LocationProviderManager extends
onAlarm();
} else if (mExpirationRealtimeMs < Long.MAX_VALUE) {
mAlarmHelper.setDelayedAlarm(mExpirationRealtimeMs - registerTimeMs, this,
getWorkSource());
getRequest().getWorkSource());
}
// start listening for provider enabled/disabled events
@@ -690,7 +685,7 @@ class LocationProviderManager extends
if (maxLocationAgeMs > MIN_REQUEST_DELAY_MS) {
Location lastLocation = getLastLocationUnsafe(
getIdentity().getUserId(),
PERMISSION_FINE, // acceptLocationChange() handles coarsening this
getPermissionLevel(),
getRequest().isLocationSettingsIgnored(),
maxLocationAgeMs);
if (lastLocation != null) {
@@ -732,18 +727,8 @@ class LocationProviderManager extends
return null;
}
Location location;
switch (mPermissionLevel) {
case PERMISSION_FINE:
location = fineLocation;
break;
case PERMISSION_COARSE:
location = mLocationFudger.createCoarse(fineLocation);
break;
default:
// shouldn't be possible to have a client added without location permissions
throw new AssertionError();
}
Location location = Objects.requireNonNull(
getPermittedLocation(fineLocation, getPermissionLevel()));
Location lastDeliveredLocation = getLastDeliveredLocation();
if (lastDeliveredLocation != null) {
@@ -765,7 +750,7 @@ class LocationProviderManager extends
}
// note app ops
if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(mPermissionLevel),
if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(getPermissionLevel()),
getIdentity())) {
if (D) {
Log.w(TAG, "noteOp denied for " + getIdentity());
@@ -962,7 +947,7 @@ class LocationProviderManager extends
}
protected final class GetCurrentLocationListenerRegistration extends Registration implements
IBinder.DeathRecipient, ProviderEnabledListener, OnAlarmListener {
IBinder.DeathRecipient, OnAlarmListener {
private volatile LocationTransport mTransport;
@@ -974,11 +959,6 @@ class LocationProviderManager extends
mTransport = transport;
}
@GuardedBy("mLock")
void deliverLocation(@Nullable Location location) {
executeSafely(getExecutor(), () -> mTransport, acceptLocationChange(location));
}
@Override
protected void onListenerUnregister() {
mTransport = null;
@@ -1001,29 +981,13 @@ class LocationProviderManager extends
onAlarm();
} else if (mExpirationRealtimeMs < Long.MAX_VALUE) {
mAlarmHelper.setDelayedAlarm(mExpirationRealtimeMs - registerTimeMs, this,
getWorkSource());
}
// if this request is ignoring location settings, then we don't want to immediately fail
// it if the provider is disabled or becomes disabled.
if (!getRequest().isLocationSettingsIgnored()) {
// start listening for provider enabled/disabled events
addEnabledListener(this);
// if the provider is currently disabled fail immediately
int userId = getIdentity().getUserId();
if (!isEnabled(userId)) {
deliverLocation(null);
}
getRequest().getWorkSource());
}
}
@GuardedBy("mLock")
@Override
protected void onProviderListenerUnregister() {
// stop listening for provider enabled/disabled events
removeEnabledListener(this);
// remove alarm for expiration
if (mExpirationRealtimeMs < Long.MAX_VALUE) {
mAlarmHelper.cancel(this);
@@ -1032,6 +996,38 @@ class LocationProviderManager extends
((IBinder) getKey()).unlinkToDeath(this, 0);
}
@GuardedBy("mLock")
@Override
protected LocationListenerOperation onProviderListenerActive() {
Location lastLocation = getLastLocationUnsafe(
getIdentity().getUserId(),
getPermissionLevel(),
getRequest().isLocationSettingsIgnored(),
MAX_CURRENT_LOCATION_AGE_MS);
if (lastLocation != null) {
return acceptLocationChange(lastLocation);
}
return null;
}
@GuardedBy("mLock")
@Override
protected LocationListenerOperation onProviderListenerInactive() {
if (!getRequest().isLocationSettingsIgnored()) {
// if we go inactive for any reason, fail immediately
return acceptLocationChange(null);
}
return null;
}
void deliverNull() {
synchronized (mLock) {
executeSafely(getExecutor(), () -> mTransport, acceptLocationChange(null));
}
}
@Override
public void onAlarm() {
if (D) {
@@ -1041,9 +1037,10 @@ class LocationProviderManager extends
}
synchronized (mLock) {
deliverLocation(null);
// no need to remove alarm after it's fired
mExpirationRealtimeMs = Long.MAX_VALUE;
deliverNull();
}
}
@@ -1062,29 +1059,16 @@ class LocationProviderManager extends
}
// lastly - note app ops
Location location;
if (fineLocation == null) {
location = null;
} else if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(mPermissionLevel),
if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(getPermissionLevel()),
getIdentity())) {
if (D) {
Log.w(TAG, "noteOp denied for " + getIdentity());
}
location = null;
} else {
switch (mPermissionLevel) {
case PERMISSION_FINE:
location = fineLocation;
break;
case PERMISSION_COARSE:
location = mLocationFudger.createCoarse(fineLocation);
break;
default:
// shouldn't be possible to have a client added without location permissions
throw new AssertionError();
}
fineLocation = null;
}
Location location = getPermittedLocation(fineLocation, getPermissionLevel());
return new LocationListenerOperation() {
@Override
public Location getLocation() {
@@ -1119,22 +1103,6 @@ class LocationProviderManager extends
};
}
@Override
public void onProviderEnabledChanged(String provider, int userId, boolean enabled) {
Preconditions.checkState(mName.equals(provider));
if (userId != getIdentity().getUserId()) {
return;
}
// if the provider is disabled we give up on current location immediately
if (!getRequest().isLocationSettingsIgnored() && !enabled) {
synchronized (mLock) {
deliverLocation(null);
}
}
}
@Override
public void binderDied() {
try {
@@ -1449,24 +1417,34 @@ class LocationProviderManager extends
}
}
Location location = getLastLocationUnsafe(identity.getUserId(), permissionLevel,
ignoreLocationSettings, Long.MAX_VALUE);
// lastly - note app ops
if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(permissionLevel),
identity)) {
return null;
}
// we don't note op here because we don't know what the client intends to do with the
// location, the client is responsible for noting if necessary
Location location = getPermittedLocation(
getLastLocationUnsafe(
identity.getUserId(),
permissionLevel,
ignoreLocationSettings,
Long.MAX_VALUE),
permissionLevel);
if (identity.getPid() == Process.myPid() && location != null) {
if (location != null && identity.getPid() == Process.myPid()) {
// if delivering to the same process, make a copy of the location first (since
// location is mutable)
return new Location(location);
} else {
return location;
location = new Location(location);
}
return location;
}
/**
* This function does not perform any permissions or safety checks, by calling it you are
* committing to performing all applicable checks yourself.
* committing to performing all applicable checks yourself. This always returns a "fine"
* location, even if the permissionLevel is coarse. You are responsible for coarsening the
* location if necessary.
*/
@Nullable
public Location getLastLocationUnsafe(int userId, @PermissionLevel int permissionLevel,
@@ -1535,11 +1513,10 @@ class LocationProviderManager extends
mLastLocations.put(userId, lastLocation);
}
Location coarseLocation = mLocationFudger.createCoarse(location);
if (isEnabled(userId)) {
lastLocation.set(location, coarseLocation);
lastLocation.set(location);
}
lastLocation.setBypass(location, coarseLocation);
lastLocation.setBypass(location);
}
}
@@ -1560,51 +1537,26 @@ class LocationProviderManager extends
permissionLevel);
synchronized (mLock) {
// shortcut various failure conditions so that we can return immediately rather than
// waiting for location to timeout
if (mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(),
identity.getPackageName())) {
registration.deliverLocation(null);
return null;
}
if (!request.isLocationSettingsIgnored()) {
if (!isEnabled(identity.getUserId())) {
registration.deliverLocation(null);
return null;
}
if (!identity.isSystem() && !mUserHelper.isCurrentUserId(identity.getUserId())) {
registration.deliverLocation(null);
return null;
}
}
Location lastLocation = getLastLocationUnsafe(
identity.getUserId(),
permissionLevel,
request.isLocationSettingsIgnored(),
MAX_CURRENT_LOCATION_AGE_MS);
if (lastLocation != null) {
registration.deliverLocation(lastLocation);
return null;
}
// if last location isn't good enough then we add a location request
long ident = Binder.clearCallingIdentity();
try {
addRegistration(callback.asBinder(), registration);
if (!registration.isActive()) {
// if the registration never activated, fail it immediately
registration.deliverNull();
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
ICancellationSignal cancelTransport = CancellationSignal.createTransport();
CancellationSignal cancellationSignal = CancellationSignal.fromTransport(cancelTransport);
cancellationSignal.setOnCancelListener(SingleUseCallback.wrap(
() -> {
synchronized (mLock) {
removeRegistration(callback.asBinder(), registration);
}
}));
CancellationSignal.fromTransport(cancelTransport)
.setOnCancelListener(SingleUseCallback.wrap(
() -> {
synchronized (mLock) {
removeRegistration(callback.asBinder(), registration);
}
}));
return cancelTransport;
}
@@ -1619,16 +1571,16 @@ class LocationProviderManager extends
public void registerLocationRequest(LocationRequest request, CallerIdentity identity,
@PermissionLevel int permissionLevel, ILocationListener listener) {
LocationListenerRegistration registration = new LocationListenerRegistration(
request,
identity,
new LocationListenerTransport(listener),
permissionLevel);
synchronized (mLock) {
long ident = Binder.clearCallingIdentity();
try {
addRegistration(
listener.asBinder(),
new LocationListenerRegistration(
request,
identity,
new LocationListenerTransport(listener),
permissionLevel));
addRegistration(listener.asBinder(), registration);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -1637,16 +1589,16 @@ class LocationProviderManager extends
public void registerLocationRequest(LocationRequest request, CallerIdentity callerIdentity,
@PermissionLevel int permissionLevel, PendingIntent pendingIntent) {
LocationPendingIntentRegistration registration = new LocationPendingIntentRegistration(
request,
callerIdentity,
new LocationPendingIntentTransport(mContext, pendingIntent),
permissionLevel);
synchronized (mLock) {
long identity = Binder.clearCallingIdentity();
try {
addRegistration(
pendingIntent,
new LocationPendingIntentRegistration(
request,
callerIdentity,
new LocationPendingIntentTransport(mContext, pendingIntent),
permissionLevel));
addRegistration(pendingIntent, registration);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -1897,7 +1849,7 @@ class LocationProviderManager extends
Preconditions.checkState(Thread.holdsLock(mLock));
}
long intervalMs = Long.MAX_VALUE;
long intervalMs = INTERVAL_DISABLED;
boolean locationSettingsIgnored = false;
boolean lowPower = true;
ArrayList<LocationRequest> locationRequests = new ArrayList<>(registrations.size());
@@ -1916,12 +1868,18 @@ class LocationProviderManager extends
locationRequests.add(request);
}
if (intervalMs == INTERVAL_DISABLED) {
return EMPTY_REQUEST;
}
// calculate who to blame for power in a somewhat arbitrary fashion. we pick a threshold
// interval slightly higher that the minimum interval, and spread the blame across all
// contributing registrations under that threshold (since worksource does not allow us to
// represent differing power blame ratios).
long thresholdIntervalMs = (intervalMs + 1000) * 3 / 2;
if (thresholdIntervalMs < 0 || thresholdIntervalMs >= PASSIVE_INTERVAL) {
long thresholdIntervalMs;
try {
thresholdIntervalMs = Math.multiplyExact(Math.addExact(intervalMs, 1000) / 2, 3);
} catch (ArithmeticException e) {
// check for and handle overflow by setting to one below the passive interval so passive
// requests are automatically skipped
thresholdIntervalMs = PASSIVE_INTERVAL - 1;
@@ -1930,7 +1888,7 @@ class LocationProviderManager extends
WorkSource workSource = new WorkSource();
for (Registration registration : registrations) {
if (registration.getRequest().getIntervalMillis() <= thresholdIntervalMs) {
workSource.add(registration.getWorkSource());
workSource.add(registration.getRequest().getWorkSource());
}
}
@@ -1963,7 +1921,7 @@ class LocationProviderManager extends
// location for our calculations instead. this prevents spammy add/remove behavior
last = getLastLocationUnsafe(
registration.getIdentity().getUserId(),
PERMISSION_FINE,
registration.getPermissionLevel(),
false,
locationRequest.getIntervalMillis());
}
@@ -2256,6 +2214,20 @@ class LocationProviderManager extends
updateRegistrations(registration -> registration.getIdentity().getUserId() == userId);
}
@Nullable
private Location getPermittedLocation(@Nullable Location fineLocation,
@PermissionLevel int permissionLevel) {
switch (permissionLevel) {
case PERMISSION_FINE:
return fineLocation;
case PERMISSION_COARSE:
return fineLocation != null ? mLocationFudger.createCoarse(fineLocation) : null;
default:
// shouldn't be possible to have a client added without location permissions
throw new AssertionError();
}
}
public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) {
synchronized (mLock) {
ipw.print(mName);
@@ -2306,10 +2278,14 @@ class LocationProviderManager extends
public void clearMock() {
if (mFineLocation != null && mFineLocation.isFromMockProvider()) {
mFineLocation = null;
}
if (mCoarseLocation != null && mCoarseLocation.isFromMockProvider()) {
mCoarseLocation = null;
}
if (mFineBypassLocation != null && mFineBypassLocation.isFromMockProvider()) {
mFineBypassLocation = null;
}
if (mCoarseBypassLocation != null && mCoarseBypassLocation.isFromMockProvider()) {
mCoarseBypassLocation = null;
}
}
@@ -2340,14 +2316,14 @@ class LocationProviderManager extends
}
}
public void set(Location fineLocation, Location coarseLocation) {
mFineLocation = calculateNextFine(mFineLocation, fineLocation);
mCoarseLocation = calculateNextCoarse(mCoarseLocation, coarseLocation);
public void set(Location location) {
mFineLocation = calculateNextFine(mFineLocation, location);
mCoarseLocation = calculateNextCoarse(mCoarseLocation, location);
}
public void setBypass(Location fineLocation, Location coarseLocation) {
mFineBypassLocation = calculateNextFine(mFineBypassLocation, fineLocation);
mCoarseBypassLocation = calculateNextCoarse(mCoarseBypassLocation, coarseLocation);
public void setBypass(Location location) {
mFineBypassLocation = calculateNextFine(mFineBypassLocation, location);
mCoarseBypassLocation = calculateNextCoarse(mCoarseBypassLocation, location);
}
private Location calculateNextFine(@Nullable Location oldFine, Location newFine) {
@@ -2369,8 +2345,8 @@ class LocationProviderManager extends
}
// update last coarse interval only if enough time has passed
if (newCoarse.getElapsedRealtimeNanos() - MIN_COARSE_INTERVAL_MS
> oldCoarse.getElapsedRealtimeNanos()) {
if (newCoarse.getElapsedRealtimeMillis() - MIN_COARSE_INTERVAL_MS
> oldCoarse.getElapsedRealtimeMillis()) {
return newCoarse;
} else {
return oldCoarse;

View File

@@ -66,6 +66,7 @@ import android.os.IRemoteCallback;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.WorkSource;
import android.platform.test.annotations.Presubmit;
import android.util.Log;
@@ -111,6 +112,7 @@ public class LocationProviderManagerTest {
private static final CallerIdentity IDENTITY = CallerIdentity.forTest(CURRENT_USER, 1,
"mypackage",
"attribution");
private static final WorkSource WORK_SOURCE = new WorkSource(IDENTITY.getUid());
private Random mRandom;
@@ -333,7 +335,7 @@ public class LocationProviderManagerTest {
@Test
public void testPassive_Listener() throws Exception {
ILocationListener listener = createMockLocationListener();
LocationRequest request = new LocationRequest.Builder(0).build();
LocationRequest request = new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build();
mPassive.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
Location loc = createLocation(NAME, mRandom);
@@ -358,8 +360,11 @@ public class LocationProviderManagerTest {
ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
ILocationListener listener = createMockLocationListener();
mManager.registerLocationRequest(new LocationRequest.Builder(0).build(), IDENTITY,
PERMISSION_FINE, listener);
mManager.registerLocationRequest(
new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build(),
IDENTITY,
PERMISSION_FINE,
listener);
Location loc = createLocation(NAME, mRandom);
mProvider.setProviderLocation(loc);
@@ -402,8 +407,11 @@ public class LocationProviderManagerTest {
"attribution");
ILocationListener listener = createMockLocationListener();
mManager.registerLocationRequest(new LocationRequest.Builder(0).build(), identity,
PERMISSION_FINE, listener);
mManager.registerLocationRequest(
new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build(),
identity,
PERMISSION_FINE,
listener);
Location loc = createLocation(NAME, mRandom);
mProvider.setProviderLocation(loc);
@@ -415,8 +423,11 @@ public class LocationProviderManagerTest {
@Test
public void testRegisterListener_Unregister() throws Exception {
ILocationListener listener = createMockLocationListener();
mManager.registerLocationRequest(new LocationRequest.Builder(0).build(), IDENTITY,
PERMISSION_FINE, listener);
mManager.registerLocationRequest(
new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build(),
IDENTITY,
PERMISSION_FINE,
listener);
mManager.unregisterLocationRequest(listener);
mProvider.setProviderLocation(createLocation(NAME, mRandom));
@@ -433,8 +444,11 @@ public class LocationProviderManagerTest {
"attribution");
ILocationListener listener = createMockLocationListener();
mManager.registerLocationRequest(new LocationRequest.Builder(0).build(), identity,
PERMISSION_FINE, listener);
mManager.registerLocationRequest(
new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build(),
identity,
PERMISSION_FINE,
listener);
CountDownLatch blocker = new CountDownLatch(1);
IN_PROCESS_EXECUTOR.execute(() -> {
@@ -455,7 +469,10 @@ public class LocationProviderManagerTest {
@Test
public void testRegisterListener_NumUpdates() throws Exception {
ILocationListener listener = createMockLocationListener();
LocationRequest request = new LocationRequest.Builder(0).setMaxUpdates(5).build();
LocationRequest request = new LocationRequest.Builder(0)
.setMaxUpdates(5)
.setWorkSource(WORK_SOURCE)
.build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
mProvider.setProviderLocation(createLocation(NAME, mRandom));
@@ -472,7 +489,10 @@ public class LocationProviderManagerTest {
@Test
public void testRegisterListener_ExpiringAlarm() throws Exception {
ILocationListener listener = createMockLocationListener();
LocationRequest request = new LocationRequest.Builder(0).setDurationMillis(5000).build();
LocationRequest request = new LocationRequest.Builder(0)
.setDurationMillis(5000)
.setWorkSource(WORK_SOURCE)
.build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
mInjector.getAlarmHelper().incrementAlarmTime(5000);
@@ -484,7 +504,10 @@ public class LocationProviderManagerTest {
@Test
public void testRegisterListener_ExpiringNoAlarm() throws Exception {
ILocationListener listener = createMockLocationListener();
LocationRequest request = new LocationRequest.Builder(0).setDurationMillis(25).build();
LocationRequest request = new LocationRequest.Builder(0)
.setDurationMillis(25)
.setWorkSource(WORK_SOURCE)
.build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
Thread.sleep(25);
@@ -497,8 +520,10 @@ public class LocationProviderManagerTest {
@Test
public void testRegisterListener_FastestInterval() throws Exception {
ILocationListener listener = createMockLocationListener();
LocationRequest request = new LocationRequest.Builder(5000).setMinUpdateIntervalMillis(
5000).build();
LocationRequest request = new LocationRequest.Builder(5000)
.setMinUpdateIntervalMillis(5000)
.setWorkSource(WORK_SOURCE)
.build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
mProvider.setProviderLocation(createLocation(NAME, mRandom));
@@ -511,8 +536,10 @@ public class LocationProviderManagerTest {
@Test
public void testRegisterListener_SmallestDisplacement() throws Exception {
ILocationListener listener = createMockLocationListener();
LocationRequest request = new LocationRequest.Builder(5000).setMinUpdateDistanceMeters(
1f).build();
LocationRequest request = new LocationRequest.Builder(5000)
.setMinUpdateDistanceMeters(1f)
.setWorkSource(WORK_SOURCE)
.build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
Location loc = createLocation(NAME, mRandom);
@@ -526,7 +553,7 @@ public class LocationProviderManagerTest {
@Test
public void testRegisterListener_NoteOpFailure() throws Exception {
ILocationListener listener = createMockLocationListener();
LocationRequest request = new LocationRequest.Builder(0).build();
LocationRequest request = new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
mInjector.getAppOpsHelper().setAppOpAllowed(OP_FINE_LOCATION, IDENTITY.getPackageName(),
@@ -544,8 +571,11 @@ public class LocationProviderManagerTest {
"attribution");
ILocationListener listener = createMockLocationListener();
mManager.registerLocationRequest(new LocationRequest.Builder(0).build(), identity,
PERMISSION_FINE, listener);
mManager.registerLocationRequest(
new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build(),
identity,
PERMISSION_FINE,
listener);
CountDownLatch blocker = new CountDownLatch(1);
IN_PROCESS_EXECUTOR.execute(() -> {
@@ -572,8 +602,8 @@ public class LocationProviderManagerTest {
ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
ILocationCallback listener = createMockGetCurrentLocationListener();
LocationRequest locationRequest = new LocationRequest.Builder(0).build();
mManager.getCurrentLocation(locationRequest, IDENTITY, PERMISSION_FINE, listener);
LocationRequest request = new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build();
mManager.getCurrentLocation(request, IDENTITY, PERMISSION_FINE, listener);
Location loc = createLocation(NAME, mRandom);
mProvider.setProviderLocation(loc);
@@ -586,8 +616,8 @@ public class LocationProviderManagerTest {
@Test
public void testGetCurrentLocation_Cancel() throws Exception {
ILocationCallback listener = createMockGetCurrentLocationListener();
LocationRequest locationRequest = new LocationRequest.Builder(0).build();
ICancellationSignal cancellationSignal = mManager.getCurrentLocation(locationRequest,
LocationRequest request = new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build();
ICancellationSignal cancellationSignal = mManager.getCurrentLocation(request,
IDENTITY, PERMISSION_FINE, listener);
cancellationSignal.cancel();
@@ -599,8 +629,8 @@ public class LocationProviderManagerTest {
@Test
public void testGetCurrentLocation_ProviderDisabled() throws Exception {
ILocationCallback listener = createMockGetCurrentLocationListener();
LocationRequest locationRequest = new LocationRequest.Builder(0).build();
mManager.getCurrentLocation(locationRequest, IDENTITY, PERMISSION_FINE, listener);
LocationRequest request = new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build();
mManager.getCurrentLocation(request, IDENTITY, PERMISSION_FINE, listener);
mProvider.setProviderAllowed(false);
mProvider.setProviderAllowed(true);
@@ -613,8 +643,8 @@ public class LocationProviderManagerTest {
mProvider.setProviderAllowed(false);
ILocationCallback listener = createMockGetCurrentLocationListener();
LocationRequest locationRequest = new LocationRequest.Builder(0).build();
mManager.getCurrentLocation(locationRequest, IDENTITY, PERMISSION_FINE, listener);
LocationRequest request = new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build();
mManager.getCurrentLocation(request, IDENTITY, PERMISSION_FINE, listener);
mProvider.setProviderAllowed(true);
mProvider.setProviderLocation(createLocation(NAME, mRandom));
@@ -629,8 +659,8 @@ public class LocationProviderManagerTest {
mProvider.setProviderLocation(loc);
ILocationCallback listener = createMockGetCurrentLocationListener();
LocationRequest locationRequest = new LocationRequest.Builder(0).build();
mManager.getCurrentLocation(locationRequest, IDENTITY, PERMISSION_FINE, listener);
LocationRequest request = new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build();
mManager.getCurrentLocation(request, IDENTITY, PERMISSION_FINE, listener);
verify(listener, times(1)).onLocation(locationCaptor.capture());
assertThat(locationCaptor.getValue()).isEqualTo(loc);
@@ -639,8 +669,8 @@ public class LocationProviderManagerTest {
@Test
public void testGetCurrentLocation_Timeout() throws Exception {
ILocationCallback listener = createMockGetCurrentLocationListener();
LocationRequest locationRequest = new LocationRequest.Builder(0).build();
mManager.getCurrentLocation(locationRequest, IDENTITY, PERMISSION_FINE, listener);
LocationRequest request = new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build();
mManager.getCurrentLocation(request, IDENTITY, PERMISSION_FINE, listener);
mInjector.getAlarmHelper().incrementAlarmTime(60000);
verify(listener, times(1)).onLocation(isNull());
@@ -654,7 +684,7 @@ public class LocationProviderManagerTest {
IDENTITY.getPackageName())).isFalse();
ILocationListener listener = createMockLocationListener();
LocationRequest request = new LocationRequest.Builder(0).build();
LocationRequest request = new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_LOCATION,
@@ -683,7 +713,8 @@ public class LocationProviderManagerTest {
assertThat(mProvider.getRequest().getLocationRequests()).isEmpty();
ILocationListener listener1 = createMockLocationListener();
LocationRequest request1 = new LocationRequest.Builder(5).build();
LocationRequest request1 = new LocationRequest.Builder(5).setWorkSource(
WORK_SOURCE).build();
mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
assertThat(mProvider.getRequest().isActive()).isTrue();
@@ -694,7 +725,10 @@ public class LocationProviderManagerTest {
assertThat(mProvider.getRequest().getWorkSource()).isNotNull();
ILocationListener listener2 = createMockLocationListener();
LocationRequest request2 = new LocationRequest.Builder(1).setLowPower(true).build();
LocationRequest request2 = new LocationRequest.Builder(1)
.setLowPower(true)
.setWorkSource(WORK_SOURCE)
.build();
mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
assertThat(mProvider.getRequest().isActive()).isTrue();
@@ -725,7 +759,9 @@ public class LocationProviderManagerTest {
mProvider.setProviderLocation(createLocation(NAME, mRandom));
ILocationListener listener1 = createMockLocationListener();
LocationRequest request1 = new LocationRequest.Builder(60000).build();
LocationRequest request1 = new LocationRequest.Builder(60000)
.setWorkSource(WORK_SOURCE)
.build();
mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
verify(listener1).onLocationChanged(any(Location.class), nullable(IRemoteCallback.class));
@@ -742,7 +778,9 @@ public class LocationProviderManagerTest {
mProvider.setProviderLocation(createLocation(NAME, mRandom));
ILocationListener listener1 = createMockLocationListener();
LocationRequest request1 = new LocationRequest.Builder(60000).build();
LocationRequest request1 = new LocationRequest.Builder(60000)
.setWorkSource(WORK_SOURCE)
.build();
mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
assertThat(mProvider.getRequest().isActive()).isFalse();
@@ -757,7 +795,9 @@ public class LocationProviderManagerTest {
@Test
public void testProviderRequest_BackgroundThrottle() {
ILocationListener listener1 = createMockLocationListener();
LocationRequest request1 = new LocationRequest.Builder(5).build();
LocationRequest request1 = new LocationRequest.Builder(5)
.setWorkSource(WORK_SOURCE)
.build();
mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(5);
@@ -773,7 +813,9 @@ public class LocationProviderManagerTest {
Collections.singleton(IDENTITY.getPackageName()));
ILocationListener listener1 = createMockLocationListener();
LocationRequest request1 = new LocationRequest.Builder(5).build();
LocationRequest request1 = new LocationRequest.Builder(5)
.setWorkSource(WORK_SOURCE)
.build();
mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
assertThat(mProvider.getRequest().isActive()).isTrue();
@@ -781,8 +823,10 @@ public class LocationProviderManagerTest {
assertThat(mProvider.getRequest().isLocationSettingsIgnored()).isFalse();
ILocationListener listener2 = createMockLocationListener();
LocationRequest request2 = new LocationRequest.Builder(1).setLocationSettingsIgnored(
true).build();
LocationRequest request2 = new LocationRequest.Builder(1)
.setLocationSettingsIgnored(true)
.setWorkSource(WORK_SOURCE)
.build();
mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
assertThat(mProvider.getRequest().isActive()).isTrue();
@@ -796,12 +840,16 @@ public class LocationProviderManagerTest {
Collections.singleton(IDENTITY.getPackageName()));
ILocationListener listener1 = createMockLocationListener();
LocationRequest request1 = new LocationRequest.Builder(1).build();
LocationRequest request1 = new LocationRequest.Builder(1)
.setWorkSource(WORK_SOURCE)
.build();
mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
ILocationListener listener2 = createMockLocationListener();
LocationRequest request2 = new LocationRequest.Builder(5).setLocationSettingsIgnored(
true).build();
LocationRequest request2 = new LocationRequest.Builder(5)
.setLocationSettingsIgnored(true)
.setWorkSource(WORK_SOURCE)
.build();
mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
mInjector.getSettingsHelper().setLocationEnabled(false, IDENTITY.getUserId());
@@ -818,8 +866,10 @@ public class LocationProviderManagerTest {
Collections.singleton(IDENTITY.getPackageName()));
ILocationListener listener = createMockLocationListener();
LocationRequest request = new LocationRequest.Builder(1).setLocationSettingsIgnored(
true).build();
LocationRequest request = new LocationRequest.Builder(1)
.setLocationSettingsIgnored(true)
.setWorkSource(WORK_SOURCE)
.build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
mInjector.getSettingsHelper().setIgnoreSettingsPackageWhitelist(Collections.emptySet());
@@ -835,8 +885,10 @@ public class LocationProviderManagerTest {
Collections.singleton(IDENTITY.getPackageName()));
ILocationListener listener1 = createMockLocationListener();
LocationRequest request1 = new LocationRequest.Builder(5).setLocationSettingsIgnored(
true).build();
LocationRequest request1 = new LocationRequest.Builder(5)
.setLocationSettingsIgnored(true)
.setWorkSource(WORK_SOURCE)
.build();
mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(5);
@@ -851,7 +903,7 @@ public class LocationProviderManagerTest {
LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF);
ILocationListener listener = createMockLocationListener();
LocationRequest request = new LocationRequest.Builder(5).build();
LocationRequest request = new LocationRequest.Builder(5).setWorkSource(WORK_SOURCE).build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
assertThat(mProvider.getRequest().isActive()).isTrue();