summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/com/android/internal/app/NetInitiatedActivity.java22
-rw-r--r--location/java/android/location/ILocationManager.aidl2
-rw-r--r--location/java/android/location/LocationManager.java15
-rw-r--r--location/java/android/location/LocationManagerInternal.java15
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java411
-rw-r--r--services/core/java/com/android/server/LocationManagerServiceUtils.java51
-rw-r--r--services/core/java/com/android/server/location/AbstractLocationProvider.java4
-rw-r--r--services/core/java/com/android/server/location/AppForegroundHelper.java131
-rw-r--r--services/core/java/com/android/server/location/GeofenceManager.java4
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java8
-rw-r--r--services/core/java/com/android/server/location/SettingsHelper.java (renamed from services/core/java/com/android/server/location/LocationSettingsStore.java)78
-rw-r--r--services/core/java/com/android/server/location/UserInfoHelper.java (renamed from services/core/java/com/android/server/location/UserInfoStore.java)103
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssManagerService.java506
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/AppForegroundHelperTest.java112
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/UserInfoHelperTest.java (renamed from services/tests/mockingservicestests/src/com/android/server/location/UserInfoStoreTest.java)51
-rw-r--r--services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java57
16 files changed, 796 insertions, 774 deletions
diff --git a/core/java/com/android/internal/app/NetInitiatedActivity.java b/core/java/com/android/internal/app/NetInitiatedActivity.java
index 89aa770d7f1c..92e9fe492442 100644
--- a/core/java/com/android/internal/app/NetInitiatedActivity.java
+++ b/core/java/com/android/internal/app/NetInitiatedActivity.java
@@ -23,7 +23,7 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
-import android.location.LocationManager;
+import android.location.LocationManagerInternal;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -32,6 +32,7 @@ import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.location.GpsNetInitiatedHandler;
+import com.android.server.LocalServices;
/**
* This activity is shown to the user for him/her to accept or deny network-initiated
@@ -68,14 +69,14 @@ public class NetInitiatedActivity extends AlertActivity implements DialogInterfa
private final Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
- case GPS_NO_RESPONSE_TIME_OUT: {
- if (notificationId != -1) {
- sendUserResponse(default_response);
+ case GPS_NO_RESPONSE_TIME_OUT: {
+ if (notificationId != -1) {
+ sendUserResponse(default_response);
+ }
+ finish();
}
- finish();
- }
- break;
- default:
+ break;
+ default:
}
}
};
@@ -137,9 +138,8 @@ public class NetInitiatedActivity extends AlertActivity implements DialogInterfa
// Respond to NI Handler under GnssLocationProvider, 1 = accept, 2 = deny
private void sendUserResponse(int response) {
if (DEBUG) Log.d(TAG, "sendUserResponse, response: " + response);
- LocationManager locationManager = (LocationManager)
- this.getSystemService(Context.LOCATION_SERVICE);
- locationManager.sendNiResponse(notificationId, response);
+ LocationManagerInternal lm = LocalServices.getService(LocationManagerInternal.class);
+ lm.sendNiResponse(notificationId, response);
}
@UnsupportedAppUsage
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 79bec920c10e..6a5c0ec9457a 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -69,8 +69,6 @@ interface ILocationManager
double upperRightLatitude, double upperRightLongitude, int maxResults,
in GeocoderParams params, out List<Address> addrs);
- boolean sendNiResponse(int notifId, int userResponse);
-
boolean addGnssMeasurementsListener(in IGnssMeasurementsListener listener,
String packageName, String featureId, String listenerIdentifier);
void injectGnssMeasurementCorrections(in GnssMeasurementCorrections corrections,
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 0c5fe787bbbc..197787e5b6e6 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -2397,21 +2397,6 @@ public class LocationManager {
}
}
- /**
- * Used by NetInitiatedActivity to report user response
- * for network initiated GPS fix requests.
- *
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- public boolean sendNiResponse(int notifId, int userResponse) {
- try {
- return mService.sendNiResponse(notifId, userResponse);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
private void checkPendingIntent(PendingIntent pendingIntent) {
Preconditions.checkArgument(pendingIntent != null, "invalid null pending intent");
if (!pendingIntent.isTargetedToPackage()) {
diff --git a/location/java/android/location/LocationManagerInternal.java b/location/java/android/location/LocationManagerInternal.java
index 44d9d2372665..69162bab3167 100644
--- a/location/java/android/location/LocationManagerInternal.java
+++ b/location/java/android/location/LocationManagerInternal.java
@@ -41,4 +41,19 @@ public abstract class LocationManagerInternal {
* @throws IllegalArgumentException if provider is null
*/
public abstract void requestSetProviderAllowed(@NonNull String provider, boolean allowed);
+
+ /**
+ * Returns true if the given package belongs to a location provider, and so should be afforded
+ * some special privileges.
+ *
+ * @param packageName The package name to check
+ * @return True is the given package belongs to a location provider, false otherwise
+ */
+ public abstract boolean isProviderPackage(@NonNull String packageName);
+
+ /**
+ * Should only be used by GNSS code.
+ */
+ // TODO: there is no reason for this to exist as part of any API. move all the logic into gnss
+ public abstract void sendNiResponse(int notifId, int userResponse);
}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index f1f2d2abea3f..3bc93cc13023 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -30,7 +30,6 @@ import static android.os.PowerManager.locationPowerSaveModeToString;
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@@ -88,6 +87,7 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.location.AbstractLocationProvider;
import com.android.server.location.AbstractLocationProvider.State;
+import com.android.server.location.AppForegroundHelper;
import com.android.server.location.CallerIdentity;
import com.android.server.location.GeocoderProxy;
import com.android.server.location.GeofenceManager;
@@ -98,12 +98,12 @@ import com.android.server.location.LocationProviderProxy;
import com.android.server.location.LocationRequestStatistics;
import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
import com.android.server.location.LocationRequestStatistics.PackageStatistics;
-import com.android.server.location.LocationSettingsStore;
import com.android.server.location.LocationUsageLogger;
import com.android.server.location.MockProvider;
import com.android.server.location.MockableLocationProvider;
import com.android.server.location.PassiveProvider;
-import com.android.server.location.UserInfoStore;
+import com.android.server.location.SettingsHelper;
+import com.android.server.location.UserInfoHelper;
import com.android.server.location.gnss.GnssManagerService;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
@@ -140,7 +140,6 @@ public class LocationManagerService extends ILocationManager.Stub {
public Lifecycle(Context context) {
super(context);
mService = new LocationManagerService(context);
- LocalServices.addService(LocationManagerInternal.class, mService.new LocalService());
}
@Override
@@ -181,9 +180,6 @@ public class LocationManagerService extends ILocationManager.Stub {
// maximum age of a location before it is no longer considered "current"
private static final long MAX_CURRENT_LOCATION_AGE_MS = 10 * 1000;
- private static final int FOREGROUND_IMPORTANCE_CUTOFF
- = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
-
// Location Providers may sometimes deliver location updates
// slightly faster that requested - provide grace period so
// we don't unnecessarily filter events that are otherwise on
@@ -195,21 +191,23 @@ public class LocationManagerService extends ILocationManager.Stub {
private final Object mLock = new Object();
private final Context mContext;
private final Handler mHandler;
- private final UserInfoStore mUserInfoStore;
- private final LocationSettingsStore mSettingsStore;
+ private final LocalService mLocalService;
+ private final UserInfoHelper mUserInfoHelper;
+ private final SettingsHelper mSettingsHelper;
+ private final AppForegroundHelper mAppForegroundHelper;
private final LocationUsageLogger mLocationUsageLogger;
+ @Nullable private GnssManagerService mGnssManagerService = null;
+
private final PassiveLocationProviderManager mPassiveManager;
private AppOpsManager mAppOps;
private PackageManager mPackageManager;
private PowerManager mPowerManager;
- private ActivityManager mActivityManager;
private GeofenceManager mGeofenceManager;
private LocationFudger mLocationFudger;
private GeocoderProxy mGeocodeProvider;
- @Nullable private GnssManagerService mGnssManagerService;
@GuardedBy("mLock")
private String mExtraLocationControllerPackage;
@@ -245,8 +243,13 @@ public class LocationManagerService extends ILocationManager.Stub {
private LocationManagerService(Context context) {
mContext = context;
mHandler = FgThread.getHandler();
- mUserInfoStore = new UserInfoStore(mContext);
- mSettingsStore = new LocationSettingsStore(mContext, mHandler);
+ mLocalService = new LocalService();
+
+ LocalServices.addService(LocationManagerInternal.class, mLocalService);
+
+ mUserInfoHelper = new UserInfoHelper(mContext);
+ mSettingsHelper = new SettingsHelper(mContext, mHandler);
+ mAppForegroundHelper = new AppForegroundHelper(mContext);
mLocationUsageLogger = new LocationUsageLogger();
// set up passive provider - we do this early because it has no dependencies on system
@@ -272,17 +275,23 @@ public class LocationManagerService extends ILocationManager.Stub {
}
private void onSystemReady() {
- mUserInfoStore.onSystemReady();
- mSettingsStore.onSystemReady();
+ mUserInfoHelper.onSystemReady();
+ mSettingsHelper.onSystemReady();
+ mAppForegroundHelper.onSystemReady();
+
+ if (GnssManagerService.isGnssSupported()) {
+ mGnssManagerService = new GnssManagerService(mContext, mSettingsHelper,
+ mAppForegroundHelper, mLocationUsageLogger);
+ mGnssManagerService.onSystemReady();
+ }
synchronized (mLock) {
mPackageManager = mContext.getPackageManager();
mAppOps = mContext.getSystemService(AppOpsManager.class);
mPowerManager = mContext.getSystemService(PowerManager.class);
- mActivityManager = mContext.getSystemService(ActivityManager.class);
mLocationFudger = new LocationFudger(mContext, mHandler);
- mGeofenceManager = new GeofenceManager(mContext, mSettingsStore);
+ mGeofenceManager = new GeofenceManager(mContext, mSettingsHelper);
PowerManagerInternal localPowerManager =
LocalServices.getService(PowerManagerInternal.class);
@@ -313,17 +322,6 @@ public class LocationManagerService extends ILocationManager.Stub {
}
});
});
- mActivityManager.addOnUidImportanceListener(
- (uid, importance) -> {
- // listener invoked on ui thread, move to our thread to reduce risk of
- // blocking ui thread
- mHandler.post(() -> {
- synchronized (mLock) {
- onUidImportanceChangedLocked(uid, importance);
- }
- });
- },
- FOREGROUND_IMPORTANCE_CUTOFF);
localPowerManager.registerLowPowerModeObserver(ServiceType.LOCATION,
state -> {
@@ -337,26 +335,13 @@ public class LocationManagerService extends ILocationManager.Stub {
});
mBatterySaverMode = mPowerManager.getLocationPowerSaveMode();
- mSettingsStore.addOnLocationEnabledChangedListener((userId) -> {
- synchronized (mLock) {
- onLocationModeChangedLocked(userId);
- }
- });
- mSettingsStore.addOnBackgroundThrottleIntervalChangedListener(() -> {
- synchronized (mLock) {
- onBackgroundThrottleIntervalChangedLocked();
- }
- });
- mSettingsStore.addOnBackgroundThrottlePackageWhitelistChangedListener(() -> {
- synchronized (mLock) {
- onBackgroundThrottleWhitelistChangedLocked();
- }
- });
- mSettingsStore.addOnIgnoreSettingsPackageWhitelistChangedListener(() -> {
- synchronized (mLock) {
- onIgnoreSettingsWhitelistChangedLocked();
- }
- });
+ mSettingsHelper.addOnLocationEnabledChangedListener(this::onLocationModeChanged);
+ mSettingsHelper.addOnBackgroundThrottleIntervalChangedListener(
+ this::onBackgroundThrottleIntervalChanged);
+ mSettingsHelper.addOnBackgroundThrottlePackageWhitelistChangedListener(
+ this::onBackgroundThrottleWhitelistChanged);
+ mSettingsHelper.addOnIgnoreSettingsPackageWhitelistChangedListener(
+ this::onIgnoreSettingsWhitelistChanged);
new PackageMonitor() {
@Override
@@ -367,11 +352,9 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}.register(mContext, mHandler.getLooper(), true);
- mUserInfoStore.addListener((oldUserId, newUserId) -> {
- synchronized (mLock) {
- onUserChangedLocked(oldUserId, newUserId);
- }
- });
+ mUserInfoHelper.addListener(this::onUserChanged);
+
+ mAppForegroundHelper.addListener(this::onAppForegroundChanged);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
@@ -398,7 +381,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// switching the user from null to current here performs the bulk of the initialization
// work. the user being changed will cause a reload of all user specific settings, which
// causes initialization, and propagates changes until a steady state is reached
- onUserChangedLocked(UserHandle.USER_NULL, mUserInfoStore.getCurrentUserId());
+ onUserChanged(UserHandle.USER_NULL, mUserInfoHelper.getCurrentUserId());
}
}
@@ -455,20 +438,23 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- @GuardedBy("mLock")
- private void onLocationModeChangedLocked(int userId) {
+ private void onLocationModeChanged(int userId) {
+ boolean enabled = mSettingsHelper.isLocationEnabled(userId);
+
if (D) {
- Log.d(TAG, "[u" + userId + "] location enabled = " + isLocationEnabledForUser(userId));
+ Log.d(TAG, "[u" + userId + "] location enabled = " + enabled);
}
- Intent intent = new Intent(LocationManager.MODE_CHANGED_ACTION)
- .putExtra(LocationManager.EXTRA_LOCATION_ENABLED, isLocationEnabledForUser(userId))
- .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
- .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
+ synchronized (mLock) {
+ Intent intent = new Intent(LocationManager.MODE_CHANGED_ACTION)
+ .putExtra(LocationManager.EXTRA_LOCATION_ENABLED, enabled)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
- for (LocationProviderManager manager : mProviderManagers) {
+ for (LocationProviderManager manager : mProviderManagers) {
manager.onEnabledChangedLocked(userId);
+ }
}
}
@@ -493,58 +479,55 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- @GuardedBy("mLock")
- private void onUidImportanceChangedLocked(int uid, int importance) {
- boolean foreground = LocationManagerServiceUtils.isImportanceForeground(importance);
- HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
- for (Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
- String provider = entry.getKey();
- for (UpdateRecord record : entry.getValue()) {
- if (record.mReceiver.mCallerIdentity.mUid == uid
- && record.mIsForegroundUid != foreground) {
- if (D) {
- Log.d(TAG, "request from uid " + uid + " is now "
- + LocationManagerServiceUtils.foregroundAsString(
- foreground));
- }
- record.updateForeground(foreground);
+ private void onAppForegroundChanged(int uid, boolean foreground) {
+ synchronized (mLock) {
+ HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
+ for (Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
+ String provider = entry.getKey();
+ for (UpdateRecord record : entry.getValue()) {
+ if (record.mReceiver.mCallerIdentity.mUid == uid
+ && record.mIsForegroundUid != foreground) {
+ record.updateForeground(foreground);
- if (!isThrottlingExemptLocked(record.mReceiver.mCallerIdentity)) {
- affectedProviders.add(provider);
+ if (!isThrottlingExempt(record.mReceiver.mCallerIdentity)) {
+ affectedProviders.add(provider);
+ }
}
}
}
- }
- for (String provider : affectedProviders) {
- applyRequirementsLocked(provider);
+ for (String provider : affectedProviders) {
+ applyRequirementsLocked(provider);
+ }
}
}
- @GuardedBy("mLock")
- private void onBackgroundThrottleIntervalChangedLocked() {
- for (LocationProviderManager manager : mProviderManagers) {
- applyRequirementsLocked(manager);
+ private void onBackgroundThrottleIntervalChanged() {
+ synchronized (mLock) {
+ for (LocationProviderManager manager : mProviderManagers) {
+ applyRequirementsLocked(manager);
+ }
}
}
- @GuardedBy("mLock")
- private void onBackgroundThrottleWhitelistChangedLocked() {
- for (LocationProviderManager manager : mProviderManagers) {
- applyRequirementsLocked(manager);
+ private void onBackgroundThrottleWhitelistChanged() {
+ synchronized (mLock) {
+ for (LocationProviderManager manager : mProviderManagers) {
+ applyRequirementsLocked(manager);
+ }
}
}
- @GuardedBy("lock")
- private void onIgnoreSettingsWhitelistChangedLocked() {
- for (LocationProviderManager manager : mProviderManagers) {
- applyRequirementsLocked(manager);
+ private void onIgnoreSettingsWhitelistChanged() {
+ synchronized (mLock) {
+ for (LocationProviderManager manager : mProviderManagers) {
+ applyRequirementsLocked(manager);
+ }
}
}
@GuardedBy("mLock")
private void initializeProvidersLocked() {
- if (GnssManagerService.isGnssSupported()) {
- mGnssManagerService = new GnssManagerService(this, mContext, mLocationUsageLogger);
+ if (mGnssManagerService != null) {
LocationProviderManager gnssManager = new LocationProviderManager(GPS_PROVIDER);
mProviderManagers.add(gnssManager);
gnssManager.setRealProvider(mGnssManagerService.getGnssLocationProvider());
@@ -627,19 +610,20 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- @GuardedBy("mLock")
- private void onUserChangedLocked(int oldUserId, int newUserId) {
+ private void onUserChanged(int oldUserId, int newUserId) {
if (D) {
Log.d(TAG, "foreground user is changing to " + newUserId);
}
- for (LocationProviderManager manager : mProviderManagers) {
- // update LOCATION_PROVIDERS_ALLOWED for best effort backwards compatibility
- mSettingsStore.setLocationProviderAllowed(manager.getName(),
- manager.isEnabled(newUserId), newUserId);
+ synchronized (mLock) {
+ for (LocationProviderManager manager : mProviderManagers) {
+ // update LOCATION_PROVIDERS_ALLOWED for best effort backwards compatibility
+ mSettingsHelper.setLocationProviderAllowed(manager.getName(),
+ manager.isEnabled(newUserId), newUserId);
- manager.onEnabledChangedLocked(oldUserId);
- manager.onEnabledChangedLocked(newUserId);
+ manager.onEnabledChangedLocked(oldUserId);
+ manager.onEnabledChangedLocked(newUserId);
+ }
}
}
@@ -778,7 +762,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// it would be more correct to call this for all users, but we know this can
// only affect the current user since providers are disabled for non-current
// users
- onEnabledChangedLocked(mUserInfoStore.getCurrentUserId());
+ onEnabledChangedLocked(mUserInfoHelper.getCurrentUserId());
}
}
@@ -787,14 +771,14 @@ public class LocationManagerService extends ILocationManager.Stub {
}
public boolean isEnabled() {
- return isEnabled(mUserInfoStore.getCurrentUserId());
+ return isEnabled(mUserInfoHelper.getCurrentUserId());
}
public boolean isEnabled(int userId) {
synchronized (mLock) {
// normalize user id to always refer to parent since profile state is always the
// same as parent state
- userId = mUserInfoStore.getParentUserId(userId);
+ userId = mUserInfoHelper.getParentUserId(userId);
return mEnabled.get(userId, Boolean.FALSE);
}
}
@@ -808,13 +792,13 @@ public class LocationManagerService extends ILocationManager.Stub {
// normalize user id to always refer to parent since profile state is always the same
// as parent state
- userId = mUserInfoStore.getParentUserId(userId);
+ userId = mUserInfoHelper.getParentUserId(userId);
// if any property that contributes to "enabled" here changes state, it MUST result
// in a direct or indrect call to onEnabledChangedLocked. this allows the provider to
// guarantee that it will always eventually reach the correct state.
- boolean enabled = (userId == mUserInfoStore.getCurrentUserId())
- && mSettingsStore.isLocationEnabled(userId) && mProvider.getState().allowed;
+ boolean enabled = (userId == mUserInfoHelper.getCurrentUserId())
+ && mSettingsHelper.isLocationEnabled(userId) && mProvider.getState().allowed;
if (enabled == isEnabled(userId)) {
return;
@@ -829,7 +813,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// fused and passive provider never get public updates for legacy reasons
if (!FUSED_PROVIDER.equals(mName) && !PASSIVE_PROVIDER.equals(mName)) {
// update LOCATION_PROVIDERS_ALLOWED for best effort backwards compatibility
- mSettingsStore.setLocationProviderAllowed(mName, enabled, userId);
+ mSettingsHelper.setLocationProviderAllowed(mName, enabled, userId);
Intent intent = new Intent(LocationManager.PROVIDERS_CHANGED_ACTION)
.putExtra(LocationManager.EXTRA_PROVIDER_NAME, mName)
@@ -1009,7 +993,7 @@ public class LocationManagerService extends ILocationManager.Stub {
if (manager == null) {
continue;
}
- if (!manager.isEnabled() && !isSettingsExemptLocked(updateRecord)) {
+ if (!manager.isEnabled() && !isSettingsExempt(updateRecord)) {
continue;
}
@@ -1475,13 +1459,13 @@ public class LocationManagerService extends ILocationManager.Stub {
ArrayList<UpdateRecord> records = mRecordsByProvider.get(manager.getName());
if (records != null) {
for (UpdateRecord record : records) {
- if (!mUserInfoStore.isCurrentUserOrProfile(
+ if (!mUserInfoHelper.isCurrentUserOrProfile(
UserHandle.getUserId(record.mReceiver.mCallerIdentity.mUid))) {
continue;
}
// requests that ignore location settings will never provide notifications
- if (isSettingsExemptLocked(record)) {
+ if (isSettingsExempt(record)) {
continue;
}
@@ -1520,14 +1504,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// if provider is not active, it should not respond to requests
if (mProviderManagers.contains(manager) && records != null && !records.isEmpty()) {
- long backgroundThrottleInterval;
-
- long identity = Binder.clearCallingIdentity();
- try {
- backgroundThrottleInterval = mSettingsStore.getBackgroundThrottleIntervalMs();
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ long backgroundThrottleInterval = mSettingsHelper.getBackgroundThrottleIntervalMs();
ArrayList<LocationRequest> requests = new ArrayList<>(records.size());
@@ -1540,7 +1517,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// initialize the low power mode to true and set to false if any of the records requires
providerRequest.setLowPowerMode(true);
for (UpdateRecord record : records) {
- if (!mUserInfoStore.isCurrentUserOrProfile(
+ if (!mUserInfoHelper.isCurrentUserOrProfile(
UserHandle.getUserId(record.mReceiver.mCallerIdentity.mUid))) {
continue;
}
@@ -1554,7 +1531,7 @@ public class LocationManagerService extends ILocationManager.Stub {
final boolean isBatterySaverDisablingLocation = shouldThrottleRequests
|| (isForegroundOnlyMode && !record.mIsForegroundUid);
if (!manager.isEnabled() || isBatterySaverDisablingLocation) {
- if (isSettingsExemptLocked(record)) {
+ if (isSettingsExempt(record)) {
providerRequest.setLocationSettingsIgnored(true);
providerRequest.setLowPowerMode(false);
} else {
@@ -1567,7 +1544,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// if we're forcing location, don't apply any throttling
- if (!providerRequest.isLocationSettingsIgnored() && !isThrottlingExemptLocked(
+ if (!providerRequest.isLocationSettingsIgnored() && !isThrottlingExempt(
record.mReceiver.mCallerIdentity)) {
if (!record.mIsForegroundUid) {
interval = Math.max(interval, backgroundThrottleInterval);
@@ -1599,7 +1576,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// TODO: overflow
long thresholdInterval = (providerRequest.getInterval() + 1000) * 3 / 2;
for (UpdateRecord record : records) {
- if (mUserInfoStore.isCurrentUserOrProfile(
+ if (mUserInfoHelper.isCurrentUserOrProfile(
UserHandle.getUserId(record.mReceiver.mCallerIdentity.mUid))) {
LocationRequest locationRequest = record.mRequest;
@@ -1648,41 +1625,39 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public String[] getBackgroundThrottlingWhitelist() {
- return mSettingsStore.getBackgroundThrottlePackageWhitelist().toArray(new String[0]);
+ return mSettingsHelper.getBackgroundThrottlePackageWhitelist().toArray(new String[0]);
}
@Override
public String[] getIgnoreSettingsWhitelist() {
- return mSettingsStore.getIgnoreSettingsPackageWhitelist().toArray(new String[0]);
+ return mSettingsHelper.getIgnoreSettingsPackageWhitelist().toArray(new String[0]);
}
- @GuardedBy("mLock")
- public boolean isThrottlingExemptLocked(CallerIdentity callerIdentity) {
+ private boolean isThrottlingExempt(CallerIdentity callerIdentity) {
if (callerIdentity.mUid == Process.SYSTEM_UID) {
return true;
}
- if (mSettingsStore.getBackgroundThrottlePackageWhitelist().contains(
+ if (mSettingsHelper.getBackgroundThrottlePackageWhitelist().contains(
callerIdentity.mPackageName)) {
return true;
}
- return isProviderPackage(callerIdentity.mPackageName);
+ return mLocalService.isProviderPackage(callerIdentity.mPackageName);
}
- @GuardedBy("mLock")
- private boolean isSettingsExemptLocked(UpdateRecord record) {
+ private boolean isSettingsExempt(UpdateRecord record) {
if (!record.mRealRequest.isLocationSettingsIgnored()) {
return false;
}
- if (mSettingsStore.getIgnoreSettingsPackageWhitelist().contains(
+ if (mSettingsHelper.getIgnoreSettingsPackageWhitelist().contains(
record.mReceiver.mCallerIdentity.mPackageName)) {
return true;
}
- return isProviderPackage(record.mReceiver.mCallerIdentity.mPackageName);
+ return mLocalService.isProviderPackage(record.mReceiver.mCallerIdentity.mPackageName);
}
@@ -1705,10 +1680,7 @@ public class LocationManagerService extends ILocationManager.Stub {
mRealRequest = request;
mRequest = request;
mReceiver = receiver;
- mIsForegroundUid =
- LocationManagerServiceUtils.isImportanceForeground(
- mActivityManager.getPackageImportance(
- mReceiver.mCallerIdentity.mPackageName));
+ mIsForegroundUid = mAppForegroundHelper.isAppForeground(mReceiver.mCallerIdentity.mUid);
if (D && receiver.mCallerIdentity.mPid == Process.myPid()) {
mStackTrace = new Throwable();
@@ -1753,7 +1725,7 @@ public class LocationManagerService extends ILocationManager.Stub {
mReceiver.isListener(),
mReceiver.isPendingIntent(),
/* geofence= */ null,
- mActivityManager.getPackageImportance(packageName));
+ mAppForegroundHelper.getImportance(mReceiver.mCallerIdentity.mUid));
// remove from mRecordsByProvider
ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
@@ -1923,7 +1895,7 @@ public class LocationManagerService extends ILocationManager.Stub {
LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
packageName, request, listener != null, intent != null,
/* geofence= */ null,
- mActivityManager.getPackageImportance(packageName));
+ mAppForegroundHelper.getImportance(uid));
Receiver receiver;
if (intent != null) {
@@ -1961,7 +1933,7 @@ public class LocationManagerService extends ILocationManager.Stub {
Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
+ " " + name + " " + request + " from " + packageName + "(" + uid + " "
+ (record.mIsForegroundUid ? "foreground" : "background")
- + (isThrottlingExemptLocked(receiver.mCallerIdentity)
+ + (isThrottlingExempt(receiver.mCallerIdentity)
? " [whitelisted]" : "") + ")");
}
@@ -1970,7 +1942,7 @@ public class LocationManagerService extends ILocationManager.Stub {
oldRecord.disposeLocked(false);
}
- if (!manager.isEnabled() && !isSettingsExemptLocked(record)) {
+ if (!manager.isEnabled() && !isSettingsExempt(record)) {
// Notify the listener that updates are currently disabled - but only if the request
// does not ignore location settings
receiver.callProviderEnabledLocked(name, false);
@@ -2060,7 +2032,7 @@ public class LocationManagerService extends ILocationManager.Stub {
final int uid = Binder.getCallingUid();
final long identity = Binder.clearCallingIdentity();
try {
- if (mSettingsStore.isLocationPackageBlacklisted(UserHandle.getUserId(uid),
+ if (mSettingsHelper.isLocationPackageBlacklisted(UserHandle.getUserId(uid),
packageName)) {
if (D) {
Log.d(TAG, "not returning last loc for blacklisted app: "
@@ -2077,8 +2049,8 @@ public class LocationManagerService extends ILocationManager.Stub {
if (manager == null) return null;
// only the current user or location providers may get location this way
- if (!mUserInfoStore.isCurrentUserOrProfile(UserHandle.getUserId(uid))
- && !isProviderPackage(packageName)) {
+ if (!mUserInfoHelper.isCurrentUserOrProfile(UserHandle.getUserId(uid))
+ && !mLocalService.isProviderPackage(packageName)) {
return null;
}
@@ -2102,7 +2074,7 @@ public class LocationManagerService extends ILocationManager.Stub {
String op = resolutionLevelToOpStr(allowedResolutionLevel);
long locationAgeMs = TimeUnit.NANOSECONDS.toMillis(
SystemClock.elapsedRealtime() - location.getElapsedRealtimeNanos());
- if (locationAgeMs > mSettingsStore.getMaxLastLocationAgeMs()
+ if (locationAgeMs > mSettingsHelper.getMaxLastLocationAgeMs()
&& (mAppOps.unsafeCheckOp(op, uid, packageName)
== AppOpsManager.MODE_FOREGROUND)) {
return null;
@@ -2145,29 +2117,21 @@ public class LocationManagerService extends ILocationManager.Stub {
long locationAgeMs = TimeUnit.NANOSECONDS.toMillis(
SystemClock.elapsedRealtimeNanos() - lastLocation.getElapsedRealtimeNanos());
- long identity = Binder.clearCallingIdentity();
- try {
- if (locationAgeMs < MAX_CURRENT_LOCATION_AGE_MS) {
- try {
- listener.onLocationChanged(lastLocation);
- return true;
- } catch (RemoteException e) {
- Log.w(TAG, e);
- return false;
- }
+ if (locationAgeMs < MAX_CURRENT_LOCATION_AGE_MS) {
+ try {
+ listener.onLocationChanged(lastLocation);
+ return true;
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
+ return false;
}
+ }
- // packageName already validated by getLastLocation() call above
- boolean foreground = LocationManagerServiceUtils.isImportanceForeground(
- mActivityManager.getPackageImportance(packageName));
- if (!foreground) {
- if (locationAgeMs < mSettingsStore.getBackgroundThrottleIntervalMs()) {
- // not allowed to request new locations, so we can't return anything
- return false;
- }
+ if (!mAppForegroundHelper.isAppForeground(Binder.getCallingUid())) {
+ if (locationAgeMs < mSettingsHelper.getBackgroundThrottleIntervalMs()) {
+ // not allowed to request new locations, so we can't return anything
+ return false;
}
- } finally {
- Binder.restoreCallingIdentity(identity);
}
}
@@ -2252,20 +2216,19 @@ public class LocationManagerService extends ILocationManager.Stub {
Log.w(TAG, "proximity alerts are currently available only to the primary user");
return;
}
+
+ mLocationUsageLogger.logLocationApiUsage(
+ LocationStatsEnums.USAGE_STARTED,
+ LocationStatsEnums.API_REQUEST_GEOFENCE,
+ packageName,
+ request,
+ /* hasListener= */ false,
+ true,
+ geofence,
+ mAppForegroundHelper.getImportance(uid));
+
long identity = Binder.clearCallingIdentity();
try {
- synchronized (mLock) {
- mLocationUsageLogger.logLocationApiUsage(
- LocationStatsEnums.USAGE_STARTED,
- LocationStatsEnums.API_REQUEST_GEOFENCE,
- packageName,
- request,
- /* hasListener= */ false,
- true,
- geofence,
- mActivityManager.getPackageImportance(packageName));
- }
-
mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
uid, packageName, featureId, listenerIdentifier);
} finally {
@@ -2282,20 +2245,19 @@ public class LocationManagerService extends ILocationManager.Stub {
if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
+ mLocationUsageLogger.logLocationApiUsage(
+ LocationStatsEnums.USAGE_ENDED,
+ LocationStatsEnums.API_REQUEST_GEOFENCE,
+ packageName,
+ /* LocationRequest= */ null,
+ /* hasListener= */ false,
+ true,
+ geofence,
+ mAppForegroundHelper.getImportance(Binder.getCallingUid()));
+
// geo-fence manager uses the public location API, need to clear identity
long identity = Binder.clearCallingIdentity();
try {
- synchronized (mLock) {
- mLocationUsageLogger.logLocationApiUsage(
- LocationStatsEnums.USAGE_ENDED,
- LocationStatsEnums.API_REQUEST_GEOFENCE,
- packageName,
- /* LocationRequest= */ null,
- /* hasListener= */ false,
- true,
- geofence,
- mActivityManager.getPackageImportance(packageName));
- }
mGeofenceManager.removeFence(geofence, intent);
} finally {
Binder.restoreCallingIdentity(identity);
@@ -2392,12 +2354,6 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Override
- public boolean sendNiResponse(int notifId, int userResponse) {
- return mGnssManagerService != null && mGnssManagerService.sendNiResponse(notifId,
- userResponse);
- }
-
- @Override
public ProviderProperties getProviderProperties(String providerName) {
LocationProviderManager manager = getLocationProviderManager(providerName);
if (manager == null) {
@@ -2408,20 +2364,13 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public boolean isProviderPackage(String packageName) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_DEVICE_CONFIG,
- Manifest.permission.READ_DEVICE_CONFIG + " permission required");
- for (LocationProviderManager manager : mProviderManagers) {
- if (manager.getPackages().contains(packageName)) {
- return true;
- }
- }
- return false;
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_DEVICE_CONFIG, null);
+ return mLocalService.isProviderPackage(packageName);
}
@Override
public List<String> getProviderPackages(String providerName) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_DEVICE_CONFIG,
- Manifest.permission.READ_DEVICE_CONFIG + " permission required");
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_DEVICE_CONFIG, null);
LocationProviderManager manager = getLocationProviderManager(providerName);
return manager == null ? Collections.emptyList() : new ArrayList<>(manager.getPackages());
}
@@ -2461,28 +2410,19 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public boolean isLocationEnabledForUser(int userId) {
- // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
if (UserHandle.getCallingUserId() != userId) {
- mContext.enforceCallingOrSelfPermission(
- Manifest.permission.INTERACT_ACROSS_USERS,
- "Requires INTERACT_ACROSS_USERS permission");
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS,
+ null);
}
- long identity = Binder.clearCallingIdentity();
- try {
- return mSettingsStore.isLocationEnabled(userId);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ return mSettingsHelper.isLocationEnabled(userId);
}
@Override
public boolean isProviderEnabledForUser(String providerName, int userId) {
- // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
if (UserHandle.getCallingUserId() != userId) {
- mContext.enforceCallingOrSelfPermission(
- Manifest.permission.INTERACT_ACROSS_USERS,
- "Requires INTERACT_ACROSS_USERS permission");
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS,
+ null);
}
// Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
@@ -2593,12 +2533,12 @@ public class LocationManagerService extends ILocationManager.Stub {
Receiver receiver = r.mReceiver;
boolean receiverDead = false;
- if (!manager.isEnabled() && !isSettingsExemptLocked(r)) {
+ if (!manager.isEnabled() && !isSettingsExempt(r)) {
continue;
}
int receiverUserId = UserHandle.getUserId(receiver.mCallerIdentity.mUid);
- if (!mUserInfoStore.isCurrentUserOrProfile(receiverUserId)
+ if (!mUserInfoHelper.isCurrentUserOrProfile(receiverUserId)
&& !isProviderPackage(receiver.mCallerIdentity.mPackageName)) {
if (D) {
Log.d(TAG, "skipping loc update for background user " + receiverUserId +
@@ -2607,7 +2547,7 @@ public class LocationManagerService extends ILocationManager.Stub {
continue;
}
- if (mSettingsStore.isLocationPackageBlacklisted(receiverUserId,
+ if (mSettingsHelper.isLocationPackageBlacklisted(receiverUserId,
receiver.mCallerIdentity.mPackageName)) {
if (D) {
Log.d(TAG, "skipping loc update for blacklisted app: " +
@@ -2855,12 +2795,12 @@ public class LocationManagerService extends ILocationManager.Stub {
ipw.println("User Info:");
ipw.increaseIndent();
- mUserInfoStore.dump(fd, ipw, args);
+ mUserInfoHelper.dump(fd, ipw, args);
ipw.decreaseIndent();
ipw.println("Location Settings:");
ipw.increaseIndent();
- mSettingsStore.dump(fd, ipw, args);
+ mSettingsHelper.dump(fd, ipw, args);
ipw.decreaseIndent();
ipw.println("Battery Saver Location Mode: "
@@ -2960,5 +2900,22 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
}
+
+ @Override
+ public boolean isProviderPackage(String packageName) {
+ for (LocationProviderManager manager : mProviderManagers) {
+ if (manager.getPackages().contains(packageName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void sendNiResponse(int notifId, int userResponse) {
+ if (mGnssManagerService != null) {
+ mGnssManagerService.sendNiResponse(notifId, userResponse);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/LocationManagerServiceUtils.java b/services/core/java/com/android/server/LocationManagerServiceUtils.java
index 9c8ac19cc591..372e91e41772 100644
--- a/services/core/java/com/android/server/LocationManagerServiceUtils.java
+++ b/services/core/java/com/android/server/LocationManagerServiceUtils.java
@@ -17,8 +17,6 @@
package com.android.server;
import android.annotation.NonNull;
-import android.app.ActivityManager;
-import android.content.Context;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
@@ -91,12 +89,8 @@ public class LocationManagerServiceUtils {
/**
* Link listener (i.e. callback) to a binder, so that it will be called upon binder's death.
- *
- * @param binder that calls listener upon death
- * @return true if listener is successfully linked to binder, false otherwise
*/
- public boolean linkToListenerDeathNotificationLocked(
- IBinder binder) {
+ public boolean linkToListenerDeathNotificationLocked(IBinder binder) {
try {
binder.linkToDeath(this, 0 /* flags */);
return true;
@@ -110,54 +104,13 @@ public class LocationManagerServiceUtils {
/**
* Unlink death listener (i.e. callback) from binder.
- *
- * @param binder that calls listener upon death
- * @return true if binder is successfully unlinked from binder, false otherwise
*/
- public boolean unlinkFromListenerDeathNotificationLocked(
- IBinder binder) {
+ public void unlinkFromListenerDeathNotificationLocked(IBinder binder) {
try {
binder.unlinkToDeath(this, 0 /* flags */);
- return true;
} catch (NoSuchElementException e) {
- // if the death callback isn't connected (it should be...), log error,
- // swallow the exception and return
Log.w(TAG, "Could not unlink " + mListenerName + " death callback.", e);
- return false;
}
}
-
- }
-
- /**
- * Convert boolean foreground into "foreground" or "background" string.
- *
- * @param foreground boolean indicating foreground
- * @return "foreground" string if true, false otherwise
- */
- public static String foregroundAsString(boolean foreground) {
- return foreground ? "foreground" : "background";
- }
-
-
- /**
- * Classifies importance level as foreground or not.
- *
- * @param importance level as int
- * @return boolean indicating if importance level is foreground or greater
- */
- public static boolean isImportanceForeground(int importance) {
- return importance <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
- }
-
- /**
- * Get package importance level.
- *
- * @param packageName package name
- * @return package importance level as int
- */
- public static int getPackageImportance(String packageName, Context context) {
- return ((ActivityManager) context.getSystemService(
- Context.ACTIVITY_SERVICE)).getPackageImportance(packageName);
}
}
diff --git a/services/core/java/com/android/server/location/AbstractLocationProvider.java b/services/core/java/com/android/server/location/AbstractLocationProvider.java
index 5afa48a2b34d..64bca78f294d 100644
--- a/services/core/java/com/android/server/location/AbstractLocationProvider.java
+++ b/services/core/java/com/android/server/location/AbstractLocationProvider.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.location.Location;
import android.os.Binder;
import android.os.Bundle;
+import android.util.ArraySet;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
@@ -120,7 +121,8 @@ public abstract class AbstractLocationProvider {
if (providerPackageNames.equals(this.providerPackageNames)) {
return this;
} else {
- return new State(allowed, properties, providerPackageNames);
+ return new State(allowed, properties,
+ Collections.unmodifiableSet(new ArraySet<>(providerPackageNames)));
}
}
diff --git a/services/core/java/com/android/server/location/AppForegroundHelper.java b/services/core/java/com/android/server/location/AppForegroundHelper.java
new file mode 100644
index 000000000000..8ddfc652d333
--- /dev/null
+++ b/services/core/java/com/android/server/location/AppForegroundHelper.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
+import static android.app.ActivityManager.RunningAppProcessInfo.Importance;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.os.Binder;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+import com.android.server.FgThread;
+
+import java.util.Objects;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Provides accessors and listeners for all application foreground status. An application is
+ * considered foreground if it's uid's importance level is at or more important than
+ * {@link android.app.ActivityManager.RunningAppProcessInfo#IMPORTANCE_FOREGROUND_SERVICE}.
+ */
+public class AppForegroundHelper {
+
+ /**
+ * Listener for application foreground state changes.
+ */
+ public interface AppForegroundListener {
+ /**
+ * Called when an application's foreground state changes.
+ */
+ void onAppForegroundChanged(int uid, boolean foreground);
+ }
+
+ // importance constants decrement with increasing importance - this is our limit for an
+ // importance level we consider foreground.
+ private static final int FOREGROUND_IMPORTANCE_CUTOFF = IMPORTANCE_FOREGROUND_SERVICE;
+
+ private static boolean isForeground(@Importance int importance) {
+ return importance <= FOREGROUND_IMPORTANCE_CUTOFF;
+ }
+
+ private final Context mContext;
+ private final CopyOnWriteArrayList<AppForegroundListener> mListeners;
+
+ @GuardedBy("this")
+ @Nullable private ActivityManager mActivityManager;
+
+ public AppForegroundHelper(Context context) {
+ mContext = context;
+ mListeners = new CopyOnWriteArrayList<>();
+ }
+
+ /** Called when system is ready. */
+ public synchronized void onSystemReady() {
+ if (mActivityManager != null) {
+ return;
+ }
+
+ mActivityManager = Objects.requireNonNull(mContext.getSystemService(ActivityManager.class));
+ mActivityManager.addOnUidImportanceListener(this::onAppForegroundChanged,
+ FOREGROUND_IMPORTANCE_CUTOFF);
+ }
+
+ /**
+ * Adds a listener for app foreground changed events. Callbacks occur on an unspecified thread.
+ */
+ public void addListener(AppForegroundListener listener) {
+ mListeners.add(listener);
+ }
+
+ /**
+ * Removes a listener for app foreground changed events.
+ */
+ public void removeListener(AppForegroundListener listener) {
+ mListeners.remove(listener);
+ }
+
+ private void onAppForegroundChanged(int uid, @Importance int importance) {
+ // invoked on ui thread, move to fg thread so we don't block the ui thread
+ boolean foreground = isForeground(importance);
+ FgThread.getHandler().post(() -> {
+ for (AppForegroundListener listener : mListeners) {
+ listener.onAppForegroundChanged(uid, foreground);
+ }
+ });
+ }
+
+ /**
+ * Whether the given uid is currently foreground.
+ */
+ public boolean isAppForeground(int uid) {
+ return isForeground(getImportance(uid));
+ }
+
+ /**
+ * Retrieves the current importance of the given uid.
+ *
+ * @deprecated Prefer {@link #isAppForeground(int)}.
+ */
+ @Deprecated
+ @Importance
+ public int getImportance(int uid) {
+ synchronized (this) {
+ Preconditions.checkState(mActivityManager != null);
+ }
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ return mActivityManager.getUidImportance(uid);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/location/GeofenceManager.java b/services/core/java/com/android/server/location/GeofenceManager.java
index 81c06d7125f9..4e9c06761e54 100644
--- a/services/core/java/com/android/server/location/GeofenceManager.java
+++ b/services/core/java/com/android/server/location/GeofenceManager.java
@@ -77,7 +77,7 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish
private final AppOpsManager mAppOps;
private final PowerManager.WakeLock mWakeLock;
- private final LocationSettingsStore mSettingsStore;
+ private final SettingsHelper mSettingsStore;
private final Object mLock = new Object();
@@ -111,7 +111,7 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish
*/
private boolean mPendingUpdate;
- public GeofenceManager(Context context, LocationSettingsStore settingsStore) {
+ public GeofenceManager(Context context, SettingsHelper settingsStore) {
mContext = context;
mHandler = new GeofenceHandler(FgThread.getHandler().getLooper());
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 306e1e3afcd7..62fa5ec82aea 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -43,7 +43,6 @@ import android.os.BatteryStats;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
-import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.Message;
import android.os.PersistableBundle;
@@ -76,6 +75,7 @@ import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import com.android.internal.location.gnssmetrics.GnssMetrics;
import com.android.server.DeviceIdleInternal;
+import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.location.GnssSatelliteBlacklistHelper.GnssSatelliteBlacklistCallback;
import com.android.server.location.NtpTimeHelper.InjectNtpTimeCallback;
@@ -624,12 +624,12 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
}
- public GnssLocationProvider(Context context, Handler handler) {
- super(context, new HandlerExecutor(handler));
+ public GnssLocationProvider(Context context) {
+ super(context, FgThread.getExecutor());
ensureInitialized();
- mLooper = handler.getLooper();
+ mLooper = FgThread.getHandler().getLooper();
// Create a wake lock
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
diff --git a/services/core/java/com/android/server/location/LocationSettingsStore.java b/services/core/java/com/android/server/location/SettingsHelper.java
index 0e8720ebb08f..9163490fa777 100644
--- a/services/core/java/com/android/server/location/LocationSettingsStore.java
+++ b/services/core/java/com/android/server/location/SettingsHelper.java
@@ -54,7 +54,7 @@ import java.util.function.Supplier;
/**
* Provides accessors and listeners for all location related settings.
*/
-public class LocationSettingsStore {
+public class SettingsHelper {
/**
* Listener for user-specific settings changes.
@@ -99,7 +99,7 @@ public class LocationSettingsStore {
private final StringSetCachedGlobalSetting mIgnoreSettingsPackageWhitelist;
// TODO: get rid of handler
- public LocationSettingsStore(Context context, Handler handler) {
+ public SettingsHelper(Context context, Handler handler) {
mContext = context;
mLocationMode = new IntegerSecureSetting(context, LOCATION_MODE, handler);
@@ -118,7 +118,7 @@ public class LocationSettingsStore {
}
/** Called when system is ready. */
- public synchronized void onSystemReady() {
+ public void onSystemReady() {
mLocationMode.register();
mBackgroundThrottleIntervalMs.register();
mLocationPackageBlacklist.register();
@@ -135,7 +135,8 @@ public class LocationSettingsStore {
}
/**
- * Add a listener for changes to the location enabled setting.
+ * Add a listener for changes to the location enabled setting. Callbacks occur on an unspecified
+ * thread.
*/
public void addOnLocationEnabledChangedListener(UserSettingChangedListener listener) {
mLocationMode.addListener(listener);
@@ -156,7 +157,8 @@ public class LocationSettingsStore {
}
/**
- * Add a listener for changes to the background throttle interval.
+ * Add a listener for changes to the background throttle interval. Callbacks occur on an
+ * unspecified thread.
*/
public void addOnBackgroundThrottleIntervalChangedListener(
GlobalSettingChangedListener listener) {
@@ -204,7 +206,8 @@ public class LocationSettingsStore {
}
/**
- * Add a listener for changes to the background throttle package whitelist.
+ * Add a listener for changes to the background throttle package whitelist. Callbacks occur on
+ * an unspecified thread.
*/
public void addOnBackgroundThrottlePackageWhitelistChangedListener(
GlobalSettingChangedListener listener) {
@@ -227,7 +230,8 @@ public class LocationSettingsStore {
}
/**
- * Add a listener for changes to the ignore settings package whitelist.
+ * Add a listener for changes to the ignore settings package whitelist. Callbacks occur on an
+ * unspecified thread.
*/
public void addOnIgnoreSettingsPackageWhitelistChangedListener(
GlobalSettingChangedListener listener) {
@@ -340,6 +344,8 @@ public class LocationSettingsStore {
private abstract static class ObservingSetting extends ContentObserver {
private final CopyOnWriteArrayList<UserSettingChangedListener> mListeners;
+
+ @GuardedBy("this")
private boolean mRegistered;
private ObservingSetting(Handler handler) {
@@ -347,11 +353,11 @@ public class LocationSettingsStore {
mListeners = new CopyOnWriteArrayList<>();
}
- protected boolean isRegistered() {
+ protected synchronized boolean isRegistered() {
return mRegistered;
}
- protected void register(Context context, Uri uri) {
+ protected synchronized void register(Context context, Uri uri) {
if (mRegistered) {
return;
}
@@ -393,8 +399,13 @@ public class LocationSettingsStore {
}
public int getValueForUser(int defaultValue, int userId) {
- return Settings.Secure.getIntForUser(mContext.getContentResolver(), mSettingName,
- defaultValue, userId);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ return Settings.Secure.getIntForUser(mContext.getContentResolver(), mSettingName,
+ defaultValue, userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
@@ -417,7 +428,7 @@ public class LocationSettingsStore {
mCachedUserId = UserHandle.USER_NULL;
}
- public synchronized void register() {
+ public void register() {
register(mContext, Settings.Secure.getUriFor(mSettingName));
}
@@ -426,12 +437,17 @@ public class LocationSettingsStore {
List<String> value = mCachedValue;
if (userId != mCachedUserId) {
- String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(),
- mSettingName, userId);
- if (TextUtils.isEmpty(setting)) {
- value = Collections.emptyList();
- } else {
- value = Arrays.asList(setting.split(","));
+ long identity = Binder.clearCallingIdentity();
+ try {
+ String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+ mSettingName, userId);
+ if (TextUtils.isEmpty(setting)) {
+ value = Collections.emptyList();
+ } else {
+ value = Arrays.asList(setting.split(","));
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
if (isRegistered()) {
@@ -473,8 +489,13 @@ public class LocationSettingsStore {
}
public long getValue(long defaultValue) {
- return Settings.Global.getLong(mContext.getContentResolver(), mSettingName,
- defaultValue);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ return Settings.Global.getLong(mContext.getContentResolver(), mSettingName,
+ defaultValue);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
@@ -499,18 +520,23 @@ public class LocationSettingsStore {
mValid = false;
}
- public synchronized void register() {
+ public void register() {
register(mContext, Settings.Global.getUriFor(mSettingName));
}
public synchronized Set<String> getValue() {
ArraySet<String> value = mCachedValue;
if (!mValid) {
- value = new ArraySet<>(mBaseValuesSupplier.get());
- String setting = Settings.Global.getString(mContext.getContentResolver(),
- mSettingName);
- if (!TextUtils.isEmpty(setting)) {
- value.addAll(Arrays.asList(setting.split(",")));
+ long identity = Binder.clearCallingIdentity();
+ try {
+ value = new ArraySet<>(mBaseValuesSupplier.get());
+ String setting = Settings.Global.getString(mContext.getContentResolver(),
+ mSettingName);
+ if (!TextUtils.isEmpty(setting)) {
+ value.addAll(Arrays.asList(setting.split(",")));
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
if (isRegistered()) {
diff --git a/services/core/java/com/android/server/location/UserInfoStore.java b/services/core/java/com/android/server/location/UserInfoHelper.java
index f282ed26a831..94f3a88cb859 100644
--- a/services/core/java/com/android/server/location/UserInfoStore.java
+++ b/services/core/java/com/android/server/location/UserInfoHelper.java
@@ -42,7 +42,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
/**
* Provides accessors and listeners for all user info.
*/
-public class UserInfoStore {
+public class UserInfoHelper {
/**
* Listener for current user changes.
@@ -58,20 +58,16 @@ public class UserInfoStore {
private final CopyOnWriteArrayList<UserChangedListener> mListeners;
@GuardedBy("this")
- @Nullable
- private UserManager mUserManager;
+ @Nullable private UserManager mUserManager;
- @GuardedBy("this")
- @UserIdInt
- private int mCurrentUserId;
+ @UserIdInt private volatile int mCurrentUserId;
@GuardedBy("this")
- @UserIdInt
- private int mCachedParentUserId;
+ @UserIdInt private int mCachedParentUserId;
@GuardedBy("this")
private int[] mCachedProfileUserIds;
- public UserInfoStore(Context context) {
+ public UserInfoHelper(Context context) {
mContext = context;
mListeners = new CopyOnWriteArrayList<>();
@@ -120,7 +116,7 @@ public class UserInfoStore {
}
/**
- * Adds a listener for user changed events.
+ * Adds a listener for user changed events. Callbacks occur on an unspecified thread.
*/
public void addListener(UserChangedListener listener) {
mListeners.add(listener);
@@ -134,16 +130,13 @@ public class UserInfoStore {
}
private void onUserChanged(@UserIdInt int newUserId) {
- int oldUserId;
- synchronized (this) {
- if (newUserId == mCurrentUserId) {
- return;
- }
-
- oldUserId = mCurrentUserId;
- mCurrentUserId = newUserId;
+ if (newUserId == mCurrentUserId) {
+ return;
}
+ int oldUserId = mCurrentUserId;
+ mCurrentUserId = newUserId;
+
for (UserChangedListener listener : mListeners) {
listener.onUserChanged(oldUserId, newUserId);
}
@@ -161,7 +154,7 @@ public class UserInfoStore {
* Returns the user id of the current user.
*/
@UserIdInt
- public synchronized int getCurrentUserId() {
+ public int getCurrentUserId() {
return mCurrentUserId;
}
@@ -169,9 +162,10 @@ public class UserInfoStore {
* Returns true if the given user id is either the current user or a profile of the current
* user.
*/
- public synchronized boolean isCurrentUserOrProfile(@UserIdInt int userId) {
- return userId == mCurrentUserId || ArrayUtils.contains(
- getProfileUserIdsForParentUser(mCurrentUserId), userId);
+ public boolean isCurrentUserOrProfile(@UserIdInt int userId) {
+ int currentUserId = mCurrentUserId;
+ return userId == currentUserId || ArrayUtils.contains(
+ getProfileUserIdsForParentUser(currentUserId), userId);
}
/**
@@ -179,50 +173,44 @@ public class UserInfoStore {
* is a parent or has no profiles.
*/
@UserIdInt
- public synchronized int getParentUserId(@UserIdInt int userId) {
- int parentUserId;
- if (userId == mCachedParentUserId || ArrayUtils.contains(mCachedProfileUserIds, userId)) {
- parentUserId = mCachedParentUserId;
- } else {
+ public int getParentUserId(@UserIdInt int userId) {
+ synchronized (this) {
+ if (userId == mCachedParentUserId || ArrayUtils.contains(mCachedProfileUserIds,
+ userId)) {
+ return mCachedParentUserId;
+ }
+
Preconditions.checkState(mUserManager != null);
+ }
- long identity = Binder.clearCallingIdentity();
- try {
- UserInfo userInfo = mUserManager.getProfileParent(userId);
- if (userInfo != null) {
- parentUserId = userInfo.id;
- } else {
- // getProfileParent() returns null if the userId is already the parent...
- parentUserId = userId;
- }
+ int parentUserId;
- // force profiles into cache
- getProfileUserIdsForParentUser(parentUserId);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ long identity = Binder.clearCallingIdentity();
+ try {
+ UserInfo userInfo = mUserManager.getProfileParent(userId);
+ parentUserId = userInfo != null ? userInfo.id : userId;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
+ // force profiles into cache
+ getProfileUserIdsForParentUser(parentUserId);
return parentUserId;
}
@GuardedBy("this")
- private int[] getProfileUserIdsForParentUser(@UserIdInt int parentUserId) {
- Preconditions.checkState(mUserManager != null);
-
- // only assert on debug builds as this is a more expensive check
- if (Build.IS_DEBUGGABLE) {
- long identity = Binder.clearCallingIdentity();
- try {
- Preconditions.checkArgument(mUserManager.getProfileParent(parentUserId) == null);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
+ private synchronized int[] getProfileUserIdsForParentUser(@UserIdInt int parentUserId) {
if (parentUserId != mCachedParentUserId) {
long identity = Binder.clearCallingIdentity();
try {
+ Preconditions.checkState(mUserManager != null);
+
+ // more expensive check - check that argument really is a parent user id
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkArgument(
+ mUserManager.getProfileParent(parentUserId) == null);
+ }
+
mCachedParentUserId = parentUserId;
mCachedProfileUserIds = mUserManager.getProfileIdsWithDisabled(parentUserId);
} finally {
@@ -236,8 +224,9 @@ public class UserInfoStore {
/**
* Dump info for debugging.
*/
- public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("Current User: " + mCurrentUserId + " " + Arrays.toString(
- getProfileUserIdsForParentUser(mCurrentUserId)));
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ int currentUserId = mCurrentUserId;
+ pw.println("Current User: " + currentUserId + " " + Arrays.toString(
+ getProfileUserIdsForParentUser(currentUserId)));
}
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssManagerService.java b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
index 1eb2c525ff22..2bab9fa67eb0 100644
--- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java
+++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
@@ -16,10 +16,11 @@
package com.android.server.location.gnss;
+import static android.app.AppOpsManager.OP_FINE_LOCATION;
+
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.Context;
import android.location.GnssCapabilities;
@@ -31,8 +32,8 @@ import android.location.IGnssStatusListener;
import android.location.IGpsGeofenceHardware;
import android.location.INetInitiatedListener;
import android.location.Location;
+import android.location.LocationManagerInternal;
import android.os.Binder;
-import android.os.Handler;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Process;
@@ -43,13 +44,12 @@ import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.FgThread;
-import com.android.server.LocationManagerService;
-import com.android.server.LocationManagerServiceUtils;
+import com.android.internal.util.Preconditions;
+import com.android.server.LocalServices;
import com.android.server.LocationManagerServiceUtils.LinkedListener;
import com.android.server.LocationManagerServiceUtils.LinkedListenerBase;
+import com.android.server.location.AppForegroundHelper;
import com.android.server.location.CallerIdentity;
import com.android.server.location.GnssBatchingProvider;
import com.android.server.location.GnssCapabilitiesProvider;
@@ -60,6 +60,7 @@ import com.android.server.location.GnssNavigationMessageProvider;
import com.android.server.location.GnssStatusListenerHelper;
import com.android.server.location.LocationUsageLogger;
import com.android.server.location.RemoteListenerHelper;
+import com.android.server.location.SettingsHelper;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -70,10 +71,18 @@ import java.util.function.Function;
/** Manages Gnss providers and related Gnss functions for LocationManagerService. */
public class GnssManagerService {
+
private static final String TAG = "GnssManagerService";
- private static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
- // Providers
+ public static boolean isGnssSupported() {
+ return GnssLocationProvider.isSupported();
+ }
+
+ private final Context mContext;
+ private final SettingsHelper mSettingsHelper;
+ private final AppForegroundHelper mAppForegroundHelper;
+ private final LocationUsageLogger mLocationUsageLogger;
+
private final GnssLocationProvider mGnssLocationProvider;
private final GnssStatusListenerHelper mGnssStatusProvider;
private final GnssMeasurementsProvider mGnssMeasurementsProvider;
@@ -83,58 +92,59 @@ public class GnssManagerService {
private final GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
private final GnssCapabilitiesProvider mGnssCapabilitiesProvider;
private final GnssBatchingProvider mGnssBatchingProvider;
-
private final INetInitiatedListener mNetInitiatedListener;
private final IGpsGeofenceHardware mGpsGeofenceProxy;
- private final LocationManagerService mLocationManagerService;
- private final LocationUsageLogger mLocationUsageLogger;
@GuardedBy("mGnssMeasurementsListeners")
- private final ArrayMap<IBinder,
- LinkedListener<IGnssMeasurementsListener>>
+ private final ArrayMap<IBinder, LinkedListener<IGnssMeasurementsListener>>
mGnssMeasurementsListeners = new ArrayMap<>();
@GuardedBy("mGnssNavigationMessageListeners")
- private final ArrayMap<
- IBinder, LinkedListener<IGnssNavigationMessageListener>>
+ private final ArrayMap<IBinder, LinkedListener<IGnssNavigationMessageListener>>
mGnssNavigationMessageListeners = new ArrayMap<>();
@GuardedBy("mGnssStatusListeners")
private final ArrayMap<IBinder, LinkedListener<IGnssStatusListener>>
mGnssStatusListeners = new ArrayMap<>();
+ @GuardedBy("this")
+ @Nullable private LocationManagerInternal mLocationManagerInternal;
+ @GuardedBy("this")
+ @Nullable private AppOpsManager mAppOpsManager;
+
+ private final Object mGnssBatchingLock = new Object();
+
@GuardedBy("mGnssBatchingLock")
- private IBatchedLocationCallback mGnssBatchingCallback;
+ @Nullable private IBatchedLocationCallback mGnssBatchingCallback;
@GuardedBy("mGnssBatchingLock")
- private LinkedListener<IBatchedLocationCallback>
- mGnssBatchingDeathCallback;
+ @Nullable private LinkedListener<IBatchedLocationCallback> mGnssBatchingDeathCallback;
@GuardedBy("mGnssBatchingLock")
private boolean mGnssBatchingInProgress = false;
- private final Object mGnssBatchingLock = new Object();
- private final Context mContext;
- private final Handler mHandler;
-
- public GnssManagerService(LocationManagerService locationManagerService,
- Context context, LocationUsageLogger locationUsageLogger) {
- this(locationManagerService, context,
- new GnssLocationProvider(context, FgThread.getHandler()), locationUsageLogger);
+ public GnssManagerService(Context context, SettingsHelper settingsHelper,
+ AppForegroundHelper appForegroundHelper, LocationUsageLogger locationUsageLogger) {
+ this(context, settingsHelper, appForegroundHelper, locationUsageLogger, null);
}
// Can use this constructor to inject GnssLocationProvider for testing
@VisibleForTesting
- public GnssManagerService(LocationManagerService locationManagerService,
- Context context,
- GnssLocationProvider gnssLocationProvider,
- LocationUsageLogger locationUsageLogger) {
+ GnssManagerService(Context context, SettingsHelper settingsHelper,
+ AppForegroundHelper appForegroundHelper, LocationUsageLogger locationUsageLogger,
+ GnssLocationProvider gnssLocationProvider) {
+ Preconditions.checkState(isGnssSupported());
+
mContext = context;
- mHandler = FgThread.getHandler();
+ mSettingsHelper = settingsHelper;
+ mAppForegroundHelper = appForegroundHelper;
+ mLocationUsageLogger = locationUsageLogger;
- mGnssLocationProvider =
- gnssLocationProvider;
+ if (gnssLocationProvider == null) {
+ gnssLocationProvider = new GnssLocationProvider(mContext);
+ }
+ mGnssLocationProvider = gnssLocationProvider;
mGnssStatusProvider = mGnssLocationProvider.getGnssStatusProvider();
mGnssMeasurementsProvider = mGnssLocationProvider.getGnssMeasurementsProvider();
mGnssMeasurementCorrectionsProvider =
@@ -144,108 +154,73 @@ public class GnssManagerService {
mGnssMetricsProvider = mGnssLocationProvider.getGnssMetricsProvider();
mGnssCapabilitiesProvider = mGnssLocationProvider.getGnssCapabilitiesProvider();
mGnssBatchingProvider = mGnssLocationProvider.getGnssBatchingProvider();
-
mNetInitiatedListener = mGnssLocationProvider.getNetInitiatedListener();
mGpsGeofenceProxy = mGnssLocationProvider.getGpsGeofenceProxy();
- mLocationManagerService = locationManagerService;
- mLocationUsageLogger = locationUsageLogger;
-
- registerUidListener();
}
- public static boolean isGnssSupported() {
- return GnssLocationProvider.isSupported();
- }
+ /** Called when system is ready. */
+ public synchronized void onSystemReady() {
+ if (mLocationManagerInternal != null) {
+ return;
+ }
- private boolean hasGnssPermissions(String packageName) {
- mContext.enforceCallingPermission(
- Manifest.permission.ACCESS_FINE_LOCATION,
- "Fine location permission not granted.");
+ mSettingsHelper.onSystemReady();
+ mAppForegroundHelper.onSystemReady();
- int uid = Binder.getCallingUid();
- long identity = Binder.clearCallingIdentity();
- try {
- return mContext.getSystemService(
- AppOpsManager.class).checkOp(AppOpsManager.OP_FINE_LOCATION, uid, packageName)
- == AppOpsManager.MODE_ALLOWED;
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ mLocationManagerInternal = LocalServices.getService(LocationManagerInternal.class);
+ mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
+
+ mAppForegroundHelper.addListener(this::onAppForegroundChanged);
}
+ /** Retrieve the GnssLocationProvider. */
public GnssLocationProvider getGnssLocationProvider() {
return mGnssLocationProvider;
}
+ /** Retrieve the IGpsGeofenceHardware. */
public IGpsGeofenceHardware getGpsGeofenceProxy() {
return mGpsGeofenceProxy;
}
/**
* Get year of GNSS hardware.
- *
- * @return year of GNSS hardware as an int if possible, otherwise zero
*/
public int getGnssYearOfHardware() {
- if (mGnssSystemInfoProvider != null) {
- return mGnssSystemInfoProvider.getGnssYearOfHardware();
- } else {
- return 0;
- }
+ return mGnssSystemInfoProvider.getGnssYearOfHardware();
}
/**
* Get model name of GNSS hardware.
- *
- * @return GNSS hardware model name as a string if possible, otherwise null
*/
+ @Nullable
public String getGnssHardwareModelName() {
- if (mGnssSystemInfoProvider != null) {
- return mGnssSystemInfoProvider.getGnssHardwareModelName();
- } else {
- return null;
- }
+ return mGnssSystemInfoProvider.getGnssHardwareModelName();
}
/**
- * Get GNSS hardware capabilities. The capabilities are described in {@link
- * android.location.GnssCapabilities} and their integer values correspond to the
- * bit positions in the returned {@code long} value.
- *
- * @param packageName name of requesting package
- * @return capabilities supported by the GNSS chipset
+ * Get GNSS hardware capabilities. The capabilities returned are a bitfield as described in
+ * {@link android.location.GnssCapabilities}.
*/
public long getGnssCapabilities(String packageName) {
- mContext.enforceCallingPermission(
- android.Manifest.permission.LOCATION_HARDWARE,
- "Location Hardware permission not granted to obtain GNSS chipset capabilities.");
- if (!hasGnssPermissions(packageName) || mGnssCapabilitiesProvider == null) {
+ mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, null);
+ mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
+
+ if (!checkLocationAppOp(packageName)) {
return GnssCapabilities.INVALID_CAPABILITIES;
}
+
return mGnssCapabilitiesProvider.getGnssCapabilities();
}
/**
* Get size of GNSS batch (GNSS location results are batched together for power savings).
- * Requires LOCATION_HARDWARE and GNSS permissions.
- *
- * @param packageName name of requesting package
- * @return size of the GNSS batch collection
*/
public int getGnssBatchSize(String packageName) {
- mContext.enforceCallingPermission(
- android.Manifest.permission.LOCATION_HARDWARE,
- "Location Hardware permission not granted to access hardware batching");
+ mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, null);
+ mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
- if (!hasGnssPermissions(packageName)) {
- Log.e(TAG, "getGnssBatchSize called without GNSS permissions");
- return 0;
- }
- if (mGnssBatchingProvider == null) {
- Log.e(
- TAG,
- "Can not get GNSS batch size. GNSS batching provider "
- + "not available.");
+ if (!checkLocationAppOp(packageName)) {
return 0;
}
@@ -257,27 +232,12 @@ public class GnssManagerService {
/**
* Starts GNSS batch collection. GNSS positions are collected in a batch before being delivered
* as a collection.
- *
- * @param periodNanos duration over which to collect GPS positions before delivering as a
- * batch
- * @param wakeOnFifoFull specifying whether to wake on full queue
- * @param packageName name of requesting package
- * @return true of batch started successfully, false otherwise
*/
public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
- mContext.enforceCallingPermission(
- android.Manifest.permission.LOCATION_HARDWARE,
- "Location Hardware permission not granted to access hardware batching");
+ mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, null);
+ mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
- if (!hasGnssPermissions(packageName)) {
- Log.e(TAG, "startGnssBatch called without GNSS permissions");
- return false;
- }
- if (mGnssBatchingProvider == null) {
- Log.e(
- TAG,
- "Can not start GNSS batching. GNSS batching provider "
- + "not available.");
+ if (!checkLocationAppOp(packageName)) {
return false;
}
@@ -285,7 +245,6 @@ public class GnssManagerService {
if (mGnssBatchingInProgress) {
// Current design does not expect multiple starts to be called repeatedly
Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
- // Try to clean up anyway, and continue
stopGnssBatch();
}
@@ -296,26 +255,13 @@ public class GnssManagerService {
/**
* Adds a GNSS batching callback for delivering GNSS location batch results.
- *
- * @param callback called when batching operation is complete to deliver GPS positions
- * @param packageName name of requesting package
- * @return true if callback is successfully added, false otherwise
*/
public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName,
@Nullable String featureId, @NonNull String listenerIdentity) {
- mContext.enforceCallingPermission(
- android.Manifest.permission.LOCATION_HARDWARE,
- "Location Hardware permission not granted to access hardware batching");
+ mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, null);
+ mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
- if (!hasGnssPermissions(packageName)) {
- Log.e(TAG, "addGnssBatchingCallback called without GNSS permissions");
- return false;
- }
- if (mGnssBatchingProvider == null) {
- Log.e(
- TAG,
- "Can not add GNSS batching callback. GNSS batching provider "
- + "not available.");
+ if (!checkLocationAppOp(packageName)) {
return false;
}
@@ -333,11 +279,9 @@ public class GnssManagerService {
stopGnssBatch();
removeGnssBatchingCallback();
});
- if (!mGnssBatchingDeathCallback.linkToListenerDeathNotificationLocked(
- callback.asBinder())) {
- return false;
- }
- return true;
+
+ return mGnssBatchingDeathCallback.linkToListenerDeathNotificationLocked(
+ callback.asBinder());
}
}
@@ -347,27 +291,14 @@ public class GnssManagerService {
* @param packageName name of requesting package
*/
public void flushGnssBatch(String packageName) {
- mContext.enforceCallingPermission(
- android.Manifest.permission.LOCATION_HARDWARE,
- "Location Hardware permission not granted to access hardware batching");
-
- if (!hasGnssPermissions(packageName)) {
- Log.e(TAG, "flushGnssBatch called without GNSS permissions");
- return;
- }
+ mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, null);
+ mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
- if (mGnssBatchingProvider == null) {
- Log.e(
- TAG,
- "Can not flush GNSS batch. GNSS batching provider "
- + "not available.");
+ if (!checkLocationAppOp(packageName)) {
return;
}
synchronized (mGnssBatchingLock) {
- if (!mGnssBatchingInProgress) {
- Log.w(TAG, "flushGnssBatch called with no batch in progress");
- }
mGnssBatchingProvider.flush();
}
}
@@ -376,17 +307,7 @@ public class GnssManagerService {
* Removes GNSS batching callback.
*/
public void removeGnssBatchingCallback() {
- mContext.enforceCallingPermission(
- android.Manifest.permission.LOCATION_HARDWARE,
- "Location Hardware permission not granted to access hardware batching");
-
- if (mGnssBatchingProvider == null) {
- Log.e(
- TAG,
- "Can not add GNSS batching callback. GNSS batching provider "
- + "not available.");
- return;
- }
+ mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE, null);
synchronized (mGnssBatchingLock) {
mGnssBatchingDeathCallback.unlinkFromListenerDeathNotificationLocked(
@@ -398,44 +319,17 @@ public class GnssManagerService {
/**
* Stop GNSS batch collection.
- *
- * @return true if GNSS batch successfully stopped, false otherwise
*/
public boolean stopGnssBatch() {
- mContext.enforceCallingPermission(
- android.Manifest.permission.LOCATION_HARDWARE,
- "Location Hardware permission not granted to access hardware batching");
+ mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE, null);
- if (mGnssBatchingProvider == null) {
- Log.e(
- TAG,
- "Can not stop GNSS batch. GNSS batching provider "
- + "not available.");
- return false;
- }
synchronized (mGnssBatchingLock) {
mGnssBatchingInProgress = false;
return mGnssBatchingProvider.stop();
}
}
- private void registerUidListener() {
- mContext.getSystemService(
- ActivityManager.class).addOnUidImportanceListener(
- (uid, importance) -> {
- // listener invoked on ui thread, move to our thread to reduce risk
- // of blocking ui thread
- mHandler.post(
- () -> {
- onForegroundChanged(uid,
- LocationManagerServiceUtils.isImportanceForeground(
- importance));
- });
- },
- ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE);
- }
-
- private void onForegroundChanged(int uid, boolean foreground) {
+ private void onAppForegroundChanged(int uid, boolean foreground) {
synchronized (mGnssMeasurementsListeners) {
updateListenersOnForegroundChangedLocked(
mGnssMeasurementsListeners,
@@ -463,8 +357,7 @@ public class GnssManagerService {
}
private <TListener extends IInterface> void updateListenersOnForegroundChangedLocked(
- ArrayMap<IBinder, ? extends LinkedListenerBase>
- gnssDataListeners,
+ Map<IBinder, ? extends LinkedListenerBase> gnssDataListeners,
RemoteListenerHelper<TListener> gnssDataProvider,
Function<IBinder, TListener> mapBinderToListener,
int uid,
@@ -477,18 +370,8 @@ public class GnssManagerService {
continue;
}
- if (D) {
- Log.d(
- TAG,
- linkedListener.getListenerName()
- + " from uid "
- + uid
- + " is now "
- + LocationManagerServiceUtils.foregroundAsString(foreground));
- }
-
TListener listener = mapBinderToListener.apply(entry.getKey());
- if (foreground || mLocationManagerService.isThrottlingExemptLocked(callerIdentity)) {
+ if (foreground || isThrottlingExempt(callerIdentity)) {
gnssDataProvider.addListener(listener, callerIdentity);
} else {
gnssDataProvider.removeListener(listener);
@@ -502,67 +385,49 @@ public class GnssManagerService {
@Nullable String featureId,
@NonNull String listenerIdentifier,
RemoteListenerHelper<TListener> gnssDataProvider,
- ArrayMap<IBinder,
- LinkedListener<TListener>> gnssDataListeners,
+ ArrayMap<IBinder, LinkedListener<TListener>> gnssDataListeners,
Consumer<TListener> binderDeathCallback) {
- if (!hasGnssPermissions(packageName)) {
- Log.e(TAG, "addGnssDataListenerLocked called without GNSS permissions");
- return false;
- }
+ mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
- if (gnssDataProvider == null) {
- Log.e(
- TAG,
- "Can not add GNSS data listener. GNSS data provider "
- + "not available.");
+ if (!checkLocationAppOp(packageName)) {
return false;
}
- CallerIdentity callerIdentity =
- new CallerIdentity(Binder.getCallingUid(), Binder.getCallingPid(), packageName,
- featureId, listenerIdentifier);
- LinkedListener<TListener> linkedListener =
- new LocationManagerServiceUtils.LinkedListener<>(
- listener, listenerIdentifier, callerIdentity, binderDeathCallback);
+ CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(),
+ Binder.getCallingPid(), packageName, featureId, listenerIdentifier);
+ LinkedListener<TListener> linkedListener = new LinkedListener<>(listener,
+ listenerIdentifier, callerIdentity, binderDeathCallback);
IBinder binder = listener.asBinder();
if (!linkedListener.linkToListenerDeathNotificationLocked(binder)) {
return false;
}
gnssDataListeners.put(binder, linkedListener);
- long identity = Binder.clearCallingIdentity();
- try {
- if (gnssDataProvider == mGnssMeasurementsProvider
- || gnssDataProvider == mGnssStatusProvider) {
- mLocationUsageLogger.logLocationApiUsage(
- LocationStatsEnums.USAGE_STARTED,
- gnssDataProvider == mGnssMeasurementsProvider
- ? LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER
- : LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK,
- packageName,
- /* LocationRequest= */ null,
- /* hasListener= */ true,
- /* hasIntent= */ false,
- /* geofence= */ null,
- LocationManagerServiceUtils.getPackageImportance(packageName,
- mContext));
- }
- if (mLocationManagerService.isThrottlingExemptLocked(callerIdentity)
- || LocationManagerServiceUtils.isImportanceForeground(
- LocationManagerServiceUtils.getPackageImportance(packageName, mContext))) {
- gnssDataProvider.addListener(listener, callerIdentity);
- }
- return true;
- } finally {
- Binder.restoreCallingIdentity(identity);
+ if (gnssDataProvider == mGnssMeasurementsProvider
+ || gnssDataProvider == mGnssStatusProvider) {
+ mLocationUsageLogger.logLocationApiUsage(
+ LocationStatsEnums.USAGE_STARTED,
+ gnssDataProvider == mGnssMeasurementsProvider
+ ? LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER
+ : LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK,
+ packageName,
+ /* LocationRequest= */ null,
+ /* hasListener= */ true,
+ /* hasIntent= */ false,
+ /* geofence= */ null,
+ mAppForegroundHelper.getImportance(callerIdentity.mUid));
}
+ if (mAppForegroundHelper.isAppForeground(callerIdentity.mUid)
+ || isThrottlingExempt(callerIdentity)) {
+ gnssDataProvider.addListener(listener, callerIdentity);
+ }
+ return true;
}
- private <TListener extends IInterface> void removeGnssDataListener(
+ private <TListener extends IInterface> void removeGnssDataListenerLocked(
TListener listener,
RemoteListenerHelper<TListener> gnssDataProvider,
- ArrayMap<IBinder,
- LinkedListener<TListener>> gnssDataListeners) {
+ ArrayMap<IBinder, LinkedListener<TListener>> gnssDataListeners) {
if (gnssDataProvider == null) {
Log.e(
TAG,
@@ -577,25 +442,19 @@ public class GnssManagerService {
if (linkedListener == null) {
return;
}
- long identity = Binder.clearCallingIdentity();
- try {
- if (gnssDataProvider == mGnssMeasurementsProvider
- || gnssDataProvider == mGnssStatusProvider) {
- mLocationUsageLogger.logLocationApiUsage(
- LocationStatsEnums.USAGE_ENDED,
- gnssDataProvider == mGnssMeasurementsProvider
- ? LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER
- : LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK,
- linkedListener.getCallerIdentity().mPackageName,
- /* LocationRequest= */ null,
- /* hasListener= */ true,
- /* hasIntent= */ false,
- /* geofence= */ null,
- LocationManagerServiceUtils.getPackageImportance(
- linkedListener.getCallerIdentity().mPackageName, mContext));
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
+ if (gnssDataProvider == mGnssMeasurementsProvider
+ || gnssDataProvider == mGnssStatusProvider) {
+ mLocationUsageLogger.logLocationApiUsage(
+ LocationStatsEnums.USAGE_ENDED,
+ gnssDataProvider == mGnssMeasurementsProvider
+ ? LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER
+ : LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK,
+ linkedListener.getCallerIdentity().mPackageName,
+ /* LocationRequest= */ null,
+ /* hasListener= */ true,
+ /* hasIntent= */ false,
+ /* geofence= */ null,
+ mAppForegroundHelper.getImportance(Binder.getCallingUid()));
}
linkedListener.unlinkFromListenerDeathNotificationLocked(binder);
gnssDataProvider.removeListener(listener);
@@ -603,10 +462,6 @@ public class GnssManagerService {
/**
* Registers listener for GNSS status changes.
- *
- * @param listener called when GNSS status changes
- * @param packageName name of requesting package
- * @return true if listener is successfully registered, false otherwise
*/
public boolean registerGnssStatusCallback(IGnssStatusListener listener, String packageName,
@Nullable String featureId) {
@@ -624,21 +479,15 @@ public class GnssManagerService {
/**
* Unregisters listener for GNSS status changes.
- *
- * @param listener called when GNSS status changes
*/
public void unregisterGnssStatusCallback(IGnssStatusListener listener) {
synchronized (mGnssStatusListeners) {
- removeGnssDataListener(listener, mGnssStatusProvider, mGnssStatusListeners);
+ removeGnssDataListenerLocked(listener, mGnssStatusProvider, mGnssStatusListeners);
}
}
/**
* Adds a GNSS measurements listener.
- *
- * @param listener called when GNSS measurements are received
- * @param packageName name of requesting package
- * @return true if listener is successfully added, false otherwise
*/
public boolean addGnssMeasurementsListener(
IGnssMeasurementsListener listener, String packageName, @Nullable String featureId,
@@ -657,47 +506,32 @@ public class GnssManagerService {
/**
* Injects GNSS measurement corrections.
- *
- * @param measurementCorrections GNSS measurement corrections
- * @param packageName name of requesting package
*/
public void injectGnssMeasurementCorrections(
GnssMeasurementCorrections measurementCorrections, String packageName) {
- mContext.enforceCallingPermission(
- android.Manifest.permission.LOCATION_HARDWARE,
- "Location Hardware permission not granted to inject GNSS measurement corrections.");
- if (!hasGnssPermissions(packageName)) {
- Log.e(TAG, "Can not inject GNSS corrections due to no permission.");
- return;
- }
- if (mGnssMeasurementCorrectionsProvider == null) {
- Log.e(
- TAG,
- "Can not inject GNSS corrections. GNSS measurement corrections provider "
- + "not available.");
+ mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, null);
+ mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
+
+ if (!checkLocationAppOp(packageName)) {
return;
}
+
mGnssMeasurementCorrectionsProvider.injectGnssMeasurementCorrections(
measurementCorrections);
}
/**
* Removes a GNSS measurements listener.
- *
- * @param listener called when GNSS measurements are received
*/
public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
synchronized (mGnssMeasurementsListeners) {
- removeGnssDataListener(listener, mGnssMeasurementsProvider, mGnssMeasurementsListeners);
+ removeGnssDataListenerLocked(listener, mGnssMeasurementsProvider,
+ mGnssMeasurementsListeners);
}
}
/**
* Adds a GNSS navigation message listener.
- *
- * @param listener called when navigation message is received
- * @param packageName name of requesting package
- * @return true if listener is successfully added, false otherwise
*/
public boolean addGnssNavigationMessageListener(
IGnssNavigationMessageListener listener, String packageName,
@@ -716,12 +550,10 @@ public class GnssManagerService {
/**
* Removes a GNSS navigation message listener.
- *
- * @param listener called when navigation message is received
*/
public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
synchronized (mGnssNavigationMessageListeners) {
- removeGnssDataListener(
+ removeGnssDataListenerLocked(
listener, mGnssNavigationMessageProvider, mGnssNavigationMessageListeners);
}
}
@@ -729,43 +561,62 @@ public class GnssManagerService {
/**
* Send Ni Response, indicating a location request initiated by a network carrier.
*/
- public boolean sendNiResponse(int notifId, int userResponse) {
- if (Binder.getCallingUid() != Process.myUid()) {
- throw new SecurityException(
- "calling sendNiResponse from outside of the system is not allowed");
- }
+ public void sendNiResponse(int notifId, int userResponse) {
try {
- return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
+ mNetInitiatedListener.sendNiResponse(notifId, userResponse);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
- return false;
}
}
/**
* Report location results to GNSS batching listener.
- *
- * @param locations batch of locations to report to GNSS batching callback
*/
public void onReportLocation(List<Location> locations) {
- if (mGnssBatchingCallback == null) {
- Log.e(TAG, "reportLocationBatch() called without active Callback");
+ IBatchedLocationCallback gnssBatchingCallback;
+ synchronized (mGnssBatchingLock) {
+ gnssBatchingCallback = mGnssBatchingCallback;
+ }
+
+ if (gnssBatchingCallback == null) {
return;
}
try {
- mGnssBatchingCallback.onLocationBatch(locations);
+ gnssBatchingCallback.onLocationBatch(locations);
} catch (RemoteException e) {
Log.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
}
}
+ private boolean isThrottlingExempt(CallerIdentity callerIdentity) {
+ if (callerIdentity.mUid == Process.SYSTEM_UID) {
+ return true;
+ }
+
+ if (mSettingsHelper.getBackgroundThrottlePackageWhitelist().contains(
+ callerIdentity.mPackageName)) {
+ return true;
+ }
+
+ synchronized (this) {
+ Preconditions.checkState(mLocationManagerInternal != null);
+ }
+ return mLocationManagerInternal.isProviderPackage(callerIdentity.mPackageName);
+ }
+
+ private boolean checkLocationAppOp(String packageName) {
+ synchronized (this) {
+ Preconditions.checkState(mAppOpsManager != null);
+ }
+ return mAppOpsManager.checkOp(OP_FINE_LOCATION, Binder.getCallingUid(), packageName)
+ == AppOpsManager.MODE_ALLOWED;
+ }
+
/**
- * Dump for debugging.
+ * Dump info for debugging.
*/
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
-
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
if (args.length > 0 && args[0].equals("--gnssmetrics")) {
@@ -778,11 +629,8 @@ public class GnssManagerService {
ipw.println("GnssMeasurement Listeners:");
ipw.increaseIndent();
synchronized (mGnssMeasurementsListeners) {
- for (LinkedListenerBase listener :
- mGnssMeasurementsListeners
- .values()) {
- ipw.println(listener + ": " + mLocationManagerService.isThrottlingExemptLocked(
- listener.getCallerIdentity()));
+ for (LinkedListenerBase listener : mGnssMeasurementsListeners.values()) {
+ ipw.println(listener);
}
}
ipw.decreaseIndent();
@@ -790,10 +638,8 @@ public class GnssManagerService {
ipw.println("GnssNavigationMessage Listeners:");
ipw.increaseIndent();
synchronized (mGnssNavigationMessageListeners) {
- for (LinkedListenerBase listener :
- mGnssNavigationMessageListeners.values()) {
- ipw.println(listener + ": " + mLocationManagerService.isThrottlingExemptLocked(
- listener.getCallerIdentity()));
+ for (LinkedListenerBase listener : mGnssNavigationMessageListeners.values()) {
+ ipw.println(listener);
}
}
ipw.decreaseIndent();
@@ -801,10 +647,8 @@ public class GnssManagerService {
ipw.println("GnssStatus Listeners:");
ipw.increaseIndent();
synchronized (mGnssStatusListeners) {
- for (LinkedListenerBase listener :
- mGnssStatusListeners.values()) {
- ipw.println(listener + ": " + mLocationManagerService.isThrottlingExemptLocked(
- listener.getCallerIdentity()));
+ for (LinkedListenerBase listener : mGnssStatusListeners.values()) {
+ ipw.println(listener);
}
}
ipw.decreaseIndent();
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/AppForegroundHelperTest.java b/services/tests/mockingservicestests/src/com/android/server/location/AppForegroundHelperTest.java
new file mode 100644
index 000000000000..38ec4ce3e827
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/location/AppForegroundHelperTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AppForegroundHelperTest {
+
+ private static final long TIMEOUT_MS = 5000;
+
+ @Mock private Context mContext;
+ @Mock private ActivityManager mActivityManager;
+
+ private List<ActivityManager.OnUidImportanceListener> mListeners = new ArrayList<>();
+
+ private AppForegroundHelper mHelper;
+
+ @Before
+ public void setUp() {
+ initMocks(this);
+
+ doReturn(mActivityManager).when(mContext).getSystemService(ActivityManager.class);
+ doAnswer(invocation -> {
+ mListeners.add(invocation.getArgument(0));
+ return null;
+ }).when(mActivityManager).addOnUidImportanceListener(any(
+ ActivityManager.OnUidImportanceListener.class), eq(IMPORTANCE_FOREGROUND_SERVICE));
+
+ mHelper = new AppForegroundHelper(mContext);
+ mHelper.onSystemReady();
+ }
+
+ private void setImportance(int uid, int importance) {
+ doReturn(importance).when(mActivityManager).getUidImportance(uid);
+ for (ActivityManager.OnUidImportanceListener listener : mListeners) {
+ listener.onUidImportance(uid, importance);
+ }
+ }
+
+ @Test
+ public void testListeners() {
+ AppForegroundHelper.AppForegroundListener listener = mock(
+ AppForegroundHelper.AppForegroundListener.class);
+ mHelper.addListener(listener);
+
+ setImportance(0, IMPORTANCE_FOREGROUND);
+ verify(listener, timeout(TIMEOUT_MS)).onAppForegroundChanged(0, true);
+
+ setImportance(1, IMPORTANCE_FOREGROUND_SERVICE);
+ verify(listener, timeout(TIMEOUT_MS)).onAppForegroundChanged(1, true);
+
+ setImportance(2, IMPORTANCE_VISIBLE);
+ verify(listener, timeout(TIMEOUT_MS)).onAppForegroundChanged(2, false);
+ }
+
+ @Test
+ public void testIsAppForeground() {
+ setImportance(0, IMPORTANCE_FOREGROUND);
+ assertThat(mHelper.isAppForeground(0)).isEqualTo(true);
+
+ setImportance(0, IMPORTANCE_FOREGROUND_SERVICE);
+ assertThat(mHelper.isAppForeground(0)).isEqualTo(true);
+
+ setImportance(0, IMPORTANCE_VISIBLE);
+ assertThat(mHelper.isAppForeground(0)).isEqualTo(false);
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/UserInfoStoreTest.java b/services/tests/mockingservicestests/src/com/android/server/location/UserInfoHelperTest.java
index 06fb10257a37..389fdf9b0abc 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/UserInfoStoreTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/UserInfoHelperTest.java
@@ -57,7 +57,7 @@ import java.util.List;
@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class UserInfoStoreTest {
+public class UserInfoHelperTest {
private static final int USER1_ID = 1;
private static final int USER1_MANAGED_ID = 11;
@@ -72,7 +72,7 @@ public class UserInfoStoreTest {
private StaticMockitoSession mMockingSession;
private List<BroadcastReceiver> mBroadcastReceivers = new ArrayList<>();
- private UserInfoStore mStore;
+ private UserInfoHelper mHelper;
@Before
public void setUp() {
@@ -97,8 +97,8 @@ public class UserInfoStoreTest {
doReturn(USER1_ID).when(ActivityManager::getCurrentUser);
- mStore = new UserInfoStore(mContext);
- mStore.onSystemReady();
+ mHelper = new UserInfoHelper(mContext);
+ mHelper.onSystemReady();
}
@After
@@ -119,8 +119,9 @@ public class UserInfoStoreTest {
@Test
public void testListeners() {
- UserInfoStore.UserChangedListener listener = mock(UserInfoStore.UserChangedListener.class);
- mStore.addListener(listener);
+ UserInfoHelper.UserChangedListener listener = mock(
+ UserInfoHelper.UserChangedListener.class);
+ mHelper.addListener(listener);
switchUser(USER1_ID);
verify(listener, never()).onUserChanged(anyInt(), anyInt());
@@ -134,44 +135,44 @@ public class UserInfoStoreTest {
@Test
public void testCurrentUser() {
- assertThat(mStore.getCurrentUserId()).isEqualTo(USER1_ID);
+ assertThat(mHelper.getCurrentUserId()).isEqualTo(USER1_ID);
switchUser(USER2_ID);
- assertThat(mStore.getCurrentUserId()).isEqualTo(USER2_ID);
+ assertThat(mHelper.getCurrentUserId()).isEqualTo(USER2_ID);
switchUser(USER1_ID);
- assertThat(mStore.getCurrentUserId()).isEqualTo(USER1_ID);
+ assertThat(mHelper.getCurrentUserId()).isEqualTo(USER1_ID);
}
@Test
public void testIsCurrentUserOrProfile() {
- assertThat(mStore.isCurrentUserOrProfile(USER1_ID)).isTrue();
- assertThat(mStore.isCurrentUserOrProfile(USER1_MANAGED_ID)).isTrue();
- assertThat(mStore.isCurrentUserOrProfile(USER2_ID)).isFalse();
- assertThat(mStore.isCurrentUserOrProfile(USER2_MANAGED_ID)).isFalse();
+ assertThat(mHelper.isCurrentUserOrProfile(USER1_ID)).isTrue();
+ assertThat(mHelper.isCurrentUserOrProfile(USER1_MANAGED_ID)).isTrue();
+ assertThat(mHelper.isCurrentUserOrProfile(USER2_ID)).isFalse();
+ assertThat(mHelper.isCurrentUserOrProfile(USER2_MANAGED_ID)).isFalse();
switchUser(USER2_ID);
- assertThat(mStore.isCurrentUserOrProfile(USER1_ID)).isFalse();
- assertThat(mStore.isCurrentUserOrProfile(USER2_ID)).isTrue();
- assertThat(mStore.isCurrentUserOrProfile(USER1_MANAGED_ID)).isFalse();
- assertThat(mStore.isCurrentUserOrProfile(USER2_MANAGED_ID)).isTrue();
+ assertThat(mHelper.isCurrentUserOrProfile(USER1_ID)).isFalse();
+ assertThat(mHelper.isCurrentUserOrProfile(USER2_ID)).isTrue();
+ assertThat(mHelper.isCurrentUserOrProfile(USER1_MANAGED_ID)).isFalse();
+ assertThat(mHelper.isCurrentUserOrProfile(USER2_MANAGED_ID)).isTrue();
}
@Test
public void testGetParentUserId() {
- assertThat(mStore.getParentUserId(USER1_ID)).isEqualTo(USER1_ID);
- assertThat(mStore.getParentUserId(USER1_MANAGED_ID)).isEqualTo(USER1_ID);
- assertThat(mStore.getParentUserId(USER2_ID)).isEqualTo(USER2_ID);
- assertThat(mStore.getParentUserId(USER2_MANAGED_ID)).isEqualTo(USER2_ID);
+ assertThat(mHelper.getParentUserId(USER1_ID)).isEqualTo(USER1_ID);
+ assertThat(mHelper.getParentUserId(USER1_MANAGED_ID)).isEqualTo(USER1_ID);
+ assertThat(mHelper.getParentUserId(USER2_ID)).isEqualTo(USER2_ID);
+ assertThat(mHelper.getParentUserId(USER2_MANAGED_ID)).isEqualTo(USER2_ID);
switchUser(USER2_ID);
- assertThat(mStore.getParentUserId(USER1_ID)).isEqualTo(USER1_ID);
- assertThat(mStore.getParentUserId(USER2_ID)).isEqualTo(USER2_ID);
- assertThat(mStore.getParentUserId(USER1_MANAGED_ID)).isEqualTo(USER1_ID);
- assertThat(mStore.getParentUserId(USER2_MANAGED_ID)).isEqualTo(USER2_ID);
+ assertThat(mHelper.getParentUserId(USER1_ID)).isEqualTo(USER1_ID);
+ assertThat(mHelper.getParentUserId(USER2_ID)).isEqualTo(USER2_ID);
+ assertThat(mHelper.getParentUserId(USER1_MANAGED_ID)).isEqualTo(USER1_ID);
+ assertThat(mHelper.getParentUserId(USER2_MANAGED_ID)).isEqualTo(USER2_ID);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java
index f262733bb882..f16cf35bfb34 100644
--- a/services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java
@@ -24,6 +24,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -31,7 +32,6 @@ import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;
import android.Manifest;
-import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -46,13 +46,15 @@ import android.location.IGnssNavigationMessageListener;
import android.location.IGnssStatusListener;
import android.location.INetInitiatedListener;
import android.location.Location;
+import android.location.LocationManagerInternal;
import android.os.Handler;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Message;
import android.os.RemoteException;
-import com.android.server.LocationManagerService;
+import com.android.server.LocalServices;
+import com.android.server.location.AppForegroundHelper;
import com.android.server.location.GnssBatchingProvider;
import com.android.server.location.GnssCapabilitiesProvider;
import com.android.server.location.GnssLocationProvider;
@@ -63,7 +65,9 @@ import com.android.server.location.GnssNavigationMessageProvider;
import com.android.server.location.GnssNavigationMessageProvider.GnssNavigationMessageProviderNative;
import com.android.server.location.GnssStatusListenerHelper;
import com.android.server.location.LocationUsageLogger;
+import com.android.server.location.SettingsHelper;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.AdditionalMatchers;
@@ -93,18 +97,20 @@ public class GnssManagerServiceTest {
@Mock
private GnssMeasurementCorrectionsProvider mMockGnssMeasurementCorrectionsProvider;
@Mock
- private INetInitiatedListener mMockNetInitiatedListener;
+ private INetInitiatedListener mNetInitiatedListener;
private GnssMeasurementsProvider mTestGnssMeasurementsProvider;
private GnssStatusListenerHelper mTestGnssStatusProvider;
private GnssNavigationMessageProvider mTestGnssNavigationMessageProvider;
// Managers and services
@Mock
- private AppOpsManager mMockAppOpsManager;
+ private AppOpsManager mAppOpsManager;
@Mock
- private ActivityManager mMockActivityManager;
+ private SettingsHelper mSettingsHelper;
@Mock
- private LocationManagerService mMockLocationManagerService;
+ private AppForegroundHelper mAppForegroundHelper;
+ @Mock
+ private LocationManagerInternal mLocationManagerInternal;
// Context and handler
@Mock
@@ -113,25 +119,23 @@ public class GnssManagerServiceTest {
private Context mMockContext;
// Class under test
- private com.android.server.location.gnss.GnssManagerService mGnssManagerService;
+ private GnssManagerService mGnssManagerService;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
GnssLocationProvider.setIsSupportedForTest(true);
- // Set up mock context
when(mMockContext.getSystemServiceName(AppOpsManager.class)).thenReturn(
Context.APP_OPS_SERVICE);
- when(mMockContext.getSystemServiceName(ActivityManager.class)).thenReturn(
- Context.ACTIVITY_SERVICE);
when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(
- mMockAppOpsManager);
- when(mMockContext.getSystemService(
- eq(Context.ACTIVITY_SERVICE))).thenReturn(
- mMockActivityManager);
+ mAppOpsManager);
enableLocationPermissions();
+ when(mAppForegroundHelper.isAppForeground(anyInt())).thenReturn(true);
+
+ LocalServices.addService(LocationManagerInternal.class, mLocationManagerInternal);
+
// Mock Handler will execute posted runnables immediately
when(mMockHandler.sendMessageAtTime(any(Message.class), anyLong())).thenAnswer(
(InvocationOnMock invocation) -> {
@@ -164,15 +168,22 @@ public class GnssManagerServiceTest {
when(mMockGnssLocationProvider.getGnssNavigationMessageProvider()).thenReturn(
mTestGnssNavigationMessageProvider);
when(mMockGnssLocationProvider.getNetInitiatedListener()).thenReturn(
- mMockNetInitiatedListener);
+ mNetInitiatedListener);
// Setup GnssBatching provider
when(mMockGnssBatchingProvider.start(anyLong(), anyBoolean())).thenReturn(true);
when(mMockGnssBatchingProvider.stop()).thenReturn(true);
// Create GnssManagerService
- mGnssManagerService = new GnssManagerService(mMockLocationManagerService, mMockContext,
- mMockGnssLocationProvider, new LocationUsageLogger());
+ mGnssManagerService = new GnssManagerService(mMockContext, mSettingsHelper,
+ mAppForegroundHelper, new LocationUsageLogger(),
+ mMockGnssLocationProvider);
+ mGnssManagerService.onSystemReady();
+ }
+
+ @After
+ public void tearDown() {
+ LocalServices.removeServiceForTest(LocationManagerInternal.class);
}
private void overrideAsBinder(IInterface mockListener) {
@@ -225,7 +236,7 @@ public class GnssManagerServiceTest {
PackageManager.PERMISSION_GRANTED);
// AppOpsManager will return true if OP_FINE_LOCATION is checked
- when(mMockAppOpsManager.checkOp(anyInt(), anyInt(), anyString())).thenAnswer(
+ when(mAppOpsManager.checkOp(anyInt(), anyInt(), anyString())).thenAnswer(
(InvocationOnMock invocation) -> {
int code = (int) (invocation.getArguments()[0]);
if (code == AppOpsManager.OP_FINE_LOCATION) {
@@ -237,11 +248,11 @@ public class GnssManagerServiceTest {
private void disableLocationPermissions() {
Mockito.doThrow(new SecurityException()).when(
- mMockContext).enforceCallingPermission(anyString(), anyString());
+ mMockContext).enforceCallingPermission(anyString(), nullable(String.class));
Mockito.doThrow(new SecurityException()).when(
mMockContext).checkPermission(anyString(), anyInt(), anyInt());
- when(mMockAppOpsManager.checkOp(anyInt(), anyInt(),
+ when(mAppOpsManager.checkOp(anyInt(), anyInt(),
anyString())).thenReturn(AppOpsManager.MODE_ERRORED);
}
@@ -733,14 +744,12 @@ public class GnssManagerServiceTest {
@Test
public void sendNiResponseWithPermissionsTest() throws RemoteException {
- when(mMockNetInitiatedListener.sendNiResponse(anyInt(), anyInt())).thenReturn(true);
-
int notifId = 0;
int userResponse = 0;
enableLocationPermissions();
- assertThat(mGnssManagerService.sendNiResponse(notifId, userResponse)).isEqualTo(true);
+ mGnssManagerService.sendNiResponse(notifId, userResponse);
- verify(mMockNetInitiatedListener, times(1)).sendNiResponse(notifId, userResponse);
+ verify(mNetInitiatedListener, times(1)).sendNiResponse(notifId, userResponse);
}
}