Merge "Implement dumpheap -m."

This commit is contained in:
Christopher Ferris
2017-07-13 20:10:47 +00:00
committed by Android (Google) Code Review
7 changed files with 75 additions and 25 deletions

View File

@@ -658,6 +658,8 @@ public final class ActivityThread {
}
static final class DumpHeapData {
public boolean managed;
public boolean mallocInfo;
public boolean runGc;
String path;
ParcelFileDescriptor fd;
@@ -1025,12 +1027,15 @@ public final class ActivityThread {
}
@Override
public void dumpHeap(boolean managed, boolean runGc, String path, ParcelFileDescriptor fd) {
public void dumpHeap(boolean managed, boolean mallocInfo, boolean runGc, String path,
ParcelFileDescriptor fd) {
DumpHeapData dhd = new DumpHeapData();
dhd.managed = managed;
dhd.mallocInfo = mallocInfo;
dhd.runGc = runGc;
dhd.path = path;
dhd.fd = fd;
sendMessage(H.DUMP_HEAP, dhd, managed ? 1 : 0, 0, true /*async*/);
sendMessage(H.DUMP_HEAP, dhd, 0, 0, true /*async*/);
}
public void attachAgent(String agent) {
@@ -1762,7 +1767,7 @@ public final class ActivityThread {
case SCHEDULE_CRASH:
throw new RemoteServiceException((String)msg.obj);
case DUMP_HEAP:
handleDumpHeap(msg.arg1 != 0, (DumpHeapData)msg.obj);
handleDumpHeap((DumpHeapData) msg.obj);
break;
case DUMP_ACTIVITY:
handleDumpActivity((DumpComponentInfo)msg.obj);
@@ -5173,13 +5178,13 @@ public final class ActivityThread {
}
}
static final void handleDumpHeap(boolean managed, DumpHeapData dhd) {
static void handleDumpHeap(DumpHeapData dhd) {
if (dhd.runGc) {
System.gc();
System.runFinalization();
System.gc();
}
if (managed) {
if (dhd.managed) {
try {
Debug.dumpHprofData(dhd.path, dhd.fd.getFileDescriptor());
} catch (IOException e) {
@@ -5192,6 +5197,8 @@ public final class ActivityThread {
Slog.w(TAG, "Failure closing profile fd", e);
}
}
} else if (dhd.mallocInfo) {
Debug.dumpNativeMallocInfo(dhd.fd.getFileDescriptor());
} else {
Debug.dumpNativeHeap(dhd.fd.getFileDescriptor());
}

View File

@@ -277,8 +277,8 @@ interface IActivityManager {
int checkGrantUriPermission(int callingUid, in String targetPkg, in Uri uri,
int modeFlags, int userId);
// Cause the specified process to dump the specified heap.
boolean dumpHeap(in String process, int userId, boolean managed, boolean runGc, in String path,
in ParcelFileDescriptor fd);
boolean dumpHeap(in String process, int userId, boolean managed, boolean mallocInfo,
boolean runGc, in String path, in ParcelFileDescriptor fd);
int startActivities(in IApplicationThread caller, in String callingPackage,
in Intent[] intents, in String[] resolvedTypes, in IBinder resultTo,
in Bundle options, int userId);

View File

@@ -117,7 +117,8 @@ oneway interface IApplicationThread {
void scheduleSuicide();
void dispatchPackageBroadcast(int cmd, in String[] packages);
void scheduleCrash(in String msg);
void dumpHeap(boolean managed, boolean runGc, in String path, in ParcelFileDescriptor fd);
void dumpHeap(boolean managed, boolean mallocInfo, boolean runGc, in String path,
in ParcelFileDescriptor fd);
void dumpActivity(in ParcelFileDescriptor fd, IBinder servicetoken, in String prefix,
in String[] args);
void clearDnsCache();

View File

@@ -1813,6 +1813,13 @@ public final class Debug
*/
public static native void dumpNativeHeap(FileDescriptor fd);
/**
* Writes malloc info data to the specified file descriptor.
*
* @hide
*/
public static native void dumpNativeMallocInfo(FileDescriptor fd);
/**
* Returns a count of the extant instances of a class.
*

View File

@@ -48,10 +48,14 @@
namespace android
{
using UniqueFile = std::unique_ptr<FILE, decltype(&fclose)>;
static void safeFclose(FILE* fp) {
if (fp) fclose(fp);
}
using UniqueFile = std::unique_ptr<FILE, decltype(&safeFclose)>;
static inline UniqueFile MakeUniqueFile(const char* path, const char* mode) {
return UniqueFile(fopen(path, mode), fclose);
return UniqueFile(fopen(path, mode), safeFclose);
}
enum {
@@ -972,21 +976,16 @@ static void dumpNativeHeap(FILE* fp)
fprintf(fp, "END\n");
}
/*
* Dump the native heap, writing human-readable output to the specified
* file descriptor.
*/
static void android_os_Debug_dumpNativeHeap(JNIEnv* env, jobject clazz,
jobject fileDescriptor)
static bool openFile(JNIEnv* env, jobject fileDescriptor, UniqueFile& fp)
{
if (fileDescriptor == NULL) {
jniThrowNullPointerException(env, "fd == null");
return;
return false;
}
int origFd = jniGetFDFromFileDescriptor(env, fileDescriptor);
if (origFd < 0) {
jniThrowRuntimeException(env, "Invalid file descriptor");
return;
return false;
}
/* dup() the descriptor so we don't close the original with fclose() */
@@ -994,14 +993,28 @@ static void android_os_Debug_dumpNativeHeap(JNIEnv* env, jobject clazz,
if (fd < 0) {
ALOGW("dup(%d) failed: %s\n", origFd, strerror(errno));
jniThrowRuntimeException(env, "dup() failed");
return;
return false;
}
UniqueFile fp(fdopen(fd, "w"), fclose);
fp.reset(fdopen(fd, "w"));
if (fp == nullptr) {
ALOGW("fdopen(%d) failed: %s\n", fd, strerror(errno));
close(fd);
jniThrowRuntimeException(env, "fdopen() failed");
return false;
}
return true;
}
/*
* Dump the native heap, writing human-readable output to the specified
* file descriptor.
*/
static void android_os_Debug_dumpNativeHeap(JNIEnv* env, jobject,
jobject fileDescriptor)
{
UniqueFile fp(nullptr, safeFclose);
if (!openFile(env, fileDescriptor, fp)) {
return;
}
@@ -1010,6 +1023,21 @@ static void android_os_Debug_dumpNativeHeap(JNIEnv* env, jobject clazz,
ALOGD("Native heap dump complete.\n");
}
/*
* Dump the native malloc info, writing xml output to the specified
* file descriptor.
*/
static void android_os_Debug_dumpNativeMallocInfo(JNIEnv* env, jobject,
jobject fileDescriptor)
{
UniqueFile fp(nullptr, safeFclose);
if (!openFile(env, fileDescriptor, fp)) {
return;
}
malloc_info(0, fp.get());
}
static bool dumpTraces(JNIEnv* env, jint pid, jstring fileName, jint timeoutSecs,
DebuggerdDumpType dumpType) {
const ScopedUtfChars fileNameChars(env, fileName);
@@ -1070,6 +1098,8 @@ static const JNINativeMethod gMethods[] = {
(void*) android_os_Debug_getMemInfo },
{ "dumpNativeHeap", "(Ljava/io/FileDescriptor;)V",
(void*) android_os_Debug_dumpNativeHeap },
{ "dumpNativeMallocInfo", "(Ljava/io/FileDescriptor;)V",
(void*) android_os_Debug_dumpNativeMallocInfo },
{ "getBinderSentTransactions", "()I",
(void*) android_os_Debug_getBinderSentTransactions },
{ "getBinderReceivedTransactions", "()I",

View File

@@ -21631,7 +21631,8 @@ public class ActivityManagerService extends IActivityManager.Stub
if (DEBUG_PSS) Slog.d(TAG_PSS,
"Requesting dump heap from "
+ myProc + " to " + heapdumpFile);
thread.dumpHeap(/* managed=*/ true, /* runGc= */ false,
thread.dumpHeap(/* managed= */ true,
/* mallocInfo= */ false, /* runGc= */ false,
heapdumpFile.toString(), fd);
} catch (RemoteException e) {
}
@@ -23394,8 +23395,8 @@ public class ActivityManagerService extends IActivityManager.Stub
return proc;
}
public boolean dumpHeap(String process, int userId, boolean managed, boolean runGc,
String path, ParcelFileDescriptor fd) throws RemoteException {
public boolean dumpHeap(String process, int userId, boolean managed, boolean mallocInfo,
boolean runGc, String path, ParcelFileDescriptor fd) throws RemoteException {
try {
synchronized (this) {
@@ -23423,7 +23424,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
proc.thread.dumpHeap(managed, runGc, path, fd);
proc.thread.dumpHeap(managed, mallocInfo, runGc, path, fd);
fd = null;
return true;
}

View File

@@ -784,6 +784,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
int runDumpHeap(PrintWriter pw) throws RemoteException {
final PrintWriter err = getErrPrintWriter();
boolean managed = true;
boolean mallocInfo = false;
int userId = UserHandle.USER_CURRENT;
boolean runGc = false;
@@ -799,6 +800,9 @@ final class ActivityManagerShellCommand extends ShellCommand {
managed = false;
} else if (opt.equals("-g")) {
runGc = true;
} else if (opt.equals("-m")) {
managed = false;
mallocInfo = true;
} else {
err.println("Error: Unknown option: " + opt);
return -1;
@@ -814,7 +818,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
return -1;
}
if (!mInterface.dumpHeap(process, userId, managed, runGc, heapFile, fd)) {
if (!mInterface.dumpHeap(process, userId, managed, mallocInfo, runGc, heapFile, fd)) {
err.println("HEAP DUMP FAILED on process " + process);
return -1;
}