Loading location/java/android/location/flags/location.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,13 @@ flag { bug: "229872126" } flag { name: "enable_location_bypass" namespace: "location" description: "Enable location bypass feature" bug: "301150056" } flag { name: "location_bypass" is_exported: true Loading services/core/java/com/android/server/location/LocationManagerService.java +55 −8 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.location; import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.Manifest.permission.LOCATION_BYPASS; import static android.Manifest.permission.WRITE_SECURE_SETTINGS; import static android.app.compat.CompatChanges.isChangeEnabled; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; Loading @@ -34,6 +35,7 @@ import static android.location.provider.LocationProviderBase.ACTION_NETWORK_PROV import static com.android.server.location.LocationPermissions.PERMISSION_COARSE; import static com.android.server.location.LocationPermissions.PERMISSION_FINE; import static com.android.server.location.LocationPermissions.PERMISSION_NONE; import static com.android.server.location.eventlog.LocationEventLog.EVENT_LOG; import static java.util.concurrent.TimeUnit.NANOSECONDS; Loading Loading @@ -73,6 +75,7 @@ import android.location.LocationManagerInternal.LocationPackageTagsListener; import android.location.LocationProvider; import android.location.LocationRequest; import android.location.LocationTime; import android.location.flags.Flags; import android.location.provider.ForwardGeocodeRequest; import android.location.provider.IGeocodeCallback; import android.location.provider.IProviderRequestListener; Loading Loading @@ -776,8 +779,19 @@ public class LocationManagerService extends ILocationManager.Stub implements listenerId); int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(), identity.getPid()); if (Flags.enableLocationBypass()) { if (permissionLevel == PERMISSION_NONE) { if (mContext.checkCallingPermission(LOCATION_BYPASS) != PERMISSION_GRANTED) { LocationPermissions.enforceLocationPermission( identity.getUid(), permissionLevel, PERMISSION_COARSE); } else { permissionLevel = PERMISSION_FINE; } } } else { LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel, PERMISSION_COARSE); } // clients in the system process must have an attribution tag set Preconditions.checkState(identity.getPid() != Process.myPid() || attributionTag != null); Loading Loading @@ -805,8 +819,19 @@ public class LocationManagerService extends ILocationManager.Stub implements listenerId); int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(), identity.getPid()); if (Flags.enableLocationBypass()) { if (permissionLevel == PERMISSION_NONE) { if (mContext.checkCallingPermission(LOCATION_BYPASS) != PERMISSION_GRANTED) { LocationPermissions.enforceLocationPermission( identity.getUid(), permissionLevel, PERMISSION_COARSE); } else { permissionLevel = PERMISSION_FINE; } } } else { LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel, PERMISSION_COARSE); } // clients in the system process should have an attribution tag set if (identity.getPid() == Process.myPid() && attributionTag == null) { Loading @@ -830,8 +855,19 @@ public class LocationManagerService extends ILocationManager.Stub implements AppOpsManager.toReceiverId(pendingIntent)); int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(), identity.getPid()); if (Flags.enableLocationBypass()) { if (permissionLevel == PERMISSION_NONE) { if (mContext.checkCallingPermission(LOCATION_BYPASS) != PERMISSION_GRANTED) { LocationPermissions.enforceLocationPermission( identity.getUid(), permissionLevel, PERMISSION_COARSE); } else { permissionLevel = PERMISSION_FINE; } } } else { LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel, PERMISSION_COARSE); } // clients in the system process must have an attribution tag set Preconditions.checkArgument(identity.getPid() != Process.myPid() || attributionTag != null); Loading Loading @@ -982,8 +1018,19 @@ public class LocationManagerService extends ILocationManager.Stub implements CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag); int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(), identity.getPid()); if (Flags.enableLocationBypass()) { if (permissionLevel == PERMISSION_NONE) { if (mContext.checkCallingPermission(LOCATION_BYPASS) != PERMISSION_GRANTED) { LocationPermissions.enforceLocationPermission( identity.getUid(), permissionLevel, PERMISSION_COARSE); } else { permissionLevel = PERMISSION_FINE; } } } else { LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel, PERMISSION_COARSE); } // clients in the system process must have an attribution tag set Preconditions.checkArgument(identity.getPid() != Process.myPid() || attributionTag != null); Loading services/core/java/com/android/server/location/provider/LocationProviderManager.java +87 −12 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.location.provider; import static android.Manifest.permission.LOCATION_BYPASS; import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION; import static android.app.AppOpsManager.OP_MONITOR_LOCATION; import static android.app.compat.CompatChanges.isChangeEnabled; Loading Loading @@ -51,6 +52,7 @@ import android.annotation.IntDef; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.app.AlarmManager.OnAlarmListener; import android.app.AppOpsManager; import android.app.BroadcastOptions; import android.app.PendingIntent; import android.content.Context; Loading @@ -66,6 +68,7 @@ import android.location.LocationRequest; import android.location.LocationResult; import android.location.LocationResult.BadLocationException; import android.location.altitude.AltitudeConverter; import android.location.flags.Flags; import android.location.provider.IProviderRequestListener; import android.location.provider.ProviderProperties; import android.location.provider.ProviderRequest; Loading Loading @@ -106,6 +109,7 @@ import com.android.server.location.injector.AlarmHelper; import com.android.server.location.injector.AppForegroundHelper; import com.android.server.location.injector.AppForegroundHelper.AppForegroundListener; import com.android.server.location.injector.AppOpsHelper; import com.android.server.location.injector.EmergencyHelper; import com.android.server.location.injector.Injector; import com.android.server.location.injector.LocationPermissionsHelper; import com.android.server.location.injector.LocationPermissionsHelper.LocationPermissionsListener; Loading Loading @@ -375,8 +379,13 @@ public class LocationProviderManager extends // we cache these values because checking/calculating on the fly is more expensive @GuardedBy("mMultiplexerLock") private boolean mPermitted; @GuardedBy("mMultiplexerLock") private boolean mBypassPermitted; @GuardedBy("mMultiplexerLock") private boolean mForeground; @GuardedBy("mMultiplexerLock") private LocationRequest mProviderLocationRequest; @GuardedBy("mMultiplexerLock") Loading Loading @@ -421,8 +430,8 @@ public class LocationProviderManager extends EVENT_LOG.logProviderClientRegistered(mName, getIdentity(), mBaseRequest); // initialization order is important as there are ordering dependencies mPermitted = mLocationPermissionsHelper.hasLocationPermissions(mPermissionLevel, getIdentity()); onLocationPermissionsChanged(); onBypassLocationPermissionsChanged(mEmergencyHelper.isInEmergency(0)); mForeground = mAppForegroundHelper.isAppForeground(getIdentity().getUid()); mProviderLocationRequest = calculateProviderLocationRequest(); mIsUsingHighPower = isUsingHighPower(); Loading Loading @@ -491,7 +500,13 @@ public class LocationProviderManager extends public final boolean isPermitted() { synchronized (mMultiplexerLock) { return mPermitted; return mPermitted || mBypassPermitted; } } public final boolean isOnlyBypassPermitted() { synchronized (mMultiplexerLock) { return mBypassPermitted && !mPermitted; } } Loading Loading @@ -562,6 +577,33 @@ public class LocationProviderManager extends } } boolean onBypassLocationPermissionsChanged(boolean isInEmergency) { synchronized (mMultiplexerLock) { boolean bypassPermitted = Flags.enableLocationBypass() && isInEmergency && mContext.checkPermission( LOCATION_BYPASS, mIdentity.getPid(), mIdentity.getUid()) == PERMISSION_GRANTED; if (mBypassPermitted != bypassPermitted) { if (D) { Log.v( TAG, mName + " provider package " + getIdentity().getPackageName() + " bypass permitted = " + bypassPermitted); } mBypassPermitted = bypassPermitted; return true; } return false; } } @GuardedBy("mMultiplexerLock") private boolean onLocationPermissionsChanged() { boolean permitted = mLocationPermissionsHelper.hasLocationPermissions(mPermissionLevel, Loading Loading @@ -941,8 +983,11 @@ public class LocationProviderManager extends } // note app ops if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(getPermissionLevel()), getIdentity())) { int op = Flags.enableLocationBypass() && isOnlyBypassPermitted() ? AppOpsManager.OP_EMERGENCY_LOCATION : LocationPermissions.asAppOp(getPermissionLevel()); if (!mAppOpsHelper.noteOpNoThrow(op, getIdentity())) { if (D) { Log.w(TAG, mName + " provider registration " + getIdentity() + " noteOp denied"); Loading Loading @@ -1292,13 +1337,18 @@ public class LocationProviderManager extends } // lastly - note app ops if (fineLocationResult != null && !mAppOpsHelper.noteOpNoThrow( LocationPermissions.asAppOp(getPermissionLevel()), getIdentity())) { if (fineLocationResult != null) { int op = Flags.enableLocationBypass() && isOnlyBypassPermitted() ? AppOpsManager.OP_EMERGENCY_LOCATION : LocationPermissions.asAppOp(getPermissionLevel()); if (!mAppOpsHelper.noteOpNoThrow(op, getIdentity())) { if (D) { Log.w(TAG, "noteOp denied for " + getIdentity()); } fineLocationResult = null; } } if (fineLocationResult != null) { fineLocationResult = fineLocationResult.asLastLocationResult(); Loading Loading @@ -1399,6 +1449,7 @@ public class LocationProviderManager extends protected final ScreenInteractiveHelper mScreenInteractiveHelper; protected final LocationUsageLogger mLocationUsageLogger; protected final LocationFudger mLocationFudger; protected final EmergencyHelper mEmergencyHelper; private final PackageResetHelper mPackageResetHelper; private final UserListener mUserChangedListener = this::onUserChanged; Loading Loading @@ -1434,6 +1485,8 @@ public class LocationProviderManager extends this::onLocationPowerSaveModeChanged; private final ScreenInteractiveChangedListener mScreenInteractiveChangedListener = this::onScreenInteractiveChanged; private final EmergencyHelper.EmergencyStateChangedListener mEmergencyStateChangedListener = this::onEmergencyStateChanged; private final PackageResetHelper.Responder mPackageResetResponder = new PackageResetHelper.Responder() { @Override Loading Loading @@ -1507,6 +1560,7 @@ public class LocationProviderManager extends mScreenInteractiveHelper = injector.getScreenInteractiveHelper(); mLocationUsageLogger = injector.getLocationUsageLogger(); mLocationFudger = new LocationFudger(mSettingsHelper.getCoarseLocationAccuracyM()); mEmergencyHelper = injector.getEmergencyHelper(); mPackageResetHelper = injector.getPackageResetHelper(); mProvider = new MockableLocationProvider(mMultiplexerLock); Loading Loading @@ -1757,8 +1811,17 @@ public class LocationProviderManager extends if (location != null) { // lastly - note app ops if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(permissionLevel), identity)) { int op = (Flags.enableLocationBypass() && !mLocationPermissionsHelper.hasLocationPermissions( permissionLevel, identity) && mEmergencyHelper.isInEmergency(0) && mContext.checkPermission( LOCATION_BYPASS, identity.getPid(), identity.getUid()) == PERMISSION_GRANTED) ? AppOpsManager.OP_EMERGENCY_LOCATION : LocationPermissions.asAppOp(permissionLevel); if (!mAppOpsHelper.noteOpNoThrow(op, identity)) { return null; } Loading Loading @@ -2069,6 +2132,9 @@ public class LocationProviderManager extends mAppForegroundHelper.addListener(mAppForegroundChangedListener); mLocationPowerSaveModeHelper.addListener(mLocationPowerSaveModeChangedListener); mScreenInteractiveHelper.addListener(mScreenInteractiveChangedListener); if (Flags.enableLocationBypass()) { mEmergencyHelper.addOnEmergencyStateChangedListener(mEmergencyStateChangedListener); } mPackageResetHelper.register(mPackageResetResponder); } Loading @@ -2088,6 +2154,9 @@ public class LocationProviderManager extends mAppForegroundHelper.removeListener(mAppForegroundChangedListener); mLocationPowerSaveModeHelper.removeListener(mLocationPowerSaveModeChangedListener); mScreenInteractiveHelper.removeListener(mScreenInteractiveChangedListener); if (Flags.enableLocationBypass()) { mEmergencyHelper.removeOnEmergencyStateChangedListener(mEmergencyStateChangedListener); } mPackageResetHelper.unregister(mPackageResetResponder); } Loading Loading @@ -2466,6 +2535,12 @@ public class LocationProviderManager extends } } private void onEmergencyStateChanged() { boolean inEmergency = mEmergencyHelper.isInEmergency(0); updateRegistrations( registration -> registration.onBypassLocationPermissionsChanged(inEmergency)); } private void onBackgroundThrottlePackageWhitelistChanged() { updateRegistrations(Registration::onProviderLocationRequestChanged); } Loading services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java +1 −1 Original line number Diff line number Diff line Loading @@ -110,7 +110,7 @@ public class TestInjector implements Injector { } @Override public EmergencyHelper getEmergencyHelper() { public FakeEmergencyHelper getEmergencyHelper() { return mEmergencyHelper; } Loading services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java +60 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,9 @@ package com.android.server.location.provider; import static android.Manifest.permission.ACCESS_COARSE_LOCATION; import static android.Manifest.permission.ACCESS_FINE_LOCATION; import static android.Manifest.permission.LOCATION_BYPASS; import static android.app.AppOpsManager.OP_FINE_LOCATION; import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION; import static android.app.AppOpsManager.OP_MONITOR_LOCATION; Loading Loading @@ -1169,6 +1172,63 @@ public class LocationProviderManagerTest { assertThat(mProvider.getRequest().isLocationSettingsIgnored()).isFalse(); } @Test public void testProviderRequest_IgnoreLocationSettings_LocationBypass() { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LOCATION_BYPASS); doReturn(PackageManager.PERMISSION_GRANTED) .when(mContext) .checkPermission(LOCATION_BYPASS, IDENTITY.getPid(), IDENTITY.getUid()); mInjector.getLocationPermissionsHelper() .revokePermission(IDENTITY.getPackageName(), ACCESS_FINE_LOCATION); mInjector.getLocationPermissionsHelper() .revokePermission(IDENTITY.getPackageName(), ACCESS_COARSE_LOCATION); mInjector .getSettingsHelper() .setIgnoreSettingsAllowlist( new PackageTagsList.Builder().add(IDENTITY.getPackageName()).build()); ILocationListener listener = createMockLocationListener(); LocationRequest request = new LocationRequest.Builder(1) .setLocationSettingsIgnored(true) .setWorkSource(WORK_SOURCE) .build(); mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener); assertThat(mProvider.getRequest().isActive()).isFalse(); } @Test public void testProviderRequest_IgnoreLocationSettings_LocationBypass_EmergencyCall() { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LOCATION_BYPASS); doReturn(PackageManager.PERMISSION_GRANTED) .when(mContext) .checkPermission(LOCATION_BYPASS, IDENTITY.getPid(), IDENTITY.getUid()); mInjector.getLocationPermissionsHelper() .revokePermission(IDENTITY.getPackageName(), ACCESS_FINE_LOCATION); mInjector.getLocationPermissionsHelper() .revokePermission(IDENTITY.getPackageName(), ACCESS_COARSE_LOCATION); mInjector.getEmergencyHelper().setInEmergency(true); mInjector .getSettingsHelper() .setIgnoreSettingsAllowlist( new PackageTagsList.Builder().add(IDENTITY.getPackageName()).build()); ILocationListener listener = createMockLocationListener(); LocationRequest request = new LocationRequest.Builder(1) .setLocationSettingsIgnored(true) .setWorkSource(WORK_SOURCE) .build(); mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener); assertThat(mProvider.getRequest().isActive()).isTrue(); assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(1); assertThat(mProvider.getRequest().isLocationSettingsIgnored()).isTrue(); } @Test public void testProviderRequest_BackgroundThrottle_IgnoreLocationSettings() { mInjector.getSettingsHelper().setIgnoreSettingsAllowlist( Loading Loading
location/java/android/location/flags/location.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,13 @@ flag { bug: "229872126" } flag { name: "enable_location_bypass" namespace: "location" description: "Enable location bypass feature" bug: "301150056" } flag { name: "location_bypass" is_exported: true Loading
services/core/java/com/android/server/location/LocationManagerService.java +55 −8 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.location; import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.Manifest.permission.LOCATION_BYPASS; import static android.Manifest.permission.WRITE_SECURE_SETTINGS; import static android.app.compat.CompatChanges.isChangeEnabled; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; Loading @@ -34,6 +35,7 @@ import static android.location.provider.LocationProviderBase.ACTION_NETWORK_PROV import static com.android.server.location.LocationPermissions.PERMISSION_COARSE; import static com.android.server.location.LocationPermissions.PERMISSION_FINE; import static com.android.server.location.LocationPermissions.PERMISSION_NONE; import static com.android.server.location.eventlog.LocationEventLog.EVENT_LOG; import static java.util.concurrent.TimeUnit.NANOSECONDS; Loading Loading @@ -73,6 +75,7 @@ import android.location.LocationManagerInternal.LocationPackageTagsListener; import android.location.LocationProvider; import android.location.LocationRequest; import android.location.LocationTime; import android.location.flags.Flags; import android.location.provider.ForwardGeocodeRequest; import android.location.provider.IGeocodeCallback; import android.location.provider.IProviderRequestListener; Loading Loading @@ -776,8 +779,19 @@ public class LocationManagerService extends ILocationManager.Stub implements listenerId); int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(), identity.getPid()); if (Flags.enableLocationBypass()) { if (permissionLevel == PERMISSION_NONE) { if (mContext.checkCallingPermission(LOCATION_BYPASS) != PERMISSION_GRANTED) { LocationPermissions.enforceLocationPermission( identity.getUid(), permissionLevel, PERMISSION_COARSE); } else { permissionLevel = PERMISSION_FINE; } } } else { LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel, PERMISSION_COARSE); } // clients in the system process must have an attribution tag set Preconditions.checkState(identity.getPid() != Process.myPid() || attributionTag != null); Loading Loading @@ -805,8 +819,19 @@ public class LocationManagerService extends ILocationManager.Stub implements listenerId); int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(), identity.getPid()); if (Flags.enableLocationBypass()) { if (permissionLevel == PERMISSION_NONE) { if (mContext.checkCallingPermission(LOCATION_BYPASS) != PERMISSION_GRANTED) { LocationPermissions.enforceLocationPermission( identity.getUid(), permissionLevel, PERMISSION_COARSE); } else { permissionLevel = PERMISSION_FINE; } } } else { LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel, PERMISSION_COARSE); } // clients in the system process should have an attribution tag set if (identity.getPid() == Process.myPid() && attributionTag == null) { Loading @@ -830,8 +855,19 @@ public class LocationManagerService extends ILocationManager.Stub implements AppOpsManager.toReceiverId(pendingIntent)); int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(), identity.getPid()); if (Flags.enableLocationBypass()) { if (permissionLevel == PERMISSION_NONE) { if (mContext.checkCallingPermission(LOCATION_BYPASS) != PERMISSION_GRANTED) { LocationPermissions.enforceLocationPermission( identity.getUid(), permissionLevel, PERMISSION_COARSE); } else { permissionLevel = PERMISSION_FINE; } } } else { LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel, PERMISSION_COARSE); } // clients in the system process must have an attribution tag set Preconditions.checkArgument(identity.getPid() != Process.myPid() || attributionTag != null); Loading Loading @@ -982,8 +1018,19 @@ public class LocationManagerService extends ILocationManager.Stub implements CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag); int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(), identity.getPid()); if (Flags.enableLocationBypass()) { if (permissionLevel == PERMISSION_NONE) { if (mContext.checkCallingPermission(LOCATION_BYPASS) != PERMISSION_GRANTED) { LocationPermissions.enforceLocationPermission( identity.getUid(), permissionLevel, PERMISSION_COARSE); } else { permissionLevel = PERMISSION_FINE; } } } else { LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel, PERMISSION_COARSE); } // clients in the system process must have an attribution tag set Preconditions.checkArgument(identity.getPid() != Process.myPid() || attributionTag != null); Loading
services/core/java/com/android/server/location/provider/LocationProviderManager.java +87 −12 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.location.provider; import static android.Manifest.permission.LOCATION_BYPASS; import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION; import static android.app.AppOpsManager.OP_MONITOR_LOCATION; import static android.app.compat.CompatChanges.isChangeEnabled; Loading Loading @@ -51,6 +52,7 @@ import android.annotation.IntDef; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.app.AlarmManager.OnAlarmListener; import android.app.AppOpsManager; import android.app.BroadcastOptions; import android.app.PendingIntent; import android.content.Context; Loading @@ -66,6 +68,7 @@ import android.location.LocationRequest; import android.location.LocationResult; import android.location.LocationResult.BadLocationException; import android.location.altitude.AltitudeConverter; import android.location.flags.Flags; import android.location.provider.IProviderRequestListener; import android.location.provider.ProviderProperties; import android.location.provider.ProviderRequest; Loading Loading @@ -106,6 +109,7 @@ import com.android.server.location.injector.AlarmHelper; import com.android.server.location.injector.AppForegroundHelper; import com.android.server.location.injector.AppForegroundHelper.AppForegroundListener; import com.android.server.location.injector.AppOpsHelper; import com.android.server.location.injector.EmergencyHelper; import com.android.server.location.injector.Injector; import com.android.server.location.injector.LocationPermissionsHelper; import com.android.server.location.injector.LocationPermissionsHelper.LocationPermissionsListener; Loading Loading @@ -375,8 +379,13 @@ public class LocationProviderManager extends // we cache these values because checking/calculating on the fly is more expensive @GuardedBy("mMultiplexerLock") private boolean mPermitted; @GuardedBy("mMultiplexerLock") private boolean mBypassPermitted; @GuardedBy("mMultiplexerLock") private boolean mForeground; @GuardedBy("mMultiplexerLock") private LocationRequest mProviderLocationRequest; @GuardedBy("mMultiplexerLock") Loading Loading @@ -421,8 +430,8 @@ public class LocationProviderManager extends EVENT_LOG.logProviderClientRegistered(mName, getIdentity(), mBaseRequest); // initialization order is important as there are ordering dependencies mPermitted = mLocationPermissionsHelper.hasLocationPermissions(mPermissionLevel, getIdentity()); onLocationPermissionsChanged(); onBypassLocationPermissionsChanged(mEmergencyHelper.isInEmergency(0)); mForeground = mAppForegroundHelper.isAppForeground(getIdentity().getUid()); mProviderLocationRequest = calculateProviderLocationRequest(); mIsUsingHighPower = isUsingHighPower(); Loading Loading @@ -491,7 +500,13 @@ public class LocationProviderManager extends public final boolean isPermitted() { synchronized (mMultiplexerLock) { return mPermitted; return mPermitted || mBypassPermitted; } } public final boolean isOnlyBypassPermitted() { synchronized (mMultiplexerLock) { return mBypassPermitted && !mPermitted; } } Loading Loading @@ -562,6 +577,33 @@ public class LocationProviderManager extends } } boolean onBypassLocationPermissionsChanged(boolean isInEmergency) { synchronized (mMultiplexerLock) { boolean bypassPermitted = Flags.enableLocationBypass() && isInEmergency && mContext.checkPermission( LOCATION_BYPASS, mIdentity.getPid(), mIdentity.getUid()) == PERMISSION_GRANTED; if (mBypassPermitted != bypassPermitted) { if (D) { Log.v( TAG, mName + " provider package " + getIdentity().getPackageName() + " bypass permitted = " + bypassPermitted); } mBypassPermitted = bypassPermitted; return true; } return false; } } @GuardedBy("mMultiplexerLock") private boolean onLocationPermissionsChanged() { boolean permitted = mLocationPermissionsHelper.hasLocationPermissions(mPermissionLevel, Loading Loading @@ -941,8 +983,11 @@ public class LocationProviderManager extends } // note app ops if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(getPermissionLevel()), getIdentity())) { int op = Flags.enableLocationBypass() && isOnlyBypassPermitted() ? AppOpsManager.OP_EMERGENCY_LOCATION : LocationPermissions.asAppOp(getPermissionLevel()); if (!mAppOpsHelper.noteOpNoThrow(op, getIdentity())) { if (D) { Log.w(TAG, mName + " provider registration " + getIdentity() + " noteOp denied"); Loading Loading @@ -1292,13 +1337,18 @@ public class LocationProviderManager extends } // lastly - note app ops if (fineLocationResult != null && !mAppOpsHelper.noteOpNoThrow( LocationPermissions.asAppOp(getPermissionLevel()), getIdentity())) { if (fineLocationResult != null) { int op = Flags.enableLocationBypass() && isOnlyBypassPermitted() ? AppOpsManager.OP_EMERGENCY_LOCATION : LocationPermissions.asAppOp(getPermissionLevel()); if (!mAppOpsHelper.noteOpNoThrow(op, getIdentity())) { if (D) { Log.w(TAG, "noteOp denied for " + getIdentity()); } fineLocationResult = null; } } if (fineLocationResult != null) { fineLocationResult = fineLocationResult.asLastLocationResult(); Loading Loading @@ -1399,6 +1449,7 @@ public class LocationProviderManager extends protected final ScreenInteractiveHelper mScreenInteractiveHelper; protected final LocationUsageLogger mLocationUsageLogger; protected final LocationFudger mLocationFudger; protected final EmergencyHelper mEmergencyHelper; private final PackageResetHelper mPackageResetHelper; private final UserListener mUserChangedListener = this::onUserChanged; Loading Loading @@ -1434,6 +1485,8 @@ public class LocationProviderManager extends this::onLocationPowerSaveModeChanged; private final ScreenInteractiveChangedListener mScreenInteractiveChangedListener = this::onScreenInteractiveChanged; private final EmergencyHelper.EmergencyStateChangedListener mEmergencyStateChangedListener = this::onEmergencyStateChanged; private final PackageResetHelper.Responder mPackageResetResponder = new PackageResetHelper.Responder() { @Override Loading Loading @@ -1507,6 +1560,7 @@ public class LocationProviderManager extends mScreenInteractiveHelper = injector.getScreenInteractiveHelper(); mLocationUsageLogger = injector.getLocationUsageLogger(); mLocationFudger = new LocationFudger(mSettingsHelper.getCoarseLocationAccuracyM()); mEmergencyHelper = injector.getEmergencyHelper(); mPackageResetHelper = injector.getPackageResetHelper(); mProvider = new MockableLocationProvider(mMultiplexerLock); Loading Loading @@ -1757,8 +1811,17 @@ public class LocationProviderManager extends if (location != null) { // lastly - note app ops if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(permissionLevel), identity)) { int op = (Flags.enableLocationBypass() && !mLocationPermissionsHelper.hasLocationPermissions( permissionLevel, identity) && mEmergencyHelper.isInEmergency(0) && mContext.checkPermission( LOCATION_BYPASS, identity.getPid(), identity.getUid()) == PERMISSION_GRANTED) ? AppOpsManager.OP_EMERGENCY_LOCATION : LocationPermissions.asAppOp(permissionLevel); if (!mAppOpsHelper.noteOpNoThrow(op, identity)) { return null; } Loading Loading @@ -2069,6 +2132,9 @@ public class LocationProviderManager extends mAppForegroundHelper.addListener(mAppForegroundChangedListener); mLocationPowerSaveModeHelper.addListener(mLocationPowerSaveModeChangedListener); mScreenInteractiveHelper.addListener(mScreenInteractiveChangedListener); if (Flags.enableLocationBypass()) { mEmergencyHelper.addOnEmergencyStateChangedListener(mEmergencyStateChangedListener); } mPackageResetHelper.register(mPackageResetResponder); } Loading @@ -2088,6 +2154,9 @@ public class LocationProviderManager extends mAppForegroundHelper.removeListener(mAppForegroundChangedListener); mLocationPowerSaveModeHelper.removeListener(mLocationPowerSaveModeChangedListener); mScreenInteractiveHelper.removeListener(mScreenInteractiveChangedListener); if (Flags.enableLocationBypass()) { mEmergencyHelper.removeOnEmergencyStateChangedListener(mEmergencyStateChangedListener); } mPackageResetHelper.unregister(mPackageResetResponder); } Loading Loading @@ -2466,6 +2535,12 @@ public class LocationProviderManager extends } } private void onEmergencyStateChanged() { boolean inEmergency = mEmergencyHelper.isInEmergency(0); updateRegistrations( registration -> registration.onBypassLocationPermissionsChanged(inEmergency)); } private void onBackgroundThrottlePackageWhitelistChanged() { updateRegistrations(Registration::onProviderLocationRequestChanged); } Loading
services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java +1 −1 Original line number Diff line number Diff line Loading @@ -110,7 +110,7 @@ public class TestInjector implements Injector { } @Override public EmergencyHelper getEmergencyHelper() { public FakeEmergencyHelper getEmergencyHelper() { return mEmergencyHelper; } Loading
services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java +60 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,9 @@ package com.android.server.location.provider; import static android.Manifest.permission.ACCESS_COARSE_LOCATION; import static android.Manifest.permission.ACCESS_FINE_LOCATION; import static android.Manifest.permission.LOCATION_BYPASS; import static android.app.AppOpsManager.OP_FINE_LOCATION; import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION; import static android.app.AppOpsManager.OP_MONITOR_LOCATION; Loading Loading @@ -1169,6 +1172,63 @@ public class LocationProviderManagerTest { assertThat(mProvider.getRequest().isLocationSettingsIgnored()).isFalse(); } @Test public void testProviderRequest_IgnoreLocationSettings_LocationBypass() { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LOCATION_BYPASS); doReturn(PackageManager.PERMISSION_GRANTED) .when(mContext) .checkPermission(LOCATION_BYPASS, IDENTITY.getPid(), IDENTITY.getUid()); mInjector.getLocationPermissionsHelper() .revokePermission(IDENTITY.getPackageName(), ACCESS_FINE_LOCATION); mInjector.getLocationPermissionsHelper() .revokePermission(IDENTITY.getPackageName(), ACCESS_COARSE_LOCATION); mInjector .getSettingsHelper() .setIgnoreSettingsAllowlist( new PackageTagsList.Builder().add(IDENTITY.getPackageName()).build()); ILocationListener listener = createMockLocationListener(); LocationRequest request = new LocationRequest.Builder(1) .setLocationSettingsIgnored(true) .setWorkSource(WORK_SOURCE) .build(); mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener); assertThat(mProvider.getRequest().isActive()).isFalse(); } @Test public void testProviderRequest_IgnoreLocationSettings_LocationBypass_EmergencyCall() { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LOCATION_BYPASS); doReturn(PackageManager.PERMISSION_GRANTED) .when(mContext) .checkPermission(LOCATION_BYPASS, IDENTITY.getPid(), IDENTITY.getUid()); mInjector.getLocationPermissionsHelper() .revokePermission(IDENTITY.getPackageName(), ACCESS_FINE_LOCATION); mInjector.getLocationPermissionsHelper() .revokePermission(IDENTITY.getPackageName(), ACCESS_COARSE_LOCATION); mInjector.getEmergencyHelper().setInEmergency(true); mInjector .getSettingsHelper() .setIgnoreSettingsAllowlist( new PackageTagsList.Builder().add(IDENTITY.getPackageName()).build()); ILocationListener listener = createMockLocationListener(); LocationRequest request = new LocationRequest.Builder(1) .setLocationSettingsIgnored(true) .setWorkSource(WORK_SOURCE) .build(); mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener); assertThat(mProvider.getRequest().isActive()).isTrue(); assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(1); assertThat(mProvider.getRequest().isLocationSettingsIgnored()).isTrue(); } @Test public void testProviderRequest_BackgroundThrottle_IgnoreLocationSettings() { mInjector.getSettingsHelper().setIgnoreSettingsAllowlist( Loading