blob: 93e19df01cf354c171a0e2f331fb6cb220e56a05 [file] [log] [blame]
Hongyi Zhang700137e2019-05-23 21:19:36 -07001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Soonil Nagarkar3f128402019-12-12 08:31:27 -080017package com.android.server.location;
18
19import static com.android.server.LocationManagerService.TAG;
Hongyi Zhang700137e2019-05-23 21:19:36 -070020
21import android.app.ActivityManager;
Hongyi Zhang0e9ea752019-06-09 22:49:25 -070022import android.location.Geofence;
Hongyi Zhang700137e2019-05-23 21:19:36 -070023import android.location.LocationManager;
24import android.location.LocationRequest;
Hongyi Zhang700137e2019-05-23 21:19:36 -070025import android.stats.location.LocationStatsEnums;
26import android.util.Log;
Hongyi Zhang700137e2019-05-23 21:19:36 -070027
Soonil Nagarkar3f128402019-12-12 08:31:27 -080028import com.android.internal.annotations.GuardedBy;
Muhammad Qureshi6f207102020-01-28 10:37:41 -080029import com.android.internal.util.FrameworkStatsLog;
Soonil Nagarkar3f128402019-12-12 08:31:27 -080030
Hongyi Zhang700137e2019-05-23 21:19:36 -070031import java.time.Instant;
32
33/**
34 * Logger for Location API usage logging.
35 */
Sasha Kuznetsovb9f26b42019-10-03 17:30:46 -070036public class LocationUsageLogger {
Hongyi Zhang700137e2019-05-23 21:19:36 -070037
38 private static final int ONE_SEC_IN_MILLIS = 1000;
39 private static final int ONE_MINUTE_IN_MILLIS = 60000;
40 private static final int ONE_HOUR_IN_MILLIS = 3600000;
41
Hongyi Zhang700137e2019-05-23 21:19:36 -070042 private static final int API_USAGE_LOG_HOURLY_CAP = 60;
43
Soonil Nagarkar3f128402019-12-12 08:31:27 -080044 @GuardedBy("this")
45 private long mLastApiUsageLogHour = 0;
46 @GuardedBy("this")
47 private int mApiUsageLogHourlyCount = 0;
48
49 /**
50 * Log a location API usage event.
51 */
52 public void logLocationApiUsage(int usageType, int apiInUse,
53 String packageName, LocationRequest locationRequest,
54 boolean hasListener, boolean hasIntent,
55 Geofence geofence, int activityImportance) {
56 try {
57 if (hitApiUsageLogCap()) {
58 return;
59 }
60
61 boolean isLocationRequestNull = locationRequest == null;
62 boolean isGeofenceNull = geofence == null;
63
Muhammad Qureshi6f207102020-01-28 10:37:41 -080064 FrameworkStatsLog.write(FrameworkStatsLog.LOCATION_MANAGER_API_USAGE_REPORTED,
65 usageType, apiInUse, packageName,
Soonil Nagarkar3f128402019-12-12 08:31:27 -080066 isLocationRequestNull
67 ? LocationStatsEnums.PROVIDER_UNKNOWN
68 : bucketizeProvider(locationRequest.getProvider()),
69 isLocationRequestNull
70 ? LocationStatsEnums.QUALITY_UNKNOWN
71 : locationRequest.getQuality(),
72 isLocationRequestNull
73 ? LocationStatsEnums.INTERVAL_UNKNOWN
74 : bucketizeInterval(locationRequest.getInterval()),
75 isLocationRequestNull
76 ? LocationStatsEnums.DISTANCE_UNKNOWN
77 : bucketizeDistance(
78 locationRequest.getSmallestDisplacement()),
79 isLocationRequestNull ? 0 : locationRequest.getNumUpdates(),
80 // only log expireIn for USAGE_STARTED
81 isLocationRequestNull || usageType == LocationStatsEnums.USAGE_ENDED
82 ? LocationStatsEnums.EXPIRATION_UNKNOWN
83 : bucketizeExpireIn(locationRequest.getExpireIn()),
84 getCallbackType(apiInUse, hasListener, hasIntent),
85 isGeofenceNull
86 ? LocationStatsEnums.RADIUS_UNKNOWN
87 : bucketizeRadius(geofence.getRadius()),
88 categorizeActivityImportance(activityImportance));
89 } catch (Exception e) {
90 // Swallow exceptions to avoid crashing LMS.
91 Log.w(TAG, "Failed to log API usage to statsd.", e);
92 }
93 }
94
95 /**
96 * Log a location API usage event.
97 */
98 public void logLocationApiUsage(int usageType, int apiInUse, String providerName) {
99 try {
100 if (hitApiUsageLogCap()) {
101 return;
102 }
103
Muhammad Qureshi6f207102020-01-28 10:37:41 -0800104 FrameworkStatsLog.write(FrameworkStatsLog.LOCATION_MANAGER_API_USAGE_REPORTED,
105 usageType, apiInUse,
Soonil Nagarkar3f128402019-12-12 08:31:27 -0800106 /* package_name= */ null,
107 bucketizeProvider(providerName),
108 LocationStatsEnums.QUALITY_UNKNOWN,
109 LocationStatsEnums.INTERVAL_UNKNOWN,
110 LocationStatsEnums.DISTANCE_UNKNOWN,
111 /* numUpdates= */ 0,
112 LocationStatsEnums.EXPIRATION_UNKNOWN,
113 getCallbackType(
114 apiInUse,
115 /* isListenerNull= */ true,
116 /* isIntentNull= */ true),
117 /* bucketizedRadius= */ 0,
118 LocationStatsEnums.IMPORTANCE_UNKNOWN);
119 } catch (Exception e) {
120 Log.w(TAG, "Failed to log API usage to statsd.", e);
121 }
122 }
123
124 private static int bucketizeProvider(String provider) {
Hongyi Zhang700137e2019-05-23 21:19:36 -0700125 if (LocationManager.NETWORK_PROVIDER.equals(provider)) {
126 return LocationStatsEnums.PROVIDER_NETWORK;
127 } else if (LocationManager.GPS_PROVIDER.equals(provider)) {
128 return LocationStatsEnums.PROVIDER_GPS;
129 } else if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
130 return LocationStatsEnums.PROVIDER_PASSIVE;
131 } else if (LocationManager.FUSED_PROVIDER.equals(provider)) {
132 return LocationStatsEnums.PROVIDER_FUSED;
133 } else {
134 return LocationStatsEnums.PROVIDER_UNKNOWN;
135 }
136 }
137
Soonil Nagarkar3f128402019-12-12 08:31:27 -0800138 private static int bucketizeInterval(long interval) {
Hongyi Zhang700137e2019-05-23 21:19:36 -0700139 if (interval < ONE_SEC_IN_MILLIS) {
140 return LocationStatsEnums.INTERVAL_BETWEEN_0_SEC_AND_1_SEC;
141 } else if (interval < ONE_SEC_IN_MILLIS * 5) {
142 return LocationStatsEnums.INTERVAL_BETWEEN_1_SEC_AND_5_SEC;
143 } else if (interval < ONE_MINUTE_IN_MILLIS) {
144 return LocationStatsEnums.INTERVAL_BETWEEN_5_SEC_AND_1_MIN;
145 } else if (interval < ONE_MINUTE_IN_MILLIS * 10) {
146 return LocationStatsEnums.INTERVAL_BETWEEN_1_MIN_AND_10_MIN;
147 } else if (interval < ONE_HOUR_IN_MILLIS) {
148 return LocationStatsEnums.INTERVAL_BETWEEN_10_MIN_AND_1_HOUR;
149 } else {
150 return LocationStatsEnums.INTERVAL_LARGER_THAN_1_HOUR;
151 }
152 }
153
Soonil Nagarkar3f128402019-12-12 08:31:27 -0800154 private static int bucketizeDistance(float smallestDisplacement) {
155 if (smallestDisplacement <= 0) {
Hongyi Zhang700137e2019-05-23 21:19:36 -0700156 return LocationStatsEnums.DISTANCE_ZERO;
157 } else if (smallestDisplacement > 0 && smallestDisplacement <= 100) {
158 return LocationStatsEnums.DISTANCE_BETWEEN_0_AND_100;
159 } else {
160 return LocationStatsEnums.DISTANCE_LARGER_THAN_100;
161 }
162 }
163
Soonil Nagarkar3f128402019-12-12 08:31:27 -0800164 private static int bucketizeRadius(float radius) {
Hongyi Zhang700137e2019-05-23 21:19:36 -0700165 if (radius < 0) {
166 return LocationStatsEnums.RADIUS_NEGATIVE;
167 } else if (radius < 100) {
168 return LocationStatsEnums.RADIUS_BETWEEN_0_AND_100;
169 } else if (radius < 200) {
170 return LocationStatsEnums.RADIUS_BETWEEN_100_AND_200;
171 } else if (radius < 300) {
172 return LocationStatsEnums.RADIUS_BETWEEN_200_AND_300;
173 } else if (radius < 1000) {
174 return LocationStatsEnums.RADIUS_BETWEEN_300_AND_1000;
175 } else if (radius < 10000) {
176 return LocationStatsEnums.RADIUS_BETWEEN_1000_AND_10000;
177 } else {
178 return LocationStatsEnums.RADIUS_LARGER_THAN_100000;
179 }
180 }
181
Soonil Nagarkar3f128402019-12-12 08:31:27 -0800182 private static int bucketizeExpireIn(long expireIn) {
183 if (expireIn == Long.MAX_VALUE) {
Hongyi Zhang700137e2019-05-23 21:19:36 -0700184 return LocationStatsEnums.EXPIRATION_NO_EXPIRY;
185 }
186
Hongyi Zhang700137e2019-05-23 21:19:36 -0700187 if (expireIn < 20 * ONE_SEC_IN_MILLIS) {
188 return LocationStatsEnums.EXPIRATION_BETWEEN_0_AND_20_SEC;
189 } else if (expireIn < ONE_MINUTE_IN_MILLIS) {
190 return LocationStatsEnums.EXPIRATION_BETWEEN_20_SEC_AND_1_MIN;
191 } else if (expireIn < ONE_MINUTE_IN_MILLIS * 10) {
192 return LocationStatsEnums.EXPIRATION_BETWEEN_1_MIN_AND_10_MIN;
193 } else if (expireIn < ONE_HOUR_IN_MILLIS) {
194 return LocationStatsEnums.EXPIRATION_BETWEEN_10_MIN_AND_1_HOUR;
195 } else {
196 return LocationStatsEnums.EXPIRATION_LARGER_THAN_1_HOUR;
197 }
198 }
199
200 private static int categorizeActivityImportance(int importance) {
201 if (importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
202 return LocationStatsEnums.IMPORTANCE_TOP;
203 } else if (importance == ActivityManager
Soonil Nagarkar3f128402019-12-12 08:31:27 -0800204 .RunningAppProcessInfo
205 .IMPORTANCE_FOREGROUND_SERVICE) {
Hongyi Zhang700137e2019-05-23 21:19:36 -0700206 return LocationStatsEnums.IMPORTANCE_FORGROUND_SERVICE;
207 } else {
208 return LocationStatsEnums.IMPORTANCE_BACKGROUND;
209 }
210 }
211
212 private static int getCallbackType(
213 int apiType, boolean hasListener, boolean hasIntent) {
214 if (apiType == LocationStatsEnums.API_SEND_EXTRA_COMMAND) {
215 return LocationStatsEnums.CALLBACK_NOT_APPLICABLE;
216 }
217
218 // Listener and PendingIntent will not be set at
219 // the same time.
220 if (hasIntent) {
221 return LocationStatsEnums.CALLBACK_PENDING_INTENT;
222 } else if (hasListener) {
223 return LocationStatsEnums.CALLBACK_LISTENER;
224 } else {
225 return LocationStatsEnums.CALLBACK_UNKNOWN;
226 }
227 }
228
Soonil Nagarkar3f128402019-12-12 08:31:27 -0800229 private synchronized boolean hitApiUsageLogCap() {
Hongyi Zhang700137e2019-05-23 21:19:36 -0700230 long currentHour = Instant.now().toEpochMilli() / ONE_HOUR_IN_MILLIS;
231 if (currentHour > mLastApiUsageLogHour) {
232 mLastApiUsageLogHour = currentHour;
233 mApiUsageLogHourlyCount = 0;
Soonil Nagarkar3f128402019-12-12 08:31:27 -0800234 return false;
Hongyi Zhang700137e2019-05-23 21:19:36 -0700235 } else {
236 mApiUsageLogHourlyCount = Math.min(
Soonil Nagarkar3f128402019-12-12 08:31:27 -0800237 mApiUsageLogHourlyCount + 1, API_USAGE_LOG_HOURLY_CAP);
238 return mApiUsageLogHourlyCount >= API_USAGE_LOG_HOURLY_CAP;
Hongyi Zhang700137e2019-05-23 21:19:36 -0700239 }
240 }
241}