diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 6fc14e768b64c..3696919734168 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -94,6 +94,7 @@ import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.Process; +import android.os.RemoteCallback; import android.os.RemoteException; import android.os.ServiceManager; import android.os.StrictMode; @@ -739,6 +740,7 @@ public final class ActivityThread extends ClientTransactionHandler { public boolean runGc; String path; ParcelFileDescriptor fd; + RemoteCallback finishCallback; } static final class UpdateCompatibilityData { @@ -998,13 +1000,14 @@ public final class ActivityThread extends ClientTransactionHandler { @Override public void dumpHeap(boolean managed, boolean mallocInfo, boolean runGc, String path, - ParcelFileDescriptor fd) { + ParcelFileDescriptor fd, RemoteCallback finishCallback) { DumpHeapData dhd = new DumpHeapData(); dhd.managed = managed; dhd.mallocInfo = mallocInfo; dhd.runGc = runGc; dhd.path = path; dhd.fd = fd; + dhd.finishCallback = finishCallback; sendMessage(H.DUMP_HEAP, dhd, 0, 0, true /*async*/); } @@ -5310,6 +5313,9 @@ public final class ActivityThread extends ClientTransactionHandler { } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } + if (dhd.finishCallback != null) { + dhd.finishCallback.sendResult(null); + } } final void handleDispatchPackageBroadcast(int cmd, String[] packages) { diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 569c2bd37b6a0..d22f578eeea98 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -63,6 +63,7 @@ import android.os.IBinder; import android.os.IProgressListener; import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; +import android.os.RemoteCallback; import android.os.StrictMode; import android.os.WorkSource; import android.service.voice.IVoiceInteractionSession; @@ -288,7 +289,8 @@ interface IActivityManager { int modeFlags, int userId); // Cause the specified process to dump the specified heap. boolean dumpHeap(in String process, int userId, boolean managed, boolean mallocInfo, - boolean runGc, in String path, in ParcelFileDescriptor fd); + boolean runGc, in String path, in ParcelFileDescriptor fd, + in RemoteCallback finishCallback); int startActivities(in IApplicationThread caller, in String callingPackage, in Intent[] intents, in String[] resolvedTypes, in IBinder resultTo, in Bundle options, int userId); diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl index ae9b83ec01222..fcb6c14d052cb 100644 --- a/core/java/android/app/IApplicationThread.aidl +++ b/core/java/android/app/IApplicationThread.aidl @@ -38,6 +38,7 @@ import android.os.IBinder; import android.os.IInterface; import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; +import android.os.RemoteCallback; import com.android.internal.app.IVoiceInteractor; import com.android.internal.content.ReferrerIntent; @@ -95,7 +96,7 @@ oneway interface IApplicationThread { void dispatchPackageBroadcast(int cmd, in String[] packages); void scheduleCrash(in String msg); void dumpHeap(boolean managed, boolean mallocInfo, boolean runGc, in String path, - in ParcelFileDescriptor fd); + in ParcelFileDescriptor fd, in RemoteCallback finishCallback); void dumpActivity(in ParcelFileDescriptor fd, IBinder servicetoken, in String prefix, in String[] args); void clearDnsCache(); diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java index 0906435db912f..2801f32430ef6 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java @@ -47,6 +47,7 @@ import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Parcelable; import android.os.PersistableBundle; +import android.os.RemoteCallback; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import android.support.test.filters.SmallTest; @@ -609,7 +610,7 @@ public class TransactionParcelTests { @Override public void dumpHeap(boolean managed, boolean mallocInfo, boolean runGc, String path, - ParcelFileDescriptor fd) { + ParcelFileDescriptor fd, RemoteCallback finishCallback) { } @Override diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index e1c9d047eb32d..900bf8fb607de 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -342,6 +342,7 @@ import android.os.PowerManager; import android.os.PowerManager.ServiceType; import android.os.PowerManagerInternal; import android.os.Process; +import android.os.RemoteCallback; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ResultReceiver; @@ -23972,7 +23973,8 @@ public class ActivityManagerService extends IActivityManager.Stub + myProc + " to " + heapdumpFile); thread.dumpHeap(/* managed= */ true, /* mallocInfo= */ false, /* runGc= */ false, - heapdumpFile.toString(), fd); + heapdumpFile.toString(), fd, + /* finishCallback= */ null); } catch (RemoteException e) { } } @@ -25865,8 +25867,9 @@ public class ActivityManagerService extends IActivityManager.Stub return proc; } + @Override public boolean dumpHeap(String process, int userId, boolean managed, boolean mallocInfo, - boolean runGc, String path, ParcelFileDescriptor fd) throws RemoteException { + boolean runGc, String path, ParcelFileDescriptor fd, RemoteCallback finishCallback) { try { synchronized (this) { @@ -25894,7 +25897,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } - proc.thread.dumpHeap(managed, mallocInfo, runGc, path, fd); + proc.thread.dumpHeap(managed, mallocInfo, runGc, path, fd, finishCallback); fd = null; return true; } diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index dc9a5adb5a0cb..256769713da9b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -56,6 +56,8 @@ import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.ParcelFileDescriptor; +import android.os.RemoteCallback; +import android.os.RemoteCallback.OnResultListener; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ShellCommand; @@ -65,6 +67,7 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.text.TextUtils; +import android.text.format.Time; import android.util.ArrayMap; import android.util.DebugUtils; import android.util.DisplayMetrics; @@ -89,6 +92,7 @@ import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.CountDownLatch; import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; @@ -872,7 +876,14 @@ final class ActivityManagerShellCommand extends ShellCommand { } } String process = getNextArgRequired(); - String heapFile = getNextArgRequired(); + String heapFile = getNextArg(); + if (heapFile == null) { + final Time t = new Time(); + t.set(System.currentTimeMillis()); + heapFile = "/data/local/tmp/heapdump-" + t.format("%Y%m%d-%H%M%S") + ".prof"; + } + pw.println("File: " + heapFile); + pw.flush(); File file = new File(heapFile); file.delete(); @@ -881,10 +892,28 @@ final class ActivityManagerShellCommand extends ShellCommand { return -1; } - if (!mInterface.dumpHeap(process, userId, managed, mallocInfo, runGc, heapFile, fd)) { + final CountDownLatch latch = new CountDownLatch(1); + + final RemoteCallback finishCallback = new RemoteCallback(new OnResultListener() { + @Override + public void onResult(Bundle result) { + latch.countDown(); + } + }, null); + + if (!mInterface.dumpHeap(process, userId, managed, mallocInfo, runGc, heapFile, fd, + finishCallback)) { err.println("HEAP DUMP FAILED on process " + process); return -1; } + pw.println("Waiting for dump to finish..."); + pw.flush(); + try { + latch.await(); + } catch (InterruptedException e) { + err.println("Caught InterruptedException"); + } + return 0; }