summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2011-04-07 18:46:54 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2011-04-07 18:46:54 -0700
commitbdf7b013f81b0b56a18cc9dd2fb987b56d595650 (patch)
tree439b9fc97a0cdc311d9c080327752943cf1f79d3
parent280dda75f3a974a7f519c8c99ea1c56100f01677 (diff)
parente17aeb31030cfeed339a39a107912ad5e9178390 (diff)
downloadframeworks_base-bdf7b013f81b0b56a18cc9dd2fb987b56d595650.zip
frameworks_base-bdf7b013f81b0b56a18cc9dd2fb987b56d595650.tar.gz
frameworks_base-bdf7b013f81b0b56a18cc9dd2fb987b56d595650.tar.bz2
Merge "Improve activity manager debug dumps."
-rw-r--r--api/current.xml49
-rw-r--r--cmds/dumpstate/dumpstate.c11
-rw-r--r--core/java/android/app/ActivityThread.java85
-rw-r--r--core/java/android/app/ApplicationThreadNative.java4
-rw-r--r--core/java/android/content/res/Configuration.java127
-rw-r--r--core/java/android/os/Binder.java33
-rw-r--r--core/java/android/os/IBinder.java10
-rw-r--r--core/java/android/os/Parcel.java2
-rw-r--r--core/java/android/os/ParcelFileDescriptor.java11
-rw-r--r--core/jni/android_util_Binder.cpp35
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java727
-rw-r--r--services/java/com/android/server/am/ActivityRecord.java2
-rw-r--r--services/java/com/android/server/am/ContentProviderRecord.java2
-rw-r--r--services/java/com/android/server/am/ServiceRecord.java2
-rw-r--r--services/java/com/android/server/am/TransferPipe.java242
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();
+ }
+ }
+}