summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xapi/current.txt4
-rw-r--r--core/java/android/app/usage/UsageEvents.java47
-rw-r--r--core/java/android/app/usage/UsageStats.java276
-rw-r--r--core/java/android/app/usage/UsageStatsManager.java5
-rw-r--r--core/proto/android/server/usagestatsservice.proto6
-rw-r--r--core/tests/coretests/src/android/app/usage/UsageStatsTest.java390
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java95
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java20
-rw-r--r--services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java38
-rw-r--r--services/usage/java/com/android/server/usage/AppStandbyController.java8
-rw-r--r--services/usage/java/com/android/server/usage/IntervalStats.java55
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsProto.java36
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsXmlV1.java33
-rw-r--r--services/usage/java/com/android/server/usage/UserUsageStatsService.java84
-rw-r--r--tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java14
15 files changed, 971 insertions, 140 deletions
diff --git a/api/current.txt b/api/current.txt
index 533c70f9221c..5c3562cfd72b 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -7580,6 +7580,8 @@ package android.app.usage {
method public java.lang.String getShortcutId();
method public long getTimeStamp();
field public static final int CONFIGURATION_CHANGE = 5; // 0x5
+ field public static final int FOREGROUND_SERVICE_START = 19; // 0x13
+ field public static final int FOREGROUND_SERVICE_STOP = 20; // 0x14
field public static final int KEYGUARD_HIDDEN = 18; // 0x12
field public static final int KEYGUARD_SHOWN = 17; // 0x11
field public static final int MOVE_TO_BACKGROUND = 2; // 0x2
@@ -7597,9 +7599,11 @@ package android.app.usage {
method public void add(android.app.usage.UsageStats);
method public int describeContents();
method public long getFirstTimeStamp();
+ method public long getLastTimeForegroundServiceUsed();
method public long getLastTimeStamp();
method public long getLastTimeUsed();
method public java.lang.String getPackageName();
+ method public long getTotalTimeForegroundServiceUsed();
method public long getTotalTimeInForeground();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.usage.UsageStats> CREATOR;
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 308b39efc3b1..3a5975aea628 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -50,12 +50,20 @@ public final class UsageEvents implements Parcelable {
public static final int NONE = 0;
/**
- * An event type denoting that a component moved to the foreground.
+ * An event type denoting that an {@link android.app.Activity} moved to the foreground.
+ * This event has a package name and class name associated with it and can be retrieved
+ * using {@link #getPackageName()} and {@link #getClassName()}.
+ * If a package has multiple activities, this event is reported for each activity that moves
+ * to foreground.
*/
public static final int MOVE_TO_FOREGROUND = 1;
/**
- * An event type denoting that a component moved to the background.
+ * An event type denoting that an {@link android.app.Activity} moved to the background.
+ * This event has a package name and class name associated with it and can be retrieved
+ * using {@link #getPackageName()} and {@link #getClassName()}.
+ * If a package has multiple activities, this event is reported for each activity that moves
+ * to background.
*/
public static final int MOVE_TO_BACKGROUND = 2;
@@ -166,10 +174,43 @@ public final class UsageEvents implements Parcelable {
public static final int KEYGUARD_HIDDEN = 18;
/**
+ * An event type denoting start of a foreground service.
+ * This event has a package name and class name associated with it and can be retrieved
+ * using {@link #getPackageName()} and {@link #getClassName()}.
+ * If a package has multiple foreground services, this event is reported for each service
+ * that is started.
+ */
+ public static final int FOREGROUND_SERVICE_START = 19;
+
+ /**
+ * An event type denoting stop of a foreground service.
+ * This event has a package name and class name associated with it and can be retrieved
+ * using {@link #getPackageName()} and {@link #getClassName()}.
+ * If a package has multiple foreground services, this event is reported for each service
+ * that is stopped.
+ */
+ public static final int FOREGROUND_SERVICE_STOP = 20;
+
+ /**
+ * An event type denoting that a foreground service is at started state at beginning of a
+ * time interval.
+ * This is effectively treated as a {@link #FOREGROUND_SERVICE_START}.
+ * {@hide}
+ */
+ public static final int CONTINUING_FOREGROUND_SERVICE = 21;
+
+ /**
+ * An event type denoting that a foreground service is at started state when the stats
+ * rolled-over at the end of a time interval.
+ * {@hide}
+ */
+ public static final int ROLLOVER_FOREGROUND_SERVICE = 22;
+
+ /**
* Keep in sync with the greatest event type value.
* @hide
*/
- public static final int MAX_EVENT_TYPE = 18;
+ public static final int MAX_EVENT_TYPE = 22;
/** @hide */
public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0;
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index 0659a237d522..73426e495037 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -16,6 +16,15 @@
package android.app.usage;
+import static android.app.usage.UsageEvents.Event.CONTINUE_PREVIOUS_DAY;
+import static android.app.usage.UsageEvents.Event.CONTINUING_FOREGROUND_SERVICE;
+import static android.app.usage.UsageEvents.Event.END_OF_DAY;
+import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_START;
+import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_STOP;
+import static android.app.usage.UsageEvents.Event.MOVE_TO_BACKGROUND;
+import static android.app.usage.UsageEvents.Event.MOVE_TO_FOREGROUND;
+import static android.app.usage.UsageEvents.Event.ROLLOVER_FOREGROUND_SERVICE;
+
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.os.Bundle;
@@ -48,19 +57,32 @@ public final class UsageStats implements Parcelable {
public long mEndTimeStamp;
/**
- * Last time used by the user with an explicit action (notification, activity launch).
+ * Last time used by the user with an explicit action (notification, activity launch)
* {@hide}
*/
@UnsupportedAppUsage
public long mLastTimeUsed;
/**
+ * Total time this package's activity is in foreground.
* {@hide}
*/
@UnsupportedAppUsage
public long mTotalTimeInForeground;
/**
+ * Last time foreground service is started.
+ * {@hide}
+ */
+ public long mLastTimeForegroundServiceUsed;
+
+ /**
+ * Total time this package's foreground service is started.
+ * {@hide}
+ */
+ public long mTotalTimeForegroundServiceUsed;
+
+ /**
* {@hide}
*/
@UnsupportedAppUsage
@@ -71,16 +93,36 @@ public final class UsageStats implements Parcelable {
*/
public int mAppLaunchCount;
- /**
+ /** Last activity MOVE_TO_FOREGROUND or MOVE_TO_BACKGROUND event.
* {@hide}
+ * @deprecated use {@link #mLastForegroundActivityEventMap} instead.
*/
@UnsupportedAppUsage
+ @Deprecated
public int mLastEvent;
/**
+ * If an activity is in foreground, it has one entry in this map.
+ * When activity moves to background, it is removed from this map.
+ * Key is activity class name.
+ * Value is last time this activity MOVE_TO_FOREGROUND or MOVE_TO_BACKGROUND event.
+ * {@hide}
+ */
+ public ArrayMap<String, Integer> mLastForegroundActivityEventMap = new ArrayMap<>();
+
+ /**
+ * If a foreground service is started, it has one entry in this map.
+ * When a foreground service is stopped, it is removed from this map.
+ * Key is foreground service class name.
+ * Value is last foreground service FOREGROUND_SERVICE_START ot FOREGROUND_SERVICE_STOP event.
* {@hide}
*/
- public ArrayMap<String, ArrayMap<String, Integer>> mChooserCounts;
+ public ArrayMap<String, Integer> mLastForegroundServiceEventMap = new ArrayMap<>();
+
+ /**
+ * {@hide}
+ */
+ public ArrayMap<String, ArrayMap<String, Integer>> mChooserCounts = new ArrayMap<>();
/**
* {@hide}
@@ -93,10 +135,14 @@ public final class UsageStats implements Parcelable {
mBeginTimeStamp = stats.mBeginTimeStamp;
mEndTimeStamp = stats.mEndTimeStamp;
mLastTimeUsed = stats.mLastTimeUsed;
+ mLastTimeForegroundServiceUsed = stats.mLastTimeForegroundServiceUsed;
mTotalTimeInForeground = stats.mTotalTimeInForeground;
+ mTotalTimeForegroundServiceUsed = stats.mTotalTimeForegroundServiceUsed;
mLaunchCount = stats.mLaunchCount;
mAppLaunchCount = stats.mAppLaunchCount;
mLastEvent = stats.mLastEvent;
+ mLastForegroundActivityEventMap = stats.mLastForegroundActivityEventMap;
+ mLastForegroundServiceEventMap = stats.mLastForegroundServiceEventMap;
mChooserCounts = stats.mChooserCounts;
}
@@ -136,7 +182,7 @@ public final class UsageStats implements Parcelable {
}
/**
- * Get the last time this package was used, measured in milliseconds since the epoch.
+ * Get the last time this package's activity was used, measured in milliseconds since the epoch.
* <p/>
* See {@link System#currentTimeMillis()}.
*/
@@ -152,6 +198,23 @@ public final class UsageStats implements Parcelable {
}
/**
+ * Get the last time this package's foreground service was used, measured in milliseconds since
+ * the epoch.
+ * <p/>
+ * See {@link System#currentTimeMillis()}.
+ */
+ public long getLastTimeForegroundServiceUsed() {
+ return mLastTimeForegroundServiceUsed;
+ }
+
+ /**
+ * Get the total time this package's foreground services are started, measured in milliseconds.
+ */
+ public long getTotalTimeForegroundServiceUsed() {
+ return mTotalTimeForegroundServiceUsed;
+ }
+
+ /**
* Returns the number of times the app was launched as an activity from outside of the app.
* Excludes intra-app activity transitions.
* @hide
@@ -161,6 +224,19 @@ public final class UsageStats implements Parcelable {
return mAppLaunchCount;
}
+ private void mergeEventMap(ArrayMap<String, Integer> left, ArrayMap<String, Integer> right) {
+ final int size = right.size();
+ for (int i = 0; i < size; i++) {
+ final String className = right.keyAt(i);
+ final Integer event = right.valueAt(i);
+ if (left.containsKey(className)) {
+ left.put(className, Math.max(left.get(className), event));
+ } else {
+ left.put(className, event);
+ }
+ }
+ }
+
/**
* Add the statistics from the right {@link UsageStats} to the left. The package name for
* both {@link UsageStats} objects must be the same.
@@ -179,12 +255,16 @@ public final class UsageStats implements Parcelable {
if (right.mBeginTimeStamp > mBeginTimeStamp) {
// Even though incoming UsageStat begins after this one, its last time used fields
// may somehow be empty or chronologically preceding the older UsageStat.
- mLastEvent = Math.max(mLastEvent, right.mLastEvent);
+ mergeEventMap(mLastForegroundActivityEventMap, right.mLastForegroundActivityEventMap);
+ mergeEventMap(mLastForegroundServiceEventMap, right.mLastForegroundServiceEventMap);
mLastTimeUsed = Math.max(mLastTimeUsed, right.mLastTimeUsed);
+ mLastTimeForegroundServiceUsed = Math.max(mLastTimeForegroundServiceUsed,
+ right.mLastTimeForegroundServiceUsed);
}
mBeginTimeStamp = Math.min(mBeginTimeStamp, right.mBeginTimeStamp);
mEndTimeStamp = Math.max(mEndTimeStamp, right.mEndTimeStamp);
mTotalTimeInForeground += right.mTotalTimeInForeground;
+ mTotalTimeForegroundServiceUsed += right.mTotalTimeForegroundServiceUsed;
mLaunchCount += right.mLaunchCount;
mAppLaunchCount += right.mAppLaunchCount;
if (mChooserCounts == null) {
@@ -209,6 +289,161 @@ public final class UsageStats implements Parcelable {
}
}
+ /**
+ * Tell if an event indicate activity is in foreground or not.
+ * @param event the activity event.
+ * @return true if activity is in foreground, false otherwise.
+ * @hide
+ */
+ private boolean isActivityInForeground(int event) {
+ return event == MOVE_TO_FOREGROUND
+ || event == CONTINUE_PREVIOUS_DAY;
+ }
+
+ /**
+ * Tell if an event indicate foreground sevice is started or not.
+ * @param event the foreground service event.
+ * @return true if foreground service is started, false if stopped.
+ * @hide
+ */
+ private boolean isForegroundServiceStarted(int event) {
+ return event == FOREGROUND_SERVICE_START
+ || event == CONTINUING_FOREGROUND_SERVICE;
+ }
+
+ /**
+ * If any activity in foreground or any foreground service is started, the app is considered in
+ * use.
+ * @return true if in use, false otherwise.
+ * @hide
+ */
+ private boolean isAppInUse() {
+ return !mLastForegroundActivityEventMap.isEmpty()
+ || !mLastForegroundServiceEventMap.isEmpty();
+ }
+
+ /**
+ * Update by an event of an activity.
+ * @param className className of the activity.
+ * @param timeStamp timeStamp of the event.
+ * @param eventType type of the event.
+ * @hide
+ */
+ private void updateForegroundActivity(String className, long timeStamp, int eventType) {
+ if (eventType != MOVE_TO_BACKGROUND
+ && eventType != MOVE_TO_FOREGROUND
+ && eventType != END_OF_DAY) {
+ return;
+ }
+
+ final Integer lastEvent = mLastForegroundActivityEventMap.get(className);
+ if (lastEvent != null) {
+ if (isActivityInForeground(lastEvent)) {
+ if (timeStamp > mLastTimeUsed) {
+ mTotalTimeInForeground += timeStamp - mLastTimeUsed;
+ mLastTimeUsed = timeStamp;
+ }
+ }
+ if (eventType == MOVE_TO_BACKGROUND) {
+ mLastForegroundActivityEventMap.remove(className);
+ } else {
+ mLastForegroundActivityEventMap.put(className, eventType);
+ }
+ } else if (eventType == MOVE_TO_FOREGROUND) {
+ if (!isAppInUse()) {
+ mLastTimeUsed = timeStamp;
+ }
+ mLastForegroundActivityEventMap.put(className, eventType);
+ }
+ }
+
+ /**
+ * Update by an event of an foreground service.
+ * @param className className of the foreground service.
+ * @param timeStamp timeStamp of the event.
+ * @param eventType type of the event.
+ * @hide
+ */
+ private void updateForegroundService(String className, long timeStamp, int eventType) {
+ if (eventType != FOREGROUND_SERVICE_STOP
+ && eventType != FOREGROUND_SERVICE_START
+ && eventType != ROLLOVER_FOREGROUND_SERVICE) {
+ return;
+ }
+ final Integer lastEvent = mLastForegroundServiceEventMap.get(className);
+ if (lastEvent != null) {
+ if (isForegroundServiceStarted(lastEvent)) {
+ if (timeStamp > mLastTimeForegroundServiceUsed) {
+ mTotalTimeForegroundServiceUsed +=
+ timeStamp - mLastTimeForegroundServiceUsed;
+ mLastTimeForegroundServiceUsed = timeStamp;
+ }
+ }
+ if (eventType == FOREGROUND_SERVICE_STOP) {
+ mLastForegroundServiceEventMap.remove(className);
+ } else {
+ mLastForegroundServiceEventMap.put(className, eventType);
+ }
+ } else if (eventType == FOREGROUND_SERVICE_START) {
+ if (!isAppInUse()) {
+ mLastTimeForegroundServiceUsed = timeStamp;
+ }
+ mLastForegroundServiceEventMap.put(className, eventType);
+ }
+ }
+
+ /**
+ * Update the UsageStats by a activity or foreground service event.
+ * @param className class name of a activity or foreground service, could be null to mark
+ * END_OF_DAY or rollover.
+ * @param timeStamp Epoch timestamp in milliseconds.
+ * @param eventType event type as in {@link UsageEvents.Event}
+ * @hide
+ */
+ public void update(String className, long timeStamp, int eventType) {
+ switch(eventType) {
+ case MOVE_TO_BACKGROUND:
+ case MOVE_TO_FOREGROUND:
+ updateForegroundActivity(className, timeStamp, eventType);
+ break;
+ case END_OF_DAY:
+ // END_OF_DAY means updating all activities.
+ final int size = mLastForegroundActivityEventMap.size();
+ for (int i = 0; i < size; i++) {
+ final String name = mLastForegroundActivityEventMap.keyAt(i);
+ updateForegroundActivity(name, timeStamp, eventType);
+ }
+ break;
+ case CONTINUE_PREVIOUS_DAY:
+ mLastTimeUsed = timeStamp;
+ mLastForegroundActivityEventMap.put(className, eventType);
+ break;
+ case FOREGROUND_SERVICE_STOP:
+ case FOREGROUND_SERVICE_START:
+ updateForegroundService(className, timeStamp, eventType);
+ break;
+ case ROLLOVER_FOREGROUND_SERVICE:
+ // ROLLOVER_FOREGROUND_SERVICE means updating all foreground services.
+ final int size2 = mLastForegroundServiceEventMap.size();
+ for (int i = 0; i < size2; i++) {
+ final String name = mLastForegroundServiceEventMap.keyAt(i);
+ updateForegroundService(name, timeStamp, eventType);
+ }
+ break;
+ case CONTINUING_FOREGROUND_SERVICE:
+ mLastTimeForegroundServiceUsed = timeStamp;
+ mLastForegroundServiceEventMap.put(className, eventType);
+ break;
+ default:
+ break;
+ }
+ mEndTimeStamp = timeStamp;
+
+ if (eventType == MOVE_TO_FOREGROUND) {
+ mLaunchCount += 1;
+ }
+ }
+
@Override
public int describeContents() {
return 0;
@@ -220,7 +455,9 @@ public final class UsageStats implements Parcelable {
dest.writeLong(mBeginTimeStamp);
dest.writeLong(mEndTimeStamp);
dest.writeLong(mLastTimeUsed);
+ dest.writeLong(mLastTimeForegroundServiceUsed);
dest.writeLong(mTotalTimeInForeground);
+ dest.writeLong(mTotalTimeForegroundServiceUsed);
dest.writeInt(mLaunchCount);
dest.writeInt(mAppLaunchCount);
dest.writeInt(mLastEvent);
@@ -239,6 +476,22 @@ public final class UsageStats implements Parcelable {
}
}
dest.writeBundle(allCounts);
+
+ final Bundle foregroundActivityEventBundle = new Bundle();
+ final int foregroundEventSize = mLastForegroundActivityEventMap.size();
+ for (int i = 0; i < foregroundEventSize; i++) {
+ foregroundActivityEventBundle.putInt(mLastForegroundActivityEventMap.keyAt(i),
+ mLastForegroundActivityEventMap.valueAt(i));
+ }
+ dest.writeBundle(foregroundActivityEventBundle);
+
+ final Bundle foregroundServiceEventBundle = new Bundle();
+ final int foregroundServiceEventSize = mLastForegroundServiceEventMap.size();
+ for (int i = 0; i < foregroundServiceEventSize; i++) {
+ foregroundServiceEventBundle.putInt(mLastForegroundServiceEventMap.keyAt(i),
+ mLastForegroundServiceEventMap.valueAt(i));
+ }
+ dest.writeBundle(foregroundServiceEventBundle);
}
public static final Creator<UsageStats> CREATOR = new Creator<UsageStats>() {
@@ -249,7 +502,9 @@ public final class UsageStats implements Parcelable {
stats.mBeginTimeStamp = in.readLong();
stats.mEndTimeStamp = in.readLong();
stats.mLastTimeUsed = in.readLong();
+ stats.mLastTimeForegroundServiceUsed = in.readLong();
stats.mTotalTimeInForeground = in.readLong();
+ stats.mTotalTimeForegroundServiceUsed = in.readLong();
stats.mLaunchCount = in.readInt();
stats.mAppLaunchCount = in.readInt();
stats.mLastEvent = in.readInt();
@@ -272,9 +527,20 @@ public final class UsageStats implements Parcelable {
}
}
}
+ readBundleToEventMap(stats.mLastForegroundActivityEventMap, in.readBundle());
+ readBundleToEventMap(stats.mLastForegroundServiceEventMap, in.readBundle());
return stats;
}
+ private void readBundleToEventMap(ArrayMap<String, Integer> eventMap, Bundle bundle) {
+ if (bundle != null) {
+ for (String className : bundle.keySet()) {
+ final int event = bundle.getInt(className);
+ eventMap.put(className, event);
+ }
+ }
+ }
+
@Override
public UsageStats[] newArray(int size) {
return new UsageStats[size];
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 6d7400e0ef73..55148511ed10 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -192,7 +192,10 @@ public final class UsageStatsManager {
public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE = 0x000C;
/** @hide */
public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_START = 0x000D;
-
+ /** @hide */
+ public static final int REASON_SUB_USAGE_FOREGROUND_SERVICE_START = 0x000E;
+ /** @hide */
+ public static final int REASON_SUB_USAGE_FOREGROUND_SERVICE_STOP = 0x000F;
/** @hide */
public static final int REASON_SUB_PREDICTED_RESTORED = 0x0001;
diff --git a/core/proto/android/server/usagestatsservice.proto b/core/proto/android/server/usagestatsservice.proto
index 941c81fbb8df..3d60a86d86c9 100644
--- a/core/proto/android/server/usagestatsservice.proto
+++ b/core/proto/android/server/usagestatsservice.proto
@@ -45,11 +45,15 @@ message IntervalStatsProto {
optional string package = 1;
// package_index contains the index + 1 of the package name in the string pool
optional int32 package_index = 2;
+ // Time attributes stored as an offset of the IntervalStats's beginTime.
optional int64 last_time_active_ms = 3;
optional int64 total_time_active_ms = 4;
optional int32 last_event = 5;
optional int32 app_launch_count = 6;
repeated ChooserAction chooser_actions = 7;
+ // Time attributes stored as an offset of the IntervalStats's beginTime.
+ optional int64 last_time_service_used_ms = 8;
+ optional int64 total_time_service_used_ms = 9;
}
// Stores the relevant information an IntervalStats will have about a Configuration
@@ -86,6 +90,8 @@ message IntervalStatsProto {
// stringpool contains all the package and class names used by UsageStats and Event
// They will hold a number that is equal to the index + 1 of their string in the pool
optional StringPool stringpool = 2;
+ optional int32 major_version = 3;
+ optional int32 minor_version = 4;
// The following fields contain aggregated usage stats data
optional CountAndTime interactive = 10;
diff --git a/core/tests/coretests/src/android/app/usage/UsageStatsTest.java b/core/tests/coretests/src/android/app/usage/UsageStatsTest.java
index c6d077dee18f..1f047f9e6d10 100644
--- a/core/tests/coretests/src/android/app/usage/UsageStatsTest.java
+++ b/core/tests/coretests/src/android/app/usage/UsageStatsTest.java
@@ -16,8 +16,19 @@
package android.app.usage;
-import static com.google.common.truth.Truth.assertThat;
+import static android.app.usage.UsageEvents.Event.CONTINUE_PREVIOUS_DAY;
+import static android.app.usage.UsageEvents.Event.CONTINUING_FOREGROUND_SERVICE;
+import static android.app.usage.UsageEvents.Event.END_OF_DAY;
+import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_START;
+import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_STOP;
+import static android.app.usage.UsageEvents.Event.MOVE_TO_BACKGROUND;
+import static android.app.usage.UsageEvents.Event.MOVE_TO_FOREGROUND;
+import static android.app.usage.UsageEvents.Event.ROLLOVER_FOREGROUND_SERVICE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import android.os.Parcel;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -46,7 +57,7 @@ public class UsageStatsTest {
left.add(right);
- assertThat(left.getFirstTimeStamp()).isEqualTo(99999);
+ assertEquals(left.getFirstTimeStamp(), 99999);
}
@Test
@@ -58,7 +69,7 @@ public class UsageStatsTest {
left.add(right);
- assertThat(left.getLastTimeStamp()).isEqualTo(100001);
+ assertEquals(left.getLastTimeStamp(), 100001);
}
@Test
@@ -72,7 +83,7 @@ public class UsageStatsTest {
left.add(right);
- assertThat(left.getLastTimeUsed()).isEqualTo(200001);
+ assertEquals(left.getLastTimeUsed(), 200001);
}
@Test
@@ -86,7 +97,7 @@ public class UsageStatsTest {
left.add(right);
- assertThat(left.getLastTimeUsed()).isEqualTo(200000);
+ assertEquals(left.getLastTimeUsed(), 200000);
}
@Test
@@ -100,6 +111,373 @@ public class UsageStatsTest {
left.add(right);
- assertThat(left.getTotalTimeInForeground()).isEqualTo(11);
+ assertEquals(left.getTotalTimeInForeground(), 11);
+ }
+
+ @Test
+ public void testParcelable() {
+ left.mPackageName = "com.test";
+ left.mBeginTimeStamp = 100000;
+ left.mTotalTimeInForeground = 10;
+
+ left.mLastForegroundActivityEventMap.put("com.test.activity1", MOVE_TO_FOREGROUND);
+ left.mLastForegroundActivityEventMap.put("com.test.activity2", MOVE_TO_FOREGROUND);
+ left.mLastForegroundServiceEventMap.put("com.test.service1", FOREGROUND_SERVICE_START);
+ left.mLastForegroundServiceEventMap.put("com.test.service2", FOREGROUND_SERVICE_START);
+
+ Parcel p = Parcel.obtain();
+ left.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ right = UsageStats.CREATOR.createFromParcel(p);
+ compareUsageStats(left, right);
+ }
+
+ @Test
+ public void testForegroundActivity() {
+ left.mPackageName = "com.test";
+ left.mBeginTimeStamp = 100000;
+
+ left.update("com.test.activity1", 200000, MOVE_TO_FOREGROUND);
+ assertEquals(left.mLastTimeUsed, 200000);
+ assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"),
+ new Integer(MOVE_TO_FOREGROUND));
+ assertEquals(left.mLaunchCount, 1);
+
+ left.update("com.test.activity1", 350000, MOVE_TO_BACKGROUND);
+ assertEquals(left.mLastTimeUsed, 350000);
+ assertFalse(left.mLastForegroundActivityEventMap.containsKey("com.test.activity1"));
+ assertEquals(left.mTotalTimeInForeground, 350000 - 200000);
+ }
+
+ @Test
+ public void testEvent_CONTINUE_PREVIOUS_DAY() {
+ left.mPackageName = "com.test";
+ left.mBeginTimeStamp = 100000;
+
+ left.update("com.test.activity1", 100000, CONTINUE_PREVIOUS_DAY);
+ assertEquals(left.mLastTimeUsed, 100000);
+ assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"),
+ new Integer(CONTINUE_PREVIOUS_DAY));
+ assertEquals(left.mLaunchCount, 0);
+
+ left.update("com.test.activity1", 350000, MOVE_TO_BACKGROUND);
+ assertEquals(left.mLastTimeUsed, 350000);
+ assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), null);
+ assertEquals(left.mTotalTimeInForeground, 350000 - 100000);
+ }
+
+ @Test
+ public void testEvent_END_OF_DAY() {
+ left.mPackageName = "com.test";
+ left.mBeginTimeStamp = 100000;
+
+ left.update("com.test.activity1", 100000, CONTINUE_PREVIOUS_DAY);
+ assertEquals(left.mLastTimeUsed, 100000);
+ assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"),
+ new Integer(CONTINUE_PREVIOUS_DAY));
+ assertEquals(left.mLaunchCount, 0);
+
+ left.update(null, 350000, END_OF_DAY);
+ assertEquals(left.mLastTimeUsed, 350000);
+ assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"),
+ new Integer(END_OF_DAY));
+ assertEquals(left.mTotalTimeInForeground, 350000 - 100000);
+ }
+
+ @Test
+ public void testForegroundActivityEventSequence() {
+ left.mPackageName = "com.test";
+ left.mBeginTimeStamp = 100000;
+
+ left.update("com.test.activity1", 100000, CONTINUE_PREVIOUS_DAY);
+ assertEquals(left.mLastTimeUsed, 100000);
+ assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"),
+ new Integer(CONTINUE_PREVIOUS_DAY));
+ assertEquals(left.mLaunchCount, 0);
+
+ left.update("com.test.activity1", 350000, MOVE_TO_BACKGROUND);
+ assertEquals(left.mLastTimeUsed, 350000);
+ assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), null);
+ assertEquals(left.mTotalTimeInForeground, 250000 /*350000 - 100000*/);
+
+ left.update("com.test.activity1", 450000, MOVE_TO_FOREGROUND);
+ assertEquals(left.mLastTimeUsed, 450000);
+ assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"),
+ new Integer(MOVE_TO_FOREGROUND));
+ assertEquals(left.mTotalTimeInForeground, 250000);
+
+ left.update("com.test.activity1", 500000, MOVE_TO_BACKGROUND);
+ assertEquals(left.mLastTimeUsed, 500000);
+ assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), null);
+ assertEquals(left.mTotalTimeInForeground, 250000 + 50000 /*500000 - 450000*/);
+ }
+
+ @Test
+ public void testForegroundActivityEventOutOfSequence() {
+ left.mPackageName = "com.test";
+ left.mBeginTimeStamp = 100000;
+
+ left.update("com.test.activity1", 100000, CONTINUE_PREVIOUS_DAY);
+ assertEquals(left.mLastTimeUsed, 100000);
+ assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"),
+ new Integer(CONTINUE_PREVIOUS_DAY));
+ assertEquals(left.mLaunchCount, 0);
+
+ left.update("com.test.activity1", 150000, MOVE_TO_FOREGROUND);
+ assertEquals(left.mLastTimeUsed, 150000);
+ assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"),
+ new Integer(MOVE_TO_FOREGROUND));
+ assertEquals(left.mLaunchCount, 1);
+ assertEquals(left.mTotalTimeInForeground, 50000 /*150000 - 100000*/);
+
+ left.update("com.test.activity1", 200000, MOVE_TO_FOREGROUND);
+ assertEquals(left.mLastTimeUsed, 200000);
+ assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"),
+ new Integer(MOVE_TO_FOREGROUND));
+ assertEquals(left.mLaunchCount, 2);
+ assertEquals(left.mTotalTimeInForeground, 100000);
+
+ left.update("com.test.activity1", 250000, MOVE_TO_BACKGROUND);
+ assertEquals(left.mLastTimeUsed, 250000);
+ assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), null);
+ assertEquals(left.mTotalTimeInForeground, 150000);
+
+ left.update("com.test.activity1", 300000, MOVE_TO_BACKGROUND);
+ assertEquals(left.mLastTimeUsed, 250000);
+ assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), null);
+ assertEquals(left.mTotalTimeInForeground, 150000);
+
+ left.update("com.test.activity1", 350000, MOVE_TO_FOREGROUND);
+ assertEquals(left.mLastTimeUsed, 350000);
+ assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"),
+ new Integer(MOVE_TO_FOREGROUND));
+ assertEquals(left.mTotalTimeInForeground, 150000);
+
+ left.update("com.test.activity1", 400000, END_OF_DAY);
+ assertEquals(left.mLastTimeUsed, 400000);
+ assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"),
+ new Integer(END_OF_DAY));
+ assertEquals(left.mTotalTimeInForeground, 200000);
+ }
+
+ @Test
+ public void testTwoActivityEventSequence() {
+ left.mPackageName = "com.test";
+ left.mBeginTimeStamp = 100000;
+
+ left.update("com.test.activity1", 100000, CONTINUE_PREVIOUS_DAY);
+ left.update("com.test.activity2", 100000, CONTINUE_PREVIOUS_DAY);
+ assertEquals(left.mLastTimeUsed, 100000);
+ assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"),
+ new Integer(CONTINUE_PREVIOUS_DAY));
+ assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity2"),
+ new Integer(CONTINUE_PREVIOUS_DAY));
+ assertEquals(left.mLaunchCount, 0);
+
+ left.update("com.test.activity1", 350000, MOVE_TO_BACKGROUND);
+ assertEquals(left.mLastTimeUsed, 350000);
+ assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), null);
+ assertEquals(left.mTotalTimeInForeground, 250000 /*350000 - 100000*/);
+
+ left.update("com.test.activity2", 450000, MOVE_TO_BACKGROUND);
+ assertEquals(left.mLastTimeUsed, 450000);
+ assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity2"), null);
+ assertEquals(left.mTotalTimeInForeground, 250000 + 100000 /*450000 - 350000*/);
+
+ left.update(null, 500000, END_OF_DAY);
+ assertEquals(left.mLastTimeUsed, 450000);
+ assertEquals(left.mTotalTimeInForeground, 350000);
+ }
+
+ @Test
+ public void testForegroundService() {
+ left.mPackageName = "com.test";
+ left.mBeginTimeStamp = 100000;
+
+ left.update("com.test.service1", 200000, FOREGROUND_SERVICE_START);
+ assertEquals(left.mLastTimeForegroundServiceUsed, 200000);
+ assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"),
+ new Integer(FOREGROUND_SERVICE_START));
+ assertEquals(left.mLaunchCount, 0);
+
+ left.update("com.test.service1", 350000, FOREGROUND_SERVICE_STOP);
+ assertEquals(left.mLastTimeForegroundServiceUsed, 350000);
+ assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"), null);
+ assertEquals(left.mTotalTimeForegroundServiceUsed, 350000 - 200000);
+ }
+
+ @Test
+ public void testEvent_CONTINUING_FOREGROUND_SERVICE() {
+ left.mPackageName = "com.test";
+ left.mBeginTimeStamp = 100000;
+
+ left.update("com.test.service1", 100000, CONTINUING_FOREGROUND_SERVICE);
+ assertEquals(left.mLastTimeForegroundServiceUsed, 100000);
+ assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"),
+ new Integer(CONTINUING_FOREGROUND_SERVICE));
+ assertEquals(left.mLaunchCount, 0);
+
+ left.update("com.test.service1", 350000, FOREGROUND_SERVICE_STOP);
+ assertEquals(left.mLastTimeForegroundServiceUsed, 350000);
+ assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"), null);
+ assertEquals(left.mTotalTimeForegroundServiceUsed, 350000 - 100000);
+ }
+
+ @Test
+ public void testEvent_ROLLOVER_FOREGROUND_SERVICE() {
+ left.mPackageName = "com.test";
+ left.mBeginTimeStamp = 100000;
+
+ left.update("com.test.service1", 100000,
+ CONTINUING_FOREGROUND_SERVICE);
+ assertEquals(left.mLastTimeForegroundServiceUsed, 100000);
+ assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"),
+ new Integer(CONTINUING_FOREGROUND_SERVICE));
+ assertEquals(left.mLaunchCount, 0);
+
+ left.update(null, 350000, ROLLOVER_FOREGROUND_SERVICE);
+ assertEquals(left.mLastTimeForegroundServiceUsed, 350000);
+ assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"),
+ new Integer(ROLLOVER_FOREGROUND_SERVICE));
+ assertEquals(left.mTotalTimeForegroundServiceUsed, 350000 - 100000);
+ }
+
+ @Test
+ public void testForegroundServiceEventSequence() {
+ left.mPackageName = "com.test";
+ left.mBeginTimeStamp = 100000;
+
+ left.update("com.test.service1", 100000,
+ CONTINUING_FOREGROUND_SERVICE);
+ assertEquals(left.mLastTimeForegroundServiceUsed, 100000);
+ assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"),
+ new Integer(CONTINUING_FOREGROUND_SERVICE));
+ assertEquals(left.mLaunchCount, 0);
+
+ left.update("com.test.service1", 350000, FOREGROUND_SERVICE_STOP);
+ assertEquals(left.mLastTimeForegroundServiceUsed, 350000);
+ assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"), null);
+ assertEquals(left.mTotalTimeForegroundServiceUsed, 250000 /*350000 - 100000*/);
+
+ left.update("com.test.service1", 450000, FOREGROUND_SERVICE_START);
+ assertEquals(left.mLastTimeForegroundServiceUsed, 450000);
+ assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"),
+ new Integer(FOREGROUND_SERVICE_START));
+ assertEquals(left.mTotalTimeForegroundServiceUsed, 250000);
+
+ left.update("com.test.service1", 500000, FOREGROUND_SERVICE_STOP);
+ assertEquals(left.mLastTimeForegroundServiceUsed, 500000);
+ assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"), null);
+ assertEquals(left.mTotalTimeForegroundServiceUsed, 250000 + 50000 /*500000 - 450000*/);
+ }
+
+ @Test
+ public void testTwoServiceEventSequence() {
+ left.mPackageName = "com.test";
+ left.mBeginTimeStamp = 100000;
+
+ left.update("com.test.service1", 100000,
+ CONTINUING_FOREGROUND_SERVICE);
+ left.update("com.test.service2", 100000,
+ CONTINUING_FOREGROUND_SERVICE);
+ assertEquals(left.mLastTimeForegroundServiceUsed, 100000);
+ assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"),
+ new Integer(CONTINUING_FOREGROUND_SERVICE));
+ assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service2"),
+ new Integer(CONTINUING_FOREGROUND_SERVICE));
+ assertEquals(left.mLaunchCount, 0);
+
+ left.update("com.test.service1", 350000, FOREGROUND_SERVICE_STOP);
+ assertEquals(left.mLastTimeForegroundServiceUsed, 350000);
+ assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"), null);
+ assertEquals(left.mTotalTimeForegroundServiceUsed, 250000 /*350000 - 100000*/);
+
+ left.update("com.test.service2", 450000, FOREGROUND_SERVICE_STOP);
+ assertEquals(left.mLastTimeForegroundServiceUsed, 450000);
+ assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service2"), null);
+ assertEquals(left.mTotalTimeForegroundServiceUsed, 250000 + 100000 /*450000 - 350000*/);
+
+ left.update(null, 500000, ROLLOVER_FOREGROUND_SERVICE);
+ assertEquals(left.mLastTimeForegroundServiceUsed, 450000);
+ assertEquals(left.mTotalTimeForegroundServiceUsed, 350000);
+ }
+
+ @Test
+ public void testTwoActivityAndTwoServiceEventSequence() {
+ left.mPackageName = "com.test";
+ left.mBeginTimeStamp = 100000;
+
+ left.update("com.test.activity1", 100000, CONTINUE_PREVIOUS_DAY);
+ left.update("com.test.activity2", 100000, CONTINUE_PREVIOUS_DAY);
+ left.update("com.test.service1", 100000,
+ CONTINUING_FOREGROUND_SERVICE);
+ left.update("com.test.service2", 100000,
+ CONTINUING_FOREGROUND_SERVICE);
+ assertEquals(left.mLastTimeUsed, 100000);
+ assertEquals(left.mLastTimeForegroundServiceUsed, 100000);
+ assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"),
+ new Integer(CONTINUE_PREVIOUS_DAY));
+ assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity2"),
+ new Integer(CONTINUE_PREVIOUS_DAY));
+ assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"),
+ new Integer(CONTINUING_FOREGROUND_SERVICE));
+ assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service2"),
+ new Integer(CONTINUING_FOREGROUND_SERVICE));
+ assertEquals(left.mLaunchCount, 0);
+
+ left.update("com.test.activity1", 350000, MOVE_TO_BACKGROUND);
+ assertEquals(left.mLastTimeUsed, 350000);
+ assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity1"), null);
+ assertEquals(left.mTotalTimeInForeground, 250000 /*350000 - 100000*/);
+
+ left.update("com.test.service1", 400000, FOREGROUND_SERVICE_STOP);
+ assertEquals(left.mLastTimeForegroundServiceUsed, 400000);
+ assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service1"), null);
+ assertEquals(left.mTotalTimeForegroundServiceUsed, 300000 /*400000 - 100000*/);
+
+ left.update("com.test.activity2", 450000, MOVE_TO_BACKGROUND);
+ assertEquals(left.mLastTimeUsed, 450000);
+ assertEquals(left.mLastForegroundActivityEventMap.get("com.test.activity2"), null);
+ assertEquals(left.mTotalTimeInForeground, 250000 + 100000 /*450000 - 350000*/);
+
+ left.update("com.test.service2", 500000, FOREGROUND_SERVICE_STOP);
+ assertEquals(left.mLastTimeForegroundServiceUsed, 500000);
+ assertEquals(left.mLastForegroundServiceEventMap.get("com.test.service2"), null);
+ assertEquals(left.mTotalTimeForegroundServiceUsed, 300000 + 100000 /*500000 - 400000*/);
+
+
+ left.update(null, 550000, END_OF_DAY);
+ assertEquals(left.mLastTimeUsed, 450000);
+ assertEquals(left.mTotalTimeInForeground, 350000);
+ left.update(null, 550000, ROLLOVER_FOREGROUND_SERVICE);
+ assertEquals(left.mLastTimeForegroundServiceUsed, 500000);
+ assertEquals(left.mTotalTimeForegroundServiceUsed, 400000);
+ }
+
+ void compareUsageStats(UsageStats us1, UsageStats us2) {
+ assertEquals(us1.mPackageName, us2.mPackageName);
+ assertEquals(us1.mBeginTimeStamp, us2.mBeginTimeStamp);
+ assertEquals(us1.mLastTimeUsed, us2.mLastTimeUsed);
+ assertEquals(us1.mLastTimeForegroundServiceUsed, us2.mLastTimeForegroundServiceUsed);
+ assertEquals(us1.mTotalTimeInForeground, us2.mTotalTimeInForeground);
+ assertEquals(us1.mTotalTimeForegroundServiceUsed, us2.mTotalTimeForegroundServiceUsed);
+ assertEquals(us1.mAppLaunchCount, us2.mAppLaunchCount);
+ assertEquals(us1.mLastForegroundActivityEventMap.size(),
+ us2.mLastForegroundActivityEventMap.size());
+ for (int i = 0; i < us1.mLastForegroundActivityEventMap.size(); i++) {
+ assertEquals(us1.mLastForegroundActivityEventMap.keyAt(i),
+ us2.mLastForegroundActivityEventMap.keyAt(i));
+ assertEquals(us1.mLastForegroundActivityEventMap.valueAt(i),
+ us2.mLastForegroundActivityEventMap.valueAt(i));
+ }
+ assertEquals(us1.mLastForegroundServiceEventMap.size(),
+ us2.mLastForegroundServiceEventMap.size());
+ for (int i = 0; i < us1.mLastForegroundServiceEventMap.size(); i++) {
+ assertEquals(us1.mLastForegroundServiceEventMap.keyAt(i),
+ us2.mLastForegroundServiceEventMap.keyAt(i));
+ assertEquals(us1.mLastForegroundServiceEventMap.valueAt(i),
+ us2.mLastForegroundServiceEventMap.valueAt(i));
+ }
+ assertEquals(us1.mChooserCounts, us2.mChooserCounts);
}
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 2d3912bda9cc..a33ac700ba95 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -17,40 +17,69 @@
package com.android.server.am;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static com.android.server.am.ActivityManagerDebugConfig.*;
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-import java.util.function.Predicate;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKGROUND_CHECK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOREGROUND_SERVICE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE_EXECUTING;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SERVICE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SERVICE_EXECUTING;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityThread;
+import android.app.AppGlobals;
import android.app.AppOpsManager;
+import android.app.IApplicationThread;
+import android.app.IServiceConnection;
+import android.app.Notification;
import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
import android.app.ServiceStartArgs;
+import android.content.ComponentName;
import android.content.ComponentName.WithComponentName;
+import android.content.Context;
import android.content.IIntentSender;
+import android.content.Intent;
import android.content.IntentSender;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
import android.net.Uri;
+import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
import android.os.RemoteCallback;
+import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.TransactionTooLargeException;
+import android.os.UserHandle;
import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.EventLog;
+import android.util.PrintWriterPrinter;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.StatsLog;
+import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
+import android.webkit.WebViewZygote;
import com.android.internal.R;
import com.android.internal.app.procstats.ServiceState;
@@ -64,39 +93,20 @@ import com.android.server.AppStateTracker;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.am.ActivityManagerService.ItemMatcher;
-
-import android.app.ActivityManager;
-import android.app.AppGlobals;
-import android.app.IApplicationThread;
-import android.app.IServiceConnection;
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.util.EventLog;
-import android.util.PrintWriterPrinter;
-import android.util.Slog;
-import android.util.StatsLog;
-import android.util.SparseArray;
-import android.util.TimeUtils;
-import android.util.proto.ProtoOutputStream;
-import android.webkit.WebViewZygote;
import com.android.server.uri.NeededUriGrants;
import com.android.server.wm.ActivityServiceConnectionsHolder;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Predicate;
+
public final class ActiveServices {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActiveServices" : TAG_AM;
private static final String TAG_MU = TAG + POSTFIX_MU;
@@ -1285,6 +1295,7 @@ public final class ActiveServices {
StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED,
r.appInfo.uid, r.shortName,
StatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER);
+ mAm.updateForegroundServiceUsageStats(r.name, r.userId, true);
}
r.postNotification();
if (r.app != null) {
@@ -1334,6 +1345,7 @@ public final class ActiveServices {
StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED,
r.appInfo.uid, r.shortName,
StatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT);
+ mAm.updateForegroundServiceUsageStats(r.name, r.userId, false);
if (r.app != null) {
mAm.updateLruProcessLocked(r.app, false, null);
updateServiceForegroundLocked(r.app, true);
@@ -2797,6 +2809,7 @@ public final class ActiveServices {
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName);
StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.appInfo.uid, r.shortName,
StatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT);
+ mAm.updateForegroundServiceUsageStats(r.name, r.userId, false);
}
r.isForeground = false;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e90d42fa2dce..6c4f6297fc01 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2690,8 +2690,10 @@ public class ActivityManagerService extends IActivityManager.Stub
}
void updateUsageStats(ComponentName activity, int uid, int userId, boolean resumed) {
- if (DEBUG_SWITCH) Slog.d(TAG_SWITCH,
- "updateUsageStats: comp=" + activity + "res=" + resumed);
+ if (DEBUG_SWITCH) {
+ Slog.d(TAG_SWITCH,
+ "updateUsageStats: comp=" + activity + "res=" + resumed);
+ }
final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
StatsLog.write(StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED,
uid, activity.getPackageName(),
@@ -2718,6 +2720,20 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
+ void updateForegroundServiceUsageStats(ComponentName service, int userId, boolean started) {
+ if (DEBUG_SWITCH) {
+ Slog.d(TAG_SWITCH, "updateForegroundServiceUsageStats: comp="
+ + service + "started=" + started);
+ }
+ synchronized (this) {
+ if (mUsageStatsService != null) {
+ mUsageStatsService.reportEvent(service, userId,
+ started ? UsageEvents.Event.FOREGROUND_SERVICE_START
+ : UsageEvents.Event.FOREGROUND_SERVICE_STOP);
+ }
+ }
+ }
+
CompatibilityInfo compatibilityInfoForPackage(ApplicationInfo ai) {
return mAtmInternal.compatibilityInfoForPackage(ai);
}
diff --git a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
index 473682d4d906..bf7f53dd7d8f 100644
--- a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
+++ b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
@@ -16,13 +16,12 @@
package com.android.server.usage;
-import static junit.framework.TestCase.assertNull;
import static junit.framework.TestCase.fail;
import static org.testng.Assert.assertEquals;
import android.app.usage.EventList;
-import android.app.usage.UsageEvents;
+import android.app.usage.UsageEvents.Event;
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManager;
import android.content.Context;
@@ -112,6 +111,8 @@ public class UsageStatsDatabaseTest {
long time = System.currentTimeMillis() - (numberOfEvents*timeProgression);
mIntervalStats = new IntervalStats();
+ mIntervalStats.majorVersion = 7;
+ mIntervalStats.minorVersion = 8;
mIntervalStats.beginTime = time;
mIntervalStats.interactiveTracker.count = 2;
mIntervalStats.interactiveTracker.duration = 111111;
@@ -127,41 +128,39 @@ public class UsageStatsDatabaseTest {
}
for (int i = 0; i < numberOfEvents; i++) {
- UsageEvents.Event event = new UsageEvents.Event();
+ Event event = new Event();
final int packageInt = ((i / 3) % 7);
event.mPackage = "fake.package.name" + packageInt; //clusters of 3 events from 7 "apps"
if (packageInt == 3) {
// Third app is an instant app
- event.mFlags |= UsageEvents.Event.FLAG_IS_PACKAGE_INSTANT_APP;
- } else if (packageInt == 2 || packageInt == 4) {
- event.mClass = ".fake.class.name" + i % 11;
+ event.mFlags |= Event.FLAG_IS_PACKAGE_INSTANT_APP;
}
-
+ event.mClass = ".fake.class.name" + i % 11;
event.mTimeStamp = time;
event.mEventType = i % 19; //"random" event type
switch (event.mEventType) {
- case UsageEvents.Event.CONFIGURATION_CHANGE:
+ case Event.CONFIGURATION_CHANGE:
//empty config,
event.mConfiguration = new Configuration();
break;
- case UsageEvents.Event.SHORTCUT_INVOCATION:
+ case Event.SHORTCUT_INVOCATION:
//"random" shortcut
event.mShortcutId = "shortcut" + (i % 8);
break;
- case UsageEvents.Event.STANDBY_BUCKET_CHANGED:
+ case Event.STANDBY_BUCKET_CHANGED:
//"random" bucket and reason
event.mBucketAndReason = (((i % 5 + 1) * 10) << 16) & (i % 5 + 1) << 8;
break;
- case UsageEvents.Event.NOTIFICATION_INTERRUPTION:
+ case Event.NOTIFICATION_INTERRUPTION:
//"random" channel
event.mNotificationChannelId = "channel" + (i % 5);
break;
}
mIntervalStats.events.insert(event);
- mIntervalStats.update(event.mPackage, event.mTimeStamp, event.mEventType);
+ mIntervalStats.update(event.mPackage, event.mClass, event.mTimeStamp, event.mEventType);
time += timeProgression; // Arbitrary progression of time
}
@@ -221,29 +220,30 @@ public class UsageStatsDatabaseTest {
// mEndTimeStamp is based on the enclosing IntervalStats, don't bother checking
assertEquals(us1.mLastTimeUsed, us2.mLastTimeUsed);
assertEquals(us1.mTotalTimeInForeground, us2.mTotalTimeInForeground);
+ assertEquals(us1.mLastTimeForegroundServiceUsed, us2.mLastTimeForegroundServiceUsed);
+ assertEquals(us1.mTotalTimeForegroundServiceUsed, us2.mTotalTimeForegroundServiceUsed);
// mLaunchCount not persisted, so skipped
assertEquals(us1.mAppLaunchCount, us2.mAppLaunchCount);
- assertEquals(us1.mLastEvent, us2.mLastEvent);
assertEquals(us1.mChooserCounts, us2.mChooserCounts);
}
- void compareUsageEvent(UsageEvents.Event e1, UsageEvents.Event e2, int debugId) {
+ void compareUsageEvent(Event e1, Event e2, int debugId) {
assertEquals(e1.mPackage, e2.mPackage, "Usage event " + debugId);
assertEquals(e1.mClass, e2.mClass, "Usage event " + debugId);
assertEquals(e1.mTimeStamp, e2.mTimeStamp, "Usage event " + debugId);
assertEquals(e1.mEventType, e2.mEventType, "Usage event " + debugId);
switch (e1.mEventType) {
- case UsageEvents.Event.CONFIGURATION_CHANGE:
+ case Event.CONFIGURATION_CHANGE:
assertEquals(e1.mConfiguration, e2.mConfiguration,
"Usage event " + debugId + e2.mConfiguration.toString());
break;
- case UsageEvents.Event.SHORTCUT_INVOCATION:
+ case Event.SHORTCUT_INVOCATION:
assertEquals(e1.mShortcutId, e2.mShortcutId, "Usage event " + debugId);
break;
- case UsageEvents.Event.STANDBY_BUCKET_CHANGED:
+ case Event.STANDBY_BUCKET_CHANGED:
assertEquals(e1.mBucketAndReason, e2.mBucketAndReason, "Usage event " + debugId);
break;
- case UsageEvents.Event.NOTIFICATION_INTERRUPTION:
+ case Event.NOTIFICATION_INTERRUPTION:
assertEquals(e1.mNotificationChannelId, e2.mNotificationChannelId,
"Usage event " + debugId);
break;
@@ -252,6 +252,8 @@ public class UsageStatsDatabaseTest {
}
void compareIntervalStats(IntervalStats stats1, IntervalStats stats2) {
+ assertEquals(stats1.majorVersion, stats2.majorVersion);
+ assertEquals(stats1.minorVersion, stats2.minorVersion);
assertEquals(stats1.beginTime, stats2.beginTime);
assertEquals(stats1.endTime, stats2.endTime);
assertEquals(stats1.interactiveTracker.count, stats2.interactiveTracker.count);
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 4f573a475ae7..152831f50770 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -27,6 +27,8 @@ import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_ACTIVE_TIMEOU
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_START;
+import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_FOREGROUND_SERVICE_START;
+import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_FOREGROUND_SERVICE_STOP;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_BACKGROUND;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_NOTIFICATION_SEEN;
@@ -844,6 +846,8 @@ public class AppStandbyController {
// Inform listeners if necessary
if ((event.mEventType == UsageEvents.Event.MOVE_TO_FOREGROUND
|| event.mEventType == UsageEvents.Event.MOVE_TO_BACKGROUND
+ || event.mEventType == UsageEvents.Event.FOREGROUND_SERVICE_START
+ || event.mEventType == UsageEvents.Event.FOREGROUND_SERVICE_STOP
|| event.mEventType == UsageEvents.Event.SYSTEM_INTERACTION
|| event.mEventType == UsageEvents.Event.USER_INTERACTION
|| event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN
@@ -896,6 +900,10 @@ public class AppStandbyController {
switch (eventType) {
case UsageEvents.Event.MOVE_TO_FOREGROUND: return REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
case UsageEvents.Event.MOVE_TO_BACKGROUND: return REASON_SUB_USAGE_MOVE_TO_BACKGROUND;
+ case UsageEvents.Event.FOREGROUND_SERVICE_START:
+ return REASON_SUB_USAGE_FOREGROUND_SERVICE_START;
+ case UsageEvents.Event.FOREGROUND_SERVICE_STOP:
+ return REASON_SUB_USAGE_FOREGROUND_SERVICE_STOP;
case UsageEvents.Event.SYSTEM_INTERACTION: return REASON_SUB_USAGE_SYSTEM_INTERACTION;
case UsageEvents.Event.USER_INTERACTION: return REASON_SUB_USAGE_USER_INTERACTION;
case UsageEvents.Event.NOTIFICATION_SEEN: return REASON_SUB_USAGE_NOTIFICATION_SEEN;
diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java
index db9972f96b21..84052672f6d3 100644
--- a/services/usage/java/com/android/server/usage/IntervalStats.java
+++ b/services/usage/java/com/android/server/usage/IntervalStats.java
@@ -18,7 +18,6 @@ package com.android.server.usage;
import android.app.usage.ConfigurationStats;
import android.app.usage.EventList;
import android.app.usage.EventStats;
-import android.app.usage.TimeSparseArray;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStats;
import android.content.res.Configuration;
@@ -26,12 +25,16 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.proto.ProtoInputStream;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.io.IOException;
import java.util.List;
-import com.android.internal.annotations.VisibleForTesting;
-
public class IntervalStats {
+ public static final int CURRENT_MAJOR_VERSION = 1;
+ public static final int CURRENT_MINOR_VERSION = 1;
+ public int majorVersion = CURRENT_MAJOR_VERSION;
+ public int minorVersion = CURRENT_MINOR_VERSION;
public long beginTime;
public long endTime;
public long lastTimeSaved;
@@ -219,8 +222,12 @@ public class IntervalStats {
switch (eventType) {
case UsageEvents.Event.MOVE_TO_FOREGROUND:
case UsageEvents.Event.MOVE_TO_BACKGROUND:
+ case UsageEvents.Event.FOREGROUND_SERVICE_START:
+ case UsageEvents.Event.FOREGROUND_SERVICE_STOP:
case UsageEvents.Event.END_OF_DAY:
+ case UsageEvents.Event.ROLLOVER_FOREGROUND_SERVICE:
case UsageEvents.Event.CONTINUE_PREVIOUS_DAY:
+ case UsageEvents.Event.CONTINUING_FOREGROUND_SERVICE:
return true;
}
return false;
@@ -239,32 +246,9 @@ public class IntervalStats {
* @hide
*/
@VisibleForTesting
- public void update(String packageName, long timeStamp, int eventType) {
+ public void update(String packageName, String className, long timeStamp, int eventType) {
UsageStats usageStats = getOrCreateUsageStats(packageName);
-
- // TODO(adamlesinski): Ensure that we recover from incorrect event sequences
- // like double MOVE_TO_BACKGROUND, etc.
- if (eventType == UsageEvents.Event.MOVE_TO_BACKGROUND ||
- eventType == UsageEvents.Event.END_OF_DAY) {
- if (usageStats.mLastEvent == UsageEvents.Event.MOVE_TO_FOREGROUND ||
- usageStats.mLastEvent == UsageEvents.Event.CONTINUE_PREVIOUS_DAY) {
- usageStats.mTotalTimeInForeground += timeStamp - usageStats.mLastTimeUsed;
- }
- }
-
- if (isStatefulEvent(eventType)) {
- usageStats.mLastEvent = eventType;
- }
-
- if (isUserVisibleEvent(eventType)) {
- usageStats.mLastTimeUsed = timeStamp;
- }
- usageStats.mEndTimeStamp = timeStamp;
-
- if (eventType == UsageEvents.Event.MOVE_TO_FOREGROUND) {
- usageStats.mLaunchCount += 1;
- }
-
+ usageStats.update(className, timeStamp, eventType);
endTime = timeStamp;
}
@@ -372,4 +356,19 @@ public class IntervalStats {
}
return mStringCache.valueAt(index);
}
+
+ /**
+ * When an IntervalStats object is deserialized, if the object's version number
+ * is lower than current version number, optionally perform a upgrade.
+ */
+ void upgradeIfNeeded() {
+ // We only uprade on majorVersion change, no need to upgrade on minorVersion change.
+ if (!(majorVersion < CURRENT_MAJOR_VERSION)) {
+ return;
+ }
+ /*
+ Optional upgrade code here.
+ */
+ majorVersion = CURRENT_MAJOR_VERSION;
+ }
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsProto.java b/services/usage/java/com/android/server/usage/UsageStatsProto.java
index 30d303f426bf..8e1c06091605 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsProto.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsProto.java
@@ -21,13 +21,12 @@ import android.app.usage.UsageEvents;
import android.app.usage.UsageStats;
import android.content.res.Configuration;
import android.util.ArrayMap;
-
import android.util.Slog;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoOutputStream;
-import java.io.InputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
import java.net.ProtocolException;
import java.util.ArrayList;
@@ -105,6 +104,7 @@ final class UsageStatsProto {
stats = tempPackageIndex;
break;
case (int) IntervalStatsProto.UsageStats.LAST_TIME_ACTIVE_MS:
+ // Time attributes stored is an offset of the beginTime.
stats.mLastTimeUsed = statsOut.beginTime + proto.readLong(
IntervalStatsProto.UsageStats.LAST_TIME_ACTIVE_MS);
break;
@@ -113,7 +113,8 @@ final class UsageStatsProto {
IntervalStatsProto.UsageStats.TOTAL_TIME_ACTIVE_MS);
break;
case (int) IntervalStatsProto.UsageStats.LAST_EVENT:
- stats.mLastEvent = proto.readInt(IntervalStatsProto.UsageStats.LAST_EVENT);
+ stats.mLastEvent =
+ proto.readInt(IntervalStatsProto.UsageStats.LAST_EVENT);
break;
case (int) IntervalStatsProto.UsageStats.APP_LAUNCH_COUNT:
stats.mAppLaunchCount = proto.readInt(
@@ -125,6 +126,15 @@ final class UsageStatsProto {
loadChooserCounts(proto, stats);
proto.end(chooserToken);
break;
+ case (int) IntervalStatsProto.UsageStats.LAST_TIME_SERVICE_USED_MS:
+ // Time attributes stored is an offset of the beginTime.
+ stats.mLastTimeForegroundServiceUsed = statsOut.beginTime + proto.readLong(
+ IntervalStatsProto.UsageStats.LAST_TIME_SERVICE_USED_MS);
+ break;
+ case (int) IntervalStatsProto.UsageStats.TOTAL_TIME_SERVICE_USED_MS:
+ stats.mTotalTimeForegroundServiceUsed = proto.readLong(
+ IntervalStatsProto.UsageStats.TOTAL_TIME_SERVICE_USED_MS);
+ break;
}
}
if (stats.mLastTimeUsed == 0) {
@@ -315,11 +325,18 @@ final class UsageStatsProto {
+ ") not found in IntervalStats string cache");
proto.write(IntervalStatsProto.UsageStats.PACKAGE, usageStats.mPackageName);
}
+ // Time attributes stored as an offset of the beginTime.
proto.write(IntervalStatsProto.UsageStats.LAST_TIME_ACTIVE_MS,
usageStats.mLastTimeUsed - stats.beginTime);
proto.write(IntervalStatsProto.UsageStats.TOTAL_TIME_ACTIVE_MS,
usageStats.mTotalTimeInForeground);
- proto.write(IntervalStatsProto.UsageStats.LAST_EVENT, usageStats.mLastEvent);
+ proto.write(IntervalStatsProto.UsageStats.LAST_EVENT,
+ usageStats.mLastEvent);
+ // Time attributes stored as an offset of the beginTime.
+ proto.write(IntervalStatsProto.UsageStats.LAST_TIME_SERVICE_USED_MS,
+ usageStats.mLastTimeForegroundServiceUsed - stats.beginTime);
+ proto.write(IntervalStatsProto.UsageStats.TOTAL_TIME_SERVICE_USED_MS,
+ usageStats.mTotalTimeForegroundServiceUsed);
proto.write(IntervalStatsProto.UsageStats.APP_LAUNCH_COUNT, usageStats.mAppLaunchCount);
writeChooserCounts(proto, usageStats);
proto.end(token);
@@ -471,6 +488,14 @@ final class UsageStatsProto {
statsOut.endTime = statsOut.beginTime + proto.readLong(
IntervalStatsProto.END_TIME_MS);
break;
+ case (int) IntervalStatsProto.MAJOR_VERSION:
+ statsOut.majorVersion = proto.readInt(
+ IntervalStatsProto.MAJOR_VERSION);
+ break;
+ case (int) IntervalStatsProto.MINOR_VERSION:
+ statsOut.minorVersion = proto.readInt(
+ IntervalStatsProto.MINOR_VERSION);
+ break;
case (int) IntervalStatsProto.INTERACTIVE:
loadCountAndTime(proto, IntervalStatsProto.INTERACTIVE,
statsOut.interactiveTracker);
@@ -505,6 +530,7 @@ final class UsageStatsProto {
// endTime not assigned, assume default value of 0 plus beginTime
statsOut.endTime = statsOut.beginTime;
}
+ statsOut.upgradeIfNeeded();
return;
}
}
@@ -519,6 +545,8 @@ final class UsageStatsProto {
public static void write(OutputStream out, IntervalStats stats) throws IOException {
final ProtoOutputStream proto = new ProtoOutputStream(out);
proto.write(IntervalStatsProto.END_TIME_MS, stats.endTime - stats.beginTime);
+ proto.write(IntervalStatsProto.MAJOR_VERSION, stats.majorVersion);
+ proto.write(IntervalStatsProto.MINOR_VERSION, stats.minorVersion);
// String pool should be written before the rest of the usage stats
writeStringPool(proto, stats);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
index a68f9d385ca5..d94062002dcd 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
@@ -15,19 +15,18 @@
*/
package com.android.server.usage;
-import com.android.internal.util.XmlUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
import android.app.usage.ConfigurationStats;
-import android.app.usage.EventList;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStats;
import android.content.res.Configuration;
import android.util.ArrayMap;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
import java.io.IOException;
import java.net.ProtocolException;
@@ -61,6 +60,7 @@ final class UsageStatsXmlV1 {
private static final String FLAGS_ATTR = "flags";
private static final String CLASS_ATTR = "class";
private static final String TOTAL_TIME_ACTIVE_ATTR = "timeActive";
+ private static final String TOTAL_TIME_SERVICE_USED_ATTR = "timeServiceUsed";
private static final String COUNT_ATTR = "count";
private static final String ACTIVE_ATTR = "active";
private static final String LAST_EVENT_ATTR = "lastEvent";
@@ -69,9 +69,12 @@ final class UsageStatsXmlV1 {
private static final String STANDBY_BUCKET_ATTR = "standbyBucket";
private static final String APP_LAUNCH_COUNT_ATTR = "appLaunchCount";
private static final String NOTIFICATION_CHANNEL_ATTR = "notificationChannel";
+ private static final String MAJOR_VERSION_ATTR = "majorVersion";
+ private static final String MINOR_VERSION_ATTR = "minorVersion";
// Time attributes stored as an offset of the beginTime.
private static final String LAST_TIME_ACTIVE_ATTR = "lastTimeActive";
+ private static final String LAST_TIME_SERVICE_USED_ATTR = "lastTimeServiceUsed";
private static final String END_TIME_ATTR = "endTime";
private static final String TIME_ATTR = "time";
@@ -86,9 +89,14 @@ final class UsageStatsXmlV1 {
// Apply the offset to the beginTime to find the absolute time.
stats.mLastTimeUsed = statsOut.beginTime + XmlUtils.readLongAttribute(
parser, LAST_TIME_ACTIVE_ATTR);
+ stats.mLastTimeForegroundServiceUsed = statsOut.beginTime + XmlUtils.readLongAttribute(
+ parser, LAST_TIME_SERVICE_USED_ATTR);
stats.mTotalTimeInForeground = XmlUtils.readLongAttribute(parser, TOTAL_TIME_ACTIVE_ATTR);
+ stats.mTotalTimeForegroundServiceUsed = XmlUtils.readLongAttribute(parser,
+ TOTAL_TIME_SERVICE_USED_ATTR);
stats.mLastEvent = XmlUtils.readIntAttribute(parser, LAST_EVENT_ATTR);
- stats.mAppLaunchCount = XmlUtils.readIntAttribute(parser, APP_LAUNCH_COUNT_ATTR, 0);
+ stats.mAppLaunchCount = XmlUtils.readIntAttribute(parser, APP_LAUNCH_COUNT_ATTR,
+ 0);
int eventCode;
while ((eventCode = parser.next()) != XmlPullParser.END_DOCUMENT) {
final String tag = parser.getName();
@@ -206,9 +214,12 @@ final class UsageStatsXmlV1 {
// Write the time offset.
XmlUtils.writeLongAttribute(xml, LAST_TIME_ACTIVE_ATTR,
usageStats.mLastTimeUsed - stats.beginTime);
-
+ XmlUtils.writeLongAttribute(xml, LAST_TIME_SERVICE_USED_ATTR,
+ usageStats.mLastTimeForegroundServiceUsed - stats.beginTime);
XmlUtils.writeStringAttribute(xml, PACKAGE_ATTR, usageStats.mPackageName);
XmlUtils.writeLongAttribute(xml, TOTAL_TIME_ACTIVE_ATTR, usageStats.mTotalTimeInForeground);
+ XmlUtils.writeLongAttribute(xml, TOTAL_TIME_SERVICE_USED_ATTR,
+ usageStats.mTotalTimeForegroundServiceUsed);
XmlUtils.writeIntAttribute(xml, LAST_EVENT_ATTR, usageStats.mLastEvent);
if (usageStats.mAppLaunchCount > 0) {
XmlUtils.writeIntAttribute(xml, APP_LAUNCH_COUNT_ATTR, usageStats.mAppLaunchCount);
@@ -339,6 +350,8 @@ final class UsageStatsXmlV1 {
}
statsOut.endTime = statsOut.beginTime + XmlUtils.readLongAttribute(parser, END_TIME_ATTR);
+ statsOut.majorVersion = XmlUtils.readIntAttribute(parser, MAJOR_VERSION_ATTR);
+ statsOut.minorVersion = XmlUtils.readIntAttribute(parser, MINOR_VERSION_ATTR);
int eventCode;
int outerDepth = parser.getDepth();
@@ -391,6 +404,8 @@ final class UsageStatsXmlV1 {
*/
public static void write(XmlSerializer xml, IntervalStats stats) throws IOException {
XmlUtils.writeLongAttribute(xml, END_TIME_ATTR, stats.endTime - stats.beginTime);
+ XmlUtils.writeIntAttribute(xml, MAJOR_VERSION_ATTR, stats.majorVersion);
+ XmlUtils.writeIntAttribute(xml, MINOR_VERSION_ATTR, stats.minorVersion);
writeCountAndTime(xml, INTERACTIVE_TAG, stats.interactiveTracker.count,
stats.interactiveTracker.duration);
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 1a8aba085d24..32875dab465f 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -22,9 +22,9 @@ import android.app.usage.EventStats;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManager;
+import android.content.Context;
import android.content.res.Configuration;
import android.os.SystemClock;
-import android.content.Context;
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -129,11 +129,17 @@ class UserUsageStatsService {
for (IntervalStats stat : mCurrentStats) {
final int pkgCount = stat.packageStats.size();
for (int i = 0; i < pkgCount; i++) {
- UsageStats pkgStats = stat.packageStats.valueAt(i);
- if (pkgStats.mLastEvent == UsageEvents.Event.MOVE_TO_FOREGROUND ||
- pkgStats.mLastEvent == UsageEvents.Event.CONTINUE_PREVIOUS_DAY) {
- stat.update(pkgStats.mPackageName, stat.lastTimeSaved,
- UsageEvents.Event.END_OF_DAY);
+ final UsageStats pkgStats = stat.packageStats.valueAt(i);
+ if (!pkgStats.mLastForegroundActivityEventMap.isEmpty()
+ || !pkgStats.mLastForegroundServiceEventMap.isEmpty()) {
+ if (!pkgStats.mLastForegroundActivityEventMap.isEmpty()) {
+ stat.update(pkgStats.mPackageName, null, stat.lastTimeSaved,
+ UsageEvents.Event.END_OF_DAY);
+ }
+ if (!pkgStats.mLastForegroundServiceEventMap.isEmpty()) {
+ stat.update(pkgStats.mPackageName, null , stat.lastTimeSaved,
+ UsageEvents.Event.ROLLOVER_FOREGROUND_SERVICE);
+ }
notifyStatsChanged();
}
}
@@ -218,7 +224,8 @@ class UserUsageStatsService {
stats.updateKeyguardHidden(event.mTimeStamp);
} break;
default: {
- stats.update(event.mPackage, event.mTimeStamp, event.mEventType);
+ stats.update(event.mPackage, event.getClassName(),
+ event.mTimeStamp, event.mEventType);
if (incrementAppLaunch) {
stats.incrementAppLaunchCount(event.mPackage);
}
@@ -481,25 +488,43 @@ class UserUsageStatsService {
final long startTime = SystemClock.elapsedRealtime();
Slog.i(TAG, mLogPrefix + "Rolling over usage stats");
- // Finish any ongoing events with an END_OF_DAY event. Make a note of which components
- // need a new CONTINUE_PREVIOUS_DAY entry.
+ // Finish any ongoing events with an END_OF_DAY or ROLLOVER_FOREGROUND_SERVICE event.
+ // Make a note of which components need a new CONTINUE_PREVIOUS_DAY or
+ // CONTINUING_FOREGROUND_SERVICE entry.
final Configuration previousConfig =
mCurrentStats[UsageStatsManager.INTERVAL_DAILY].activeConfiguration;
ArraySet<String> continuePreviousDay = new ArraySet<>();
+ ArrayMap<String, ArrayMap<String, Integer>> continuePreviousDayForegroundActivity =
+ new ArrayMap<>();
+ ArrayMap<String, ArrayMap<String, Integer>> continuePreviousDayForegroundService =
+ new ArrayMap<>();
for (IntervalStats stat : mCurrentStats) {
final int pkgCount = stat.packageStats.size();
for (int i = 0; i < pkgCount; i++) {
- UsageStats pkgStats = stat.packageStats.valueAt(i);
- if (pkgStats.mLastEvent == UsageEvents.Event.MOVE_TO_FOREGROUND ||
- pkgStats.mLastEvent == UsageEvents.Event.CONTINUE_PREVIOUS_DAY) {
+ final UsageStats pkgStats = stat.packageStats.valueAt(i);
+ if (!pkgStats.mLastForegroundActivityEventMap.isEmpty()
+ || !pkgStats.mLastForegroundServiceEventMap.isEmpty()) {
+ if (!pkgStats.mLastForegroundActivityEventMap.isEmpty()) {
+ continuePreviousDayForegroundActivity.put(pkgStats.mPackageName,
+ pkgStats.mLastForegroundActivityEventMap);
+ stat.update(pkgStats.mPackageName, null,
+ mDailyExpiryDate.getTimeInMillis() - 1,
+ UsageEvents.Event.END_OF_DAY);
+ }
+ if (!pkgStats.mLastForegroundServiceEventMap.isEmpty()) {
+ continuePreviousDayForegroundService.put(pkgStats.mPackageName,
+ pkgStats.mLastForegroundServiceEventMap);
+ stat.update(pkgStats.mPackageName, null,
+ mDailyExpiryDate.getTimeInMillis() - 1,
+ UsageEvents.Event.ROLLOVER_FOREGROUND_SERVICE);
+ }
continuePreviousDay.add(pkgStats.mPackageName);
- stat.update(pkgStats.mPackageName, mDailyExpiryDate.getTimeInMillis() - 1,
- UsageEvents.Event.END_OF_DAY);
notifyStatsChanged();
}
}
- stat.updateConfigurationStats(null, mDailyExpiryDate.getTimeInMillis() - 1);
+ stat.updateConfigurationStats(null,
+ mDailyExpiryDate.getTimeInMillis() - 1);
stat.commitTime(mDailyExpiryDate.getTimeInMillis() - 1);
}
@@ -509,10 +534,27 @@ class UserUsageStatsService {
final int continueCount = continuePreviousDay.size();
for (int i = 0; i < continueCount; i++) {
- String name = continuePreviousDay.valueAt(i);
+ String pkgName = continuePreviousDay.valueAt(i);
final long beginTime = mCurrentStats[UsageStatsManager.INTERVAL_DAILY].beginTime;
for (IntervalStats stat : mCurrentStats) {
- stat.update(name, beginTime, UsageEvents.Event.CONTINUE_PREVIOUS_DAY);
+ if (continuePreviousDayForegroundActivity.containsKey(pkgName)) {
+ final ArrayMap<String, Integer> foregroundActivityEventMap =
+ continuePreviousDayForegroundActivity.get(pkgName);
+ final int size = foregroundActivityEventMap.size();
+ for (int j = 0; j < size; j++) {
+ stat.update(pkgName, foregroundActivityEventMap.keyAt(j), beginTime,
+ UsageEvents.Event.CONTINUE_PREVIOUS_DAY);
+ }
+ }
+ if (continuePreviousDayForegroundService.containsKey(pkgName)) {
+ final ArrayMap<String, Integer> foregroundServiceEventMap =
+ continuePreviousDayForegroundService.get(pkgName);
+ final int size = foregroundServiceEventMap.size();
+ for (int j = 0; j < size; j++) {
+ stat.update(pkgName, foregroundServiceEventMap.keyAt(j), beginTime,
+ UsageEvents.Event.CONTINUING_FOREGROUND_SERVICE);
+ }
+ }
stat.updateConfigurationStats(previousConfig, beginTime);
notifyStatsChanged();
}
@@ -837,10 +879,18 @@ class UserUsageStatsService {
return "MOVE_TO_BACKGROUND";
case UsageEvents.Event.MOVE_TO_FOREGROUND:
return "MOVE_TO_FOREGROUND";
+ case UsageEvents.Event.FOREGROUND_SERVICE_START:
+ return "FOREGROUND_SERVICE_START";
+ case UsageEvents.Event.FOREGROUND_SERVICE_STOP:
+ return "FOREGROUND_SERVICE_STOP";
case UsageEvents.Event.END_OF_DAY:
return "END_OF_DAY";
+ case UsageEvents.Event.ROLLOVER_FOREGROUND_SERVICE:
+ return "ROLLOVER_FOREGROUND_SERVICE";
case UsageEvents.Event.CONTINUE_PREVIOUS_DAY:
return "CONTINUE_PREVIOUS_DAY";
+ case UsageEvents.Event.CONTINUING_FOREGROUND_SERVICE:
+ return "CONTINUING_FOREGROUND_SERVICE";
case UsageEvents.Event.CONFIGURATION_CHANGE:
return "CONFIGURATION_CHANGE";
case UsageEvents.Event.SYSTEM_INTERACTION:
diff --git a/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java b/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java
index 8467bee819cb..be74a6d162ae 100644
--- a/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java
+++ b/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java
@@ -18,10 +18,6 @@ package com.android.frameworks.perftests.usage.tests;
import static junit.framework.Assert.assertEquals;
-import com.android.server.usage.UsageStatsDatabase;
-import com.android.server.usage.UsageStatsDatabase.StatCombiner;
-import com.android.server.usage.IntervalStats;
-
import android.app.usage.EventList;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManager;
@@ -29,10 +25,14 @@ import android.content.Context;
import android.os.SystemClock;
import android.perftests.utils.ManualBenchmarkState;
import android.perftests.utils.PerfManualStatusReporter;
-import android.support.test.filters.LargeTest;
import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
+import com.android.server.usage.IntervalStats;
+import com.android.server.usage.UsageStatsDatabase;
+import com.android.server.usage.UsageStatsDatabase.StatCombiner;
+
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
@@ -90,11 +90,13 @@ public class UsageStatsDatabasePerfTest {
for (int pkg = 0; pkg < packageCount; pkg++) {
UsageEvents.Event event = new UsageEvents.Event();
event.mPackage = "fake.package.name" + pkg;
+ event.mClass = event.mPackage + ".class1";
event.mTimeStamp = 1;
event.mEventType = UsageEvents.Event.MOVE_TO_FOREGROUND;
for (int evt = 0; evt < eventsPerPackage; evt++) {
intervalStats.events.insert(event);
- intervalStats.update(event.mPackage, event.mTimeStamp, event.mEventType);
+ intervalStats.update(event.mPackage, event.mClass, event.mTimeStamp,
+ event.mEventType);
}
}
}