Adding Location Request History Foreground Tracking
Improving adb shell dumpsys location in light of
Background Location Limits
Bug: 73598719
Test: atest and on-device verification
Change-Id: I0b24d14f1557a36d9162770c9bc7081d9787d0cf
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index fb5fba0..18d5ced 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -424,7 +424,7 @@
Log.d(TAG, "request from uid " + uid + " is now "
+ (foreground ? "foreground" : "background)"));
}
- record.mIsForegroundUid = foreground;
+ record.updateForeground(foreground);
if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
affectedProviders.add(provider);
@@ -1902,7 +1902,17 @@
// Update statistics for historical location requests by package/provider
mRequestStatistics.startRequesting(
- mReceiver.mIdentity.mPackageName, provider, request.getInterval());
+ mReceiver.mIdentity.mPackageName, provider, request.getInterval(),
+ mIsForegroundUid);
+ }
+
+ /**
+ * Method to be called when record changes foreground/background
+ */
+ void updateForeground(boolean isForeground){
+ mIsForegroundUid = isForeground;
+ mRequestStatistics.updateForeground(
+ mReceiver.mIdentity.mPackageName, mProvider, isForeground);
}
/**
diff --git a/services/core/java/com/android/server/location/LocationRequestStatistics.java b/services/core/java/com/android/server/location/LocationRequestStatistics.java
index 264026e..b7934d9 100644
--- a/services/core/java/com/android/server/location/LocationRequestStatistics.java
+++ b/services/core/java/com/android/server/location/LocationRequestStatistics.java
@@ -24,7 +24,8 @@
* @param providerName Name of provider that is requested (e.g. "gps").
* @param intervalMs The interval that is requested in ms.
*/
- public void startRequesting(String packageName, String providerName, long intervalMs) {
+ public void startRequesting(String packageName, String providerName, long intervalMs,
+ boolean isForeground) {
PackageProviderKey key = new PackageProviderKey(packageName, providerName);
PackageStatistics stats = statistics.get(key);
if (stats == null) {
@@ -32,6 +33,7 @@
statistics.put(key, stats);
}
stats.startRequesting(intervalMs);
+ stats.updateForeground(isForeground);
}
/**
@@ -45,9 +47,20 @@
PackageStatistics stats = statistics.get(key);
if (stats != null) {
stats.stopRequesting();
- } else {
- // This shouldn't be a possible code path.
- Log.e(TAG, "Couldn't find package statistics when removing location request.");
+ }
+ }
+
+ /**
+ * Signals that a package possibly switched background/foreground.
+ *
+ * @param packageName Name of package that has stopped requesting locations.
+ * @param providerName Provider that is no longer being requested.
+ */
+ public void updateForeground(String packageName, String providerName, boolean isForeground) {
+ PackageProviderKey key = new PackageProviderKey(packageName, providerName);
+ PackageStatistics stats = statistics.get(key);
+ if (stats != null) {
+ stats.updateForeground(isForeground);
}
}
@@ -103,12 +116,21 @@
// The total time this app has requested location (not including currently running requests).
private long mTotalDurationMs;
+ // Time when this package most recently went to foreground, requesting location. 0 means
+ // not currently in foreground.
+ private long mLastForegroundElapsedTimeMs;
+ // The time this app has requested location (not including currently running requests), while
+ // in foreground.
+ private long mForegroundDurationMs;
+
private PackageStatistics() {
mInitialElapsedTimeMs = SystemClock.elapsedRealtime();
mNumActiveRequests = 0;
mTotalDurationMs = 0;
mFastestIntervalMs = Long.MAX_VALUE;
mSlowestIntervalMs = 0;
+ mForegroundDurationMs = 0;
+ mLastForegroundElapsedTimeMs = 0;
}
private void startRequesting(long intervalMs) {
@@ -127,6 +149,15 @@
mNumActiveRequests++;
}
+ private void updateForeground(boolean isForeground) {
+ long nowElapsedTimeMs = SystemClock.elapsedRealtime();
+ // if previous interval was foreground, accumulate before resetting start
+ if (mLastForegroundElapsedTimeMs != 0) {
+ mForegroundDurationMs += (nowElapsedTimeMs - mLastForegroundElapsedTimeMs);
+ }
+ mLastForegroundElapsedTimeMs = isForeground ? nowElapsedTimeMs : 0;
+ }
+
private void stopRequesting() {
if (mNumActiveRequests <= 0) {
// Shouldn't be a possible code path
@@ -139,6 +170,7 @@
long lastDurationMs
= SystemClock.elapsedRealtime() - mLastActivitationElapsedTimeMs;
mTotalDurationMs += lastDurationMs;
+ updateForeground(false);
}
}
@@ -155,6 +187,18 @@
}
/**
+ * Returns the duration that this request has been active.
+ */
+ public long getForegroundDurationMs() {
+ long currentDurationMs = mForegroundDurationMs;
+ if (mLastForegroundElapsedTimeMs != 0 ) {
+ currentDurationMs
+ += SystemClock.elapsedRealtime() - mLastForegroundElapsedTimeMs;
+ }
+ return currentDurationMs;
+ }
+
+ /**
* Returns the time since the initial request in ms.
*/
public long getTimeSinceFirstRequestMs() {
@@ -193,7 +237,9 @@
}
s.append(": Duration requested ")
.append((getDurationMs() / 1000) / 60)
- .append(" out of the last ")
+ .append(" total, ")
+ .append((getForegroundDurationMs() / 1000) / 60)
+ .append(" foreground, out of the last ")
.append((getTimeSinceFirstRequestMs() / 1000) / 60)
.append(" minutes");
if (isActive()) {
diff --git a/services/tests/servicestests/src/com/android/server/location/LocationRequestStatisticsTest.java b/services/tests/servicestests/src/com/android/server/location/LocationRequestStatisticsTest.java
index 33f604d..c45820e6 100644
--- a/services/tests/servicestests/src/com/android/server/location/LocationRequestStatisticsTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/LocationRequestStatisticsTest.java
@@ -30,7 +30,7 @@
* Tests that adding a single package works correctly.
*/
public void testSinglePackage() {
- mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1);
+ mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1, true);
assertEquals(1, mStatistics.statistics.size());
PackageProviderKey key = mStatistics.statistics.keySet().iterator().next();
@@ -47,9 +47,9 @@
* Tests that adding a single package works correctly when it is stopped and restarted.
*/
public void testSinglePackage_stopAndRestart() {
- mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1);
+ mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1, true);
mStatistics.stopRequesting(PACKAGE1, PROVIDER1);
- mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1);
+ mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1, true);
assertEquals(1, mStatistics.statistics.size());
PackageProviderKey key = mStatistics.statistics.keySet().iterator().next();
@@ -69,8 +69,8 @@
* Tests that adding a single package works correctly when multiple intervals are used.
*/
public void testSinglePackage_multipleIntervals() {
- mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1);
- mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL2);
+ mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1, true);
+ mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL2, true);
assertEquals(1, mStatistics.statistics.size());
PackageProviderKey key = mStatistics.statistics.keySet().iterator().next();
@@ -91,8 +91,8 @@
* Tests that adding a single package works correctly when multiple providers are used.
*/
public void testSinglePackage_multipleProviders() {
- mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1);
- mStatistics.startRequesting(PACKAGE1, PROVIDER2, INTERVAL2);
+ mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1, true);
+ mStatistics.startRequesting(PACKAGE1, PROVIDER2, INTERVAL2, true);
assertEquals(2, mStatistics.statistics.size());
PackageProviderKey key1 = new PackageProviderKey(PACKAGE1, PROVIDER1);
@@ -120,10 +120,10 @@
* Tests that adding multiple packages works correctly.
*/
public void testMultiplePackages() {
- mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1);
- mStatistics.startRequesting(PACKAGE1, PROVIDER2, INTERVAL1);
- mStatistics.startRequesting(PACKAGE1, PROVIDER2, INTERVAL2);
- mStatistics.startRequesting(PACKAGE2, PROVIDER1, INTERVAL1);
+ mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1, true);
+ mStatistics.startRequesting(PACKAGE1, PROVIDER2, INTERVAL1, true);
+ mStatistics.startRequesting(PACKAGE1, PROVIDER2, INTERVAL2, true);
+ mStatistics.startRequesting(PACKAGE2, PROVIDER1, INTERVAL1, true);
assertEquals(3, mStatistics.statistics.size());
PackageProviderKey key1 = new PackageProviderKey(PACKAGE1, PROVIDER1);
@@ -165,11 +165,33 @@
assertFalse(stats3.isActive());
}
+ /**
+ * Tests that switching foreground & background states accmulates time reasonably.
+ */
+ public void testForegroundBackground() {
+ mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1, true);
+ mStatistics.startRequesting(PACKAGE1, PROVIDER2, INTERVAL1, true);
+ mStatistics.startRequesting(PACKAGE2, PROVIDER1, INTERVAL1, false);
+
+ mStatistics.updateForeground(PACKAGE1, PROVIDER2, false);
+ mStatistics.updateForeground(PACKAGE2, PROVIDER1, true);
+
+ mStatistics.stopRequesting(PACKAGE1, PROVIDER1);
+
+ for (PackageStatistics stats : mStatistics.statistics.values()) {
+ verifyStatisticsTimes(stats);
+ }
+ }
+
private void verifyStatisticsTimes(PackageStatistics stats) {
long durationMs = stats.getDurationMs();
+ long foregroundDurationMs = stats.getForegroundDurationMs();
long timeSinceFirstRequestMs = stats.getTimeSinceFirstRequestMs();
long maxDeltaMs = SystemClock.elapsedRealtime() - mStartElapsedRealtimeMs;
+ assertTrue("Duration is too small", durationMs >= 0);
assertTrue("Duration is too large", durationMs <= maxDeltaMs);
+ assertTrue("Foreground Duration is too small", foregroundDurationMs >= 0);
+ assertTrue("Foreground Duration is too large", foregroundDurationMs <= maxDeltaMs);
assertTrue("Time since first request is too large", timeSinceFirstRequestMs <= maxDeltaMs);
}
}