From 164371fb759bad6854570af0fca60d9a01e17235 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Tue, 1 Oct 2013 19:10:13 -0700 Subject: Fix issue #11005453: [SUW] G+ profile creation for new user broken The main problem here was a mistake when turning a single process structure to a multi-package-process structure with a common process. When we cloned the original process state, if there were any services already created for the process for that package, they would be left with their process pointer still referencing the original now common process instead of the package-specific process, allowing the active counts to get bad. Now we switch any of those processes over to the new package-specific process. There was also another smaller issue with how ServiceRecord is associated with a ServiceState -- we could be waiting for an old ServiceRecord to be destroyed while at the same time creating a new ServiceRecord for that same service class. These would share the same ServiceState, so when the old record finally finished destroying itself it would trample over whatever the new service is doing. This is fixed by changing the model to instead of using an "active" reference count, we have an object identifying the current owner of the ServiceState. Then when the old ServiceRecord is cleaning up, we know if it is still the owner at that point. Also some other small things along the way -- new Log.wtfStack() method that is convenient, new suite of Slog.wtf methods, fixed some services to use Slog.wtf when catching exceptions being returned to the caller so that we actually know about them. Change-Id: I75674ce38050b6423fd3c6f43d1be172b470741f --- core/java/android/util/Log.java | 25 ++- core/java/android/util/Slog.java | 16 ++ .../com/android/internal/app/ProcessStats.java | 250 +++++++++++++++------ .../java/com/android/server/ClipboardService.java | 4 +- .../android/server/InputMethodManagerService.java | 2 +- .../server/accounts/AccountManagerService.java | 16 ++ .../java/com/android/server/am/ActiveServices.java | 93 ++++---- .../android/server/am/ActivityManagerService.java | 2 +- .../com/android/server/am/ProcessStatsService.java | 27 ++- .../java/com/android/server/am/ServiceRecord.java | 14 +- .../com/android/server/content/ContentService.java | 2 +- .../android/server/pm/PackageManagerService.java | 2 +- services/java/com/android/server/wm/Session.java | 2 +- .../android/server/wm/WindowManagerService.java | 2 +- 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 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> pkgMap = mPackages.getMap(); @@ -1746,6 +1770,11 @@ public final class ProcessStats implements Parcelable { if (!dumpSummary || dumpAll) { for (int iproc=0; iproc procs = new ArrayList(); for (int iproc=0; iproc 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 collectProcessesLocked(int[] screenStates, int[] memStates, - int[] procStates, int sortProcStates[], long now, String reqPackage) { + int[] procStates, int sortProcStates[], long now, String reqPackage, + boolean activeOnly) { ArraySet foundProcs = new ArraySet(); ArrayMap> pkgMap = mPackages.getMap(); for (int ip=0; ip outProcs = new ArrayList(foundProcs.size()); for (int i=0; i 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= 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(); /** - * List of services that are in the process of being stopped. + * List of services that are in the process of being destroyed. */ - final ArrayList mStoppingServices + final ArrayList mDestroyingServices = new ArrayList(); static final class DelayingProcess extends ArrayList { @@ -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 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] []"); 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; } -- cgit v1.1