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.GnssMeasurementRequest; 34 import android.location.LocationRequest; 35 import android.location.provider.ProviderRequest; 36 import android.location.util.identity.CallerIdentity; 37 import android.os.PowerManager.LocationPowerSaveMode; 38 import android.os.SystemClock; 39 import android.util.ArrayMap; 40 import android.util.TimeUtils; 41 42 import com.android.internal.annotations.GuardedBy; 43 import com.android.internal.util.Preconditions; 44 45 import java.util.function.Consumer; 46 47 /** In memory event log for location events. */ 48 public class LocationEventLog extends LocalEventLog<Object> { 49 50 public static final LocationEventLog EVENT_LOG = new LocationEventLog(); 51 getLogSize()52 private static int getLogSize() { 53 if (D) { 54 return 600; 55 } else { 56 return 300; 57 } 58 } 59 getLocationsLogSize()60 private static int getLocationsLogSize() { 61 if (D) { 62 return 400; 63 } else { 64 return 200; 65 } 66 } 67 68 @GuardedBy("mAggregateStats") 69 private final ArrayMap<String, ArrayMap<CallerIdentity, AggregateStats>> mAggregateStats; 70 71 @GuardedBy("mGnssMeasAggregateStats") 72 private final ArrayMap<CallerIdentity, GnssMeasurementAggregateStats> mGnssMeasAggregateStats; 73 74 @GuardedBy("this") 75 private final LocationsEventLog mLocationsLog; 76 LocationEventLog()77 private LocationEventLog() { 78 super(getLogSize(), Object.class); 79 mAggregateStats = new ArrayMap<>(4); 80 mGnssMeasAggregateStats = new ArrayMap<>(); 81 mLocationsLog = new LocationsEventLog(getLocationsLogSize()); 82 } 83 84 /** Copies out all aggregated stats. */ copyAggregateStats()85 public ArrayMap<String, ArrayMap<CallerIdentity, AggregateStats>> copyAggregateStats() { 86 synchronized (mAggregateStats) { 87 ArrayMap<String, ArrayMap<CallerIdentity, AggregateStats>> copy = new ArrayMap<>( 88 mAggregateStats); 89 for (int i = 0; i < copy.size(); i++) { 90 copy.setValueAt(i, new ArrayMap<>(copy.valueAt(i))); 91 } 92 return copy; 93 } 94 } 95 getAggregateStats(String provider, CallerIdentity identity)96 private AggregateStats getAggregateStats(String provider, CallerIdentity identity) { 97 synchronized (mAggregateStats) { 98 ArrayMap<CallerIdentity, AggregateStats> packageMap = mAggregateStats.get(provider); 99 if (packageMap == null) { 100 packageMap = new ArrayMap<>(2); 101 mAggregateStats.put(provider, packageMap); 102 } 103 CallerIdentity aggregate = CallerIdentity.forAggregation(identity); 104 AggregateStats stats = packageMap.get(aggregate); 105 if (stats == null) { 106 stats = new AggregateStats(); 107 packageMap.put(aggregate, stats); 108 } 109 return stats; 110 } 111 } 112 113 /** Copies out gnss measurement aggregated stats. */ 114 public ArrayMap<CallerIdentity, GnssMeasurementAggregateStats> copyGnssMeasurementAggregateStats()115 copyGnssMeasurementAggregateStats() { 116 synchronized (mGnssMeasAggregateStats) { 117 ArrayMap<CallerIdentity, GnssMeasurementAggregateStats> copy = new ArrayMap<>( 118 mGnssMeasAggregateStats); 119 return copy; 120 } 121 } 122 getGnssMeasurementAggregateStats( CallerIdentity identity)123 private GnssMeasurementAggregateStats getGnssMeasurementAggregateStats( 124 CallerIdentity identity) { 125 synchronized (mGnssMeasAggregateStats) { 126 CallerIdentity aggregate = CallerIdentity.forAggregation(identity); 127 GnssMeasurementAggregateStats stats = mGnssMeasAggregateStats.get(aggregate); 128 if (stats == null) { 129 stats = new GnssMeasurementAggregateStats(); 130 mGnssMeasAggregateStats.put(aggregate, stats); 131 } 132 return stats; 133 } 134 } 135 136 /** Logs a user switched event. */ logUserSwitched(int userIdFrom, int userIdTo)137 public void logUserSwitched(int userIdFrom, int userIdTo) { 138 addLog(new UserSwitchedEvent(userIdFrom, userIdTo)); 139 } 140 141 /** Logs a user visibility changed event. */ logUserVisibilityChanged(int userId, boolean visible)142 public void logUserVisibilityChanged(int userId, boolean visible) { 143 addLog(new UserVisibilityChangedEvent(userId, visible)); 144 } 145 146 /** Logs a location enabled/disabled event. */ logLocationEnabled(int userId, boolean enabled)147 public void logLocationEnabled(int userId, boolean enabled) { 148 addLog(new LocationEnabledEvent(userId, enabled)); 149 } 150 151 /** Logs a location enabled/disabled event. */ logAdasLocationEnabled(int userId, boolean enabled)152 public void logAdasLocationEnabled(int userId, boolean enabled) { 153 addLog(new LocationAdasEnabledEvent(userId, enabled)); 154 } 155 156 /** Logs a location provider enabled/disabled event. */ logProviderEnabled(String provider, int userId, boolean enabled)157 public void logProviderEnabled(String provider, int userId, boolean enabled) { 158 addLog(new ProviderEnabledEvent(provider, userId, enabled)); 159 } 160 161 /** Logs a location provider being replaced/unreplaced by a mock provider. */ logProviderMocked(String provider, boolean mocked)162 public void logProviderMocked(String provider, boolean mocked) { 163 addLog(new ProviderMockedEvent(provider, mocked)); 164 } 165 166 /** Logs a new client registration for a location provider. */ logProviderClientRegistered(String provider, CallerIdentity identity, LocationRequest request)167 public void logProviderClientRegistered(String provider, CallerIdentity identity, 168 LocationRequest request) { 169 addLog(new ProviderClientRegisterEvent(provider, true, identity, request)); 170 getAggregateStats(provider, identity).markRequestAdded(request.getIntervalMillis()); 171 } 172 173 /** Logs a client unregistration for a location provider. */ logProviderClientUnregistered(String provider, CallerIdentity identity)174 public void logProviderClientUnregistered(String provider, CallerIdentity identity) { 175 addLog(new ProviderClientRegisterEvent(provider, false, identity, null)); 176 getAggregateStats(provider, identity).markRequestRemoved(); 177 } 178 179 /** Logs a client for a location provider entering the active state. */ logProviderClientActive(String provider, CallerIdentity identity)180 public void logProviderClientActive(String provider, CallerIdentity identity) { 181 getAggregateStats(provider, identity).markRequestActive(); 182 } 183 184 /** Logs a client for a location provider leaving the active state. */ logProviderClientInactive(String provider, CallerIdentity identity)185 public void logProviderClientInactive(String provider, CallerIdentity identity) { 186 getAggregateStats(provider, identity).markRequestInactive(); 187 } 188 189 /** Logs a client for a location provider entering the foreground state. */ logProviderClientForeground(String provider, CallerIdentity identity)190 public void logProviderClientForeground(String provider, CallerIdentity identity) { 191 if (D) { 192 addLog(new ProviderClientForegroundEvent(provider, true, identity)); 193 } 194 getAggregateStats(provider, identity).markRequestForeground(); 195 } 196 197 /** Logs a client for a location provider leaving the foreground state. */ logProviderClientBackground(String provider, CallerIdentity identity)198 public void logProviderClientBackground(String provider, CallerIdentity identity) { 199 if (D) { 200 addLog(new ProviderClientForegroundEvent(provider, false, identity)); 201 } 202 getAggregateStats(provider, identity).markRequestBackground(); 203 } 204 205 /** Logs a client for a location provider entering the permitted state. */ logProviderClientPermitted(String provider, CallerIdentity identity)206 public void logProviderClientPermitted(String provider, CallerIdentity identity) { 207 if (D) { 208 addLog(new ProviderClientPermittedEvent(provider, true, identity)); 209 } 210 } 211 212 /** Logs a client for a location provider leaving the permitted state. */ logProviderClientUnpermitted(String provider, CallerIdentity identity)213 public void logProviderClientUnpermitted(String provider, CallerIdentity identity) { 214 if (D) { 215 addLog(new ProviderClientPermittedEvent(provider, false, identity)); 216 } 217 } 218 219 /** Logs a change to the provider request for a location provider. */ logProviderUpdateRequest(String provider, ProviderRequest request)220 public void logProviderUpdateRequest(String provider, ProviderRequest request) { 221 addLog(new ProviderUpdateEvent(provider, request)); 222 } 223 224 /** Logs a new incoming location for a location provider. */ logProviderReceivedLocations(String provider, int numLocations)225 public void logProviderReceivedLocations(String provider, int numLocations) { 226 synchronized (this) { 227 mLocationsLog.logProviderReceivedLocations(provider, numLocations); 228 } 229 } 230 231 /** Logs a location deliver for a client of a location provider. */ logProviderDeliveredLocations(String provider, int numLocations, CallerIdentity identity)232 public void logProviderDeliveredLocations(String provider, int numLocations, 233 CallerIdentity identity) { 234 synchronized (this) { 235 mLocationsLog.logProviderDeliveredLocations(provider, numLocations, identity); 236 } 237 getAggregateStats(provider, identity).markLocationDelivered(); 238 } 239 240 /** Logs that a provider has entered or exited stationary throttling. */ logProviderStationaryThrottled(String provider, boolean throttled, ProviderRequest request)241 public void logProviderStationaryThrottled(String provider, boolean throttled, 242 ProviderRequest request) { 243 addLog(new ProviderStationaryThrottledEvent(provider, throttled, request)); 244 } 245 246 /** Logs that the location power save mode has changed. */ logLocationPowerSaveMode( @ocationPowerSaveMode int locationPowerSaveMode)247 public void logLocationPowerSaveMode( 248 @LocationPowerSaveMode int locationPowerSaveMode) { 249 addLog(new LocationPowerSaveModeEvent(locationPowerSaveMode)); 250 } 251 252 /** Logs a new client registration for a GNSS Measurement. */ logGnssMeasurementClientRegistered(CallerIdentity identity, GnssMeasurementRequest request)253 public void logGnssMeasurementClientRegistered(CallerIdentity identity, 254 GnssMeasurementRequest request) { 255 addLog(new GnssMeasurementClientRegisterEvent(true, identity, request)); 256 getGnssMeasurementAggregateStats(identity).markRequestAdded(request.getIntervalMillis(), 257 request.isFullTracking()); 258 } 259 260 /** Logs a new client unregistration for a GNSS Measurement. */ logGnssMeasurementClientUnregistered(CallerIdentity identity)261 public void logGnssMeasurementClientUnregistered(CallerIdentity identity) { 262 addLog(new GnssMeasurementClientRegisterEvent(false, identity, null)); 263 getGnssMeasurementAggregateStats(identity).markRequestRemoved(); 264 } 265 266 /** Logs a GNSS measurement event deliver for a client. */ logGnssMeasurementsDelivered(int numGnssMeasurements, CallerIdentity identity)267 public void logGnssMeasurementsDelivered(int numGnssMeasurements, 268 CallerIdentity identity) { 269 synchronized (this) { 270 mLocationsLog.logDeliveredGnssMeasurements(numGnssMeasurements, identity); 271 } 272 getGnssMeasurementAggregateStats(identity).markGnssMeasurementDelivered(); 273 } 274 addLog(Object logEvent)275 private void addLog(Object logEvent) { 276 addLog(SystemClock.elapsedRealtime(), logEvent); 277 } 278 279 @Override iterate(LogConsumer<? super Object> consumer)280 public synchronized void iterate(LogConsumer<? super Object> consumer) { 281 iterate(consumer, this, mLocationsLog); 282 } 283 iterate(Consumer<String> consumer)284 public void iterate(Consumer<String> consumer) { 285 iterate(consumer, null); 286 } 287 iterate(Consumer<String> consumer, @Nullable String providerFilter)288 public void iterate(Consumer<String> consumer, @Nullable String providerFilter) { 289 long systemTimeDeltaMs = System.currentTimeMillis() - SystemClock.elapsedRealtime(); 290 StringBuilder builder = new StringBuilder(); 291 iterate( 292 (time, logEvent) -> { 293 boolean match = providerFilter == null || (logEvent instanceof ProviderEvent 294 && providerFilter.equals(((ProviderEvent) logEvent).mProvider)); 295 if (match) { 296 builder.setLength(0); 297 builder.append(TimeUtils.logTimeOfDay(time + systemTimeDeltaMs)); 298 builder.append(": "); 299 builder.append(logEvent); 300 consumer.accept(builder.toString()); 301 } 302 }); 303 } 304 305 private abstract static class ProviderEvent { 306 307 protected final String mProvider; 308 ProviderEvent(String provider)309 ProviderEvent(String provider) { 310 mProvider = provider; 311 } 312 } 313 314 private static final class ProviderEnabledEvent extends ProviderEvent { 315 316 private final int mUserId; 317 private final boolean mEnabled; 318 ProviderEnabledEvent(String provider, int userId, boolean enabled)319 ProviderEnabledEvent(String provider, int userId, 320 boolean enabled) { 321 super(provider); 322 mUserId = userId; 323 mEnabled = enabled; 324 } 325 326 @Override toString()327 public String toString() { 328 return mProvider + " provider [u" + mUserId + "] " + (mEnabled ? "enabled" 329 : "disabled"); 330 } 331 } 332 333 private static final class ProviderMockedEvent extends ProviderEvent { 334 335 private final boolean mMocked; 336 ProviderMockedEvent(String provider, boolean mocked)337 ProviderMockedEvent(String provider, boolean mocked) { 338 super(provider); 339 mMocked = mocked; 340 } 341 342 @Override toString()343 public String toString() { 344 if (mMocked) { 345 return mProvider + " provider added mock provider override"; 346 } else { 347 return mProvider + " provider removed mock provider override"; 348 } 349 } 350 } 351 352 private static final class ProviderClientRegisterEvent extends ProviderEvent { 353 354 private final boolean mRegistered; 355 private final CallerIdentity mIdentity; 356 @Nullable private final LocationRequest mLocationRequest; 357 ProviderClientRegisterEvent(String provider, boolean registered, CallerIdentity identity, @Nullable LocationRequest locationRequest)358 ProviderClientRegisterEvent(String provider, boolean registered, 359 CallerIdentity identity, @Nullable LocationRequest locationRequest) { 360 super(provider); 361 mRegistered = registered; 362 mIdentity = identity; 363 mLocationRequest = locationRequest; 364 } 365 366 @Override toString()367 public String toString() { 368 if (mRegistered) { 369 return mProvider + " provider +registration " + mIdentity + " -> " 370 + mLocationRequest; 371 } else { 372 return mProvider + " provider -registration " + mIdentity; 373 } 374 } 375 } 376 377 private static final class ProviderClientForegroundEvent extends ProviderEvent { 378 379 private final boolean mForeground; 380 private final CallerIdentity mIdentity; 381 ProviderClientForegroundEvent(String provider, boolean foreground, CallerIdentity identity)382 ProviderClientForegroundEvent(String provider, boolean foreground, 383 CallerIdentity identity) { 384 super(provider); 385 mForeground = foreground; 386 mIdentity = identity; 387 } 388 389 @Override toString()390 public String toString() { 391 return mProvider + " provider client " + mIdentity + " -> " 392 + (mForeground ? "foreground" : "background"); 393 } 394 } 395 396 private static final class ProviderClientPermittedEvent extends ProviderEvent { 397 398 private final boolean mPermitted; 399 private final CallerIdentity mIdentity; 400 ProviderClientPermittedEvent(String provider, boolean permitted, CallerIdentity identity)401 ProviderClientPermittedEvent(String provider, boolean permitted, CallerIdentity identity) { 402 super(provider); 403 mPermitted = permitted; 404 mIdentity = identity; 405 } 406 407 @Override toString()408 public String toString() { 409 return mProvider + " provider client " + mIdentity + " -> " 410 + (mPermitted ? "permitted" : "unpermitted"); 411 } 412 } 413 414 private static final class ProviderUpdateEvent extends ProviderEvent { 415 416 private final ProviderRequest mRequest; 417 ProviderUpdateEvent(String provider, ProviderRequest request)418 ProviderUpdateEvent(String provider, ProviderRequest request) { 419 super(provider); 420 mRequest = request; 421 } 422 423 @Override toString()424 public String toString() { 425 return mProvider + " provider request = " + mRequest; 426 } 427 } 428 429 private static final class ProviderReceiveLocationEvent extends ProviderEvent { 430 431 private final int mNumLocations; 432 ProviderReceiveLocationEvent(String provider, int numLocations)433 ProviderReceiveLocationEvent(String provider, int numLocations) { 434 super(provider); 435 mNumLocations = numLocations; 436 } 437 438 @Override toString()439 public String toString() { 440 return mProvider + " provider received location[" + mNumLocations + "]"; 441 } 442 } 443 444 private static final class ProviderDeliverLocationEvent extends ProviderEvent { 445 446 private final int mNumLocations; 447 @Nullable private final CallerIdentity mIdentity; 448 ProviderDeliverLocationEvent(String provider, int numLocations, @Nullable CallerIdentity identity)449 ProviderDeliverLocationEvent(String provider, int numLocations, 450 @Nullable CallerIdentity identity) { 451 super(provider); 452 mNumLocations = numLocations; 453 mIdentity = identity; 454 } 455 456 @Override toString()457 public String toString() { 458 return mProvider + " provider delivered location[" + mNumLocations + "] to " 459 + mIdentity; 460 } 461 } 462 463 private static final class ProviderStationaryThrottledEvent extends ProviderEvent { 464 465 private final boolean mStationaryThrottled; 466 private final ProviderRequest mRequest; 467 ProviderStationaryThrottledEvent(String provider, boolean stationaryThrottled, ProviderRequest request)468 ProviderStationaryThrottledEvent(String provider, boolean stationaryThrottled, 469 ProviderRequest request) { 470 super(provider); 471 mStationaryThrottled = stationaryThrottled; 472 mRequest = request; 473 } 474 475 @Override toString()476 public String toString() { 477 return mProvider + " provider stationary/idle " + (mStationaryThrottled ? "throttled" 478 : "unthrottled") + ", request = " + mRequest; 479 } 480 } 481 482 private static final class LocationPowerSaveModeEvent { 483 484 @LocationPowerSaveMode 485 private final int mLocationPowerSaveMode; 486 LocationPowerSaveModeEvent(@ocationPowerSaveMode int locationPowerSaveMode)487 LocationPowerSaveModeEvent(@LocationPowerSaveMode int locationPowerSaveMode) { 488 mLocationPowerSaveMode = locationPowerSaveMode; 489 } 490 491 @Override toString()492 public String toString() { 493 String mode; 494 switch (mLocationPowerSaveMode) { 495 case LOCATION_MODE_NO_CHANGE: 496 mode = "NO_CHANGE"; 497 break; 498 case LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF: 499 mode = "GPS_DISABLED_WHEN_SCREEN_OFF"; 500 break; 501 case LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF: 502 mode = "ALL_DISABLED_WHEN_SCREEN_OFF"; 503 break; 504 case LOCATION_MODE_FOREGROUND_ONLY: 505 mode = "FOREGROUND_ONLY"; 506 break; 507 case LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF: 508 mode = "THROTTLE_REQUESTS_WHEN_SCREEN_OFF"; 509 break; 510 default: 511 mode = "UNKNOWN"; 512 break; 513 } 514 return "location power save mode changed to " + mode; 515 } 516 } 517 518 private static final class UserSwitchedEvent { 519 520 private final int mUserIdFrom; 521 private final int mUserIdTo; 522 UserSwitchedEvent(int userIdFrom, int userIdTo)523 UserSwitchedEvent(int userIdFrom, int userIdTo) { 524 mUserIdFrom = userIdFrom; 525 mUserIdTo = userIdTo; 526 } 527 528 @Override toString()529 public String toString() { 530 return "current user switched from u" + mUserIdFrom + " to u" + mUserIdTo; 531 } 532 } 533 534 private static final class UserVisibilityChangedEvent { 535 536 private final int mUserId; 537 private final boolean mVisible; 538 UserVisibilityChangedEvent(int userId, boolean visible)539 UserVisibilityChangedEvent(int userId, boolean visible) { 540 mUserId = userId; 541 mVisible = visible; 542 } 543 544 @Override toString()545 public String toString() { 546 return "[u" + mUserId + "] " + (mVisible ? "visible" : "invisible"); 547 } 548 } 549 550 private static final class LocationEnabledEvent { 551 552 private final int mUserId; 553 private final boolean mEnabled; 554 LocationEnabledEvent(int userId, boolean enabled)555 LocationEnabledEvent(int userId, boolean enabled) { 556 mUserId = userId; 557 mEnabled = enabled; 558 } 559 560 @Override toString()561 public String toString() { 562 return "location [u" + mUserId + "] " + (mEnabled ? "enabled" : "disabled"); 563 } 564 } 565 566 private static final class LocationAdasEnabledEvent { 567 568 private final int mUserId; 569 private final boolean mEnabled; 570 LocationAdasEnabledEvent(int userId, boolean enabled)571 LocationAdasEnabledEvent(int userId, boolean enabled) { 572 mUserId = userId; 573 mEnabled = enabled; 574 } 575 576 @Override toString()577 public String toString() { 578 return "adas location [u" + mUserId + "] " + (mEnabled ? "enabled" : "disabled"); 579 } 580 } 581 582 private static final class GnssMeasurementClientRegisterEvent{ 583 584 private final boolean mRegistered; 585 private final CallerIdentity mIdentity; 586 @Nullable 587 private final GnssMeasurementRequest mGnssMeasurementRequest; 588 GnssMeasurementClientRegisterEvent(boolean registered, CallerIdentity identity, @Nullable GnssMeasurementRequest measurementRequest)589 GnssMeasurementClientRegisterEvent(boolean registered, 590 CallerIdentity identity, @Nullable GnssMeasurementRequest measurementRequest) { 591 mRegistered = registered; 592 mIdentity = identity; 593 mGnssMeasurementRequest = measurementRequest; 594 } 595 596 @Override toString()597 public String toString() { 598 if (mRegistered) { 599 return "gnss measurements +registration " + mIdentity + " -> " 600 + mGnssMeasurementRequest; 601 } else { 602 return "gnss measurements -registration " + mIdentity; 603 } 604 } 605 } 606 607 private static final class GnssMeasurementDeliverEvent { 608 609 private final int mNumGnssMeasurements; 610 @Nullable 611 private final CallerIdentity mIdentity; 612 GnssMeasurementDeliverEvent(int numGnssMeasurements, @Nullable CallerIdentity identity)613 GnssMeasurementDeliverEvent(int numGnssMeasurements, 614 @Nullable CallerIdentity identity) { 615 mNumGnssMeasurements = numGnssMeasurements; 616 mIdentity = identity; 617 } 618 619 @Override toString()620 public String toString() { 621 return "gnss measurements delivered GnssMeasurements[" + mNumGnssMeasurements + "]" 622 + " to " + mIdentity; 623 } 624 } 625 626 private static final class LocationsEventLog extends LocalEventLog<Object> { 627 LocationsEventLog(int size)628 LocationsEventLog(int size) { 629 super(size, Object.class); 630 } 631 logProviderReceivedLocations(String provider, int numLocations)632 public void logProviderReceivedLocations(String provider, int numLocations) { 633 addLog(new ProviderReceiveLocationEvent(provider, numLocations)); 634 } 635 logDeliveredGnssMeasurements(int numGnssMeasurements, CallerIdentity identity)636 public void logDeliveredGnssMeasurements(int numGnssMeasurements, 637 CallerIdentity identity) { 638 addLog(new GnssMeasurementDeliverEvent(numGnssMeasurements, identity)); 639 } 640 logProviderDeliveredLocations(String provider, int numLocations, CallerIdentity identity)641 public void logProviderDeliveredLocations(String provider, int numLocations, 642 CallerIdentity identity) { 643 addLog(new ProviderDeliverLocationEvent(provider, numLocations, identity)); 644 } 645 addLog(Object logEvent)646 private void addLog(Object logEvent) { 647 this.addLog(SystemClock.elapsedRealtime(), logEvent); 648 } 649 } 650 651 /** 652 * Aggregate statistics for a single package under a single provider. 653 */ 654 public static final class AggregateStats { 655 656 @GuardedBy("this") 657 private int mAddedRequestCount; 658 @GuardedBy("this") 659 private int mActiveRequestCount; 660 @GuardedBy("this") 661 private int mForegroundRequestCount; 662 @GuardedBy("this") 663 private int mDeliveredLocationCount; 664 665 @GuardedBy("this") 666 private long mFastestIntervalMs = Long.MAX_VALUE; 667 @GuardedBy("this") 668 private long mSlowestIntervalMs = 0; 669 670 @GuardedBy("this") 671 private long mAddedTimeTotalMs; 672 @GuardedBy("this") 673 private long mAddedTimeLastUpdateRealtimeMs; 674 675 @GuardedBy("this") 676 private long mActiveTimeTotalMs; 677 @GuardedBy("this") 678 private long mActiveTimeLastUpdateRealtimeMs; 679 680 @GuardedBy("this") 681 private long mForegroundTimeTotalMs; 682 @GuardedBy("this") 683 private long mForegroundTimeLastUpdateRealtimeMs; 684 AggregateStats()685 AggregateStats() {} 686 markRequestAdded(long intervalMillis)687 synchronized void markRequestAdded(long intervalMillis) { 688 if (mAddedRequestCount++ == 0) { 689 mAddedTimeLastUpdateRealtimeMs = SystemClock.elapsedRealtime(); 690 } 691 692 mFastestIntervalMs = min(intervalMillis, mFastestIntervalMs); 693 mSlowestIntervalMs = max(intervalMillis, mSlowestIntervalMs); 694 } 695 markRequestRemoved()696 synchronized void markRequestRemoved() { 697 updateTotals(); 698 --mAddedRequestCount; 699 Preconditions.checkState(mAddedRequestCount >= 0); 700 701 mActiveRequestCount = min(mAddedRequestCount, mActiveRequestCount); 702 mForegroundRequestCount = min(mAddedRequestCount, mForegroundRequestCount); 703 } 704 markRequestActive()705 synchronized void markRequestActive() { 706 Preconditions.checkState(mAddedRequestCount > 0); 707 if (mActiveRequestCount++ == 0) { 708 mActiveTimeLastUpdateRealtimeMs = SystemClock.elapsedRealtime(); 709 } 710 } 711 markRequestInactive()712 synchronized void markRequestInactive() { 713 updateTotals(); 714 --mActiveRequestCount; 715 Preconditions.checkState(mActiveRequestCount >= 0); 716 } 717 markRequestForeground()718 synchronized void markRequestForeground() { 719 Preconditions.checkState(mAddedRequestCount > 0); 720 if (mForegroundRequestCount++ == 0) { 721 mForegroundTimeLastUpdateRealtimeMs = SystemClock.elapsedRealtime(); 722 } 723 } 724 markRequestBackground()725 synchronized void markRequestBackground() { 726 updateTotals(); 727 --mForegroundRequestCount; 728 Preconditions.checkState(mForegroundRequestCount >= 0); 729 } 730 markLocationDelivered()731 synchronized void markLocationDelivered() { 732 mDeliveredLocationCount++; 733 } 734 updateTotals()735 public synchronized void updateTotals() { 736 if (mAddedRequestCount > 0) { 737 long realtimeMs = SystemClock.elapsedRealtime(); 738 mAddedTimeTotalMs += realtimeMs - mAddedTimeLastUpdateRealtimeMs; 739 mAddedTimeLastUpdateRealtimeMs = realtimeMs; 740 } 741 if (mActiveRequestCount > 0) { 742 long realtimeMs = SystemClock.elapsedRealtime(); 743 mActiveTimeTotalMs += realtimeMs - mActiveTimeLastUpdateRealtimeMs; 744 mActiveTimeLastUpdateRealtimeMs = realtimeMs; 745 } 746 if (mForegroundRequestCount > 0) { 747 long realtimeMs = SystemClock.elapsedRealtime(); 748 mForegroundTimeTotalMs += realtimeMs - mForegroundTimeLastUpdateRealtimeMs; 749 mForegroundTimeLastUpdateRealtimeMs = realtimeMs; 750 } 751 } 752 753 @Override toString()754 public synchronized String toString() { 755 return "min/max interval = " + intervalToString(mFastestIntervalMs) + "/" 756 + intervalToString(mSlowestIntervalMs) 757 + ", total/active/foreground duration = " + formatDuration(mAddedTimeTotalMs) 758 + "/" + formatDuration(mActiveTimeTotalMs) + "/" 759 + formatDuration(mForegroundTimeTotalMs) + ", locations = " 760 + mDeliveredLocationCount; 761 } 762 intervalToString(long intervalMs)763 private static String intervalToString(long intervalMs) { 764 if (intervalMs == LocationRequest.PASSIVE_INTERVAL) { 765 return "passive"; 766 } else { 767 return MILLISECONDS.toSeconds(intervalMs) + "s"; 768 } 769 } 770 } 771 772 /** 773 * Aggregate statistics for GNSS measurements. 774 */ 775 public static final class GnssMeasurementAggregateStats { 776 @GuardedBy("this") 777 private int mAddedRequestCount; 778 @GuardedBy("this") 779 private int mReceivedMeasurementEventCount; 780 @GuardedBy("this") 781 private long mAddedTimeTotalMs; 782 @GuardedBy("this") 783 private long mAddedTimeLastUpdateRealtimeMs; 784 @GuardedBy("this") 785 private long mFastestIntervalMs = Long.MAX_VALUE; 786 @GuardedBy("this") 787 private long mSlowestIntervalMs = 0; 788 @GuardedBy("this") 789 private boolean mHasFullTracking; 790 @GuardedBy("this") 791 private boolean mHasDutyCycling; 792 GnssMeasurementAggregateStats()793 GnssMeasurementAggregateStats() { 794 } 795 markRequestAdded(long intervalMillis, boolean fullTracking)796 synchronized void markRequestAdded(long intervalMillis, boolean fullTracking) { 797 if (mAddedRequestCount++ == 0) { 798 mAddedTimeLastUpdateRealtimeMs = SystemClock.elapsedRealtime(); 799 } 800 if (fullTracking) { 801 mHasFullTracking = true; 802 } else { 803 mHasDutyCycling = true; 804 } 805 mFastestIntervalMs = min(intervalMillis, mFastestIntervalMs); 806 mSlowestIntervalMs = max(intervalMillis, mSlowestIntervalMs); 807 } 808 markRequestRemoved()809 synchronized void markRequestRemoved() { 810 updateTotals(); 811 --mAddedRequestCount; 812 Preconditions.checkState(mAddedRequestCount >= 0); 813 } 814 markGnssMeasurementDelivered()815 synchronized void markGnssMeasurementDelivered() { 816 mReceivedMeasurementEventCount++; 817 } 818 updateTotals()819 public synchronized void updateTotals() { 820 if (mAddedRequestCount > 0) { 821 long realtimeMs = SystemClock.elapsedRealtime(); 822 mAddedTimeTotalMs += realtimeMs - mAddedTimeLastUpdateRealtimeMs; 823 mAddedTimeLastUpdateRealtimeMs = realtimeMs; 824 } 825 } 826 827 @Override toString()828 public synchronized String toString() { 829 return "min/max interval = " 830 + intervalToString(mFastestIntervalMs) + "/" 831 + intervalToString(mSlowestIntervalMs) 832 + ", total duration = " + formatDuration(mAddedTimeTotalMs) 833 + ", tracking mode = " + trackingModeToString() + ", GNSS measurement events = " 834 + mReceivedMeasurementEventCount; 835 } 836 intervalToString(long intervalMs)837 private static String intervalToString(long intervalMs) { 838 if (intervalMs == GnssMeasurementRequest.PASSIVE_INTERVAL) { 839 return "passive"; 840 } else { 841 return MILLISECONDS.toSeconds(intervalMs) + "s"; 842 } 843 } 844 845 @GuardedBy("this") trackingModeToString()846 private String trackingModeToString() { 847 if (mHasFullTracking && mHasDutyCycling) { 848 return "mixed tracking mode"; 849 } else if (mHasFullTracking) { 850 return "always full-tracking"; 851 } else { 852 return "always duty-cycling"; 853 } 854 } 855 } 856 } 857