1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /* 18 * Preparation and completion of hprof data generation. The output is 19 * written into two files and then combined. This is necessary because 20 * we generate some of the data (strings and classes) while we dump the 21 * heap, and some analysis tools require that the class and string data 22 * appear first. 23 */ 24 #include "Hprof.h" 25 26 #include <string.h> 27 #include <unistd.h> 28 #include <fcntl.h> 29 #include <errno.h> 30 #include <sys/time.h> 31 #include <time.h> 32 33 34 #define kHeadSuffix "-hptemp" 35 36 hprof_context_t * 37 hprofStartup(const char *outputFileName, int fd, bool directToDdms) 38 { 39 hprofStartup_String(); 40 hprofStartup_Class(); 41 #if WITH_HPROF_STACK 42 hprofStartup_StackFrame(); 43 hprofStartup_Stack(); 44 #endif 45 46 hprof_context_t *ctx = malloc(sizeof(*ctx)); 47 if (ctx == NULL) { 48 LOGE("hprof: can't allocate context.\n"); 49 return NULL; 50 } 51 52 /* pass in name or descriptor of the output file */ 53 hprofContextInit(ctx, strdup(outputFileName), fd, false, directToDdms); 54 55 assert(ctx->memFp != NULL); 56 57 return ctx; 58 } 59 60 /* 61 * Finish up the hprof dump. Returns true on success. 62 */ 63 bool 64 hprofShutdown(hprof_context_t *tailCtx) 65 { 66 /* flush the "tail" portion of the output */ 67 hprofFlushCurrentRecord(tailCtx); 68 69 /* 70 * Create a new context struct for the start of the file. We 71 * heap-allocate it so we can share the "free" function. 72 */ 73 hprof_context_t *headCtx = malloc(sizeof(*headCtx)); 74 if (headCtx == NULL) { 75 LOGE("hprof: can't allocate context.\n"); 76 hprofFreeContext(tailCtx); 77 return false; 78 } 79 hprofContextInit(headCtx, strdup(tailCtx->fileName), tailCtx->fd, true, 80 tailCtx->directToDdms); 81 82 LOGI("hprof: dumping heap strings to \"%s\".\n", tailCtx->fileName); 83 hprofDumpStrings(headCtx); 84 hprofDumpClasses(headCtx); 85 86 /* Write a dummy stack trace record so the analysis 87 * tools don't freak out. 88 */ 89 hprofStartNewRecord(headCtx, HPROF_TAG_STACK_TRACE, HPROF_TIME); 90 hprofAddU4ToRecord(&headCtx->curRec, HPROF_NULL_STACK_TRACE); 91 hprofAddU4ToRecord(&headCtx->curRec, HPROF_NULL_THREAD); 92 hprofAddU4ToRecord(&headCtx->curRec, 0); // no frames 93 94 #if WITH_HPROF_STACK 95 hprofDumpStackFrames(headCtx); 96 hprofDumpStacks(headCtx); 97 #endif 98 99 hprofFlushCurrentRecord(headCtx); 100 101 hprofShutdown_Class(); 102 hprofShutdown_String(); 103 #if WITH_HPROF_STACK 104 hprofShutdown_Stack(); 105 hprofShutdown_StackFrame(); 106 #endif 107 108 /* flush to ensure memstream pointer and size are updated */ 109 fflush(headCtx->memFp); 110 fflush(tailCtx->memFp); 111 112 if (tailCtx->directToDdms) { 113 /* send the data off to DDMS */ 114 struct iovec iov[2]; 115 iov[0].iov_base = headCtx->fileDataPtr; 116 iov[0].iov_len = headCtx->fileDataSize; 117 iov[1].iov_base = tailCtx->fileDataPtr; 118 iov[1].iov_len = tailCtx->fileDataSize; 119 dvmDbgDdmSendChunkV(CHUNK_TYPE("HPDS"), iov, 2); 120 } else { 121 /* 122 * Open the output file, and copy the head and tail to it. 123 */ 124 assert(headCtx->fd == tailCtx->fd); 125 126 int outFd; 127 if (headCtx->fd >= 0) { 128 outFd = dup(headCtx->fd); 129 if (outFd < 0) { 130 LOGE("dup(%d) failed: %s\n", headCtx->fd, strerror(errno)); 131 /* continue to fail-handler below */ 132 } 133 } else { 134 outFd = open(tailCtx->fileName, O_WRONLY|O_CREAT, 0644); 135 if (outFd < 0) { 136 LOGE("can't open %s: %s\n", headCtx->fileName, strerror(errno)); 137 /* continue to fail-handler below */ 138 } 139 } 140 if (outFd < 0) { 141 hprofFreeContext(headCtx); 142 hprofFreeContext(tailCtx); 143 return false; 144 } 145 146 int result; 147 result = sysWriteFully(outFd, headCtx->fileDataPtr, 148 headCtx->fileDataSize, "hprof-head"); 149 result |= sysWriteFully(outFd, tailCtx->fileDataPtr, 150 tailCtx->fileDataSize, "hprof-tail"); 151 close(outFd); 152 if (result != 0) { 153 hprofFreeContext(headCtx); 154 hprofFreeContext(tailCtx); 155 return false; 156 } 157 } 158 159 /* throw out a log message for the benefit of "runhat" */ 160 LOGI("hprof: heap dump completed (%dKB)\n", 161 (headCtx->fileDataSize + tailCtx->fileDataSize + 1023) / 1024); 162 163 hprofFreeContext(headCtx); 164 hprofFreeContext(tailCtx); 165 166 return true; 167 } 168 169 /* 170 * Free any heap-allocated items in "ctx", and then free "ctx" itself. 171 */ 172 void 173 hprofFreeContext(hprof_context_t *ctx) 174 { 175 assert(ctx != NULL); 176 177 /* we don't own ctx->fd, do not close */ 178 179 if (ctx->memFp != NULL) 180 fclose(ctx->memFp); 181 free(ctx->curRec.body); 182 free(ctx->fileName); 183 free(ctx->fileDataPtr); 184 free(ctx); 185 } 186