diff options
author | Dianne Hackborn <hackbod@google.com> | 2015-01-08 18:08:12 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-01-08 18:08:13 +0000 |
commit | a7881fd30b973f923c98d53bddf397d744b4229c (patch) | |
tree | 80e5a0c051b56ffb5a2d153a34829b59bb7ae4c7 | |
parent | d656955efdd2e148d9390125b899e8fe2b677abd (diff) | |
parent | ab2df067fc9757f19061b968c53953ca90a4c384 (diff) | |
download | frameworks_base-a7881fd30b973f923c98d53bddf397d744b4229c.zip frameworks_base-a7881fd30b973f923c98d53bddf397d744b4229c.tar.gz frameworks_base-a7881fd30b973f923c98d53bddf397d744b4229c.tar.bz2 |
Merge "Add new debug feature to track associations between processes. Also add some debugging for spurious service ANRs." into lmp-mr1-dev
-rwxr-xr-x | services/core/java/com/android/server/am/ActiveServices.java | 30 | ||||
-rwxr-xr-x | services/core/java/com/android/server/am/ActivityManagerService.java | 242 |
2 files changed, 256 insertions, 16 deletions
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index f02a815..d199c3f 100755 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -751,6 +751,9 @@ public final class ActiveServices { } } + mAm.startAssociationLocked(callerApp.uid, callerApp.processName, + s.appInfo.uid, s.name, s.processName); + AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp); ConnectionRecord c = new ConnectionRecord(b, activity, connection, flags, clientLabel, clientIntent); @@ -1445,10 +1448,10 @@ public final class ActiveServices { boolean created = false; try { - String nameTerm; - int lastPeriod = r.shortName.lastIndexOf('.'); - nameTerm = lastPeriod >= 0 ? r.shortName.substring(lastPeriod) : r.shortName; if (LOG_SERVICE_START_STOP) { + String nameTerm; + int lastPeriod = r.shortName.lastIndexOf('.'); + nameTerm = lastPeriod >= 0 ? r.shortName.substring(lastPeriod) : r.shortName; EventLogTags.writeAmCreateService( r.userId, System.identityHashCode(r), nameTerm, r.app.uid, r.app.pid); } @@ -1746,6 +1749,8 @@ public final class ActiveServices { } } + mAm.stopAssociationLocked(b.client.uid, b.client.processName, s.appInfo.uid, s.name); + if (b.connections.size() == 0) { b.intent.apps.remove(b.client); } @@ -2367,7 +2372,8 @@ public final class ActiveServices { if (proc.executingServices.size() == 0 || proc.thread == null) { return; } - long maxTime = SystemClock.uptimeMillis() - + final long now = SystemClock.uptimeMillis(); + final long maxTime = now - (proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT); ServiceRecord timeout = null; long nextTime = 0; @@ -2383,7 +2389,21 @@ public final class ActiveServices { } if (timeout != null && mAm.mLruProcesses.contains(proc)) { Slog.w(TAG, "Timeout executing service: " + timeout); - anrMessage = "Executing service " + timeout.shortName; + StringBuilder sb = new StringBuilder(); + sb.append("sxecuting service "); + sb.append(timeout.shortName); + sb.append(" (execStart="); + TimeUtils.formatDuration(now-timeout.executingStart, sb); + sb.append(", nesting="); + sb.append(timeout.executeNesting); + sb.append(", fg="); + sb.append(proc.execServicesFg); + sb.append(", create="); + TimeUtils.formatDuration(now-timeout.createTime, sb); + sb.append(", proc="); + sb.append(timeout.app != null ? timeout.app.toShortString() : "null"); + sb.append(")"); + anrMessage = sb.toString(); } else { Message msg = mAm.mHandler.obtainMessage( ActivityManagerService.SERVICE_TIMEOUT_MSG); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index ed16d2e..97b4353 100755 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -749,6 +749,38 @@ public final class ActivityManagerService extends ActivityManagerNative final ActiveServices mServices; + final static class Association { + final int mSourceUid; + final String mSourceProcess; + final int mTargetUid; + final ComponentName mTargetComponent; + final String mTargetProcess; + + int mCount; + long mTime; + + int mNesting; + long mStartTime; + + Association(int sourceUid, String sourceProcess, int targetUid, + ComponentName targetComponent, String targetProcess) { + mSourceUid = sourceUid; + mSourceProcess = sourceProcess; + mTargetUid = targetUid; + mTargetComponent = targetComponent; + mTargetProcess = targetProcess; + } + } + + /** + * When service association tracking is enabled, this is all of the associations we + * have seen. Mapping is target uid -> target component -> source uid -> source process name + * -> association data. + */ + final SparseArray<ArrayMap<ComponentName, SparseArray<ArrayMap<String, Association>>>> + mAssociations = new SparseArray<>(); + boolean mTrackingAssociations; + /** * Backup/restore process management */ @@ -2071,6 +2103,8 @@ public final class ActivityManagerService extends ActivityManagerNative GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version", ConfigurationInfo.GL_ES_VERSION_UNDEFINED); + mTrackingAssociations = "1".equals(SystemProperties.get("debug.track-associations")); + mConfiguration.setToDefaults(); mConfiguration.setLocale(Locale.getDefault()); @@ -9082,6 +9116,7 @@ public final class ActivityManagerService extends ActivityManagerNative } cpr.connections.add(conn); r.conProviders.add(conn); + startAssociationLocked(r.uid, r.processName, cpr.uid, cpr.name, cpr.info.processName); return conn; } cpr.addExternalProcessHandleLocked(externalProcessToken); @@ -9105,6 +9140,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (conn.stableCount == 0 && conn.unstableCount == 0) { cpr.connections.remove(conn); conn.client.conProviders.remove(conn); + stopAssociationLocked(conn.client.uid, conn.client.processName, cpr.uid, cpr.name); return true; } return false; @@ -12320,9 +12356,18 @@ public final class ActivityManagerService extends ActivityManagerNative dumpAll = true; } else if ("-c".equals(opt)) { dumpClient = true; + } else if ("-p".equals(opt)) { + if (opti < args.length) { + dumpPackage = args[opti]; + opti++; + } else { + pw.println("Error: -p option requires package argument"); + return; + } + dumpClient = true; } else if ("-h".equals(opt)) { pw.println("Activity manager dump options:"); - pw.println(" [-a] [-c] [-h] [cmd] ..."); + pw.println(" [-a] [-c] [-p package] [-h] [cmd] ..."); pw.println(" cmd may be one of:"); pw.println(" a[ctivities]: activity stack state"); pw.println(" r[recents]: recent activities state"); @@ -12333,17 +12378,21 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println(" prov[iders] [COMP_SPEC ...]: content provider state"); pw.println(" provider [COMP_SPEC]: provider client-side state"); pw.println(" s[ervices] [COMP_SPEC ...]: service state"); + pw.println(" as[sociations]: tracked app associations"); pw.println(" service [COMP_SPEC]: service client-side state"); pw.println(" package [PACKAGE_NAME]: all state related to given package"); pw.println(" all: dump all activities"); pw.println(" top: dump the top activity"); pw.println(" write: write all pending state to storage"); + pw.println(" track-associations: enable association tracking"); + pw.println(" untrack-associations: disable and clear association tracking"); pw.println(" cmd may also be a COMP_SPEC to dump activities."); pw.println(" COMP_SPEC may be a component name (com.foo/.myApp),"); pw.println(" a partial substring in a component name, a"); pw.println(" hex object identifier."); pw.println(" -a: include all available server state."); pw.println(" -c: include client state."); + pw.println(" -p: limit output to given package."); return; } else { pw.println("Unknown argument: " + opt + "; use -h for help"); @@ -12358,11 +12407,11 @@ public final class ActivityManagerService extends ActivityManagerNative opti++; if ("activities".equals(cmd) || "a".equals(cmd)) { synchronized (this) { - dumpActivitiesLocked(fd, pw, args, opti, true, dumpClient, null); + dumpActivitiesLocked(fd, pw, args, opti, true, dumpClient, dumpPackage); } } else if ("recents".equals(cmd) || "r".equals(cmd)) { synchronized (this) { - dumpRecentsLocked(fd, pw, args, opti, true, null); + dumpRecentsLocked(fd, pw, args, opti, true, dumpPackage); } } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) { String[] newArgs; @@ -12371,14 +12420,14 @@ public final class ActivityManagerService extends ActivityManagerNative name = null; newArgs = EMPTY_STRING_ARRAY; } else { - name = args[opti]; + dumpPackage = args[opti]; opti++; newArgs = new String[args.length - opti]; if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti); } synchronized (this) { - dumpBroadcastsLocked(fd, pw, args, opti, true, name); + dumpBroadcastsLocked(fd, pw, args, opti, true, dumpPackage); } } else if ("intents".equals(cmd) || "i".equals(cmd)) { String[] newArgs; @@ -12387,14 +12436,14 @@ public final class ActivityManagerService extends ActivityManagerNative name = null; newArgs = EMPTY_STRING_ARRAY; } else { - name = args[opti]; + dumpPackage = args[opti]; opti++; newArgs = new String[args.length - opti]; if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti); } synchronized (this) { - dumpPendingIntentsLocked(fd, pw, args, opti, true, name); + dumpPendingIntentsLocked(fd, pw, args, opti, true, dumpPackage); } } else if ("processes".equals(cmd) || "p".equals(cmd)) { String[] newArgs; @@ -12403,14 +12452,14 @@ public final class ActivityManagerService extends ActivityManagerNative name = null; newArgs = EMPTY_STRING_ARRAY; } else { - name = args[opti]; + dumpPackage = args[opti]; opti++; newArgs = new String[args.length - opti]; if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti); } synchronized (this) { - dumpProcessesLocked(fd, pw, args, opti, true, name); + dumpProcessesLocked(fd, pw, args, opti, true, dumpPackage); } } else if ("oom".equals(cmd) || "o".equals(cmd)) { synchronized (this) { @@ -12468,14 +12517,39 @@ public final class ActivityManagerService extends ActivityManagerNative opti = 0; more = true; } + } else if ("associations".equals(cmd) || "as".equals(cmd)) { + synchronized (this) { + dumpAssociationsLocked(fd, pw, args, opti, true, dumpClient, dumpPackage); + } } else if ("services".equals(cmd) || "s".equals(cmd)) { synchronized (this) { - mServices.dumpServicesLocked(fd, pw, args, opti, true, dumpClient, null); + mServices.dumpServicesLocked(fd, pw, args, opti, true, dumpClient, dumpPackage); } } else if ("write".equals(cmd)) { mTaskPersister.flush(); pw.println("All tasks persisted."); return; + } else if ("track-associations".equals(cmd)) { + synchronized (this) { + if (!mTrackingAssociations) { + mTrackingAssociations = true; + pw.println("Association tracking started."); + } else { + pw.println("Association tracking already enabled."); + } + } + return; + } else if ("untrack-associations".equals(cmd)) { + synchronized (this) { + if (mTrackingAssociations) { + mTrackingAssociations = false; + mAssociations.clear(); + pw.println("Association tracking stopped."); + } else { + pw.println("Association tracking not running."); + } + } + return; } else { // Dumping a single activity? if (!dumpActivity(fd, pw, cmd, args, opti, dumpAll)) { @@ -12517,6 +12591,13 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println("-------------------------------------------------------------------------------"); } dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage); + if (mAssociations.size() > 0) { + pw.println(); + if (dumpAll) { + pw.println("-------------------------------------------------------------------------------"); + } + dumpAssociationsLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage); + } pw.println(); if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); @@ -12591,6 +12672,78 @@ public final class ActivityManagerService extends ActivityManagerNative } } + void dumpAssociationsLocked(FileDescriptor fd, PrintWriter pw, String[] args, + int opti, boolean dumpAll, boolean dumpClient, String dumpPackage) { + pw.println("ACTIVITY MANAGER ASSOCIATIONS (dumpsys activity associations)"); + + int dumpUid = 0; + if (dumpPackage != null) { + IPackageManager pm = AppGlobals.getPackageManager(); + try { + dumpUid = pm.getPackageUid(dumpPackage, 0); + } catch (RemoteException e) { + } + } + + boolean printedAnything = false; + + final long now = SystemClock.uptimeMillis(); + + for (int i1=0, N1=mAssociations.size(); i1<N1; i1++) { + ArrayMap<ComponentName, SparseArray<ArrayMap<String, Association>>> targetComponents + = mAssociations.valueAt(i1); + for (int i2=0, N2=targetComponents.size(); i2<N2; i2++) { + SparseArray<ArrayMap<String, Association>> sourceUids + = targetComponents.valueAt(i2); + for (int i3=0, N3=sourceUids.size(); i3<N3; i3++) { + ArrayMap<String, Association> sourceProcesses = sourceUids.valueAt(i3); + for (int i4=0, N4=sourceProcesses.size(); i4<N4; i4++) { + Association ass = sourceProcesses.valueAt(i4); + if (dumpPackage != null) { + if (!ass.mTargetComponent.getPackageName().equals(dumpPackage) + && UserHandle.getAppId(ass.mSourceUid) != dumpUid) { + continue; + } + } + printedAnything = true; + pw.print(" "); + pw.print(ass.mTargetProcess); + pw.print("/"); + UserHandle.formatUid(pw, ass.mTargetUid); + pw.print(" <- "); + pw.print(ass.mSourceProcess); + pw.print("/"); + UserHandle.formatUid(pw, ass.mSourceUid); + pw.println(); + pw.print(" via "); + pw.print(ass.mTargetComponent.flattenToShortString()); + pw.println(); + pw.print(" "); + long dur = ass.mTime; + if (ass.mNesting > 0) { + dur += now - ass.mStartTime; + } + TimeUtils.formatDuration(dur, pw); + pw.print(" ("); + pw.print(ass.mCount); + pw.println(" times)"); + if (ass.mNesting > 0) { + pw.print(" "); + pw.print(" Currently active: "); + TimeUtils.formatDuration(now - ass.mStartTime, pw); + pw.println(); + } + } + } + } + + } + + if (!printedAnything) { + pw.println(" (nothing)"); + } + } + void dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args, int opti, boolean dumpAll, String dumpPackage) { boolean needSep = false; @@ -14687,7 +14840,9 @@ public final class ActivityManagerService extends ActivityManagerNative // In the protocol here, we don't expect the client to correctly // clean up this connection, we'll just remove it. cpr.connections.remove(i); - conn.client.conProviders.remove(conn); + if (conn.client.conProviders.remove(conn)) { + stopAssociationLocked(capp.uid, capp.processName, cpr.uid, cpr.name); + } } } @@ -14773,6 +14928,8 @@ public final class ActivityManagerService extends ActivityManagerNative for (int i=0; i<app.conProviders.size(); i++) { ContentProviderConnection conn = app.conProviders.get(i); conn.provider.connections.remove(conn); + stopAssociationLocked(app.uid, app.processName, conn.provider.uid, + conn.provider.name); } app.conProviders.clear(); } @@ -16715,6 +16872,69 @@ public final class ActivityManagerService extends ActivityManagerNative return null; } + Association startAssociationLocked(int sourceUid, String sourceProcess, int targetUid, + ComponentName targetComponent, String targetProcess) { + if (!mTrackingAssociations) { + return null; + } + ArrayMap<ComponentName, SparseArray<ArrayMap<String, Association>>> components + = mAssociations.get(targetUid); + if (components == null) { + components = new ArrayMap<>(); + mAssociations.put(targetUid, components); + } + SparseArray<ArrayMap<String, Association>> sourceUids = components.get(targetComponent); + if (sourceUids == null) { + sourceUids = new SparseArray<>(); + components.put(targetComponent, sourceUids); + } + ArrayMap<String, Association> sourceProcesses = sourceUids.get(sourceUid); + if (sourceProcesses == null) { + sourceProcesses = new ArrayMap<>(); + sourceUids.put(sourceUid, sourceProcesses); + } + Association ass = sourceProcesses.get(sourceProcess); + if (ass == null) { + ass = new Association(sourceUid, sourceProcess, targetUid, targetComponent, + targetProcess); + sourceProcesses.put(sourceProcess, ass); + } + ass.mCount++; + ass.mNesting++; + if (ass.mNesting == 1) { + ass.mStartTime = SystemClock.uptimeMillis(); + } + return ass; + } + + void stopAssociationLocked(int sourceUid, String sourceProcess, int targetUid, + ComponentName targetComponent) { + if (!mTrackingAssociations) { + return; + } + ArrayMap<ComponentName, SparseArray<ArrayMap<String, Association>>> components + = mAssociations.get(targetUid); + if (components == null) { + return; + } + SparseArray<ArrayMap<String, Association>> sourceUids = components.get(targetComponent); + if (sourceUids == null) { + return; + } + ArrayMap<String, Association> sourceProcesses = sourceUids.get(sourceUid); + if (sourceProcesses == null) { + return; + } + Association ass = sourceProcesses.get(sourceProcess); + if (ass == null || ass.mNesting <= 0) { + return; + } + ass.mNesting--; + if (ass.mNesting == 0) { + ass.mTime += SystemClock.uptimeMillis() - ass.mStartTime; + } + } + private final int computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP, boolean doingAll, long now) { if (mAdjSeq == app.adjSeq) { |