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 <JNIHelp.h> 22 #include <jni.h> 23 #include <android_runtime/AndroidRuntime.h> 24 25 #include <utils/Log.h> 26 27 #include <fcntl.h> 28 #include <errno.h> 29 #include <sys/types.h> 30 #include <sys/stat.h> 31 32 #if defined(__arm__) 33 extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize, 34 size_t* infoSize, size_t* totalMemory, size_t* backtraceSize); 35 36 extern "C" void free_malloc_leak_info(uint8_t* info); 37 #endif 38 39 #define MAPS_FILE_SIZE 65 * 1024 40 41 struct Header { 42 size_t mapSize; 43 size_t allocSize; 44 size_t allocInfoSize; 45 size_t totalMemory; 46 size_t backtraceSize; 47 }; 48 49 namespace android { 50 51 /* 52 * Retrieve the native heap information and the info from /proc/<self>/maps, 53 * copy them into a byte[] with a "struct Header" that holds data offsets, 54 * and return the array. 55 */ 56 static jbyteArray getLeakInfo(JNIEnv *env, jobject clazz) 57 { 58 #if defined(__arm__) 59 // get the info in /proc/[pid]/map 60 Header header; 61 memset(&header, 0, sizeof(header)); 62 63 pid_t pid = getpid(); 64 65 char path[FILENAME_MAX]; 66 sprintf(path, "/proc/%d/maps", pid); 67 68 struct stat sb; 69 int ret = stat(path, &sb); 70 71 uint8_t* mapsFile = NULL; 72 if (ret == 0) { 73 mapsFile = (uint8_t*)malloc(MAPS_FILE_SIZE); 74 int fd = open(path, O_RDONLY); 75 76 if (mapsFile != NULL && fd != -1) { 77 int amount = 0; 78 do { 79 uint8_t* ptr = mapsFile + header.mapSize; 80 amount = read(fd, ptr, MAPS_FILE_SIZE); 81 if (amount <= 0) { 82 if (errno != EINTR) 83 break; 84 else 85 continue; 86 } 87 header.mapSize += amount; 88 } while (header.mapSize < MAPS_FILE_SIZE); 89 90 LOGD("**** read %d bytes from '%s'", (int) header.mapSize, path); 91 } 92 } 93 94 uint8_t* allocBytes; 95 get_malloc_leak_info(&allocBytes, &header.allocSize, &header.allocInfoSize, 96 &header.totalMemory, &header.backtraceSize); 97 98 jbyte* bytes = NULL; 99 jbyte* ptr = NULL; 100 jbyteArray array = env->NewByteArray(sizeof(Header) + header.mapSize + header.allocSize); 101 if (array == NULL) { 102 goto done; 103 } 104 105 bytes = env->GetByteArrayElements(array, NULL); 106 ptr = bytes; 107 108 // LOGD("*** mapSize: %d allocSize: %d allocInfoSize: %d totalMemory: %d", 109 // header.mapSize, header.allocSize, header.allocInfoSize, header.totalMemory); 110 111 memcpy(ptr, &header, sizeof(header)); 112 ptr += sizeof(header); 113 114 if (header.mapSize > 0 && mapsFile != NULL) { 115 memcpy(ptr, mapsFile, header.mapSize); 116 ptr += header.mapSize; 117 } 118 119 memcpy(ptr, allocBytes, header.allocSize); 120 env->ReleaseByteArrayElements(array, bytes, 0); 121 122 done: 123 if (mapsFile != NULL) { 124 free(mapsFile); 125 } 126 // free the info up! 127 free_malloc_leak_info(allocBytes); 128 129 return array; 130 #else 131 return NULL; 132 #endif 133 } 134 135 static JNINativeMethod method_table[] = { 136 { "getLeakInfo", "()[B", (void*)getLeakInfo }, 137 }; 138 139 int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env) 140 { 141 return AndroidRuntime::registerNativeMethods(env, "android/ddm/DdmHandleNativeHeap", method_table, NELEM(method_table)); 142 } 143 144 }; 145