1 /* //device/libs/android_runtime/android_ddm_DdmHandleNativeHeap.cpp
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 ** http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17
18 #undef LOG_TAG
19 #define LOG_TAG "DdmHandleNativeHeap"
20
21 #include <nativehelper/JNIHelp.h>
22 #include <jni.h>
23 #include "core_jni_helpers.h"
24
25 #include <android-base/logging.h>
26 #include <bionic_malloc.h>
27
28 #include <utils/Log.h>
29 #include <utils/String8.h>
30
31 #include <fcntl.h>
32 #include <errno.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35
36 #define DDMS_HEADER_SIGNATURE 0x812345dd
37 #define DDMS_VERSION 2
38
39 struct Header {
40 #if defined(__LP64__)
41 uint32_t signature;
42 uint16_t version;
43 uint16_t pointerSize;
44 #endif
45 size_t mapSize;
46 size_t allocSize;
47 size_t allocInfoSize;
48 size_t totalMemory;
49 size_t backtraceSize;
50 };
51
52 namespace android {
53
ReadFile(const char * path,String8 & s)54 static void ReadFile(const char* path, String8& s) {
55 int fd = open(path, O_RDONLY | O_CLOEXEC);
56 if (fd != -1) {
57 char bytes[1024];
58 ssize_t byteCount;
59 while ((byteCount = TEMP_FAILURE_RETRY(read(fd, bytes, sizeof(bytes)))) > 0) {
60 s.append(bytes, byteCount);
61 }
62 close(fd);
63 }
64 }
65
66 /*
67 * Retrieve the native heap information and the info from /proc/self/maps,
68 * copy them into a byte[] with a "struct Header" that holds data offsets,
69 * and return the array.
70 */
DdmHandleNativeHeap_getLeakInfo(JNIEnv * env,jobject)71 static jbyteArray DdmHandleNativeHeap_getLeakInfo(JNIEnv* env, jobject) {
72 Header header;
73 memset(&header, 0, sizeof(header));
74
75 String8 maps;
76 ReadFile("/proc/self/maps", maps);
77 header.mapSize = maps.size();
78
79 android_mallopt_leak_info_t leak_info;
80 if (!android_mallopt(M_GET_MALLOC_LEAK_INFO, &leak_info, sizeof(leak_info))) {
81 PLOG(ERROR) << "*** Failed to get malloc leak info";
82 return nullptr;
83 }
84
85 header.allocSize = leak_info.overall_size;
86 header.allocInfoSize = leak_info.info_size;
87 header.totalMemory = leak_info.total_memory;
88 header.backtraceSize = leak_info.backtrace_size;
89
90 ALOGD("*** mapSize: %zu allocSize: %zu allocInfoSize: %zu totalMemory: %zu",
91 header.mapSize, header.allocSize, header.allocInfoSize, header.totalMemory);
92
93 #if defined(__LP64__)
94 header.signature = DDMS_HEADER_SIGNATURE;
95 header.version = DDMS_VERSION;
96 header.pointerSize = sizeof(void*);
97 #endif
98
99 jbyteArray array = env->NewByteArray(sizeof(Header) + header.mapSize + header.allocSize);
100 if (array != NULL) {
101 env->SetByteArrayRegion(array, 0,
102 sizeof(header), reinterpret_cast<jbyte*>(&header));
103 env->SetByteArrayRegion(array, sizeof(header),
104 maps.size(), reinterpret_cast<const jbyte*>(maps.string()));
105 env->SetByteArrayRegion(array, sizeof(header) + maps.size(),
106 header.allocSize, reinterpret_cast<jbyte*>(leak_info.buffer));
107 }
108
109 android_mallopt(M_FREE_MALLOC_LEAK_INFO, &leak_info, sizeof(leak_info));
110 return array;
111 }
112
113 static const JNINativeMethod method_table[] = {
114 { "getLeakInfo", "()[B", (void*) DdmHandleNativeHeap_getLeakInfo },
115 };
116
register_android_ddm_DdmHandleNativeHeap(JNIEnv * env)117 int register_android_ddm_DdmHandleNativeHeap(JNIEnv* env) {
118 return RegisterMethodsOrDie(env, "android/ddm/DdmHandleNativeHeap", method_table,
119 NELEM(method_table));
120 }
121
122 };
123