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
This commit is contained in:
@@ -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<UserUsageStatsService> 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<UsageStats> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<UsageStats> queryUsageStats(int bucketType, long beginTime, long endTime) {
|
||||
if (!validRange(checkAndGetTimeLocked(), beginTime, endTime)) {
|
||||
return null;
|
||||
}
|
||||
return queryStats(bucketType, beginTime, endTime, sUsageStatsCombiner);
|
||||
}
|
||||
|
||||
List<ConfigurationStats> queryConfigurationStats(int bucketType, long beginTime, long endTime) {
|
||||
if (!validRange(checkAndGetTimeLocked(), beginTime, endTime)) {
|
||||
return null;
|
||||
}
|
||||
return queryStats(bucketType, beginTime, endTime, sConfigStatsCombiner);
|
||||
}
|
||||
|
||||
List<EventStats> 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<String> names = new ArraySet<>();
|
||||
List<Event> results = queryStats(INTERVAL_DAILY,
|
||||
beginTime, endTime, new StatCombiner<Event>() {
|
||||
@@ -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<String> names = new ArraySet<>();
|
||||
names.add(packageName);
|
||||
final List<Event> 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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user