diff options
3 files changed, 105 insertions, 72 deletions
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java index 534533f2fc97..f4d0a6254318 100644 --- a/services/core/java/com/android/server/location/LocationManagerService.java +++ b/services/core/java/com/android/server/location/LocationManagerService.java @@ -697,7 +697,8 @@ public class LocationManagerService extends ILocationManager.Stub { return null; } - Location location = manager.getLastLocation(request, identity, permissionLevel); + Location location = manager.getLastLocation(identity, permissionLevel, + request.isLocationSettingsIgnored()); // lastly - note app ops if (!mInjector.getAppOpsHelper().noteOpNoThrow(LocationPermissions.asAppOp(permissionLevel), @@ -740,13 +741,9 @@ public class LocationManagerService extends ILocationManager.Stub { return null; } - // create a location request that works in almost all circumstances - LocationRequest request = LocationRequest.createFromDeprecatedProvider(GPS_PROVIDER, 0, - 0, true); - - // use our own identity rather than the caller - CallerIdentity identity = CallerIdentity.fromContext(mContext); - Location location = gpsManager.getLastLocation(request, identity, PERMISSION_FINE); + // use fine permission level to avoid creating unnecessary coarse locations + Location location = gpsManager.getLastLocationUnsafe(UserHandle.USER_ALL, + PERMISSION_FINE, false); if (location == null) { return null; } diff --git a/services/core/java/com/android/server/location/LocationProviderManager.java b/services/core/java/com/android/server/location/LocationProviderManager.java index 66245a279666..1815a8554705 100644 --- a/services/core/java/com/android/server/location/LocationProviderManager.java +++ b/services/core/java/com/android/server/location/LocationProviderManager.java @@ -434,18 +434,17 @@ class LocationProviderManager extends } LocationRequest newRequest = calculateProviderLocationRequest(); - if (!mProviderLocationRequest.equals(newRequest)) { - LocationRequest oldRequest = mProviderLocationRequest; - mProviderLocationRequest = newRequest; - onHighPowerUsageChanged(); - updateService(); - - // if location settings ignored has changed then the active state may have changed - return oldRequest.isLocationSettingsIgnored() - != newRequest.isLocationSettingsIgnored(); + if (mProviderLocationRequest.equals(newRequest)) { + return false; } - return false; + LocationRequest oldRequest = mProviderLocationRequest; + mProviderLocationRequest = newRequest; + onHighPowerUsageChanged(); + updateService(); + + // if location settings ignored has changed then the active state may have changed + return oldRequest.isLocationSettingsIgnored() != newRequest.isLocationSettingsIgnored(); } private LocationRequest calculateProviderLocationRequest() { @@ -1229,10 +1228,8 @@ class LocationProviderManager extends } @Nullable - public Location getLastLocation(LocationRequest request, CallerIdentity identity, - @PermissionLevel int permissionLevel) { - Preconditions.checkArgument(mName.equals(request.getProvider())); - + public Location getLastLocation(CallerIdentity identity, @PermissionLevel int permissionLevel, + boolean ignoreLocationSettings) { if (mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(), identity.getPackageName())) { return null; @@ -1240,12 +1237,12 @@ class LocationProviderManager extends if (!mUserInfoHelper.isCurrentUserId(identity.getUserId())) { return null; } - if (!request.isLocationSettingsIgnored() && !isEnabled(identity.getUserId())) { + if (!ignoreLocationSettings && !isEnabled(identity.getUserId())) { return null; } - Location location = getLastLocation(identity.getUserId(), permissionLevel, - request.isLocationSettingsIgnored()); + Location location = getLastLocationUnsafe(identity.getUserId(), permissionLevel, + ignoreLocationSettings); // 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 @@ -1259,9 +1256,30 @@ class LocationProviderManager extends } } + /** + * This function does not perform any permissions or safety checks, by calling it you are + * committing to performing all applicable checks yourself. Prefer + * {@link #getLastLocation(CallerIdentity, int, boolean)} where possible. + */ @Nullable - private Location getLastLocation(int userId, @PermissionLevel int permissionLevel, + public Location getLastLocationUnsafe(int userId, @PermissionLevel int permissionLevel, boolean ignoreLocationSettings) { + if (userId == UserHandle.USER_ALL) { + Location lastLocation = null; + final int[] runningUserIds = mUserInfoHelper.getRunningUserIds(); + for (int i = 0; i < runningUserIds.length; i++) { + Location next = getLastLocationUnsafe(runningUserIds[i], permissionLevel, + ignoreLocationSettings); + if (lastLocation == null || (next != null && next.getElapsedRealtimeNanos() + > lastLocation.getElapsedRealtimeNanos())) { + lastLocation = next; + } + } + return lastLocation; + } + + Preconditions.checkArgument(userId >= 0); + synchronized (mLock) { LastLocation lastLocation = mLastLocations.get(userId); if (lastLocation == null) { @@ -1273,7 +1291,7 @@ class LocationProviderManager extends public void injectLastLocation(Location location, int userId) { synchronized (mLock) { - if (getLastLocation(userId, PERMISSION_FINE, false) == null) { + if (getLastLocationUnsafe(userId, PERMISSION_FINE, false) == null) { setLastLocation(location, userId); } } @@ -1322,7 +1340,22 @@ class LocationProviderManager extends permissionLevel); synchronized (mLock) { - Location lastLocation = getLastLocation(request, callerIdentity, permissionLevel); + if (mSettingsHelper.isLocationPackageBlacklisted(callerIdentity.getUserId(), + callerIdentity.getPackageName())) { + registration.deliverLocation(null); + return; + } + if (!mUserInfoHelper.isCurrentUserId(callerIdentity.getUserId())) { + registration.deliverLocation(null); + return; + } + if (!request.isLocationSettingsIgnored() && !isEnabled(callerIdentity.getUserId())) { + registration.deliverLocation(null); + return; + } + + Location lastLocation = getLastLocationUnsafe(callerIdentity.getUserId(), + permissionLevel, request.isLocationSettingsIgnored()); if (lastLocation != null) { long locationAgeMs = NANOSECONDS.toMillis( SystemClock.elapsedRealtimeNanos() @@ -1346,17 +1379,17 @@ class LocationProviderManager extends } finally { Binder.restoreCallingIdentity(identity); } + } - CancellationSignal cancellationSignal = CancellationSignal.fromTransport( - cancellationTransport); - if (cancellationSignal != null) { - cancellationSignal.setOnCancelListener( - () -> { - synchronized (mLock) { - removeRegistration(callback.asBinder(), registration); - } - }); - } + CancellationSignal cancellationSignal = CancellationSignal.fromTransport( + cancellationTransport); + if (cancellationSignal != null) { + cancellationSignal.setOnCancelListener(SingleUseCallback.wrap( + () -> { + synchronized (mLock) { + removeRegistration(callback.asBinder(), registration); + } + })); } } @@ -1934,7 +1967,8 @@ class LocationProviderManager extends ipw.println("user " + userId + ":"); ipw.increaseIndent(); } - ipw.println("last location=" + getLastLocation(userId, PERMISSION_FINE, false)); + ipw.println( + "last location=" + getLastLocationUnsafe(userId, PERMISSION_FINE, false)); ipw.println("enabled=" + isEnabled(userId)); if (userIds.length != 1) { ipw.decreaseIndent(); @@ -2007,7 +2041,7 @@ class LocationProviderManager extends } // update last coarse interval only if enough time has passed long timeDeltaMs = NANOSECONDS.toMillis(newCoarse.getElapsedRealtimeNanos()) - - NANOSECONDS.toMillis(oldCoarse.getElapsedRealtimeNanos()); + - NANOSECONDS.toMillis(oldCoarse.getElapsedRealtimeNanos()); if (timeDeltaMs > FASTEST_COARSE_INTERVAL_MS) { return newCoarse; } else { @@ -2016,10 +2050,11 @@ class LocationProviderManager extends } } - private static class SingleUseCallback extends IRemoteCallback.Stub { + private static class SingleUseCallback extends IRemoteCallback.Stub implements Runnable, + CancellationSignal.OnCancelListener { @Nullable - public static IRemoteCallback wrap(@Nullable Runnable callback) { + public static SingleUseCallback wrap(@Nullable Runnable callback) { return callback == null ? null : new SingleUseCallback(callback); } @@ -2032,6 +2067,16 @@ class LocationProviderManager extends @Override public void sendResult(Bundle data) { + run(); + } + + @Override + public void onCancel() { + run(); + } + + @Override + public void run() { Runnable callback; synchronized (this) { callback = mCallback; diff --git a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java index d6894cf2a4e8..80ad0a838bbb 100644 --- a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java @@ -274,60 +274,55 @@ public class LocationProviderManagerTest { @Test public void testGetLastLocation_Fine() { - LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false); - assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull(); + assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull(); Location loc = createLocation(NAME, mRandom); mProvider.setProviderLocation(loc); - assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc); + assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc); } @Test public void testGetLastLocation_Coarse() { - LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false); - assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull(); + assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull(); Location loc = createLocation(NAME, mRandom); mProvider.setProviderLocation(loc); - Location coarse = mManager.getLastLocation(request, IDENTITY, PERMISSION_COARSE); + Location coarse = mManager.getLastLocation(IDENTITY, PERMISSION_COARSE, false); assertThat(coarse).isNotEqualTo(loc); assertThat(coarse).isNearby(loc, 5000); } @Test public void testGetLastLocation_Bypass() { - LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false); - LocationRequest bypassRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, - false).setLocationSettingsIgnored(true); - assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull(); - assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isNull(); + assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull(); + assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, true)).isNull(); Location loc = createLocation(NAME, mRandom); mProvider.setProviderLocation(loc); - assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc); - assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo( + assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc); + assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, true)).isEqualTo( loc); mProvider.setProviderAllowed(false); - assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull(); - assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo( + assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull(); + assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, true)).isEqualTo( loc); loc = createLocation(NAME, mRandom); mProvider.setProviderLocation(loc); - assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull(); - assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo( + assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull(); + assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, true)).isEqualTo( loc); mProvider.setProviderAllowed(true); - assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull(); - assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo( + assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull(); + assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, true)).isEqualTo( loc); loc = createLocation(NAME, mRandom); mProvider.setProviderLocation(loc); - assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc); - assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo( + assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc); + assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, true)).isEqualTo( loc); } @@ -337,13 +332,12 @@ public class LocationProviderManagerTest { mockProvider.setAllowed(true); mManager.setMockProvider(mockProvider); - LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false); Location loc = createLocation(NAME, mRandom); mockProvider.setProviderLocation(loc); - assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc); + assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc); mManager.setMockProvider(null); - assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull(); + assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull(); } @Test @@ -351,13 +345,12 @@ public class LocationProviderManagerTest { Location loc1 = createLocation(NAME, mRandom); mManager.injectLastLocation(loc1, CURRENT_USER); - LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false); - assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc1); + assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc1); Location loc2 = createLocation(NAME, mRandom); mManager.injectLastLocation(loc2, CURRENT_USER); - assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc1); + assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc1); } @Test @@ -381,9 +374,7 @@ public class LocationProviderManagerTest { Location loc = createLocation(NAME, mRandom); mProvider.setProviderLocation(loc); - LocationRequest request = LocationRequest.createFromDeprecatedProvider(PASSIVE_PROVIDER, 0, - 0, false); - assertThat(mPassive.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc); + assertThat(mPassive.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc); } @Test |