Misc.cpp revision b08e2b6017770e887f6072c1520b2d7f2ef6916c
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 * Miscellaneous utility functions. 19 */ 20#include "Dalvik.h" 21 22#include <stdlib.h> 23#include <stddef.h> 24#include <string.h> 25#include <strings.h> 26#include <ctype.h> 27#include <time.h> 28#include <sys/time.h> 29#include <fcntl.h> 30#include <cutils/ashmem.h> 31#include <sys/mman.h> 32 33/* 34 * Print a hex dump in this format: 35 * 3601234567: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff 0123456789abcdef\n 37 * 38 * If "mode" is kHexDumpLocal, we start at offset zero, and show a full 39 * 16 bytes on the first line. If it's kHexDumpMem, we make this look 40 * like a memory dump, using the actual address, outputting a partial line 41 * if "vaddr" isn't aligned on a 16-byte boundary. 42 * 43 * "priority" and "tag" determine the values passed to the log calls. 44 * 45 * Does not use printf() or other string-formatting calls. 46 */ 47void dvmPrintHexDumpEx(int priority, const char* tag, const void* vaddr, 48 size_t length, HexDumpMode mode) 49{ 50 static const char gHexDigit[] = "0123456789abcdef"; 51 const unsigned char* addr = (const unsigned char*)vaddr; 52 char out[77]; /* exact fit */ 53 unsigned int offset; /* offset to show while printing */ 54 char* hex; 55 char* asc; 56 int gap; 57 //int trickle = 0; 58 59 if (mode == kHexDumpLocal) 60 offset = 0; 61 else 62 offset = (int) addr; 63 64 memset(out, ' ', sizeof(out)-1); 65 out[8] = ':'; 66 out[sizeof(out)-2] = '\n'; 67 out[sizeof(out)-1] = '\0'; 68 69 gap = (int) offset & 0x0f; 70 while (length) { 71 unsigned int lineOffset = offset & ~0x0f; 72 int i, count; 73 74 hex = out; 75 asc = out + 59; 76 77 for (i = 0; i < 8; i++) { 78 *hex++ = gHexDigit[lineOffset >> 28]; 79 lineOffset <<= 4; 80 } 81 hex++; 82 hex++; 83 84 count = ((int)length > 16-gap) ? 16-gap : (int)length; /* cap length */ 85 assert(count != 0); 86 assert(count+gap <= 16); 87 88 if (gap) { 89 /* only on first line */ 90 hex += gap * 3; 91 asc += gap; 92 } 93 94 for (i = gap ; i < count+gap; i++) { 95 *hex++ = gHexDigit[*addr >> 4]; 96 *hex++ = gHexDigit[*addr & 0x0f]; 97 hex++; 98 if (*addr >= 0x20 && *addr < 0x7f /*isprint(*addr)*/) 99 *asc++ = *addr; 100 else 101 *asc++ = '.'; 102 addr++; 103 } 104 for ( ; i < 16; i++) { 105 /* erase extra stuff; only happens on last line */ 106 *hex++ = ' '; 107 *hex++ = ' '; 108 hex++; 109 *asc++ = ' '; 110 } 111 112 LOG_PRI(priority, tag, "%s", out); 113#if 0 //def HAVE_ANDROID_OS 114 /* 115 * We can overrun logcat easily by writing at full speed. On the 116 * other hand, we can make Eclipse time out if we're showing 117 * packet dumps while debugging JDWP. 118 */ 119 { 120 if (trickle++ == 8) { 121 trickle = 0; 122 usleep(20000); 123 } 124 } 125#endif 126 127 gap = 0; 128 length -= count; 129 offset += count; 130 } 131} 132 133 134/* 135 * Fill out a DebugOutputTarget, suitable for printing to the log. 136 */ 137void dvmCreateLogOutputTarget(DebugOutputTarget* target, int priority, 138 const char* tag) 139{ 140 assert(target != NULL); 141 assert(tag != NULL); 142 143 target->which = kDebugTargetLog; 144 target->data.log.priority = priority; 145 target->data.log.tag = tag; 146} 147 148/* 149 * Fill out a DebugOutputTarget suitable for printing to a file pointer. 150 */ 151void dvmCreateFileOutputTarget(DebugOutputTarget* target, FILE* fp) 152{ 153 assert(target != NULL); 154 assert(fp != NULL); 155 156 target->which = kDebugTargetFile; 157 target->data.file.fp = fp; 158} 159 160/* 161 * Free "target" and any associated data. 162 */ 163void dvmFreeOutputTarget(DebugOutputTarget* target) 164{ 165 free(target); 166} 167 168/* 169 * Print a debug message, to either a file or the log. 170 */ 171void dvmPrintDebugMessage(const DebugOutputTarget* target, const char* format, 172 ...) 173{ 174 va_list args; 175 176 va_start(args, format); 177 178 switch (target->which) { 179 case kDebugTargetLog: 180 LOG_PRI_VA(target->data.log.priority, target->data.log.tag, 181 format, args); 182 break; 183 case kDebugTargetFile: 184 vfprintf(target->data.file.fp, format, args); 185 break; 186 default: 187 LOGE("unexpected 'which' %d", target->which); 188 break; 189 } 190 191 va_end(args); 192} 193 194 195/* 196 * Return a newly-allocated string in which all occurrences of '.' have 197 * been changed to '/'. If we find a '/' in the original string, NULL 198 * is returned to avoid ambiguity. 199 */ 200char* dvmDotToSlash(const char* str) 201{ 202 char* newStr = strdup(str); 203 char* cp = newStr; 204 205 if (newStr == NULL) 206 return NULL; 207 208 while (*cp != '\0') { 209 if (*cp == '/') { 210 assert(false); 211 return NULL; 212 } 213 if (*cp == '.') 214 *cp = '/'; 215 cp++; 216 } 217 218 return newStr; 219} 220 221std::string dvmHumanReadableDescriptor(const char* descriptor) { 222 // Count the number of '['s to get the dimensionality. 223 const char* c = descriptor; 224 size_t dim = 0; 225 while (*c == '[') { 226 dim++; 227 c++; 228 } 229 230 // Reference or primitive? 231 if (*c == 'L') { 232 // "[[La/b/C;" -> "a.b.C[][]". 233 c++; // Skip the 'L'. 234 } else { 235 // "[[B" -> "byte[][]". 236 // To make life easier, we make primitives look like unqualified 237 // reference types. 238 switch (*c) { 239 case 'B': c = "byte;"; break; 240 case 'C': c = "char;"; break; 241 case 'D': c = "double;"; break; 242 case 'F': c = "float;"; break; 243 case 'I': c = "int;"; break; 244 case 'J': c = "long;"; break; 245 case 'S': c = "short;"; break; 246 case 'Z': c = "boolean;"; break; 247 default: return descriptor; 248 } 249 } 250 251 // At this point, 'c' is a string of the form "fully/qualified/Type;" 252 // or "primitive;". Rewrite the type with '.' instead of '/': 253 std::string result; 254 const char* p = c; 255 while (*p != ';') { 256 char ch = *p++; 257 if (ch == '/') { 258 ch = '.'; 259 } 260 result.push_back(ch); 261 } 262 // ...and replace the semicolon with 'dim' "[]" pairs: 263 while (dim--) { 264 result += "[]"; 265 } 266 return result; 267} 268 269/* 270 * Return a newly-allocated string for the "dot version" of the class 271 * name for the given type descriptor. That is, The initial "L" and 272 * final ";" (if any) have been removed and all occurrences of '/' 273 * have been changed to '.'. 274 * 275 * "Dot version" names are used in the class loading machinery. 276 * See also dvmHumanReadableDescriptor. 277 */ 278char* dvmDescriptorToDot(const char* str) 279{ 280 size_t at = strlen(str); 281 char* newStr; 282 283 if ((at >= 2) && (str[0] == 'L') && (str[at - 1] == ';')) { 284 at -= 2; /* Two fewer chars to copy. */ 285 str++; /* Skip the 'L'. */ 286 } 287 288 newStr = (char*)malloc(at + 1); /* Add one for the '\0'. */ 289 if (newStr == NULL) 290 return NULL; 291 292 newStr[at] = '\0'; 293 294 while (at > 0) { 295 at--; 296 newStr[at] = (str[at] == '/') ? '.' : str[at]; 297 } 298 299 return newStr; 300} 301 302/* 303 * Return a newly-allocated string for the type descriptor 304 * corresponding to the "dot version" of the given class name. That 305 * is, non-array names are surrounded by "L" and ";", and all 306 * occurrences of '.' have been changed to '/'. 307 * 308 * "Dot version" names are used in the class loading machinery. 309 */ 310char* dvmDotToDescriptor(const char* str) 311{ 312 size_t length = strlen(str); 313 int wrapElSemi = 0; 314 char* newStr; 315 char* at; 316 317 if (str[0] != '[') { 318 length += 2; /* for "L" and ";" */ 319 wrapElSemi = 1; 320 } 321 322 newStr = at = (char*)malloc(length + 1); /* + 1 for the '\0' */ 323 324 if (newStr == NULL) { 325 return NULL; 326 } 327 328 if (wrapElSemi) { 329 *(at++) = 'L'; 330 } 331 332 while (*str) { 333 char c = *(str++); 334 if (c == '.') { 335 c = '/'; 336 } 337 *(at++) = c; 338 } 339 340 if (wrapElSemi) { 341 *(at++) = ';'; 342 } 343 344 *at = '\0'; 345 return newStr; 346} 347 348/* 349 * Return a newly-allocated string for the internal-form class name for 350 * the given type descriptor. That is, the initial "L" and final ";" (if 351 * any) have been removed. 352 */ 353char* dvmDescriptorToName(const char* str) 354{ 355 if (str[0] == 'L') { 356 size_t length = strlen(str) - 1; 357 char* newStr = (char*)malloc(length); 358 359 if (newStr == NULL) { 360 return NULL; 361 } 362 363 strlcpy(newStr, str + 1, length); 364 return newStr; 365 } 366 367 return strdup(str); 368} 369 370/* 371 * Return a newly-allocated string for the type descriptor for the given 372 * internal-form class name. That is, a non-array class name will get 373 * surrounded by "L" and ";", while array names are left as-is. 374 */ 375char* dvmNameToDescriptor(const char* str) 376{ 377 if (str[0] != '[') { 378 size_t length = strlen(str); 379 char* descriptor = (char*)malloc(length + 3); 380 381 if (descriptor == NULL) { 382 return NULL; 383 } 384 385 descriptor[0] = 'L'; 386 strcpy(descriptor + 1, str); 387 descriptor[length + 1] = ';'; 388 descriptor[length + 2] = '\0'; 389 390 return descriptor; 391 } 392 393 return strdup(str); 394} 395 396/* 397 * Get a notion of the current time, in nanoseconds. This is meant for 398 * computing durations (e.g. "operation X took 52nsec"), so the result 399 * should not be used to get the current date/time. 400 */ 401u8 dvmGetRelativeTimeNsec() 402{ 403#ifdef HAVE_POSIX_CLOCKS 404 struct timespec now; 405 clock_gettime(CLOCK_MONOTONIC, &now); 406 return (u8)now.tv_sec*1000000000LL + now.tv_nsec; 407#else 408 struct timeval now; 409 gettimeofday(&now, NULL); 410 return (u8)now.tv_sec*1000000000LL + now.tv_usec * 1000LL; 411#endif 412} 413 414/* 415 * Get the per-thread CPU time, in nanoseconds. 416 * 417 * Only useful for time deltas. 418 */ 419u8 dvmGetThreadCpuTimeNsec() 420{ 421#ifdef HAVE_POSIX_CLOCKS 422 struct timespec now; 423 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now); 424 return (u8)now.tv_sec*1000000000LL + now.tv_nsec; 425#else 426 return (u8) -1; 427#endif 428} 429 430/* 431 * Get the per-thread CPU time, in nanoseconds, for the specified thread. 432 */ 433u8 dvmGetOtherThreadCpuTimeNsec(pthread_t thread) 434{ 435#if 0 /*def HAVE_POSIX_CLOCKS*/ 436 int clockId; 437 438 if (pthread_getcpuclockid(thread, &clockId) != 0) 439 return (u8) -1; 440 441 struct timespec now; 442 clock_gettime(clockId, &now); 443 return (u8)now.tv_sec*1000000000LL + now.tv_nsec; 444#else 445 return (u8) -1; 446#endif 447} 448 449 450/* 451 * Call this repeatedly, with successively higher values for "iteration", 452 * to sleep for a period of time not to exceed "maxTotalSleep". 453 * 454 * For example, when called with iteration==0 we will sleep for a very 455 * brief time. On the next call we will sleep for a longer time. When 456 * the sum total of all sleeps reaches "maxTotalSleep", this returns false. 457 * 458 * The initial start time value for "relStartTime" MUST come from the 459 * dvmGetRelativeTimeUsec call. On the device this must come from the 460 * monotonic clock source, not the wall clock. 461 * 462 * This should be used wherever you might be tempted to call sched_yield() 463 * in a loop. The problem with sched_yield is that, for a high-priority 464 * thread, the kernel might not actually transfer control elsewhere. 465 * 466 * Returns "false" if we were unable to sleep because our time was up. 467 */ 468bool dvmIterativeSleep(int iteration, int maxTotalSleep, u8 relStartTime) 469{ 470 const int minSleep = 10000; 471 u8 curTime; 472 int curDelay; 473 474 /* 475 * Get current time, and see if we've already exceeded the limit. 476 */ 477 curTime = dvmGetRelativeTimeUsec(); 478 if (curTime >= relStartTime + maxTotalSleep) { 479 LOGVV("exsl: sleep exceeded (start=%llu max=%d now=%llu)", 480 relStartTime, maxTotalSleep, curTime); 481 return false; 482 } 483 484 /* 485 * Compute current delay. We're bounded by "maxTotalSleep", so no 486 * real risk of overflow assuming "usleep" isn't returning early. 487 * (Besides, 2^30 usec is about 18 minutes by itself.) 488 * 489 * For iteration==0 we just call sched_yield(), so the first sleep 490 * at iteration==1 is actually (minSleep * 2). 491 */ 492 curDelay = minSleep; 493 while (iteration-- > 0) 494 curDelay *= 2; 495 assert(curDelay > 0); 496 497 if (curTime + curDelay >= relStartTime + maxTotalSleep) { 498 LOGVV("exsl: reduced delay from %d to %d", 499 curDelay, (int) ((relStartTime + maxTotalSleep) - curTime)); 500 curDelay = (int) ((relStartTime + maxTotalSleep) - curTime); 501 } 502 503 if (iteration == 0) { 504 LOGVV("exsl: yield"); 505 sched_yield(); 506 } else { 507 LOGVV("exsl: sleep for %d", curDelay); 508 usleep(curDelay); 509 } 510 return true; 511} 512 513 514/* 515 * Set the "close on exec" flag so we don't expose our file descriptors 516 * to processes launched by us. 517 */ 518bool dvmSetCloseOnExec(int fd) 519{ 520 int flags; 521 522 /* 523 * There's presently only one flag defined, so getting the previous 524 * value of the fd flags is probably unnecessary. 525 */ 526 flags = fcntl(fd, F_GETFD); 527 if (flags < 0) { 528 LOGW("Unable to get fd flags for fd %d", fd); 529 return false; 530 } 531 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) { 532 LOGW("Unable to set close-on-exec for fd %d", fd); 533 return false; 534 } 535 return true; 536} 537 538#if (!HAVE_STRLCPY) 539/* Implementation of strlcpy() for platforms that don't already have it. */ 540size_t strlcpy(char *dst, const char *src, size_t size) { 541 size_t srcLength = strlen(src); 542 size_t copyLength = srcLength; 543 544 if (srcLength > (size - 1)) { 545 copyLength = size - 1; 546 } 547 548 if (size != 0) { 549 strncpy(dst, src, copyLength); 550 dst[copyLength] = '\0'; 551 } 552 553 return srcLength; 554} 555#endif 556 557/* 558 * Allocates a memory region using ashmem and mmap, initialized to 559 * zero. Actual allocation rounded up to page multiple. Returns 560 * NULL on failure. 561 */ 562void *dvmAllocRegion(size_t byteCount, int prot, const char *name) { 563 void *base; 564 int fd, ret; 565 566 byteCount = ALIGN_UP_TO_PAGE_SIZE(byteCount); 567 fd = ashmem_create_region(name, byteCount); 568 if (fd == -1) { 569 return NULL; 570 } 571 base = mmap(NULL, byteCount, prot, MAP_PRIVATE, fd, 0); 572 ret = close(fd); 573 if (base == MAP_FAILED) { 574 return NULL; 575 } 576 if (ret == -1) { 577 return NULL; 578 } 579 return base; 580} 581 582/* 583 * Get some per-thread stats. 584 * 585 * This is currently generated by opening the appropriate "stat" file 586 * in /proc and reading the pile of stuff that comes out. 587 */ 588bool dvmGetThreadStats(ProcStatData* pData, pid_t tid) 589{ 590 /* 591 int pid; 592 char comm[128]; 593 char state; 594 int ppid, pgrp, session, tty_nr, tpgid; 595 unsigned long flags, minflt, cminflt, majflt, cmajflt, utime, stime; 596 long cutime, cstime, priority, nice, zero, itrealvalue; 597 unsigned long starttime, vsize; 598 long rss; 599 unsigned long rlim, startcode, endcode, startstack, kstkesp, kstkeip; 600 unsigned long signal, blocked, sigignore, sigcatch, wchan, nswap, cnswap; 601 int exit_signal, processor; 602 unsigned long rt_priority, policy; 603 604 scanf("%d %s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld " 605 "%ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu " 606 "%lu %lu %lu %d %d %lu %lu", 607 &pid, comm, &state, &ppid, &pgrp, &session, &tty_nr, &tpgid, 608 &flags, &minflt, &cminflt, &majflt, &cmajflt, &utime, &stime, 609 &cutime, &cstime, &priority, &nice, &zero, &itrealvalue, 610 &starttime, &vsize, &rss, &rlim, &startcode, &endcode, 611 &startstack, &kstkesp, &kstkeip, &signal, &blocked, &sigignore, 612 &sigcatch, &wchan, &nswap, &cnswap, &exit_signal, &processor, 613 &rt_priority, &policy); 614 615 (new: delayacct_blkio_ticks %llu (since Linux 2.6.18)) 616 */ 617 618 char nameBuf[64]; 619 int i, fd; 620 621 /* 622 * Open and read the appropriate file. This is expected to work on 623 * Linux but will fail on other platforms (e.g. Mac sim). 624 */ 625 sprintf(nameBuf, "/proc/self/task/%d/stat", (int) tid); 626 fd = open(nameBuf, O_RDONLY); 627 if (fd < 0) { 628 LOGV("Unable to open '%s': %s", nameBuf, strerror(errno)); 629 return false; 630 } 631 632 char lineBuf[512]; /* > 2x typical */ 633 int cc = read(fd, lineBuf, sizeof(lineBuf)-1); 634 if (cc <= 0) { 635 const char* msg = (cc == 0) ? "unexpected EOF" : strerror(errno); 636 LOGI("Unable to read '%s': %s", nameBuf, msg); 637 close(fd); 638 return false; 639 } 640 close(fd); 641 lineBuf[cc] = '\0'; 642 643 /* 644 * Skip whitespace-separated tokens. For the most part we can assume 645 * that tokens do not contain spaces, and are separated by exactly one 646 * space character. The only exception is the second field ("comm") 647 * which may contain spaces but is surrounded by parenthesis. 648 */ 649 char* cp = strchr(lineBuf, ')'); 650 if (cp == NULL) 651 goto parse_fail; 652 cp++; 653 for (i = 2; i < 13; i++) { 654 cp = strchr(cp+1, ' '); 655 if (cp == NULL) 656 goto parse_fail; 657 } 658 659 /* 660 * Grab utime/stime. 661 */ 662 char* endp; 663 pData->utime = strtoul(cp+1, &endp, 10); 664 if (endp == cp+1) 665 LOGI("Warning: strtoul failed on utime ('%.30s...')", cp); 666 667 cp = strchr(cp+1, ' '); 668 if (cp == NULL) 669 goto parse_fail; 670 671 pData->stime = strtoul(cp+1, &endp, 10); 672 if (endp == cp+1) 673 LOGI("Warning: strtoul failed on stime ('%.30s...')", cp); 674 675 /* 676 * Skip more stuff we don't care about. 677 */ 678 for (i = 14; i < 38; i++) { 679 cp = strchr(cp+1, ' '); 680 if (cp == NULL) 681 goto parse_fail; 682 } 683 684 /* 685 * Grab processor number. 686 */ 687 pData->processor = strtol(cp+1, &endp, 10); 688 if (endp == cp+1) 689 LOGI("Warning: strtoul failed on processor ('%.30s...')", cp); 690 691 return true; 692 693parse_fail: 694 LOGI("stat parse failed (%s)", lineBuf); 695 return false; 696} 697 698/* documented in header file */ 699const char* dvmPathToAbsolutePortion(const char* path) { 700 if (path == NULL) { 701 return NULL; 702 } 703 704 if (path[0] == '/') { 705 /* It's a regular absolute path. Return it. */ 706 return path; 707 } 708 709 const char* sentinel = strstr(path, "/./"); 710 711 if (sentinel != NULL) { 712 /* It's got the sentinel. Return a pointer to the second slash. */ 713 return sentinel + 2; 714 } 715 716 return NULL; 717} 718