diff options
| -rw-r--r-- | cmds/statsd/src/atoms.proto | 59 | ||||
| -rw-r--r-- | core/proto/android/stats/location/location_enums.proto | 122 | ||||
| -rw-r--r-- | services/core/java/com/android/server/LocationManagerService.java | 92 | ||||
| -rw-r--r-- | services/core/java/com/android/server/LocationUsageLogger.java | 265 |
4 files changed, 537 insertions, 1 deletions
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 2899d49cf179..495a09f2e99a 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -48,6 +48,7 @@ import "frameworks/base/core/proto/android/stats/docsui/docsui_enums.proto"; import "frameworks/base/core/proto/android/stats/enums.proto"; import "frameworks/base/core/proto/android/stats/intelligence/enums.proto"; import "frameworks/base/core/proto/android/stats/launcher/launcher.proto"; +import "frameworks/base/core/proto/android/stats/location/location_enums.proto"; import "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.proto"; import "frameworks/base/core/proto/android/stats/storage/storage_enums.proto"; import "frameworks/base/core/proto/android/stats/style/style_enums.proto"; @@ -301,6 +302,7 @@ message Atom { ContentCaptureServiceEvents content_capture_service_events = 207; ContentCaptureSessionEvents content_capture_session_events = 208; ContentCaptureFlushed content_capture_flushed = 209; + LocationManagerApiUsageReported location_manager_api_usage_reported = 210; } // Pulled events will start at field 10000. @@ -6485,3 +6487,60 @@ message AppOps { // while the app was in the background (only for trusted requests) optional int64 trusted_background_duration_millis = 9; } + +/** + * Location Manager API Usage information(e.g. API under usage, + * API call's parameters). + * Logged from: + * frameworks/base/services/core/java/com/android/server/LocationManagerService.java + */ +message LocationManagerApiUsageReported { + + // Indicating if usage starts or usage ends. + optional android.stats.location.UsageState state = 1; + + // LocationManagerService's API in use. + // We can identify which API from LocationManager is + // invoking current LMS API by the combination of + // API parameter(e.g. is_listener_null, is_intent_null, + // is_location_request_null) + optional android.stats.location.LocationManagerServiceApi api_in_use = 2; + + // Name of the package calling the API. + optional string calling_package_name = 3; + + // Type of the location provider. + optional android.stats.location.ProviderType provider = 4; + + // Quality of the location request + optional android.stats.location.LocationRequestQuality quality = 5; + + // The desired interval for active location updates, in milliseconds. + // Bucketized to reduce cardinality. + optional android.stats.location.LocationRequestIntervalBucket bucketized_interval = 6; + + // Minimum distance between location updates, in meters. + // Bucketized to reduce cardinality. + optional android.stats.location.SmallestDisplacementBucket + bucketized_smallest_displacement = 7; + + // The number of location updates. + optional int64 num_updates = 8; + + // The request expiration time, in millisecond since boot. + // Bucketized to reduce cardinality. + optional android.stats.location.ExpirationBucket + bucketized_expire_in = 9; + + // Type of Callback passed in for this API. + optional android.stats.location.CallbackType callback_type = 10; + + // The radius of the central point of the alert + // region, in meters. Only for API REQUEST_GEOFENCE. + // Bucketized to reduce cardinality. + optional android.stats.location.GeofenceRadiusBucket bucketized_radius = 11; + + // Activity Importance of API caller. + // Categorized to 3 types that are interesting from location's perspective. + optional android.stats.location.ActivityImportance activiy_importance = 12; +} diff --git a/core/proto/android/stats/location/location_enums.proto b/core/proto/android/stats/location/location_enums.proto new file mode 100644 index 000000000000..553c01c5d0dd --- /dev/null +++ b/core/proto/android/stats/location/location_enums.proto @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2019 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. + */ + +syntax = "proto2"; + +package android.stats.location; +option java_outer_classname = "LocationStatsEnums"; + + +// APIs from LocationManagerService +enum LocationManagerServiceApi { + API_UNKNOWN = 0; + API_REQUEST_LOCATION_UPDATES = 1; + API_ADD_GNSS_MEASUREMENTS_LISTENER = 2; + API_REGISTER_GNSS_STATUS_CALLBACK = 3; + API_REQUEST_GEOFENCE = 4; + API_SEND_EXTRA_COMMAND = 5; +} + +enum UsageState { + USAGE_STARTED = 0; + USAGE_ENDED = 1; +} + +// Type of location providers +enum ProviderType { + PROVIDER_UNKNOWN = 0; + PROVIDER_NETWORK = 1; + PROVIDER_GPS = 2; + PROVIDER_PASSIVE = 3; + PROVIDER_FUSED = 4; +} + +// Type of Callback passed in for this API +enum CallbackType { + CALLBACK_UNKNOWN = 0; + // Current API does not need a callback, e.g. sendExtraCommand + CALLBACK_NOT_APPLICABLE = 1; + CALLBACK_LISTENER = 2; + CALLBACK_PENDING_INTENT = 3; +} + +// Possible values for mQuality field in +// frameworks/base/location/java/android/location/LocationRequest.java +enum LocationRequestQuality { + QUALITY_UNKNOWN = 0; + ACCURACY_FINE = 100; + ACCURACY_BLOCK = 102; + ACCURACY_CITY = 104; + POWER_NONE = 200; + POWER_LOW = 201; + POWER_HIGH = 203; +} + +// Bucketized values for interval field in +// frameworks/base/location/java/android/location/LocationRequest.java +enum LocationRequestIntervalBucket { + INTERVAL_UNKNOWN = 0; + INTERVAL_BETWEEN_0_SEC_AND_1_SEC = 1; + INTERVAL_BETWEEN_1_SEC_AND_5_SEC = 2; + INTERVAL_BETWEEN_5_SEC_AND_1_MIN = 3; + INTERVAL_BETWEEN_1_MIN_AND_10_MIN = 4; + INTERVAL_BETWEEN_10_MIN_AND_1_HOUR = 5; + INTERVAL_LARGER_THAN_1_HOUR = 6; +} + +// Bucketized values for small displacement field in +// frameworks/base/location/java/android/location/LocationRequest.java +// Value in meters. +enum SmallestDisplacementBucket { + DISTANCE_UNKNOWN = 0; + DISTANCE_ZERO = 1; + DISTANCE_BETWEEN_0_AND_100 = 2; + DISTANCE_LARGER_THAN_100 = 3; +} + +// Bucketized values for expire_in field in +// frameworks/base/location/java/android/location/LocationRequest.java +enum ExpirationBucket { + EXPIRATION_UNKNOWN = 0; + EXPIRATION_BETWEEN_0_AND_20_SEC = 1; + EXPIRATION_BETWEEN_20_SEC_AND_1_MIN = 2; + EXPIRATION_BETWEEN_1_MIN_AND_10_MIN = 3; + EXPIRATION_BETWEEN_10_MIN_AND_1_HOUR = 4; + EXPIRATION_LARGER_THAN_1_HOUR = 5; + EXPIRATION_NO_EXPIRY = 6; +} + +// Bucketized values for radius field in +// frameworks/base/location/java/android/location/Geofence.java +// Value in meters. +enum GeofenceRadiusBucket { + RADIUS_UNKNOWN = 0; + RADIUS_BETWEEN_0_AND_100 = 1; + RADIUS_BETWEEN_100_AND_200 = 2; + RADIUS_BETWEEN_200_AND_300 = 3; + RADIUS_BETWEEN_300_AND_1000 = 4; + RADIUS_BETWEEN_1000_AND_10000 = 5; + RADIUS_LARGER_THAN_100000 = 6; + RADIUS_NEGATIVE = 7; +} + +// Caller Activity Importance. +enum ActivityImportance { + IMPORTANCE_UNKNOWN = 0; + IMPORTANCE_TOP = 1; + IMPORTANCE_FORGROUND_SERVICE = 2; + IMPORTANCE_BACKGROUND = 3; +} diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index d52fe8170358..ae04f76b95b4 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -82,6 +82,7 @@ import android.os.UserManager; import android.os.WorkSource; import android.os.WorkSource.WorkChain; import android.provider.Settings; +import android.stats.location.LocationStatsEnums; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -269,10 +270,14 @@ public class LocationManagerService extends ILocationManager.Stub { @PowerManager.LocationPowerSaveMode private int mBatterySaverMode; + @GuardedBy("mLock") + private final LocationUsageLogger mLocationUsageLogger; + public LocationManagerService(Context context) { super(); mContext = context; mHandler = FgThread.getHandler(); + mLocationUsageLogger = new LocationUsageLogger(); // Let the package manager query which are the default location // providers as they get certain permissions granted by default. @@ -2346,7 +2351,18 @@ public class LocationManagerService extends ILocationManager.Stub { * Method to be called when a record will no longer be used. */ private void disposeLocked(boolean removeReceiver) { - mRequestStatistics.stopRequesting(mReceiver.mCallerIdentity.mPackageName, mProvider); + String packageName = mReceiver.mCallerIdentity.mPackageName; + mRequestStatistics.stopRequesting(packageName, mProvider); + + mLocationUsageLogger.logLocationApiUsage( + LocationStatsEnums.USAGE_ENDED, + LocationStatsEnums.API_REQUEST_LOCATION_UPDATES, + packageName, + mRealRequest, + mReceiver.isListener(), + mReceiver.isPendingIntent(), + /* radius= */ 0, + mActivityManager.getPackageImportance(packageName)); // remove from mRecordsByProvider ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider); @@ -2521,6 +2537,13 @@ public class LocationManagerService extends ILocationManager.Stub { "cannot register both listener and intent"); } + mLocationUsageLogger.logLocationApiUsage( + LocationStatsEnums.USAGE_STARTED, + LocationStatsEnums.API_REQUEST_LOCATION_UPDATES, + packageName, request, listener != null, intent != null, + /* radius= */ 0, + mActivityManager.getPackageImportance(packageName)); + Receiver receiver; if (intent != null) { receiver = getReceiverLocked(intent, pid, uid, packageName, workSource, @@ -2813,6 +2836,18 @@ public class LocationManagerService extends ILocationManager.Stub { } long identity = Binder.clearCallingIdentity(); try { + synchronized (mLock) { + mLocationUsageLogger.logLocationApiUsage( + LocationStatsEnums.USAGE_STARTED, + LocationStatsEnums.API_REQUEST_GEOFENCE, + packageName, + request, + /* hasListener= */ false, + intent != null, + geofence.getRadius(), + mActivityManager.getPackageImportance(packageName)); + } + mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel, uid, packageName); @@ -2833,6 +2868,17 @@ public class LocationManagerService extends ILocationManager.Stub { // 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, + intent != null, + geofence.getRadius(), + mActivityManager.getPackageImportance(packageName)); + } mGeofenceManager.removeFence(geofence, intent); } finally { Binder.restoreCallingIdentity(identity); @@ -2916,6 +2962,20 @@ public class LocationManagerService extends ILocationManager.Stub { gnssDataListeners.put(binder, linkedListener); long identity = Binder.clearCallingIdentity(); try { + if (gnssDataProvider == mGnssNavigationMessageProvider + || gnssDataProvider == mGnssStatusProvider) { + mLocationUsageLogger.logLocationApiUsage( + LocationStatsEnums.USAGE_STARTED, + gnssDataProvider == mGnssNavigationMessageProvider + ? LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER + : LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK, + packageName, + /* LocationRequest= */ null, + /* hasListener= */ true, + /* hasIntent= */ false, + /* radius */ 0, + mActivityManager.getPackageImportance(packageName)); + } if (isThrottlingExemptLocked(callerIdentity) || isImportanceForeground( mActivityManager.getPackageImportance(packageName))) { @@ -2941,6 +3001,26 @@ public class LocationManagerService extends ILocationManager.Stub { if (linkedListener == null) { return; } + long identity = Binder.clearCallingIdentity(); + try { + if (gnssDataProvider == mGnssNavigationMessageProvider + || gnssDataProvider == mGnssStatusProvider) { + mLocationUsageLogger.logLocationApiUsage( + LocationStatsEnums.USAGE_ENDED, + gnssDataProvider == mGnssNavigationMessageProvider + ? LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER + : LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK, + linkedListener.mCallerIdentity.mPackageName, + /* LocationRequest= */ null, + /* hasListener= */ true, + /* hasIntent= */ false, + /* radius= */ 0, + mActivityManager.getPackageImportance( + linkedListener.mCallerIdentity.mPackageName)); + } + } finally { + Binder.restoreCallingIdentity(identity); + } unlinkFromListenerDeathNotificationLocked(binder, linkedListener); gnssDataProvider.removeListener(listener); } @@ -3026,6 +3106,11 @@ public class LocationManagerService extends ILocationManager.Stub { checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(), providerName); + mLocationUsageLogger.logLocationApiUsage( + LocationStatsEnums.USAGE_STARTED, + LocationStatsEnums.API_SEND_EXTRA_COMMAND, + providerName); + // and check for ACCESS_LOCATION_EXTRA_COMMANDS if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS) != PERMISSION_GRANTED)) { @@ -3037,6 +3122,11 @@ public class LocationManagerService extends ILocationManager.Stub { provider.sendExtraCommandLocked(command, extras); } + mLocationUsageLogger.logLocationApiUsage( + LocationStatsEnums.USAGE_ENDED, + LocationStatsEnums.API_SEND_EXTRA_COMMAND, + providerName); + return true; } } diff --git a/services/core/java/com/android/server/LocationUsageLogger.java b/services/core/java/com/android/server/LocationUsageLogger.java new file mode 100644 index 000000000000..c5030351f69d --- /dev/null +++ b/services/core/java/com/android/server/LocationUsageLogger.java @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2019 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; + +import android.app.ActivityManager; +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 java.time.Instant; + +/** + * Logger for Location API usage logging. + */ +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) { + if (LocationManager.NETWORK_PROVIDER.equals(provider)) { + return LocationStatsEnums.PROVIDER_NETWORK; + } else if (LocationManager.GPS_PROVIDER.equals(provider)) { + return LocationStatsEnums.PROVIDER_GPS; + } else if (LocationManager.PASSIVE_PROVIDER.equals(provider)) { + return LocationStatsEnums.PROVIDER_PASSIVE; + } else if (LocationManager.FUSED_PROVIDER.equals(provider)) { + return LocationStatsEnums.PROVIDER_FUSED; + } else { + return LocationStatsEnums.PROVIDER_UNKNOWN; + } + } + + private static int bucketizeIntervalToStatsdEnum(long interval) { + // LocationManager already converts negative values to 0. + if (interval < ONE_SEC_IN_MILLIS) { + return LocationStatsEnums.INTERVAL_BETWEEN_0_SEC_AND_1_SEC; + } else if (interval < ONE_SEC_IN_MILLIS * 5) { + return LocationStatsEnums.INTERVAL_BETWEEN_1_SEC_AND_5_SEC; + } else if (interval < ONE_MINUTE_IN_MILLIS) { + return LocationStatsEnums.INTERVAL_BETWEEN_5_SEC_AND_1_MIN; + } else if (interval < ONE_MINUTE_IN_MILLIS * 10) { + return LocationStatsEnums.INTERVAL_BETWEEN_1_MIN_AND_10_MIN; + } else if (interval < ONE_HOUR_IN_MILLIS) { + return LocationStatsEnums.INTERVAL_BETWEEN_10_MIN_AND_1_HOUR; + } else { + return LocationStatsEnums.INTERVAL_LARGER_THAN_1_HOUR; + } + } + + private static int bucketizeSmallestDisplacementToStatsdEnum(float smallestDisplacement) { + // LocationManager already converts negative values to 0. + if (smallestDisplacement == 0) { + return LocationStatsEnums.DISTANCE_ZERO; + } else if (smallestDisplacement > 0 && smallestDisplacement <= 100) { + return LocationStatsEnums.DISTANCE_BETWEEN_0_AND_100; + } else { + return LocationStatsEnums.DISTANCE_LARGER_THAN_100; + } + } + + private static int bucketizeRadiusToStatsdEnum(float radius) { + if (radius < 0) { + return LocationStatsEnums.RADIUS_NEGATIVE; + } else if (radius < 100) { + return LocationStatsEnums.RADIUS_BETWEEN_0_AND_100; + } else if (radius < 200) { + return LocationStatsEnums.RADIUS_BETWEEN_100_AND_200; + } else if (radius < 300) { + return LocationStatsEnums.RADIUS_BETWEEN_200_AND_300; + } else if (radius < 1000) { + return LocationStatsEnums.RADIUS_BETWEEN_300_AND_1000; + } else if (radius < 10000) { + return LocationStatsEnums.RADIUS_BETWEEN_1000_AND_10000; + } else { + return LocationStatsEnums.RADIUS_LARGER_THAN_100000; + } + } + + private static int getBucketizedExpireIn(long expireAt) { + if (expireAt == 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) { + return LocationStatsEnums.EXPIRATION_BETWEEN_20_SEC_AND_1_MIN; + } else if (expireIn < ONE_MINUTE_IN_MILLIS * 10) { + return LocationStatsEnums.EXPIRATION_BETWEEN_1_MIN_AND_10_MIN; + } else if (expireIn < ONE_HOUR_IN_MILLIS) { + return LocationStatsEnums.EXPIRATION_BETWEEN_10_MIN_AND_1_HOUR; + } else { + return LocationStatsEnums.EXPIRATION_LARGER_THAN_1_HOUR; + } + } + + private static int categorizeActivityImportance(int importance) { + if (importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { + return LocationStatsEnums.IMPORTANCE_TOP; + } else if (importance == ActivityManager + .RunningAppProcessInfo + .IMPORTANCE_FOREGROUND_SERVICE) { + return LocationStatsEnums.IMPORTANCE_FORGROUND_SERVICE; + } else { + return LocationStatsEnums.IMPORTANCE_BACKGROUND; + } + } + + private static int getCallbackType( + int apiType, boolean hasListener, boolean hasIntent) { + if (apiType == LocationStatsEnums.API_SEND_EXTRA_COMMAND) { + return LocationStatsEnums.CALLBACK_NOT_APPLICABLE; + } + + // Listener and PendingIntent will not be set at + // the same time. + if (hasIntent) { + return LocationStatsEnums.CALLBACK_PENDING_INTENT; + } else if (hasListener) { + return LocationStatsEnums.CALLBACK_LISTENER; + } else { + return LocationStatsEnums.CALLBACK_UNKNOWN; + } + } + + // 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."); + } + + long currentHour = Instant.now().toEpochMilli() / ONE_HOUR_IN_MILLIS; + if (currentHour > mLastApiUsageLogHour) { + mLastApiUsageLogHour = currentHour; + mApiUsageLogHourlyCount = 0; + return true; + } 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, + float radius, int activityImportance) { + try { + if (!checkApiUsageLogCap()) { + return; + } + + boolean isLocationRequestNull = locationRequest == 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 + + ", radius: " + radius + + ", 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), + bucketizeRadiusToStatsdEnum(radius), + 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); + } + } +} |