diff options
| author | 2016-01-12 00:28:28 +0000 | |
|---|---|---|
| committer | 2016-01-12 00:28:28 +0000 | |
| commit | 15df80f069c72989539df560c02f377ae9214ae2 (patch) | |
| tree | 380f48b0d095cab2c6923899e4e8aa51db790cda | |
| parent | d3b2826a1a3ff128db1e89a081124192ac70c509 (diff) | |
| parent | da4a3775735ffc0fa510031f75bc459b764b259d (diff) | |
Merge "UsageStatsService: Fix app idle issue at rollover time" into mnc-dr1.5-dev
| -rw-r--r-- | services/usage/java/com/android/server/usage/UserUsageStatsService.java | 85 |
1 files changed, 81 insertions, 4 deletions
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java index b07b8153279d..d8f26edaf85e 100644 --- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java @@ -59,6 +59,7 @@ class UserUsageStatsService { private final Context mContext; private final UsageStatsDatabase mDatabase; private final IntervalStats[] mCurrentStats; + private IntervalStats mAppIdleRollingWindow; private boolean mStatsChanged = false; private final UnixCalendar mDailyExpiryDate; private final StatsUpdatedListener mListener; @@ -138,6 +139,8 @@ class UserUsageStatsService { initializeDefaultsForApps(currentTimeMillis, deviceUsageTime, mDatabase.isFirstUpdate()); } + + refreshAppIdleRollingWindow(currentTimeMillis); } /** @@ -171,6 +174,7 @@ class UserUsageStatsService { persistActiveStats(); mDatabase.onTimeChanged(newTime - oldTime); loadActiveStats(newTime, /* force= */ true, resetBeginIdleTime); + refreshAppIdleRollingWindow(newTime); } void reportEvent(UsageEvents.Event event, long deviceUsageTime) { @@ -212,6 +216,11 @@ class UserUsageStatsService { } } + if (event.mEventType != Event.CONFIGURATION_CHANGE) { + mAppIdleRollingWindow.update(event.mPackage, event.mTimeStamp, event.mEventType); + mAppIdleRollingWindow.updateBeginIdleTime(event.mPackage, deviceUsageTime); + } + notifyStatsChanged(); } @@ -223,6 +232,7 @@ class UserUsageStatsService { for (IntervalStats stats : mCurrentStats) { stats.updateBeginIdleTime(packageName, beginIdleTime); } + mAppIdleRollingWindow.updateBeginIdleTime(packageName, beginIdleTime); notifyStatsChanged(); } @@ -230,6 +240,7 @@ class UserUsageStatsService { for (IntervalStats stats : mCurrentStats) { stats.updateSystemLastUsedTime(packageName, lastUsedTime); } + mAppIdleRollingWindow.updateSystemLastUsedTime(packageName, lastUsedTime); notifyStatsChanged(); } @@ -388,9 +399,8 @@ class UserUsageStatsService { } long getBeginIdleTime(String packageName) { - final IntervalStats yearly = mCurrentStats[UsageStatsManager.INTERVAL_YEARLY]; UsageStats packageUsage; - if ((packageUsage = yearly.packageStats.get(packageName)) == null) { + if ((packageUsage = mAppIdleRollingWindow.packageStats.get(packageName)) == null) { return -1; } else { return packageUsage.getBeginIdleTime(); @@ -398,9 +408,8 @@ class UserUsageStatsService { } long getSystemLastUsedTime(String packageName) { - final IntervalStats yearly = mCurrentStats[UsageStatsManager.INTERVAL_YEARLY]; UsageStats packageUsage; - if ((packageUsage = yearly.packageStats.get(packageName)) == null) { + if ((packageUsage = mAppIdleRollingWindow.packageStats.get(packageName)) == null) { return -1; } else { return packageUsage.getLastTimeSystemUsed(); @@ -462,6 +471,8 @@ class UserUsageStatsService { } persistActiveStats(); + refreshAppIdleRollingWindow(currentTimeMillis); + final long totalTime = SystemClock.elapsedRealtime() - startTime; Slog.i(TAG, mLogPrefix + "Rolling over usage stats complete. Took " + totalTime + " milliseconds"); @@ -521,6 +532,7 @@ class UserUsageStatsService { } } } + mStatsChanged = false; mDailyExpiryDate.setTimeInMillis(currentTimeMillis); mDailyExpiryDate.addDays(1); @@ -530,6 +542,68 @@ class UserUsageStatsService { tempCal.getTimeInMillis() + ")"); } + private static void mergePackageStats(IntervalStats dst, IntervalStats src) { + dst.endTime = Math.max(dst.endTime, src.endTime); + + final int srcPackageCount = src.packageStats.size(); + for (int i = 0; i < srcPackageCount; i++) { + final String packageName = src.packageStats.keyAt(i); + final UsageStats srcStats = src.packageStats.valueAt(i); + final UsageStats dstStats = dst.packageStats.get(packageName); + if (dstStats == null) { + dst.packageStats.put(packageName, new UsageStats(srcStats)); + } else { + dstStats.add(src.packageStats.valueAt(i)); + } + } + } + + /** + * Merges all the stats into the first element of the resulting list. + */ + private static final StatCombiner<IntervalStats> sPackageStatsMerger = + new StatCombiner<IntervalStats>() { + @Override + public void combine(IntervalStats stats, boolean mutable, + List<IntervalStats> accumulatedResult) { + IntervalStats accum; + if (accumulatedResult.isEmpty()) { + accum = new IntervalStats(); + accum.beginTime = stats.beginTime; + accumulatedResult.add(accum); + } else { + accum = accumulatedResult.get(0); + } + + mergePackageStats(accum, stats); + } + }; + + /** + * App idle operates on a rolling window of time. When we roll over time, we end up with a + * period of time where in-memory stats are empty and we don't hit the disk for older stats + * for performance reasons. Suddenly all apps will become idle. + * + * Instead, at times we do a deep query to find all the apps that have run in the past few + * days and keep the cached data up to date. + * + * @param currentTimeMillis + */ + void refreshAppIdleRollingWindow(long currentTimeMillis) { + // Start the rolling window for AppIdle requests. + List<IntervalStats> stats = mDatabase.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, + currentTimeMillis - (1000 * 60 * 60 * 24 * 2), currentTimeMillis, + sPackageStatsMerger); + + if (stats == null || stats.isEmpty()) { + mAppIdleRollingWindow = new IntervalStats(); + mergePackageStats(mAppIdleRollingWindow, + mCurrentStats[UsageStatsManager.INTERVAL_YEARLY]); + } else { + mAppIdleRollingWindow = stats.get(0); + } + } + // // -- DUMP related methods -- // @@ -552,6 +626,9 @@ class UserUsageStatsService { pw.println(" stats"); printIntervalStats(pw, mCurrentStats[interval], screenOnTime, true); } + + pw.println("AppIdleRollingWindow cache"); + printIntervalStats(pw, mAppIdleRollingWindow, screenOnTime, true); } private String formatDateTime(long dateTime, boolean pretty) { |