Merge "Assorted location cleanup"
diff --git a/services/core/java/com/android/server/GnssManagerService.java b/services/core/java/com/android/server/GnssManagerService.java
index cbf2a62..bbcfdc6 100644
--- a/services/core/java/com/android/server/GnssManagerService.java
+++ b/services/core/java/com/android/server/GnssManagerService.java
@@ -56,6 +56,7 @@
import com.android.server.location.GnssMeasurementsProvider;
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 java.io.FileDescriptor;
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 6300ab8..cad917b 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -104,6 +104,7 @@
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.PassiveProvider;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
@@ -158,21 +159,15 @@
}
}
- private static final String TAG = "LocationManagerService";
+ public static final String TAG = "LocationManagerService";
public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
private static final String WAKELOCK_KEY = "*location*";
- // Location resolution level: no location data whatsoever
private static final int RESOLUTION_LEVEL_NONE = 0;
- // Location resolution level: coarse location data only
private static final int RESOLUTION_LEVEL_COARSE = 1;
- // Location resolution level: fine location data
private static final int RESOLUTION_LEVEL_FINE = 2;
- private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
- android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
-
private static final String NETWORK_LOCATION_SERVICE_ACTION =
"com.android.location.service.v3.NetworkLocationProvider";
private static final String FUSED_LOCATION_SERVICE_ACTION =
@@ -198,6 +193,8 @@
private final Object mLock = new Object();
private final Context mContext;
private final Handler mHandler;
+ private final LocationSettingsStore mSettingsStore;
+ private final LocationUsageLogger mLocationUsageLogger;
private AppOpsManager mAppOps;
private PackageManager mPackageManager;
@@ -205,8 +202,6 @@
private ActivityManager mActivityManager;
private UserManager mUserManager;
- private LocationSettingsStore mSettingsStore;
-
private GeofenceManager mGeofenceManager;
private LocationFudger mLocationFudger;
private GeocoderProxy mGeocodeProvider;
@@ -219,12 +214,12 @@
// list of currently active providers
@GuardedBy("mLock")
- private final ArrayList<LocationProvider> mProviders = new ArrayList<>();
+ private final ArrayList<LocationProviderManager> mProviders = new ArrayList<>();
// list of non-mock providers, so that when mock providers replace real providers, they can be
// later re-replaced
@GuardedBy("mLock")
- private final ArrayList<LocationProvider> mRealProviders = new ArrayList<>();
+ private final ArrayList<LocationProviderManager> mRealProviders = new ArrayList<>();
@GuardedBy("mLock")
private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
@@ -251,12 +246,10 @@
@PowerManager.LocationPowerSaveMode
private int mBatterySaverMode;
- @GuardedBy("mLock")
- private final LocationUsageLogger mLocationUsageLogger;
-
private LocationManagerService(Context context) {
mContext = context;
mHandler = FgThread.getHandler();
+ mSettingsStore = new LocationSettingsStore(mContext, mHandler);
mLocationUsageLogger = new LocationUsageLogger();
// Let the package manager query which are the default location
@@ -274,6 +267,8 @@
}
private void onSystemReady() {
+ mSettingsStore.onSystemReady();
+
synchronized (mLock) {
mPackageManager = mContext.getPackageManager();
mAppOps = mContext.getSystemService(AppOpsManager.class);
@@ -281,7 +276,6 @@
mActivityManager = mContext.getSystemService(ActivityManager.class);
mUserManager = mContext.getSystemService(UserManager.class);
- mSettingsStore = new LocationSettingsStore(mContext, mHandler);
mLocationFudger = new LocationFudger(mContext, mHandler);
mGeofenceManager = new GeofenceManager(mContext, mSettingsStore);
@@ -421,14 +415,14 @@
for (Receiver receiver : mReceivers.values()) {
receiver.updateMonitoring(true);
}
- for (LocationProvider p : mProviders) {
+ for (LocationProviderManager p : mProviders) {
applyRequirementsLocked(p);
}
}
@GuardedBy("mLock")
private void onPermissionsChangedLocked() {
- for (LocationProvider p : mProviders) {
+ for (LocationProviderManager p : mProviders) {
applyRequirementsLocked(p);
}
}
@@ -448,7 +442,7 @@
mBatterySaverMode = newLocationMode;
- for (LocationProvider p : mProviders) {
+ for (LocationProviderManager p : mProviders) {
applyRequirementsLocked(p);
}
}
@@ -456,7 +450,7 @@
@GuardedBy("mLock")
private void onScreenStateChangedLocked() {
if (mBatterySaverMode == PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF) {
- for (LocationProvider p : mProviders) {
+ for (LocationProviderManager p : mProviders) {
applyRequirementsLocked(p);
}
}
@@ -472,7 +466,7 @@
intent.putExtra(LocationManager.EXTRA_LOCATION_ENABLED, isLocationEnabledForUser(userId));
mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
- for (LocationProvider p : mProviders) {
+ for (LocationProviderManager p : mProviders) {
p.onUseableChangedLocked(userId);
}
}
@@ -527,21 +521,21 @@
@GuardedBy("mLock")
private void onBackgroundThrottleIntervalChangedLocked() {
- for (LocationProvider provider : mProviders) {
+ for (LocationProviderManager provider : mProviders) {
applyRequirementsLocked(provider);
}
}
@GuardedBy("mLock")
private void onBackgroundThrottleWhitelistChangedLocked() {
- for (LocationProvider p : mProviders) {
+ for (LocationProviderManager p : mProviders) {
applyRequirementsLocked(p);
}
}
@GuardedBy("lock")
private void onIgnoreSettingsWhitelistChangedLocked() {
- for (LocationProvider p : mProviders) {
+ for (LocationProviderManager p : mProviders) {
applyRequirementsLocked(p);
}
}
@@ -630,14 +624,15 @@
@GuardedBy("mLock")
private void initializeProvidersLocked() {
// create a passive location provider, which is always enabled
- LocationProvider passiveProviderManager = new LocationProvider(PASSIVE_PROVIDER);
+ LocationProviderManager passiveProviderManager = new LocationProviderManager(
+ PASSIVE_PROVIDER);
addProviderLocked(passiveProviderManager);
mPassiveProvider = new PassiveProvider(mContext, passiveProviderManager);
passiveProviderManager.attachLocked(mPassiveProvider);
if (GnssManagerService.isGnssSupported()) {
// Create a gps location provider manager
- LocationProvider gnssProviderManager = new LocationProvider(GPS_PROVIDER);
+ LocationProviderManager gnssProviderManager = new LocationProviderManager(GPS_PROVIDER);
mRealProviders.add(gnssProviderManager);
addProviderLocked(gnssProviderManager);
@@ -668,7 +663,8 @@
ensureFallbackFusedProviderPresentLocked(pkgs);
// bind to network provider
- LocationProvider networkProviderManager = new LocationProvider(NETWORK_PROVIDER);
+ LocationProviderManager networkProviderManager = new LocationProviderManager(
+ NETWORK_PROVIDER);
LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
mContext,
networkProviderManager,
@@ -685,7 +681,7 @@
}
// bind to fused provider
- LocationProvider fusedProviderManager = new LocationProvider(FUSED_PROVIDER);
+ LocationProviderManager fusedProviderManager = new LocationProviderManager(FUSED_PROVIDER);
LocationProviderProxy fusedProvider = LocationProviderProxy.createAndBind(
mContext,
fusedProviderManager,
@@ -758,7 +754,7 @@
Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
Integer.parseInt(fragments[8]) /* powerRequirement */,
Integer.parseInt(fragments[9]) /* accuracy */);
- LocationProvider testProviderManager = new LocationProvider(name);
+ LocationProviderManager testProviderManager = new LocationProviderManager(name);
addProviderLocked(testProviderManager);
testProviderManager.attachLocked(
new MockProvider(mContext, testProviderManager, properties));
@@ -780,7 +776,7 @@
onUserProfilesChangedLocked();
// let providers know the current user has changed
- for (LocationProvider p : mProviders) {
+ for (LocationProviderManager p : mProviders) {
p.onUseableChangedLocked(oldUserId);
p.onUseableChangedLocked(mCurrentUserId);
}
@@ -789,7 +785,7 @@
/**
* Location provider manager, manages a LocationProvider.
*/
- class LocationProvider implements AbstractLocationProvider.LocationProviderManager {
+ class LocationProviderManager implements AbstractLocationProvider.LocationProviderManager {
private final String mName;
@@ -807,7 +803,7 @@
@Nullable
private ProviderProperties mProperties;
- private LocationProvider(String name) {
+ private LocationProviderManager(String name) {
mName = name;
mProvider = null;
@@ -944,7 +940,7 @@
return;
}
synchronized (mLock) {
- LocationProvider gpsProvider = getLocationProviderLocked(GPS_PROVIDER);
+ LocationProviderManager gpsProvider = getLocationProviderLocked(GPS_PROVIDER);
if (gpsProvider == null || !gpsProvider.isUseableLocked()) {
Slog.w(TAG, "reportLocationBatch() called without user permission");
return;
@@ -1035,7 +1031,7 @@
}
}
- private class MockLocationProvider extends LocationProvider {
+ private class MockLocationProvider extends LocationProviderManager {
private ProviderRequest mCurrentRequest;
@@ -1185,7 +1181,8 @@
// See if receiver has any enabled update records. Also note if any update records
// are high power (has a high power provider with an interval under a threshold).
for (UpdateRecord updateRecord : mUpdateRecords.values()) {
- LocationProvider provider = getLocationProviderLocked(updateRecord.mProvider);
+ LocationProviderManager provider = getLocationProviderLocked(
+ updateRecord.mProvider);
if (provider == null) {
continue;
}
@@ -1461,7 +1458,7 @@
}
@GuardedBy("mLock")
- private void addProviderLocked(LocationProvider provider) {
+ private void addProviderLocked(LocationProviderManager provider) {
Preconditions.checkState(getLocationProviderLocked(provider.getName()) == null);
mProviders.add(provider);
@@ -1472,7 +1469,7 @@
}
@GuardedBy("mLock")
- private void removeProviderLocked(LocationProvider provider) {
+ private void removeProviderLocked(LocationProviderManager provider) {
if (mProviders.remove(provider)) {
// 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
@@ -1482,8 +1479,8 @@
@GuardedBy("mLock")
@Nullable
- private LocationProvider getLocationProviderLocked(String providerName) {
- for (LocationProvider provider : mProviders) {
+ private LocationProviderManager getLocationProviderLocked(String providerName) {
+ for (LocationProviderManager provider : mProviders) {
if (providerName.equals(provider.getName())) {
return provider;
}
@@ -1534,7 +1531,7 @@
// network and fused providers are ok with COARSE or FINE
return RESOLUTION_LEVEL_COARSE;
} else {
- for (LocationProvider lp : mProviders) {
+ for (LocationProviderManager lp : mProviders) {
if (!lp.getName().equals(provider)) {
continue;
}
@@ -1634,7 +1631,7 @@
public List<String> getAllProviders() {
synchronized (mLock) {
ArrayList<String> providers = new ArrayList<>(mProviders.size());
- for (LocationProvider provider : mProviders) {
+ for (LocationProviderManager provider : mProviders) {
String name = provider.getName();
if (FUSED_PROVIDER.equals(name)) {
continue;
@@ -1655,7 +1652,7 @@
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
synchronized (mLock) {
ArrayList<String> providers = new ArrayList<>(mProviders.size());
- for (LocationProvider provider : mProviders) {
+ for (LocationProviderManager provider : mProviders) {
String name = provider.getName();
if (FUSED_PROVIDER.equals(name)) {
continue;
@@ -1705,7 +1702,7 @@
}
@GuardedBy("mLock")
- private void updateProviderUseableLocked(LocationProvider provider) {
+ private void updateProviderUseableLocked(LocationProviderManager provider) {
boolean useable = provider.isUseableLocked();
ArrayList<Receiver> deadReceivers = null;
@@ -1744,14 +1741,14 @@
@GuardedBy("mLock")
private void applyRequirementsLocked(String providerName) {
- LocationProvider provider = getLocationProviderLocked(providerName);
+ LocationProviderManager provider = getLocationProviderLocked(providerName);
if (provider != null) {
applyRequirementsLocked(provider);
}
}
@GuardedBy("mLock")
- private void applyRequirementsLocked(LocationProvider provider) {
+ private void applyRequirementsLocked(LocationProviderManager provider) {
ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
WorkSource worksource = new WorkSource();
ProviderRequest providerRequest = new ProviderRequest();
@@ -2201,7 +2198,7 @@
throw new IllegalArgumentException("provider name must not be null");
}
- LocationProvider provider = getLocationProviderLocked(name);
+ LocationProviderManager provider = getLocationProviderLocked(name);
if (provider == null) {
throw new IllegalArgumentException("provider doesn't exist: " + name);
}
@@ -2323,7 +2320,7 @@
// or use the fused provider
String name = request.getProvider();
if (name == null) name = LocationManager.FUSED_PROVIDER;
- LocationProvider provider = getLocationProviderLocked(name);
+ LocationProviderManager provider = getLocationProviderLocked(name);
if (provider == null) return null;
// only the current user or location providers may get location this way
@@ -2453,7 +2450,7 @@
"Access Fine Location permission not granted to inject Location");
synchronized (mLock) {
- LocationProvider provider = getLocationProviderLocked(location.getProvider());
+ LocationProviderManager provider = getLocationProviderLocked(location.getProvider());
if (provider == null || !provider.isUseableLocked()) {
return false;
}
@@ -2624,6 +2621,10 @@
// throw NullPointerException to remain compatible with previous implementation
throw new NullPointerException();
}
+
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, null);
+
synchronized (mLock) {
checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(),
providerName);
@@ -2633,13 +2634,7 @@
LocationStatsEnums.API_SEND_EXTRA_COMMAND,
providerName);
- // and check for ACCESS_LOCATION_EXTRA_COMMANDS
- if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
- != PERMISSION_GRANTED)) {
- throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
- }
-
- LocationProvider provider = getLocationProviderLocked(providerName);
+ LocationProviderManager provider = getLocationProviderLocked(providerName);
if (provider != null) {
provider.sendExtraCommand(command, extras);
}
@@ -2662,7 +2657,7 @@
@Override
public ProviderProperties getProviderProperties(String providerName) {
synchronized (mLock) {
- LocationProvider provider = getLocationProviderLocked(providerName);
+ LocationProviderManager provider = getLocationProviderLocked(providerName);
if (provider == null) {
return null;
}
@@ -2675,7 +2670,7 @@
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_DEVICE_CONFIG,
Manifest.permission.READ_DEVICE_CONFIG + " permission required");
synchronized (mLock) {
- for (LocationProvider provider : mProviders) {
+ for (LocationProviderManager provider : mProviders) {
if (provider.getPackagesLocked().contains(packageName)) {
return true;
}
@@ -2689,7 +2684,7 @@
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_DEVICE_CONFIG,
Manifest.permission.READ_DEVICE_CONFIG + " permission required");
synchronized (mLock) {
- LocationProvider provider = getLocationProviderLocked(providerName);
+ LocationProviderManager provider = getLocationProviderLocked(providerName);
return provider == null ? Collections.emptyList() : provider.getPackagesLocked();
}
}
@@ -2758,7 +2753,7 @@
if (FUSED_PROVIDER.equals(providerName)) return false;
synchronized (mLock) {
- LocationProvider provider = getLocationProviderLocked(providerName);
+ LocationProviderManager provider = getLocationProviderLocked(providerName);
return provider != null && provider.isUseableLocked(userId);
}
}
@@ -2797,7 +2792,7 @@
}
@GuardedBy("mLock")
- private void handleLocationChangedLocked(Location location, LocationProvider provider) {
+ private void handleLocationChangedLocked(Location location, LocationProviderManager provider) {
if (!mProviders.contains(provider)) {
return;
}
@@ -3029,7 +3024,7 @@
synchronized (mLock) {
long identity = Binder.clearCallingIdentity();
try {
- LocationProvider oldProvider = getLocationProviderLocked(name);
+ LocationProviderManager oldProvider = getLocationProviderLocked(name);
if (oldProvider != null) {
removeProviderLocked(oldProvider);
}
@@ -3053,7 +3048,7 @@
synchronized (mLock) {
long identity = Binder.clearCallingIdentity();
try {
- LocationProvider testProvider = getLocationProviderLocked(name);
+ LocationProviderManager testProvider = getLocationProviderLocked(name);
if (testProvider == null || !testProvider.isMock()) {
return;
}
@@ -3061,8 +3056,8 @@
removeProviderLocked(testProvider);
// reinstate real provider if available
- LocationProvider realProvider = null;
- for (LocationProvider provider : mRealProviders) {
+ LocationProviderManager realProvider = null;
+ for (LocationProviderManager provider : mRealProviders) {
if (name.equals(provider.getName())) {
realProvider = provider;
break;
@@ -3086,7 +3081,7 @@
}
synchronized (mLock) {
- LocationProvider testProvider = getLocationProviderLocked(providerName);
+ LocationProviderManager testProvider = getLocationProviderLocked(providerName);
if (testProvider == null || !testProvider.isMock()) {
throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
}
@@ -3110,7 +3105,7 @@
}
synchronized (mLock) {
- LocationProvider testProvider = getLocationProviderLocked(providerName);
+ LocationProviderManager testProvider = getLocationProviderLocked(providerName);
if (testProvider == null || !testProvider.isMock()) {
throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
}
@@ -3128,7 +3123,7 @@
}
synchronized (mLock) {
- LocationProvider testProvider = getLocationProviderLocked(providerName);
+ LocationProviderManager testProvider = getLocationProviderLocked(providerName);
if (testProvider == null || !testProvider.isMock()) {
throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
}
@@ -3237,7 +3232,7 @@
ipw.println("Location Providers:");
ipw.increaseIndent();
- for (LocationProvider provider : mProviders) {
+ for (LocationProviderManager provider : mProviders) {
provider.dumpLocked(fd, ipw, args);
}
ipw.decreaseIndent();
diff --git a/services/core/java/com/android/server/location/LocationSettingsStore.java b/services/core/java/com/android/server/location/LocationSettingsStore.java
index 3d18d4a..f625452 100644
--- a/services/core/java/com/android/server/location/LocationSettingsStore.java
+++ b/services/core/java/com/android/server/location/LocationSettingsStore.java
@@ -34,6 +34,7 @@
import android.text.TextUtils;
import android.util.ArraySet;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.SystemConfig;
@@ -113,6 +114,16 @@
() -> SystemConfig.getInstance().getAllowIgnoreLocationSettings(), handler);
}
+ /** Called when system is ready. */
+ public synchronized void onSystemReady() {
+ mLocationMode.register();
+ mBackgroundThrottleIntervalMs.register();
+ mLocationPackageBlacklist.register();
+ mLocationPackageWhitelist.register();
+ mBackgroundThrottlePackageWhitelist.register();
+ mIgnoreSettingsPackageWhitelist.register();
+ }
+
/**
* Retrieve if location is enabled or not.
*/
@@ -300,13 +311,25 @@
private abstract static class ObservingSetting extends ContentObserver {
private final CopyOnWriteArrayList<UserSettingChangedListener> mListeners;
+ private boolean mRegistered;
- private ObservingSetting(Context context, String settingName, Handler handler) {
+ private ObservingSetting(Handler handler) {
super(handler);
mListeners = new CopyOnWriteArrayList<>();
+ }
+
+ protected boolean isRegistered() {
+ return mRegistered;
+ }
+
+ protected void register(Context context, Uri uri) {
+ if (mRegistered) {
+ return;
+ }
context.getContentResolver().registerContentObserver(
- getUriFor(settingName), false, this, UserHandle.USER_ALL);
+ uri, false, this, UserHandle.USER_ALL);
+ mRegistered = true;
}
public void addListener(UserSettingChangedListener listener) {
@@ -317,8 +340,6 @@
mListeners.remove(listener);
}
- protected abstract Uri getUriFor(String settingName);
-
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
for (UserSettingChangedListener listener : mListeners) {
@@ -333,20 +354,19 @@
private final String mSettingName;
private IntegerSecureSetting(Context context, String settingName, Handler handler) {
- super(context, settingName, handler);
+ super(handler);
mContext = context;
mSettingName = settingName;
}
+ private void register() {
+ register(mContext, Settings.Secure.getUriFor(mSettingName));
+ }
+
public int getValueForUser(int defaultValue, int userId) {
return Settings.Secure.getIntForUser(mContext.getContentResolver(), mSettingName,
defaultValue, userId);
}
-
- @Override
- protected Uri getUriFor(String settingName) {
- return Settings.Secure.getUriFor(settingName);
- }
}
private static class StringListCachedSecureSetting extends ObservingSetting {
@@ -354,31 +374,44 @@
private final Context mContext;
private final String mSettingName;
- private int mCachedUserId = UserHandle.USER_NULL;
+ @GuardedBy("this")
+ private int mCachedUserId;
+ @GuardedBy("this")
private List<String> mCachedValue;
private StringListCachedSecureSetting(Context context, String settingName,
Handler handler) {
- super(context, settingName, handler);
+ super(handler);
mContext = context;
mSettingName = settingName;
+
+ mCachedUserId = UserHandle.USER_NULL;
+ }
+
+ public synchronized void register() {
+ register(mContext, Settings.Secure.getUriFor(mSettingName));
}
public synchronized List<String> getValueForUser(int userId) {
Preconditions.checkArgument(userId != UserHandle.USER_NULL);
+ List<String> value = mCachedValue;
if (userId != mCachedUserId) {
String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(),
mSettingName, userId);
if (TextUtils.isEmpty(setting)) {
- mCachedValue = Collections.emptyList();
+ value = Collections.emptyList();
} else {
- mCachedValue = Arrays.asList(setting.split(","));
+ value = Arrays.asList(setting.split(","));
}
- mCachedUserId = userId;
+
+ if (isRegistered()) {
+ mCachedUserId = userId;
+ mCachedValue = value;
+ }
}
- return mCachedValue;
+ return value;
}
public synchronized void invalidateForUser(int userId) {
@@ -393,11 +426,6 @@
invalidateForUser(userId);
super.onChange(selfChange, uri, userId);
}
-
- @Override
- protected Uri getUriFor(String settingName) {
- return Settings.Secure.getUriFor(settingName);
- }
}
private static class LongGlobalSetting extends ObservingSetting {
@@ -406,20 +434,19 @@
private final String mSettingName;
private LongGlobalSetting(Context context, String settingName, Handler handler) {
- super(context, settingName, handler);
+ super(handler);
mContext = context;
mSettingName = settingName;
}
+ public void register() {
+ register(mContext, Settings.Global.getUriFor(mSettingName));
+ }
+
public long getValue(long defaultValue) {
return Settings.Global.getLong(mContext.getContentResolver(), mSettingName,
defaultValue);
}
-
- @Override
- protected Uri getUriFor(String settingName) {
- return Settings.Global.getUriFor(settingName);
- }
}
private static class StringSetCachedGlobalSetting extends ObservingSetting {
@@ -428,29 +455,42 @@
private final String mSettingName;
private final Supplier<ArraySet<String>> mBaseValuesSupplier;
+ @GuardedBy("this")
private boolean mValid;
+ @GuardedBy("this")
private ArraySet<String> mCachedValue;
private StringSetCachedGlobalSetting(Context context, String settingName,
Supplier<ArraySet<String>> baseValuesSupplier, Handler handler) {
- super(context, settingName, handler);
+ super(handler);
mContext = context;
mSettingName = settingName;
mBaseValuesSupplier = baseValuesSupplier;
+
+ mValid = false;
+ }
+
+ public synchronized void register() {
+ register(mContext, Settings.Global.getUriFor(mSettingName));
}
public synchronized Set<String> getValue() {
+ ArraySet<String> value = mCachedValue;
if (!mValid) {
- mCachedValue = new ArraySet<>(mBaseValuesSupplier.get());
+ value = new ArraySet<>(mBaseValuesSupplier.get());
String setting = Settings.Global.getString(mContext.getContentResolver(),
mSettingName);
if (!TextUtils.isEmpty(setting)) {
- mCachedValue.addAll(Arrays.asList(setting.split(",")));
+ value.addAll(Arrays.asList(setting.split(",")));
}
- mValid = true;
+
+ if (isRegistered()) {
+ mValid = true;
+ mCachedValue = value;
+ }
}
- return mCachedValue;
+ return value;
}
public synchronized void invalidate() {
@@ -463,10 +503,5 @@
invalidate();
super.onChange(selfChange, uri, userId);
}
-
- @Override
- protected Uri getUriFor(String settingName) {
- return Settings.Global.getUriFor(settingName);
- }
}
}
diff --git a/services/core/java/com/android/server/LocationUsageLogger.java b/services/core/java/com/android/server/location/LocationUsageLogger.java
similarity index 72%
rename from services/core/java/com/android/server/LocationUsageLogger.java
rename to services/core/java/com/android/server/location/LocationUsageLogger.java
index a8a3cc4..755438b 100644
--- a/services/core/java/com/android/server/LocationUsageLogger.java
+++ b/services/core/java/com/android/server/location/LocationUsageLogger.java
@@ -14,37 +14,113 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.location;
+
+import static com.android.server.LocationManagerService.TAG;
import android.app.ActivityManager;
import android.location.Geofence;
import android.location.LocationManager;
import android.location.LocationRequest;
-import android.os.SystemClock;
import android.stats.location.LocationStatsEnums;
import android.util.Log;
import android.util.StatsLog;
+import com.android.internal.annotations.GuardedBy;
+
import java.time.Instant;
/**
* Logger for Location API usage logging.
*/
public class LocationUsageLogger {
- private static final String TAG = "LocationUsageLogger";
- private static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
private static final int ONE_SEC_IN_MILLIS = 1000;
private static final int ONE_MINUTE_IN_MILLIS = 60000;
private static final int ONE_HOUR_IN_MILLIS = 3600000;
- private long mLastApiUsageLogHour = 0;
-
- private int mApiUsageLogHourlyCount = 0;
-
private static final int API_USAGE_LOG_HOURLY_CAP = 60;
- private static int providerNameToStatsdEnum(String provider) {
+ @GuardedBy("this")
+ private long mLastApiUsageLogHour = 0;
+ @GuardedBy("this")
+ private int mApiUsageLogHourlyCount = 0;
+
+ /**
+ * Log a location API usage event.
+ */
+ public void logLocationApiUsage(int usageType, int apiInUse,
+ String packageName, LocationRequest locationRequest,
+ boolean hasListener, boolean hasIntent,
+ Geofence geofence, int activityImportance) {
+ try {
+ if (hitApiUsageLogCap()) {
+ return;
+ }
+
+ boolean isLocationRequestNull = locationRequest == null;
+ boolean isGeofenceNull = geofence == null;
+
+ StatsLog.write(StatsLog.LOCATION_MANAGER_API_USAGE_REPORTED, usageType,
+ apiInUse, packageName,
+ isLocationRequestNull
+ ? LocationStatsEnums.PROVIDER_UNKNOWN
+ : bucketizeProvider(locationRequest.getProvider()),
+ isLocationRequestNull
+ ? LocationStatsEnums.QUALITY_UNKNOWN
+ : locationRequest.getQuality(),
+ isLocationRequestNull
+ ? LocationStatsEnums.INTERVAL_UNKNOWN
+ : bucketizeInterval(locationRequest.getInterval()),
+ isLocationRequestNull
+ ? LocationStatsEnums.DISTANCE_UNKNOWN
+ : bucketizeDistance(
+ locationRequest.getSmallestDisplacement()),
+ isLocationRequestNull ? 0 : locationRequest.getNumUpdates(),
+ // only log expireIn for USAGE_STARTED
+ isLocationRequestNull || usageType == LocationStatsEnums.USAGE_ENDED
+ ? LocationStatsEnums.EXPIRATION_UNKNOWN
+ : bucketizeExpireIn(locationRequest.getExpireIn()),
+ getCallbackType(apiInUse, hasListener, hasIntent),
+ isGeofenceNull
+ ? LocationStatsEnums.RADIUS_UNKNOWN
+ : bucketizeRadius(geofence.getRadius()),
+ categorizeActivityImportance(activityImportance));
+ } catch (Exception e) {
+ // Swallow exceptions to avoid crashing LMS.
+ Log.w(TAG, "Failed to log API usage to statsd.", e);
+ }
+ }
+
+ /**
+ * Log a location API usage event.
+ */
+ public void logLocationApiUsage(int usageType, int apiInUse, String providerName) {
+ try {
+ if (hitApiUsageLogCap()) {
+ return;
+ }
+
+ StatsLog.write(StatsLog.LOCATION_MANAGER_API_USAGE_REPORTED, usageType, apiInUse,
+ /* package_name= */ null,
+ bucketizeProvider(providerName),
+ LocationStatsEnums.QUALITY_UNKNOWN,
+ LocationStatsEnums.INTERVAL_UNKNOWN,
+ LocationStatsEnums.DISTANCE_UNKNOWN,
+ /* numUpdates= */ 0,
+ LocationStatsEnums.EXPIRATION_UNKNOWN,
+ getCallbackType(
+ apiInUse,
+ /* isListenerNull= */ true,
+ /* isIntentNull= */ true),
+ /* bucketizedRadius= */ 0,
+ LocationStatsEnums.IMPORTANCE_UNKNOWN);
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to log API usage to statsd.", e);
+ }
+ }
+
+ private static int bucketizeProvider(String provider) {
if (LocationManager.NETWORK_PROVIDER.equals(provider)) {
return LocationStatsEnums.PROVIDER_NETWORK;
} else if (LocationManager.GPS_PROVIDER.equals(provider)) {
@@ -58,8 +134,7 @@
}
}
- private static int bucketizeIntervalToStatsdEnum(long interval) {
- // LocationManager already converts negative values to 0.
+ private static int bucketizeInterval(long interval) {
if (interval < ONE_SEC_IN_MILLIS) {
return LocationStatsEnums.INTERVAL_BETWEEN_0_SEC_AND_1_SEC;
} else if (interval < ONE_SEC_IN_MILLIS * 5) {
@@ -75,9 +150,8 @@
}
}
- private static int bucketizeSmallestDisplacementToStatsdEnum(float smallestDisplacement) {
- // LocationManager already converts negative values to 0.
- if (smallestDisplacement == 0) {
+ private static int bucketizeDistance(float smallestDisplacement) {
+ if (smallestDisplacement <= 0) {
return LocationStatsEnums.DISTANCE_ZERO;
} else if (smallestDisplacement > 0 && smallestDisplacement <= 100) {
return LocationStatsEnums.DISTANCE_BETWEEN_0_AND_100;
@@ -86,7 +160,7 @@
}
}
- private static int bucketizeRadiusToStatsdEnum(float radius) {
+ private static int bucketizeRadius(float radius) {
if (radius < 0) {
return LocationStatsEnums.RADIUS_NEGATIVE;
} else if (radius < 100) {
@@ -104,14 +178,11 @@
}
}
- private static int getBucketizedExpireIn(long expireAt) {
- if (expireAt == Long.MAX_VALUE) {
+ private static int bucketizeExpireIn(long expireIn) {
+ if (expireIn == Long.MAX_VALUE) {
return LocationStatsEnums.EXPIRATION_NO_EXPIRY;
}
- long elapsedRealtime = SystemClock.elapsedRealtime();
- long expireIn = Math.max(0, expireAt - elapsedRealtime);
-
if (expireIn < 20 * ONE_SEC_IN_MILLIS) {
return LocationStatsEnums.EXPIRATION_BETWEEN_0_AND_20_SEC;
} else if (expireIn < ONE_MINUTE_IN_MILLIS) {
@@ -129,8 +200,8 @@
if (importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
return LocationStatsEnums.IMPORTANCE_TOP;
} else if (importance == ActivityManager
- .RunningAppProcessInfo
- .IMPORTANCE_FOREGROUND_SERVICE) {
+ .RunningAppProcessInfo
+ .IMPORTANCE_FOREGROUND_SERVICE) {
return LocationStatsEnums.IMPORTANCE_FORGROUND_SERVICE;
} else {
return LocationStatsEnums.IMPORTANCE_BACKGROUND;
@@ -154,117 +225,16 @@
}
}
- // Update the hourly count of APIUsage log event.
- // Returns false if hit the hourly log cap.
- private boolean checkApiUsageLogCap() {
- if (D) {
- Log.d(TAG, "checking APIUsage log cap.");
- }
-
+ private synchronized boolean hitApiUsageLogCap() {
long currentHour = Instant.now().toEpochMilli() / ONE_HOUR_IN_MILLIS;
if (currentHour > mLastApiUsageLogHour) {
mLastApiUsageLogHour = currentHour;
mApiUsageLogHourlyCount = 0;
- return true;
+ return false;
} else {
mApiUsageLogHourlyCount = Math.min(
- mApiUsageLogHourlyCount + 1, API_USAGE_LOG_HOURLY_CAP);
- return mApiUsageLogHourlyCount < API_USAGE_LOG_HOURLY_CAP;
- }
- }
-
- /**
- * Log a Location API usage event to Statsd.
- * Logging event is capped at 60 per hour. Usage events exceeding
- * the cap will be dropped by LocationUsageLogger.
- */
- public void logLocationApiUsage(int usageType, int apiInUse,
- String packageName, LocationRequest locationRequest,
- boolean hasListener, boolean hasIntent,
- Geofence geofence, int activityImportance) {
- try {
- if (!checkApiUsageLogCap()) {
- return;
- }
-
- boolean isLocationRequestNull = locationRequest == null;
- boolean isGeofenceNull = geofence == null;
- if (D) {
- Log.d(TAG, "log API Usage to statsd. usageType: " + usageType + ", apiInUse: "
- + apiInUse + ", packageName: " + (packageName == null ? "" : packageName)
- + ", locationRequest: "
- + (isLocationRequestNull ? "" : locationRequest.toString())
- + ", hasListener: " + hasListener
- + ", hasIntent: " + hasIntent
- + ", geofence: "
- + (isGeofenceNull ? "" : geofence.toString())
- + ", importance: " + activityImportance);
- }
-
- StatsLog.write(StatsLog.LOCATION_MANAGER_API_USAGE_REPORTED, usageType,
- apiInUse, packageName,
- isLocationRequestNull
- ? LocationStatsEnums.PROVIDER_UNKNOWN
- : providerNameToStatsdEnum(locationRequest.getProvider()),
- isLocationRequestNull
- ? LocationStatsEnums.QUALITY_UNKNOWN
- : locationRequest.getQuality(),
- isLocationRequestNull
- ? LocationStatsEnums.INTERVAL_UNKNOWN
- : bucketizeIntervalToStatsdEnum(locationRequest.getInterval()),
- isLocationRequestNull
- ? LocationStatsEnums.DISTANCE_UNKNOWN
- : bucketizeSmallestDisplacementToStatsdEnum(
- locationRequest.getSmallestDisplacement()),
- isLocationRequestNull ? 0 : locationRequest.getNumUpdates(),
- // only log expireIn for USAGE_STARTED
- isLocationRequestNull || usageType == LocationStatsEnums.USAGE_ENDED
- ? LocationStatsEnums.EXPIRATION_UNKNOWN
- : getBucketizedExpireIn(locationRequest.getExpireAt()),
- getCallbackType(apiInUse, hasListener, hasIntent),
- isGeofenceNull
- ? LocationStatsEnums.RADIUS_UNKNOWN
- : bucketizeRadiusToStatsdEnum(geofence.getRadius()),
- categorizeActivityImportance(activityImportance));
- } catch (Exception e) {
- // Swallow exceptions to avoid crashing LMS.
- Log.w(TAG, "Failed to log API usage to statsd.", e);
- }
- }
-
- /**
- * Log a Location API usage event to Statsd.
- * Logging event is capped at 60 per hour. Usage events exceeding
- * the cap will be dropped by LocationUsageLogger.
- */
- public void logLocationApiUsage(int usageType, int apiInUse, String providerName) {
- try {
- if (!checkApiUsageLogCap()) {
- return;
- }
-
- if (D) {
- Log.d(TAG, "log API Usage to statsd. usageType: " + usageType + ", apiInUse: "
- + apiInUse + ", providerName: " + providerName);
- }
-
- StatsLog.write(StatsLog.LOCATION_MANAGER_API_USAGE_REPORTED, usageType, apiInUse,
- /* package_name= */ null,
- providerNameToStatsdEnum(providerName),
- LocationStatsEnums.QUALITY_UNKNOWN,
- LocationStatsEnums.INTERVAL_UNKNOWN,
- LocationStatsEnums.DISTANCE_UNKNOWN,
- /* numUpdates= */ 0,
- LocationStatsEnums.EXPIRATION_UNKNOWN,
- getCallbackType(
- apiInUse,
- /* isListenerNull= */ true,
- /* isIntentNull= */ true),
- /* bucketizedRadius= */ 0,
- LocationStatsEnums.IMPORTANCE_UNKNOWN);
- } catch (Exception e) {
- // Swallow exceptions to avoid crashing LMS.
- Log.w(TAG, "Failed to log API usage to statsd.", e);
+ mApiUsageLogHourlyCount + 1, API_USAGE_LOG_HOURLY_CAP);
+ return mApiUsageLogHourlyCount >= API_USAGE_LOG_HOURLY_CAP;
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/GnssManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/GnssManagerServiceTest.java
index 9692c25..8b5444c 100644
--- a/services/tests/servicestests/src/com/android/server/GnssManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/GnssManagerServiceTest.java
@@ -61,6 +61,7 @@
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 org.junit.Before;
import org.junit.Test;