Loading cmds/am/src/com/android/commands/am/Am.java +26 −0 Original line number Original line Diff line number Diff line Loading @@ -98,6 +98,8 @@ public class Am { sendBroadcast(); sendBroadcast(); } else if (op.equals("profile")) { } else if (op.equals("profile")) { runProfile(); runProfile(); } else if (op.equals("dumpheap")) { runDumpHeap(); } else { } else { throw new IllegalArgumentException("Unknown command: " + op); throw new IllegalArgumentException("Unknown command: " + op); } } Loading Loading @@ -424,6 +426,28 @@ public class Am { } } } } private void runDumpHeap() throws Exception { boolean managed = !"-n".equals(nextOption()); String process = nextArgRequired(); String heapFile = nextArgRequired(); ParcelFileDescriptor fd = null; try { fd = ParcelFileDescriptor.open( new File(heapFile), ParcelFileDescriptor.MODE_CREATE | ParcelFileDescriptor.MODE_TRUNCATE | ParcelFileDescriptor.MODE_READ_WRITE); } catch (FileNotFoundException e) { System.err.println("Error: Unable to open file: " + heapFile); return; } if (!mAm.dumpHeap(process, managed, heapFile, fd)) { throw new AndroidException("HEAP DUMP FAILED on process " + process); } } private class IntentReceiver extends IIntentReceiver.Stub { private class IntentReceiver extends IIntentReceiver.Stub { private boolean mFinished = false; private boolean mFinished = false; Loading Loading @@ -593,6 +617,8 @@ public class Am { "\n" + "\n" + " start profiling: am profile <PROCESS> start <FILE>\n" + " start profiling: am profile <PROCESS> start <FILE>\n" + " stop profiling: am profile <PROCESS> stop\n" + " stop profiling: am profile <PROCESS> stop\n" + " dump heap: am dumpheap [flags] <PROCESS> <FILE>\n" + " -n: dump native heap instead of managed heap\n" + "\n" + "\n" + " <INTENT> specifications include these flags:\n" + " <INTENT> specifications include these flags:\n" + " [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" + " [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" + Loading core/java/android/app/ActivityManagerNative.java +36 −1 Original line number Original line Diff line number Diff line Loading @@ -1294,6 +1294,19 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; 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); return super.onTransact(code, data, reply, flags); Loading Loading @@ -2875,5 +2888,27 @@ class ActivityManagerProxy implements IActivityManager reply.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; private IBinder mRemote; } } core/java/android/app/ActivityThread.java +37 −0 Original line number Original line Diff line number Diff line Loading @@ -356,6 +356,11 @@ public final class ActivityThread { ParcelFileDescriptor fd; ParcelFileDescriptor fd; } } private static final class DumpHeapData { String path; ParcelFileDescriptor fd; } private final class ApplicationThread extends ApplicationThreadNative { private final class ApplicationThread extends ApplicationThreadNative { private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s"; private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s"; private static final String ONE_COUNT_COLUMN = "%17s %8d"; private static final String ONE_COUNT_COLUMN = "%17s %8d"; Loading Loading @@ -623,6 +628,13 @@ public final class ActivityThread { queueOrSendMessage(H.PROFILER_CONTROL, pcd, start ? 1 : 0); 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) { public void setSchedulingGroup(int group) { // Note: do this immediately, since going into the foreground // Note: do this immediately, since going into the foreground // should happen regardless of what pending work we have to do // should happen regardless of what pending work we have to do Loading Loading @@ -874,6 +886,7 @@ public final class ActivityThread { public static final int ENABLE_JIT = 132; public static final int ENABLE_JIT = 132; public static final int DISPATCH_PACKAGE_BROADCAST = 133; public static final int DISPATCH_PACKAGE_BROADCAST = 133; public static final int SCHEDULE_CRASH = 134; public static final int SCHEDULE_CRASH = 134; public static final int DUMP_HEAP = 135; String codeToString(int code) { String codeToString(int code) { if (localLOGV) { if (localLOGV) { switch (code) { switch (code) { Loading Loading @@ -912,6 +925,7 @@ public final class ActivityThread { case ENABLE_JIT: return "ENABLE_JIT"; case ENABLE_JIT: return "ENABLE_JIT"; case DISPATCH_PACKAGE_BROADCAST: return "DISPATCH_PACKAGE_BROADCAST"; case DISPATCH_PACKAGE_BROADCAST: return "DISPATCH_PACKAGE_BROADCAST"; case SCHEDULE_CRASH: return "SCHEDULE_CRASH"; case SCHEDULE_CRASH: return "SCHEDULE_CRASH"; case DUMP_HEAP: return "DUMP_HEAP"; } } } } return "(unknown)"; return "(unknown)"; Loading Loading @@ -1037,6 +1051,9 @@ public final class ActivityThread { break; break; case SCHEDULE_CRASH: case SCHEDULE_CRASH: throw new RemoteServiceException((String)msg.obj); throw new RemoteServiceException((String)msg.obj); case DUMP_HEAP: handleDumpHeap(msg.arg1 != 0, (DumpHeapData)msg.obj); break; } } } } Loading Loading @@ -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) { final void handleDispatchPackageBroadcast(int cmd, String[] packages) { boolean hasPkgInfo = false; boolean hasPkgInfo = false; if (packages != null) { if (packages != null) { Loading core/java/android/app/ApplicationThreadNative.java +28 −0 Original line number Original line Diff line number Diff line Loading @@ -403,6 +403,17 @@ public abstract class ApplicationThreadNative extends Binder scheduleCrash(msg); scheduleCrash(msg); return true; 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); return super.onTransact(code, data, reply, flags); Loading Loading @@ -829,5 +840,22 @@ class ApplicationThreadProxy implements IApplicationThread { data.recycle(); 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(); } } } core/java/android/app/IActivityManager.java +6 −1 Original line number Original line Diff line number Diff line Loading @@ -317,6 +317,10 @@ public interface IActivityManager extends IInterface { public void crashApplication(int uid, int initialPid, String packageName, public void crashApplication(int uid, int initialPid, String packageName, String message) throws RemoteException; 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 * Private non-Binder interfaces */ */ Loading Loading @@ -533,4 +537,5 @@ public interface IActivityManager extends IInterface { int SET_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+111; int SET_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+111; int IS_TOP_ACTIVITY_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+112; int IS_TOP_ACTIVITY_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+112; int CRASH_APPLICATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+113; int CRASH_APPLICATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+113; int DUMP_HEAP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+114; } } Loading
cmds/am/src/com/android/commands/am/Am.java +26 −0 Original line number Original line Diff line number Diff line Loading @@ -98,6 +98,8 @@ public class Am { sendBroadcast(); sendBroadcast(); } else if (op.equals("profile")) { } else if (op.equals("profile")) { runProfile(); runProfile(); } else if (op.equals("dumpheap")) { runDumpHeap(); } else { } else { throw new IllegalArgumentException("Unknown command: " + op); throw new IllegalArgumentException("Unknown command: " + op); } } Loading Loading @@ -424,6 +426,28 @@ public class Am { } } } } private void runDumpHeap() throws Exception { boolean managed = !"-n".equals(nextOption()); String process = nextArgRequired(); String heapFile = nextArgRequired(); ParcelFileDescriptor fd = null; try { fd = ParcelFileDescriptor.open( new File(heapFile), ParcelFileDescriptor.MODE_CREATE | ParcelFileDescriptor.MODE_TRUNCATE | ParcelFileDescriptor.MODE_READ_WRITE); } catch (FileNotFoundException e) { System.err.println("Error: Unable to open file: " + heapFile); return; } if (!mAm.dumpHeap(process, managed, heapFile, fd)) { throw new AndroidException("HEAP DUMP FAILED on process " + process); } } private class IntentReceiver extends IIntentReceiver.Stub { private class IntentReceiver extends IIntentReceiver.Stub { private boolean mFinished = false; private boolean mFinished = false; Loading Loading @@ -593,6 +617,8 @@ public class Am { "\n" + "\n" + " start profiling: am profile <PROCESS> start <FILE>\n" + " start profiling: am profile <PROCESS> start <FILE>\n" + " stop profiling: am profile <PROCESS> stop\n" + " stop profiling: am profile <PROCESS> stop\n" + " dump heap: am dumpheap [flags] <PROCESS> <FILE>\n" + " -n: dump native heap instead of managed heap\n" + "\n" + "\n" + " <INTENT> specifications include these flags:\n" + " <INTENT> specifications include these flags:\n" + " [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" + " [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" + Loading
core/java/android/app/ActivityManagerNative.java +36 −1 Original line number Original line Diff line number Diff line Loading @@ -1294,6 +1294,19 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; 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); return super.onTransact(code, data, reply, flags); Loading Loading @@ -2875,5 +2888,27 @@ class ActivityManagerProxy implements IActivityManager reply.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; private IBinder mRemote; } }
core/java/android/app/ActivityThread.java +37 −0 Original line number Original line Diff line number Diff line Loading @@ -356,6 +356,11 @@ public final class ActivityThread { ParcelFileDescriptor fd; ParcelFileDescriptor fd; } } private static final class DumpHeapData { String path; ParcelFileDescriptor fd; } private final class ApplicationThread extends ApplicationThreadNative { private final class ApplicationThread extends ApplicationThreadNative { private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s"; private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s"; private static final String ONE_COUNT_COLUMN = "%17s %8d"; private static final String ONE_COUNT_COLUMN = "%17s %8d"; Loading Loading @@ -623,6 +628,13 @@ public final class ActivityThread { queueOrSendMessage(H.PROFILER_CONTROL, pcd, start ? 1 : 0); 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) { public void setSchedulingGroup(int group) { // Note: do this immediately, since going into the foreground // Note: do this immediately, since going into the foreground // should happen regardless of what pending work we have to do // should happen regardless of what pending work we have to do Loading Loading @@ -874,6 +886,7 @@ public final class ActivityThread { public static final int ENABLE_JIT = 132; public static final int ENABLE_JIT = 132; public static final int DISPATCH_PACKAGE_BROADCAST = 133; public static final int DISPATCH_PACKAGE_BROADCAST = 133; public static final int SCHEDULE_CRASH = 134; public static final int SCHEDULE_CRASH = 134; public static final int DUMP_HEAP = 135; String codeToString(int code) { String codeToString(int code) { if (localLOGV) { if (localLOGV) { switch (code) { switch (code) { Loading Loading @@ -912,6 +925,7 @@ public final class ActivityThread { case ENABLE_JIT: return "ENABLE_JIT"; case ENABLE_JIT: return "ENABLE_JIT"; case DISPATCH_PACKAGE_BROADCAST: return "DISPATCH_PACKAGE_BROADCAST"; case DISPATCH_PACKAGE_BROADCAST: return "DISPATCH_PACKAGE_BROADCAST"; case SCHEDULE_CRASH: return "SCHEDULE_CRASH"; case SCHEDULE_CRASH: return "SCHEDULE_CRASH"; case DUMP_HEAP: return "DUMP_HEAP"; } } } } return "(unknown)"; return "(unknown)"; Loading Loading @@ -1037,6 +1051,9 @@ public final class ActivityThread { break; break; case SCHEDULE_CRASH: case SCHEDULE_CRASH: throw new RemoteServiceException((String)msg.obj); throw new RemoteServiceException((String)msg.obj); case DUMP_HEAP: handleDumpHeap(msg.arg1 != 0, (DumpHeapData)msg.obj); break; } } } } Loading Loading @@ -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) { final void handleDispatchPackageBroadcast(int cmd, String[] packages) { boolean hasPkgInfo = false; boolean hasPkgInfo = false; if (packages != null) { if (packages != null) { Loading
core/java/android/app/ApplicationThreadNative.java +28 −0 Original line number Original line Diff line number Diff line Loading @@ -403,6 +403,17 @@ public abstract class ApplicationThreadNative extends Binder scheduleCrash(msg); scheduleCrash(msg); return true; 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); return super.onTransact(code, data, reply, flags); Loading Loading @@ -829,5 +840,22 @@ class ApplicationThreadProxy implements IApplicationThread { data.recycle(); 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(); } } }
core/java/android/app/IActivityManager.java +6 −1 Original line number Original line Diff line number Diff line Loading @@ -317,6 +317,10 @@ public interface IActivityManager extends IInterface { public void crashApplication(int uid, int initialPid, String packageName, public void crashApplication(int uid, int initialPid, String packageName, String message) throws RemoteException; 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 * Private non-Binder interfaces */ */ Loading Loading @@ -533,4 +537,5 @@ public interface IActivityManager extends IInterface { int SET_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+111; int SET_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+111; int IS_TOP_ACTIVITY_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+112; int IS_TOP_ACTIVITY_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+112; int CRASH_APPLICATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+113; int CRASH_APPLICATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+113; int DUMP_HEAP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+114; } }