diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 7fd166059ac46..aab7b1f504ba9 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -119,6 +119,16 @@ public abstract class BatteryStats implements Parcelable { */ public static final int PROCESS_STATE = 12; + /** + * A constant indicating a sync timer + */ + public static final int SYNC = 13; + + /** + * A constant indicating a job timer + */ + public static final int JOB = 14; + /** * Include all of the data in the stats, including previously saved data. */ @@ -157,6 +167,8 @@ public abstract class BatteryStats implements Parcelable { private static final String FOREGROUND_DATA = "fg"; private static final String STATE_TIME_DATA = "st"; private static final String WAKELOCK_DATA = "wl"; + private static final String SYNC_DATA = "sy"; + private static final String JOB_DATA = "jb"; private static final String KERNEL_WAKELOCK_DATA = "kwl"; private static final String WAKEUP_REASON_DATA = "wr"; private static final String NETWORK_DATA = "nt"; @@ -272,6 +284,20 @@ public abstract class BatteryStats implements Parcelable { */ public abstract Map getWakelockStats(); + /** + * Returns a mapping containing sync statistics. + * + * @return a Map from Strings to Timer objects. + */ + public abstract Map getSyncStats(); + + /** + * Returns a mapping containing scheduled job statistics. + * + * @return a Map from Strings to Timer objects. + */ + public abstract Map getJobStats(); + /** * The statistics associated with a particular wake lock. */ @@ -660,13 +686,19 @@ public abstract class BatteryStats implements Parcelable { public static final int EVENT_FOREGROUND = 0x0002; // Event is about an application package that is at the top of the screen. public static final int EVENT_TOP = 0x0003; - // Event is about an application package that is at the top of the screen. + // Event is about active sync operations. public static final int EVENT_SYNC = 0x0004; // Events for all additional wake locks aquired/release within a wake block. // These are not generated by default. public static final int EVENT_WAKE_LOCK = 0x0005; + // Event is about an application executing a scheduled job. + public static final int EVENT_JOB = 0x0006; + // Events for users running. + public static final int EVENT_USER_RUNNING = 0x0007; + // Events for foreground user. + public static final int EVENT_USER_FOREGROUND = 0x0008; // Number of event types. - public static final int EVENT_COUNT = 0x0006; + public static final int EVENT_COUNT = 0x0009; // Mask to extract out only the type part of the event. public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH); @@ -680,6 +712,14 @@ public abstract class BatteryStats implements Parcelable { public static final int EVENT_SYNC_FINISH = EVENT_SYNC | EVENT_FLAG_FINISH; public static final int EVENT_WAKE_LOCK_START = EVENT_WAKE_LOCK | EVENT_FLAG_START; public static final int EVENT_WAKE_LOCK_FINISH = EVENT_WAKE_LOCK | EVENT_FLAG_FINISH; + public static final int EVENT_JOB_START = EVENT_JOB | EVENT_FLAG_START; + public static final int EVENT_JOB_FINISH = EVENT_JOB | EVENT_FLAG_FINISH; + public static final int EVENT_USER_RUNNING_START = EVENT_USER_RUNNING | EVENT_FLAG_START; + public static final int EVENT_USER_RUNNING_FINISH = EVENT_USER_RUNNING | EVENT_FLAG_FINISH; + public static final int EVENT_USER_FOREGROUND_START = + EVENT_USER_FOREGROUND | EVENT_FLAG_START; + public static final int EVENT_USER_FOREGROUND_FINISH = + EVENT_USER_FOREGROUND | EVENT_FLAG_FINISH; // For CMD_EVENT. public int eventCode; @@ -1269,11 +1309,11 @@ public abstract class BatteryStats implements Parcelable { }; public static final String[] HISTORY_EVENT_NAMES = new String[] { - "null", "proc", "fg", "top", "sync", "wake_lock_in" + "null", "proc", "fg", "top", "sync", "wake_lock_in", "job", "user", "userfg" }; public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] { - "Enl", "Epr", "Efg", "Etp", "Esy", "Ewl" + "Enl", "Epr", "Efg", "Etp", "Esy", "Ewl", "Ejb", "Eur", "Euf" }; /** @@ -2080,10 +2120,9 @@ public abstract class BatteryStats implements Parcelable { } } - Map wakelocks = u.getWakelockStats(); + Map wakelocks = u.getWakelockStats(); if (wakelocks.size() > 0) { - for (Map.Entry ent - : wakelocks.entrySet()) { + for (Map.Entry ent : wakelocks.entrySet()) { Uid.Wakelock wl = ent.getValue(); String linePrefix = ""; sb.setLength(0); @@ -2105,6 +2144,32 @@ public abstract class BatteryStats implements Parcelable { } } + Map syncs = u.getSyncStats(); + if (syncs.size() > 0) { + for (Map.Entry ent : syncs.entrySet()) { + Timer timer = ent.getValue(); + // Convert from microseconds to milliseconds with rounding + long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000; + int count = timer.getCountLocked(which); + if (totalTime != 0) { + dumpLine(pw, uid, category, SYNC_DATA, ent.getKey(), totalTime, count); + } + } + } + + Map jobs = u.getJobStats(); + if (jobs.size() > 0) { + for (Map.Entry ent : jobs.entrySet()) { + Timer timer = ent.getValue(); + // Convert from microseconds to milliseconds with rounding + long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000; + int count = timer.getCountLocked(which); + if (totalTime != 0) { + dumpLine(pw, uid, category, JOB_DATA, ent.getKey(), totalTime, count); + } + } + } + SparseArray sensors = u.getSensorStats(); int NSE = sensors.size(); for (int ise=0; ise 0) { long totalFull = 0, totalPartial = 0, totalWindow = 0; int count = 0; - for (Map.Entry ent - : wakelocks.entrySet()) { + for (Map.Entry ent : wakelocks.entrySet()) { Uid.Wakelock wl = ent.getValue(); String linePrefix = ": "; sb.setLength(0); @@ -2998,6 +3062,56 @@ public abstract class BatteryStats implements Parcelable { } } + Map syncs = u.getSyncStats(); + if (syncs.size() > 0) { + for (Map.Entry ent : syncs.entrySet()) { + Timer timer = ent.getValue(); + // Convert from microseconds to milliseconds with rounding + long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000; + int count = timer.getCountLocked(which); + sb.setLength(0); + sb.append(prefix); + sb.append(" Sync "); + sb.append(ent.getKey()); + sb.append(": "); + if (totalTime != 0) { + formatTimeMs(sb, totalTime); + sb.append("realtime ("); + sb.append(count); + sb.append(" times)"); + } else { + sb.append("(not used)"); + } + pw.println(sb.toString()); + uidActivity = true; + } + } + + Map jobs = u.getJobStats(); + if (syncs.size() > 0) { + for (Map.Entry ent : jobs.entrySet()) { + Timer timer = ent.getValue(); + // Convert from microseconds to milliseconds with rounding + long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000; + int count = timer.getCountLocked(which); + sb.setLength(0); + sb.append(prefix); + sb.append(" Job "); + sb.append(ent.getKey()); + sb.append(": "); + if (totalTime != 0) { + formatTimeMs(sb, totalTime); + sb.append("realtime ("); + sb.append(count); + sb.append(" times)"); + } else { + sb.append("(not used)"); + } + pw.println(sb.toString()); + uidActivity = true; + } + } + SparseArray sensors = u.getSensorStats(); int NSE = sensors.size(); for (int ise=0; ise mWakelockStats = new ArrayMap(); + /** + * The statistics we have collected for this uid's syncs. + */ + final ArrayMap mSyncStats = new ArrayMap(); + + /** + * The statistics we have collected for this uid's jobs. + */ + final ArrayMap mJobStats = new ArrayMap(); + /** * The statistics we have collected for this uid's sensor activations. */ @@ -3871,6 +3930,16 @@ public final class BatteryStatsImpl extends BatteryStats { return mWakelockStats; } + @Override + public Map getSyncStats() { + return mSyncStats; + } + + @Override + public Map getJobStats() { + return mJobStats; + } + @Override public SparseArray getSensorStats() { return mSensorStats; @@ -4396,6 +4465,24 @@ public final class BatteryStatsImpl extends BatteryStats { active = true; } } + for (int is=mSyncStats.size()-1; is>=0; is--) { + StopwatchTimer timer = mSyncStats.valueAt(is); + if (timer.reset(false)) { + mSyncStats.removeAt(is); + timer.detach(); + } else { + active = true; + } + } + for (int ij=mJobStats.size()-1; ij>=0; ij--) { + StopwatchTimer timer = mJobStats.valueAt(ij); + if (timer.reset(false)) { + mJobStats.removeAt(ij); + timer.detach(); + } else { + active = true; + } + } for (int ise=mSensorStats.size()-1; ise>=0; ise--) { Sensor s = mSensorStats.valueAt(ise); if (s.reset()) { @@ -4497,6 +4584,22 @@ public final class BatteryStatsImpl extends BatteryStats { wakelock.writeToParcelLocked(out, elapsedRealtimeUs); } + int NS = mSyncStats.size(); + out.writeInt(NS); + for (int is=0; is MAX_WAKELOCKS_PER_UID) { + name = BATCHED_WAKELOCK_NAME; + t = mSyncStats.get(name); + } + if (t == null) { + t = new StopwatchTimer(Uid.this, SYNC, null, mOnBatteryTimeBase); + mSyncStats.put(name, t); + } + } + return t; + } + + public StopwatchTimer getJobTimerLocked(String name) { + StopwatchTimer t = mJobStats.get(name); + if (t == null) { + final int N = mJobStats.size(); + if (N > MAX_WAKELOCKS_PER_UID) { + name = BATCHED_WAKELOCK_NAME; + t = mJobStats.get(name); + } + if (t == null) { + t = new StopwatchTimer(Uid.this, JOB, null, mOnBatteryTimeBase); + mJobStats.put(name, t); + } + } + return t; + } + public StopwatchTimer getWakeTimerLocked(String name, int type) { Wakelock wl = mWakelockStats.get(name); if (wl == null) { @@ -5737,6 +5891,34 @@ public final class BatteryStatsImpl extends BatteryStats { return t; } + public void noteStartSyncLocked(String name, long elapsedRealtimeMs) { + StopwatchTimer t = getSyncTimerLocked(name); + if (t != null) { + t.startRunningLocked(elapsedRealtimeMs); + } + } + + public void noteStopSyncLocked(String name, long elapsedRealtimeMs) { + StopwatchTimer t = getSyncTimerLocked(name); + if (t != null) { + t.stopRunningLocked(elapsedRealtimeMs); + } + } + + public void noteStartJobLocked(String name, long elapsedRealtimeMs) { + StopwatchTimer t = getJobTimerLocked(name); + if (t != null) { + t.startRunningLocked(elapsedRealtimeMs); + } + } + + public void noteStopJobLocked(String name, long elapsedRealtimeMs) { + StopwatchTimer t = getJobTimerLocked(name); + if (t != null) { + t.stopRunningLocked(elapsedRealtimeMs); + } + } + public void noteStartWakeLocked(int pid, String name, int type, long elapsedRealtimeMs) { StopwatchTimer t = getWakeTimerLocked(name, type); if (t != null) { @@ -7170,7 +7352,7 @@ public final class BatteryStatsImpl extends BatteryStats { // the last run until samples in this run. if (mHistoryBaseTime > 0) { long oldnow = SystemClock.elapsedRealtime(); - mHistoryBaseTime = (mHistoryBaseTime - oldnow) + 60*1000; + mHistoryBaseTime = mHistoryBaseTime - oldnow + 1; if (DEBUG_HISTORY) { StringBuilder sb = new StringBuilder(128); sb.append("****************** ADJUSTED mHistoryBaseTime: "); @@ -7433,6 +7615,26 @@ public final class BatteryStatsImpl extends BatteryStats { } } + int NS = in.readInt(); + if (NS > 100) { + Slog.w(TAG, "File corrupt: too many syncs " + NS); + return; + } + for (int is = 0; is < NS; is++) { + String name = in.readString(); + u.getSyncTimerLocked(name).readSummaryFromParcelLocked(in); + } + + int NJ = in.readInt(); + if (NJ > 100) { + Slog.w(TAG, "File corrupt: too many job timers " + NJ); + return; + } + for (int ij = 0; ij < NJ; ij++) { + String name = in.readString(); + u.getJobTimerLocked(name).readSummaryFromParcelLocked(in); + } + int NP = in.readInt(); if (NP > 1000) { Slog.w(TAG, "File corrupt: too many sensors " + NP); @@ -7484,7 +7686,7 @@ public final class BatteryStatsImpl extends BatteryStats { String pkgName = in.readString(); Uid.Pkg p = u.getPackageStatsLocked(pkgName); p.mWakeups = p.mLoadedWakeups = in.readInt(); - final int NS = in.readInt(); + NS = in.readInt(); if (NS > 1000) { Slog.w(TAG, "File corrupt: too many services " + NS); return; @@ -7717,6 +7919,20 @@ public final class BatteryStatsImpl extends BatteryStats { } } + int NS = u.mSyncStats.size(); + out.writeInt(NS); + for (int is=0; is 0) { for (Map.Entry sent @@ -7786,7 +8002,7 @@ public final class BatteryStatsImpl extends BatteryStats { void readFromParcelLocked(Parcel in) { int magic = in.readInt(); if (magic != MAGIC) { - throw new ParcelFormatException("Bad magic number"); + throw new ParcelFormatException("Bad magic number: #" + Integer.toHexString(magic)); } readHistory(in, false); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 8ef6dd61ff92e..79cb60e16d4a2 100755 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1811,10 +1811,18 @@ public final class ActivityManagerService extends ActivityManagerNative break; } case SYSTEM_USER_START_MSG: { + mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_RUNNING_START, + Integer.toString(msg.arg1), msg.arg1); mSystemServiceManager.startUser(msg.arg1); break; } case SYSTEM_USER_CURRENT_MSG: { + mBatteryStatsService.noteEvent( + BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_FINISH, + Integer.toString(msg.arg2), msg.arg2); + mBatteryStatsService.noteEvent( + BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_START, + Integer.toString(msg.arg1), msg.arg1); mSystemServiceManager.switchUser(msg.arg1); break; } @@ -10168,7 +10176,11 @@ public final class ActivityManagerService extends ActivityManagerNative } if (goingCallback != null) goingCallback.run(); - + + mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_RUNNING_START, + Integer.toString(mCurrentUserId), mCurrentUserId); + mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_START, + Integer.toString(mCurrentUserId), mCurrentUserId); mSystemServiceManager.startUser(mCurrentUserId); synchronized (this) { @@ -12441,12 +12453,11 @@ public final class ActivityManagerService extends ActivityManagerNative pw.print(" lastCachedPss="); pw.println(r.lastCachedPss); pw.print(prefix); pw.print(" "); - pw.print("keeping="); pw.print(r.keeping); - pw.print(" cached="); pw.print(r.cached); + pw.print("cached="); pw.print(r.cached); pw.print(" empty="); pw.print(r.empty); pw.print(" hasAboveClient="); pw.println(r.hasAboveClient); - if (!r.keeping) { + if (r.setProcState >= ActivityManager.PROCESS_STATE_SERVICE) { if (r.lastWakeTime != 0) { long wtime; BatteryStatsImpl stats = service.mBatteryStatsService.getActiveStatistics(); @@ -15200,7 +15211,6 @@ public final class ActivityManagerService extends ActivityManagerNative app.adjSeq = mAdjSeq; app.curRawAdj = app.maxAdj; app.foregroundActivities = false; - app.keeping = true; app.curSchedGroup = Process.THREAD_GROUP_DEFAULT; app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT; // System processes can do UI, and when they do we want to have @@ -15224,7 +15234,6 @@ public final class ActivityManagerService extends ActivityManagerNative return (app.curAdj=app.maxAdj); } - app.keeping = false; app.systemNoUi = false; // Determine the importance of the process, starting with most @@ -15469,9 +15478,6 @@ public final class ActivityManagerService extends ActivityManagerNative app.adjType = "cch-started-services"; } } - // Don't kill this process because it is doing work; it - // has said it is doing work. - app.keeping = true; } for (int conni = s.connections.size()-1; conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ @@ -15561,9 +15567,6 @@ public final class ActivityManagerService extends ActivityManagerNative if (!client.cached) { app.cached = false; } - if (client.keeping) { - app.keeping = true; - } adjType = "service"; } } @@ -15675,7 +15678,6 @@ public final class ActivityManagerService extends ActivityManagerNative app.adjType = "provider"; } app.cached &= client.cached; - app.keeping |= client.keeping; app.adjTypeCode = ActivityManager.RunningAppProcessInfo .REASON_PROVIDER_IN_USE; app.adjSource = client; @@ -15719,7 +15721,6 @@ public final class ActivityManagerService extends ActivityManagerNative adj = ProcessList.FOREGROUND_APP_ADJ; schedGroup = Process.THREAD_GROUP_DEFAULT; app.cached = false; - app.keeping = true; app.adjType = "provider"; app.adjTarget = cpr.name; } @@ -15802,9 +15803,6 @@ public final class ActivityManagerService extends ActivityManagerNative schedGroup = Process.THREAD_GROUP_DEFAULT; } } - if (adj < ProcessList.CACHED_APP_MIN_ADJ) { - app.keeping = true; - } // Do final modification to adj. Everything we do between here and applying // the final setAdj must be done in this function, because we will also use @@ -16026,7 +16024,7 @@ public final class ActivityManagerService extends ActivityManagerNative while (i > 0) { i--; ProcessRecord app = mLruProcesses.get(i); - if (!app.keeping) { + if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) { long wtime; synchronized (stats) { wtime = stats.getProcessWakeTime(app.info.uid, @@ -16071,7 +16069,7 @@ public final class ActivityManagerService extends ActivityManagerNative + " during " + realtimeSince); app.baseProcessTracker.reportExcessiveWake(app.pkgList); } else if (doCpuKills && uptimeSince > 0 - && ((cputimeUsed*100)/uptimeSince) >= 50) { + && ((cputimeUsed*100)/uptimeSince) >= 25) { synchronized (stats) { stats.reportExcessiveCpuLocked(app.info.uid, app.processName, uptimeSince, cputimeUsed); @@ -16087,23 +16085,11 @@ public final class ActivityManagerService extends ActivityManagerNative } } - private final boolean applyOomAdjLocked(ProcessRecord app, boolean wasKeeping, + private final boolean applyOomAdjLocked(ProcessRecord app, ProcessRecord TOP_APP, boolean doingAll, long now) { boolean success = true; if (app.curRawAdj != app.setRawAdj) { - if (wasKeeping && !app.keeping) { - // This app is no longer something we want to keep. Note - // its current wake lock time to later know to kill it if - // it is not behaving well. - BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); - synchronized (stats) { - app.lastWakeTime = stats.getProcessWakeTime(app.info.uid, - app.pid, SystemClock.elapsedRealtime()); - } - app.lastCpuTime = app.curCpuTime; - } - app.setRawAdj = app.curRawAdj; } @@ -16192,6 +16178,21 @@ public final class ActivityManagerService extends ActivityManagerNative if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG, "Proc state change of " + app.processName + " to " + app.curProcState); + boolean setImportant = app.setProcState < ActivityManager.PROCESS_STATE_SERVICE; + boolean curImportant = app.curProcState < ActivityManager.PROCESS_STATE_SERVICE; + if (setImportant && !curImportant) { + // This app is no longer something we consider important enough to allow to + // use arbitrary amounts of battery power. Note + // its current wake lock time to later know to kill it if + // it is not behaving well. + BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); + synchronized (stats) { + app.lastWakeTime = stats.getProcessWakeTime(app.info.uid, + app.pid, SystemClock.elapsedRealtime()); + } + app.lastCpuTime = app.curCpuTime; + + } app.setProcState = app.curProcState; if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) { app.notCachedSinceIdle = false; @@ -16268,11 +16269,9 @@ public final class ActivityManagerService extends ActivityManagerNative return false; } - final boolean wasKeeping = app.keeping; - computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now); - return applyOomAdjLocked(app, wasKeeping, TOP_APP, doingAll, now); + return applyOomAdjLocked(app, TOP_APP, doingAll, now); } final void updateProcessForegroundLocked(ProcessRecord proc, boolean isForeground, @@ -16428,7 +16427,6 @@ public final class ActivityManagerService extends ActivityManagerNative ProcessRecord app = mLruProcesses.get(i); if (!app.killedByAm && app.thread != null) { app.procStateChanged = false; - final boolean wasKeeping = app.keeping; computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now); // If we haven't yet assigned the final cached adj @@ -16483,7 +16481,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } - applyOomAdjLocked(app, wasKeeping, TOP_APP, true, now); + applyOomAdjLocked(app, TOP_APP, true, now); // Count the number of process types. switch (app.curProcState) { @@ -17127,7 +17125,8 @@ public final class ActivityManagerService extends ActivityManagerNative } if (foreground) { - mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_CURRENT_MSG, userId)); + mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_CURRENT_MSG, userId, + oldUserId)); mHandler.removeMessages(REPORT_USER_SWITCH_MSG); mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG); mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_MSG, @@ -17502,6 +17501,9 @@ public final class ActivityManagerService extends ActivityManagerNative } uss.mState = UserStartedState.STATE_SHUTDOWN; } + mBatteryStatsService.noteEvent( + BatteryStats.HistoryItem.EVENT_USER_RUNNING_FINISH, + Integer.toString(userId), userId); mSystemServiceManager.stopUser(userId); broadcastIntentLocked(null, null, shutdownIntent, null, shutdownReceiver, 0, null, null, null, AppOpsManager.OP_NONE, diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index da444f9beca93..ac19bde081ec7 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -186,6 +186,34 @@ public final class BatteryStatsService extends IBatteryStats.Stub } } + public void noteSyncStart(String name, int uid) { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteSyncStartLocked(name, uid); + } + } + + public void noteSyncFinish(String name, int uid) { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteSyncFinishLocked(name, uid); + } + } + + public void noteJobStart(String name, int uid) { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteJobStartLocked(name, uid); + } + } + + public void noteJobFinish(String name, int uid) { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteJobFinishLocked(name, uid); + } + } + public void noteStartWakelock(int uid, int pid, String name, String historyName, int type, boolean unimportantForLogging) { enforceCallingPermission(); diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 2f25bd495975f..a20be73f2722d 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -83,7 +83,6 @@ final class ProcessRecord { int pssProcState = -1; // The proc state we are currently requesting pss for boolean serviceb; // Process currently is on the service B list boolean serviceHighRam; // We are forcing to service B list due to its RAM use - boolean keeping; // Actively running code so don't kill due to that? boolean setIsForeground; // Running foreground UI when last set? boolean notCachedSinceIdle; // Has this process not been in a cached state since last idle? boolean hasClientActivities; // Are there any client services with activities? @@ -225,8 +224,7 @@ final class ProcessRecord { pw.print(" lruSeq="); pw.print(lruSeq); pw.print(" lastPss="); pw.print(lastPss); pw.print(" lastCachedPss="); pw.println(lastCachedPss); - pw.print(prefix); pw.print("keeping="); pw.print(keeping); - pw.print(" cached="); pw.print(cached); + pw.print(prefix); pw.print("cached="); pw.print(cached); pw.print(" empty="); pw.println(empty); if (serviceb) { pw.print(prefix); pw.print("serviceb="); pw.print(serviceb); @@ -275,16 +273,15 @@ final class ProcessRecord { if (hasStartedServices) { pw.print(prefix); pw.print("hasStartedServices="); pw.println(hasStartedServices); } - if (!keeping) { + if (setProcState >= ActivityManager.PROCESS_STATE_SERVICE) { long wtime; synchronized (mBatteryStats) { wtime = mBatteryStats.getProcessWakeTime(info.uid, pid, SystemClock.elapsedRealtime()); } - long timeUsed = wtime - lastWakeTime; pw.print(prefix); pw.print("lastWakeTime="); pw.print(lastWakeTime); pw.print(" timeUsed="); - TimeUtils.formatDuration(timeUsed, pw); pw.println(""); + TimeUtils.formatDuration(wtime-lastWakeTime, pw); pw.println(""); pw.print(prefix); pw.print("lastCpuTime="); pw.print(lastCpuTime); pw.print(" timeUsed="); TimeUtils.formatDuration(curCpuTime-lastCpuTime, pw); pw.println(""); diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index 1b40cdf5caf2e..08d6fc9d7a9f0 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -1212,8 +1212,7 @@ public class SyncManager { } else { try { mEventName = mSyncOperation.wakeLockName(); - mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_SYNC_START, - mEventName, mSyncAdapterUid); + mBatteryStats.noteSyncStart(mEventName, mSyncAdapterUid); } catch (RemoteException e) { } } @@ -1232,8 +1231,7 @@ public class SyncManager { mBound = false; mContext.unbindService(this); try { - mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_SYNC_FINISH, - mEventName, mSyncAdapterUid); + mBatteryStats.noteSyncFinish(mEventName, mSyncAdapterUid); } catch (RemoteException e) { } } diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index 7f8b23233e293..caae9f5116ee9 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -35,16 +35,20 @@ import android.content.IntentFilter; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; +import android.os.BatteryStats; import android.os.Binder; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.RemoteException; +import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; +import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; +import com.android.internal.app.IBatteryStats; import com.android.server.job.controllers.BatteryController; import com.android.server.job.controllers.ConnectivityController; import com.android.server.job.controllers.IdleController; @@ -52,8 +56,6 @@ import com.android.server.job.controllers.JobStatus; import com.android.server.job.controllers.StateController; import com.android.server.job.controllers.TimeController; -import java.util.LinkedList; - /** * Responsible for taking jobs representing work to be performed by a client app, and determining * based on the criteria specified when that job should be run against the client application's @@ -74,7 +76,7 @@ public class JobSchedulerService extends com.android.server.SystemService private static final int MAX_JOB_CONTEXTS_COUNT = 3; static final String TAG = "JobManagerService"; /** Master list of jobs. */ - private final JobStore mJobs; + final JobStore mJobs; static final int MSG_JOB_EXPIRED = 0; static final int MSG_CHECK_JOB = 1; @@ -84,33 +86,41 @@ public class JobSchedulerService extends com.android.server.SystemService * Minimum # of idle jobs that must be ready in order to force the JMS to schedule things * early. */ - private static final int MIN_IDLE_COUNT = 1; + static final int MIN_IDLE_COUNT = 1; /** * Minimum # of connectivity jobs that must be ready in order to force the JMS to schedule * things early. */ - private static final int MIN_CONNECTIVITY_COUNT = 2; + static final int MIN_CONNECTIVITY_COUNT = 2; /** * Minimum # of jobs (with no particular constraints) for which the JMS will be happy running * some work early. */ - private static final int MIN_READY_JOBS_COUNT = 4; + static final int MIN_READY_JOBS_COUNT = 4; /** * Track Services that have currently active or pending jobs. The index is provided by * {@link JobStatus#getServiceToken()} */ - private final List mActiveServices = new LinkedList(); + final List mActiveServices = new ArrayList(); /** List of controllers that will notify this service of updates to jobs. */ - private List mControllers; + List mControllers; /** * Queue of pending jobs. The JobServiceContext class will receive jobs from this list * when ready to execute them. */ - private final LinkedList mPendingJobs = new LinkedList(); + final ArrayList mPendingJobs = new ArrayList(); + + final JobHandler mHandler; + final JobSchedulerStub mJobSchedulerStub; + + IBatteryStats mBatteryStats; + + /** + * Set to true once we are allowed to run third party apps. + */ + boolean mReadyToRock; - private final JobHandler mHandler; - private final JobSchedulerStub mJobSchedulerStub; /** * Cleans up outstanding jobs when a package is removed. Even if it's being replaced later we * still clean up. On reinstall the package will have a new uid. @@ -152,7 +162,9 @@ public class JobSchedulerService extends com.android.server.SystemService public List getPendingJobs(int uid) { ArrayList outList = new ArrayList(); synchronized (mJobs) { - for (JobStatus job : mJobs.getJobs()) { + ArraySet jobs = mJobs.getJobs(); + for (int i=0; i jobsForUser = mJobs.getJobsByUser(userHandle); - for (JobStatus toRemove : jobsForUser) { + for (int i=0; i jobsForUid = mJobs.getJobsByUid(uid); - for (JobStatus toRemove : jobsForUid) { + for (int i=0; i(); + mControllers = new ArrayList(); mControllers.add(ConnectivityController.get(this)); mControllers.add(TimeController.get(this)); mControllers.add(IdleController.get(this)); @@ -238,11 +252,6 @@ public class JobSchedulerService extends com.android.server.SystemService mHandler = new JobHandler(context.getMainLooper()); mJobSchedulerStub = new JobSchedulerStub(); - // Create the "runners". - for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) { - mActiveServices.add( - new JobServiceContext(this, context.getMainLooper())); - } mJobs = JobStore.initAndGet(this); } @@ -262,6 +271,29 @@ public class JobSchedulerService extends com.android.server.SystemService final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED); getContext().registerReceiverAsUser( mBroadcastReceiver, UserHandle.ALL, userFilter, null, null); + } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { + synchronized (mJobs) { + // Let's go! + mReadyToRock = true; + mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( + BatteryStats.SERVICE_NAME)); + // Create the "runners". + for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) { + mActiveServices.add( + new JobServiceContext(this, mBatteryStats, + getContext().getMainLooper())); + } + // Attach jobs to their controllers. + ArraySet jobs = mJobs.getJobs(); + for (int i=0; i jobs) { synchronized (mJobs) { - for (JobStatus js : jobs) { + for (int i=0; i jobs = mJobs.getJobs(); + for (int i=0; i runnableJobs = new ArrayList(); - for (JobStatus job : mJobs.getJobs()) { + ArraySet jobs = mJobs.getJobs(); + for (int i=0; i 0) { backoffCount++; @@ -539,8 +591,8 @@ public class JobSchedulerService extends com.android.server.SystemService if (backoffCount > 0 || idleCount >= MIN_IDLE_COUNT || connectivityCount >= MIN_CONNECTIVITY_COUNT || runnableJobs.size() >= MIN_READY_JOBS_COUNT) { - for (JobStatus job : runnableJobs) { - mPendingJobs.add(job); + for (int i=0; i 0) { - for (JobStatus job : mJobs.getJobs()) { + ArraySet jobs = mJobs.getJobs(); + for (int i=0; i=0; i--) { + JobStatus ts = mJobSet.valueAt(i); if (ts.getUid() == uId && ts.getJobId() == jobId) { return true; } @@ -267,7 +268,8 @@ public class JobStore { List mStoreCopy = new ArrayList(); synchronized (JobStore.this) { // Copy over the jobs so we can release the lock before writing. - for (JobStatus jobStatus : mJobSet) { + for (int i=0; i