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

Commit 2bd90c6a authored by Adam Lesinski's avatar Adam Lesinski
Browse files

DO NOT MERGE ANYWHERE: UsageStats: Fix issue where initializing data for first...

DO NOT MERGE ANYWHERE: UsageStats: Fix issue where initializing data for first time would cause crash

With the updated rolling window of stats for app idleness, we need to make sure
it is populated before we initialize some defaults.

Now that we look at older entries to figure out idleness, if those
entries are in the future (due to time change), set them to the current
screen on time.
Bug:26504153

Change-Id: Ia22add0e8eaf0f137002bbe3e91d747fef5b7d69
parent 9c7b5433
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -547,7 +547,8 @@ public class UsageStatsService extends SystemService implements
            final int userCount = mUserState.size();
            final int userCount = mUserState.size();
            for (int i = 0; i < userCount; i++) {
            for (int i = 0; i < userCount; i++) {
                final UserUsageStatsService service = mUserState.valueAt(i);
                final UserUsageStatsService service = mUserState.valueAt(i);
                service.onTimeChanged(expectedSystemTime, actualSystemTime, resetBeginIdleTime);
                service.onTimeChanged(expectedSystemTime, actualSystemTime, mScreenOnTime,
                        resetBeginIdleTime);
            }
            }
            mRealTimeSnapshot = actualRealtime;
            mRealTimeSnapshot = actualRealtime;
            mSystemTimeSnapshot = actualSystemTime;
            mSystemTimeSnapshot = actualSystemTime;
