diff options
14 files changed, 329 insertions, 128 deletions
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java index 6a6f027..8c1cf5f 100644 --- a/core/java/android/util/Log.java +++ b/core/java/android/util/Log.java @@ -84,14 +84,14 @@ public final class Log { public static final int ASSERT = 7; /** - * Exception class used to capture a stack trace in {@link #wtf()}. + * Exception class used to capture a stack trace in {@link #wtf}. */ private static class TerribleFailure extends Exception { TerribleFailure(String msg, Throwable cause) { super(msg, cause); } } /** - * Interface to handle terrible failures from {@link #wtf()}. + * Interface to handle terrible failures from {@link #wtf}. * * @hide */ @@ -257,6 +257,15 @@ public final class Log { } /** + * Like {@link #wtf(String, String)}, but also writes to the log the full + * call stack. + * @hide + */ + public static int wtfStack(String tag, String msg) { + return wtfStack(LOG_ID_MAIN, tag, msg); + } + + /** * What a Terrible Failure: Report an exception that should never happen. * Similar to {@link #wtf(String, String)}, with an exception to log. * @param tag Used to identify the source of a log message. @@ -274,8 +283,18 @@ public final class Log { * @param tr An exception to log. May be null. */ public static int wtf(String tag, String msg, Throwable tr) { + return wtf(LOG_ID_MAIN, tag, msg, tr); + } + + static int wtfStack(int logId, String tag, String msg) { + TerribleFailure here = new TerribleFailure("here", null); + here.fillInStackTrace(); + return wtf(logId, tag, msg, here); + } + + static int wtf(int logId, String tag, String msg, Throwable tr) { TerribleFailure what = new TerribleFailure(msg, tr); - int bytes = println_native(LOG_ID_MAIN, ASSERT, tag, msg + '\n' + getStackTraceString(tr)); + int bytes = println_native(logId, ASSERT, tag, msg + '\n' + getStackTraceString(tr)); sWtfHandler.onTerribleFailure(tag, what); return bytes; } diff --git a/core/java/android/util/Slog.java b/core/java/android/util/Slog.java index ecf5ea1..a5c22ff 100644 --- a/core/java/android/util/Slog.java +++ b/core/java/android/util/Slog.java @@ -78,6 +78,22 @@ public final class Slog { msg + '\n' + Log.getStackTraceString(tr)); } + public static int wtf(String tag, String msg) { + return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, null); + } + + public static int wtfStack(String tag, String msg) { + return Log.wtfStack(Log.LOG_ID_SYSTEM, tag, msg); + } + + public static int wtf(String tag, Throwable tr) { + return Log.wtf(Log.LOG_ID_SYSTEM, tag, tr.getMessage(), tr); + } + + public static int wtf(String tag, String msg, Throwable tr) { + return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, tr); + } + public static int println(int priority, String tag, String msg) { return Log.println_native(Log.LOG_ID_SYSTEM, priority, tag, msg); } diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java index a95bac8..430e43a 100644 --- a/core/java/com/android/internal/app/ProcessStats.java +++ b/core/java/com/android/internal/app/ProcessStats.java @@ -44,6 +44,7 @@ import java.util.Objects; public final class ProcessStats implements Parcelable { static final String TAG = "ProcessStats"; static final boolean DEBUG = false; + static final boolean DEBUG_PARCEL = false; public static final String SERVICE_NAME = "procstats"; @@ -1076,7 +1077,7 @@ public final class ProcessStats implements Parcelable { final int[] table = new int[size]; for (int i=0; i<size; i++) { table[i] = in.readInt(); - if (DEBUG) Slog.i(TAG, "Reading in " + name + " table #" + i + ": " + if (DEBUG_PARCEL) Slog.i(TAG, "Reading in " + name + " table #" + i + ": " + ProcessStats.printLongOffset(table[i])); if (!validateLongOffset(table[i])) { Slog.w(TAG, "Ignoring existing stats; bad " + what + " table entry: " @@ -1294,10 +1295,10 @@ public final class ProcessStats implements Parcelable { byte[] data = new byte[initialAvail > 0 ? (initialAvail+1) : 16384]; while (true) { int amt = stream.read(data, pos, data.length-pos); - if (DEBUG) Slog.i("foo", "Read " + amt + " bytes at " + pos + if (DEBUG_PARCEL) Slog.i("foo", "Read " + amt + " bytes at " + pos + " of avail " + data.length); if (amt < 0) { - if (DEBUG) Slog.i("foo", "**** FINISHED READING: pos=" + pos + if (DEBUG_PARCEL) Slog.i("foo", "**** FINISHED READING: pos=" + pos + " len=" + data.length); outLen[0] = pos; return data; @@ -1305,7 +1306,7 @@ public final class ProcessStats implements Parcelable { pos += amt; if (pos >= data.length) { byte[] newData = new byte[pos+16384]; - if (DEBUG) Slog.i(TAG, "Copying " + pos + " bytes to new array len " + if (DEBUG_PARCEL) Slog.i(TAG, "Copying " + pos + " bytes to new array len " + newData.length); System.arraycopy(data, 0, newData, 0, pos); data = newData; @@ -1422,12 +1423,13 @@ public final class ProcessStats implements Parcelable { return; } } - if (DEBUG) Slog.d(TAG, "Adding process: " + procName + " " + uid + " " + proc); + if (DEBUG_PARCEL) Slog.d(TAG, "Adding process: " + procName + " " + uid + + " " + proc); mProcesses.put(procName, uid, proc); } } - if (DEBUG) Slog.d(TAG, "Read " + mProcesses.getMap().size() + " processes"); + if (DEBUG_PARCEL) Slog.d(TAG, "Read " + mProcesses.getMap().size() + " processes"); int NPKG = in.readInt(); if (NPKG < 0) { @@ -1468,10 +1470,10 @@ public final class ProcessStats implements Parcelable { return; } int hasProc = in.readInt(); - if (DEBUG) Slog.d(TAG, "Reading package " + pkgName + " " + uid + if (DEBUG_PARCEL) Slog.d(TAG, "Reading package " + pkgName + " " + uid + " process " + procName + " hasProc=" + hasProc); ProcessState commonProc = mProcesses.get(procName, uid); - if (DEBUG) Slog.d(TAG, "Got common proc " + procName + " " + uid + if (DEBUG_PARCEL) Slog.d(TAG, "Got common proc " + procName + " " + uid + ": " + commonProc); if (commonProc == null) { mReadError = "no common proc: " + procName; @@ -1493,11 +1495,11 @@ public final class ProcessStats implements Parcelable { return; } } - if (DEBUG) Slog.d(TAG, "Adding package " + pkgName + " process: " + if (DEBUG_PARCEL) Slog.d(TAG, "Adding package " + pkgName + " process: " + procName + " " + uid + " " + proc); pkgState.mProcesses.put(procName, proc); } else { - if (DEBUG) Slog.d(TAG, "Adding package " + pkgName + " process: " + if (DEBUG_PARCEL) Slog.d(TAG, "Adding package " + pkgName + " process: " + procName + " " + uid + " " + commonProc); pkgState.mProcesses.put(procName, commonProc); } @@ -1522,7 +1524,7 @@ public final class ProcessStats implements Parcelable { if (!serv.readFromParcel(in)) { return; } - if (DEBUG) Slog.d(TAG, "Adding package " + pkgName + " service: " + if (DEBUG_PARCEL) Slog.d(TAG, "Adding package " + pkgName + " service: " + serviceName + " " + uid + " " + serv); pkgState.mServices.put(serviceName, serv); } @@ -1531,7 +1533,7 @@ public final class ProcessStats implements Parcelable { mIndexToCommonString = null; - if (DEBUG) Slog.d(TAG, "Successfully read procstats!"); + if (DEBUG_PARCEL) Slog.d(TAG, "Successfully read procstats!"); } int addLongData(int index, int type, int num) { @@ -1577,7 +1579,7 @@ public final class ProcessStats implements Parcelable { if (idx >= LONGS_SIZE) { return false; } - if (DEBUG) Slog.d(TAG, "Validated long " + printLongOffset(off) + if (DEBUG_PARCEL) Slog.d(TAG, "Validated long " + printLongOffset(off) + ": " + getLong(off, 0)); return true; } @@ -1639,13 +1641,16 @@ public final class ProcessStats implements Parcelable { if (commonProc == null) { commonProc = new ProcessState(this, packageName, uid, processName); mProcesses.put(processName, uid, commonProc); + if (DEBUG) Slog.d(TAG, "GETPROC created new common " + commonProc); } if (!commonProc.mMultiPackage) { if (packageName.equals(commonProc.mPackage)) { // This common process is not in use by multiple packages, and // is for the calling package, so we can just use it directly. ps = commonProc; + if (DEBUG) Slog.d(TAG, "GETPROC also using for pkg " + commonProc); } else { + if (DEBUG) Slog.d(TAG, "GETPROC need to split common proc!"); // This common process has not been in use by multiple packages, // but it was created for a different package than the caller. // We need to convert it to a multi-package process. @@ -1659,22 +1664,39 @@ public final class ProcessStats implements Parcelable { // that under the now unique state for its original package name. final PackageState commonPkgState = getPackageStateLocked(commonProc.mPackage, uid); if (commonPkgState != null) { - commonPkgState.mProcesses.put(commonProc.mName, commonProc.clone( - commonProc.mPackage, now)); + ProcessState cloned = commonProc.clone(commonProc.mPackage, now); + if (DEBUG) Slog.d(TAG, "GETPROC setting clone to pkg " + commonProc.mPackage + + ": " + cloned); + commonPkgState.mProcesses.put(commonProc.mName, cloned); + // If this has active services, we need to update their process pointer + // to point to the new package-specific process state. + for (int i=commonPkgState.mServices.size()-1; i>=0; i--) { + ServiceState ss = commonPkgState.mServices.valueAt(i); + if (ss.mProc == commonProc) { + if (DEBUG) Slog.d(TAG, "GETPROC switching service to cloned: " + + ss); + ss.mProc = cloned; + } else if (DEBUG) { + Slog.d(TAG, "GETPROC leaving proc of " + ss); + } + } } else { Slog.w(TAG, "Cloning proc state: no package state " + commonProc.mPackage + "/" + uid + " for proc " + commonProc.mName); } // And now make a fresh new process state for the new package name. ps = new ProcessState(commonProc, packageName, uid, processName, now); + if (DEBUG) Slog.d(TAG, "GETPROC created new pkg " + ps); } } else { // The common process is for multiple packages, we need to create a // separate object for the per-package data. ps = new ProcessState(commonProc, packageName, uid, processName, SystemClock.uptimeMillis()); + if (DEBUG) Slog.d(TAG, "GETPROC created new pkg " + ps); } pkgState.mProcesses.put(processName, ps); + if (DEBUG) Slog.d(TAG, "GETPROC adding new pkg " + ps); return ps; } @@ -1683,12 +1705,14 @@ public final class ProcessStats implements Parcelable { final ProcessStats.PackageState as = getPackageStateLocked(packageName, uid); ProcessStats.ServiceState ss = as.mServices.get(className); if (ss != null) { + if (DEBUG) Slog.d(TAG, "GETSVC: returning existing " + ss); return ss; } final ProcessStats.ProcessState ps = processName != null ? getProcessStateLocked(packageName, uid, processName) : null; ss = new ProcessStats.ServiceState(this, packageName, className, processName, ps); as.mServices.put(className, ss); + if (DEBUG) Slog.d(TAG, "GETSVC: creating " + ss + " in " + ps); return ss; } @@ -1719,7 +1743,7 @@ public final class ProcessStats implements Parcelable { } public void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpSummary, - boolean dumpAll) { + boolean dumpAll, boolean activeOnly) { long totalTime = dumpSingleTime(null, null, mMemFactorDurations, mMemFactor, mStartTime, now); ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap(); @@ -1746,6 +1770,11 @@ public final class ProcessStats implements Parcelable { if (!dumpSummary || dumpAll) { for (int iproc=0; iproc<NPROCS; iproc++) { ProcessState proc = pkgState.mProcesses.valueAt(iproc); + if (activeOnly && !proc.isInUse()) { + pw.print(" (Not active: "); + pw.print(pkgState.mProcesses.keyAt(iproc)); pw.println(")"); + continue; + } pw.print(" Process "); pw.print(pkgState.mProcesses.keyAt(iproc)); pw.print(" ("); @@ -1761,12 +1790,22 @@ public final class ProcessStats implements Parcelable { } else { ArrayList<ProcessState> procs = new ArrayList<ProcessState>(); for (int iproc=0; iproc<NPROCS; iproc++) { - procs.add(pkgState.mProcesses.valueAt(iproc)); + ProcessState proc = pkgState.mProcesses.valueAt(iproc); + if (activeOnly && !proc.isInUse()) { + continue; + } + procs.add(proc); } dumpProcessSummaryLocked(pw, " ", procs, ALL_SCREEN_ADJ, ALL_MEM_ADJ, NON_CACHED_PROC_STATES, now, totalTime); } for (int isvc=0; isvc<NSRVS; isvc++) { + ServiceState svc = pkgState.mServices.valueAt(isvc); + if (activeOnly && !svc.isInUse()) { + pw.print(" (Not active: "); + pw.print(pkgState.mServices.keyAt(isvc)); pw.println(")"); + continue; + } if (dumpAll) { pw.print(" Service "); } else { @@ -1774,7 +1813,6 @@ public final class ProcessStats implements Parcelable { } pw.print(pkgState.mServices.keyAt(isvc)); pw.println(":"); - ServiceState svc = pkgState.mServices.valueAt(isvc); pw.print(" Process: "); pw.println(svc.mProcessName); dumpServiceStats(pw, " ", " ", " ", "Running", svc, svc.mRunCount, ServiceState.SERVICE_RUN, svc.mRunState, @@ -1789,7 +1827,9 @@ public final class ProcessStats implements Parcelable { svc.mExecCount, ServiceState.SERVICE_EXEC, svc.mExecState, svc.mExecStartTime, now, totalTime, !dumpSummary || dumpAll); if (dumpAll) { - pw.print(" mActive="); pw.println(svc.mActive); + if (svc.mOwner != null) { + pw.print(" mOwner="); pw.println(svc.mOwner); + } } } } @@ -1816,6 +1856,10 @@ public final class ProcessStats implements Parcelable { pw.println("Per-Process Stats:"); printedHeader = true; } + if (activeOnly && !proc.isInUse()) { + pw.print(" (Not active: "); pw.print(procName); pw.println(")"); + continue; + } pw.print(" * "); pw.print(procName); pw.print(" / "); UserHandle.formatUid(pw, uid); pw.print(" ("); pw.print(proc.mDurationsTableSize); @@ -1838,7 +1882,7 @@ public final class ProcessStats implements Parcelable { pw.println(); if (dumpSummary) { pw.println("Summary:"); - dumpSummaryLocked(pw, reqPackage, now); + dumpSummaryLocked(pw, reqPackage, now, activeOnly); } else { dumpTotalsLocked(pw, now); } @@ -1916,11 +1960,11 @@ public final class ProcessStats implements Parcelable { } } - public void dumpSummaryLocked(PrintWriter pw, String reqPackage, long now) { + public void dumpSummaryLocked(PrintWriter pw, String reqPackage, long now, boolean activeOnly) { long totalTime = dumpSingleTime(null, null, mMemFactorDurations, mMemFactor, mStartTime, now); dumpFilteredSummaryLocked(pw, null, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ, - ALL_PROC_STATES, NON_CACHED_PROC_STATES, now, totalTime, reqPackage); + ALL_PROC_STATES, NON_CACHED_PROC_STATES, now, totalTime, reqPackage, activeOnly); pw.println(); dumpTotalsLocked(pw, now); } @@ -1961,9 +2005,9 @@ public final class ProcessStats implements Parcelable { void dumpFilteredSummaryLocked(PrintWriter pw, String header, String prefix, int[] screenStates, int[] memStates, int[] procStates, - int[] sortProcStates, long now, long totalTime, String reqPackage) { + int[] sortProcStates, long now, long totalTime, String reqPackage, boolean activeOnly) { ArrayList<ProcessState> procs = collectProcessesLocked(screenStates, memStates, - procStates, sortProcStates, now, reqPackage); + procStates, sortProcStates, now, reqPackage, activeOnly); if (procs.size() > 0) { if (header != null) { pw.println(); @@ -1975,7 +2019,8 @@ public final class ProcessStats implements Parcelable { } public ArrayList<ProcessState> collectProcessesLocked(int[] screenStates, int[] memStates, - int[] procStates, int sortProcStates[], long now, String reqPackage) { + int[] procStates, int sortProcStates[], long now, String reqPackage, + boolean activeOnly) { ArraySet<ProcessState> foundProcs = new ArraySet<ProcessState>(); ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap(); for (int ip=0; ip<pkgMap.size(); ip++) { @@ -1987,6 +2032,9 @@ public final class ProcessStats implements Parcelable { PackageState state = procs.valueAt(iu); for (int iproc=0; iproc<state.mProcesses.size(); iproc++) { ProcessState proc = state.mProcesses.valueAt(iproc); + if (activeOnly && !proc.isInUse()) { + continue; + } foundProcs.add(proc.mCommonProcess); } } @@ -1994,8 +2042,7 @@ public final class ProcessStats implements Parcelable { ArrayList<ProcessState> outProcs = new ArrayList<ProcessState>(foundProcs.size()); for (int i=0; i<foundProcs.size(); i++) { ProcessState proc = foundProcs.valueAt(i); - if (computeProcessTimeLocked(proc, screenStates, memStates, - procStates, now) > 0) { + if (computeProcessTimeLocked(proc, screenStates, memStates, procStates, now) > 0) { outProcs.add(proc); if (procStates != sortProcStates) { computeProcessTimeLocked(proc, screenStates, memStates, sortProcStates, now); @@ -2229,7 +2276,7 @@ public final class ProcessStats implements Parcelable { void writeDurationsToParcel(Parcel out) { out.writeInt(mDurationsTableSize); for (int i=0; i<mDurationsTableSize; i++) { - if (DEBUG) Slog.i(TAG, "Writing in " + mName + " dur #" + i + ": " + if (DEBUG_PARCEL) Slog.i(TAG, "Writing in " + mName + " dur #" + i + ": " + printLongOffset(mDurationsTable[i])); out.writeInt(mDurationsTable[i]); } @@ -2350,6 +2397,7 @@ public final class ProcessStats implements Parcelable { pnew.mAvgCachedKillPss = mAvgCachedKillPss; pnew.mMaxCachedKillPss = mMaxCachedKillPss; pnew.mActive = mActive; + pnew.mNumActiveServices = mNumActiveServices; pnew.mNumStartedServices = mNumStartedServices; return pnew; } @@ -2396,7 +2444,7 @@ public final class ProcessStats implements Parcelable { if (!mDead) { return; } - throw new IllegalStateException("ProcessState dead: name=" + mName + Slog.wtfStack(TAG, "ProcessState dead: name=" + mName + " pkg=" + mPackage + " uid=" + mUid + " common.name=" + mCommonProcess.mName); } @@ -2405,7 +2453,7 @@ public final class ProcessStats implements Parcelable { writeDurationsToParcel(out); out.writeInt(mPssTableSize); for (int i=0; i<mPssTableSize; i++) { - if (DEBUG) Slog.i(TAG, "Writing in " + mName + " pss #" + i + ": " + if (DEBUG_PARCEL) Slog.i(TAG, "Writing in " + mName + " pss #" + i + ": " + printLongOffset(mPssTable[i])); out.writeInt(mPssTable[i]); } @@ -2424,11 +2472,11 @@ public final class ProcessStats implements Parcelable { if (fully) { mMultiPackage = multiPackage; } - if (DEBUG) Slog.d(TAG, "Reading durations table..."); + if (DEBUG_PARCEL) Slog.d(TAG, "Reading durations table..."); if (!readDurationsFromParcel(in)) { return false; } - if (DEBUG) Slog.d(TAG, "Reading pss table..."); + if (DEBUG_PARCEL) Slog.d(TAG, "Reading pss table..."); mPssTable = mStats.readTableFromParcel(in, mName, "pss"); if (mPssTable == BAD_TABLE) { return false; @@ -2512,21 +2560,34 @@ public final class ProcessStats implements Parcelable { mStartTime = now; } - void incActiveServices() { + void incActiveServices(String serviceName) { + if (DEBUG && "".equals(mName)) { + RuntimeException here = new RuntimeException("here"); + here.fillInStackTrace(); + Slog.d(TAG, "incActiveServices: " + this + " service=" + serviceName + + " to " + (mNumActiveServices+1), here); + } if (mCommonProcess != this) { - mCommonProcess.incActiveServices(); + mCommonProcess.incActiveServices(serviceName); } mNumActiveServices++; } - void decActiveServices() { + void decActiveServices(String serviceName) { + if (DEBUG && "".equals(mName)) { + RuntimeException here = new RuntimeException("here"); + here.fillInStackTrace(); + Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName + + " to " + (mNumActiveServices-1), here); + } if (mCommonProcess != this) { - mCommonProcess.decActiveServices(); + mCommonProcess.decActiveServices(serviceName); } mNumActiveServices--; if (mNumActiveServices < 0) { - throw new IllegalStateException("Proc active services underrun: pkg=" - + mPackage + " uid=" + mUid + " name=" + mName); + Slog.wtfStack(TAG, "Proc active services underrun: pkg=" + mPackage + + " uid=" + mUid + " proc=" + mName + " service=" + serviceName); + mNumActiveServices = 0; } } @@ -2548,8 +2609,9 @@ public final class ProcessStats implements Parcelable { if (mNumStartedServices == 0 && mCurState == STATE_SERVICE_RESTARTING) { setState(STATE_NOTHING, memFactor, now, null); } else if (mNumStartedServices < 0) { - throw new IllegalStateException("Proc started services underrun: pkg=" + Slog.wtfStack(TAG, "Proc started services underrun: pkg=" + mPackage + " uid=" + mUid + " name=" + mName); + mNumStartedServices = 0; } } @@ -2689,8 +2751,7 @@ public final class ProcessStats implements Parcelable { // The array map is still pointing to a common process state // that is now shared across packages. Update it to point to // the new per-package state. - ProcessState proc = mStats.mPackages.get(pkgName, - mUid).mProcesses.get(mName); + ProcessState proc = mStats.mPackages.get(pkgName, mUid).mProcesses.get(mName); if (proc == null) { throw new IllegalStateException("Didn't create per-package process"); } @@ -2717,11 +2778,13 @@ public final class ProcessStats implements Parcelable { PackageState pkg = mStats.mPackages.get(pkgList.keyAt(index), proc.mUid); if (pkg == null) { throw new IllegalStateException("No existing package " - + pkgList.keyAt(index) + " for multi-proc " + proc.mName); + + pkgList.keyAt(index) + "/" + proc.mUid + + " for multi-proc " + proc.mName); } proc = pkg.mProcesses.get(proc.mName); if (proc == null) { - throw new IllegalStateException("Didn't create per-package process"); + throw new IllegalStateException("Didn't create per-package process " + + proc.mName + " in pkg " + pkg.mPackageName + "/" + pkg.mUid); } pkgList.setValueAt(index, proc); } @@ -2770,6 +2833,17 @@ public final class ProcessStats implements Parcelable { int idx = binarySearch(mPssTable, mPssTableSize, state); return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_USS_MAXIMUM) : 0; } + + public String toString() { + StringBuilder sb = new StringBuilder(128); + sb.append("ProcessState{").append(Integer.toHexString(System.identityHashCode(this))) + .append(" ").append(mName).append("/").append(mUid) + .append(" pkg=").append(mPackage); + if (mMultiPackage) sb.append(" (multi)"); + if (mCommonProcess != this) sb.append(" (sub)"); + sb.append("}"); + return sb.toString(); + } } public static final class ServiceState extends DurationsTable { @@ -2777,7 +2851,7 @@ public final class ProcessStats implements Parcelable { public final String mProcessName; ProcessState mProc; - int mActive = 0; + Object mOwner; public static final int SERVICE_RUN = 0; public static final int SERVICE_STARTED = 1; @@ -2809,27 +2883,69 @@ public final class ProcessStats implements Parcelable { mProc = proc; } - public void makeActive() { - if (mActive == 0) { - mProc.incActiveServices(); + public void applyNewOwner(Object newOwner) { + if (mOwner != newOwner) { + if (mOwner == null) { + mOwner = newOwner; + mProc.incActiveServices(mName); + } else { + // There was already an old owner, reset this object for its + // new owner. + mOwner = newOwner; + if (mStartedState != STATE_NOTHING || mBoundState != STATE_NOTHING + || mExecState != STATE_NOTHING) { + long now = SystemClock.uptimeMillis(); + if (mStartedState != STATE_NOTHING) { + if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner + + " from " + mOwner + " while started: pkg=" + + mPackage + " service=" + mName + " proc=" + mProc); + setStarted(false, 0, now); + } + if (mBoundState != STATE_NOTHING) { + if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner + + " from " + mOwner + " while bound: pkg=" + + mPackage + " service=" + mName + " proc=" + mProc); + setBound(false, 0, now); + } + if (mExecState != STATE_NOTHING) { + if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner + + " from " + mOwner + " while executing: pkg=" + + mPackage + " service=" + mName + " proc=" + mProc); + setExecuting(false, 0, now); + } + } + } } - mActive++; } - public void makeInactive() { - /* - RuntimeException here = new RuntimeException("here"); - here.fillInStackTrace(); - Slog.i(TAG, "Making " + this + " inactive", here); - */ - mActive--; - if (mActive == 0) { - mProc.decActiveServices(); + public void clearCurrentOwner(Object owner) { + if (mOwner == owner) { + mOwner = null; + mProc.decActiveServices(mName); + if (mStartedState != STATE_NOTHING || mBoundState != STATE_NOTHING + || mExecState != STATE_NOTHING) { + long now = SystemClock.uptimeMillis(); + if (mStartedState != STATE_NOTHING) { + Slog.wtfStack(TAG, "Service owner " + owner + " cleared while started: pkg=" + + mPackage + " service=" + mName + " proc=" + mProc); + setStarted(false, 0, now); + } + if (mBoundState != STATE_NOTHING) { + Slog.wtfStack(TAG, "Service owner " + owner + " cleared while bound: pkg=" + + mPackage + " service=" + mName + " proc=" + mProc); + setBound(false, 0, now); + } + if (mExecState != STATE_NOTHING) { + Slog.wtfStack(TAG, "Service owner " + owner + " cleared while exec: pkg=" + + mPackage + " service=" + mName + " proc=" + mProc); + setExecuting(false, 0, now); + } + } } } public boolean isInUse() { - return mActive > 0; + return mOwner != null; } void add(ServiceState other) { @@ -2904,8 +3020,8 @@ public final class ProcessStats implements Parcelable { } public void setStarted(boolean started, int memFactor, long now) { - if (mActive <= 0) { - throw new IllegalStateException("Service " + this + " has mActive=" + mActive); + if (mOwner == null) { + Slog.wtf(TAG, "Starting service " + this + " without owner"); } final boolean wasStarted = mStartedState != STATE_NOTHING; final int state = started ? memFactor : STATE_NOTHING; @@ -2931,8 +3047,8 @@ public final class ProcessStats implements Parcelable { } public void setBound(boolean bound, int memFactor, long now) { - if (mActive <= 0) { - throw new IllegalStateException("Service " + this + " has mActive=" + mActive); + if (mOwner == null) { + Slog.wtf(TAG, "Binding service " + this + " without owner"); } final int state = bound ? memFactor : STATE_NOTHING; if (mBoundState != state) { @@ -2949,8 +3065,8 @@ public final class ProcessStats implements Parcelable { } public void setExecuting(boolean executing, int memFactor, long now) { - if (mActive <= 0) { - throw new IllegalStateException("Service " + this + " has mActive=" + mActive); + if (mOwner == null) { + Slog.wtf(TAG, "Executing service " + this + " without owner"); } final int state = executing ? memFactor : STATE_NOTHING; if (mExecState != state) { @@ -2974,6 +3090,12 @@ public final class ProcessStats implements Parcelable { } return time; } + + public String toString() { + return "ServiceState{" + Integer.toHexString(System.identityHashCode(this)) + + " " + mName + " pkg=" + mPackage + " proc=" + + Integer.toHexString(System.identityHashCode(this)) + "}"; + } } public static final class PackageState { diff --git a/services/java/com/android/server/ClipboardService.java b/services/java/com/android/server/ClipboardService.java index 0bf03b5..069ae23 100644 --- a/services/java/com/android/server/ClipboardService.java +++ b/services/java/com/android/server/ClipboardService.java @@ -122,7 +122,9 @@ public class ClipboardService extends IClipboard.Stub { try { return super.onTransact(code, data, reply, flags); } catch (RuntimeException e) { - Slog.w("clipboard", "Exception: ", e); + if (!(e instanceof SecurityException)) { + Slog.wtf("clipboard", "Exception: ", e); + } throw e; } diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index 45c614f..794d274 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -817,7 +817,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // The input method manager only throws security exceptions, so let's // log all others. if (!(e instanceof SecurityException)) { - Slog.e(TAG, "Input Method Manager Crash", e); + Slog.wtf(TAG, "Input Method Manager Crash", e); } throw e; } diff --git a/services/java/com/android/server/accounts/AccountManagerService.java b/services/java/com/android/server/accounts/AccountManagerService.java index 3a3dfd5..dd9ae4c 100644 --- a/services/java/com/android/server/accounts/AccountManagerService.java +++ b/services/java/com/android/server/accounts/AccountManagerService.java @@ -60,6 +60,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.Parcel; import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; @@ -267,6 +268,21 @@ public class AccountManagerService }, UserHandle.ALL, userFilter, null, null); } + @Override + public boolean onTransact(int code, Parcel data, Parcel reply, int flags) + throws RemoteException { + try { + return super.onTransact(code, data, reply, flags); + } catch (RuntimeException e) { + // The account manager only throws security exceptions, so let's + // log all others. + if (!(e instanceof SecurityException)) { + Slog.wtf(TAG, "Account Manager Crash", e); + } + throw e; + } + } + public void systemReady() { } diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java index 8f4bf21..27ca7a0 100644 --- a/services/java/com/android/server/am/ActiveServices.java +++ b/services/java/com/android/server/am/ActiveServices.java @@ -130,9 +130,9 @@ public final class ActiveServices { = new ArrayList<ServiceRecord>(); /** - * List of services that are in the process of being stopped. + * List of services that are in the process of being destroyed. */ - final ArrayList<ServiceRecord> mStoppingServices + final ArrayList<ServiceRecord> mDestroyingServices = new ArrayList<ServiceRecord>(); static final class DelayingProcess extends ArrayList<ServiceRecord> { @@ -788,7 +788,7 @@ public final class ActiveServices { } } - serviceDoneExecutingLocked(r, mStoppingServices.contains(r)); + serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false); } } finally { Binder.restoreCallingIdentity(origId); @@ -834,9 +834,9 @@ public final class ActiveServices { + " at " + b + ": apps=" + (b != null ? b.apps.size() : 0)); - boolean inStopping = mStoppingServices.contains(r); + boolean inDestroying = mDestroyingServices.contains(r); if (b != null) { - if (b.apps.size() > 0 && !inStopping) { + if (b.apps.size() > 0 && !inDestroying) { // Applications have already bound since the last // unbind, so just rebind right here. boolean inFg = false; @@ -856,7 +856,7 @@ public final class ActiveServices { } } - serviceDoneExecutingLocked(r, inStopping); + serviceDoneExecutingLocked(r, inDestroying, false); } } finally { Binder.restoreCallingIdentity(origId); @@ -1419,14 +1419,10 @@ public final class ActiveServices { } } - private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn, - boolean hasConn) { - //Slog.i(TAG, "Bring down service:"); - //r.dump(" "); - + private final boolean isServiceNeeded(ServiceRecord r, boolean knowConn, boolean hasConn) { // Are we still explicitly being asked to run? if (r.startRequested) { - return; + return true; } // Is someone still bound to us keepign us running? @@ -1434,6 +1430,18 @@ public final class ActiveServices { hasConn = r.hasAutoCreateConnections(); } if (hasConn) { + return true; + } + + return false; + } + + private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn, + boolean hasConn) { + //Slog.i(TAG, "Bring down service:"); + //r.dump(" "); + + if (isServiceNeeded(r, knowConn, hasConn)) { return; } @@ -1484,7 +1492,7 @@ public final class ActiveServices { } catch (Exception e) { Slog.w(TAG, "Exception when unbinding service " + r.shortName, e); - serviceDoneExecutingLocked(r, true); + serviceDoneExecutingLocked(r, true, true); } } } @@ -1527,14 +1535,14 @@ public final class ActiveServices { r.app.services.remove(r); if (r.app.thread != null) { try { - bumpServiceExecutingLocked(r, false, "stop"); - mStoppingServices.add(r); + bumpServiceExecutingLocked(r, false, "destroy"); + mDestroyingServices.add(r); mAm.updateOomAdjLocked(r.app); r.app.thread.scheduleStopService(r); } catch (Exception e) { - Slog.w(TAG, "Exception when stopping service " + Slog.w(TAG, "Exception when destroying service " + r.shortName, e); - serviceDoneExecutingLocked(r, true); + serviceDoneExecutingLocked(r, true, true); } updateServiceForegroundLocked(r.app, false); } else { @@ -1560,7 +1568,7 @@ public final class ActiveServices { r.tracker.setStarted(false, memFactor, now); r.tracker.setBound(false, memFactor, now); if (r.executeNesting == 0) { - r.tracker.makeInactive(); + r.tracker.clearCurrentOwner(r); r.tracker = null; } } @@ -1619,7 +1627,7 @@ public final class ActiveServices { s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent()); } catch (Exception e) { Slog.w(TAG, "Exception when unbinding service " + s.shortName, e); - serviceDoneExecutingLocked(s, true); + serviceDoneExecutingLocked(s, true, true); } } @@ -1637,7 +1645,7 @@ public final class ActiveServices { } void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) { - boolean inStopping = mStoppingServices.contains(r); + boolean inDestroying = mDestroyingServices.contains(r); if (r != null) { if (type == 1) { // This is a call from a service start... take care of @@ -1690,7 +1698,7 @@ public final class ActiveServices { } } final long origId = Binder.clearCallingIdentity(); - serviceDoneExecutingLocked(r, inStopping); + serviceDoneExecutingLocked(r, inDestroying, inDestroying); Binder.restoreCallingIdentity(origId); } else { Slog.w(TAG, "Done executing unknown service from pid " @@ -1698,10 +1706,11 @@ public final class ActiveServices { } } - private void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) { + private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying, + boolean finishing) { if (DEBUG_SERVICE) Slog.v(TAG, "<<< DONE EXECUTING " + r + ": nesting=" + r.executeNesting - + ", inStopping=" + inStopping + ", app=" + r.app); + + ", inDestroying=" + inDestroying + ", app=" + r.app); else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG, "<<< DONE EXECUTING " + r.shortName); r.executeNesting--; if (r.executeNesting <= 0) { @@ -1723,10 +1732,10 @@ public final class ActiveServices { } } } - if (inStopping) { + if (inDestroying) { if (DEBUG_SERVICE) Slog.v(TAG, - "doneExecuting remove stopping " + r); - mStoppingServices.remove(r); + "doneExecuting remove destroying " + r); + mDestroyingServices.remove(r); r.bindings.clear(); } mAm.updateOomAdjLocked(r.app); @@ -1735,8 +1744,8 @@ public final class ActiveServices { if (r.tracker != null) { r.tracker.setExecuting(false, mAm.mProcessStats.getMemFactorLocked(), SystemClock.uptimeMillis()); - if (inStopping) { - r.tracker.makeInactive(); + if (finishing) { + r.tracker.clearCurrentOwner(r); r.tracker = null; } } @@ -1931,12 +1940,9 @@ public final class ActiveServices { sr.app = null; sr.isolatedProc = null; sr.executeNesting = 0; - if (sr.tracker != null) { - sr.tracker.setExecuting(false, mAm.mProcessStats.getMemFactorLocked(), - SystemClock.uptimeMillis()); - } - if (mStoppingServices.remove(sr)) { - if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove stopping " + sr); + sr.forceClearTracker(); + if (mDestroyingServices.remove(sr)) { + if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove destroying " + sr); } final int numClients = sr.bindings.size(); @@ -1984,13 +1990,14 @@ public final class ActiveServices { } // Make sure we have no more records on the stopping list. - int i = mStoppingServices.size(); + int i = mDestroyingServices.size(); while (i > 0) { i--; - ServiceRecord sr = mStoppingServices.get(i); + ServiceRecord sr = mDestroyingServices.get(i); if (sr.app == app) { - mStoppingServices.remove(i); - if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove stopping " + sr); + sr.forceClearTracker(); + mDestroyingServices.remove(i); + if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove destroying " + sr); } } @@ -2340,10 +2347,10 @@ public final class ActiveServices { needSep = true; } - if (mStoppingServices.size() > 0) { + if (mDestroyingServices.size() > 0) { boolean printed = false; - for (int i=0; i<mStoppingServices.size(); i++) { - ServiceRecord r = mStoppingServices.get(i); + for (int i=0; i< mDestroyingServices.size(); i++) { + ServiceRecord r = mDestroyingServices.get(i); if (!matcher.match(r, r.name)) { continue; } @@ -2354,10 +2361,10 @@ public final class ActiveServices { if (!printed) { if (needSep) pw.println(); needSep = true; - pw.println(" Stopping services:"); + pw.println(" Destroying services:"); printed = true; } - pw.print(" * Stopping "); pw.println(r); + pw.print(" * Destroy "); pw.println(r); r.dump(pw, " "); } needSep = true; diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index c1ac7d5..f2ff9ca 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -2051,7 +2051,7 @@ public final class ActivityManagerService extends ActivityManagerNative // The activity manager only throws security exceptions, so let's // log all others. if (!(e instanceof SecurityException)) { - Slog.e(TAG, "Activity Manager Crash", e); + Slog.wtf(TAG, "Activity Manager Crash", e); } throw e; } diff --git a/services/java/com/android/server/am/ProcessStatsService.java b/services/java/com/android/server/am/ProcessStatsService.java index 2c49bb9..7dc006c 100644 --- a/services/java/com/android/server/am/ProcessStatsService.java +++ b/services/java/com/android/server/am/ProcessStatsService.java @@ -357,7 +357,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates, boolean sepProcStates, int[] procStates, long now, String reqPackage) { ArrayList<ProcessStats.ProcessState> procs = mProcessStats.collectProcessesLocked( - screenStates, memStates, procStates, procStates, now, reqPackage); + screenStates, memStates, procStates, procStates, now, reqPackage, false); if (procs.size() > 0) { if (header != null) { pw.println(header); @@ -519,7 +519,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { static private void dumpHelp(PrintWriter pw) { pw.println("Process stats (procstats) dump options:"); pw.println(" [--checkin|-c|--csv] [--csv-screen] [--csv-proc] [--csv-mem]"); - pw.println(" [--details] [--full-details] [--current] [--hours]"); + pw.println(" [--details] [--full-details] [--current] [--hours] [--active]"); pw.println(" [--commit] [--reset] [--clear] [--write] [-h] [<package.name>]"); pw.println(" --checkin: perform a checkin: print and delete old committed states."); pw.println(" --c: print only state in checkin format."); @@ -528,10 +528,11 @@ public final class ProcessStatsService extends IProcessStats.Stub { pw.println(" --csv-mem: norm, mod, low, crit."); pw.println(" --csv-proc: pers, top, fore, vis, precept, backup,"); pw.println(" service, home, prev, cached"); - pw.println(" --details: dump all execution details, not just summary."); - pw.println(" --full-details: dump only detail information, for all saved state."); + pw.println(" --details: dump per-package details, not just summary."); + pw.println(" --full-details: dump all timing and active state details."); pw.println(" --current: only dump current state."); pw.println(" --hours: aggregate over about N last hours."); + pw.println(" --active: only show currently active processes/services."); pw.println(" --commit: commit current stats to disk and reset to start new stats."); pw.println(" --reset: reset current stats, without committing."); pw.println(" --clear: clear all stats; does both --reset and deletes old stats."); @@ -562,6 +563,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { boolean dumpFullDetails = false; boolean dumpAll = false; int aggregateHours = 0; + boolean activeOnly = false; String reqPackage = null; boolean csvSepScreenStats = false; int[] csvScreenStats = new int[] { ProcessStats.ADJ_SCREEN_OFF, ProcessStats.ADJ_SCREEN_ON}; @@ -645,6 +647,9 @@ public final class ProcessStatsService extends IProcessStats.Stub { dumpHelp(pw); return; } + } else if ("--active".equals(arg)) { + activeOnly = true; + currentOnly = true; } else if ("--current".equals(arg)) { currentOnly = true; } else if ("--commit".equals(arg)) { @@ -779,9 +784,9 @@ public final class ProcessStatsService extends IProcessStats.Stub { stats.dumpCheckinLocked(pw, reqPackage); } else { if (dumpDetails || dumpFullDetails) { - stats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpAll); + stats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpAll, activeOnly); } else { - stats.dumpSummaryLocked(pw, reqPackage, now); + stats.dumpSummaryLocked(pw, reqPackage, now, activeOnly); } } return; @@ -826,9 +831,10 @@ public final class ProcessStatsService extends IProcessStats.Stub { // Always dump summary here, dumping all details is just too // much crud. if (dumpFullDetails) { - mProcessStats.dumpLocked(pw, reqPackage, now, false, false); + mProcessStats.dumpLocked(pw, reqPackage, now, false, false, + activeOnly); } else { - processStats.dumpSummaryLocked(pw, reqPackage, now); + processStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly); } } if (isCheckin) { @@ -856,12 +862,13 @@ public final class ProcessStatsService extends IProcessStats.Stub { pw.println("CURRENT STATS:"); } if (dumpDetails || dumpFullDetails) { - mProcessStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpAll); + mProcessStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpAll, + activeOnly); if (dumpAll) { pw.print(" mFile="); pw.println(mFile.getBaseFile()); } } else { - mProcessStats.dumpSummaryLocked(pw, reqPackage, now); + mProcessStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly); } } } diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java index ac14da9..c47c1ac 100644 --- a/services/java/com/android/server/am/ServiceRecord.java +++ b/services/java/com/android/server/am/ServiceRecord.java @@ -328,11 +328,23 @@ final class ServiceRecord extends Binder { if ((serviceInfo.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) { tracker = ams.mProcessStats.getServiceStateLocked(serviceInfo.packageName, serviceInfo.applicationInfo.uid, serviceInfo.processName, serviceInfo.name); - tracker.makeActive(); + tracker.applyNewOwner(this); } return tracker; } + public void forceClearTracker() { + if (tracker != null) { + int memFactor = ams.mProcessStats.getMemFactorLocked(); + long now = SystemClock.uptimeMillis(); + tracker.setStarted(false, memFactor, now); + tracker.setBound(false, memFactor, now); + tracker.setExecuting(false, memFactor, now); + tracker.clearCurrentOwner(this); + tracker = null; + } + } + public AppBindRecord retrieveAppBindingLocked(Intent intent, ProcessRecord app) { Intent.FilterComparison filter = new Intent.FilterComparison(intent); diff --git a/services/java/com/android/server/content/ContentService.java b/services/java/com/android/server/content/ContentService.java index 7c82821..885ec9f 100644 --- a/services/java/com/android/server/content/ContentService.java +++ b/services/java/com/android/server/content/ContentService.java @@ -141,7 +141,7 @@ public final class ContentService extends IContentService.Stub { // The content service only throws security exceptions, so let's // log all others. if (!(e instanceof SecurityException)) { - Log.e(TAG, "Content Service Crash", e); + Slog.wtf(TAG, "Content Service Crash", e); } throw e; } diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 6cf3223..f093f2b 100755 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -1501,7 +1501,7 @@ public class PackageManagerService extends IPackageManager.Stub { return super.onTransact(code, data, reply, flags); } catch (RuntimeException e) { if (!(e instanceof SecurityException) && !(e instanceof IllegalArgumentException)) { - Slog.e(TAG, "Package Manager Crash", e); + Slog.wtf(TAG, "Package Manager Crash", e); } throw e; } diff --git a/services/java/com/android/server/wm/Session.java b/services/java/com/android/server/wm/Session.java index 1d95c44..87cabc9 100644 --- a/services/java/com/android/server/wm/Session.java +++ b/services/java/com/android/server/wm/Session.java @@ -126,7 +126,7 @@ final class Session extends IWindowSession.Stub } catch (RuntimeException e) { // Log all 'real' exceptions thrown to the caller if (!(e instanceof SecurityException)) { - Slog.e(WindowManagerService.TAG, "Window Session Crash", e); + Slog.wtf(WindowManagerService.TAG, "Window Session Crash", e); } throw e; } diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index a888731..76ba0ce 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -813,7 +813,7 @@ public class WindowManagerService extends IWindowManager.Stub // The window manager only throws security exceptions, so let's // log all others. if (!(e instanceof SecurityException)) { - Log.wtf(TAG, "Window Manager Crash", e); + Slog.wtf(TAG, "Window Manager Crash", e); } throw e; } |