Reduce screen on delay during UsageStats rollover
Decoupled the app idle book-keeping from usage stats lock, by
introducing an mAppIdleLock. This is used for all state related
to app idle. In some cases, the locks will be nested, with
mLock being acquired first and then mAppIdleLock.
This should fix the situation where a rollover, which writes to
disk and could take several seconds when the system is swamped,
like when the device just came out of idle and the screen was
turned on (like this run-on sentence), causes calls from other
services for app-idle status to be blocked. This was resulting
in a long time to turn on the screen.
Also fixed a dump indentation issue.
Bug: 34627115
Bug: 34961340
Test: Manual, force into idle, increased rollover frequency,
and tested screen on time.
Change-Id: Ie8b44e6f07f82d8a31f1b733a403dd9b6dc310f6
This commit is contained in:
@@ -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