1 /* 2 * Copyright (C) 2021 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 17 package com.android.server.location.eventlog; 18 19 import static android.os.PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF; 20 import static android.os.PowerManager.LOCATION_MODE_FOREGROUND_ONLY; 21 import static android.os.PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF; 22 import static android.os.PowerManager.LOCATION_MODE_NO_CHANGE; 23 import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF; 24 import static android.util.TimeUtils.formatDuration; 25 26 import static com.android.server.location.LocationManagerService.D; 27 28 import static java.lang.Math.max; 29 import static java.lang.Math.min; 30 import static java.util.concurrent.TimeUnit.MILLISECONDS; 31 32 import android.annotation.Nullable; 33 import android.location.LocationRequest; 34 import android.location.provider.ProviderRequest; 35 import android.location.util.identity.CallerIdentity; 36 import android.os.PowerManager.LocationPowerSaveMode; 37 import android.os.SystemClock; 38 import android.util.ArrayMap; 39 40 import com.android.internal.annotations.GuardedBy; 41 import com.android.internal.util.Preconditions; 42 43 /** In memory event log for location events. */ 44 public class LocationEventLog extends LocalEventLog { 45 46 public static final LocationEventLog EVENT_LOG = new LocationEventLog(); 47 getLogSize()48 private static int getLogSize() { 49 if (D) { 50 return 600; 51 } else { 52 return 200; 53 } 54 } 55 56 private static final int EVENT_USER_SWITCHED = 1; 57 private static final int EVENT_LOCATION_ENABLED = 2; 58 private static final int EVENT_ADAS_LOCATION_ENABLED = 3; 59 private static final int EVENT_PROVIDER_ENABLED = 4; 60 private static final int EVENT_PROVIDER_MOCKED = 5; 61 private static final int EVENT_PROVIDER_CLIENT_REGISTER = 6; 62 private static final int EVENT_PROVIDER_CLIENT_UNREGISTER = 7; 63 private static final int EVENT_PROVIDER_CLIENT_FOREGROUND = 8; 64 private static final int EVENT_PROVIDER_CLIENT_BACKGROUND = 9; 65 private static final int EVENT_PROVIDER_CLIENT_PERMITTED = 10; 66 private static final int EVENT_PROVIDER_CLIENT_UNPERMITTED = 11; 67 private static final int EVENT_PROVIDER_UPDATE_REQUEST = 12; 68 private static final int EVENT_PROVIDER_RECEIVE_LOCATION = 13; 69 private static final int EVENT_PROVIDER_DELIVER_LOCATION = 14; 70 private static final int EVENT_PROVIDER_STATIONARY_THROTTLED = 15; 71 private static final int EVENT_LOCATION_POWER_SAVE_MODE_CHANGE = 16; 72 73 @GuardedBy("mAggregateStats") 74 private final ArrayMap<String, ArrayMap<CallerIdentity, AggregateStats>> mAggregateStats; 75 LocationEventLog()76 public LocationEventLog() { 77 super(getLogSize()); 78 mAggregateStats = new ArrayMap<>(4); 79 } 80 81 /** Copies out all aggregated stats. */ copyAggregateStats()82 public ArrayMap<String, ArrayMap<CallerIdentity, AggregateStats>> copyAggregateStats() { 83 synchronized (mAggregateStats) { 84 ArrayMap<String, ArrayMap<CallerIdentity, AggregateStats>> copy = new ArrayMap<>( 85 mAggregateStats); 86 for (int i = 0; i < copy.size(); i++) { 87 copy.setValueAt(i, new ArrayMap<>(copy.valueAt(i))); 88 } 89 return copy; 90 } 91 } 92 getAggregateStats(String provider, CallerIdentity identity)93 private AggregateStats getAggregateStats(String provider, CallerIdentity identity) { 94 synchronized (mAggregateStats) { 95 ArrayMap<CallerIdentity, AggregateStats> packageMap = mAggregateStats.get(provider); 96 if (packageMap == null) { 97 packageMap = new ArrayMap<>(2); 98 mAggregateStats.put(provider, packageMap); 99 } 100 CallerIdentity aggregate = CallerIdentity.forAggregation(identity); 101 AggregateStats stats = packageMap.get(aggregate); 102 if (stats == null) { 103 stats = new AggregateStats(); 104 packageMap.put(aggregate, stats); 105 } 106 return stats; 107 } 108 } 109 110 /** Logs a user switched event. */ logUserSwitched(int userIdFrom, int userIdTo)111 public void logUserSwitched(int userIdFrom, int userIdTo) { 112 addLogEvent(EVENT_USER_SWITCHED, userIdFrom, userIdTo); 113 } 114 115 /** Logs a location enabled/disabled event. */ logLocationEnabled(int userId, boolean enabled)116 public void logLocationEnabled(int userId, boolean enabled) { 117 addLogEvent(EVENT_LOCATION_ENABLED, userId, enabled); 118 } 119 120 /** Logs a location enabled/disabled event. */ logAdasLocationEnabled(int userId, boolean enabled)121 public void logAdasLocationEnabled(int userId, boolean enabled) { 122 addLogEvent(EVENT_ADAS_LOCATION_ENABLED, userId, enabled); 123 } 124 125 /** Logs a location provider enabled/disabled event. */ logProviderEnabled(String provider, int userId, boolean enabled)126 public void logProviderEnabled(String provider, int userId, boolean enabled) { 127 addLogEvent(EVENT_PROVIDER_ENABLED, provider, userId, enabled); 128 } 129 130 /** Logs a location provider being replaced/unreplaced by a mock provider. */ logProviderMocked(String provider, boolean mocked)131 public void logProviderMocked(String provider, boolean mocked) { 132 addLogEvent(EVENT_PROVIDER_MOCKED, provider, mocked); 133 } 134 135 /** Logs a new client registration for a location provider. */ logProviderClientRegistered(String provider, CallerIdentity identity, LocationRequest request)136 public void logProviderClientRegistered(String provider, CallerIdentity identity, 137 LocationRequest request) { 138 addLogEvent(EVENT_PROVIDER_CLIENT_REGISTER, provider, identity, request); 139 getAggregateStats(provider, identity).markRequestAdded(request.getIntervalMillis()); 140 } 141 142 /** Logs a client unregistration for a location provider. */ logProviderClientUnregistered(String provider, CallerIdentity identity)143 public void logProviderClientUnregistered(String provider, CallerIdentity identity) { 144 addLogEvent(EVENT_PROVIDER_CLIENT_UNREGISTER, provider, identity); 145 getAggregateStats(provider, identity).markRequestRemoved(); 146 } 147 148 /** Logs a client for a location provider entering the active state. */ logProviderClientActive(String provider, CallerIdentity identity)149 public void logProviderClientActive(String provider, CallerIdentity identity) { 150 getAggregateStats(provider, identity).markRequestActive(); 151 } 152 153 /** Logs a client for a location provider leaving the active state. */ logProviderClientInactive(String provider, CallerIdentity identity)154 public void logProviderClientInactive(String provider, CallerIdentity identity) { 155 getAggregateStats(provider, identity).markRequestInactive(); 156 } 157 158 /** Logs a client for a location provider entering the foreground state. */ logProviderClientForeground(String provider, CallerIdentity identity)159 public void logProviderClientForeground(String provider, CallerIdentity identity) { 160 if (D) { 161 addLogEvent(EVENT_PROVIDER_CLIENT_FOREGROUND, provider, identity); 162 } 163 getAggregateStats(provider, identity).markRequestForeground(); 164 } 165 166 /** Logs a client for a location provider leaving the foreground state. */ logProviderClientBackground(String provider, CallerIdentity identity)167 public void logProviderClientBackground(String provider, CallerIdentity identity) { 168 if (D) { 169 addLogEvent(EVENT_PROVIDER_CLIENT_BACKGROUND, provider, identity); 170 } 171 getAggregateStats(provider, identity).markRequestBackground(); 172 } 173 174 /** Logs a client for a location provider entering the permitted state. */ logProviderClientPermitted(String provider, CallerIdentity identity)175 public void logProviderClientPermitted(String provider, CallerIdentity identity) { 176 if (D) { 177 addLogEvent(EVENT_PROVIDER_CLIENT_PERMITTED, provider, identity); 178 } 179 } 180 181 /** Logs a client for a location provider leaving the permitted state. */ logProviderClientUnpermitted(String provider, CallerIdentity identity)182 public void logProviderClientUnpermitted(String provider, CallerIdentity identity) { 183 if (D) { 184 addLogEvent(EVENT_PROVIDER_CLIENT_UNPERMITTED, provider, identity); 185 } 186 } 187 188 /** Logs a change to the provider request for a location provider. */ logProviderUpdateRequest(String provider, ProviderRequest request)189 public void logProviderUpdateRequest(String provider, ProviderRequest request) { 190 addLogEvent(EVENT_PROVIDER_UPDATE_REQUEST, provider, request); 191 } 192 193 /** Logs a new incoming location for a location provider. */ logProviderReceivedLocations(String provider, int numLocations)194 public void logProviderReceivedLocations(String provider, int numLocations) { 195 addLogEvent(EVENT_PROVIDER_RECEIVE_LOCATION, provider, numLocations); 196 } 197 198 /** Logs a location deliver for a client of a location provider. */ logProviderDeliveredLocations(String provider, int numLocations, CallerIdentity identity)199 public void logProviderDeliveredLocations(String provider, int numLocations, 200 CallerIdentity identity) { 201 if (D) { 202 addLogEvent(EVENT_PROVIDER_DELIVER_LOCATION, provider, numLocations, identity); 203 } 204 getAggregateStats(provider, identity).markLocationDelivered(); 205 } 206 207 /** Logs that a provider has entered or exited stationary throttling. */ logProviderStationaryThrottled(String provider, boolean throttled, ProviderRequest request)208 public void logProviderStationaryThrottled(String provider, boolean throttled, 209 ProviderRequest request) { 210 addLogEvent(EVENT_PROVIDER_STATIONARY_THROTTLED, provider, throttled, request); 211 } 212 213 /** Logs that the location power save mode has changed. */ logLocationPowerSaveMode( @ocationPowerSaveMode int locationPowerSaveMode)214 public void logLocationPowerSaveMode( 215 @LocationPowerSaveMode int locationPowerSaveMode) { 216 addLogEvent(EVENT_LOCATION_POWER_SAVE_MODE_CHANGE, locationPowerSaveMode); 217 } 218 219 @Override createLogEvent(long timeDelta, int event, Object... args)220 protected LogEvent createLogEvent(long timeDelta, int event, Object... args) { 221 switch (event) { 222 case EVENT_USER_SWITCHED: 223 return new UserSwitchedEvent(timeDelta, (Integer) args[0], (Integer) args[1]); 224 case EVENT_LOCATION_ENABLED: 225 return new LocationEnabledEvent(timeDelta, (Integer) args[0], (Boolean) args[1]); 226 case EVENT_ADAS_LOCATION_ENABLED: 227 return new LocationAdasEnabledEvent(timeDelta, (Integer) args[0], 228 (Boolean) args[1]); 229 case EVENT_PROVIDER_ENABLED: 230 return new ProviderEnabledEvent(timeDelta, (String) args[0], (Integer) args[1], 231 (Boolean) args[2]); 232 case EVENT_PROVIDER_MOCKED: 233 return new ProviderMockedEvent(timeDelta, (String) args[0], (Boolean) args[1]); 234 case EVENT_PROVIDER_CLIENT_REGISTER: 235 return new ProviderClientRegisterEvent(timeDelta, (String) args[0], true, 236 (CallerIdentity) args[1], (LocationRequest) args[2]); 237 case EVENT_PROVIDER_CLIENT_UNREGISTER: 238 return new ProviderClientRegisterEvent(timeDelta, (String) args[0], false, 239 (CallerIdentity) args[1], null); 240 case EVENT_PROVIDER_CLIENT_FOREGROUND: 241 return new ProviderClientForegroundEvent(timeDelta, (String) args[0], true, 242 (CallerIdentity) args[1]); 243 case EVENT_PROVIDER_CLIENT_BACKGROUND: 244 return new ProviderClientForegroundEvent(timeDelta, (String) args[0], false, 245 (CallerIdentity) args[1]); 246 case EVENT_PROVIDER_CLIENT_PERMITTED: 247 return new ProviderClientPermittedEvent(timeDelta, (String) args[0], true, 248 (CallerIdentity) args[1]); 249 case EVENT_PROVIDER_CLIENT_UNPERMITTED: 250 return new ProviderClientPermittedEvent(timeDelta, (String) args[0], false, 251 (CallerIdentity) args[1]); 252 case EVENT_PROVIDER_UPDATE_REQUEST: 253 return new ProviderUpdateEvent(timeDelta, (String) args[0], 254 (ProviderRequest) args[1]); 255 case EVENT_PROVIDER_RECEIVE_LOCATION: 256 return new ProviderReceiveLocationEvent(timeDelta, (String) args[0], 257 (Integer) args[1]); 258 case EVENT_PROVIDER_DELIVER_LOCATION: 259 return new ProviderDeliverLocationEvent(timeDelta, (String) args[0], 260 (Integer) args[1], (CallerIdentity) args[2]); 261 case EVENT_PROVIDER_STATIONARY_THROTTLED: 262 return new ProviderStationaryThrottledEvent(timeDelta, (String) args[0], 263 (Boolean) args[1], (ProviderRequest) args[2]); 264 case EVENT_LOCATION_POWER_SAVE_MODE_CHANGE: 265 return new LocationPowerSaveModeEvent(timeDelta, (Integer) args[0]); 266 default: 267 throw new AssertionError(); 268 } 269 } 270 271 private abstract static class ProviderEvent extends LogEvent { 272 273 protected final String mProvider; 274 ProviderEvent(long timeDelta, String provider)275 ProviderEvent(long timeDelta, String provider) { 276 super(timeDelta); 277 mProvider = provider; 278 } 279 280 @Override filter(String filter)281 public boolean filter(String filter) { 282 return mProvider.equals(filter); 283 } 284 } 285 286 private static final class ProviderEnabledEvent extends ProviderEvent { 287 288 private final int mUserId; 289 private final boolean mEnabled; 290 ProviderEnabledEvent(long timeDelta, String provider, int userId, boolean enabled)291 ProviderEnabledEvent(long timeDelta, String provider, int userId, 292 boolean enabled) { 293 super(timeDelta, provider); 294 mUserId = userId; 295 mEnabled = enabled; 296 } 297 298 @Override getLogString()299 public String getLogString() { 300 return mProvider + " provider [u" + mUserId + "] " + (mEnabled ? "enabled" 301 : "disabled"); 302 } 303 } 304 305 private static final class ProviderMockedEvent extends ProviderEvent { 306 307 private final boolean mMocked; 308 ProviderMockedEvent(long timeDelta, String provider, boolean mocked)309 ProviderMockedEvent(long timeDelta, String provider, boolean mocked) { 310 super(timeDelta, provider); 311 mMocked = mocked; 312 } 313 314 @Override getLogString()315 public String getLogString() { 316 if (mMocked) { 317 return mProvider + " provider added mock provider override"; 318 } else { 319 return mProvider + " provider removed mock provider override"; 320 } 321 } 322 } 323 324 private static final class ProviderClientRegisterEvent extends ProviderEvent { 325 326 private final boolean mRegistered; 327 private final CallerIdentity mIdentity; 328 @Nullable private final LocationRequest mLocationRequest; 329 ProviderClientRegisterEvent(long timeDelta, String provider, boolean registered, CallerIdentity identity, @Nullable LocationRequest locationRequest)330 ProviderClientRegisterEvent(long timeDelta, String provider, boolean registered, 331 CallerIdentity identity, @Nullable LocationRequest locationRequest) { 332 super(timeDelta, provider); 333 mRegistered = registered; 334 mIdentity = identity; 335 mLocationRequest = locationRequest; 336 } 337 338 @Override getLogString()339 public String getLogString() { 340 if (mRegistered) { 341 return mProvider + " provider +registration " + mIdentity + " -> " 342 + mLocationRequest; 343 } else { 344 return mProvider + " provider -registration " + mIdentity; 345 } 346 } 347 } 348 349 private static final class ProviderClientForegroundEvent extends ProviderEvent { 350 351 private final boolean mForeground; 352 private final CallerIdentity mIdentity; 353 ProviderClientForegroundEvent(long timeDelta, String provider, boolean foreground, CallerIdentity identity)354 ProviderClientForegroundEvent(long timeDelta, String provider, boolean foreground, 355 CallerIdentity identity) { 356 super(timeDelta, provider); 357 mForeground = foreground; 358 mIdentity = identity; 359 } 360 361 @Override getLogString()362 public String getLogString() { 363 return mProvider + " provider client " + mIdentity + " -> " 364 + (mForeground ? "foreground" : "background"); 365 } 366 } 367 368 private static final class ProviderClientPermittedEvent extends ProviderEvent { 369 370 private final boolean mPermitted; 371 private final CallerIdentity mIdentity; 372 ProviderClientPermittedEvent(long timeDelta, String provider, boolean permitted, CallerIdentity identity)373 ProviderClientPermittedEvent(long timeDelta, String provider, boolean permitted, 374 CallerIdentity identity) { 375 super(timeDelta, provider); 376 mPermitted = permitted; 377 mIdentity = identity; 378 } 379 380 @Override getLogString()381 public String getLogString() { 382 return mProvider + " provider client " + mIdentity + " -> " 383 + (mPermitted ? "permitted" : "unpermitted"); 384 } 385 } 386 387 private static final class ProviderUpdateEvent extends ProviderEvent { 388 389 private final ProviderRequest mRequest; 390 ProviderUpdateEvent(long timeDelta, String provider, ProviderRequest request)391 ProviderUpdateEvent(long timeDelta, String provider, ProviderRequest request) { 392 super(timeDelta, provider); 393 mRequest = request; 394 } 395 396 @Override getLogString()397 public String getLogString() { 398 return mProvider + " provider request = " + mRequest; 399 } 400 } 401 402 private static final class ProviderReceiveLocationEvent extends ProviderEvent { 403 404 private final int mNumLocations; 405 ProviderReceiveLocationEvent(long timeDelta, String provider, int numLocations)406 ProviderReceiveLocationEvent(long timeDelta, String provider, int numLocations) { 407 super(timeDelta, provider); 408 mNumLocations = numLocations; 409 } 410 411 @Override getLogString()412 public String getLogString() { 413 return mProvider + " provider received location[" + mNumLocations + "]"; 414 } 415 } 416 417 private static final class ProviderDeliverLocationEvent extends ProviderEvent { 418 419 private final int mNumLocations; 420 @Nullable private final CallerIdentity mIdentity; 421 ProviderDeliverLocationEvent(long timeDelta, String provider, int numLocations, @Nullable CallerIdentity identity)422 ProviderDeliverLocationEvent(long timeDelta, String provider, int numLocations, 423 @Nullable CallerIdentity identity) { 424 super(timeDelta, provider); 425 mNumLocations = numLocations; 426 mIdentity = identity; 427 } 428 429 @Override getLogString()430 public String getLogString() { 431 return mProvider + " provider delivered location[" + mNumLocations + "] to " 432 + mIdentity; 433 } 434 } 435 436 private static final class ProviderStationaryThrottledEvent extends ProviderEvent { 437 438 private final boolean mStationaryThrottled; 439 private final ProviderRequest mRequest; 440 ProviderStationaryThrottledEvent(long timeDelta, String provider, boolean stationaryThrottled, ProviderRequest request)441 ProviderStationaryThrottledEvent(long timeDelta, String provider, 442 boolean stationaryThrottled, ProviderRequest request) { 443 super(timeDelta, provider); 444 mStationaryThrottled = stationaryThrottled; 445 mRequest = request; 446 } 447 448 @Override getLogString()449 public String getLogString() { 450 return mProvider + " provider stationary/idle " + (mStationaryThrottled ? "throttled" 451 : "unthrottled") + ", request = " + mRequest; 452 } 453 } 454 455 private static final class LocationPowerSaveModeEvent extends LogEvent { 456 457 @LocationPowerSaveMode 458 private final int mLocationPowerSaveMode; 459 LocationPowerSaveModeEvent(long timeDelta, @LocationPowerSaveMode int locationPowerSaveMode)460 LocationPowerSaveModeEvent(long timeDelta, 461 @LocationPowerSaveMode int locationPowerSaveMode) { 462 super(timeDelta); 463 mLocationPowerSaveMode = locationPowerSaveMode; 464 } 465 466 @Override getLogString()467 public String getLogString() { 468 String mode; 469 switch (mLocationPowerSaveMode) { 470 case LOCATION_MODE_NO_CHANGE: 471 mode = "NO_CHANGE"; 472 break; 473 case LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF: 474 mode = "GPS_DISABLED_WHEN_SCREEN_OFF"; 475 break; 476 case LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF: 477 mode = "ALL_DISABLED_WHEN_SCREEN_OFF"; 478 break; 479 case LOCATION_MODE_FOREGROUND_ONLY: 480 mode = "FOREGROUND_ONLY"; 481 break; 482 case LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF: 483 mode = "THROTTLE_REQUESTS_WHEN_SCREEN_OFF"; 484 break; 485 default: 486 mode = "UNKNOWN"; 487 break; 488 } 489 return "location power save mode changed to " + mode; 490 } 491 } 492 493 private static final class UserSwitchedEvent extends LogEvent { 494 495 private final int mUserIdFrom; 496 private final int mUserIdTo; 497 UserSwitchedEvent(long timeDelta, int userIdFrom, int userIdTo)498 UserSwitchedEvent(long timeDelta, int userIdFrom, int userIdTo) { 499 super(timeDelta); 500 mUserIdFrom = userIdFrom; 501 mUserIdTo = userIdTo; 502 } 503 504 @Override getLogString()505 public String getLogString() { 506 return "current user switched from u" + mUserIdFrom + " to u" + mUserIdTo; 507 } 508 } 509 510 private static final class LocationEnabledEvent extends LogEvent { 511 512 private final int mUserId; 513 private final boolean mEnabled; 514 LocationEnabledEvent(long timeDelta, int userId, boolean enabled)515 LocationEnabledEvent(long timeDelta, int userId, boolean enabled) { 516 super(timeDelta); 517 mUserId = userId; 518 mEnabled = enabled; 519 } 520 521 @Override getLogString()522 public String getLogString() { 523 return "location [u" + mUserId + "] " + (mEnabled ? "enabled" : "disabled"); 524 } 525 } 526 527 private static final class LocationAdasEnabledEvent extends LogEvent { 528 529 private final int mUserId; 530 private final boolean mEnabled; 531 LocationAdasEnabledEvent(long timeDelta, int userId, boolean enabled)532 LocationAdasEnabledEvent(long timeDelta, int userId, boolean enabled) { 533 super(timeDelta); 534 mUserId = userId; 535 mEnabled = enabled; 536 } 537 538 @Override getLogString()539 public String getLogString() { 540 return "adas location [u" + mUserId + "] " + (mEnabled ? "enabled" : "disabled"); 541 } 542 } 543 544 /** 545 * Aggregate statistics for a single package under a single provider. 546 */ 547 public static final class AggregateStats { 548 549 @GuardedBy("this") 550 private int mAddedRequestCount; 551 @GuardedBy("this") 552 private int mActiveRequestCount; 553 @GuardedBy("this") 554 private int mForegroundRequestCount; 555 @GuardedBy("this") 556 private int mDeliveredLocationCount; 557 558 @GuardedBy("this") 559 private long mFastestIntervalMs = Long.MAX_VALUE; 560 @GuardedBy("this") 561 private long mSlowestIntervalMs = 0; 562 563 @GuardedBy("this") 564 private long mAddedTimeTotalMs; 565 @GuardedBy("this") 566 private long mAddedTimeLastUpdateRealtimeMs; 567 568 @GuardedBy("this") 569 private long mActiveTimeTotalMs; 570 @GuardedBy("this") 571 private long mActiveTimeLastUpdateRealtimeMs; 572 573 @GuardedBy("this") 574 private long mForegroundTimeTotalMs; 575 @GuardedBy("this") 576 private long mForegroundTimeLastUpdateRealtimeMs; 577 AggregateStats()578 AggregateStats() {} 579 markRequestAdded(long intervalMillis)580 synchronized void markRequestAdded(long intervalMillis) { 581 if (mAddedRequestCount++ == 0) { 582 mAddedTimeLastUpdateRealtimeMs = SystemClock.elapsedRealtime(); 583 } 584 585 mFastestIntervalMs = min(intervalMillis, mFastestIntervalMs); 586 mSlowestIntervalMs = max(intervalMillis, mSlowestIntervalMs); 587 } 588 markRequestRemoved()589 synchronized void markRequestRemoved() { 590 updateTotals(); 591 --mAddedRequestCount; 592 Preconditions.checkState(mAddedRequestCount >= 0); 593 594 mActiveRequestCount = min(mAddedRequestCount, mActiveRequestCount); 595 mForegroundRequestCount = min(mAddedRequestCount, mForegroundRequestCount); 596 } 597 markRequestActive()598 synchronized void markRequestActive() { 599 Preconditions.checkState(mAddedRequestCount > 0); 600 if (mActiveRequestCount++ == 0) { 601 mActiveTimeLastUpdateRealtimeMs = SystemClock.elapsedRealtime(); 602 } 603 } 604 markRequestInactive()605 synchronized void markRequestInactive() { 606 updateTotals(); 607 --mActiveRequestCount; 608 Preconditions.checkState(mActiveRequestCount >= 0); 609 } 610 markRequestForeground()611 synchronized void markRequestForeground() { 612 Preconditions.checkState(mAddedRequestCount > 0); 613 if (mForegroundRequestCount++ == 0) { 614 mForegroundTimeLastUpdateRealtimeMs = SystemClock.elapsedRealtime(); 615 } 616 } 617 markRequestBackground()618 synchronized void markRequestBackground() { 619 updateTotals(); 620 --mForegroundRequestCount; 621 Preconditions.checkState(mForegroundRequestCount >= 0); 622 } 623 markLocationDelivered()624 synchronized void markLocationDelivered() { 625 mDeliveredLocationCount++; 626 } 627 updateTotals()628 public synchronized void updateTotals() { 629 if (mAddedRequestCount > 0) { 630 long realtimeMs = SystemClock.elapsedRealtime(); 631 mAddedTimeTotalMs += realtimeMs - mAddedTimeLastUpdateRealtimeMs; 632 mAddedTimeLastUpdateRealtimeMs = realtimeMs; 633 } 634 if (mActiveRequestCount > 0) { 635 long realtimeMs = SystemClock.elapsedRealtime(); 636 mActiveTimeTotalMs += realtimeMs - mActiveTimeLastUpdateRealtimeMs; 637 mActiveTimeLastUpdateRealtimeMs = realtimeMs; 638 } 639 if (mForegroundRequestCount > 0) { 640 long realtimeMs = SystemClock.elapsedRealtime(); 641 mForegroundTimeTotalMs += realtimeMs - mForegroundTimeLastUpdateRealtimeMs; 642 mForegroundTimeLastUpdateRealtimeMs = realtimeMs; 643 } 644 } 645 646 @Override toString()647 public synchronized String toString() { 648 return "min/max interval = " + intervalToString(mFastestIntervalMs) + "/" 649 + intervalToString(mSlowestIntervalMs) 650 + ", total/active/foreground duration = " + formatDuration(mAddedTimeTotalMs) 651 + "/" + formatDuration(mActiveTimeTotalMs) + "/" 652 + formatDuration(mForegroundTimeTotalMs) + ", locations = " 653 + mDeliveredLocationCount; 654 } 655 intervalToString(long intervalMs)656 private static String intervalToString(long intervalMs) { 657 if (intervalMs == LocationRequest.PASSIVE_INTERVAL) { 658 return "passive"; 659 } else { 660 return MILLISECONDS.toSeconds(intervalMs) + "s"; 661 } 662 } 663 } 664 } 665