+39 −34
Original line number Original line Diff line number Diff line
@@ -135,12 +135,12 @@ class UserUsageStatsService {
            stat.updateConfigurationStats(null, stat.lastTimeSaved);
            stat.updateConfigurationStats(null, stat.lastTimeSaved);
        }
        }


        refreshAppIdleRollingWindow(currentTimeMillis, deviceUsageTime);

        if (mDatabase.isNewUpdate()) {
        if (mDatabase.isNewUpdate()) {
            initializeDefaultsForApps(currentTimeMillis, deviceUsageTime,
            initializeDefaultsForApps(currentTimeMillis, deviceUsageTime,
                    mDatabase.isFirstUpdate());
                    mDatabase.isFirstUpdate());
        }
        }

        refreshAppIdleRollingWindow(currentTimeMillis);
    }
    }


    /**
    /**
@@ -162,19 +162,23 @@ class UserUsageStatsService {
                for (IntervalStats stats : mCurrentStats) {
                for (IntervalStats stats : mCurrentStats) {
                    stats.update(packageName, currentTimeMillis, Event.SYSTEM_INTERACTION);
                    stats.update(packageName, currentTimeMillis, Event.SYSTEM_INTERACTION);
                    stats.updateBeginIdleTime(packageName, deviceUsageTime);
                    stats.updateBeginIdleTime(packageName, deviceUsageTime);
                    mStatsChanged = true;
                }
                }
                mAppIdleRollingWindow.update(packageName, currentTimeMillis,
                        Event.SYSTEM_INTERACTION);
                mAppIdleRollingWindow.updateBeginIdleTime(packageName, deviceUsageTime);
                mStatsChanged = true;
            }
            }
        }
        }
        // Persist the new OTA-related access stats.
        // Persist the new OTA-related access stats.
        persistActiveStats();
        persistActiveStats();
    }
    }


    void onTimeChanged(long oldTime, long newTime, boolean resetBeginIdleTime) {
    void onTimeChanged(long oldTime, long newTime, long deviceUsageTime,
                       boolean resetBeginIdleTime) {
        persistActiveStats();
        persistActiveStats();
        mDatabase.onTimeChanged(newTime - oldTime);
        mDatabase.onTimeChanged(newTime - oldTime);
        loadActiveStats(newTime, /* force= */ true, resetBeginIdleTime);
        loadActiveStats(newTime, /* force= */ true, resetBeginIdleTime);
        refreshAppIdleRollingWindow(newTime);
        refreshAppIdleRollingWindow(newTime, deviceUsageTime);
    }
    }


    void reportEvent(UsageEvents.Event event, long deviceUsageTime) {
    void reportEvent(UsageEvents.Event event, long deviceUsageTime) {
@@ -186,7 +190,7 @@ class UserUsageStatsService {


        if (event.mTimeStamp >= mDailyExpiryDate.getTimeInMillis()) {
        if (event.mTimeStamp >= mDailyExpiryDate.getTimeInMillis()) {
            // Need to rollover
            // Need to rollover
            rolloverStats(event.mTimeStamp);
            rolloverStats(event.mTimeStamp, deviceUsageTime);
        }
        }


        final IntervalStats currentDailyStats = mCurrentStats[UsageStatsManager.INTERVAL_DAILY];
        final IntervalStats currentDailyStats = mCurrentStats[UsageStatsManager.INTERVAL_DAILY];
@@ -430,7 +434,7 @@ class UserUsageStatsService {
        }
        }
    }
    }


    private void rolloverStats(final long currentTimeMillis) {
    private void rolloverStats(final long currentTimeMillis, final long deviceUsageTime) {
        final long startTime = SystemClock.elapsedRealtime();
        final long startTime = SystemClock.elapsedRealtime();
        Slog.i(TAG, mLogPrefix + "Rolling over usage stats");
        Slog.i(TAG, mLogPrefix + "Rolling over usage stats");


@@ -471,7 +475,7 @@ class UserUsageStatsService {
        }
        }
        persistActiveStats();
        persistActiveStats();


        refreshAppIdleRollingWindow(currentTimeMillis);
        refreshAppIdleRollingWindow(currentTimeMillis, deviceUsageTime);


        final long totalTime = SystemClock.elapsedRealtime() - startTime;
        final long totalTime = SystemClock.elapsedRealtime() - startTime;
        Slog.i(TAG, mLogPrefix + "Rolling over usage stats complete. Took " + totalTime
        Slog.i(TAG, mLogPrefix + "Rolling over usage stats complete. Took " + totalTime
@@ -542,26 +546,43 @@ class UserUsageStatsService {
                tempCal.getTimeInMillis() + ")");
                tempCal.getTimeInMillis() + ")");
    }
    }


    private static void mergePackageStats(IntervalStats dst, IntervalStats src) {
    private static void mergePackageStats(IntervalStats dst, IntervalStats src,
                                          final long deviceUsageTime) {
        dst.endTime = Math.max(dst.endTime, src.endTime);
        dst.endTime = Math.max(dst.endTime, src.endTime);


        final int srcPackageCount = src.packageStats.size();
        final int srcPackageCount = src.packageStats.size();
        for (int i = 0; i < srcPackageCount; i++) {
        for (int i = 0; i < srcPackageCount; i++) {
            final String packageName = src.packageStats.keyAt(i);
            final String packageName = src.packageStats.keyAt(i);
            final UsageStats srcStats = src.packageStats.valueAt(i);
            final UsageStats srcStats = src.packageStats.valueAt(i);
            final UsageStats dstStats = dst.packageStats.get(packageName);
            UsageStats dstStats = dst.packageStats.get(packageName);
            if (dstStats == null) {
            if (dstStats == null) {
                dst.packageStats.put(packageName, new UsageStats(srcStats));
                dstStats = new UsageStats(srcStats);
                dst.packageStats.put(packageName, dstStats);
            } else {
            } else {
                dstStats.add(src.packageStats.valueAt(i));
                dstStats.add(src.packageStats.valueAt(i));
            }
            }

            // App idle times can not begin in the future. This happens if we had a time change.
            if (dstStats.mBeginIdleTime > deviceUsageTime) {
                dstStats.mBeginIdleTime = deviceUsageTime;
            }
        }
        }
    }
    }


    /**
    /**
     * Merges all the stats into the first element of the resulting list.
     * 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
     */
     */
    private static final StatCombiner<IntervalStats> sPackageStatsMerger =
    void refreshAppIdleRollingWindow(final long currentTimeMillis, final long deviceUsageTime) {
        // Start the rolling window for AppIdle requests.
        List<IntervalStats> stats = mDatabase.queryUsageStats(UsageStatsManager.INTERVAL_DAILY,
                currentTimeMillis - (1000 * 60 * 60 * 24 * 2), currentTimeMillis,
                new StatCombiner<IntervalStats>() {
                new StatCombiner<IntervalStats>() {
                    @Override
                    @Override
                    public void combine(IntervalStats stats, boolean mutable,
                    public void combine(IntervalStats stats, boolean mutable,
@@ -575,30 +596,14 @@ class UserUsageStatsService {
                            accum = accumulatedResult.get(0);
                            accum = accumulatedResult.get(0);
                        }
                        }


            mergePackageStats(accum, stats);
                        mergePackageStats(accum, stats, deviceUsageTime);
                    }
                    }
    };
                });

    /**
     * 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()) {
        if (stats == null || stats.isEmpty()) {
            mAppIdleRollingWindow = new IntervalStats();
            mAppIdleRollingWindow = new IntervalStats();
            mergePackageStats(mAppIdleRollingWindow,
            mergePackageStats(mAppIdleRollingWindow,
                    mCurrentStats[UsageStatsManager.INTERVAL_YEARLY]);
                    mCurrentStats[UsageStatsManager.INTERVAL_YEARLY], deviceUsageTime);
        } else {
        } else {
            mAppIdleRollingWindow = stats.get(0);
            mAppIdleRollingWindow = stats.get(0);
        }
        }