From 5e1613ef644567982597e5f27e90fc5c3ff56f09 Mon Sep 17 00:00:00 2001 From: Varun Shah Date: Thu, 5 Sep 2019 11:50:18 -0700 Subject: [PATCH] Update UsageStats#checkAndGetTimeLocked behavior. The time change event was happening for every user even if they were not unlocked, causing UsageStatsService to crash. Since the data is now located in CE, the #checkAndGetTimeLocked function has been moved to UserUsageStatsService, tying time change events to each user instead of UsageStatsService. This gives the guarantee that no usage stats data will be accessed or modified if the user service is not existent while keeping the same behavior as earlier. References to #checkAndGetTimeLocked in UsageStatsService have been updated to call System.currentTimeMillis() directly. Bug: 140529704 Test: atest UsageStatsTest Test: atest UsageStatsDatabaseTest Change-Id: I746790f3918b927ac8ac76ee860c94cac603e5da --- .../server/usage/UsageStatsService.java | 90 +++---------------- .../server/usage/UserUsageStatsService.java | 59 +++++++++++- 2 files changed, 70 insertions(+), 79 deletions(-) diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index fc464a1f4393f..090623e2f767f 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -121,7 +121,7 @@ public class UsageStatsService extends SystemService implements private static final long TEN_SECONDS = 10 * 1000; private static final long TWENTY_MINUTES = 20 * 60 * 1000; private static final long FLUSH_INTERVAL = COMPRESS_TIME ? TEN_SECONDS : TWENTY_MINUTES; - private static final long TIME_CHANGE_THRESHOLD_MILLIS = 2 * 1000; // Two seconds. + static final long TIME_CHANGE_THRESHOLD_MILLIS = 2 * 1000; // Two seconds. private static final boolean ENABLE_KERNEL_UPDATES = true; private static final File KERNEL_COUNTER_FILE = new File("/proc/uid_procstat/set"); @@ -156,8 +156,6 @@ public class UsageStatsService extends SystemService implements private final SparseArray mUserState = new SparseArray<>(); private final SparseBooleanArray mUserUnlockedStates = new SparseBooleanArray(); private final SparseIntArray mUidToKernelCounter = new SparseIntArray(); - long mRealTimeSnapshot; - long mSystemTimeSnapshot; int mUsageSource; /** Manages the standby state of apps. */ @@ -253,9 +251,6 @@ public class UsageStatsService extends SystemService implements getContext().registerReceiverAsUser(new UserActionsReceiver(), UserHandle.ALL, filter, null, mHandler); - mRealTimeSnapshot = SystemClock.elapsedRealtime(); - mSystemTimeSnapshot = System.currentTimeMillis(); - publishLocalService(UsageStatsManagerInternal.class, new LocalService()); publishBinderService(Context.USAGE_STATS_SERVICE, new BinderService()); } @@ -345,7 +340,7 @@ public class UsageStatsService extends SystemService implements mUserUnlockedStates.put(userId, true); final UserUsageStatsService userService = getUserDataAndInitializeIfNeededLocked( userId, System.currentTimeMillis()); - userService.userUnlocked(checkAndGetTimeLocked()); + userService.userUnlocked(System.currentTimeMillis()); // Process all the pending reported events while (pendingEvents.peek() != null) { reportEvent(pendingEvents.poll(), userId); @@ -568,37 +563,6 @@ public class UsageStatsService extends SystemService implements } } - /** - * This should be the only way to get the time from the system. - */ - private long checkAndGetTimeLocked() { - final long actualSystemTime = System.currentTimeMillis(); - final long actualRealtime = SystemClock.elapsedRealtime(); - final long expectedSystemTime = (actualRealtime - mRealTimeSnapshot) + mSystemTimeSnapshot; - final long diffSystemTime = actualSystemTime - expectedSystemTime; - if (Math.abs(diffSystemTime) > TIME_CHANGE_THRESHOLD_MILLIS - && ENABLE_TIME_CHANGE_CORRECTION) { - // The time has changed. - Slog.i(TAG, "Time changed in UsageStats by " + (diffSystemTime / 1000) + " seconds"); - final int userCount = mUserState.size(); - for (int i = 0; i < userCount; i++) { - final UserUsageStatsService service = mUserState.valueAt(i); - service.onTimeChanged(expectedSystemTime, actualSystemTime); - } - mRealTimeSnapshot = actualRealtime; - mSystemTimeSnapshot = actualSystemTime; - } - return actualSystemTime; - } - - /** - * Assuming the event's timestamp is measured in milliseconds since boot, - * convert it to a system wall time. - */ - private void convertToSystemTimeLocked(Event event) { - event.mTimeStamp = Math.max(0, event.mTimeStamp - mRealTimeSnapshot) + mSystemTimeSnapshot; - } - /** * Called by the Binder stub */ @@ -718,9 +682,8 @@ public class UsageStatsService extends SystemService implements return; } - final long timeNow = checkAndGetTimeLocked(); + final long timeNow = System.currentTimeMillis(); final long elapsedRealtime = SystemClock.elapsedRealtime(); - convertToSystemTimeLocked(event); if (event.mPackage != null && mPackageManagerInternal.isPackageEphemeral(userId, event.mPackage)) { @@ -876,13 +839,8 @@ public class UsageStatsService extends SystemService implements return null; } - final long timeNow = checkAndGetTimeLocked(); - if (!validRange(timeNow, beginTime, endTime)) { - return null; - } - final UserUsageStatsService service = - getUserDataAndInitializeIfNeededLocked(userId, timeNow); + getUserDataAndInitializeIfNeededLocked(userId, System.currentTimeMillis()); List list = service.queryUsageStats(bucketType, beginTime, endTime); if (list == null) { return null; @@ -913,13 +871,8 @@ public class UsageStatsService extends SystemService implements return null; } - final long timeNow = checkAndGetTimeLocked(); - if (!validRange(timeNow, beginTime, endTime)) { - return null; - } - final UserUsageStatsService service = - getUserDataAndInitializeIfNeededLocked(userId, timeNow); + getUserDataAndInitializeIfNeededLocked(userId, System.currentTimeMillis()); return service.queryConfigurationStats(bucketType, beginTime, endTime); } } @@ -935,13 +888,8 @@ public class UsageStatsService extends SystemService implements return null; } - final long timeNow = checkAndGetTimeLocked(); - if (!validRange(timeNow, beginTime, endTime)) { - return null; - } - final UserUsageStatsService service = - getUserDataAndInitializeIfNeededLocked(userId, timeNow); + getUserDataAndInitializeIfNeededLocked(userId, System.currentTimeMillis()); return service.queryEventStats(bucketType, beginTime, endTime); } } @@ -957,13 +905,8 @@ public class UsageStatsService extends SystemService implements return null; } - final long timeNow = checkAndGetTimeLocked(); - if (!validRange(timeNow, beginTime, endTime)) { - return null; - } - final UserUsageStatsService service = - getUserDataAndInitializeIfNeededLocked(userId, timeNow); + getUserDataAndInitializeIfNeededLocked(userId, System.currentTimeMillis()); return service.queryEvents(beginTime, endTime, shouldObfuscateInstantApps); } } @@ -979,21 +922,12 @@ public class UsageStatsService extends SystemService implements return null; } - final long timeNow = checkAndGetTimeLocked(); - if (!validRange(timeNow, beginTime, endTime)) { - return null; - } - final UserUsageStatsService service = - getUserDataAndInitializeIfNeededLocked(userId, timeNow); + getUserDataAndInitializeIfNeededLocked(userId, System.currentTimeMillis()); return service.queryEventsForPackage(beginTime, endTime, packageName, includeTaskRoot); } } - private static boolean validRange(long currentTime, long beginTime, long endTime) { - return beginTime <= currentTime && beginTime < endTime; - } - private String buildFullToken(String packageName, String token) { final StringBuilder sb = new StringBuilder(packageName.length() + token.length() + 1); sb.append(packageName); @@ -2050,8 +1984,8 @@ public class UsageStatsService extends SystemService implements // Check to ensure that only user 0's data is b/r for now if (user == UserHandle.USER_SYSTEM) { - final UserUsageStatsService userStats = - getUserDataAndInitializeIfNeededLocked(user, checkAndGetTimeLocked()); + final UserUsageStatsService userStats = getUserDataAndInitializeIfNeededLocked( + user, System.currentTimeMillis()); return userStats.getBackupPayload(key); } else { return null; @@ -2068,8 +2002,8 @@ public class UsageStatsService extends SystemService implements } if (user == UserHandle.USER_SYSTEM) { - final UserUsageStatsService userStats = - getUserDataAndInitializeIfNeededLocked(user, checkAndGetTimeLocked()); + final UserUsageStatsService userStats = getUserDataAndInitializeIfNeededLocked( + user, System.currentTimeMillis()); userStats.applyRestoredPayload(key, payload); } } diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java index 6fbd88227f9b2..1560b9e708e3b 100644 --- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java @@ -76,6 +76,8 @@ class UserUsageStatsService { private final String mLogPrefix; private String mLastBackgroundedPackage; private final int mUserId; + private long mRealTimeSnapshot; + private long mSystemTimeSnapshot; private static final long[] INTERVAL_LENGTH = new long[] { UnixCalendar.DAY_IN_MILLIS, UnixCalendar.WEEK_IN_MILLIS, @@ -101,6 +103,8 @@ class UserUsageStatsService { mListener = listener; mLogPrefix = "User[" + Integer.toString(userId) + "] "; mUserId = userId; + mRealTimeSnapshot = SystemClock.elapsedRealtime(); + mSystemTimeSnapshot = System.currentTimeMillis(); } void init(final long currentTimeMillis) { @@ -165,12 +169,41 @@ class UserUsageStatsService { persistActiveStats(); } - void onTimeChanged(long oldTime, long newTime) { + private void onTimeChanged(long oldTime, long newTime) { persistActiveStats(); mDatabase.onTimeChanged(newTime - oldTime); loadActiveStats(newTime); } + /** + * This should be the only way to get the time from the system. + */ + private long checkAndGetTimeLocked() { + final long actualSystemTime = System.currentTimeMillis(); + if (!UsageStatsService.ENABLE_TIME_CHANGE_CORRECTION) { + return actualSystemTime; + } + final long actualRealtime = SystemClock.elapsedRealtime(); + final long expectedSystemTime = (actualRealtime - mRealTimeSnapshot) + mSystemTimeSnapshot; + final long diffSystemTime = actualSystemTime - expectedSystemTime; + if (Math.abs(diffSystemTime) > UsageStatsService.TIME_CHANGE_THRESHOLD_MILLIS) { + // The time has changed. + Slog.i(TAG, mLogPrefix + "Time changed in by " + (diffSystemTime / 1000) + " seconds"); + onTimeChanged(expectedSystemTime, actualSystemTime); + mRealTimeSnapshot = actualRealtime; + mSystemTimeSnapshot = actualSystemTime; + } + return actualSystemTime; + } + + /** + * Assuming the event's timestamp is measured in milliseconds since boot, + * convert it to a system wall time. + */ + private void convertToSystemTimeLocked(Event event) { + event.mTimeStamp = Math.max(0, event.mTimeStamp - mRealTimeSnapshot) + mSystemTimeSnapshot; + } + void reportEvent(Event event) { if (DEBUG) { Slog.d(TAG, mLogPrefix + "Got usage event for " + event.mPackage @@ -178,6 +211,9 @@ class UserUsageStatsService { + eventToString(event.mEventType)); } + checkAndGetTimeLocked(); + convertToSystemTimeLocked(event); + if (event.mTimeStamp >= mDailyExpiryDate.getTimeInMillis()) { // Need to rollover rolloverStats(event.mTimeStamp); @@ -298,6 +334,10 @@ class UserUsageStatsService { } }; + private static boolean validRange(long currentTime, long beginTime, long endTime) { + return beginTime <= currentTime && beginTime < endTime; + } + /** * Generic query method that selects the appropriate IntervalStats for the specified time range * and bucket, then calls the {@link com.android.server.usage.UsageStatsDatabase.StatCombiner} @@ -370,19 +410,31 @@ class UserUsageStatsService { } List queryUsageStats(int bucketType, long beginTime, long endTime) { + if (!validRange(checkAndGetTimeLocked(), beginTime, endTime)) { + return null; + } return queryStats(bucketType, beginTime, endTime, sUsageStatsCombiner); } List queryConfigurationStats(int bucketType, long beginTime, long endTime) { + if (!validRange(checkAndGetTimeLocked(), beginTime, endTime)) { + return null; + } return queryStats(bucketType, beginTime, endTime, sConfigStatsCombiner); } List queryEventStats(int bucketType, long beginTime, long endTime) { + if (!validRange(checkAndGetTimeLocked(), beginTime, endTime)) { + return null; + } return queryStats(bucketType, beginTime, endTime, sEventStatsCombiner); } UsageEvents queryEvents(final long beginTime, final long endTime, boolean obfuscateInstantApps) { + if (!validRange(checkAndGetTimeLocked(), beginTime, endTime)) { + return null; + } final ArraySet names = new ArraySet<>(); List results = queryStats(INTERVAL_DAILY, beginTime, endTime, new StatCombiner() { @@ -428,6 +480,9 @@ class UserUsageStatsService { UsageEvents queryEventsForPackage(final long beginTime, final long endTime, final String packageName, boolean includeTaskRoot) { + if (!validRange(checkAndGetTimeLocked(), beginTime, endTime)) { + return null; + } final ArraySet names = new ArraySet<>(); names.add(packageName); final List results = queryStats(INTERVAL_DAILY, @@ -1030,10 +1085,12 @@ class UserUsageStatsService { } byte[] getBackupPayload(String key){ + checkAndGetTimeLocked(); return mDatabase.getBackupPayload(key); } void applyRestoredPayload(String key, byte[] payload){ + checkAndGetTimeLocked(); mDatabase.applyRestoredPayload(key, payload); } }