Merge "Reduce screen on delay during UsageStats rollover"
This commit is contained in:
committed by
Android (Google) Code Review
commit
99ccebf548
@@ -45,12 +45,12 @@ public class AppIdleHistoryTests extends AndroidTestCase {
|
||||
final int userId = 0;
|
||||
AppIdleHistory aih = new AppIdleHistory(mStorageDir, 0);
|
||||
|
||||
aih.updateDisplayLocked(true, /* elapsedRealtime= */ 1000);
|
||||
aih.updateDisplayLocked(false, /* elapsedRealtime= */ 2000);
|
||||
aih.updateDisplay(true, /* elapsedRealtime= */ 1000);
|
||||
aih.updateDisplay(false, /* elapsedRealtime= */ 2000);
|
||||
// Screen On time file should be written right away
|
||||
assertTrue(aih.getScreenOnTimeFile().exists());
|
||||
|
||||
aih.writeAppIdleTimesLocked(userId);
|
||||
aih.writeAppIdleTimes(userId);
|
||||
// stats file should be written now
|
||||
assertTrue(new File(new File(mStorageDir, "users/" + userId),
|
||||
AppIdleHistory.APP_IDLE_FILENAME).exists());
|
||||
@@ -58,43 +58,43 @@ public class AppIdleHistoryTests extends AndroidTestCase {
|
||||
|
||||
public void testScreenOnTime() {
|
||||
AppIdleHistory aih = new AppIdleHistory(mStorageDir, 1000);
|
||||
aih.updateDisplayLocked(false, 2000);
|
||||
assertEquals(aih.getScreenOnTimeLocked(2000), 0);
|
||||
aih.updateDisplayLocked(true, 3000);
|
||||
assertEquals(aih.getScreenOnTimeLocked(4000), 1000);
|
||||
assertEquals(aih.getScreenOnTimeLocked(5000), 2000);
|
||||
aih.updateDisplayLocked(false, 6000);
|
||||
aih.updateDisplay(false, 2000);
|
||||
assertEquals(aih.getScreenOnTime(2000), 0);
|
||||
aih.updateDisplay(true, 3000);
|
||||
assertEquals(aih.getScreenOnTime(4000), 1000);
|
||||
assertEquals(aih.getScreenOnTime(5000), 2000);
|
||||
aih.updateDisplay(false, 6000);
|
||||
// Screen on time should not keep progressing with screen is off
|
||||
assertEquals(aih.getScreenOnTimeLocked(7000), 3000);
|
||||
assertEquals(aih.getScreenOnTimeLocked(8000), 3000);
|
||||
aih.writeAppIdleDurationsLocked();
|
||||
assertEquals(aih.getScreenOnTime(7000), 3000);
|
||||
assertEquals(aih.getScreenOnTime(8000), 3000);
|
||||
aih.writeAppIdleDurations();
|
||||
|
||||
// Check if the screen on time is persisted across instantiations
|
||||
AppIdleHistory aih2 = new AppIdleHistory(mStorageDir, 0);
|
||||
assertEquals(aih2.getScreenOnTimeLocked(11000), 3000);
|
||||
aih2.updateDisplayLocked(true, 4000);
|
||||
aih2.updateDisplayLocked(false, 5000);
|
||||
assertEquals(aih2.getScreenOnTimeLocked(13000), 4000);
|
||||
assertEquals(aih2.getScreenOnTime(11000), 3000);
|
||||
aih2.updateDisplay(true, 4000);
|
||||
aih2.updateDisplay(false, 5000);
|
||||
assertEquals(aih2.getScreenOnTime(13000), 4000);
|
||||
}
|
||||
|
||||
public void testPackageEvents() {
|
||||
AppIdleHistory aih = new AppIdleHistory(mStorageDir, 1000);
|
||||
aih.setThresholds(4000, 1000);
|
||||
aih.updateDisplayLocked(true, 1000);
|
||||
aih.updateDisplay(true, 1000);
|
||||
// App is not-idle by default
|
||||
assertFalse(aih.isIdleLocked(PACKAGE_1, 0, 1500));
|
||||
assertFalse(aih.isIdle(PACKAGE_1, 0, 1500));
|
||||
// Still not idle
|
||||
assertFalse(aih.isIdleLocked(PACKAGE_1, 0, 3000));
|
||||
assertFalse(aih.isIdle(PACKAGE_1, 0, 3000));
|
||||
// Idle now
|
||||
assertTrue(aih.isIdleLocked(PACKAGE_1, 0, 8000));
|
||||
assertTrue(aih.isIdle(PACKAGE_1, 0, 8000));
|
||||
// Not idle
|
||||
assertFalse(aih.isIdleLocked(PACKAGE_2, 0, 9000));
|
||||
assertFalse(aih.isIdle(PACKAGE_2, 0, 9000));
|
||||
|
||||
// Screen off
|
||||
aih.updateDisplayLocked(false, 9100);
|
||||
aih.updateDisplay(false, 9100);
|
||||
// Still idle after 10 seconds because screen hasn't been on long enough
|
||||
assertFalse(aih.isIdleLocked(PACKAGE_2, 0, 20000));
|
||||
aih.updateDisplayLocked(true, 21000);
|
||||
assertTrue(aih.isIdleLocked(PACKAGE_2, 0, 23000));
|
||||
assertFalse(aih.isIdle(PACKAGE_2, 0, 20000));
|
||||
aih.updateDisplay(true, 21000);
|
||||
assertTrue(aih.isIdle(PACKAGE_2, 0, 23000));
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,6 @@ package com.android.server.usage;
|
||||
|
||||
import android.os.Environment;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.AtomicFile;
|
||||
import android.util.Slog;
|
||||
@@ -101,7 +100,7 @@ public class AppIdleHistory {
|
||||
mElapsedSnapshot = elapsedRealtime;
|
||||
mScreenOnSnapshot = elapsedRealtime;
|
||||
mStorageDir = storageDir;
|
||||
readScreenOnTimeLocked();
|
||||
readScreenOnTime();
|
||||
}
|
||||
|
||||
public void setThresholds(long elapsedTimeThreshold, long screenOnTimeThreshold) {
|
||||
@@ -109,7 +108,7 @@ public class AppIdleHistory {
|
||||
mScreenOnTimeThreshold = screenOnTimeThreshold;
|
||||
}
|
||||
|
||||
public void updateDisplayLocked(boolean screenOn, long elapsedRealtime) {
|
||||
public void updateDisplay(boolean screenOn, long elapsedRealtime) {
|
||||
if (screenOn == mScreenOn) return;
|
||||
|
||||
mScreenOn = screenOn;
|
||||
@@ -122,7 +121,7 @@ public class AppIdleHistory {
|
||||
}
|
||||
}
|
||||
|
||||
public long getScreenOnTimeLocked(long elapsedRealtime) {
|
||||
public long getScreenOnTime(long elapsedRealtime) {
|
||||
long screenOnTime = mScreenOnDuration;
|
||||
if (mScreenOn) {
|
||||
screenOnTime += elapsedRealtime - mScreenOnSnapshot;
|
||||
@@ -135,7 +134,7 @@ public class AppIdleHistory {
|
||||
return new File(mStorageDir, "screen_on_time");
|
||||
}
|
||||
|
||||
private void readScreenOnTimeLocked() {
|
||||
private void readScreenOnTime() {
|
||||
File screenOnTimeFile = getScreenOnTimeFile();
|
||||
if (screenOnTimeFile.exists()) {
|
||||
try {
|
||||
@@ -146,11 +145,11 @@ public class AppIdleHistory {
|
||||
} catch (IOException | NumberFormatException e) {
|
||||
}
|
||||
} else {
|
||||
writeScreenOnTimeLocked();
|
||||
writeScreenOnTime();
|
||||
}
|
||||
}
|
||||
|
||||
private void writeScreenOnTimeLocked() {
|
||||
private void writeScreenOnTime() {
|
||||
AtomicFile screenOnTimeFile = new AtomicFile(getScreenOnTimeFile());
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
@@ -166,30 +165,30 @@ public class AppIdleHistory {
|
||||
/**
|
||||
* To be called periodically to keep track of elapsed time when app idle times are written
|
||||
*/
|
||||
public void writeAppIdleDurationsLocked() {
|
||||
public void writeAppIdleDurations() {
|
||||
final long elapsedRealtime = SystemClock.elapsedRealtime();
|
||||
// Only bump up and snapshot the elapsed time. Don't change screen on duration.
|
||||
mElapsedDuration += elapsedRealtime - mElapsedSnapshot;
|
||||
mElapsedSnapshot = elapsedRealtime;
|
||||
writeScreenOnTimeLocked();
|
||||
writeScreenOnTime();
|
||||
}
|
||||
|
||||
public void reportUsageLocked(String packageName, int userId, long elapsedRealtime) {
|
||||
ArrayMap<String, PackageHistory> userHistory = getUserHistoryLocked(userId);
|
||||
PackageHistory packageHistory = getPackageHistoryLocked(userHistory, packageName,
|
||||
public void reportUsage(String packageName, int userId, long elapsedRealtime) {
|
||||
ArrayMap<String, PackageHistory> userHistory = getUserHistory(userId);
|
||||
PackageHistory packageHistory = getPackageHistory(userHistory, packageName,
|
||||
elapsedRealtime);
|
||||
|
||||
shiftHistoryToNow(userHistory, elapsedRealtime);
|
||||
|
||||
packageHistory.lastUsedElapsedTime = mElapsedDuration
|
||||
+ (elapsedRealtime - mElapsedSnapshot);
|
||||
packageHistory.lastUsedScreenTime = getScreenOnTimeLocked(elapsedRealtime);
|
||||
packageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime);
|
||||
packageHistory.recent[HISTORY_SIZE - 1] = FLAG_LAST_STATE | FLAG_PARTIAL_ACTIVE;
|
||||
}
|
||||
|
||||
public void setIdle(String packageName, int userId, long elapsedRealtime) {
|
||||
ArrayMap<String, PackageHistory> userHistory = getUserHistoryLocked(userId);
|
||||
PackageHistory packageHistory = getPackageHistoryLocked(userHistory, packageName,
|
||||
ArrayMap<String, PackageHistory> userHistory = getUserHistory(userId);
|
||||
PackageHistory packageHistory = getPackageHistory(userHistory, packageName,
|
||||
elapsedRealtime);
|
||||
|
||||
shiftHistoryToNow(userHistory, elapsedRealtime);
|
||||
@@ -222,23 +221,23 @@ public class AppIdleHistory {
|
||||
mLastPeriod = thisPeriod;
|
||||
}
|
||||
|
||||
private ArrayMap<String, PackageHistory> getUserHistoryLocked(int userId) {
|
||||
private ArrayMap<String, PackageHistory> getUserHistory(int userId) {
|
||||
ArrayMap<String, PackageHistory> userHistory = mIdleHistory.get(userId);
|
||||
if (userHistory == null) {
|
||||
userHistory = new ArrayMap<>();
|
||||
mIdleHistory.put(userId, userHistory);
|
||||
readAppIdleTimesLocked(userId, userHistory);
|
||||
readAppIdleTimes(userId, userHistory);
|
||||
}
|
||||
return userHistory;
|
||||
}
|
||||
|
||||
private PackageHistory getPackageHistoryLocked(ArrayMap<String, PackageHistory> userHistory,
|
||||
private PackageHistory getPackageHistory(ArrayMap<String, PackageHistory> userHistory,
|
||||
String packageName, long elapsedRealtime) {
|
||||
PackageHistory packageHistory = userHistory.get(packageName);
|
||||
if (packageHistory == null) {
|
||||
packageHistory = new PackageHistory();
|
||||
packageHistory.lastUsedElapsedTime = getElapsedTimeLocked(elapsedRealtime);
|
||||
packageHistory.lastUsedScreenTime = getScreenOnTimeLocked(elapsedRealtime);
|
||||
packageHistory.lastUsedElapsedTime = getElapsedTime(elapsedRealtime);
|
||||
packageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime);
|
||||
userHistory.put(packageName, packageHistory);
|
||||
}
|
||||
return packageHistory;
|
||||
@@ -248,41 +247,41 @@ public class AppIdleHistory {
|
||||
mIdleHistory.remove(userId);
|
||||
}
|
||||
|
||||
public boolean isIdleLocked(String packageName, int userId, long elapsedRealtime) {
|
||||
ArrayMap<String, PackageHistory> userHistory = getUserHistoryLocked(userId);
|
||||
public boolean isIdle(String packageName, int userId, long elapsedRealtime) {
|
||||
ArrayMap<String, PackageHistory> userHistory = getUserHistory(userId);
|
||||
PackageHistory packageHistory =
|
||||
getPackageHistoryLocked(userHistory, packageName, elapsedRealtime);
|
||||
getPackageHistory(userHistory, packageName, elapsedRealtime);
|
||||
if (packageHistory == null) {
|
||||
return false; // Default to not idle
|
||||
} else {
|
||||
return hasPassedThresholdsLocked(packageHistory, elapsedRealtime);
|
||||
return hasPassedThresholds(packageHistory, elapsedRealtime);
|
||||
}
|
||||
}
|
||||
|
||||
private long getElapsedTimeLocked(long elapsedRealtime) {
|
||||
private long getElapsedTime(long elapsedRealtime) {
|
||||
return (elapsedRealtime - mElapsedSnapshot + mElapsedDuration);
|
||||
}
|
||||
|
||||
public void setIdleLocked(String packageName, int userId, boolean idle, long elapsedRealtime) {
|
||||
ArrayMap<String, PackageHistory> userHistory = getUserHistoryLocked(userId);
|
||||
PackageHistory packageHistory = getPackageHistoryLocked(userHistory, packageName,
|
||||
public void setIdle(String packageName, int userId, boolean idle, long elapsedRealtime) {
|
||||
ArrayMap<String, PackageHistory> userHistory = getUserHistory(userId);
|
||||
PackageHistory packageHistory = getPackageHistory(userHistory, packageName,
|
||||
elapsedRealtime);
|
||||
packageHistory.lastUsedElapsedTime = getElapsedTimeLocked(elapsedRealtime)
|
||||
packageHistory.lastUsedElapsedTime = getElapsedTime(elapsedRealtime)
|
||||
- mElapsedTimeThreshold;
|
||||
packageHistory.lastUsedScreenTime = getScreenOnTimeLocked(elapsedRealtime)
|
||||
packageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime)
|
||||
- (idle ? mScreenOnTimeThreshold : 0) - 1000 /* just a second more */;
|
||||
}
|
||||
|
||||
public void clearUsageLocked(String packageName, int userId) {
|
||||
ArrayMap<String, PackageHistory> userHistory = getUserHistoryLocked(userId);
|
||||
public void clearUsage(String packageName, int userId) {
|
||||
ArrayMap<String, PackageHistory> userHistory = getUserHistory(userId);
|
||||
userHistory.remove(packageName);
|
||||
}
|
||||
|
||||
private boolean hasPassedThresholdsLocked(PackageHistory packageHistory, long elapsedRealtime) {
|
||||
private boolean hasPassedThresholds(PackageHistory packageHistory, long elapsedRealtime) {
|
||||
return (packageHistory.lastUsedScreenTime
|
||||
<= getScreenOnTimeLocked(elapsedRealtime) - mScreenOnTimeThreshold)
|
||||
<= getScreenOnTime(elapsedRealtime) - mScreenOnTimeThreshold)
|
||||
&& (packageHistory.lastUsedElapsedTime
|
||||
<= getElapsedTimeLocked(elapsedRealtime) - mElapsedTimeThreshold);
|
||||
<= getElapsedTime(elapsedRealtime) - mElapsedTimeThreshold);
|
||||
}
|
||||
|
||||
private File getUserFile(int userId) {
|
||||
@@ -290,7 +289,7 @@ public class AppIdleHistory {
|
||||
Integer.toString(userId)), APP_IDLE_FILENAME);
|
||||
}
|
||||
|
||||
private void readAppIdleTimesLocked(int userId, ArrayMap<String, PackageHistory> userHistory) {
|
||||
private void readAppIdleTimes(int userId, ArrayMap<String, PackageHistory> userHistory) {
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
AtomicFile appIdleFile = new AtomicFile(getUserFile(userId));
|
||||
@@ -332,7 +331,7 @@ public class AppIdleHistory {
|
||||
}
|
||||
}
|
||||
|
||||
public void writeAppIdleTimesLocked(int userId) {
|
||||
public void writeAppIdleTimes(int userId) {
|
||||
FileOutputStream fos = null;
|
||||
AtomicFile appIdleFile = new AtomicFile(getUserFile(userId));
|
||||
try {
|
||||
@@ -346,7 +345,7 @@ public class AppIdleHistory {
|
||||
|
||||
xml.startTag(null, TAG_PACKAGES);
|
||||
|
||||
ArrayMap<String,PackageHistory> userHistory = getUserHistoryLocked(userId);
|
||||
ArrayMap<String,PackageHistory> userHistory = getUserHistory(userId);
|
||||
final int N = userHistory.size();
|
||||
for (int i = 0; i < N; i++) {
|
||||
String packageName = userHistory.keyAt(i);
|
||||
@@ -374,8 +373,8 @@ public class AppIdleHistory {
|
||||
idpw.increaseIndent();
|
||||
ArrayMap<String, PackageHistory> userHistory = mIdleHistory.get(userId);
|
||||
final long elapsedRealtime = SystemClock.elapsedRealtime();
|
||||
final long totalElapsedTime = getElapsedTimeLocked(elapsedRealtime);
|
||||
final long screenOnTime = getScreenOnTimeLocked(elapsedRealtime);
|
||||
final long totalElapsedTime = getElapsedTime(elapsedRealtime);
|
||||
final long screenOnTime = getScreenOnTime(elapsedRealtime);
|
||||
if (userHistory == null) return;
|
||||
final int P = userHistory.size();
|
||||
for (int p = 0; p < P; p++) {
|
||||
@@ -386,15 +385,15 @@ public class AppIdleHistory {
|
||||
TimeUtils.formatDuration(totalElapsedTime - packageHistory.lastUsedElapsedTime, idpw);
|
||||
idpw.print(" lastUsedScreenOn=");
|
||||
TimeUtils.formatDuration(screenOnTime - packageHistory.lastUsedScreenTime, idpw);
|
||||
idpw.print(" idle=" + (isIdleLocked(packageName, userId, elapsedRealtime) ? "y" : "n"));
|
||||
idpw.print(" idle=" + (isIdle(packageName, userId, elapsedRealtime) ? "y" : "n"));
|
||||
idpw.println();
|
||||
}
|
||||
idpw.println();
|
||||
idpw.print("totalElapsedTime=");
|
||||
TimeUtils.formatDuration(getElapsedTimeLocked(elapsedRealtime), idpw);
|
||||
TimeUtils.formatDuration(getElapsedTime(elapsedRealtime), idpw);
|
||||
idpw.println();
|
||||
idpw.print("totalScreenOnTime=");
|
||||
TimeUtils.formatDuration(getScreenOnTimeLocked(elapsedRealtime), idpw);
|
||||
TimeUtils.formatDuration(getScreenOnTime(elapsedRealtime), idpw);
|
||||
idpw.println();
|
||||
idpw.decreaseIndent();
|
||||
}
|
||||
@@ -410,7 +409,7 @@ public class AppIdleHistory {
|
||||
for (int i = 0; i < HISTORY_SIZE; i++) {
|
||||
idpw.print(history[i] == 0 ? '.' : 'A');
|
||||
}
|
||||
idpw.print(" idle=" + (isIdleLocked(packageName, userId, elapsedRealtime) ? "y" : "n"));
|
||||
idpw.print(" idle=" + (isIdle(packageName, userId, elapsedRealtime) ? "y" : "n"));
|
||||
idpw.print(" " + packageName);
|
||||
idpw.println();
|
||||
}
|
||||
|
||||
@@ -153,13 +153,17 @@ public class UsageStatsService extends SystemService implements
|
||||
private volatile boolean mPendingOneTimeCheckIdleStates;
|
||||
private boolean mSystemServicesReady = false;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private final Object mAppIdleLock = new Object();
|
||||
@GuardedBy("mAppIdleLock")
|
||||
private AppIdleHistory mAppIdleHistory;
|
||||
|
||||
@GuardedBy("mAppIdleLock")
|
||||
private ArrayList<UsageStatsManagerInternal.AppIdleStateChangeListener>
|
||||
mPackageAccessListeners = new ArrayList<>();
|
||||
|
||||
@GuardedBy("mAppIdleLock")
|
||||
private boolean mHaveCarrierPrivilegedApps;
|
||||
@GuardedBy("mAppIdleLock")
|
||||
private List<String> mCarrierPrivilegedApps;
|
||||
|
||||
public UsageStatsService(Context context) {
|
||||
@@ -206,6 +210,8 @@ public class UsageStatsService extends SystemService implements
|
||||
|
||||
synchronized (mLock) {
|
||||
cleanUpRemovedUsersLocked();
|
||||
}
|
||||
synchronized (mAppIdleLock) {
|
||||
mAppIdleHistory = new AppIdleHistory(SystemClock.elapsedRealtime());
|
||||
}
|
||||
|
||||
@@ -234,8 +240,8 @@ public class UsageStatsService extends SystemService implements
|
||||
mPowerManager = getContext().getSystemService(PowerManager.class);
|
||||
|
||||
mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
|
||||
synchronized (mLock) {
|
||||
mAppIdleHistory.updateDisplayLocked(isDisplayOn(), SystemClock.elapsedRealtime());
|
||||
synchronized (mAppIdleLock) {
|
||||
mAppIdleHistory.updateDisplay(isDisplayOn(), SystemClock.elapsedRealtime());
|
||||
}
|
||||
|
||||
if (mPendingOneTimeCheckIdleStates) {
|
||||
@@ -324,8 +330,8 @@ public class UsageStatsService extends SystemService implements
|
||||
@Override public void onDisplayChanged(int displayId) {
|
||||
if (displayId == Display.DEFAULT_DISPLAY) {
|
||||
final boolean displayOn = isDisplayOn();
|
||||
synchronized (UsageStatsService.this.mLock) {
|
||||
mAppIdleHistory.updateDisplayLocked(displayOn, SystemClock.elapsedRealtime());
|
||||
synchronized (UsageStatsService.this.mAppIdleLock) {
|
||||
mAppIdleHistory.updateDisplay(displayOn, SystemClock.elapsedRealtime());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -386,18 +392,20 @@ public class UsageStatsService extends SystemService implements
|
||||
PackageManager.MATCH_DISABLED_COMPONENTS,
|
||||
userId);
|
||||
final int packageCount = packages.size();
|
||||
for (int i = 0; i < packageCount; i++) {
|
||||
final PackageInfo pi = packages.get(i);
|
||||
String packageName = pi.packageName;
|
||||
if (pi.applicationInfo != null && pi.applicationInfo.isSystemApp()) {
|
||||
mAppIdleHistory.reportUsageLocked(packageName, userId, elapsedRealtime);
|
||||
synchronized (mAppIdleLock) {
|
||||
for (int i = 0; i < packageCount; i++) {
|
||||
final PackageInfo pi = packages.get(i);
|
||||
String packageName = pi.packageName;
|
||||
if (pi.applicationInfo != null && pi.applicationInfo.isSystemApp()) {
|
||||
mAppIdleHistory.reportUsage(packageName, userId, elapsedRealtime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clearAppIdleForPackage(String packageName, int userId) {
|
||||
synchronized (mLock) {
|
||||
mAppIdleHistory.clearUsageLocked(packageName, userId);
|
||||
synchronized (mAppIdleLock) {
|
||||
mAppIdleHistory.clearUsage(packageName, userId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -429,7 +437,7 @@ public class UsageStatsService extends SystemService implements
|
||||
}
|
||||
|
||||
void setChargingState(boolean charging) {
|
||||
synchronized (mLock) {
|
||||
synchronized (mAppIdleLock) {
|
||||
if (mCharging != charging) {
|
||||
mCharging = charging;
|
||||
postParoleStateChanged();
|
||||
@@ -439,15 +447,16 @@ public class UsageStatsService extends SystemService implements
|
||||
|
||||
/** Paroled here means temporary pardon from being inactive */
|
||||
void setAppIdleParoled(boolean paroled) {
|
||||
synchronized (mLock) {
|
||||
synchronized (mAppIdleLock) {
|
||||
final long now = System.currentTimeMillis();
|
||||
if (mAppIdleTempParoled != paroled) {
|
||||
mAppIdleTempParoled = paroled;
|
||||
if (DEBUG) Slog.d(TAG, "Changing paroled to " + mAppIdleTempParoled);
|
||||
if (paroled) {
|
||||
postParoleEndTimeout();
|
||||
} else {
|
||||
mLastAppIdleParoledTime = checkAndGetTimeLocked();
|
||||
postNextParoleTimeout();
|
||||
mLastAppIdleParoledTime = now;
|
||||
postNextParoleTimeout(now);
|
||||
}
|
||||
postParoleStateChanged();
|
||||
}
|
||||
@@ -455,19 +464,18 @@ public class UsageStatsService extends SystemService implements
|
||||
}
|
||||
|
||||
boolean isParoledOrCharging() {
|
||||
synchronized (mLock) {
|
||||
synchronized (mAppIdleLock) {
|
||||
return mAppIdleTempParoled || mCharging;
|
||||
}
|
||||
}
|
||||
|
||||
private void postNextParoleTimeout() {
|
||||
private void postNextParoleTimeout(long now) {
|
||||
if (DEBUG) Slog.d(TAG, "Posting MSG_CHECK_PAROLE_TIMEOUT");
|
||||
mHandler.removeMessages(MSG_CHECK_PAROLE_TIMEOUT);
|
||||
// Compute when the next parole needs to happen. We check more frequently than necessary
|
||||
// since the message handler delays are based on elapsedRealTime and not wallclock time.
|
||||
// The comparison is done in wallclock time.
|
||||
long timeLeft = (mLastAppIdleParoledTime + mAppIdleParoleIntervalMillis)
|
||||
- checkAndGetTimeLocked();
|
||||
long timeLeft = (mLastAppIdleParoledTime + mAppIdleParoleIntervalMillis) - now;
|
||||
if (timeLeft < 0) {
|
||||
timeLeft = 0;
|
||||
}
|
||||
@@ -546,7 +554,7 @@ public class UsageStatsService extends SystemService implements
|
||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
|
||||
userId, isIdle ? 1 : 0, packageName));
|
||||
if (isIdle) {
|
||||
synchronized (mLock) {
|
||||
synchronized (mAppIdleLock) {
|
||||
mAppIdleHistory.setIdle(packageName, userId, elapsedRealtime);
|
||||
}
|
||||
}
|
||||
@@ -561,18 +569,23 @@ public class UsageStatsService extends SystemService implements
|
||||
|
||||
/** Check if it's been a while since last parole and let idle apps do some work */
|
||||
void checkParoleTimeout() {
|
||||
synchronized (mLock) {
|
||||
boolean setParoled = false;
|
||||
synchronized (mAppIdleLock) {
|
||||
final long now = System.currentTimeMillis();
|
||||
if (!mAppIdleTempParoled) {
|
||||
final long timeSinceLastParole = checkAndGetTimeLocked() - mLastAppIdleParoledTime;
|
||||
final long timeSinceLastParole = now - mLastAppIdleParoledTime;
|
||||
if (timeSinceLastParole > mAppIdleParoleIntervalMillis) {
|
||||
if (DEBUG) Slog.d(TAG, "Crossed default parole interval");
|
||||
setAppIdleParoled(true);
|
||||
setParoled = true;
|
||||
} else {
|
||||
if (DEBUG) Slog.d(TAG, "Not long enough to go to parole");
|
||||
postNextParoleTimeout();
|
||||
postNextParoleTimeout(now);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (setParoled) {
|
||||
setAppIdleParoled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyBatteryStats(String packageName, int userId, boolean idle) {
|
||||
@@ -593,17 +606,23 @@ public class UsageStatsService extends SystemService implements
|
||||
void onDeviceIdleModeChanged() {
|
||||
final boolean deviceIdle = mPowerManager.isDeviceIdleMode();
|
||||
if (DEBUG) Slog.i(TAG, "DeviceIdleMode changed to " + deviceIdle);
|
||||
synchronized (mLock) {
|
||||
final long timeSinceLastParole = checkAndGetTimeLocked() - mLastAppIdleParoledTime;
|
||||
boolean paroled = false;
|
||||
synchronized (mAppIdleLock) {
|
||||
final long timeSinceLastParole = System.currentTimeMillis() - mLastAppIdleParoledTime;
|
||||
if (!deviceIdle
|
||||
&& timeSinceLastParole >= mAppIdleParoleIntervalMillis) {
|
||||
if (DEBUG) Slog.i(TAG, "Bringing idle apps out of inactive state due to deviceIdleMode=false");
|
||||
setAppIdleParoled(true);
|
||||
if (DEBUG) {
|
||||
Slog.i(TAG, "Bringing idle apps out of inactive state due to deviceIdleMode=false");
|
||||
}
|
||||
paroled = true;
|
||||
} else if (deviceIdle) {
|
||||
if (DEBUG) Slog.i(TAG, "Device idle, back to prison");
|
||||
setAppIdleParoled(false);
|
||||
paroled = false;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
setAppIdleParoled(paroled);
|
||||
}
|
||||
|
||||
private static void deleteRecursively(File f) {
|
||||
@@ -682,21 +701,24 @@ public class UsageStatsService extends SystemService implements
|
||||
|
||||
final UserUsageStatsService service =
|
||||
getUserDataAndInitializeIfNeededLocked(userId, timeNow);
|
||||
// TODO: Ideally this should call isAppIdleFiltered() to avoid calling back
|
||||
// about apps that are on some kind of whitelist anyway.
|
||||
final boolean previouslyIdle = mAppIdleHistory.isIdleLocked(
|
||||
event.mPackage, userId, elapsedRealtime);
|
||||
service.reportEvent(event);
|
||||
// Inform listeners if necessary
|
||||
if ((event.mEventType == Event.MOVE_TO_FOREGROUND
|
||||
|| event.mEventType == Event.MOVE_TO_BACKGROUND
|
||||
|| event.mEventType == Event.SYSTEM_INTERACTION
|
||||
|| event.mEventType == Event.USER_INTERACTION)) {
|
||||
mAppIdleHistory.reportUsageLocked(event.mPackage, userId, elapsedRealtime);
|
||||
if (previouslyIdle) {
|
||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
|
||||
/* idle = */ 0, event.mPackage));
|
||||
notifyBatteryStats(event.mPackage, userId, false);
|
||||
|
||||
synchronized (mAppIdleLock) {
|
||||
// TODO: Ideally this should call isAppIdleFiltered() to avoid calling back
|
||||
// about apps that are on some kind of whitelist anyway.
|
||||
final boolean previouslyIdle = mAppIdleHistory.isIdle(
|
||||
event.mPackage, userId, elapsedRealtime);
|
||||
// Inform listeners if necessary
|
||||
if ((event.mEventType == Event.MOVE_TO_FOREGROUND
|
||||
|| event.mEventType == Event.MOVE_TO_BACKGROUND
|
||||
|| event.mEventType == Event.SYSTEM_INTERACTION
|
||||
|| event.mEventType == Event.USER_INTERACTION)) {
|
||||
mAppIdleHistory.reportUsage(event.mPackage, userId, elapsedRealtime);
|
||||
if (previouslyIdle) {
|
||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
|
||||
/* idle = */ 0, event.mPackage));
|
||||
notifyBatteryStats(event.mPackage, userId, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -716,7 +738,7 @@ public class UsageStatsService extends SystemService implements
|
||||
continue;
|
||||
}
|
||||
if (!packageName.equals(providerPkgName)) {
|
||||
forceIdleState(packageName, userId, false);
|
||||
setAppIdleAsync(packageName, false, userId);
|
||||
}
|
||||
} catch (NameNotFoundException e) {
|
||||
// Shouldn't happen
|
||||
@@ -728,25 +750,28 @@ public class UsageStatsService extends SystemService implements
|
||||
* Forces the app's beginIdleTime and lastUsedTime to reflect idle or active. If idle,
|
||||
* then it rolls back the beginIdleTime and lastUsedTime to a point in time that's behind
|
||||
* the threshold for idle.
|
||||
*
|
||||
* This method is always called from the handler thread, so not much synchronization is
|
||||
* required.
|
||||
*/
|
||||
void forceIdleState(String packageName, int userId, boolean idle) {
|
||||
final int appId = getAppId(packageName);
|
||||
if (appId < 0) return;
|
||||
synchronized (mLock) {
|
||||
final long elapsedRealtime = SystemClock.elapsedRealtime();
|
||||
final long elapsedRealtime = SystemClock.elapsedRealtime();
|
||||
|
||||
final boolean previouslyIdle = isAppIdleFiltered(packageName, appId,
|
||||
userId, elapsedRealtime);
|
||||
mAppIdleHistory.setIdleLocked(packageName, userId, idle, elapsedRealtime);
|
||||
final boolean stillIdle = isAppIdleFiltered(packageName, appId,
|
||||
userId, elapsedRealtime);
|
||||
// Inform listeners if necessary
|
||||
if (previouslyIdle != stillIdle) {
|
||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
|
||||
/* idle = */ stillIdle ? 1 : 0, packageName));
|
||||
if (!stillIdle) {
|
||||
notifyBatteryStats(packageName, userId, idle);
|
||||
}
|
||||
final boolean previouslyIdle = isAppIdleFiltered(packageName, appId,
|
||||
userId, elapsedRealtime);
|
||||
synchronized (mAppIdleLock) {
|
||||
mAppIdleHistory.setIdle(packageName, userId, idle, elapsedRealtime);
|
||||
}
|
||||
final boolean stillIdle = isAppIdleFiltered(packageName, appId,
|
||||
userId, elapsedRealtime);
|
||||
// Inform listeners if necessary
|
||||
if (previouslyIdle != stillIdle) {
|
||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
|
||||
/* idle = */ stillIdle ? 1 : 0, packageName));
|
||||
if (!stillIdle) {
|
||||
notifyBatteryStats(packageName, userId, idle);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -767,7 +792,9 @@ public class UsageStatsService extends SystemService implements
|
||||
synchronized (mLock) {
|
||||
Slog.i(TAG, "Removing user " + userId + " and all data.");
|
||||
mUserState.remove(userId);
|
||||
mAppIdleHistory.onUserRemoved(userId);
|
||||
synchronized (mAppIdleLock) {
|
||||
mAppIdleHistory.onUserRemoved(userId);
|
||||
}
|
||||
cleanUpRemovedUsersLocked();
|
||||
}
|
||||
}
|
||||
@@ -822,13 +849,13 @@ public class UsageStatsService extends SystemService implements
|
||||
}
|
||||
|
||||
private boolean isAppIdleUnfiltered(String packageName, int userId, long elapsedRealtime) {
|
||||
synchronized (mLock) {
|
||||
return mAppIdleHistory.isIdleLocked(packageName, userId, elapsedRealtime);
|
||||
synchronized (mAppIdleLock) {
|
||||
return mAppIdleHistory.isIdle(packageName, userId, elapsedRealtime);
|
||||
}
|
||||
}
|
||||
|
||||
void addListener(AppIdleStateChangeListener listener) {
|
||||
synchronized (mLock) {
|
||||
synchronized (mAppIdleLock) {
|
||||
if (!mPackageAccessListeners.contains(listener)) {
|
||||
mPackageAccessListeners.add(listener);
|
||||
}
|
||||
@@ -836,7 +863,7 @@ public class UsageStatsService extends SystemService implements
|
||||
}
|
||||
|
||||
void removeListener(AppIdleStateChangeListener listener) {
|
||||
synchronized (mLock) {
|
||||
synchronized (mAppIdleLock) {
|
||||
mPackageAccessListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
@@ -988,7 +1015,7 @@ public class UsageStatsService extends SystemService implements
|
||||
return res;
|
||||
}
|
||||
|
||||
void setAppIdle(String packageName, boolean idle, int userId) {
|
||||
void setAppIdleAsync(String packageName, boolean idle, int userId) {
|
||||
if (packageName == null) return;
|
||||
|
||||
mHandler.obtainMessage(MSG_FORCE_IDLE_STATE, userId, idle ? 1 : 0, packageName)
|
||||
@@ -1012,9 +1039,9 @@ public class UsageStatsService extends SystemService implements
|
||||
}
|
||||
|
||||
private boolean isCarrierApp(String packageName) {
|
||||
synchronized (mLock) {
|
||||
synchronized (mAppIdleLock) {
|
||||
if (!mHaveCarrierPrivilegedApps) {
|
||||
fetchCarrierPrivilegedAppsLocked();
|
||||
fetchCarrierPrivilegedAppsLA();
|
||||
}
|
||||
if (mCarrierPrivilegedApps != null) {
|
||||
return mCarrierPrivilegedApps.contains(packageName);
|
||||
@@ -1027,13 +1054,14 @@ public class UsageStatsService extends SystemService implements
|
||||
if (DEBUG) {
|
||||
Slog.i(TAG, "Clearing carrier privileged apps list");
|
||||
}
|
||||
synchronized (mLock) {
|
||||
synchronized (mAppIdleLock) {
|
||||
mHaveCarrierPrivilegedApps = false;
|
||||
mCarrierPrivilegedApps = null; // Need to be refetched.
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchCarrierPrivilegedAppsLocked() {
|
||||
@GuardedBy("mAppIdleLock")
|
||||
private void fetchCarrierPrivilegedAppsLA() {
|
||||
TelephonyManager telephonyManager =
|
||||
getContext().getSystemService(TelephonyManager.class);
|
||||
mCarrierPrivilegedApps = telephonyManager.getPackagesWithCarrierPrivileges();
|
||||
@@ -1071,11 +1099,15 @@ public class UsageStatsService extends SystemService implements
|
||||
for (int i = 0; i < userCount; i++) {
|
||||
UserUsageStatsService service = mUserState.valueAt(i);
|
||||
service.persistActiveStats();
|
||||
mAppIdleHistory.writeAppIdleTimesLocked(mUserState.keyAt(i));
|
||||
synchronized (mAppIdleLock) {
|
||||
mAppIdleHistory.writeAppIdleTimes(mUserState.keyAt(i));
|
||||
}
|
||||
}
|
||||
// Persist elapsed and screen on time. If this fails for whatever reason, the apps will be
|
||||
// considered not-idle, which is the safest outcome in such an event.
|
||||
mAppIdleHistory.writeAppIdleDurationsLocked();
|
||||
synchronized (mAppIdleLock) {
|
||||
mAppIdleHistory.writeAppIdleDurations();
|
||||
}
|
||||
mHandler.removeMessages(MSG_FLUSH_TO_DISK);
|
||||
}
|
||||
|
||||
@@ -1100,20 +1132,26 @@ public class UsageStatsService extends SystemService implements
|
||||
idpw.println();
|
||||
if (args.length > 0) {
|
||||
if ("history".equals(args[0])) {
|
||||
mAppIdleHistory.dumpHistory(idpw, mUserState.keyAt(i));
|
||||
synchronized (mAppIdleLock) {
|
||||
mAppIdleHistory.dumpHistory(idpw, mUserState.keyAt(i));
|
||||
}
|
||||
} else if ("flush".equals(args[0])) {
|
||||
UsageStatsService.this.flushToDiskLocked();
|
||||
pw.println("Flushed stats to disk");
|
||||
}
|
||||
}
|
||||
}
|
||||
mAppIdleHistory.dump(idpw, mUserState.keyAt(i));
|
||||
synchronized (mAppIdleLock) {
|
||||
mAppIdleHistory.dump(idpw, mUserState.keyAt(i));
|
||||
}
|
||||
idpw.decreaseIndent();
|
||||
}
|
||||
|
||||
pw.println();
|
||||
pw.println("Carrier privileged apps (have=" + mHaveCarrierPrivilegedApps
|
||||
+ "): " + mCarrierPrivilegedApps);
|
||||
synchronized (mAppIdleLock) {
|
||||
pw.println("Carrier privileged apps (have=" + mHaveCarrierPrivilegedApps
|
||||
+ "): " + mCarrierPrivilegedApps);
|
||||
}
|
||||
|
||||
pw.println();
|
||||
pw.println("Settings:");
|
||||
@@ -1252,7 +1290,7 @@ public class UsageStatsService extends SystemService implements
|
||||
}
|
||||
|
||||
void updateSettings() {
|
||||
synchronized (mLock) {
|
||||
synchronized (mAppIdleLock) {
|
||||
// Look at global settings for this.
|
||||
// TODO: Maybe apply different thresholds for different users.
|
||||
try {
|
||||
@@ -1384,7 +1422,7 @@ public class UsageStatsService extends SystemService implements
|
||||
try {
|
||||
userId = ActivityManager.getService().handleIncomingUser(
|
||||
Binder.getCallingPid(), callingUid, userId, false, true,
|
||||
"setAppIdle", null);
|
||||
"setAppInactive", null);
|
||||
} catch (RemoteException re) {
|
||||
throw re.rethrowFromSystemServer();
|
||||
}
|
||||
@@ -1394,7 +1432,7 @@ public class UsageStatsService extends SystemService implements
|
||||
try {
|
||||
final int appId = getAppId(packageName);
|
||||
if (appId < 0) return;
|
||||
UsageStatsService.this.setAppIdle(packageName, idle, userId);
|
||||
UsageStatsService.this.setAppIdleAsync(packageName, idle, userId);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
@@ -1586,21 +1624,25 @@ public class UsageStatsService extends SystemService implements
|
||||
@Override
|
||||
public byte[] getBackupPayload(int user, String key) {
|
||||
// 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());
|
||||
return userStats.getBackupPayload(key);
|
||||
} else {
|
||||
return null;
|
||||
synchronized (UsageStatsService.this.mLock) {
|
||||
if (user == UserHandle.USER_SYSTEM) {
|
||||
final UserUsageStatsService userStats =
|
||||
getUserDataAndInitializeIfNeededLocked(user, checkAndGetTimeLocked());
|
||||
return userStats.getBackupPayload(key);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyRestoredPayload(int user, String key, byte[] payload) {
|
||||
if (user == UserHandle.USER_SYSTEM) {
|
||||
final UserUsageStatsService userStats =
|
||||
getUserDataAndInitializeIfNeededLocked(user, checkAndGetTimeLocked());
|
||||
userStats.applyRestoredPayload(key, payload);
|
||||
synchronized (UsageStatsService.this.mLock) {
|
||||
if (user == UserHandle.USER_SYSTEM) {
|
||||
final UserUsageStatsService userStats =
|
||||
getUserDataAndInitializeIfNeededLocked(user, checkAndGetTimeLocked());
|
||||
userStats.applyRestoredPayload(key, payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -529,7 +529,6 @@ class UserUsageStatsService {
|
||||
pw.decreaseIndent();
|
||||
|
||||
pw.println();
|
||||
pw.increaseIndent();
|
||||
pw.println("ChooserCounts");
|
||||
pw.increaseIndent();
|
||||
for (UsageStats usageStats : pkgStats.values()) {
|
||||
@@ -553,6 +552,7 @@ class UserUsageStatsService {
|
||||
}
|
||||
pw.println();
|
||||
}
|
||||
pw.decreaseIndent();
|
||||
|
||||
pw.println("configurations");
|
||||
pw.increaseIndent();
|
||||
|
||||
Reference in New Issue
Block a user