summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
authorAndy McFadden <fadden@android.com>2010-07-13 12:19:52 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2010-07-13 12:19:52 -0700
commit09d7d7dbc3dbb1d10f2cc18dba7d33e40a098aed (patch)
treed414b470c5a2aa47071fa9e124f0a65e63e1f811 /core/java
parent46c076d193fe91721912d3bfa8e5a6d24707b5bc (diff)
parent824c510752fd6a30cdba5ed7324cb80a5043ce26 (diff)
downloadframeworks_base-09d7d7dbc3dbb1d10f2cc18dba7d33e40a098aed.zip
frameworks_base-09d7d7dbc3dbb1d10f2cc18dba7d33e40a098aed.tar.gz
frameworks_base-09d7d7dbc3dbb1d10f2cc18dba7d33e40a098aed.tar.bz2
Merge "Allow "am" to initiate heap dumps."
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/ActivityManagerNative.java37
-rw-r--r--core/java/android/app/ActivityThread.java37
-rw-r--r--core/java/android/app/ApplicationThreadNative.java28
-rw-r--r--core/java/android/app/IActivityManager.java7
-rw-r--r--core/java/android/app/IApplicationThread.java3
-rw-r--r--core/java/android/os/Debug.java19
6 files changed, 126 insertions, 5 deletions
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 1fe85e6..43a08b5 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1294,6 +1294,19 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case DUMP_HEAP_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ String process = data.readString();
+ boolean managed = data.readInt() != 0;
+ String path = data.readString();
+ ParcelFileDescriptor fd = data.readInt() != 0
+ ? data.readFileDescriptor() : null;
+ boolean res = dumpHeap(process, managed, path, fd);
+ reply.writeNoException();
+ reply.writeInt(res ? 1 : 0);
+ return true;
+ }
+
}
return super.onTransact(code, data, reply, flags);
@@ -2874,6 +2887,28 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
reply.recycle();
}
-
+
+ public boolean dumpHeap(String process, boolean managed,
+ String path, ParcelFileDescriptor fd) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeString(process);
+ data.writeInt(managed ? 1 : 0);
+ data.writeString(path);
+ if (fd != null) {
+ data.writeInt(1);
+ fd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+ } else {
+ data.writeInt(0);
+ }
+ mRemote.transact(DUMP_HEAP_TRANSACTION, data, reply, 0);
+ reply.readException();
+ boolean res = reply.readInt() != 0;
+ reply.recycle();
+ data.recycle();
+ return res;
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index d788be8..53883b1 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -356,6 +356,11 @@ public final class ActivityThread {
ParcelFileDescriptor fd;
}
+ private static final class DumpHeapData {
+ String path;
+ ParcelFileDescriptor fd;
+ }
+
private final class ApplicationThread extends ApplicationThreadNative {
private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s";
private static final String ONE_COUNT_COLUMN = "%17s %8d";
@@ -623,6 +628,13 @@ public final class ActivityThread {
queueOrSendMessage(H.PROFILER_CONTROL, pcd, start ? 1 : 0);
}
+ public void dumpHeap(boolean managed, String path, ParcelFileDescriptor fd) {
+ DumpHeapData dhd = new DumpHeapData();
+ dhd.path = path;
+ dhd.fd = fd;
+ queueOrSendMessage(H.DUMP_HEAP, dhd, managed ? 1 : 0);
+ }
+
public void setSchedulingGroup(int group) {
// Note: do this immediately, since going into the foreground
// should happen regardless of what pending work we have to do
@@ -874,6 +886,7 @@ public final class ActivityThread {
public static final int ENABLE_JIT = 132;
public static final int DISPATCH_PACKAGE_BROADCAST = 133;
public static final int SCHEDULE_CRASH = 134;
+ public static final int DUMP_HEAP = 135;
String codeToString(int code) {
if (localLOGV) {
switch (code) {
@@ -912,6 +925,7 @@ public final class ActivityThread {
case ENABLE_JIT: return "ENABLE_JIT";
case DISPATCH_PACKAGE_BROADCAST: return "DISPATCH_PACKAGE_BROADCAST";
case SCHEDULE_CRASH: return "SCHEDULE_CRASH";
+ case DUMP_HEAP: return "DUMP_HEAP";
}
}
return "(unknown)";
@@ -1037,6 +1051,9 @@ public final class ActivityThread {
break;
case SCHEDULE_CRASH:
throw new RemoteServiceException((String)msg.obj);
+ case DUMP_HEAP:
+ handleDumpHeap(msg.arg1 != 0, (DumpHeapData)msg.obj);
+ break;
}
}
@@ -3015,6 +3032,26 @@ public final class ActivityThread {
}
}
+ final void handleDumpHeap(boolean managed, DumpHeapData dhd) {
+ if (managed) {
+ try {
+ Debug.dumpHprofData(dhd.path, dhd.fd.getFileDescriptor());
+ } catch (IOException e) {
+ Slog.w(TAG, "Managed heap dump failed on path " + dhd.path
+ + " -- can the process access this path?");
+ } finally {
+ try {
+ dhd.fd.close();
+ } catch (IOException e) {
+ Slog.w(TAG, "Failure closing profile fd", e);
+ }
+ }
+ } else {
+ // TODO
+ Slog.w(TAG, "Native heap dump not yet implemented");
+ }
+ }
+
final void handleDispatchPackageBroadcast(int cmd, String[] packages) {
boolean hasPkgInfo = false;
if (packages != null) {
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 1c20062..dc2145f 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -403,6 +403,17 @@ public abstract class ApplicationThreadNative extends Binder
scheduleCrash(msg);
return true;
}
+
+ case DUMP_HEAP_TRANSACTION:
+ {
+ data.enforceInterface(IApplicationThread.descriptor);
+ boolean managed = data.readInt() != 0;
+ String path = data.readString();
+ ParcelFileDescriptor fd = data.readInt() != 0
+ ? data.readFileDescriptor() : null;
+ dumpHeap(managed, path, fd);
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -829,5 +840,22 @@ class ApplicationThreadProxy implements IApplicationThread {
data.recycle();
}
+
+ public void dumpHeap(boolean managed, String path,
+ ParcelFileDescriptor fd) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ data.writeInt(managed ? 1 : 0);
+ data.writeString(path);
+ if (fd != null) {
+ data.writeInt(1);
+ fd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+ } else {
+ data.writeInt(0);
+ }
+ mRemote.transact(DUMP_HEAP_TRANSACTION, data, null,
+ IBinder.FLAG_ONEWAY);
+ data.recycle();
+ }
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 20c9a80..8ea59a7 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -316,7 +316,11 @@ public interface IActivityManager extends IInterface {
public void crashApplication(int uid, int initialPid, String packageName,
String message) throws RemoteException;
-
+
+ // Cause the specified process to dump the specified heap.
+ public boolean dumpHeap(String process, boolean managed, String path,
+ ParcelFileDescriptor fd) throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -533,4 +537,5 @@ public interface IActivityManager extends IInterface {
int SET_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+111;
int IS_TOP_ACTIVITY_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+112;
int CRASH_APPLICATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+113;
+ int DUMP_HEAP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+114;
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index c8ef17f..039bcb9 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -97,6 +97,8 @@ public interface IApplicationThread extends IInterface {
void scheduleActivityConfigurationChanged(IBinder token) throws RemoteException;
void profilerControl(boolean start, String path, ParcelFileDescriptor fd)
throws RemoteException;
+ void dumpHeap(boolean managed, String path, ParcelFileDescriptor fd)
+ throws RemoteException;
void setSchedulingGroup(int group) throws RemoteException;
void getMemoryInfo(Debug.MemoryInfo outInfo) throws RemoteException;
static final int PACKAGE_REMOVED = 0;
@@ -140,4 +142,5 @@ public interface IApplicationThread extends IInterface {
int SCHEDULE_SUICIDE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+32;
int DISPATCH_PACKAGE_BROADCAST_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+33;
int SCHEDULE_CRASH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+34;
+ int DUMP_HEAP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+35;
}
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 2e14667..d6b6d72 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -730,7 +730,7 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
}
/**
- * Dump "hprof" data to the specified file. This will cause a GC.
+ * Dump "hprof" data to the specified file. This may cause a GC.
*
* @param fileName Full pathname of output file (e.g. "/sdcard/dump.hprof").
* @throws UnsupportedOperationException if the VM was built without
@@ -742,11 +742,24 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
}
/**
- * Collect "hprof" and send it to DDMS. This will cause a GC.
+ * Like dumpHprofData(String), but takes an already-opened
+ * FileDescriptor to which the trace is written. The file name is also
+ * supplied simply for logging. Makes a dup of the file descriptor.
+ *
+ * Primarily for use by the "am" shell command.
+ *
+ * @hide
+ */
+ public static void dumpHprofData(String fileName, FileDescriptor fd)
+ throws IOException {
+ VMDebug.dumpHprofData(fileName, fd);
+ }
+
+ /**
+ * Collect "hprof" and send it to DDMS. This may cause a GC.
*
* @throws UnsupportedOperationException if the VM was built without
* HPROF support.
- *
* @hide
*/
public static void dumpHprofDataDdms() {