diff options
Diffstat (limited to 'services')
12 files changed, 629 insertions, 311 deletions
diff --git a/services/java/com/android/server/ProcessStats.java b/services/java/com/android/server/ProcessStats.java index 5bdadcc..43dbcc0 100644 --- a/services/java/com/android/server/ProcessStats.java +++ b/services/java/com/android/server/ProcessStats.java @@ -80,16 +80,24 @@ public class ProcessStats { PROC_SPACE_TERM|PROC_OUT_LONG, // 11: major faults PROC_SPACE_TERM, PROC_SPACE_TERM|PROC_OUT_LONG, // 13: utime - PROC_SPACE_TERM|PROC_OUT_LONG // 14: stime + PROC_SPACE_TERM|PROC_OUT_LONG, // 14: stime + PROC_SPACE_TERM, + PROC_SPACE_TERM, + PROC_SPACE_TERM, + PROC_SPACE_TERM, + PROC_SPACE_TERM, + PROC_SPACE_TERM, + PROC_SPACE_TERM|PROC_OUT_LONG, // 21: vsize }; static final int PROCESS_FULL_STAT_MINOR_FAULTS = 1; static final int PROCESS_FULL_STAT_MAJOR_FAULTS = 2; static final int PROCESS_FULL_STAT_UTIME = 3; static final int PROCESS_FULL_STAT_STIME = 4; + static final int PROCESS_FULL_STAT_VSIZE = 5; - private final String[] mProcessFullStatsStringData = new String[5]; - private final long[] mProcessFullStatsData = new long[5]; + private final String[] mProcessFullStatsStringData = new String[6]; + private final long[] mProcessFullStatsData = new long[6]; private static final int[] SYSTEM_CPU_FORMAT = new int[] { PROC_SPACE_TERM|PROC_COMBINE, @@ -171,6 +179,8 @@ public class ProcessStats { final ArrayList<Stats> threadStats; final ArrayList<Stats> workingThreads; + public boolean interesting; + public String baseName; public String name; int nameWidth; @@ -349,59 +359,62 @@ public class ProcessStats { + (parentPid < 0 ? "process" : "thread") + " pid " + pid + ": " + st); - final long uptime = SystemClock.uptimeMillis(); + if (st.interesting) { + final long uptime = SystemClock.uptimeMillis(); - final long[] procStats = mProcessStatsData; - if (!Process.readProcFile(st.statFile.toString(), - PROCESS_STATS_FORMAT, null, procStats, null)) { - continue; - } - - final long minfaults = procStats[PROCESS_STAT_MINOR_FAULTS]; - final long majfaults = procStats[PROCESS_STAT_MAJOR_FAULTS]; - final long utime = procStats[PROCESS_STAT_UTIME]; - final long stime = procStats[PROCESS_STAT_STIME]; - - if (utime == st.base_utime && stime == st.base_stime) { - st.rel_utime = 0; - st.rel_stime = 0; - st.rel_minfaults = 0; - st.rel_majfaults = 0; - if (st.active) { - st.active = false; + final long[] procStats = mProcessStatsData; + if (!Process.readProcFile(st.statFile.toString(), + PROCESS_STATS_FORMAT, null, procStats, null)) { + continue; } - continue; - } - if (!st.active) { - st.active = true; - } + final long minfaults = procStats[PROCESS_STAT_MINOR_FAULTS]; + final long majfaults = procStats[PROCESS_STAT_MAJOR_FAULTS]; + final long utime = procStats[PROCESS_STAT_UTIME]; + final long stime = procStats[PROCESS_STAT_STIME]; + + if (utime == st.base_utime && stime == st.base_stime) { + st.rel_utime = 0; + st.rel_stime = 0; + st.rel_minfaults = 0; + st.rel_majfaults = 0; + if (st.active) { + st.active = false; + } + continue; + } - if (parentPid < 0) { - getName(st, st.cmdlineFile); - if (st.threadStats != null) { - mCurThreadPids = collectStats(st.threadsDir, pid, false, - mCurThreadPids, st.threadStats); + if (!st.active) { + st.active = true; } + + if (parentPid < 0) { + getName(st, st.cmdlineFile); + if (st.threadStats != null) { + mCurThreadPids = collectStats(st.threadsDir, pid, false, + mCurThreadPids, st.threadStats); + } + } + + if (DEBUG) Slog.v("Load", "Stats changed " + st.name + " pid=" + st.pid + + " utime=" + utime + "-" + st.base_utime + + " stime=" + stime + "-" + st.base_stime + + " minfaults=" + minfaults + "-" + st.base_minfaults + + " majfaults=" + majfaults + "-" + st.base_majfaults); + + st.rel_uptime = uptime - st.base_uptime; + st.base_uptime = uptime; + st.rel_utime = (int)(utime - st.base_utime); + st.rel_stime = (int)(stime - st.base_stime); + st.base_utime = utime; + st.base_stime = stime; + st.rel_minfaults = (int)(minfaults - st.base_minfaults); + st.rel_majfaults = (int)(majfaults - st.base_majfaults); + st.base_minfaults = minfaults; + st.base_majfaults = majfaults; + st.working = true; } - if (DEBUG) Slog.v("Load", "Stats changed " + st.name + " pid=" + st.pid - + " utime=" + utime + "-" + st.base_utime - + " stime=" + stime + "-" + st.base_stime - + " minfaults=" + minfaults + "-" + st.base_minfaults - + " majfaults=" + majfaults + "-" + st.base_majfaults); - - st.rel_uptime = uptime - st.base_uptime; - st.base_uptime = uptime; - st.rel_utime = (int)(utime - st.base_utime); - st.rel_stime = (int)(stime - st.base_stime); - st.base_utime = utime; - st.base_stime = stime; - st.rel_minfaults = (int)(minfaults - st.base_minfaults); - st.rel_majfaults = (int)(majfaults - st.base_majfaults); - st.base_minfaults = minfaults; - st.base_majfaults = majfaults; - st.working = true; continue; } @@ -421,12 +434,24 @@ public class ProcessStats { if (Process.readProcFile(st.statFile.toString(), PROCESS_FULL_STATS_FORMAT, procStatsString, procStats, null)) { - st.baseName = procStatsString[0]; - st.base_minfaults = procStats[PROCESS_FULL_STAT_MINOR_FAULTS]; - st.base_majfaults = procStats[PROCESS_FULL_STAT_MAJOR_FAULTS]; - st.base_utime = procStats[PROCESS_FULL_STAT_UTIME]; - st.base_stime = procStats[PROCESS_FULL_STAT_STIME]; + // This is a possible way to filter out processes that + // are actually kernel threads... do we want to? Some + // of them do use CPU, but there can be a *lot* that are + // not doing anything. + if (true || procStats[PROCESS_FULL_STAT_VSIZE] != 0) { + st.interesting = true; + st.baseName = procStatsString[0]; + st.base_minfaults = procStats[PROCESS_FULL_STAT_MINOR_FAULTS]; + st.base_majfaults = procStats[PROCESS_FULL_STAT_MAJOR_FAULTS]; + st.base_utime = procStats[PROCESS_FULL_STAT_UTIME]; + st.base_stime = procStats[PROCESS_FULL_STAT_STIME]; + } else { + Slog.i(TAG, "Skipping kernel process pid " + pid + + " name " + procStatsString[0]); + st.baseName = procStatsString[0]; + } } else { + Slog.w(TAG, "Skipping unknown process pid " + pid); st.baseName = "<unknown>"; st.base_utime = st.base_stime = 0; st.base_minfaults = st.base_majfaults = 0; @@ -438,7 +463,7 @@ public class ProcessStats { mCurThreadPids = collectStats(st.threadsDir, pid, true, mCurThreadPids, st.threadStats); } - } else { + } else if (st.interesting) { st.name = st.baseName; st.nameWidth = onMeasureProcessName(st.name); } @@ -452,7 +477,7 @@ public class ProcessStats { st.rel_minfaults = 0; st.rel_majfaults = 0; st.added = true; - if (!first) { + if (!first && st.interesting) { st.working = true; } continue; @@ -624,6 +649,14 @@ public class ProcessStats { } } + final public int countStats() { + return mProcStats.size(); + } + + final public Stats getStats(int index) { + return mProcStats.get(index); + } + final public int countWorkingStats() { buildWorkingProcs(); return mWorkingProcs.size(); @@ -788,7 +821,8 @@ public class ProcessStats { private void getName(Stats st, String cmdlineFile) { String newName = st.name; - if (st.name == null || st.name.equals("app_process")) { + if (st.name == null || st.name.equals("app_process") + || st.name.equals("<pre-initialized>")) { String cmdName = readFile(cmdlineFile, '\0'); if (cmdName != null && cmdName.length() > 1) { newName = cmdName; diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index c52567a..7b2a570 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -804,6 +804,16 @@ public class WifiService extends IWifiManager.Stub { mWifiStateMachine.forgetNetwork(netId); } + public void startWpsPbc(String bssid) { + enforceChangePermission(); + mWifiStateMachine.startWpsPbc(bssid); + } + + public void startWpsPin(String bssid, int apPin) { + enforceChangePermission(); + mWifiStateMachine.startWpsPin(bssid, apPin); + } + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index c896c94..8e22652 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -122,6 +122,8 @@ import java.io.PrintWriter; import java.lang.IllegalStateException; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -145,6 +147,7 @@ public final class ActivityManagerService extends ActivityManagerNative static final boolean DEBUG_BROADCAST = localLOGV || false; static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false; static final boolean DEBUG_SERVICE = localLOGV || false; + static final boolean DEBUG_SERVICE_EXECUTING = localLOGV || false; static final boolean DEBUG_VISBILITY = localLOGV || false; static final boolean DEBUG_PROCESSES = localLOGV || false; static final boolean DEBUG_PROVIDER = localLOGV || false; @@ -153,6 +156,8 @@ public final class ActivityManagerService extends ActivityManagerNative static final boolean DEBUG_RESULTS = localLOGV || false; static final boolean DEBUG_BACKUP = localLOGV || false; static final boolean DEBUG_CONFIGURATION = localLOGV || false; + static final boolean DEBUG_POWER = localLOGV || false; + static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false; static final boolean VALIDATE_TOKENS = false; static final boolean SHOW_ACTIVITY_START_TIME = true; @@ -198,8 +203,16 @@ public final class ActivityManagerService extends ActivityManagerNative // The minimum amount of time between successive GC requests for a process. static final int GC_MIN_INTERVAL = 60*1000; - // The rate at which we check for apps using excessive wake locks -- 15 mins. - static final int WAKE_LOCK_CHECK_DELAY = 15*60*1000; + // The rate at which we check for apps using excessive power -- 15 mins. + static final int POWER_CHECK_DELAY = (DEBUG_POWER_QUICK ? 2 : 15) * 60*1000; + + // The minimum sample duration we will allow before deciding we have + // enough data on wake locks to start killing things. + static final int WAKE_LOCK_MIN_CHECK_DURATION = (DEBUG_POWER_QUICK ? 1 : 5) * 60*1000; + + // The minimum sample duration we will allow before deciding we have + // enough data on CPU usage to start killing things. + static final int CPU_MIN_CHECK_DURATION = (DEBUG_POWER_QUICK ? 1 : 5) * 60*1000; // How long we allow a receiver to run before giving up on it. static final int BROADCAST_TIMEOUT = 10*1000; @@ -780,9 +793,14 @@ public final class ActivityManagerService extends ActivityManagerNative boolean mDidAppSwitch; /** - * Last time (in realtime) at which we checked for wake lock usage. + * Last time (in realtime) at which we checked for power usage. + */ + long mLastPowerCheckRealtime; + + /** + * Last time (in uptime) at which we checked for power usage. */ - long mLastWakeLockCheckTime; + long mLastPowerCheckUptime; /** * Set while we are wanting to sleep, to prevent any @@ -1195,12 +1213,10 @@ public final class ActivityManagerService extends ActivityManagerNative } break; case CHECK_EXCESSIVE_WAKE_LOCKS_MSG: { synchronized (ActivityManagerService.this) { - checkExcessiveWakeLocksLocked(true); + checkExcessivePowerUsageLocked(true); removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); - if (mSleeping) { - Message nmsg = obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); - sendMessageDelayed(nmsg, WAKE_LOCK_CHECK_DELAY); - } + Message nmsg = obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); + sendMessageDelayed(nmsg, POWER_CHECK_DELAY); } } break; } @@ -1395,7 +1411,8 @@ public final class ActivityManagerService extends ActivityManagerNative systemDir, "batterystats.bin").toString()); mBatteryStatsService.getActiveStatistics().readLocked(); mBatteryStatsService.getActiveStatistics().writeAsyncLocked(); - mOnBattery = mBatteryStatsService.getActiveStatistics().getIsOnBattery(); + mOnBattery = DEBUG_POWER ? true + : mBatteryStatsService.getActiveStatistics().getIsOnBattery(); mBatteryStatsService.getActiveStatistics().setCallback(this); mUsageStatsService = new UsageStatsService(new File( @@ -1515,10 +1532,12 @@ public final class ActivityManagerService extends ActivityManagerNative int perc = bstats.startAddingCpuLocked(); int totalUTime = 0; int totalSTime = 0; - final int N = mProcessStats.countWorkingStats(); + final int N = mProcessStats.countStats(); for (int i=0; i<N; i++) { - ProcessStats.Stats st - = mProcessStats.getWorkingStats(i); + ProcessStats.Stats st = mProcessStats.getStats(i); + if (!st.working) { + continue; + } ProcessRecord pr = mPidsSelfLocked.get(st.pid); int otherUTime = (st.rel_utime*perc)/100; int otherSTime = (st.rel_stime*perc)/100; @@ -1529,6 +1548,7 @@ public final class ActivityManagerService extends ActivityManagerNative ps.addCpuTimeLocked(st.rel_utime-otherUTime, st.rel_stime-otherSTime); ps.addSpeedStepTimes(cpuSpeedTimes); + pr.curCpuTime += (st.rel_utime+st.rel_stime) * 10; } else { BatteryStatsImpl.Uid.Proc ps = bstats.getProcessStatsLocked(st.name, st.pid); @@ -1565,7 +1585,7 @@ public final class ActivityManagerService extends ActivityManagerNative updateCpuStatsNow(); synchronized (this) { synchronized(mPidsSelfLocked) { - mOnBattery = onBattery; + mOnBattery = DEBUG_POWER ? true : onBattery; } } } @@ -2795,6 +2815,16 @@ public final class ActivityManagerService extends ActivityManagerNative ArrayList<Integer> firstPids = new ArrayList<Integer>(5); SparseArray<Boolean> lastPids = new SparseArray<Boolean>(20); + if (mController != null) { + try { + // 0 == continue, -1 = kill process immediately + int res = mController.appEarlyNotResponding(app.processName, app.pid, annotation); + if (res < 0 && app.pid != MY_PID) Process.killProcess(app.pid); + } catch (RemoteException e) { + mController = null; + } + } + long anrTime = SystemClock.uptimeMillis(); if (MONITOR_CPU_USAGE) { updateCpuStatsNow(); @@ -2845,10 +2875,6 @@ public final class ActivityManagerService extends ActivityManagerNative } } - final ProcessStats processStats = new ProcessStats(true); - - File tracesFile = dumpStackTraces(true, firstPids, processStats, lastPids); - // Log the ANR to the main log. StringBuilder info = mStringBuilder; info.setLength(0); @@ -2864,6 +2890,10 @@ public final class ActivityManagerService extends ActivityManagerNative info.append("Parent: ").append(parent.shortComponentName).append("\n"); } + final ProcessStats processStats = new ProcessStats(true); + + File tracesFile = dumpStackTraces(true, firstPids, processStats, lastPids); + String cpuInfo = null; if (MONITOR_CPU_USAGE) { updateCpuStatsNow(); @@ -3742,7 +3772,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { // Start looking for apps that are abusing wake locks. Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); - mHandler.sendMessageDelayed(nmsg, WAKE_LOCK_CHECK_DELAY); + mHandler.sendMessageDelayed(nmsg, POWER_CHECK_DELAY); // Tell anyone interested that we are done booting! SystemProperties.set("sys.boot_completed", "1"); broadcastIntentLocked(null, null, @@ -5655,10 +5685,10 @@ public final class ActivityManagerService extends ActivityManagerNative } // Initialize the wake times of all processes. - checkExcessiveWakeLocksLocked(false); + checkExcessivePowerUsageLocked(false); mHandler.removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); - mHandler.sendMessageDelayed(nmsg, WAKE_LOCK_CHECK_DELAY); + mHandler.sendMessageDelayed(nmsg, POWER_CHECK_DELAY); } } @@ -5708,7 +5738,6 @@ public final class ActivityManagerService extends ActivityManagerNative mWindowManager.setEventDispatching(true); mSleeping = false; mMainStack.resumeTopActivityLocked(null); - mHandler.removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); } } @@ -7055,12 +7084,13 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println("Activity manager dump options:"); pw.println(" [-a] [-h] [cmd] ..."); pw.println(" cmd may be one of:"); - pw.println(" activities: activity stack state"); - pw.println(" broadcasts: broadcast state"); - pw.println(" intents: pending intent state"); - pw.println(" processes: process state"); - pw.println(" providers: content provider state"); - pw.println(" services: service state"); + pw.println(" a[ctivities]: activity stack state"); + pw.println(" b[roadcasts]: broadcast state"); + pw.println(" i[ntents]: pending intent state"); + pw.println(" p[rocesses]: process state"); + pw.println(" o[om]: out of memory management"); + pw.println(" prov[iders]: content provider state"); + pw.println(" s[ervices]: service state"); pw.println(" service [name]: service client-side state"); return; } else { @@ -7092,6 +7122,11 @@ public final class ActivityManagerService extends ActivityManagerNative dumpProcessesLocked(fd, pw, args, opti, true); } return; + } else if ("oom".equals(cmd) || "o".equals(cmd)) { + synchronized (this) { + dumpOomLocked(fd, pw, args, opti, true); + } + return; } else if ("providers".equals(cmd) || "prov".equals(cmd)) { synchronized (this) { dumpProvidersLocked(fd, pw, args, opti, true); @@ -7213,7 +7248,7 @@ public final class ActivityManagerService extends ActivityManagerNative return true; } - + boolean dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args, int opti, boolean dumpAll) { boolean needSep = false; @@ -7243,8 +7278,8 @@ public final class ActivityManagerService extends ActivityManagerNative if (needSep) pw.println(" "); needSep = true; pw.println(" Running processes (most recent first):"); - dumpProcessList(pw, this, mLruProcesses, " ", - "Proc", "PERS", true); + dumpProcessOomList(pw, this, mLruProcesses, " ", + "Proc", "PERS", false); needSep = true; } @@ -7275,7 +7310,7 @@ public final class ActivityManagerService extends ActivityManagerNative needSep = true; pw.println(" Persisent processes that are starting:"); dumpProcessList(pw, this, mPersistentStartingProcesses, " ", - "Starting Norm", "Restarting PERS", false); + "Starting Norm", "Restarting PERS"); } if (mStartingProcesses.size() > 0) { @@ -7283,7 +7318,7 @@ public final class ActivityManagerService extends ActivityManagerNative needSep = true; pw.println(" Processes that are starting:"); dumpProcessList(pw, this, mStartingProcesses, " ", - "Starting Norm", "Starting PERS", false); + "Starting Norm", "Starting PERS"); } if (mRemovedProcesses.size() > 0) { @@ -7291,7 +7326,7 @@ public final class ActivityManagerService extends ActivityManagerNative needSep = true; pw.println(" Processes that are being removed:"); dumpProcessList(pw, this, mRemovedProcesses, " ", - "Removed Norm", "Removed PERS", false); + "Removed Norm", "Removed PERS"); } if (mProcessesOnHold.size() > 0) { @@ -7299,26 +7334,10 @@ public final class ActivityManagerService extends ActivityManagerNative needSep = true; pw.println(" Processes that are on old until the system is ready:"); dumpProcessList(pw, this, mProcessesOnHold, " ", - "OnHold Norm", "OnHold PERS", false); + "OnHold Norm", "OnHold PERS"); } - if (mProcessesToGc.size() > 0) { - if (needSep) pw.println(" "); - needSep = true; - pw.println(" Processes that are waiting to GC:"); - long now = SystemClock.uptimeMillis(); - for (int i=0; i<mProcessesToGc.size(); i++) { - ProcessRecord proc = mProcessesToGc.get(i); - pw.print(" Process "); pw.println(proc); - pw.print(" lowMem="); pw.print(proc.reportLowMemory); - pw.print(", last gced="); - pw.print(now-proc.lastRequestedGc); - pw.print(" ms ago, last lowMem="); - pw.print(now-proc.lastLowMemory); - pw.println(" ms ago"); - - } - } + needSep = dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll); if (mProcessCrashTimes.getMap().size() > 0) { if (needSep) pw.println(" "); @@ -7382,6 +7401,12 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println(" mBooting=" + mBooting + " mBooted=" + mBooted + " mFactoryTest=" + mFactoryTest); + pw.print(" mLastPowerCheckRealtime="); + TimeUtils.formatDuration(mLastPowerCheckRealtime, pw); + pw.println(""); + pw.print(" mLastPowerCheckUptime="); + TimeUtils.formatDuration(mLastPowerCheckUptime, pw); + pw.println(""); pw.println(" mGoingToSleep=" + mMainStack.mGoingToSleep); pw.println(" mLaunchingActivity=" + mMainStack.mLaunchingActivity); pw.println(" mAdjSeq=" + mAdjSeq + " mLruSeq=" + mLruSeq); @@ -7390,6 +7415,75 @@ public final class ActivityManagerService extends ActivityManagerNative return true; } + boolean dumpProcessesToGc(FileDescriptor fd, PrintWriter pw, String[] args, + int opti, boolean needSep, boolean dumpAll) { + if (mProcessesToGc.size() > 0) { + if (needSep) pw.println(" "); + needSep = true; + pw.println(" Processes that are waiting to GC:"); + long now = SystemClock.uptimeMillis(); + for (int i=0; i<mProcessesToGc.size(); i++) { + ProcessRecord proc = mProcessesToGc.get(i); + pw.print(" Process "); pw.println(proc); + pw.print(" lowMem="); pw.print(proc.reportLowMemory); + pw.print(", last gced="); + pw.print(now-proc.lastRequestedGc); + pw.print(" ms ago, last lowMem="); + pw.print(now-proc.lastLowMemory); + pw.println(" ms ago"); + + } + } + return needSep; + } + + boolean dumpOomLocked(FileDescriptor fd, PrintWriter pw, String[] args, + int opti, boolean dumpAll) { + boolean needSep = false; + + if (mLruProcesses.size() > 0) { + ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>(mLruProcesses); + + Comparator<ProcessRecord> comparator = new Comparator<ProcessRecord>() { + @Override + public int compare(ProcessRecord object1, ProcessRecord object2) { + if (object1.setAdj != object2.setAdj) { + return object1.setAdj > object2.setAdj ? -1 : 1; + } + if (object1.setSchedGroup != object2.setSchedGroup) { + return object1.setSchedGroup > object2.setSchedGroup ? -1 : 1; + } + if (object1.keeping != object2.keeping) { + return object1.keeping ? -1 : 1; + } + if (object1.pid != object2.pid) { + return object1.pid > object2.pid ? -1 : 1; + } + return 0; + } + }; + + Collections.sort(procs, comparator); + + if (needSep) pw.println(" "); + needSep = true; + pw.println(" Process OOM control:"); + dumpProcessOomList(pw, this, procs, " ", + "Proc", "PERS", true); + needSep = true; + } + + needSep = dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll); + + pw.println(" "); + pw.println(" mHomeProcess: " + mHomeProcess); + if (mHeavyWeightProcess != null) { + pw.println(" mHeavyWeightProcess: " + mHeavyWeightProcess); + } + + return true; + } + /** * There are three ways to call this: * - no service specified: dump all the services @@ -7833,89 +7927,145 @@ public final class ActivityManagerService extends ActivityManagerNative private static final int dumpProcessList(PrintWriter pw, ActivityManagerService service, List list, - String prefix, String normalLabel, String persistentLabel, - boolean inclOomAdj) { + String prefix, String normalLabel, String persistentLabel) { int numPers = 0; final int N = list.size()-1; for (int i=N; i>=0; i--) { ProcessRecord r = (ProcessRecord)list.get(i); - if (false) { - pw.println(prefix + (r.persistent ? persistentLabel : normalLabel) - + " #" + i + ":"); - r.dump(pw, prefix + " "); - } else if (inclOomAdj) { - String oomAdj; - if (r.setAdj >= EMPTY_APP_ADJ) { - oomAdj = buildOomTag("empty", null, r.setAdj, EMPTY_APP_ADJ); - } else if (r.setAdj >= HIDDEN_APP_MIN_ADJ) { - oomAdj = buildOomTag("bak", " ", r.setAdj, HIDDEN_APP_MIN_ADJ); - } else if (r.setAdj >= HOME_APP_ADJ) { - oomAdj = buildOomTag("home ", null, r.setAdj, HOME_APP_ADJ); - } else if (r.setAdj >= SECONDARY_SERVER_ADJ) { - oomAdj = buildOomTag("svc", " ", r.setAdj, SECONDARY_SERVER_ADJ); - } else if (r.setAdj >= BACKUP_APP_ADJ) { - oomAdj = buildOomTag("bckup", null, r.setAdj, BACKUP_APP_ADJ); - } else if (r.setAdj >= HEAVY_WEIGHT_APP_ADJ) { - oomAdj = buildOomTag("hvy ", null, r.setAdj, HEAVY_WEIGHT_APP_ADJ); - } else if (r.setAdj >= PERCEPTIBLE_APP_ADJ) { - oomAdj = buildOomTag("prcp ", null, r.setAdj, PERCEPTIBLE_APP_ADJ); - } else if (r.setAdj >= VISIBLE_APP_ADJ) { - oomAdj = buildOomTag("vis ", null, r.setAdj, VISIBLE_APP_ADJ); - } else if (r.setAdj >= FOREGROUND_APP_ADJ) { - oomAdj = buildOomTag("fore ", null, r.setAdj, FOREGROUND_APP_ADJ); - } else if (r.setAdj >= CORE_SERVER_ADJ) { - oomAdj = buildOomTag("core ", null, r.setAdj, CORE_SERVER_ADJ); - } else if (r.setAdj >= SYSTEM_ADJ) { - oomAdj = buildOomTag("sys ", null, r.setAdj, SYSTEM_ADJ); + pw.println(String.format("%s%s #%2d: %s", + prefix, (r.persistent ? persistentLabel : normalLabel), + i, r.toString())); + if (r.persistent) { + numPers++; + } + } + return numPers; + } + + private static final void dumpProcessOomList(PrintWriter pw, + ActivityManagerService service, List<ProcessRecord> list, + String prefix, String normalLabel, String persistentLabel, + boolean inclDetails) { + + final long curRealtime = SystemClock.elapsedRealtime(); + final long realtimeSince = curRealtime - service.mLastPowerCheckRealtime; + final long curUptime = SystemClock.uptimeMillis(); + final long uptimeSince = curUptime - service.mLastPowerCheckUptime; + + final int N = list.size()-1; + for (int i=N; i>=0; i--) { + ProcessRecord r = list.get(i); + String oomAdj; + if (r.setAdj >= EMPTY_APP_ADJ) { + oomAdj = buildOomTag("empty", null, r.setAdj, EMPTY_APP_ADJ); + } else if (r.setAdj >= HIDDEN_APP_MIN_ADJ) { + oomAdj = buildOomTag("bak", " ", r.setAdj, HIDDEN_APP_MIN_ADJ); + } else if (r.setAdj >= HOME_APP_ADJ) { + oomAdj = buildOomTag("home ", null, r.setAdj, HOME_APP_ADJ); + } else if (r.setAdj >= SECONDARY_SERVER_ADJ) { + oomAdj = buildOomTag("svc", " ", r.setAdj, SECONDARY_SERVER_ADJ); + } else if (r.setAdj >= BACKUP_APP_ADJ) { + oomAdj = buildOomTag("bckup", null, r.setAdj, BACKUP_APP_ADJ); + } else if (r.setAdj >= HEAVY_WEIGHT_APP_ADJ) { + oomAdj = buildOomTag("hvy ", null, r.setAdj, HEAVY_WEIGHT_APP_ADJ); + } else if (r.setAdj >= PERCEPTIBLE_APP_ADJ) { + oomAdj = buildOomTag("prcp ", null, r.setAdj, PERCEPTIBLE_APP_ADJ); + } else if (r.setAdj >= VISIBLE_APP_ADJ) { + oomAdj = buildOomTag("vis ", null, r.setAdj, VISIBLE_APP_ADJ); + } else if (r.setAdj >= FOREGROUND_APP_ADJ) { + oomAdj = buildOomTag("fore ", null, r.setAdj, FOREGROUND_APP_ADJ); + } else if (r.setAdj >= CORE_SERVER_ADJ) { + oomAdj = buildOomTag("core ", null, r.setAdj, CORE_SERVER_ADJ); + } else if (r.setAdj >= SYSTEM_ADJ) { + oomAdj = buildOomTag("sys ", null, r.setAdj, SYSTEM_ADJ); + } else { + oomAdj = Integer.toString(r.setAdj); + } + String schedGroup; + switch (r.setSchedGroup) { + case Process.THREAD_GROUP_BG_NONINTERACTIVE: + schedGroup = "B"; + break; + case Process.THREAD_GROUP_DEFAULT: + schedGroup = "F"; + break; + default: + schedGroup = Integer.toString(r.setSchedGroup); + break; + } + pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)", + prefix, (r.persistent ? persistentLabel : normalLabel), + N-i, oomAdj, schedGroup, r.toShortString(), r.adjType)); + if (r.adjSource != null || r.adjTarget != null) { + pw.print(prefix); + pw.print(" "); + if (r.adjTarget instanceof ComponentName) { + pw.print(((ComponentName)r.adjTarget).flattenToShortString()); + } else if (r.adjTarget != null) { + pw.print(r.adjTarget.toString()); } else { - oomAdj = Integer.toString(r.setAdj); - } - String schedGroup; - switch (r.setSchedGroup) { - case Process.THREAD_GROUP_BG_NONINTERACTIVE: - schedGroup = "B"; - break; - case Process.THREAD_GROUP_DEFAULT: - schedGroup = "F"; - break; - default: - schedGroup = Integer.toString(r.setSchedGroup); - break; + pw.print("{null}"); + } + pw.print("<="); + if (r.adjSource instanceof ProcessRecord) { + pw.print("Proc{"); + pw.print(((ProcessRecord)r.adjSource).toShortString()); + pw.println("}"); + } else if (r.adjSource != null) { + pw.println(r.adjSource.toString()); + } else { + pw.println("{null}"); } - pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)", - prefix, (r.persistent ? persistentLabel : normalLabel), - N-i, oomAdj, schedGroup, r.toShortString(), r.adjType)); - if (r.adjSource != null || r.adjTarget != null) { - pw.print(prefix); - pw.print(" "); - if (r.adjTarget instanceof ComponentName) { - pw.print(((ComponentName)r.adjTarget).flattenToShortString()); - } else if (r.adjTarget != null) { - pw.print(r.adjTarget.toString()); - } else { - pw.print("{null}"); - } - pw.print("<="); - if (r.adjSource instanceof ProcessRecord) { - pw.print("Proc{"); - pw.print(((ProcessRecord)r.adjSource).toShortString()); - pw.println("}"); - } else if (r.adjSource != null) { - pw.println(r.adjSource.toString()); - } else { - pw.println("{null}"); + } + if (inclDetails) { + pw.print(prefix); + pw.print(" "); + pw.print("oom: max="); pw.print(r.maxAdj); + pw.print(" hidden="); pw.print(r.hiddenAdj); + pw.print(" curRaw="); pw.print(r.curRawAdj); + pw.print(" setRaw="); pw.print(r.setRawAdj); + pw.print(" cur="); pw.print(r.curAdj); + pw.print(" set="); pw.println(r.setAdj); + pw.print(prefix); + pw.print(" "); + pw.print("keeping="); pw.print(r.keeping); + pw.print(" hidden="); pw.print(r.hidden); + pw.print(" empty="); pw.println(r.empty); + + if (!r.keeping) { + if (r.lastWakeTime != 0) { + long wtime; + BatteryStatsImpl stats = service.mBatteryStatsService.getActiveStatistics(); + synchronized (stats) { + wtime = stats.getProcessWakeTime(r.info.uid, + r.pid, curRealtime); + } + long timeUsed = wtime - r.lastWakeTime; + pw.print(prefix); + pw.print(" "); + pw.print("keep awake over "); + TimeUtils.formatDuration(realtimeSince, pw); + pw.print(" used "); + TimeUtils.formatDuration(timeUsed, pw); + pw.print(" ("); + pw.print((timeUsed*100)/realtimeSince); + pw.println("%)"); + } + if (r.lastCpuTime != 0) { + long timeUsed = r.curCpuTime - r.lastCpuTime; + pw.print(prefix); + pw.print(" "); + pw.print("run cpu over "); + TimeUtils.formatDuration(uptimeSince, pw); + pw.print(" used "); + TimeUtils.formatDuration(timeUsed, pw); + pw.print(" ("); + pw.print((timeUsed*100)/uptimeSince); + pw.println("%)"); } } - } else { - pw.println(String.format("%s%s #%2d: %s", - prefix, (r.persistent ? persistentLabel : normalLabel), - i, r.toString())); - } - if (r.persistent) { - numPers++; } } - return numPers; } static final void dumpApplicationMemoryUsage(FileDescriptor fd, @@ -8544,7 +8694,11 @@ public final class ActivityManagerService extends ActivityManagerNative return null; } - private final void bumpServiceExecutingLocked(ServiceRecord r) { + private final void bumpServiceExecutingLocked(ServiceRecord r, String why) { + if (DEBUG_SERVICE) Log.v(TAG, ">>> EXECUTING " + + why + " of " + r + " in app " + r.app); + else if (DEBUG_SERVICE_EXECUTING) Log.v(TAG, ">>> EXECUTING " + + why + " of " + r.shortName); long now = SystemClock.uptimeMillis(); if (r.executeNesting == 0 && r.app != null) { if (r.app.executingServices.size() == 0) { @@ -8582,8 +8736,7 @@ public final class ActivityManagerService extends ActivityManagerNative grantUriPermissionUncheckedFromIntentLocked(si.targetPermissionUid, r.packageName, si.intent, si.getUriPermissionsLocked()); } - if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING start of " + r); - bumpServiceExecutingLocked(r); + bumpServiceExecutingLocked(r, "start"); if (!oomAdjusted) { oomAdjusted = true; updateOomAdjLocked(r.app); @@ -8616,9 +8769,7 @@ public final class ActivityManagerService extends ActivityManagerNative } if ((!i.requested || rebind) && i.apps.size() > 0) { try { - if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING bind of " + r - + " in " + i + ": shouldUnbind=" + i.hasBound); - bumpServiceExecutingLocked(r); + bumpServiceExecutingLocked(r, "bind"); r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind); if (!rebind) { i.requested = true; @@ -8653,8 +8804,7 @@ public final class ActivityManagerService extends ActivityManagerNative r.restartTime = r.lastActivity = SystemClock.uptimeMillis(); app.services.add(r); - if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING create of " + r + " " + r.intent); - bumpServiceExecutingLocked(r); + bumpServiceExecutingLocked(r, "create"); updateLruProcessLocked(app, true, true); boolean created = false; @@ -8906,9 +9056,7 @@ public final class ActivityManagerService extends ActivityManagerNative + ": hasBound=" + ibr.hasBound); if (r.app != null && r.app.thread != null && ibr.hasBound) { try { - if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING bring down unbind of " + r - + " for " + ibr); - bumpServiceExecutingLocked(r); + bumpServiceExecutingLocked(r, "bring down unbind"); updateOomAdjLocked(r.app); ibr.hasBound = false; r.app.thread.scheduleUnbindService(r, @@ -8959,12 +9107,7 @@ public final class ActivityManagerService extends ActivityManagerNative r.app.services.remove(r); if (r.app.thread != null) { try { - if (DEBUG_SERVICE) { - RuntimeException here = new RuntimeException(); - here.fillInStackTrace(); - Slog.v(TAG, ">>> EXECUTING stop of " + r, here); - } - bumpServiceExecutingLocked(r); + bumpServiceExecutingLocked(r, "stop"); mStoppingServices.add(r); updateOomAdjLocked(r.app); r.app.thread.scheduleStopService(r); @@ -9420,9 +9563,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0 && b.intent.hasBound) { try { - if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING unbind of " + s - + " from " + b); - bumpServiceExecutingLocked(s); + bumpServiceExecutingLocked(s, "unbind"); updateOomAdjLocked(s.app); b.intent.hasBound = false; // Assume the client doesn't want to know about a rebind; @@ -9643,14 +9784,20 @@ public final class ActivityManagerService extends ActivityManagerNative if (DEBUG_SERVICE) Slog.v(TAG, "<<< DONE EXECUTING " + r + ": nesting=" + r.executeNesting + ", inStopping=" + inStopping + ", app=" + r.app); + else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG, "<<< DONE EXECUTING " + r.shortName); r.executeNesting--; if (r.executeNesting <= 0 && r.app != null) { + if (DEBUG_SERVICE) Slog.v(TAG, + "Nesting at 0 of " + r.shortName); r.app.executingServices.remove(r); if (r.app.executingServices.size() == 0) { + if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG, + "No more executingServices of " + r.shortName); mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app); } if (inStopping) { - if (DEBUG_SERVICE) Slog.v(TAG, "doneExecuting remove stopping " + r); + if (DEBUG_SERVICE) Slog.v(TAG, + "doneExecuting remove stopping " + r); mStoppingServices.remove(r); } updateOomAdjLocked(r.app); @@ -9760,20 +9907,20 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!"); return; } + } - long oldIdent = Binder.clearCallingIdentity(); - try { - IBackupManager bm = IBackupManager.Stub.asInterface( - ServiceManager.getService(Context.BACKUP_SERVICE)); - bm.agentConnected(agentPackageName, agent); - } catch (RemoteException e) { - // can't happen; the backup manager service is local - } catch (Exception e) { - Slog.w(TAG, "Exception trying to deliver BackupAgent binding: "); - e.printStackTrace(); - } finally { - Binder.restoreCallingIdentity(oldIdent); - } + long oldIdent = Binder.clearCallingIdentity(); + try { + IBackupManager bm = IBackupManager.Stub.asInterface( + ServiceManager.getService(Context.BACKUP_SERVICE)); + bm.agentConnected(agentPackageName, agent); + } catch (RemoteException e) { + // can't happen; the backup manager service is local + } catch (Exception e) { + Slog.w(TAG, "Exception trying to deliver BackupAgent binding: "); + e.printStackTrace(); + } finally { + Binder.restoreCallingIdentity(oldIdent); } } @@ -11326,6 +11473,7 @@ public final class ActivityManagerService extends ActivityManagerNative app.adjType = "fixed"; app.adjSeq = mAdjSeq; app.curRawAdj = app.maxAdj; + app.keeping = true; app.curSchedGroup = Process.THREAD_GROUP_DEFAULT; return (app.curAdj=app.maxAdj); } @@ -11333,6 +11481,7 @@ public final class ActivityManagerService extends ActivityManagerNative app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN; app.adjSource = null; app.adjTarget = null; + app.keeping = false; app.empty = false; app.hidden = false; @@ -11462,6 +11611,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (adj > SECONDARY_SERVER_ADJ) { app.adjType = "started-bg-services"; } + // Don't kill this process because it is doing work; it + // has said it is doing work. + app.keeping = true; } if (s.connections.size() > 0 && (adj > FOREGROUND_APP_ADJ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) { @@ -11495,6 +11647,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (!client.hidden) { app.hidden = false; } + if (client.keeping) { + app.keeping = true; + } app.adjType = "service"; app.adjTypeCode = ActivityManager.RunningAppProcessInfo .REASON_SERVICE_IN_USE; @@ -11528,7 +11683,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } - // Finally, f this process has active services running in it, we + // Finally, if this process has active services running in it, we // would like to avoid killing it unless it would prevent the current // application from running. By default we put the process in // with the rest of the background processes; as we scan through @@ -11570,6 +11725,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (!client.hidden) { app.hidden = false; } + if (client.keeping) { + app.keeping = true; + } app.adjType = "provider"; app.adjTypeCode = ActivityManager.RunningAppProcessInfo .REASON_PROVIDER_IN_USE; @@ -11589,6 +11747,7 @@ public final class ActivityManagerService extends ActivityManagerNative adj = FOREGROUND_APP_ADJ; schedGroup = Process.THREAD_GROUP_DEFAULT; app.hidden = false; + app.keeping = true; app.adjType = "provider"; app.adjTarget = cpr.name; } @@ -11606,6 +11765,9 @@ public final class ActivityManagerService extends ActivityManagerNative schedGroup = Process.THREAD_GROUP_DEFAULT; } } + if (adj < HIDDEN_APP_MIN_ADJ) { + app.keeping = true; + } app.curAdj = adj; app.curSchedGroup = schedGroup; @@ -11743,57 +11905,99 @@ public final class ActivityManagerService extends ActivityManagerNative } } - final void checkExcessiveWakeLocksLocked(boolean doKills) { + final void checkExcessivePowerUsageLocked(boolean doKills) { + updateCpuStatsNow(); + BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); - if (mLastWakeLockCheckTime == 0) { - doKills = false; + boolean doWakeKills = doKills; + boolean doCpuKills = doKills; + if (mLastPowerCheckRealtime == 0) { + doWakeKills = false; + } + if (mLastPowerCheckUptime == 0) { + doCpuKills = false; } if (stats.isScreenOn()) { - doKills = false; + doWakeKills = false; } final long curRealtime = SystemClock.elapsedRealtime(); - final long timeSince = curRealtime - mLastWakeLockCheckTime; - mLastWakeLockCheckTime = curRealtime; - if (timeSince < (WAKE_LOCK_CHECK_DELAY/3)) { - doKills = false; + final long realtimeSince = curRealtime - mLastPowerCheckRealtime; + final long curUptime = SystemClock.uptimeMillis(); + final long uptimeSince = curUptime - mLastPowerCheckUptime; + mLastPowerCheckRealtime = curRealtime; + mLastPowerCheckUptime = curUptime; + if (realtimeSince < WAKE_LOCK_MIN_CHECK_DURATION) { + doWakeKills = false; + } + if (uptimeSince < CPU_MIN_CHECK_DURATION) { + doCpuKills = false; } int i = mLruProcesses.size(); while (i > 0) { i--; ProcessRecord app = mLruProcesses.get(i); - if (app.curAdj >= HIDDEN_APP_MIN_ADJ) { + if (!app.keeping) { long wtime; synchronized (stats) { wtime = stats.getProcessWakeTime(app.info.uid, app.pid, curRealtime); } - long timeUsed = wtime - app.lastWakeTime; - if (false) { + long wtimeUsed = wtime - app.lastWakeTime; + long cputimeUsed = app.curCpuTime - app.lastCpuTime; + if (DEBUG_POWER) { StringBuilder sb = new StringBuilder(128); sb.append("Wake for "); app.toShortString(sb); sb.append(": over "); - TimeUtils.formatDuration(timeSince, sb); + TimeUtils.formatDuration(realtimeSince, sb); + sb.append(" used "); + TimeUtils.formatDuration(wtimeUsed, sb); + sb.append(" ("); + sb.append((wtimeUsed*100)/realtimeSince); + sb.append("%)"); + Slog.i(TAG, sb.toString()); + sb.setLength(0); + sb.append("CPU for "); + app.toShortString(sb); + sb.append(": over "); + TimeUtils.formatDuration(uptimeSince, sb); sb.append(" used "); - TimeUtils.formatDuration(timeUsed, sb); + TimeUtils.formatDuration(cputimeUsed, sb); sb.append(" ("); - sb.append((timeUsed*100)/timeSince); + sb.append((cputimeUsed*100)/uptimeSince); sb.append("%)"); Slog.i(TAG, sb.toString()); } // If a process has held a wake lock for more // than 50% of the time during this period, // that sounds pad. Kill! - if (doKills && timeSince > 0 - && ((timeUsed*100)/timeSince) >= 50) { - Slog.i(TAG, "Excessive wake lock in " + app.processName - + " (pid " + app.pid + "): held " + timeUsed - + " during " + timeSince); + if (doWakeKills && realtimeSince > 0 + && ((wtimeUsed*100)/realtimeSince) >= 50) { + synchronized (stats) { + stats.reportExcessiveWakeLocked(app.info.uid, app.processName, + realtimeSince, wtimeUsed); + } + Slog.w(TAG, "Excessive wake lock in " + app.processName + + " (pid " + app.pid + "): held " + wtimeUsed + + " during " + realtimeSince); EventLog.writeEvent(EventLogTags.AM_KILL, app.pid, app.processName, app.setAdj, "excessive wake lock"); Process.killProcessQuiet(app.pid); + } else if (doCpuKills && uptimeSince > 0 + && ((cputimeUsed*100)/uptimeSince) >= 50) { + synchronized (stats) { + stats.reportExcessiveCpuLocked(app.info.uid, app.processName, + uptimeSince, cputimeUsed); + } + Slog.w(TAG, "Excessive CPU in " + app.processName + + " (pid " + app.pid + "): used " + cputimeUsed + + " during " + uptimeSince); + EventLog.writeEvent(EventLogTags.AM_KILL, app.pid, + app.processName, app.setAdj, "excessive cpu"); + Process.killProcessQuiet(app.pid); } else { app.lastWakeTime = wtime; + app.lastCpuTime = app.curCpuTime; } } } @@ -11807,6 +12011,8 @@ public final class ActivityManagerService extends ActivityManagerNative return true; } + final boolean wasKeeping = app.keeping; + int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP, false); if ((app.pid != 0 && app.pid != MY_PID) || Process.supportsProcesses()) { @@ -11821,13 +12027,20 @@ public final class ActivityManagerService extends ActivityManagerNative // Likewise do a gc when an app is moving in to the // background (such as a service stopping). scheduleAppGcLocked(app); - // And note its current wake lock time. + } + + 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; } if (adj != app.setAdj) { diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java index 67df707..404c6be 100644 --- a/services/java/com/android/server/am/ProcessRecord.java +++ b/services/java/com/android/server/am/ProcessRecord.java @@ -60,6 +60,7 @@ class ProcessRecord { int setAdj; // Last set OOM adjustment for this process int curSchedGroup; // Currently desired scheduling class int setSchedGroup; // Last set to background scheduling class + boolean keeping; // Actively running code so don't kill due to that? boolean setIsForeground; // Running foreground UI when last set? boolean foregroundServices; // Running any services that are foreground? boolean bad; // True if disabled in the bad process list @@ -75,6 +76,8 @@ class ProcessRecord { ComponentName instrumentationResultClass;// copy of instrumentationClass BroadcastRecord curReceiver;// receiver currently running in the app long lastWakeTime; // How long proc held wake lock at last check + long lastCpuTime; // How long proc has run CPU at last check + long curCpuTime; // How long proc has run CPU most recently long lastRequestedGc; // When we last asked the app to do a gc long lastLowMemory; // When we last told the app that memory is low boolean reportLowMemory; // Set to true when waiting to report low mem @@ -131,13 +134,6 @@ class ProcessRecord { void dump(PrintWriter pw, String prefix) { final long now = SystemClock.uptimeMillis(); - long wtime; - synchronized (batteryStats.getBatteryStats()) { - wtime = batteryStats.getBatteryStats().getProcessWakeTime(info.uid, - pid, SystemClock.elapsedRealtime()); - } - long timeUsed = wtime - lastWakeTime; - if (info.className != null) { pw.print(prefix); pw.print("class="); pw.println(info.className); } @@ -170,6 +166,7 @@ class ProcessRecord { pw.print(prefix); pw.print("lastActivityTime="); TimeUtils.formatDuration(lastActivityTime, now, pw); pw.print(" lruWeight="); pw.print(lruWeight); + pw.print(" keeping="); pw.print(keeping); pw.print(" hidden="); pw.print(hidden); pw.print(" empty="); pw.println(empty); pw.print(prefix); pw.print("oom: max="); pw.print(maxAdj); @@ -188,9 +185,20 @@ class ProcessRecord { pw.print(" persistentActivities="); pw.println(persistentActivities); pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq); pw.print(" lruSeq="); pw.println(lruSeq); - pw.print(prefix); pw.print("lastWakeTime="); pw.print(lastWakeTime); - pw.print(" time used="); - TimeUtils.formatDuration(timeUsed, pw); pw.println(""); + if (!keeping) { + long wtime; + synchronized (batteryStats.getBatteryStats()) { + wtime = batteryStats.getBatteryStats().getProcessWakeTime(info.uid, + pid, SystemClock.elapsedRealtime()); + } + long timeUsed = wtime - lastWakeTime; + pw.print(prefix); pw.print("lastWakeTime="); pw.print(lastWakeTime); + pw.print(" time used="); + TimeUtils.formatDuration(timeUsed, pw); pw.println(""); + pw.print(prefix); pw.print("lastCpuTime="); pw.print(lastCpuTime); + pw.print(" time used="); + TimeUtils.formatDuration(curCpuTime-lastCpuTime, pw); pw.println(""); + } pw.print(prefix); pw.print("lastRequestedGc="); TimeUtils.formatDuration(lastRequestedGc, now, pw); pw.print(" lastLowMemory="); diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java index f35a68e..e5aceb4 100644 --- a/services/java/com/android/server/am/ServiceRecord.java +++ b/services/java/com/android/server/am/ServiceRecord.java @@ -347,7 +347,9 @@ class ServiceRecord extends Binder { // If it gave us a garbage notification, it doesn't // get to be foreground. ams.setServiceForeground(name, ServiceRecord.this, - localForegroundId, null, true); + 0, null, true); + ams.crashApplication(appUid, appPid, localPackageName, + "Bad notification for startForeground: " + e); } } }); diff --git a/services/java/com/android/server/sip/SipService.java b/services/java/com/android/server/sip/SipService.java index f1dcd5a..3f43e1c 100644 --- a/services/java/com/android/server/sip/SipService.java +++ b/services/java/com/android/server/sip/SipService.java @@ -30,8 +30,8 @@ import android.net.sip.ISipSessionListener; import android.net.sip.SipErrorCode; import android.net.sip.SipManager; import android.net.sip.SipProfile; +import android.net.sip.SipSession; import android.net.sip.SipSessionAdapter; -import android.net.sip.SipSessionState; import android.net.wifi.WifiManager; import android.os.Binder; import android.os.Bundle; @@ -143,7 +143,7 @@ public final class SipService extends ISipService.Stub { } private void openToReceiveCalls(SipProfile localProfile) { - open3(localProfile, SipManager.SIP_INCOMING_CALL_ACTION, null); + open3(localProfile, SipManager.ACTION_SIP_INCOMING_CALL, null); } public synchronized void open3(SipProfile localProfile, @@ -255,15 +255,15 @@ public final class SipService extends ISipService.Stub { private void notifyProfileAdded(SipProfile localProfile) { if (DEBUG) Log.d(TAG, "notify: profile added: " + localProfile); - Intent intent = new Intent(SipManager.SIP_ADD_PHONE_ACTION); - intent.putExtra(SipManager.LOCAL_URI_KEY, localProfile.getUriString()); + Intent intent = new Intent(SipManager.ACTION_SIP_ADD_PHONE); + intent.putExtra(SipManager.EXTRA_LOCAL_URI, localProfile.getUriString()); mContext.sendBroadcast(intent); } private void notifyProfileRemoved(SipProfile localProfile) { if (DEBUG) Log.d(TAG, "notify: profile removed: " + localProfile); - Intent intent = new Intent(SipManager.SIP_REMOVE_PHONE_ACTION); - intent.putExtra(SipManager.LOCAL_URI_KEY, localProfile.getUriString()); + Intent intent = new Intent(SipManager.ACTION_SIP_REMOVE_PHONE); + intent.putExtra(SipManager.EXTRA_LOCAL_URI, localProfile.getUriString()); mContext.sendBroadcast(intent); } @@ -474,8 +474,8 @@ public final class SipService extends ISipService.Stub { // send out incoming call broadcast addPendingSession(session); Intent intent = SipManager.createIncomingCallBroadcast( - mIncomingCallBroadcastAction, session.getCallId(), - sessionDescription); + session.getCallId(), sessionDescription) + .setAction(mIncomingCallBroadcastAction); if (DEBUG) Log.d(TAG, " ringing~~ " + getUri() + ": " + caller.getUri() + ": " + session.getCallId() + " " + mIncomingCallBroadcastAction); @@ -613,10 +613,10 @@ public final class SipService extends ISipService.Stub { try { int state = (mSession == null) - ? SipSessionState.READY_TO_CALL + ? SipSession.State.READY_TO_CALL : mSession.getState(); - if ((state == SipSessionState.REGISTERING) - || (state == SipSessionState.DEREGISTERING)) { + if ((state == SipSession.State.REGISTERING) + || (state == SipSession.State.DEREGISTERING)) { mProxy.onRegistering(mSession); } else if (mRegistered) { int duration = (int) @@ -1138,7 +1138,8 @@ public final class SipService extends ISipService.Stub { event.mTriggerTime += event.mPeriod; // run the callback in a new thread to prevent deadlock - new Thread(event.mCallback).start(); + new Thread(event.mCallback, "SipServiceTimerCallbackThread") + .start(); } if (DEBUG_TIMER) { Log.d(TAG, "after timeout execution"); diff --git a/services/java/com/android/server/sip/SipSessionGroup.java b/services/java/com/android/server/sip/SipSessionGroup.java index b4c2241..66a2c05 100644 --- a/services/java/com/android/server/sip/SipSessionGroup.java +++ b/services/java/com/android/server/sip/SipSessionGroup.java @@ -25,11 +25,10 @@ import gov.nist.javax.sip.message.SIPMessage; import android.net.sip.ISipSession; import android.net.sip.ISipSessionListener; -import android.net.sip.SessionDescription; import android.net.sip.SipErrorCode; import android.net.sip.SipProfile; +import android.net.sip.SipSession; import android.net.sip.SipSessionAdapter; -import android.net.sip.SipSessionState; import android.text.TextUtils; import android.util.Log; @@ -121,7 +120,7 @@ class SipSessionGroup implements SipListener { reset(localIp); } - void reset(String localIp) throws SipException, IOException { + synchronized void reset(String localIp) throws SipException, IOException { mLocalIp = localIp; if (localIp == null) return; @@ -301,7 +300,7 @@ class SipSessionGroup implements SipListener { boolean processed = (session != null) && session.process(event); if (isLoggable && processed) { Log.d(TAG, "new state after: " - + SipSessionState.toString(session.mState)); + + SipSession.State.toString(session.mState)); } } catch (Throwable e) { Log.w(TAG, "event process error: " + event, e); @@ -332,7 +331,7 @@ class SipSessionGroup implements SipListener { public boolean process(EventObject evt) throws SipException { if (isLoggable(this, evt)) Log.d(TAG, " ~~~~~ " + this + ": " - + SipSessionState.toString(mState) + ": processing " + + SipSession.State.toString(mState) + ": processing " + log(evt)); if (isRequestEvent(Request.INVITE, evt)) { RequestEvent event = (RequestEvent) evt; @@ -342,13 +341,16 @@ class SipSessionGroup implements SipListener { newSession.mDialog = newSession.mServerTransaction.getDialog(); newSession.mInviteReceived = event; newSession.mPeerProfile = createPeerProfile(event.getRequest()); - newSession.mState = SipSessionState.INCOMING_CALL; + newSession.mState = SipSession.State.INCOMING_CALL; newSession.mPeerSessionDescription = extractContent(event.getRequest()); addSipSession(newSession); mProxy.onRinging(newSession, newSession.mPeerProfile, newSession.mPeerSessionDescription); return true; + } else if (isRequestEvent(Request.OPTIONS, evt)) { + mSipHelper.sendResponse((RequestEvent) evt, Response.OK); + return true; } else { return false; } @@ -358,7 +360,7 @@ class SipSessionGroup implements SipListener { class SipSessionImpl extends ISipSession.Stub { SipProfile mPeerProfile; SipSessionListenerProxy mProxy = new SipSessionListenerProxy(); - int mState = SipSessionState.READY_TO_CALL; + int mState = SipSession.State.READY_TO_CALL; RequestEvent mInviteReceived; Dialog mDialog; ServerTransaction mServerTransaction; @@ -378,7 +380,7 @@ class SipSessionGroup implements SipListener { sleep(timeout); if (mRunning) timeout(); } - }).start(); + }, "SipSessionTimerThread").start(); } synchronized void cancel() { @@ -413,7 +415,7 @@ class SipSessionGroup implements SipListener { mInCall = false; removeSipSession(this); mPeerProfile = null; - mState = SipSessionState.READY_TO_CALL; + mState = SipSession.State.READY_TO_CALL; mInviteReceived = null; mDialog = null; mServerTransaction = null; @@ -470,7 +472,7 @@ class SipSessionGroup implements SipListener { onError(e); } } - }).start(); + }, "SipSessionAsyncCmdThread").start(); } public void makeCall(SipProfile peerProfile, String sessionDescription, @@ -520,10 +522,10 @@ class SipSessionGroup implements SipListener { } public void sendKeepAlive() { - mState = SipSessionState.PINGING; + mState = SipSession.State.PINGING; try { processCommand(new OptionsCommand()); - while (SipSessionState.PINGING == mState) { + while (SipSession.State.PINGING == mState) { Thread.sleep(1000); } } catch (SipException e) { @@ -550,7 +552,7 @@ class SipSessionGroup implements SipListener { try { String s = super.toString(); return s.substring(s.indexOf("@")) + ":" - + SipSessionState.toString(mState); + + SipSession.State.toString(mState); } catch (Throwable e) { return super.toString(); } @@ -558,7 +560,7 @@ class SipSessionGroup implements SipListener { public boolean process(EventObject evt) throws SipException { if (isLoggable(this, evt)) Log.d(TAG, " ~~~~~ " + this + ": " - + SipSessionState.toString(mState) + ": processing " + + SipSession.State.toString(mState) + ": processing " + log(evt)); synchronized (SipSessionGroup.this) { if (isClosed()) return false; @@ -574,30 +576,30 @@ class SipSessionGroup implements SipListener { boolean processed; switch (mState) { - case SipSessionState.REGISTERING: - case SipSessionState.DEREGISTERING: + case SipSession.State.REGISTERING: + case SipSession.State.DEREGISTERING: processed = registeringToReady(evt); break; - case SipSessionState.PINGING: + case SipSession.State.PINGING: processed = keepAliveProcess(evt); break; - case SipSessionState.READY_TO_CALL: + case SipSession.State.READY_TO_CALL: processed = readyForCall(evt); break; - case SipSessionState.INCOMING_CALL: + case SipSession.State.INCOMING_CALL: processed = incomingCall(evt); break; - case SipSessionState.INCOMING_CALL_ANSWERING: + case SipSession.State.INCOMING_CALL_ANSWERING: processed = incomingCallToInCall(evt); break; - case SipSessionState.OUTGOING_CALL: - case SipSessionState.OUTGOING_CALL_RING_BACK: + case SipSession.State.OUTGOING_CALL: + case SipSession.State.OUTGOING_CALL_RING_BACK: processed = outgoingCall(evt); break; - case SipSessionState.OUTGOING_CALL_CANCELING: + case SipSession.State.OUTGOING_CALL_CANCELING: processed = outgoingCallToReady(evt); break; - case SipSessionState.IN_CALL: + case SipSession.State.IN_CALL: processed = inCall(evt); break; default: @@ -625,6 +627,9 @@ class SipSessionGroup implements SipListener { (TransactionTerminatedEvent) evt); } return true; + } else if (isRequestEvent(Request.OPTIONS, evt)) { + mSipHelper.sendResponse((RequestEvent) evt, Response.OK); + return true; } else if (evt instanceof DialogTerminatedEvent) { processDialogTerminated((DialogTerminatedEvent) evt); return true; @@ -644,8 +649,8 @@ class SipSessionGroup implements SipListener { private void processTransactionTerminated( TransactionTerminatedEvent event) { switch (mState) { - case SipSessionState.IN_CALL: - case SipSessionState.READY_TO_CALL: + case SipSession.State.IN_CALL: + case SipSession.State.READY_TO_CALL: Log.d(TAG, "Transaction terminated; do nothing"); break; default: @@ -664,27 +669,27 @@ class SipSessionGroup implements SipListener { ? event.getServerTransaction() : event.getClientTransaction(); - if ((current != target) && (mState != SipSessionState.PINGING)) { + if ((current != target) && (mState != SipSession.State.PINGING)) { Log.d(TAG, "not the current transaction; current=" + current + ", timed out=" + target); return; } switch (mState) { - case SipSessionState.REGISTERING: - case SipSessionState.DEREGISTERING: + case SipSession.State.REGISTERING: + case SipSession.State.DEREGISTERING: reset(); mProxy.onRegistrationTimeout(this); break; - case SipSessionState.INCOMING_CALL: - case SipSessionState.INCOMING_CALL_ANSWERING: - case SipSessionState.OUTGOING_CALL: - case SipSessionState.OUTGOING_CALL_CANCELING: + case SipSession.State.INCOMING_CALL: + case SipSession.State.INCOMING_CALL_ANSWERING: + case SipSession.State.OUTGOING_CALL: + case SipSession.State.OUTGOING_CALL_CANCELING: onError(SipErrorCode.TIME_OUT, event.toString()); break; - case SipSessionState.PINGING: + case SipSession.State.PINGING: reset(); mReRegisterFlag = true; - mState = SipSessionState.READY_TO_CALL; + mState = SipSession.State.READY_TO_CALL; break; default: @@ -758,7 +763,7 @@ class SipSessionGroup implements SipListener { switch (statusCode) { case Response.OK: int state = mState; - onRegistrationDone((state == SipSessionState.REGISTERING) + onRegistrationDone((state == SipSession.State.REGISTERING) ? getExpiryTime(((ResponseEvent) evt).getResponse()) : -1); mLastNonce = null; @@ -845,7 +850,7 @@ class SipSessionGroup implements SipListener { generateTag()); mDialog = mClientTransaction.getDialog(); addSipSession(this); - mState = SipSessionState.OUTGOING_CALL; + mState = SipSession.State.OUTGOING_CALL; mProxy.onCalling(this); startSessionTimer(cmd.getTimeout()); return true; @@ -855,7 +860,7 @@ class SipSessionGroup implements SipListener { generateTag(), duration); mDialog = mClientTransaction.getDialog(); addSipSession(this); - mState = SipSessionState.REGISTERING; + mState = SipSession.State.REGISTERING; mProxy.onRegistering(this); return true; } else if (DEREGISTER == evt) { @@ -863,7 +868,7 @@ class SipSessionGroup implements SipListener { generateTag(), 0); mDialog = mClientTransaction.getDialog(); addSipSession(this); - mState = SipSessionState.DEREGISTERING; + mState = SipSession.State.DEREGISTERING; mProxy.onRegistering(this); return true; } @@ -878,7 +883,7 @@ class SipSessionGroup implements SipListener { mLocalProfile, ((MakeCallCommand) evt).getSessionDescription(), mServerTransaction); - mState = SipSessionState.INCOMING_CALL_ANSWERING; + mState = SipSession.State.INCOMING_CALL_ANSWERING; startSessionTimer(((MakeCallCommand) evt).getTimeout()); return true; } else if (END_CALL == evt) { @@ -919,8 +924,8 @@ class SipSessionGroup implements SipListener { int statusCode = response.getStatusCode(); switch (statusCode) { case Response.RINGING: - if (mState == SipSessionState.OUTGOING_CALL) { - mState = SipSessionState.OUTGOING_CALL_RING_BACK; + if (mState == SipSession.State.OUTGOING_CALL) { + mState = SipSession.State.OUTGOING_CALL_RING_BACK; mProxy.onRingingBack(this); cancelSessionTimer(); } @@ -963,7 +968,7 @@ class SipSessionGroup implements SipListener { // response comes back yet. We are cheating for not checking // response. mSipHelper.sendCancel(mClientTransaction); - mState = SipSessionState.OUTGOING_CALL_CANCELING; + mState = SipSession.State.OUTGOING_CALL_CANCELING; startSessionTimer(CANCEL_CALL_TIMER); return true; } @@ -1019,7 +1024,7 @@ class SipSessionGroup implements SipListener { } else if (isRequestEvent(Request.INVITE, evt)) { // got Re-INVITE RequestEvent event = mInviteReceived = (RequestEvent) evt; - mState = SipSessionState.INCOMING_CALL; + mState = SipSession.State.INCOMING_CALL; mPeerSessionDescription = extractContent(event.getRequest()); mServerTransaction = null; mProxy.onRinging(this, mPeerProfile, mPeerSessionDescription); @@ -1032,7 +1037,7 @@ class SipSessionGroup implements SipListener { // to change call mClientTransaction = mSipHelper.sendReinvite(mDialog, ((MakeCallCommand) evt).getSessionDescription()); - mState = SipSessionState.OUTGOING_CALL; + mState = SipSession.State.OUTGOING_CALL; startSessionTimer(((MakeCallCommand) evt).getTimeout()); return true; } @@ -1060,14 +1065,14 @@ class SipSessionGroup implements SipListener { } private void establishCall() { - mState = SipSessionState.IN_CALL; + mState = SipSession.State.IN_CALL; mInCall = true; cancelSessionTimer(); mProxy.onCallEstablished(this, mPeerSessionDescription); } private void fallbackToPreviousInCall(int errorCode, String message) { - mState = SipSessionState.IN_CALL; + mState = SipSession.State.IN_CALL; mProxy.onCallChangeFailed(this, errorCode, message); } @@ -1089,8 +1094,8 @@ class SipSessionGroup implements SipListener { private void onError(int errorCode, String message) { cancelSessionTimer(); switch (mState) { - case SipSessionState.REGISTERING: - case SipSessionState.DEREGISTERING: + case SipSession.State.REGISTERING: + case SipSession.State.DEREGISTERING: onRegistrationFailed(errorCode, message); break; default: @@ -1264,7 +1269,7 @@ class SipSessionGroup implements SipListener { private static boolean isLoggable(SipSessionImpl s) { if (s != null) { switch (s.mState) { - case SipSessionState.PINGING: + case SipSession.State.PINGING: return DEBUG_PING; } } diff --git a/services/java/com/android/server/sip/SipSessionListenerProxy.java b/services/java/com/android/server/sip/SipSessionListenerProxy.java index a4cd102..f8be0a8 100644 --- a/services/java/com/android/server/sip/SipSessionListenerProxy.java +++ b/services/java/com/android/server/sip/SipSessionListenerProxy.java @@ -40,7 +40,7 @@ class SipSessionListenerProxy extends ISipSessionListener.Stub { // One thread for each calling back. // Note: Guarantee ordering if the issue becomes important. Currently, // the chance of handling two callback events at a time is none. - new Thread(runnable).start(); + new Thread(runnable, "SipSessionCallbackThread").start(); } public void onCalling(final ISipSession session) { diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 129be4e..ff887e4 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -21,6 +21,7 @@ #include <sys/types.h> #include <utils/Errors.h> +#include <utils/String8.h> #include <hardware/hardware.h> @@ -100,5 +101,25 @@ hwc_layer_t* HWComposer::getLayers() const { return mList ? mList->hwLayers : 0; } +void HWComposer::dump(String8& result, char* buffer, size_t SIZE) const { + if (mHwc && mList) { + result.append("Hardware Composer state:\n"); + + snprintf(buffer, SIZE, " numHwLayers=%u, flags=%08x\n", + mList->numHwLayers, mList->flags); + result.append(buffer); + + for (size_t i=0 ; i<mList->numHwLayers ; i++) { + const hwc_layer_t& l(mList->hwLayers[i]); + snprintf(buffer, SIZE, " %8s | %08x | %08x | %02x | %04x | [%5d,%5d,%5d,%5d] | [%5d,%5d,%5d,%5d]\n", + l.compositionType ? "OVERLAY" : "FB", + l.hints, l.flags, l.transform, l.blending, + l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom, + l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom); + result.append(buffer); + } + } +} + // --------------------------------------------------------------------------- }; // namespace android diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 22ff10c..5a9e9eb 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -27,6 +27,8 @@ namespace android { // --------------------------------------------------------------------------- +class String8; + class HWComposer { public: @@ -54,6 +56,9 @@ public: size_t getNumLayers() const; hwc_layer_t* getLayers() const; + // for debugging + void dump(String8& out, char* scratch, size_t SIZE) const; + private: hw_module_t const* mModule; hwc_composer_device_t* mHwc; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index b45f6fe..b353bff 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -85,6 +85,7 @@ SurfaceFlinger::SurfaceFlinger() mFreezeDisplayTime(0), mDebugRegion(0), mDebugBackground(0), + mDebugDisableHWC(0), mDebugInSwapBuffers(0), mLastSwapBufferTime(0), mDebugInTransaction(0), @@ -768,6 +769,10 @@ void SurfaceFlinger::handleWorkList() hwc_layer_t* const cur(hwc.getLayers()); for (size_t i=0 ; cur && i<count ; i++) { currentLayers[i]->setGeometry(&cur[i]); + if (mDebugDisableHWC) { + cur[i].compositionType = HWC_FRAMEBUFFER; + cur[i].flags |= HWC_SKIP_LAYER; + } } } } @@ -901,6 +906,7 @@ void SurfaceFlinger::composeSurfaces(const Region& dirty) continue; } } + const sp<LayerBase>& layer(layers[i]); const Region clip(dirty.intersect(layer->visibleRegionScreen)); if (!clip.isEmpty()) { @@ -1522,6 +1528,13 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) result.append(buffer); } + HWComposer& hwc(hw.getHwComposer()); + snprintf(buffer, SIZE, " h/w composer %s and %s\n", + hwc.initCheck()==NO_ERROR ? "present" : "not present", + mDebugDisableHWC ? "disabled" : "enabled"); + result.append(buffer); + hwc.dump(result, buffer, SIZE); + const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); alloc.dump(result); @@ -1580,6 +1593,11 @@ status_t SurfaceFlinger::onTransact( n = data.readInt32(); mDebugBackground = n ? 1 : 0; return NO_ERROR; + case 1008: // toggle use of hw composer + n = data.readInt32(); + mDebugDisableHWC = n ? 1 : 0; + mHwWorkListDirty = true; + // fall-through... case 1004:{ // repaint everything Mutex::Autolock _l(mStateLock); const DisplayHardware& hw(graphicPlane(0).displayHardware()); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 8e286e5..551e8e7 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -382,6 +382,7 @@ private: // don't use a lock for these, we don't care int mDebugRegion; int mDebugBackground; + int mDebugDisableHWC; volatile nsecs_t mDebugInSwapBuffers; nsecs_t mLastSwapBufferTime; volatile nsecs_t mDebugInTransaction; |