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__)
33extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
34        size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
35
36extern "C" void free_malloc_leak_info(uint8_t* info);
37#endif
38
39#define MAPS_FILE_SIZE 65 * 1024
40
41struct Header {
42    size_t mapSize;
43    size_t allocSize;
44    size_t allocInfoSize;
45    size_t totalMemory;
46    size_t backtraceSize;
47};
48
49namespace 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 */
56static 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            ALOGD("**** 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//    ALOGD("*** 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
122done:
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
135static JNINativeMethod method_table[] = {
136    { "getLeakInfo", "()[B", (void*)getLeakInfo },
137};
138
139int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env)
140{
141    return AndroidRuntime::registerNativeMethods(env, "android/ddm/DdmHandleNativeHeap", method_table, NELEM(method_table));
142}
143
144};
145