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 #include <sys/time.h> 17 #include <cutils/open_memstream.h> 18 #include <time.h> 19 #include <errno.h> 20 #include "Hprof.h" 21 22 #define HPROF_MAGIC_STRING "JAVA PROFILE 1.0.3" 23 24 #define U2_TO_BUF_BE(buf, offset, value) \ 25 do { \ 26 unsigned char *buf_ = (unsigned char *)(buf); \ 27 int offset_ = (int)(offset); \ 28 u2 value_ = (u2)(value); \ 29 buf_[offset_ + 0] = (unsigned char)(value_ >> 8); \ 30 buf_[offset_ + 1] = (unsigned char)(value_ ); \ 31 } while (0) 32 33 #define U4_TO_BUF_BE(buf, offset, value) \ 34 do { \ 35 unsigned char *buf_ = (unsigned char *)(buf); \ 36 int offset_ = (int)(offset); \ 37 u4 value_ = (u4)(value); \ 38 buf_[offset_ + 0] = (unsigned char)(value_ >> 24); \ 39 buf_[offset_ + 1] = (unsigned char)(value_ >> 16); \ 40 buf_[offset_ + 2] = (unsigned char)(value_ >> 8); \ 41 buf_[offset_ + 3] = (unsigned char)(value_ ); \ 42 } while (0) 43 44 #define U8_TO_BUF_BE(buf, offset, value) \ 45 do { \ 46 unsigned char *buf_ = (unsigned char *)(buf); \ 47 int offset_ = (int)(offset); \ 48 u8 value_ = (u8)(value); \ 49 buf_[offset_ + 0] = (unsigned char)(value_ >> 56); \ 50 buf_[offset_ + 1] = (unsigned char)(value_ >> 48); \ 51 buf_[offset_ + 2] = (unsigned char)(value_ >> 40); \ 52 buf_[offset_ + 3] = (unsigned char)(value_ >> 32); \ 53 buf_[offset_ + 4] = (unsigned char)(value_ >> 24); \ 54 buf_[offset_ + 5] = (unsigned char)(value_ >> 16); \ 55 buf_[offset_ + 6] = (unsigned char)(value_ >> 8); \ 56 buf_[offset_ + 7] = (unsigned char)(value_ ); \ 57 } while (0) 58 59 /* 60 * Initialize an hprof context struct. 61 * 62 * This will take ownership of "fileName". 63 * 64 * NOTE: ctx is expected to have been zeroed out prior to calling this 65 * function. 66 */ 67 void hprofContextInit(hprof_context_t *ctx, char *fileName, int fd, 68 bool writeHeader, bool directToDdms) 69 { 70 /* 71 * Have to do this here, because it must happen after we 72 * memset the struct (want to treat fileDataPtr/fileDataSize 73 * as read-only while the file is open). 74 */ 75 FILE* fp = open_memstream(&ctx->fileDataPtr, &ctx->fileDataSize); 76 if (fp == NULL) { 77 /* not expected */ 78 ALOGE("hprof: open_memstream failed: %s", strerror(errno)); 79 dvmAbort(); 80 } 81 82 ctx->directToDdms = directToDdms; 83 ctx->fileName = fileName; 84 ctx->memFp = fp; 85 ctx->fd = fd; 86 87 ctx->curRec.allocLen = 128; 88 ctx->curRec.body = (unsigned char *)malloc(ctx->curRec.allocLen); 89 //xxx check for/return an error 90 91 if (writeHeader) { 92 char magic[] = HPROF_MAGIC_STRING; 93 unsigned char buf[4]; 94 struct timeval now; 95 u8 nowMs; 96 97 /* Write the file header. 98 * 99 * [u1]*: NUL-terminated magic string. 100 */ 101 fwrite(magic, 1, sizeof(magic), fp); 102 103 /* u4: size of identifiers. We're using addresses 104 * as IDs, so make sure a pointer fits. 105 */ 106 U4_TO_BUF_BE(buf, 0, sizeof(void *)); 107 fwrite(buf, 1, sizeof(u4), fp); 108 109 /* The current time, in milliseconds since 0:00 GMT, 1/1/70. 110 */ 111 if (gettimeofday(&now, NULL) < 0) { 112 nowMs = 0; 113 } else { 114 nowMs = (u8)now.tv_sec * 1000 + now.tv_usec / 1000; 115 } 116 117 /* u4: high word of the 64-bit time. 118 */ 119 U4_TO_BUF_BE(buf, 0, (u4)(nowMs >> 32)); 120 fwrite(buf, 1, sizeof(u4), fp); 121 122 /* u4: low word of the 64-bit time. 123 */ 124 U4_TO_BUF_BE(buf, 0, (u4)(nowMs & 0xffffffffULL)); 125 fwrite(buf, 1, sizeof(u4), fp); //xxx fix the time 126 } 127 } 128 129 int hprofFlushRecord(hprof_record_t *rec, FILE *fp) 130 { 131 if (rec->dirty) { 132 unsigned char headBuf[sizeof (u1) + 2 * sizeof (u4)]; 133 int nb; 134 135 headBuf[0] = rec->tag; 136 U4_TO_BUF_BE(headBuf, 1, rec->time); 137 U4_TO_BUF_BE(headBuf, 5, rec->length); 138 139 nb = fwrite(headBuf, 1, sizeof(headBuf), fp); 140 if (nb != sizeof(headBuf)) { 141 return UNIQUE_ERROR(); 142 } 143 nb = fwrite(rec->body, 1, rec->length, fp); 144 if (nb != (int)rec->length) { 145 return UNIQUE_ERROR(); 146 } 147 148 rec->dirty = false; 149 } 150 //xxx if we used less than half (or whatever) of allocLen, shrink the buffer. 151 152 return 0; 153 } 154 155 int hprofFlushCurrentRecord(hprof_context_t *ctx) 156 { 157 return hprofFlushRecord(&ctx->curRec, ctx->memFp); 158 } 159 160 int hprofStartNewRecord(hprof_context_t *ctx, u1 tag, u4 time) 161 { 162 hprof_record_t *rec = &ctx->curRec; 163 int err; 164 165 err = hprofFlushRecord(rec, ctx->memFp); 166 if (err != 0) { 167 return err; 168 } else if (rec->dirty) { 169 return UNIQUE_ERROR(); 170 } 171 172 rec->dirty = true; 173 rec->tag = tag; 174 rec->time = time; 175 rec->length = 0; 176 177 return 0; 178 } 179 180 static inline int guaranteeRecordAppend(hprof_record_t *rec, size_t nmore) 181 { 182 size_t minSize; 183 184 minSize = rec->length + nmore; 185 if (minSize > rec->allocLen) { 186 unsigned char *newBody; 187 size_t newAllocLen; 188 189 newAllocLen = rec->allocLen * 2; 190 if (newAllocLen < minSize) { 191 newAllocLen = rec->allocLen + nmore + nmore/2; 192 } 193 newBody = (unsigned char *)realloc(rec->body, newAllocLen); 194 if (newBody != NULL) { 195 rec->body = newBody; 196 rec->allocLen = newAllocLen; 197 } else { 198 //TODO: set an error flag so future ops will fail 199 return UNIQUE_ERROR(); 200 } 201 } 202 203 assert(rec->length + nmore <= rec->allocLen); 204 return 0; 205 } 206 207 int hprofAddU1ListToRecord(hprof_record_t *rec, const u1 *values, 208 size_t numValues) 209 { 210 int err; 211 212 err = guaranteeRecordAppend(rec, numValues); 213 if (err != 0) { 214 return err; 215 } 216 217 memcpy(rec->body + rec->length, values, numValues); 218 rec->length += numValues; 219 220 return 0; 221 } 222 223 int hprofAddU1ToRecord(hprof_record_t *rec, u1 value) 224 { 225 int err; 226 227 err = guaranteeRecordAppend(rec, 1); 228 if (err != 0) { 229 return err; 230 } 231 232 rec->body[rec->length++] = value; 233 234 return 0; 235 } 236 237 int hprofAddUtf8StringToRecord(hprof_record_t *rec, const char *str) 238 { 239 /* The terminating NUL character is NOT written. 240 */ 241 //xxx don't do a strlen; add and grow as necessary, until NUL 242 return hprofAddU1ListToRecord(rec, (const u1 *)str, strlen(str)); 243 } 244 245 int hprofAddU2ListToRecord(hprof_record_t *rec, const u2 *values, 246 size_t numValues) 247 { 248 int err = guaranteeRecordAppend(rec, numValues * 2); 249 if (err != 0) { 250 return err; 251 } 252 253 //xxx this can be way smarter 254 //xxx also, don't do this bytewise if aligned and on a matching-endian arch 255 unsigned char *insert = rec->body + rec->length; 256 for (size_t i = 0; i < numValues; i++) { 257 U2_TO_BUF_BE(insert, 0, *values++); 258 insert += sizeof(*values); 259 } 260 rec->length += numValues * 2; 261 262 return 0; 263 } 264 265 int hprofAddU2ToRecord(hprof_record_t *rec, u2 value) 266 { 267 return hprofAddU2ListToRecord(rec, &value, 1); 268 } 269 270 int hprofAddU4ListToRecord(hprof_record_t *rec, const u4 *values, 271 size_t numValues) 272 { 273 int err = guaranteeRecordAppend(rec, numValues * 4); 274 if (err != 0) { 275 return err; 276 } 277 278 //xxx this can be way smarter 279 //xxx also, don't do this bytewise if aligned and on a matching-endian arch 280 unsigned char *insert = rec->body + rec->length; 281 for (size_t i = 0; i < numValues; i++) { 282 U4_TO_BUF_BE(insert, 0, *values++); 283 insert += sizeof(*values); 284 } 285 rec->length += numValues * 4; 286 287 return 0; 288 } 289 290 int hprofAddU4ToRecord(hprof_record_t *rec, u4 value) 291 { 292 return hprofAddU4ListToRecord(rec, &value, 1); 293 } 294 295 int hprofAddU8ListToRecord(hprof_record_t *rec, const u8 *values, 296 size_t numValues) 297 { 298 int err = guaranteeRecordAppend(rec, numValues * 8); 299 if (err != 0) { 300 return err; 301 } 302 303 //xxx this can be way smarter 304 //xxx also, don't do this bytewise if aligned and on a matching-endian arch 305 unsigned char *insert = rec->body + rec->length; 306 for (size_t i = 0; i < numValues; i++) { 307 U8_TO_BUF_BE(insert, 0, *values++); 308 insert += sizeof(*values); 309 } 310 rec->length += numValues * 8; 311 312 return 0; 313 } 314 315 int hprofAddU8ToRecord(hprof_record_t *rec, u8 value) 316 { 317 return hprofAddU8ListToRecord(rec, &value, 1); 318 } 319