diff options
author | Dianne Hackborn <hackbod@google.com> | 2011-04-07 18:46:54 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2011-04-07 18:46:54 -0700 |
commit | bdf7b013f81b0b56a18cc9dd2fb987b56d595650 (patch) | |
tree | 439b9fc97a0cdc311d9c080327752943cf1f79d3 | |
parent | 280dda75f3a974a7f519c8c99ea1c56100f01677 (diff) | |
parent | e17aeb31030cfeed339a39a107912ad5e9178390 (diff) | |
download | frameworks_base-bdf7b013f81b0b56a18cc9dd2fb987b56d595650.zip frameworks_base-bdf7b013f81b0b56a18cc9dd2fb987b56d595650.tar.gz frameworks_base-bdf7b013f81b0b56a18cc9dd2fb987b56d595650.tar.bz2 |
Merge "Improve activity manager debug dumps."
-rw-r--r-- | api/current.xml | 49 | ||||
-rw-r--r-- | cmds/dumpstate/dumpstate.c | 11 | ||||
-rw-r--r-- | core/java/android/app/ActivityThread.java | 85 | ||||
-rw-r--r-- | core/java/android/app/ApplicationThreadNative.java | 4 | ||||
-rw-r--r-- | core/java/android/content/res/Configuration.java | 127 | ||||
-rw-r--r-- | core/java/android/os/Binder.java | 33 | ||||
-rw-r--r-- | core/java/android/os/IBinder.java | 10 | ||||
-rw-r--r-- | core/java/android/os/Parcel.java | 2 | ||||
-rw-r--r-- | core/java/android/os/ParcelFileDescriptor.java | 11 | ||||
-rw-r--r-- | core/jni/android_util_Binder.cpp | 35 | ||||
-rw-r--r-- | services/java/com/android/server/am/ActivityManagerService.java | 727 | ||||
-rw-r--r-- | services/java/com/android/server/am/ActivityRecord.java | 2 | ||||
-rw-r--r-- | services/java/com/android/server/am/ContentProviderRecord.java | 2 | ||||
-rw-r--r-- | services/java/com/android/server/am/ServiceRecord.java | 2 | ||||
-rw-r--r-- | services/java/com/android/server/am/TransferPipe.java | 242 |
15 files changed, 974 insertions, 368 deletions
diff --git a/api/current.xml b/api/current.xml index 2b10d42..23c7af8 100644 --- a/api/current.xml +++ b/api/current.xml @@ -143541,6 +143541,21 @@ <parameter name="args" type="java.lang.String[]"> </parameter> </method> +<method name="dumpAsync" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="fd" type="java.io.FileDescriptor"> +</parameter> +<parameter name="args" type="java.lang.String[]"> +</parameter> +</method> <method name="flushPendingCommands" return="void" abstract="false" @@ -148013,6 +148028,23 @@ <exception name="RemoteException" type="android.os.RemoteException"> </exception> </method> +<method name="dumpAsync" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="fd" type="java.io.FileDescriptor"> +</parameter> +<parameter name="args" type="java.lang.String[]"> +</parameter> +<exception name="RemoteException" type="android.os.RemoteException"> +</exception> +</method> <method name="getInterfaceDescriptor" return="java.lang.String" abstract="true" @@ -150367,6 +150399,21 @@ visibility="public" > </method> +<method name="dup" + return="android.os.ParcelFileDescriptor" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="orig" type="java.io.FileDescriptor"> +</parameter> +<exception name="IOException" type="java.io.IOException"> +</exception> +</method> <method name="fromSocket" return="android.os.ParcelFileDescriptor" abstract="false" @@ -267896,7 +267943,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="t" type="T"> +<parameter name="arg0" type="T"> </parameter> </method> </interface> diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c index 533a60a..df7037c 100644 --- a/cmds/dumpstate/dumpstate.c +++ b/cmds/dumpstate/dumpstate.c @@ -185,11 +185,16 @@ static void dumpstate() { run_command("DUMPSYS", 60, "dumpsys", NULL); printf("========================================================\n"); - printf("== Application Services\n"); + printf("== Running Application Activities\n"); printf("========================================================\n"); - /* Instead of a 60s timeout, we should give each service a 5 second timeout */ - run_command("APP SERVICES", 60, "dumpsys", "activity", "service", NULL); + run_command("APP ACTIVITIES", 30, "dumpsys", "activity", "all", NULL); + + printf("========================================================\n"); + printf("== Running Application Services\n"); + printf("========================================================\n"); + + run_command("APP SERVICES", 30, "dumpsys", "activity", "service", "all", NULL); } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 751726a..5e4e36e 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -363,11 +363,10 @@ public final class ActivityThread { } private static final class DumpComponentInfo { - FileDescriptor fd; + ParcelFileDescriptor fd; IBinder token; String prefix; String[] args; - boolean dumped; } private static final class ResultData { @@ -621,20 +620,13 @@ public final class ActivityThread { public void dumpService(FileDescriptor fd, IBinder servicetoken, String[] args) { DumpComponentInfo data = new DumpComponentInfo(); - data.fd = fd; - data.token = servicetoken; - data.args = args; - data.dumped = false; - queueOrSendMessage(H.DUMP_SERVICE, data); - synchronized (data) { - while (!data.dumped) { - try { - data.wait(); - } catch (InterruptedException e) { - // no need to do anything here, we will keep waiting until - // dumped is set - } - } + try { + data.fd = ParcelFileDescriptor.dup(fd); + data.token = servicetoken; + data.args = args; + queueOrSendMessage(H.DUMP_SERVICE, data); + } catch (IOException e) { + Slog.w(TAG, "dumpService failed", e); } } @@ -696,21 +688,14 @@ public final class ActivityThread { public void dumpActivity(FileDescriptor fd, IBinder activitytoken, String prefix, String[] args) { DumpComponentInfo data = new DumpComponentInfo(); - data.fd = fd; - data.token = activitytoken; - data.prefix = prefix; - data.args = args; - data.dumped = false; - queueOrSendMessage(H.DUMP_ACTIVITY, data); - synchronized (data) { - while (!data.dumped) { - try { - data.wait(); - } catch (InterruptedException e) { - // no need to do anything here, we will keep waiting until - // dumped is set - } - } + try { + data.fd = ParcelFileDescriptor.dup(fd); + data.token = activitytoken; + data.prefix = prefix; + data.args = args; + queueOrSendMessage(H.DUMP_ACTIVITY, data); + } catch (IOException e) { + Slog.w(TAG, "dumpActivity failed", e); } } @@ -2113,33 +2098,27 @@ public final class ActivityThread { } private void handleDumpService(DumpComponentInfo info) { - try { - Service s = mServices.get(info.token); - if (s != null) { - PrintWriter pw = new PrintWriter(new FileOutputStream(info.fd)); - s.dump(info.fd, pw, info.args); - pw.close(); - } - } finally { - synchronized (info) { - info.dumped = true; - info.notifyAll(); + Service s = mServices.get(info.token); + if (s != null) { + PrintWriter pw = new PrintWriter(new FileOutputStream(info.fd.getFileDescriptor())); + s.dump(info.fd.getFileDescriptor(), pw, info.args); + pw.flush(); + try { + info.fd.close(); + } catch (IOException e) { } } } private void handleDumpActivity(DumpComponentInfo info) { - try { - ActivityClientRecord r = mActivities.get(info.token); - if (r != null && r.activity != null) { - PrintWriter pw = new PrintWriter(new FileOutputStream(info.fd)); - r.activity.dump(info.prefix, info.fd, pw, info.args); - pw.close(); - } - } finally { - synchronized (info) { - info.dumped = true; - info.notifyAll(); + ActivityClientRecord r = mActivities.get(info.token); + if (r != null && r.activity != null) { + PrintWriter pw = new PrintWriter(new FileOutputStream(info.fd.getFileDescriptor())); + r.activity.dump(info.prefix, info.fd.getFileDescriptor(), pw, info.args); + pw.flush(); + try { + info.fd.close(); + } catch (IOException e) { } } } diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index aa26b04..a82234e 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -822,7 +822,7 @@ class ApplicationThreadProxy implements IApplicationThread { data.writeFileDescriptor(fd); data.writeStrongBinder(token); data.writeStringArray(args); - mRemote.transact(DUMP_SERVICE_TRANSACTION, data, null, 0); + mRemote.transact(DUMP_SERVICE_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); } @@ -944,7 +944,7 @@ class ApplicationThreadProxy implements IApplicationThread { data.writeStrongBinder(token); data.writeString(prefix); data.writeStringArray(args); - mRemote.transact(DUMP_ACTIVITY_TRANSACTION, data, null, 0); + mRemote.transact(DUMP_ACTIVITY_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); } diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index 28ba4e7..b9dfd72 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -299,45 +299,106 @@ public final class Configuration implements Parcelable, Comparable<Configuration public String toString() { StringBuilder sb = new StringBuilder(128); - sb.append("{ scale="); + sb.append("{ fnt="); sb.append(fontScale); sb.append(" imsi="); sb.append(mcc); sb.append("/"); sb.append(mnc); - sb.append(" loc="); - sb.append(locale); - sb.append(" touch="); - sb.append(touchscreen); - sb.append(" keys="); - sb.append(keyboard); - sb.append("/"); - sb.append(keyboardHidden); - sb.append("/"); - sb.append(hardKeyboardHidden); - sb.append(" nav="); - sb.append(navigation); - sb.append("/"); - sb.append(navigationHidden); - sb.append(" orien="); - switch(orientation) { - case ORIENTATION_LANDSCAPE: - sb.append("L"); break; - case ORIENTATION_PORTRAIT: - sb.append("P"); break; - default: - sb.append(orientation); - } - sb.append(" layout=0x"); - sb.append(java.lang.Integer.toHexString(screenLayout)); - sb.append(" uiMode=0x"); - sb.append(java.lang.Integer.toHexString(uiMode)); - sb.append(" wdp="); - sb.append(screenWidthDp); - sb.append(" hdp="); - sb.append(screenHeightDp); + if (locale != null) { + sb.append(" "); + sb.append(locale); + } else { + sb.append(" (no locale)"); + } + switch (touchscreen) { + case TOUCHSCREEN_UNDEFINED: sb.append(" ?touch"); break; + case TOUCHSCREEN_NOTOUCH: sb.append(" -touch"); break; + case TOUCHSCREEN_STYLUS: sb.append(" stylus"); break; + case TOUCHSCREEN_FINGER: sb.append(" finger"); break; + default: sb.append(" touch="); sb.append(touchscreen); break; + } + switch (keyboard) { + case KEYBOARD_UNDEFINED: sb.append(" ?keyb"); break; + case KEYBOARD_NOKEYS: sb.append(" -keyb"); break; + case KEYBOARD_QWERTY: sb.append(" qwerty"); break; + case KEYBOARD_12KEY: sb.append(" 12key"); break; + default: sb.append(" keys="); sb.append(keyboard); break; + } + switch (keyboardHidden) { + case KEYBOARDHIDDEN_UNDEFINED: sb.append("/?"); break; + case KEYBOARDHIDDEN_NO: sb.append("/v"); break; + case KEYBOARDHIDDEN_YES: sb.append("/h"); break; + case KEYBOARDHIDDEN_SOFT: sb.append("/s"); break; + default: sb.append("/"); sb.append(keyboardHidden); break; + } + switch (hardKeyboardHidden) { + case HARDKEYBOARDHIDDEN_UNDEFINED: sb.append("/?"); break; + case HARDKEYBOARDHIDDEN_NO: sb.append("/v"); break; + case HARDKEYBOARDHIDDEN_YES: sb.append("/h"); break; + default: sb.append("/"); sb.append(hardKeyboardHidden); break; + } + switch (navigation) { + case NAVIGATION_UNDEFINED: sb.append(" ?nav"); break; + case NAVIGATION_NONAV: sb.append(" -nav"); break; + case NAVIGATION_DPAD: sb.append(" dpad"); break; + case NAVIGATION_TRACKBALL: sb.append(" tball"); break; + case NAVIGATION_WHEEL: sb.append(" wheel"); break; + default: sb.append(" nav="); sb.append(navigation); break; + } + switch (navigationHidden) { + case NAVIGATIONHIDDEN_UNDEFINED: sb.append("/?"); break; + case NAVIGATIONHIDDEN_NO: sb.append("/v"); break; + case NAVIGATIONHIDDEN_YES: sb.append("/h"); break; + default: sb.append("/"); sb.append(navigationHidden); break; + } + switch (orientation) { + case ORIENTATION_UNDEFINED: sb.append(" ?orien"); break; + case ORIENTATION_LANDSCAPE: sb.append(" land"); break; + case ORIENTATION_PORTRAIT: sb.append(" port"); break; + default: sb.append(" orien="); sb.append(orientation); break; + } + switch ((screenLayout&SCREENLAYOUT_SIZE_MASK)) { + case SCREENLAYOUT_SIZE_UNDEFINED: sb.append(" ?lsize"); break; + case SCREENLAYOUT_SIZE_SMALL: sb.append(" smll"); break; + case SCREENLAYOUT_SIZE_NORMAL: sb.append(" nrml"); break; + case SCREENLAYOUT_SIZE_LARGE: sb.append(" lrg"); break; + case SCREENLAYOUT_SIZE_XLARGE: sb.append(" xlrg"); break; + default: sb.append(" layoutSize="); + sb.append(screenLayout&SCREENLAYOUT_SIZE_MASK); break; + } + switch ((screenLayout&SCREENLAYOUT_LONG_MASK)) { + case SCREENLAYOUT_LONG_UNDEFINED: sb.append(" ?long"); break; + case SCREENLAYOUT_LONG_NO: /* not-long is not interesting to print */ break; + case SCREENLAYOUT_LONG_YES: sb.append(" long"); break; + default: sb.append(" layoutLong="); + sb.append(screenLayout&SCREENLAYOUT_LONG_MASK); break; + } + switch ((uiMode&UI_MODE_TYPE_MASK)) { + case UI_MODE_TYPE_UNDEFINED: sb.append(" ?uimode"); break; + case UI_MODE_TYPE_NORMAL: /* normal is not interesting to print */ break; + case UI_MODE_TYPE_DESK: sb.append(" desk"); break; + case UI_MODE_TYPE_CAR: sb.append(" car"); break; + default: sb.append(" uimode="); sb.append(uiMode&UI_MODE_TYPE_MASK); break; + } + switch ((uiMode&UI_MODE_NIGHT_MASK)) { + case UI_MODE_NIGHT_UNDEFINED: sb.append(" ?night"); break; + case UI_MODE_NIGHT_NO: /* not-night is not interesting to print */ break; + case UI_MODE_NIGHT_YES: sb.append(" night"); break; + default: sb.append(" night="); sb.append(uiMode&UI_MODE_NIGHT_MASK); break; + } + if (screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) { + sb.append(" w"); sb.append(screenWidthDp); sb.append("dp"); + } else { + sb.append("?wdp"); + } + if (screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) { + sb.append(" h"); sb.append(screenHeightDp); sb.append("dp"); + } else { + sb.append("?hdp"); + } if (seq != 0) { - sb.append(" seq="); + sb.append(" s."); sb.append(seq); } sb.append('}'); diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index 7dc36f9..ae1e1c2 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -256,6 +256,25 @@ public class Binder implements IBinder { } /** + * Like {@link #dump(FileDescriptor, String[])}, but ensures the target + * executes asynchronously. + */ + public void dumpAsync(final FileDescriptor fd, final String[] args) { + final FileOutputStream fout = new FileOutputStream(fd); + final PrintWriter pw = new PrintWriter(fout); + Thread thr = new Thread("Binder.dumpAsync") { + public void run() { + try { + dump(fd, pw, args); + } finally { + pw.flush(); + } + } + }; + thr.start(); + } + + /** * Print the object's state into the given stream. * * @param fd The raw file descriptor that the dump is being sent to. @@ -364,6 +383,20 @@ final class BinderProxy implements IBinder { } } + public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeFileDescriptor(fd); + data.writeStringArray(args); + try { + transact(DUMP_TRANSACTION, data, reply, FLAG_ONEWAY); + reply.readException(); + } finally { + data.recycle(); + reply.recycle(); + } + } + BinderProxy() { mSelf = new WeakReference(this); } diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java index 8ae8008..8876354 100644 --- a/core/java/android/os/IBinder.java +++ b/core/java/android/os/IBinder.java @@ -157,6 +157,16 @@ public interface IBinder { public void dump(FileDescriptor fd, String[] args) throws RemoteException; /** + * Like {@link #dump(FileDescriptor, String[])} but always executes + * asynchronously. If the object is local, a new thread is created + * to perform the dump. + * + * @param fd The raw file descriptor that the dump is being sent to. + * @param args additional arguments to the dump request. + */ + public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException; + + /** * Perform a generic operation with the object. * * @param code The action to perform. This should diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index eca3484..6b35215 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -1383,6 +1383,8 @@ public final class Parcel { private native FileDescriptor internalReadFileDescriptor(); /*package*/ static native FileDescriptor openFileDescriptor(String file, int mode) throws FileNotFoundException; + /*package*/ static native FileDescriptor dupFileDescriptor(FileDescriptor orig) + throws IOException; /*package*/ static native void closeFileDescriptor(FileDescriptor desc) throws IOException; /*package*/ static native void clearFileDescriptor(FileDescriptor desc); diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java index 5bd129f..aa959b4 100644 --- a/core/java/android/os/ParcelFileDescriptor.java +++ b/core/java/android/os/ParcelFileDescriptor.java @@ -117,6 +117,17 @@ public class ParcelFileDescriptor implements Parcelable { } /** + * Create a new ParcelFileDescriptor that is a dup of an existing + * FileDescriptor. This obeys standard POSIX semantics, where the + * new file descriptor shared state such as file position with the + * original file descriptor. + */ + public static ParcelFileDescriptor dup(FileDescriptor orig) throws IOException { + FileDescriptor fd = Parcel.dupFileDescriptor(orig); + return fd != null ? new ParcelFileDescriptor(fd) : null; + } + + /** * Create a new ParcelFileDescriptor from the specified Socket. * * @param socket The Socket whose FileDescriptor is used to create diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index 09a5fd4..eb1c437 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -1509,7 +1509,31 @@ static jobject android_os_Parcel_openFileDescriptor(JNIEnv* env, jobject clazz, int fd = open(name8.string(), flags, realMode); if (fd < 0) { - jniThrowException(env, "java/io/FileNotFoundException", NULL); + jniThrowException(env, "java/io/FileNotFoundException", strerror(errno)); + return NULL; + } + jobject object = newFileDescriptor(env, fd); + if (object == NULL) { + close(fd); + } + return object; +} + +static jobject android_os_Parcel_dupFileDescriptor(JNIEnv* env, jobject clazz, jobject orig) +{ + if (orig == NULL) { + jniThrowException(env, "java/lang/NullPointerException", NULL); + return NULL; + } + int origfd = env->GetIntField(orig, gFileDescriptorOffsets.mDescriptor); + if (origfd < 0) { + jniThrowException(env, "java/lang/IllegalArgumentException", "bad FileDescriptor"); + return NULL; + } + + int fd = dup(origfd); + if (fd < 0) { + jniThrowException(env, "java/io/IOException", strerror(errno)); return NULL; } jobject object = newFileDescriptor(env, fd); @@ -1521,6 +1545,10 @@ static jobject android_os_Parcel_openFileDescriptor(JNIEnv* env, jobject clazz, static void android_os_Parcel_closeFileDescriptor(JNIEnv* env, jobject clazz, jobject object) { + if (object == NULL) { + jniThrowException(env, "java/lang/NullPointerException", NULL); + return; + } int fd = env->GetIntField(object, gFileDescriptorOffsets.mDescriptor); if (fd >= 0) { env->SetIntField(object, gFileDescriptorOffsets.mDescriptor, -1); @@ -1531,6 +1559,10 @@ static void android_os_Parcel_closeFileDescriptor(JNIEnv* env, jobject clazz, jo static void android_os_Parcel_clearFileDescriptor(JNIEnv* env, jobject clazz, jobject object) { + if (object == NULL) { + jniThrowException(env, "java/lang/NullPointerException", NULL); + return; + } int fd = env->GetIntField(object, gFileDescriptorOffsets.mDescriptor); if (fd >= 0) { env->SetIntField(object, gFileDescriptorOffsets.mDescriptor, -1); @@ -1735,6 +1767,7 @@ static const JNINativeMethod gParcelMethods[] = { {"readStrongBinder", "()Landroid/os/IBinder;", (void*)android_os_Parcel_readStrongBinder}, {"internalReadFileDescriptor", "()Ljava/io/FileDescriptor;", (void*)android_os_Parcel_readFileDescriptor}, {"openFileDescriptor", "(Ljava/lang/String;I)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_openFileDescriptor}, + {"dupFileDescriptor", "(Ljava/io/FileDescriptor;)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_dupFileDescriptor}, {"closeFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_closeFileDescriptor}, {"clearFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_clearFileDescriptor}, {"freeBuffer", "()V", (void*)android_os_Parcel_freeBuffer}, diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 5f471fe..2e72068 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -89,6 +89,7 @@ import android.os.FileObserver; import android.os.FileUtils; import android.os.Handler; import android.os.IBinder; +import android.os.IInterface; import android.os.IPermissionController; import android.os.Looper; import android.os.Message; @@ -1398,35 +1399,7 @@ public final class ActivityManagerService extends ActivityManagerNative @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - ActivityManagerService service = mActivityManagerService; - ArrayList<ProcessRecord> procs; - synchronized (mActivityManagerService) { - if (args != null && args.length > 0 - && args[0].charAt(0) != '-') { - procs = new ArrayList<ProcessRecord>(); - int pid = -1; - try { - pid = Integer.parseInt(args[0]); - } catch (NumberFormatException e) { - - } - for (int i=service.mLruProcesses.size()-1; i>=0; i--) { - ProcessRecord proc = service.mLruProcesses.get(i); - if (proc.pid == pid) { - procs.add(proc); - } else if (proc.processName.equals(args[0])) { - procs.add(proc); - } - } - if (procs.size() <= 0) { - pw.println("No process found for: " + args[0]); - return; - } - } else { - procs = new ArrayList<ProcessRecord>(service.mLruProcesses); - } - } - dumpApplicationMemoryUsage(fd, pw, procs, " ", args); + mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args); } } @@ -1438,35 +1411,7 @@ public final class ActivityManagerService extends ActivityManagerNative @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - ActivityManagerService service = mActivityManagerService; - ArrayList<ProcessRecord> procs; - synchronized (mActivityManagerService) { - if (args != null && args.length > 0 - && args[0].charAt(0) != '-') { - procs = new ArrayList<ProcessRecord>(); - int pid = -1; - try { - pid = Integer.parseInt(args[0]); - } catch (NumberFormatException e) { - - } - for (int i=service.mLruProcesses.size()-1; i>=0; i--) { - ProcessRecord proc = service.mLruProcesses.get(i); - if (proc.pid == pid) { - procs.add(proc); - } else if (proc.processName.equals(args[0])) { - procs.add(proc); - } - } - if (procs.size() <= 0) { - pw.println("No process found for: " + args[0]); - return; - } - } else { - procs = new ArrayList<ProcessRecord>(service.mLruProcesses); - } - } - dumpGraphicsHardwareUsage(fd, pw, procs); + mActivityManagerService.dumpGraphicsHardwareUsage(fd, pw, args); } } @@ -7496,6 +7441,7 @@ public final class ActivityManagerService extends ActivityManagerNative } boolean dumpAll = false; + boolean dumpClient = false; int opti = 0; while (opti < args.length) { @@ -7506,9 +7452,11 @@ public final class ActivityManagerService extends ActivityManagerNative opti++; if ("-a".equals(opt)) { dumpAll = true; + } else if ("-c".equals(opt)) { + dumpClient = true; } else if ("-h".equals(opt)) { pw.println("Activity manager dump options:"); - pw.println(" [-a] [-h] [cmd] ..."); + pw.println(" [-a] [-c] [-h] [cmd] ..."); pw.println(" cmd may be one of:"); pw.println(" a[ctivities]: activity stack state"); pw.println(" b[roadcasts]: broadcast state"); @@ -7517,10 +7465,14 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println(" o[om]: out of memory management"); pw.println(" prov[iders]: content provider state"); pw.println(" s[ervices]: service state"); - pw.println(" service [name]: service client-side state"); - pw.println(" cmd may also be a component name (com.foo/.myApp),"); - pw.println(" a partial substring in a component name, or an"); - pw.println(" ActivityRecord hex object identifier."); + pw.println(" service [COMP_SPEC]: service client-side state"); + pw.println(" cmd may also be a COMP_SPEC to dump activities."); + pw.println(" COMP_SPEC may also be a component name (com.foo/.myApp),"); + pw.println(" a partial substring in a component name, an"); + pw.println(" ActivityRecord hex object identifier, or"); + pw.println(" \"all\" for all objects"); + pw.println(" -a: include all available server state."); + pw.println(" -c: include client state."); return; } else { pw.println("Unknown argument: " + opt + "; use -h for help"); @@ -7533,7 +7485,7 @@ public final class ActivityManagerService extends ActivityManagerNative opti++; if ("activities".equals(cmd) || "a".equals(cmd)) { synchronized (this) { - dumpActivitiesLocked(fd, pw, args, opti, true, true); + dumpActivitiesLocked(fd, pw, args, opti, true, dumpClient); } return; } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) { @@ -7562,20 +7514,33 @@ public final class ActivityManagerService extends ActivityManagerNative } return; } else if ("service".equals(cmd)) { - dumpService(fd, pw, args, opti); + String[] newArgs; + String name; + if (opti >= args.length) { + name = null; + newArgs = EMPTY_STRING_ARRAY; + } else { + name = args[opti]; + opti++; + newArgs = new String[args.length - opti]; + if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti); + } + if (!dumpService(fd, pw, name, newArgs, 0, dumpAll)) { + pw.println("No services match: " + name); + pw.println("Use -h for help."); + } return; } else if ("services".equals(cmd) || "s".equals(cmd)) { synchronized (this) { - dumpServicesLocked(fd, pw, args, opti, true); + dumpServicesLocked(fd, pw, args, opti, true, dumpClient); } return; } else { // Dumping a single activity? - if (dumpActivity(fd, pw, cmd, args, opti, dumpAll)) { - return; + if (!dumpActivity(fd, pw, cmd, args, opti, dumpAll)) { + pw.println("Bad activity command, or no activities match: " + cmd); + pw.println("Use -h for help."); } - pw.println("Bad activity command, or no activities match: " + cmd); - pw.println("Use -h for help."); return; } } @@ -7583,16 +7548,12 @@ public final class ActivityManagerService extends ActivityManagerNative // No piece of data specified, dump everything. synchronized (this) { boolean needSep; - if (dumpAll) { - pw.println("Providers in Current Activity Manager State:"); - } - needSep = dumpProvidersLocked(fd, pw, args, opti, dumpAll); + needSep = dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll); if (needSep) { pw.println(" "); } if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); - pw.println("Broadcasts in Current Activity Manager State:"); } needSep = dumpBroadcastsLocked(fd, pw, args, opti, dumpAll); if (needSep) { @@ -7600,88 +7561,95 @@ public final class ActivityManagerService extends ActivityManagerNative } if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); - pw.println("Services in Current Activity Manager State:"); } - needSep = dumpServicesLocked(fd, pw, args, opti, dumpAll); + needSep = dumpProvidersLocked(fd, pw, args, opti, dumpAll); if (needSep) { pw.println(" "); } if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); - pw.println("PendingIntents in Current Activity Manager State:"); } - needSep = dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll); + needSep = dumpServicesLocked(fd, pw, args, opti, dumpAll, dumpClient); if (needSep) { pw.println(" "); } if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); - pw.println("Activities in Current Activity Manager State:"); } - needSep = dumpActivitiesLocked(fd, pw, args, opti, dumpAll, !dumpAll); + needSep = dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient); if (needSep) { pw.println(" "); } if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); - pw.println("Processes in Current Activity Manager State:"); } dumpProcessesLocked(fd, pw, args, opti, dumpAll); } } boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args, - int opti, boolean dumpAll, boolean needHeader) { - if (needHeader) { - pw.println(" Activity stack:"); - } - dumpHistoryList(pw, mMainStack.mHistory, " ", "Hist", true); + int opti, boolean dumpAll, boolean dumpClient) { + pw.println("ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)"); + pw.println(" Main stack:"); + dumpHistoryList(fd, pw, mMainStack.mHistory, " ", "Hist", true, !dumpAll, dumpClient); pw.println(" "); pw.println(" Running activities (most recent first):"); - dumpHistoryList(pw, mMainStack.mLRUActivities, " ", "Run", false); + dumpHistoryList(fd, pw, mMainStack.mLRUActivities, " ", "Run", false, !dumpAll, false); if (mMainStack.mWaitingVisibleActivities.size() > 0) { pw.println(" "); pw.println(" Activities waiting for another to become visible:"); - dumpHistoryList(pw, mMainStack.mWaitingVisibleActivities, " ", "Wait", false); + dumpHistoryList(fd, pw, mMainStack.mWaitingVisibleActivities, " ", "Wait", false, + !dumpAll, false); } if (mMainStack.mStoppingActivities.size() > 0) { pw.println(" "); pw.println(" Activities waiting to stop:"); - dumpHistoryList(pw, mMainStack.mStoppingActivities, " ", "Stop", false); + dumpHistoryList(fd, pw, mMainStack.mStoppingActivities, " ", "Stop", false, + !dumpAll, false); } if (mMainStack.mGoingToSleepActivities.size() > 0) { pw.println(" "); pw.println(" Activities waiting to sleep:"); - dumpHistoryList(pw, mMainStack.mGoingToSleepActivities, " ", "Sleep", false); + dumpHistoryList(fd, pw, mMainStack.mGoingToSleepActivities, " ", "Sleep", false, + !dumpAll, false); } if (mMainStack.mFinishingActivities.size() > 0) { pw.println(" "); pw.println(" Activities waiting to finish:"); - dumpHistoryList(pw, mMainStack.mFinishingActivities, " ", "Fin", false); + dumpHistoryList(fd, pw, mMainStack.mFinishingActivities, " ", "Fin", false, + !dumpAll, false); } pw.println(" "); - pw.println(" mPausingActivity: " + mMainStack.mPausingActivity); + if (mMainStack.mPausingActivity != null) { + pw.println(" mPausingActivity: " + mMainStack.mPausingActivity); + } pw.println(" mResumedActivity: " + mMainStack.mResumedActivity); pw.println(" mFocusedActivity: " + mFocusedActivity); - pw.println(" mLastPausedActivity: " + mMainStack.mLastPausedActivity); - pw.println(" mSleepTimeout: " + mMainStack.mSleepTimeout); + if (dumpAll) { + pw.println(" mLastPausedActivity: " + mMainStack.mLastPausedActivity); + pw.println(" mSleepTimeout: " + mMainStack.mSleepTimeout); + } - if (dumpAll && mRecentTasks.size() > 0) { - pw.println(" "); - pw.println("Recent tasks in Current Activity Manager State:"); + if (mRecentTasks.size() > 0) { + pw.println(); + pw.println(" Recent tasks:"); final int N = mRecentTasks.size(); for (int i=0; i<N; i++) { TaskRecord tr = mRecentTasks.get(i); pw.print(" * Recent #"); pw.print(i); pw.print(": "); pw.println(tr); - mRecentTasks.get(i).dump(pw, " "); + if (dumpAll) { + mRecentTasks.get(i).dump(pw, " "); + } } } - pw.println(" "); - pw.println(" mCurTask: " + mCurTask); + if (dumpAll) { + pw.println(" "); + pw.println(" mCurTask: " + mCurTask); + } return true; } @@ -7691,6 +7659,8 @@ public final class ActivityManagerService extends ActivityManagerNative boolean needSep = false; int numPers = 0; + pw.println("ACTIVITY MANAGER RUNNING PROCESSES (dumpsys activity processes)"); + if (dumpAll) { for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) { final int NA = procs.size(); @@ -7714,20 +7684,22 @@ public final class ActivityManagerService extends ActivityManagerNative if (mLruProcesses.size() > 0) { if (needSep) pw.println(" "); needSep = true; - pw.println(" Running processes (most recent first):"); + pw.println(" Process LRU list (most recent first):"); dumpProcessOomList(pw, this, mLruProcesses, " ", "Proc", "PERS", false); needSep = true; } - synchronized (mPidsSelfLocked) { - if (mPidsSelfLocked.size() > 0) { - if (needSep) pw.println(" "); - needSep = true; - pw.println(" PID mappings:"); - for (int i=0; i<mPidsSelfLocked.size(); i++) { - pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i)); - pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i)); + if (dumpAll) { + synchronized (mPidsSelfLocked) { + if (mPidsSelfLocked.size() > 0) { + if (needSep) pw.println(" "); + needSep = true; + pw.println(" PID mappings:"); + for (int i=0; i<mPidsSelfLocked.size(); i++) { + pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i)); + pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i)); + } } } } @@ -7812,13 +7784,15 @@ public final class ActivityManagerService extends ActivityManagerNative } } - pw.println(" "); + pw.println(); pw.println(" mHomeProcess: " + mHomeProcess); if (mHeavyWeightProcess != null) { pw.println(" mHeavyWeightProcess: " + mHeavyWeightProcess); } pw.println(" mConfiguration: " + mConfiguration); - pw.println(" mConfigWillChange: " + mMainStack.mConfigWillChange); + if (dumpAll) { + pw.println(" mConfigWillChange: " + mMainStack.mConfigWillChange); + } pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown); if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient || mOrigWaitForDebugger) { @@ -7912,7 +7886,7 @@ public final class ActivityManagerService extends ActivityManagerNative needSep = dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll); - pw.println(" "); + pw.println(); pw.println(" mHomeProcess: " + mHomeProcess); if (mHeavyWeightProcess != null) { pw.println(" mHeavyWeightProcess: " + mHeavyWeightProcess); @@ -7929,61 +7903,96 @@ public final class ActivityManagerService extends ActivityManagerNative * - the first arg isn't the flattened component name of an existing service: * dump all services whose component contains the first arg as a substring */ - protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args, int opti) { - String[] newArgs; - String componentNameString; - ServiceRecord r; - if (opti >= args.length) { - componentNameString = null; - newArgs = EMPTY_STRING_ARRAY; - r = null; - } else { - componentNameString = args[opti]; - opti++; - ComponentName componentName = ComponentName.unflattenFromString(componentNameString); + protected boolean dumpService(FileDescriptor fd, PrintWriter pw, String name, String[] args, + int opti, boolean dumpAll) { + ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>(); + + if ("all".equals(name)) { synchronized (this) { - r = componentName != null ? mServices.get(componentName) : null; + for (ServiceRecord r1 : mServices.values()) { + services.add(r1); + } } - newArgs = new String[args.length - opti]; - if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti); - } - - if (r != null) { - dumpService(fd, pw, r, newArgs); } else { - ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>(); + ComponentName componentName = name != null + ? ComponentName.unflattenFromString(name) : null; + int objectId = 0; + if (componentName == null) { + // Not a '/' separated full component name; maybe an object ID? + try { + objectId = Integer.parseInt(name, 16); + name = null; + componentName = null; + } catch (RuntimeException e) { + } + } + synchronized (this) { for (ServiceRecord r1 : mServices.values()) { - if (componentNameString == null - || r1.name.flattenToString().contains(componentNameString)) { + if (componentName != null) { + if (r1.name.equals(componentName)) { + services.add(r1); + } + } else if (name != null) { + if (r1.name.flattenToString().contains(name)) { + services.add(r1); + } + } else if (System.identityHashCode(r1) == objectId) { services.add(r1); } } } - for (int i=0; i<services.size(); i++) { - dumpService(fd, pw, services.get(i), newArgs); + } + + if (services.size() <= 0) { + return false; + } + + boolean needSep = false; + for (int i=0; i<services.size(); i++) { + if (needSep) { + pw.println(); } + needSep = true; + dumpService("", fd, pw, services.get(i), args, dumpAll); } + return true; } /** * Invokes IApplicationThread.dumpService() on the thread of the specified service if * there is a thread associated with the service. */ - private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) { - pw.println("------------------------------------------------------------" - + "-------------------"); - pw.println("APP SERVICE: " + r.name.flattenToString()); + private void dumpService(String prefix, FileDescriptor fd, PrintWriter pw, + final ServiceRecord r, String[] args, boolean dumpAll) { + String innerPrefix = prefix + " "; + synchronized (this) { + pw.print(prefix); pw.print("SERVICE "); + pw.print(r.shortName); pw.print(" "); + pw.print(Integer.toHexString(System.identityHashCode(r))); + pw.print(" pid="); + if (r.app != null) pw.println(r.app.pid); + else pw.println("(not running)"); + if (dumpAll) { + r.dump(pw, innerPrefix); + } + } if (r.app != null && r.app.thread != null) { + pw.print(prefix); pw.println(" Client:"); + pw.flush(); try { - // flush anything that is already in the PrintWriter since the thread is going - // to write to the file descriptor directly - pw.flush(); - r.app.thread.dumpService(fd, r, args); - pw.print("\n"); - pw.flush(); + TransferPipe tp = new TransferPipe(); + try { + r.app.thread.dumpService(tp.getWriteFd().getFileDescriptor(), r, args); + tp.setBufferPrefix(prefix + " "); + tp.go(fd); + } finally { + tp.kill(); + } + } catch (IOException e) { + pw.println(prefix + " Failure while dumping the service: " + e); } catch (RemoteException e) { - pw.println("got a RemoteException while dumping the service"); + pw.println(prefix + " Got a RemoteException while dumping the service"); } } } @@ -7997,34 +8006,40 @@ public final class ActivityManagerService extends ActivityManagerNative */ protected boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name, String[] args, int opti, boolean dumpAll) { - String[] newArgs; - ComponentName componentName = ComponentName.unflattenFromString(name); - int objectId = 0; - if (componentName == null) { - // Not a '/' separated full component name; maybe an object ID? - try { - objectId = Integer.parseInt(name, 16); - name = null; - componentName = null; - } catch (RuntimeException e) { + ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>(); + + if ("all".equals(name)) { + synchronized (this) { + for (ActivityRecord r1 : (ArrayList<ActivityRecord>)mMainStack.mHistory) { + activities.add(r1); + } + } + } else { + ComponentName componentName = ComponentName.unflattenFromString(name); + int objectId = 0; + if (componentName == null) { + // Not a '/' separated full component name; maybe an object ID? + try { + objectId = Integer.parseInt(name, 16); + name = null; + componentName = null; + } catch (RuntimeException e) { + } } - } - newArgs = new String[args.length - opti]; - if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti); - ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>(); - synchronized (this) { - for (ActivityRecord r1 : (ArrayList<ActivityRecord>)mMainStack.mHistory) { - if (componentName != null) { - if (r1.intent.getComponent().equals(componentName)) { - activities.add(r1); - } - } else if (name != null) { - if (r1.intent.getComponent().flattenToString().contains(name)) { + synchronized (this) { + for (ActivityRecord r1 : (ArrayList<ActivityRecord>)mMainStack.mHistory) { + if (componentName != null) { + if (r1.intent.getComponent().equals(componentName)) { + activities.add(r1); + } + } else if (name != null) { + if (r1.intent.getComponent().flattenToString().contains(name)) { + activities.add(r1); + } + } else if (System.identityHashCode(r1) == objectId) { activities.add(r1); } - } else if (System.identityHashCode(r1) == objectId) { - activities.add(r1); } } } @@ -8033,15 +8048,25 @@ public final class ActivityManagerService extends ActivityManagerNative return false; } + String[] newArgs = new String[args.length - opti]; + if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti); + TaskRecord lastTask = null; + boolean needSep = false; for (int i=activities.size()-1; i>=0; i--) { ActivityRecord r = (ActivityRecord)activities.get(i); - if (lastTask != r.task) { - lastTask = r.task; - pw.print("* Task "); pw.print(lastTask.affinity); - pw.print(" id="); pw.println(lastTask.taskId); - if (dumpAll) { - lastTask.dump(pw, " "); + if (needSep) { + pw.println(); + } + needSep = true; + synchronized (this) { + if (lastTask != r.task) { + lastTask = r.task; + pw.print("TASK "); pw.print(lastTask.affinity); + pw.print(" id="); pw.println(lastTask.taskId); + if (dumpAll) { + lastTask.dump(pw, " "); + } } } dumpActivity(" ", fd, pw, activities.get(i), newArgs, dumpAll); @@ -8054,26 +8079,35 @@ public final class ActivityManagerService extends ActivityManagerNative * there is a thread associated with the activity. */ private void dumpActivity(String prefix, FileDescriptor fd, PrintWriter pw, - ActivityRecord r, String[] args, boolean dumpAll) { + final ActivityRecord r, String[] args, boolean dumpAll) { + String innerPrefix = prefix + " "; synchronized (this) { - pw.print(prefix); pw.print("* Activity "); - pw.print(Integer.toHexString(System.identityHashCode(r))); - pw.print(" "); pw.print(r.shortComponentName); pw.print(" pid="); + pw.print(prefix); pw.print("ACTIVITY "); pw.print(r.shortComponentName); + pw.print(" "); pw.print(Integer.toHexString(System.identityHashCode(r))); + pw.print(" pid="); if (r.app != null) pw.println(r.app.pid); else pw.println("(not running)"); if (dumpAll) { - r.dump(pw, prefix + " "); + r.dump(pw, innerPrefix); } } if (r.app != null && r.app.thread != null) { + // flush anything that is already in the PrintWriter since the thread is going + // to write to the file descriptor directly + pw.flush(); try { - // flush anything that is already in the PrintWriter since the thread is going - // to write to the file descriptor directly - pw.flush(); - r.app.thread.dumpActivity(fd, r, prefix + " ", args); - pw.flush(); + TransferPipe tp = new TransferPipe(); + try { + r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(), r, + innerPrefix, args); + tp.go(fd); + } finally { + tp.kill(); + } + } catch (IOException e) { + pw.println(innerPrefix + "Failure while dumping the activity: " + e); } catch (RemoteException e) { - pw.println("got a RemoteException while dumping the activity"); + pw.println(innerPrefix + "Got a RemoteException while dumping the activity"); } } } @@ -8082,9 +8116,9 @@ public final class ActivityManagerService extends ActivityManagerNative int opti, boolean dumpAll) { boolean needSep = false; + pw.println("ACTIVITY MANAGER BROADCAST STATE (dumpsys activity broadcasts)"); if (dumpAll) { if (mRegisteredReceivers.size() > 0) { - pw.println(" "); pw.println(" Registered Receivers:"); Iterator it = mRegisteredReceivers.values().iterator(); while (it.hasNext()) { @@ -8094,16 +8128,16 @@ public final class ActivityManagerService extends ActivityManagerNative } } - pw.println(" "); - pw.println("Receiver Resolver Table:"); - mReceiverResolver.dump(pw, null, " ", null, false); + pw.println(); + pw.println(" Receiver Resolver Table:"); + mReceiverResolver.dump(pw, null, " ", null, false); needSep = true; } if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0 || mPendingBroadcast != null) { if (mParallelBroadcasts.size() > 0) { - pw.println(" "); + pw.println(); pw.println(" Active broadcasts:"); } for (int i=mParallelBroadcasts.size()-1; i>=0; i--) { @@ -8111,14 +8145,14 @@ public final class ActivityManagerService extends ActivityManagerNative mParallelBroadcasts.get(i).dump(pw, " "); } if (mOrderedBroadcasts.size() > 0) { - pw.println(" "); + pw.println(); pw.println(" Active ordered broadcasts:"); } for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) { pw.println(" Serialized Broadcast #" + i + ":"); mOrderedBroadcasts.get(i).dump(pw, " "); } - pw.println(" "); + pw.println(); pw.println(" Pending broadcast:"); if (mPendingBroadcast != null) { mPendingBroadcast.dump(pw, " "); @@ -8128,47 +8162,59 @@ public final class ActivityManagerService extends ActivityManagerNative needSep = true; } - if (dumpAll) { - pw.println(" "); - pw.println(" Historical broadcasts:"); - for (int i=0; i<MAX_BROADCAST_HISTORY; i++) { - BroadcastRecord r = mBroadcastHistory[i]; - if (r == null) { + if (needSep) { + pw.println(); + } + pw.println(" Historical broadcasts:"); + for (int i=0; i<MAX_BROADCAST_HISTORY; i++) { + BroadcastRecord r = mBroadcastHistory[i]; + if (r == null) { + break; + } + if (dumpAll) { + pw.print(" Historical Broadcast #"); pw.print(i); pw.println(":"); + r.dump(pw, " "); + } else { + if (i >= 50) { + pw.println(" ..."); break; } - pw.println(" Historical Broadcast #" + i + ":"); - r.dump(pw, " "); + pw.print(" #"); pw.print(i); pw.print(": "); pw.println(r); } - needSep = true; } + needSep = true; if (mStickyBroadcasts != null) { - pw.println(" "); + pw.println(); pw.println(" Sticky broadcasts:"); StringBuilder sb = new StringBuilder(128); for (Map.Entry<String, ArrayList<Intent>> ent : mStickyBroadcasts.entrySet()) { pw.print(" * Sticky action "); pw.print(ent.getKey()); - pw.println(":"); - ArrayList<Intent> intents = ent.getValue(); - final int N = intents.size(); - for (int i=0; i<N; i++) { - sb.setLength(0); - sb.append(" Intent: "); - intents.get(i).toShortString(sb, true, false); - pw.println(sb.toString()); - Bundle bundle = intents.get(i).getExtras(); - if (bundle != null) { - pw.print(" "); - pw.println(bundle.toString()); + if (dumpAll) { + pw.println(":"); + ArrayList<Intent> intents = ent.getValue(); + final int N = intents.size(); + for (int i=0; i<N; i++) { + sb.setLength(0); + sb.append(" Intent: "); + intents.get(i).toShortString(sb, true, false); + pw.println(sb.toString()); + Bundle bundle = intents.get(i).getExtras(); + if (bundle != null) { + pw.print(" "); + pw.println(bundle.toString()); + } } + } else { + pw.println(""); } } needSep = true; } if (dumpAll) { - pw.println(" "); + pw.println(); pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled); pw.println(" mHandler:"); mHandler.dump(new PrintWriterPrinter(pw), " "); @@ -8179,20 +8225,55 @@ public final class ActivityManagerService extends ActivityManagerNative } boolean dumpServicesLocked(FileDescriptor fd, PrintWriter pw, String[] args, - int opti, boolean dumpAll) { + int opti, boolean dumpAll, boolean dumpClient) { boolean needSep = false; - if (dumpAll) { - if (mServices.size() > 0) { - pw.println(" Active services:"); - Iterator<ServiceRecord> it = mServices.values().iterator(); - while (it.hasNext()) { - ServiceRecord r = it.next(); - pw.print(" * "); pw.println(r); + pw.println("ACTIVITY MANAGER SERVICES (dumpsys activity services)"); + if (mServices.size() > 0) { + pw.println(" Active services:"); + long nowReal = SystemClock.elapsedRealtime(); + Iterator<ServiceRecord> it = mServices.values().iterator(); + needSep = false; + while (it.hasNext()) { + ServiceRecord r = it.next(); + if (needSep) { + pw.println(); + } + pw.print(" * "); pw.println(r); + if (dumpAll) { r.dump(pw, " "); + needSep = true; + } else { + pw.print(" app="); pw.println(r.app); + pw.print(" created="); + TimeUtils.formatDuration(r.createTime, nowReal, pw); + pw.print(" started="); pw.print(r.startRequested); + pw.print(" connections="); pw.println(r.connections.size()); + } + if (dumpClient && r.app != null && r.app.thread != null) { + pw.println(" Client:"); + pw.flush(); + try { + TransferPipe tp = new TransferPipe(); + try { + r.app.thread.dumpService( + tp.getWriteFd().getFileDescriptor(), r, args); + tp.setBufferPrefix(" "); + // Short timeout, since blocking here can + // deadlock with the application. + tp.go(fd, 2000); + } finally { + tp.kill(); + } + } catch (IOException e) { + pw.println(" Failure while dumping the service: " + e); + } catch (RemoteException e) { + pw.println(" Got a RemoteException while dumping the service"); + } + needSep = true; } - needSep = true; } + needSep = true; } if (mPendingServices.size() > 0) { @@ -8252,21 +8333,32 @@ public final class ActivityManagerService extends ActivityManagerNative int opti, boolean dumpAll) { boolean needSep = false; - if (dumpAll) { - if (mProvidersByClass.size() > 0) { - if (needSep) pw.println(" "); - pw.println(" Published content providers (by class):"); - Iterator<Map.Entry<String, ContentProviderRecord>> it - = mProvidersByClass.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry<String, ContentProviderRecord> e = it.next(); - ContentProviderRecord r = e.getValue(); + pw.println("ACTIVITY MANAGER CONTENT PROVIDERS (dumpsys activity providers)"); + if (mProvidersByClass.size() > 0) { + if (needSep) pw.println(" "); + pw.println(" Published content providers (by class):"); + Iterator<Map.Entry<String, ContentProviderRecord>> it + = mProvidersByClass.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry<String, ContentProviderRecord> e = it.next(); + ContentProviderRecord r = e.getValue(); + if (dumpAll) { pw.print(" * "); pw.println(r); r.dump(pw, " "); + } else { + pw.print(" * "); pw.print(r.name.toShortString()); + if (r.app != null) { + pw.println(":"); + pw.print(" "); pw.println(r.app); + } else { + pw.println(); + } } - needSep = true; } + needSep = true; + } + if (dumpAll) { if (mProvidersByName.size() > 0) { pw.println(" "); pw.println(" Authority to provider mappings:"); @@ -8303,7 +8395,9 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println(" holds:"); for (UriPermission perm : perms.values()) { pw.print(" "); pw.println(perm); - perm.dump(pw, " "); + if (dumpAll) { + perm.dump(pw, " "); + } } } needSep = true; @@ -8316,20 +8410,21 @@ public final class ActivityManagerService extends ActivityManagerNative int opti, boolean dumpAll) { boolean needSep = false; - if (dumpAll) { - if (this.mIntentSenderRecords.size() > 0) { - Iterator<WeakReference<PendingIntentRecord>> it - = mIntentSenderRecords.values().iterator(); - while (it.hasNext()) { - WeakReference<PendingIntentRecord> ref = it.next(); - PendingIntentRecord rec = ref != null ? ref.get(): null; - needSep = true; - if (rec != null) { - pw.print(" * "); pw.println(rec); + if (this.mIntentSenderRecords.size() > 0) { + pw.println("ACTIVITY MANAGER PENDING INTENTS (dumpsys activity intents)"); + Iterator<WeakReference<PendingIntentRecord>> it + = mIntentSenderRecords.values().iterator(); + while (it.hasNext()) { + WeakReference<PendingIntentRecord> ref = it.next(); + PendingIntentRecord rec = ref != null ? ref.get(): null; + needSep = true; + if (rec != null) { + pw.print(" * "); pw.println(rec); + if (dumpAll) { rec.dump(pw, " "); - } else { - pw.print(" * "); pw.print(ref); } + } else { + pw.print(" * "); pw.println(ref); } } } @@ -8337,12 +8432,19 @@ public final class ActivityManagerService extends ActivityManagerNative return needSep; } - private static final void dumpHistoryList(PrintWriter pw, List list, - String prefix, String label, boolean complete) { + private static final void dumpHistoryList(FileDescriptor fd, PrintWriter pw, List list, + String prefix, String label, boolean complete, boolean brief, boolean client) { TaskRecord lastTask = null; + boolean needNL = false; + final String innerPrefix = prefix + " "; + final String[] args = new String[0]; for (int i=list.size()-1; i>=0; i--) { - ActivityRecord r = (ActivityRecord)list.get(i); - final boolean full = complete || !r.inHistory; + final ActivityRecord r = (ActivityRecord)list.get(i); + final boolean full = !brief && (complete || !r.inHistory); + if (needNL) { + pw.println(" "); + needNL = false; + } if (lastTask != r.task) { lastTask = r.task; pw.print(prefix); @@ -8350,13 +8452,46 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println(lastTask); if (full) { lastTask.dump(pw, prefix + " "); + } else if (complete) { + // Complete + brief == give a summary. Isn't that obvious?!? + if (lastTask.intent != null) { + pw.print(prefix); pw.print(" "); pw.println(lastTask.intent); + } } } pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label); pw.print(" #"); pw.print(i); pw.print(": "); pw.println(r); if (full) { - r.dump(pw, prefix + " "); + r.dump(pw, innerPrefix); + } else if (complete) { + // Complete + brief == give a summary. Isn't that obvious?!? + pw.print(innerPrefix); pw.println(r.intent); + if (r.app != null) { + pw.print(innerPrefix); pw.println(r.app); + } + } + if (client && r.app != null && r.app.thread != null) { + // flush anything that is already in the PrintWriter since the thread is going + // to write to the file descriptor directly + pw.flush(); + try { + TransferPipe tp = new TransferPipe(); + try { + r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(), r, + innerPrefix, args); + // Short timeout, since blocking here can + // deadlock with the application. + tp.go(fd, 2000); + } finally { + tp.kill(); + } + } catch (IOException e) { + pw.println(innerPrefix + "Failure while dumping the activity: " + e); + } catch (RemoteException e) { + pw.println(innerPrefix + "Got a RemoteException while dumping the activity"); + } + needNL = true; } } } @@ -8442,7 +8577,7 @@ public final class ActivityManagerService extends ActivityManagerNative N-i, oomAdj, schedGroup, r.toShortString(), r.adjType)); if (r.adjSource != null || r.adjTarget != null) { pw.print(prefix); - pw.print(" "); + pw.print(" "); if (r.adjTarget instanceof ComponentName) { pw.print(((ComponentName)r.adjTarget).flattenToShortString()); } else if (r.adjTarget != null) { @@ -8512,30 +8647,75 @@ public final class ActivityManagerService extends ActivityManagerNative } } - static final void dumpGraphicsHardwareUsage(FileDescriptor fd, - PrintWriter pw, List list) { - String args[] = {"graphics"}; - pw.println("-------------------------------------------------------------------------------"); - pw.println("DUMP OF GRAPHICS ACCELERATION INFO:"); - for (int i = list.size() - 1 ; i >= 0 ; i--) { - ProcessRecord r = (ProcessRecord)list.get(i); + ArrayList<ProcessRecord> collectProcesses(PrintWriter pw, String[] args) { + ArrayList<ProcessRecord> procs; + synchronized (this) { + if (args != null && args.length > 0 + && args[0].charAt(0) != '-') { + procs = new ArrayList<ProcessRecord>(); + int pid = -1; + try { + pid = Integer.parseInt(args[0]); + } catch (NumberFormatException e) { + + } + for (int i=mLruProcesses.size()-1; i>=0; i--) { + ProcessRecord proc = mLruProcesses.get(i); + if (proc.pid == pid) { + procs.add(proc); + } else if (proc.processName.equals(args[0])) { + procs.add(proc); + } + } + if (procs.size() <= 0) { + pw.println("No process found for: " + args[0]); + return null; + } + } else { + procs = new ArrayList<ProcessRecord>(mLruProcesses); + } + } + return procs; + } + + final void dumpGraphicsHardwareUsage(FileDescriptor fd, + PrintWriter pw, String[] args) { + ArrayList<ProcessRecord> procs = collectProcesses(pw, args); + if (procs == null) { + return; + } + + long uptime = SystemClock.uptimeMillis(); + long realtime = SystemClock.elapsedRealtime(); + pw.println("Applications Graphics Acceleration Info:"); + pw.println("Uptime: " + uptime + " Realtime: " + realtime); + + String callArgs[] = {"graphics"}; + for (int i = procs.size() - 1 ; i >= 0 ; i--) { + ProcessRecord r = procs.get(i); if (r.thread != null) { pw.println("\n** Graphics info for pid " + r.pid + " [" + r.processName + "] **"); pw.flush(); try { - r.thread.asBinder().dump(fd, args); + TransferPipe.goDump(r.thread.asBinder(), fd, callArgs); + } catch (IOException e) { + pw.println("Failure: " + e); + pw.flush(); } catch (RemoteException e) { pw.println("Got RemoteException!"); pw.flush(); } } } - pw.println("\n"); - pw.flush(); } - static final void dumpApplicationMemoryUsage(FileDescriptor fd, - PrintWriter pw, List list, String prefix, String[] args) { + final void dumpApplicationMemoryUsage(FileDescriptor fd, + PrintWriter pw, String prefix, String[] args) { + ArrayList<ProcessRecord> procs = collectProcesses(pw, args); + if (procs == null) { + return; + } + final boolean isCheckinRequest = scanArgs(args, "--checkin"); long uptime = SystemClock.uptimeMillis(); long realtime = SystemClock.elapsedRealtime(); @@ -8548,15 +8728,18 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println("Applications Memory Usage (kB):"); pw.println("Uptime: " + uptime + " Realtime: " + realtime); } - for (int i = list.size() - 1 ; i >= 0 ; i--) { - ProcessRecord r = (ProcessRecord)list.get(i); + for (int i = procs.size() - 1 ; i >= 0 ; i--) { + ProcessRecord r = procs.get(i); if (r.thread != null) { if (!isCheckinRequest) { pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **"); pw.flush(); } try { - r.thread.asBinder().dump(fd, args); + TransferPipe.goDump(r.thread.asBinder(), fd, args); + } catch (IOException e) { + pw.println("Failure: " + e); + pw.flush(); } catch (RemoteException e) { if (!isCheckinRequest) { pw.println("Got RemoteException!"); diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java index 0fb30ff..8d8f303 100644 --- a/services/java/com/android/server/am/ActivityRecord.java +++ b/services/java/com/android/server/am/ActivityRecord.java @@ -135,7 +135,7 @@ class ActivityRecord extends IApplicationToken.Stub { pw.print(prefix); pw.print("stateNotNeeded="); pw.print(stateNotNeeded); pw.print(" componentSpecified="); pw.print(componentSpecified); pw.print(" isHomeActivity="); pw.println(isHomeActivity); - pw.print(prefix); pw.print("configuration="); pw.println(configuration); + pw.print(prefix); pw.print("config="); pw.println(configuration); if (resultTo != null || resultWho != null) { pw.print(prefix); pw.print("resultTo="); pw.print(resultTo); pw.print(" resultWho="); pw.print(resultWho); diff --git a/services/java/com/android/server/am/ContentProviderRecord.java b/services/java/com/android/server/am/ContentProviderRecord.java index 44c9742..db235ee 100644 --- a/services/java/com/android/server/am/ContentProviderRecord.java +++ b/services/java/com/android/server/am/ContentProviderRecord.java @@ -60,7 +60,7 @@ class ContentProviderRecord extends ContentProviderHolder { void dump(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("package="); pw.print(info.applicationInfo.packageName); - pw.print("process="); pw.println(info.processName); + pw.print(" process="); pw.println(info.processName); pw.print(prefix); pw.print("app="); pw.println(app); if (launchingApp != null) { pw.print(prefix); pw.print("launchingApp="); pw.println(launchingApp); diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java index e5aceb4..1a617dd 100644 --- a/services/java/com/android/server/am/ServiceRecord.java +++ b/services/java/com/android/server/am/ServiceRecord.java @@ -211,7 +211,7 @@ class ServiceRecord extends Binder { pw.print(" lastActivity="); TimeUtils.formatDuration(lastActivity, now, pw); pw.println(""); - pw.print(prefix); pw.print(" executingStart="); + pw.print(prefix); pw.print("executingStart="); TimeUtils.formatDuration(executingStart, now, pw); pw.print(" restartTime="); TimeUtils.formatDuration(restartTime, now, pw); diff --git a/services/java/com/android/server/am/TransferPipe.java b/services/java/com/android/server/am/TransferPipe.java new file mode 100644 index 0000000..c3f4f93 --- /dev/null +++ b/services/java/com/android/server/am/TransferPipe.java @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.am; + +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; + +import android.os.Binder; +import android.os.IBinder; +import android.os.IInterface; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.os.SystemClock; +import android.util.Slog; + +/** + * Helper for transferring data through a pipe from a client app. + */ +class TransferPipe implements Runnable { + static final String TAG = "TransferPipe"; + static final boolean DEBUG = false; + + static final long DEFAULT_TIMEOUT = 5000; // 5 seconds + + final Thread mThread;; + final ParcelFileDescriptor[] mFds; + + FileDescriptor mOutFd; + long mEndTime; + String mFailure; + boolean mComplete; + + String mBufferPrefix; + + interface Caller { + void go(IInterface iface, FileDescriptor fd, String prefix, + String[] args) throws RemoteException; + } + + TransferPipe() throws IOException { + mThread = new Thread(this, "TransferPipe"); + mFds = ParcelFileDescriptor.createPipe(); + } + + ParcelFileDescriptor getReadFd() { + return mFds[0]; + } + + ParcelFileDescriptor getWriteFd() { + return mFds[1]; + } + + void setBufferPrefix(String prefix) { + mBufferPrefix = prefix; + } + + static void go(Caller caller, IInterface iface, FileDescriptor out, + String prefix, String[] args) throws IOException, RemoteException { + go(caller, iface, out, prefix, args, DEFAULT_TIMEOUT); + } + + static void go(Caller caller, IInterface iface, FileDescriptor out, + String prefix, String[] args, long timeout) throws IOException, RemoteException { + if ((iface.asBinder()) instanceof Binder) { + // This is a local object... just call it directly. + try { + caller.go(iface, out, prefix, args); + } catch (RemoteException e) { + } + return; + } + + TransferPipe tp = new TransferPipe(); + try { + caller.go(iface, tp.getWriteFd().getFileDescriptor(), prefix, args); + tp.go(out, timeout); + } finally { + tp.kill(); + } + } + + static void goDump(IBinder binder, FileDescriptor out, + String[] args) throws IOException, RemoteException { + goDump(binder, out, args, DEFAULT_TIMEOUT); + } + + static void goDump(IBinder binder, FileDescriptor out, + String[] args, long timeout) throws IOException, RemoteException { + if (binder instanceof Binder) { + // This is a local object... just call it directly. + try { + binder.dump(out, args); + } catch (RemoteException e) { + } + return; + } + + TransferPipe tp = new TransferPipe(); + try { + binder.dumpAsync(tp.getWriteFd().getFileDescriptor(), args); + tp.go(out, timeout); + } finally { + tp.kill(); + } + } + + void go(FileDescriptor out) throws IOException { + go(out, DEFAULT_TIMEOUT); + } + + void go(FileDescriptor out, long timeout) throws IOException { + try { + synchronized (this) { + mOutFd = out; + mEndTime = SystemClock.uptimeMillis() + timeout; + + if (DEBUG) Slog.i(TAG, "read=" + getReadFd() + " write=" + getWriteFd() + + " out=" + out); + + // Close the write fd, so we know when the other side is done. + closeFd(1); + + mThread.start(); + + while (mFailure == null && !mComplete) { + long waitTime = mEndTime - SystemClock.uptimeMillis(); + if (waitTime <= 0) { + if (DEBUG) Slog.i(TAG, "TIMEOUT!"); + mThread.interrupt(); + throw new IOException("Timeout"); + } + + try { + wait(waitTime); + } catch (InterruptedException e) { + } + } + + if (DEBUG) Slog.i(TAG, "Finished: " + mFailure); + if (mFailure != null) { + throw new IOException(mFailure); + } + } + } finally { + kill(); + } + } + + void closeFd(int num) { + if (mFds[num] != null) { + if (DEBUG) Slog.i(TAG, "Closing: " + mFds[num]); + try { + mFds[num].close(); + } catch (IOException e) { + } + mFds[num] = null; + } + } + + void kill() { + closeFd(0); + closeFd(1); + } + + @Override + public void run() { + final byte[] buffer = new byte[1024]; + final FileInputStream fis = new FileInputStream(getReadFd().getFileDescriptor()); + final FileOutputStream fos = new FileOutputStream(mOutFd); + + if (DEBUG) Slog.i(TAG, "Ready to read pipe..."); + byte[] bufferPrefix = null; + boolean needPrefix = true; + if (mBufferPrefix != null) { + bufferPrefix = mBufferPrefix.getBytes(); + } + + int size; + try { + while ((size=fis.read(buffer)) > 0) { + if (DEBUG) Slog.i(TAG, "Got " + size + " bytes"); + if (bufferPrefix == null) { + fos.write(buffer, 0, size); + } else { + int start = 0; + for (int i=0; i<size; i++) { + if (buffer[i] != '\n') { + if (i > start) { + fos.write(buffer, start, i-start); + } + start = i; + if (needPrefix) { + fos.write(bufferPrefix); + needPrefix = false; + } + do { + i++; + } while (i<size && buffer[i] != '\n'); + if (i < size) { + needPrefix = true; + } + } + } + if (size > start) { + fos.write(buffer, start, size-start); + } + } + } + if (DEBUG) Slog.i(TAG, "End of pipe: size=" + size); + if (mThread.isInterrupted()) { + if (DEBUG) Slog.i(TAG, "Interrupted!"); + } + } catch (IOException e) { + synchronized (this) { + mFailure = e.toString(); + notifyAll(); + return; + } + } + + synchronized (this) { + mComplete = true; + notifyAll(); + } + } +} |