19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* //device/libs/android_runtime/android_ddm_DdmHandleNativeHeap.cpp
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project**
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** Copyright 2006, The Android Open Source Project
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project**
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** you may not use this file except in compliance with the License.
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** You may obtain a copy of the License at
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project**
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project**     http://www.apache.org/licenses/LICENSE-2.0
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project**
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** Unless required by applicable law or agreed to in writing, software
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** distributed under the License is distributed on an "AS IS" BASIS,
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** See the License for the specific language governing permissions and
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** limitations under the License.
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project*/
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#undef LOG_TAG
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define LOG_TAG "DdmHandleNativeHeap"
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <JNIHelp.h>
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <jni.h>
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <android_runtime/AndroidRuntime.h>
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Log.h>
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <fcntl.h>
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <errno.h>
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/types.h>
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/stat.h>
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#if defined(__arm__)
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectextern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectextern "C" void free_malloc_leak_info(uint8_t* info);
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define MAPS_FILE_SIZE 65 * 1024
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstruct Header {
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    size_t mapSize;
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    size_t allocSize;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    size_t allocInfoSize;
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    size_t totalMemory;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    size_t backtraceSize;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectnamespace android {
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Retrieve the native heap information and the info from /proc/<self>/maps,
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * copy them into a byte[] with a "struct Header" that holds data offsets,
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and return the array.
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jbyteArray getLeakInfo(JNIEnv *env, jobject clazz)
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#if defined(__arm__)
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // get the info in /proc/[pid]/map
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Header header;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    memset(&header, 0, sizeof(header));
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pid_t pid = getpid();
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char path[FILENAME_MAX];
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sprintf(path, "/proc/%d/maps", pid);
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct stat sb;
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int ret = stat(path, &sb);
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    uint8_t* mapsFile = NULL;
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (ret == 0) {
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mapsFile = (uint8_t*)malloc(MAPS_FILE_SIZE);
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int fd = open(path, O_RDONLY);
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mapsFile != NULL && fd != -1) {
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int amount = 0;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            do {
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                uint8_t* ptr = mapsFile + header.mapSize;
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                amount = read(fd, ptr, MAPS_FILE_SIZE);
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (amount <= 0) {
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (errno != EINTR)
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    else
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        continue;
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                header.mapSize += amount;
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } while (header.mapSize < MAPS_FILE_SIZE);
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOGD("**** read %d bytes from '%s'", (int) header.mapSize, path);
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    uint8_t* allocBytes;
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    get_malloc_leak_info(&allocBytes, &header.allocSize, &header.allocInfoSize,
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            &header.totalMemory, &header.backtraceSize);
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    jbyte* bytes = NULL;
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    jbyte* ptr = NULL;
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    jbyteArray array = env->NewByteArray(sizeof(Header) + header.mapSize + header.allocSize);
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (array == NULL) {
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto done;
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    bytes = env->GetByteArrayElements(array, NULL);
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ptr = bytes;
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//    LOGD("*** mapSize: %d allocSize: %d allocInfoSize: %d totalMemory: %d",
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//            header.mapSize, header.allocSize, header.allocInfoSize, header.totalMemory);
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    memcpy(ptr, &header, sizeof(header));
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ptr += sizeof(header);
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (header.mapSize > 0 && mapsFile != NULL) {
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        memcpy(ptr, mapsFile, header.mapSize);
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ptr += header.mapSize;
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    memcpy(ptr, allocBytes, header.allocSize);
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    env->ReleaseByteArrayElements(array, bytes, 0);
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectdone:
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (mapsFile != NULL) {
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        free(mapsFile);
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // free the info up!
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    free_malloc_leak_info(allocBytes);
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return array;
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#else
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NULL;
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic JNINativeMethod method_table[] = {
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { "getLeakInfo", "()[B", (void*)getLeakInfo },
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint register_android_ddm_DdmHandleNativeHeap(JNIEnv *env)
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return AndroidRuntime::registerNativeMethods(env, "android/ddm/DdmHandleNativeHeap", method_table, NELEM(method_table));
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
145