Merge "Allow "am" to initiate heap dumps."
This commit is contained in:
committed by
Android (Google) Code Review
commit
09d7d7dbc3
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user