Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1f1cbc01 authored by Adam Lesinski's avatar Adam Lesinski Committed by android-build-merger
Browse files

Merge "UsageStatsService: Fix app idle issue at rollover time" into mnc-dr1.5-dev

am: 15df80f0

* commit '15df80f0':
  UsageStatsService: Fix app idle issue at rollover time
parents c52870bb 15df80f0
Loading
Loading
Loading
Loading
+81 −4
Original line number Diff line number Diff line
@@ -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) {