diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java index ea759bf500dd2..28dc5167487d2 100644 --- a/services/core/java/com/android/server/location/LocationManagerService.java +++ b/services/core/java/com/android/server/location/LocationManagerService.java @@ -79,6 +79,7 @@ import android.os.UserHandle; import android.os.WorkSource; import android.os.WorkSource.WorkChain; import android.stats.location.LocationStatsEnums; +import android.util.ArrayMap; import android.util.IndentingPrintWriter; import android.util.Log; @@ -87,6 +88,7 @@ import com.android.internal.util.DumpUtils; import com.android.internal.util.Preconditions; import com.android.server.LocalServices; import com.android.server.SystemService; +import com.android.server.location.eventlog.LocationEventLog; import com.android.server.location.geofence.GeofenceManager; import com.android.server.location.geofence.GeofenceProxy; import com.android.server.location.gnss.GnssConfiguration; @@ -98,7 +100,6 @@ import com.android.server.location.injector.AppOpsHelper; import com.android.server.location.injector.EmergencyHelper; import com.android.server.location.injector.Injector; import com.android.server.location.injector.LocationAttributionHelper; -import com.android.server.location.injector.LocationEventLog; import com.android.server.location.injector.LocationPermissionsHelper; import com.android.server.location.injector.LocationPowerSaveModeHelper; import com.android.server.location.injector.LocationUsageLogger; @@ -147,9 +148,10 @@ public class LocationManagerService extends ILocationManager.Stub { public Lifecycle(Context context) { super(context); + LocationEventLog eventLog = new LocationEventLog(); mUserInfoHelper = new LifecycleUserInfoHelper(context); - mSystemInjector = new SystemInjector(context, mUserInfoHelper); - mService = new LocationManagerService(context, mSystemInjector); + mSystemInjector = new SystemInjector(context, mUserInfoHelper, eventLog); + mService = new LocationManagerService(context, mSystemInjector, eventLog); } @Override @@ -159,7 +161,7 @@ public class LocationManagerService extends ILocationManager.Stub { // client caching behavior is only enabled after seeing the first invalidate LocationManager.invalidateLocalLocationEnabledCaches(); // disable caching for our own process - Objects.requireNonNull(mService.mContext.getSystemService(LocationManager.class)) + Objects.requireNonNull(getContext().getSystemService(LocationManager.class)) .disableLocalLocationEnabledCaches(); } @@ -221,6 +223,7 @@ public class LocationManagerService extends ILocationManager.Stub { private final Context mContext; private final Injector mInjector; + private final LocationEventLog mEventLog; private final LocalService mLocalService; private final GeofenceManager mGeofenceManager; @@ -245,10 +248,10 @@ public class LocationManagerService extends ILocationManager.Stub { private final CopyOnWriteArrayList mProviderManagers = new CopyOnWriteArrayList<>(); - LocationManagerService(Context context, Injector injector) { + LocationManagerService(Context context, Injector injector, LocationEventLog eventLog) { mContext = context.createAttributionContext(ATTRIBUTION_TAG); mInjector = injector; - + mEventLog = eventLog; mLocalService = new LocalService(); LocalServices.addService(LocationManagerInternal.class, mLocalService); @@ -256,7 +259,7 @@ public class LocationManagerService extends ILocationManager.Stub { // set up passive provider first since it will be required for all other location providers, // which are loaded later once the system is ready. - mPassiveManager = new PassiveLocationProviderManager(mContext, injector); + mPassiveManager = new PassiveLocationProviderManager(mContext, injector, mEventLog); addLocationProviderManager(mPassiveManager, new PassiveLocationProvider(mContext)); // TODO: load the gps provider here as well, which will require refactoring @@ -297,7 +300,7 @@ public class LocationManagerService extends ILocationManager.Stub { } LocationProviderManager manager = new LocationProviderManager(mContext, mInjector, - providerName, mPassiveManager); + mEventLog, providerName, mPassiveManager); addLocationProviderManager(manager, null); return manager; } @@ -341,7 +344,7 @@ public class LocationManagerService extends ILocationManager.Stub { com.android.internal.R.string.config_networkLocationProviderPackageName); if (networkProvider != null) { LocationProviderManager networkManager = new LocationProviderManager(mContext, - mInjector, NETWORK_PROVIDER, mPassiveManager); + mInjector, mEventLog, NETWORK_PROVIDER, mPassiveManager); addLocationProviderManager(networkManager, networkProvider); } else { Log.w(TAG, "no network location provider found"); @@ -360,7 +363,7 @@ public class LocationManagerService extends ILocationManager.Stub { com.android.internal.R.string.config_fusedLocationProviderPackageName); if (fusedProvider != null) { LocationProviderManager fusedManager = new LocationProviderManager(mContext, mInjector, - FUSED_PROVIDER, mPassiveManager); + mEventLog, FUSED_PROVIDER, mPassiveManager); addLocationProviderManager(fusedManager, fusedProvider); } else { Log.wtf(TAG, "no fused location provider found"); @@ -375,7 +378,7 @@ public class LocationManagerService extends ILocationManager.Stub { mGnssManagerService.onSystemReady(); LocationProviderManager gnssManager = new LocationProviderManager(mContext, mInjector, - GPS_PROVIDER, mPassiveManager); + mEventLog, GPS_PROVIDER, mPassiveManager); addLocationProviderManager(gnssManager, mGnssManagerService.getGnssLocationProvider()); } @@ -431,7 +434,7 @@ public class LocationManagerService extends ILocationManager.Stub { Log.d(TAG, "[u" + userId + "] location enabled = " + enabled); } - mInjector.getLocationEventLog().logLocationEnabled(userId, enabled); + mEventLog.logLocationEnabled(userId, enabled); Intent intent = new Intent(LocationManager.MODE_CHANGED_ACTION) .putExtra(LocationManager.EXTRA_LOCATION_ENABLED, enabled) @@ -1193,9 +1196,27 @@ public class LocationManagerService extends ILocationManager.Stub { IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); - if (mGnssManagerService != null && args.length > 0 && args[0].equals("--gnssmetrics")) { - mGnssManagerService.dump(fd, ipw, args); - return; + if (args.length > 0) { + LocationProviderManager manager = getLocationProviderManager(args[0]); + if (manager != null) { + ipw.println("Provider:"); + ipw.increaseIndent(); + manager.dump(fd, ipw, args); + ipw.decreaseIndent(); + + ipw.println("Event Log:"); + ipw.increaseIndent(); + mEventLog.iterate(manager.getName(), ipw::println); + ipw.decreaseIndent(); + return; + } + + if ("--gnssmetrics".equals(args[0])) { + if (mGnssManagerService != null) { + mGnssManagerService.dump(fd, ipw, args); + } + return; + } } ipw.println("Location Manager State:"); @@ -1227,6 +1248,25 @@ public class LocationManagerService extends ILocationManager.Stub { } ipw.decreaseIndent(); + ipw.println("Historical Aggregate Location Provider Data:"); + ipw.increaseIndent(); + ArrayMap> aggregateStats = + mEventLog.copyAggregateStats(); + for (int i = 0; i < aggregateStats.size(); i++) { + ipw.println(aggregateStats.keyAt(i)); + ipw.increaseIndent(); + ArrayMap providerStats = + aggregateStats.valueAt(i); + for (int j = 0; j < providerStats.size(); j++) { + ipw.print(providerStats.keyAt(j)); + ipw.print(": "); + providerStats.valueAt(j).updateTotals(); + ipw.println(providerStats.valueAt(j)); + } + ipw.decreaseIndent(); + } + ipw.decreaseIndent(); + if (mGnssManagerService != null) { ipw.println("GNSS Manager:"); ipw.increaseIndent(); @@ -1241,7 +1281,7 @@ public class LocationManagerService extends ILocationManager.Stub { ipw.println("Event Log:"); ipw.increaseIndent(); - mInjector.getLocationEventLog().iterate(ipw::println); + mEventLog.iterate(ipw::println); ipw.decreaseIndent(); } @@ -1320,7 +1360,6 @@ public class LocationManagerService extends ILocationManager.Stub { private final Context mContext; private final UserInfoHelper mUserInfoHelper; - private final LocationEventLog mLocationEventLog; private final AlarmHelper mAlarmHelper; private final SystemAppOpsHelper mAppOpsHelper; private final SystemLocationPermissionsHelper mLocationPermissionsHelper; @@ -1339,19 +1378,17 @@ public class LocationManagerService extends ILocationManager.Stub { @GuardedBy("this") private boolean mSystemReady; - SystemInjector(Context context, UserInfoHelper userInfoHelper) { + SystemInjector(Context context, UserInfoHelper userInfoHelper, LocationEventLog eventLog) { mContext = context; mUserInfoHelper = userInfoHelper; - mLocationEventLog = new LocationEventLog(); mAlarmHelper = new SystemAlarmHelper(context); mAppOpsHelper = new SystemAppOpsHelper(context); mLocationPermissionsHelper = new SystemLocationPermissionsHelper(context, mAppOpsHelper); mSettingsHelper = new SystemSettingsHelper(context); mAppForegroundHelper = new SystemAppForegroundHelper(context); - mLocationPowerSaveModeHelper = new SystemLocationPowerSaveModeHelper(context, - mLocationEventLog); + mLocationPowerSaveModeHelper = new SystemLocationPowerSaveModeHelper(context, eventLog); mScreenInteractiveHelper = new SystemScreenInteractiveHelper(context); mLocationAttributionHelper = new LocationAttributionHelper(mAppOpsHelper); mLocationUsageLogger = new LocationUsageLogger(); @@ -1429,11 +1466,6 @@ public class LocationManagerService extends ILocationManager.Stub { return mEmergencyCallHelper; } - @Override - public LocationEventLog getLocationEventLog() { - return mLocationEventLog; - } - @Override public LocationUsageLogger getLocationUsageLogger() { return mLocationUsageLogger; diff --git a/services/core/java/com/android/server/location/eventlog/LocalEventLog.java b/services/core/java/com/android/server/location/eventlog/LocalEventLog.java index b5746bbf310af..12dd3e6a4a4c3 100644 --- a/services/core/java/com/android/server/location/eventlog/LocalEventLog.java +++ b/services/core/java/com/android/server/location/eventlog/LocalEventLog.java @@ -16,12 +16,13 @@ package com.android.server.location.eventlog; +import android.annotation.Nullable; import android.os.SystemClock; import android.util.TimeUtils; import com.android.internal.util.Preconditions; -import java.util.ListIterator; +import java.util.Iterator; import java.util.NoSuchElementException; import java.util.function.Consumer; @@ -35,6 +36,7 @@ public abstract class LocalEventLog { boolean isFiller(); long getTimeDeltaMs(); String getLogString(); + boolean filter(@Nullable String filter); } private static final class FillerEvent implements Log { @@ -62,6 +64,11 @@ public abstract class LocalEventLog { public String getLogString() { throw new AssertionError(); } + + @Override + public boolean filter(String filter) { + return false; + } } /** @@ -87,6 +94,11 @@ public abstract class LocalEventLog { public final long getTimeDeltaMs() { return Integer.toUnsignedLong(mTimeDelta); } + + @Override + public boolean filter(String filter) { + return false; + } } // circular buffer of log entries @@ -198,6 +210,17 @@ public abstract class LocalEventLog { } } + /** + * Iterates over the event log, passing each filter-matching log string to the given + * consumer. + */ + public synchronized void iterate(String filter, Consumer consumer) { + LogIterator it = new LogIterator(filter); + while (it.hasNext()) { + consumer.accept(it.next()); + } + } + // returns the index of the first element private int startIndex() { return wrapIndex(mLogEndIndex - mLogSize); @@ -205,12 +228,13 @@ public abstract class LocalEventLog { // returns the index after this one private int incrementIndex(int index) { - return wrapIndex(index + 1); - } - - // returns the index before this one - private int decrementIndex(int index) { - return wrapIndex(index - 1); + if (index == -1) { + return startIndex(); + } else if (index >= 0) { + return wrapIndex(index + 1); + } else { + throw new IllegalArgumentException(); + } } // rolls over the given index if necessary @@ -219,7 +243,9 @@ public abstract class LocalEventLog { return (index % mLog.length + mLog.length) % mLog.length; } - private class LogIterator implements ListIterator { + private class LogIterator implements Iterator { + + private final @Nullable String mFilter; private final long mSystemTimeDeltaMs; @@ -228,10 +254,17 @@ public abstract class LocalEventLog { private int mCount; LogIterator() { + this(null); + } + + LogIterator(@Nullable String filter) { + mFilter = filter; mSystemTimeDeltaMs = System.currentTimeMillis() - SystemClock.elapsedRealtime(); mCurrentRealtimeMs = mStartRealtimeMs; - mIndex = startIndex(); - mCount = 0; + mIndex = -1; + mCount = -1; + + increment(); } @Override @@ -239,75 +272,17 @@ public abstract class LocalEventLog { return mCount < mLogSize; } - @Override - public boolean hasPrevious() { - return mCount > 0; - } - - @Override - // return then increment public String next() { if (!hasNext()) { throw new NoSuchElementException(); } Log log = mLog[mIndex]; - long nextDeltaMs = log.getTimeDeltaMs(); - long realtimeMs = mCurrentRealtimeMs + nextDeltaMs; + long timeMs = mCurrentRealtimeMs + log.getTimeDeltaMs() + mSystemTimeDeltaMs; - // calculate next index, skipping filler events - do { - mCurrentRealtimeMs += nextDeltaMs; - mIndex = incrementIndex(mIndex); - if (++mCount < mLogSize) { - nextDeltaMs = mLog[mIndex].getTimeDeltaMs(); - } - } while (mCount < mLogSize && mLog[mIndex].isFiller()); + increment(); - return getTimePrefix(realtimeMs + mSystemTimeDeltaMs) + log.getLogString(); - } - - @Override - // decrement then return - public String previous() { - Log log; - long currentDeltaMs; - long realtimeMs; - - // calculate previous index, skipping filler events with MAX_TIME_DELTA - do { - if (!hasPrevious()) { - throw new NoSuchElementException(); - } - - mIndex = decrementIndex(mIndex); - mCount--; - - log = mLog[mIndex]; - realtimeMs = mCurrentRealtimeMs; - - if (mCount > 0) { - currentDeltaMs = log.getTimeDeltaMs(); - mCurrentRealtimeMs -= currentDeltaMs; - } - } while (mCount >= 0 && log.isFiller()); - - return getTimePrefix(realtimeMs + mSystemTimeDeltaMs) + log.getLogString(); - } - - @Override - public int nextIndex() { - throw new UnsupportedOperationException(); - } - - @Override - public int previousIndex() { - throw new UnsupportedOperationException(); - } - - @Override - public void add(String s) { - throw new UnsupportedOperationException(); + return getTimePrefix(timeMs) + log.getLogString(); } @Override @@ -315,9 +290,16 @@ public abstract class LocalEventLog { throw new UnsupportedOperationException(); } - @Override - public void set(String s) { - throw new UnsupportedOperationException(); + private void increment() { + long nextDeltaMs = mIndex == -1 ? 0 : mLog[mIndex].getTimeDeltaMs(); + do { + mCurrentRealtimeMs += nextDeltaMs; + mIndex = incrementIndex(mIndex); + if (++mCount < mLogSize) { + nextDeltaMs = mLog[mIndex].getTimeDeltaMs(); + } + } while (mCount < mLogSize && (mLog[mIndex].isFiller() || (mFilter != null + && !mLog[mIndex].filter(mFilter)))); } } } diff --git a/services/core/java/com/android/server/location/injector/LocationEventLog.java b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java similarity index 56% rename from services/core/java/com/android/server/location/injector/LocationEventLog.java rename to services/core/java/com/android/server/location/eventlog/LocationEventLog.java index 8d73518bced14..67060fc2c082a 100644 --- a/services/core/java/com/android/server/location/injector/LocationEventLog.java +++ b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * Copyright (C) 2021 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. @@ -14,24 +14,32 @@ * limitations under the License. */ -package com.android.server.location.injector; +package com.android.server.location.eventlog; import static android.os.PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF; import static android.os.PowerManager.LOCATION_MODE_FOREGROUND_ONLY; import static android.os.PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF; import static android.os.PowerManager.LOCATION_MODE_NO_CHANGE; import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF; +import static android.util.TimeUtils.formatDuration; import static com.android.server.location.LocationManagerService.D; +import static java.lang.Math.max; +import static java.lang.Math.min; +import static java.util.concurrent.TimeUnit.MILLISECONDS; + import android.annotation.Nullable; import android.location.LocationRequest; import android.location.provider.ProviderRequest; import android.location.util.identity.CallerIdentity; import android.os.Build; import android.os.PowerManager.LocationPowerSaveMode; +import android.os.SystemClock; +import android.util.ArrayMap; -import com.android.server.location.eventlog.LocalEventLog; +import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.Preconditions; /** In memory event log for location events. */ public class LocationEventLog extends LocalEventLog { @@ -54,8 +62,39 @@ public class LocationEventLog extends LocalEventLog { private static final int EVENT_PROVIDER_DELIVER_LOCATION = 8; private static final int EVENT_LOCATION_POWER_SAVE_MODE_CHANGE = 9; + @GuardedBy("mAggregateStats") + private final ArrayMap> mAggregateStats; + public LocationEventLog() { super(getLogSize()); + mAggregateStats = new ArrayMap<>(4); + } + + public ArrayMap> copyAggregateStats() { + synchronized (mAggregateStats) { + ArrayMap> copy = new ArrayMap<>( + mAggregateStats); + for (int i = 0; i < copy.size(); i++) { + copy.setValueAt(i, new ArrayMap<>(copy.valueAt(i))); + } + return copy; + } + } + + private AggregateStats getAggregateStats(String provider, String packageName) { + synchronized (mAggregateStats) { + ArrayMap packageMap = mAggregateStats.get(provider); + if (packageMap == null) { + packageMap = new ArrayMap<>(2); + mAggregateStats.put(provider, packageMap); + } + AggregateStats stats = packageMap.get(packageName); + if (stats == null) { + stats = new AggregateStats(); + packageMap.put(packageName, stats); + } + return stats; + } } /** Logs a location enabled/disabled event. */ @@ -77,12 +116,34 @@ public class LocationEventLog extends LocalEventLog { public void logProviderClientRegistered(String provider, CallerIdentity identity, LocationRequest request) { addLogEvent(EVENT_PROVIDER_REGISTER_CLIENT, provider, identity, request); + getAggregateStats(provider, identity.getPackageName()) + .markRequestAdded(request.getIntervalMillis()); } /** Logs a client unregistration for a location provider. */ - public void logProviderClientUnregistered(String provider, - CallerIdentity identity) { + public void logProviderClientUnregistered(String provider, CallerIdentity identity) { addLogEvent(EVENT_PROVIDER_UNREGISTER_CLIENT, provider, identity); + getAggregateStats(provider, identity.getPackageName()).markRequestRemoved(); + } + + /** Logs a client for a location provider entering the active state. */ + public void logProviderClientActive(String provider, CallerIdentity identity) { + getAggregateStats(provider, identity.getPackageName()).markRequestActive(); + } + + /** Logs a client for a location provider leaving the active state. */ + public void logProviderClientInactive(String provider, CallerIdentity identity) { + getAggregateStats(provider, identity.getPackageName()).markRequestInactive(); + } + + /** Logs a client for a location provider entering the foreground state. */ + public void logProviderClientForeground(String provider, CallerIdentity identity) { + getAggregateStats(provider, identity.getPackageName()).markRequestForeground(); + } + + /** Logs a client for a location provider leaving the foreground state. */ + public void logProviderClientBackground(String provider, CallerIdentity identity) { + getAggregateStats(provider, identity.getPackageName()).markRequestBackground(); } /** Logs a change to the provider request for a location provider. */ @@ -143,16 +204,29 @@ public class LocationEventLog extends LocalEventLog { } } - private static class ProviderEnabledEvent extends LogEvent { + private abstract static class ProviderEvent extends LogEvent { + + protected final String mProvider; + + protected ProviderEvent(long timeDelta, String provider) { + super(timeDelta); + mProvider = provider; + } + + @Override + public boolean filter(String filter) { + return mProvider.equals(filter); + } + } + + private static final class ProviderEnabledEvent extends ProviderEvent { - private final String mProvider; private final int mUserId; private final boolean mEnabled; protected ProviderEnabledEvent(long timeDelta, String provider, int userId, boolean enabled) { - super(timeDelta); - mProvider = provider; + super(timeDelta, provider); mUserId = userId; mEnabled = enabled; } @@ -164,14 +238,12 @@ public class LocationEventLog extends LocalEventLog { } } - private static class ProviderMockedEvent extends LogEvent { + private static final class ProviderMockedEvent extends ProviderEvent { - private final String mProvider; private final boolean mMocked; protected ProviderMockedEvent(long timeDelta, String provider, boolean mocked) { - super(timeDelta); - mProvider = provider; + super(timeDelta, provider); mMocked = mocked; } @@ -185,17 +257,15 @@ public class LocationEventLog extends LocalEventLog { } } - private static class ProviderRegisterEvent extends LogEvent { + private static final class ProviderRegisterEvent extends ProviderEvent { - private final String mProvider; private final boolean mRegistered; private final CallerIdentity mIdentity; @Nullable private final LocationRequest mLocationRequest; private ProviderRegisterEvent(long timeDelta, String provider, boolean registered, CallerIdentity identity, @Nullable LocationRequest locationRequest) { - super(timeDelta); - mProvider = provider; + super(timeDelta, provider); mRegistered = registered; mIdentity = identity; mLocationRequest = locationRequest; @@ -212,14 +282,12 @@ public class LocationEventLog extends LocalEventLog { } } - private static class ProviderUpdateEvent extends LogEvent { + private static final class ProviderUpdateEvent extends ProviderEvent { - private final String mProvider; private final ProviderRequest mRequest; private ProviderUpdateEvent(long timeDelta, String provider, ProviderRequest request) { - super(timeDelta); - mProvider = provider; + super(timeDelta, provider); mRequest = request; } @@ -229,14 +297,12 @@ public class LocationEventLog extends LocalEventLog { } } - private static class ProviderReceiveLocationEvent extends LogEvent { + private static final class ProviderReceiveLocationEvent extends ProviderEvent { - private final String mProvider; private final int mNumLocations; private ProviderReceiveLocationEvent(long timeDelta, String provider, int numLocations) { - super(timeDelta); - mProvider = provider; + super(timeDelta, provider); mNumLocations = numLocations; } @@ -246,16 +312,14 @@ public class LocationEventLog extends LocalEventLog { } } - private static class ProviderDeliverLocationEvent extends LogEvent { + private static final class ProviderDeliverLocationEvent extends ProviderEvent { - private final String mProvider; private final int mNumLocations; @Nullable private final CallerIdentity mIdentity; private ProviderDeliverLocationEvent(long timeDelta, String provider, int numLocations, @Nullable CallerIdentity identity) { - super(timeDelta); - mProvider = provider; + super(timeDelta, provider); mNumLocations = numLocations; mIdentity = identity; } @@ -267,7 +331,7 @@ public class LocationEventLog extends LocalEventLog { } } - private static class LocationPowerSaveModeEvent extends LogEvent { + private static final class LocationPowerSaveModeEvent extends LogEvent { @LocationPowerSaveMode private final int mLocationPowerSaveMode; @@ -305,7 +369,7 @@ public class LocationEventLog extends LocalEventLog { } } - private static class LocationEnabledEvent extends LogEvent { + private static final class LocationEnabledEvent extends LogEvent { private final int mUserId; private final boolean mEnabled; @@ -321,4 +385,118 @@ public class LocationEventLog extends LocalEventLog { return "[u" + mUserId + "] location setting " + (mEnabled ? "enabled" : "disabled"); } } + + /** + * Aggregate statistics for a single package under a single provider. + */ + public static final class AggregateStats { + + @GuardedBy("this") + private int mAddedRequestCount; + @GuardedBy("this") + private int mActiveRequestCount; + @GuardedBy("this") + private int mForegroundRequestCount; + + @GuardedBy("this") + private long mFastestIntervalMs = Long.MAX_VALUE; + @GuardedBy("this") + private long mSlowestIntervalMs = 0; + + @GuardedBy("this") + private long mAddedTimeTotalMs; + @GuardedBy("this") + private long mAddedTimeLastUpdateRealtimeMs; + + @GuardedBy("this") + private long mActiveTimeTotalMs; + @GuardedBy("this") + private long mActiveTimeLastUpdateRealtimeMs; + + @GuardedBy("this") + private long mForegroundTimeTotalMs; + @GuardedBy("this") + private long mForegroundTimeLastUpdateRealtimeMs; + + AggregateStats() {} + + synchronized void markRequestAdded(long intervalMillis) { + if (mAddedRequestCount++ == 0) { + mAddedTimeLastUpdateRealtimeMs = SystemClock.elapsedRealtime(); + } + + mFastestIntervalMs = min(intervalMillis, mFastestIntervalMs); + mSlowestIntervalMs = max(intervalMillis, mSlowestIntervalMs); + } + + synchronized void markRequestRemoved() { + updateTotals(); + --mAddedRequestCount; + Preconditions.checkState(mAddedRequestCount >= 0); + + mActiveRequestCount = min(mAddedRequestCount, mActiveRequestCount); + mForegroundRequestCount = min(mAddedRequestCount, mForegroundRequestCount); + } + + synchronized void markRequestActive() { + Preconditions.checkState(mAddedRequestCount > 0); + if (mActiveRequestCount++ == 0) { + mActiveTimeLastUpdateRealtimeMs = SystemClock.elapsedRealtime(); + } + } + + synchronized void markRequestInactive() { + updateTotals(); + --mActiveRequestCount; + Preconditions.checkState(mActiveRequestCount >= 0); + } + + synchronized void markRequestForeground() { + Preconditions.checkState(mAddedRequestCount > 0); + if (mForegroundRequestCount++ == 0) { + mForegroundTimeLastUpdateRealtimeMs = SystemClock.elapsedRealtime(); + } + } + + synchronized void markRequestBackground() { + updateTotals(); + --mForegroundRequestCount; + Preconditions.checkState(mForegroundRequestCount >= 0); + } + + public synchronized void updateTotals() { + if (mAddedRequestCount > 0) { + long realtimeMs = SystemClock.elapsedRealtime(); + mAddedTimeTotalMs += realtimeMs - mAddedTimeLastUpdateRealtimeMs; + mAddedTimeLastUpdateRealtimeMs = realtimeMs; + } + if (mActiveRequestCount > 0) { + long realtimeMs = SystemClock.elapsedRealtime(); + mActiveTimeTotalMs += realtimeMs - mActiveTimeLastUpdateRealtimeMs; + mActiveTimeLastUpdateRealtimeMs = realtimeMs; + } + if (mForegroundRequestCount > 0) { + long realtimeMs = SystemClock.elapsedRealtime(); + mForegroundTimeTotalMs += realtimeMs - mForegroundTimeLastUpdateRealtimeMs; + mForegroundTimeLastUpdateRealtimeMs = realtimeMs; + } + } + + @Override + public synchronized String toString() { + return "min/max interval = " + intervalToString(mFastestIntervalMs) + "/" + + intervalToString(mSlowestIntervalMs) + + ", total/active/foreground duration = " + formatDuration(mAddedTimeTotalMs) + + "/" + formatDuration(mActiveTimeTotalMs) + "/" + + formatDuration(mForegroundTimeTotalMs); + } + + private static String intervalToString(long intervalMs) { + if (intervalMs == LocationRequest.PASSIVE_INTERVAL) { + return "passive"; + } else { + return MILLISECONDS.toSeconds(intervalMs) + "s"; + } + } + } } diff --git a/services/core/java/com/android/server/location/injector/Injector.java b/services/core/java/com/android/server/location/injector/Injector.java index 03938b2b8ba2e..0e157c22a32b2 100644 --- a/services/core/java/com/android/server/location/injector/Injector.java +++ b/services/core/java/com/android/server/location/injector/Injector.java @@ -56,7 +56,4 @@ public interface Injector { /** Returns a LocationUsageLogger. */ LocationUsageLogger getLocationUsageLogger(); - - /** Returns a LocationEventLog. */ - LocationEventLog getLocationEventLog(); } diff --git a/services/core/java/com/android/server/location/injector/LocationPowerSaveModeHelper.java b/services/core/java/com/android/server/location/injector/LocationPowerSaveModeHelper.java index 532826a02ab00..cc00d56849917 100644 --- a/services/core/java/com/android/server/location/injector/LocationPowerSaveModeHelper.java +++ b/services/core/java/com/android/server/location/injector/LocationPowerSaveModeHelper.java @@ -24,6 +24,8 @@ import static com.android.server.location.LocationManagerService.TAG; import android.os.PowerManager.LocationPowerSaveMode; import android.util.Log; +import com.android.server.location.eventlog.LocationEventLog; + import java.util.concurrent.CopyOnWriteArrayList; /** diff --git a/services/core/java/com/android/server/location/injector/SystemLocationPowerSaveModeHelper.java b/services/core/java/com/android/server/location/injector/SystemLocationPowerSaveModeHelper.java index 1b74865b268e3..c47a64d6d9a75 100644 --- a/services/core/java/com/android/server/location/injector/SystemLocationPowerSaveModeHelper.java +++ b/services/core/java/com/android/server/location/injector/SystemLocationPowerSaveModeHelper.java @@ -25,6 +25,7 @@ import android.os.PowerSaveState; import com.android.internal.util.Preconditions; import com.android.server.FgThread; import com.android.server.LocalServices; +import com.android.server.location.eventlog.LocationEventLog; import java.util.Objects; import java.util.function.Consumer; diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java index 48a012e57a028..388b5a4dd54eb 100644 --- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java +++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java @@ -89,6 +89,7 @@ import com.android.server.FgThread; import com.android.server.LocalServices; import com.android.server.location.LocationPermissions; import com.android.server.location.LocationPermissions.PermissionLevel; +import com.android.server.location.eventlog.LocationEventLog; import com.android.server.location.fudger.LocationFudger; import com.android.server.location.injector.AlarmHelper; import com.android.server.location.injector.AppForegroundHelper; @@ -96,7 +97,6 @@ import com.android.server.location.injector.AppForegroundHelper.AppForegroundLis import com.android.server.location.injector.AppOpsHelper; import com.android.server.location.injector.Injector; import com.android.server.location.injector.LocationAttributionHelper; -import com.android.server.location.injector.LocationEventLog; import com.android.server.location.injector.LocationPermissionsHelper; import com.android.server.location.injector.LocationPermissionsHelper.LocationPermissionsListener; import com.android.server.location.injector.LocationPowerSaveModeHelper; @@ -323,7 +323,7 @@ public class LocationProviderManager extends + getRequest()); } - mLocationEventLog.logProviderClientRegistered(mName, getIdentity(), super.getRequest()); + mEventLog.logProviderClientRegistered(mName, getIdentity(), super.getRequest()); // initialization order is important as there are ordering dependencies mPermitted = mLocationPermissionsHelper.hasLocationPermissions(mPermissionLevel, @@ -333,6 +333,10 @@ public class LocationProviderManager extends mIsUsingHighPower = isUsingHighPower(); onProviderListenerRegister(); + + if (mForeground) { + mEventLog.logProviderClientForeground(mName, getIdentity()); + } } @GuardedBy("mLock") @@ -344,7 +348,7 @@ public class LocationProviderManager extends onProviderListenerUnregister(); - mLocationEventLog.logProviderClientUnregistered(mName, getIdentity()); + mEventLog.logProviderClientUnregistered(mName, getIdentity()); if (D) { Log.d(TAG, mName + " provider removed registration from " + getIdentity()); @@ -369,6 +373,8 @@ public class LocationProviderManager extends Preconditions.checkState(Thread.holdsLock(mLock)); } + mEventLog.logProviderClientActive(mName, getIdentity()); + if (!getRequest().isHiddenFromAppOps()) { mLocationAttributionHelper.reportLocationStart(getIdentity(), getName(), getKey()); } @@ -389,6 +395,8 @@ public class LocationProviderManager extends } onProviderListenerInactive(); + + mEventLog.logProviderClientInactive(mName, getIdentity()); } /** @@ -524,6 +532,12 @@ public class LocationProviderManager extends mForeground = foreground; + if (mForeground) { + mEventLog.logProviderClientForeground(mName, getIdentity()); + } else { + mEventLog.logProviderClientBackground(mName, getIdentity()); + } + // note that onProviderLocationRequestChanged() is always called return onProviderLocationRequestChanged() || mLocationPowerSaveModeHelper.getLocationPowerSaveMode() @@ -855,7 +869,7 @@ public class LocationProviderManager extends listener.deliverOnLocationChanged(deliverLocationResult, mUseWakeLock ? mWakeLock::release : null); - mLocationEventLog.logProviderDeliveredLocations(mName, locationResult.size(), + mEventLog.logProviderDeliveredLocations(mName, locationResult.size(), getIdentity()); } @@ -1154,7 +1168,7 @@ public class LocationProviderManager extends // we currently don't hold a wakelock for getCurrentLocation deliveries listener.deliverOnLocationChanged(deliverLocationResult, null); - mLocationEventLog.logProviderDeliveredLocations(mName, + mEventLog.logProviderDeliveredLocations(mName, locationResult != null ? locationResult.size() : 0, getIdentity()); } @@ -1223,6 +1237,7 @@ public class LocationProviderManager extends private final CopyOnWriteArrayList mProviderRequestListeners; + protected final LocationEventLog mEventLog; protected final LocationManagerInternal mLocationManagerInternal; protected final SettingsHelper mSettingsHelper; protected final UserInfoHelper mUserHelper; @@ -1235,7 +1250,6 @@ public class LocationProviderManager extends protected final LocationAttributionHelper mLocationAttributionHelper; protected final LocationUsageLogger mLocationUsageLogger; protected final LocationFudger mLocationFudger; - protected final LocationEventLog mLocationEventLog; private final UserListener mUserChangedListener = this::onUserChanged; private final UserSettingChangedListener mLocationEnabledChangedListener = @@ -1273,8 +1287,8 @@ public class LocationProviderManager extends @GuardedBy("mLock") private @Nullable OnAlarmListener mDelayedRegister; - public LocationProviderManager(Context context, Injector injector, String name, - @Nullable PassiveLocationProviderManager passiveManager) { + public LocationProviderManager(Context context, Injector injector, LocationEventLog eventLog, + String name, @Nullable PassiveLocationProviderManager passiveManager) { mContext = context; mName = Objects.requireNonNull(name); mPassiveManager = passiveManager; @@ -1285,6 +1299,7 @@ public class LocationProviderManager extends mEnabledListeners = new ArrayList<>(); mProviderRequestListeners = new CopyOnWriteArrayList<>(); + mEventLog = eventLog; mLocationManagerInternal = Objects.requireNonNull( LocalServices.getService(LocationManagerInternal.class)); mSettingsHelper = injector.getSettingsHelper(); @@ -1297,7 +1312,6 @@ public class LocationProviderManager extends mScreenInteractiveHelper = injector.getScreenInteractiveHelper(); mLocationAttributionHelper = injector.getLocationAttributionHelper(); mLocationUsageLogger = injector.getLocationUsageLogger(); - mLocationEventLog = injector.getLocationEventLog(); mLocationFudger = new LocationFudger(mSettingsHelper.getCoarseLocationAccuracyM()); mProvider = new MockableLocationProvider(mLock); @@ -1437,7 +1451,7 @@ public class LocationProviderManager extends synchronized (mLock) { Preconditions.checkState(mState != STATE_STOPPED); - mLocationEventLog.logProviderMocked(mName, provider != null); + mEventLog.logProviderMocked(mName, provider != null); final long identity = Binder.clearCallingIdentity(); try { @@ -1925,7 +1939,7 @@ public class LocationProviderManager extends @GuardedBy("mLock") private void setProviderRequest(ProviderRequest request) { - mLocationEventLog.logProviderUpdateRequest(mName, request); + mEventLog.logProviderUpdateRequest(mName, request); mProvider.getController().setRequest(request); FgThread.getHandler().post(() -> { @@ -2261,7 +2275,7 @@ public class LocationProviderManager extends } // don't log location received for passive provider because it's spammy - mLocationEventLog.logProviderReceivedLocations(mName, filtered.size()); + mEventLog.logProviderReceivedLocations(mName, filtered.size()); } else { // passive provider should get already filtered results as input filtered = locationResult; @@ -2361,7 +2375,7 @@ public class LocationProviderManager extends if (D) { Log.d(TAG, "[u" + userId + "] " + mName + " provider enabled = " + enabled); } - mLocationEventLog.logProviderEnabled(mName, userId, enabled); + mEventLog.logProviderEnabled(mName, userId, enabled); } // clear last locations if we become disabled diff --git a/services/core/java/com/android/server/location/provider/PassiveLocationProviderManager.java b/services/core/java/com/android/server/location/provider/PassiveLocationProviderManager.java index b35af4f6475c1..027f4e94f55bc 100644 --- a/services/core/java/com/android/server/location/provider/PassiveLocationProviderManager.java +++ b/services/core/java/com/android/server/location/provider/PassiveLocationProviderManager.java @@ -24,6 +24,7 @@ import android.location.provider.ProviderRequest; import android.os.Binder; import com.android.internal.util.Preconditions; +import com.android.server.location.eventlog.LocationEventLog; import com.android.server.location.injector.Injector; import java.util.Collection; @@ -33,8 +34,9 @@ import java.util.Collection; */ public class PassiveLocationProviderManager extends LocationProviderManager { - public PassiveLocationProviderManager(Context context, Injector injector) { - super(context, injector, LocationManager.PASSIVE_PROVIDER, null); + public PassiveLocationProviderManager(Context context, Injector injector, + LocationEventLog eventLog) { + super(context, injector, eventLog, LocationManager.PASSIVE_PROVIDER, null); } @Override diff --git a/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeLocationPowerSaveModeHelper.java b/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeLocationPowerSaveModeHelper.java index 0311920477a13..0597443881971 100644 --- a/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeLocationPowerSaveModeHelper.java +++ b/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeLocationPowerSaveModeHelper.java @@ -19,6 +19,8 @@ package com.android.server.location.injector; import android.os.IPowerManager; import android.os.PowerManager.LocationPowerSaveMode; +import com.android.server.location.eventlog.LocationEventLog; + /** * Version of LocationPowerSaveModeHelper for testing. Power save mode is initialized as "no * change". diff --git a/services/tests/mockingservicestests/src/com/android/server/location/injector/SystemLocationPowerSaveModeHelperTest.java b/services/tests/mockingservicestests/src/com/android/server/location/injector/SystemLocationPowerSaveModeHelperTest.java index c39a77eac23fa..6156ba9359cdd 100644 --- a/services/tests/mockingservicestests/src/com/android/server/location/injector/SystemLocationPowerSaveModeHelperTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/location/injector/SystemLocationPowerSaveModeHelperTest.java @@ -43,6 +43,7 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.server.LocalServices; +import com.android.server.location.eventlog.LocationEventLog; import com.android.server.location.injector.LocationPowerSaveModeHelper.LocationPowerSaveModeChangedListener; import org.junit.After; diff --git a/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java b/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java index 8e5b16e1ee3ac..2822d5c690916 100644 --- a/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java +++ b/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java @@ -16,9 +16,10 @@ package com.android.server.location.injector; +import com.android.server.location.eventlog.LocationEventLog; + public class TestInjector implements Injector { - private final LocationEventLog mLocationEventLog; private final FakeUserInfoHelper mUserInfoHelper; private final FakeAlarmHelper mAlarmHelper; private final FakeAppOpsHelper mAppOpsHelper; @@ -32,14 +33,17 @@ public class TestInjector implements Injector { private final LocationUsageLogger mLocationUsageLogger; public TestInjector() { - mLocationEventLog = new LocationEventLog(); + this(new LocationEventLog()); + } + + public TestInjector(LocationEventLog eventLog) { mUserInfoHelper = new FakeUserInfoHelper(); mAlarmHelper = new FakeAlarmHelper(); mAppOpsHelper = new FakeAppOpsHelper(); mLocationPermissionsHelper = new FakeLocationPermissionsHelper(mAppOpsHelper); mSettingsHelper = new FakeSettingsHelper(); mAppForegroundHelper = new FakeAppForegroundHelper(); - mLocationPowerSaveModeHelper = new FakeLocationPowerSaveModeHelper(mLocationEventLog); + mLocationPowerSaveModeHelper = new FakeLocationPowerSaveModeHelper(eventLog); mScreenInteractiveHelper = new FakeScreenInteractiveHelper(); mLocationAttributionHelper = new LocationAttributionHelper(mAppOpsHelper); mEmergencyHelper = new FakeEmergencyHelper(); @@ -100,9 +104,4 @@ public class TestInjector implements Injector { public LocationUsageLogger getLocationUsageLogger() { return mLocationUsageLogger; } - - @Override - public LocationEventLog getLocationEventLog() { - return mLocationEventLog; - } } diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java index 54fa89a1e24bb..66b037d70a40e 100644 --- a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java @@ -83,6 +83,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.server.FgThread; import com.android.server.LocalServices; +import com.android.server.location.eventlog.LocationEventLog; import com.android.server.location.injector.FakeUserInfoHelper; import com.android.server.location.injector.TestInjector; @@ -159,17 +160,19 @@ public class LocationProviderManagerTest { doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class); doReturn(mWakeLock).when(mPowerManager).newWakeLock(anyInt(), anyString()); - mInjector = new TestInjector(); + LocationEventLog eventLog = new LocationEventLog(); + + mInjector = new TestInjector(eventLog); mInjector.getUserInfoHelper().startUser(OTHER_USER); - mPassive = new PassiveLocationProviderManager(mContext, mInjector); + mPassive = new PassiveLocationProviderManager(mContext, mInjector, eventLog); mPassive.startManager(); mPassive.setRealProvider(new PassiveLocationProvider(mContext)); mProvider = new TestProvider(PROPERTIES, IDENTITY); mProvider.setProviderAllowed(true); - mManager = new LocationProviderManager(mContext, mInjector, NAME, mPassive); + mManager = new LocationProviderManager(mContext, mInjector, eventLog, NAME, mPassive); mManager.startManager(); mManager.setRealProvider(mProvider); }