summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2011-04-07 15:11:57 -0700
committerDianne Hackborn <hackbod@google.com>2011-04-07 18:26:15 -0700
commite17aeb31030cfeed339a39a107912ad5e9178390 (patch)
treee0773ea106c5504e2ef107a91f5871827cd76b75 /services
parent097786507b07ff7137b305b5cf71b5ecbc6b029e (diff)
downloadframeworks_base-e17aeb31030cfeed339a39a107912ad5e9178390.zip
frameworks_base-e17aeb31030cfeed339a39a107912ad5e9178390.tar.gz
frameworks_base-e17aeb31030cfeed339a39a107912ad5e9178390.tar.bz2
Improve activity manager debug dumps.
Activity manager now does all dump requests into apps asynchronously, so it can nicely timeout if there is an app problem. Also lots of general cleanup of the am dump output. Change-Id: Id0dbccffb217315aeb85c964e379833e6aa3f5af
Diffstat (limited to 'services')
-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
5 files changed, 700 insertions, 275 deletions
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();
+ }
+ }
+}