Home | History | Annotate | Download | only in vm
      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  *
     36 01234567: 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  */
     47 void 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  */
    137 void 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  */
    151 void 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  */
    163 void dvmFreeOutputTarget(DebugOutputTarget* target)
    164 {
    165     free(target);
    166 }
    167 
    168 /*
    169  * Print a debug message, to either a file or the log.
    170  */
    171 void 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         ALOGE("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  */
    200 char* 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 
    221 std::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 std::string dvmHumanReadableType(const Object* obj)
    270 {
    271     if (obj == NULL) {
    272         return "null";
    273     }
    274     if (obj->clazz == NULL) {
    275         /* should only be possible right after a plain dvmMalloc() */
    276         return "(raw)";
    277     }
    278     std::string result(dvmHumanReadableDescriptor(obj->clazz->descriptor));
    279     if (dvmIsClassObject(obj)) {
    280         const ClassObject* clazz = reinterpret_cast<const ClassObject*>(obj);
    281         result += "<" + dvmHumanReadableDescriptor(clazz->descriptor) + ">";
    282     }
    283     return result;
    284 }
    285 
    286 std::string dvmHumanReadableField(const Field* field)
    287 {
    288     if (field == NULL) {
    289         return "(null)";
    290     }
    291     std::string result(dvmHumanReadableDescriptor(field->clazz->descriptor));
    292     result += '.';
    293     result += field->name;
    294     return result;
    295 }
    296 
    297 std::string dvmHumanReadableMethod(const Method* method, bool withSignature)
    298 {
    299     if (method == NULL) {
    300         return "(null)";
    301     }
    302     std::string result(dvmHumanReadableDescriptor(method->clazz->descriptor));
    303     result += '.';
    304     result += method->name;
    305     if (withSignature) {
    306         // TODO: the types in this aren't human readable!
    307         char* signature = dexProtoCopyMethodDescriptor(&method->prototype);
    308         result += signature;
    309         free(signature);
    310     }
    311     return result;
    312 }
    313 
    314 /*
    315  * Return a newly-allocated string for the "dot version" of the class
    316  * name for the given type descriptor. That is, The initial "L" and
    317  * final ";" (if any) have been removed and all occurrences of '/'
    318  * have been changed to '.'.
    319  *
    320  * "Dot version" names are used in the class loading machinery.
    321  * See also dvmHumanReadableDescriptor.
    322  */
    323 char* dvmDescriptorToDot(const char* str)
    324 {
    325     size_t at = strlen(str);
    326     char* newStr;
    327 
    328     if ((at >= 2) && (str[0] == 'L') && (str[at - 1] == ';')) {
    329         at -= 2; /* Two fewer chars to copy. */
    330         str++; /* Skip the 'L'. */
    331     }
    332 
    333     newStr = (char*)malloc(at + 1); /* Add one for the '\0'. */
    334     if (newStr == NULL)
    335         return NULL;
    336 
    337     newStr[at] = '\0';
    338 
    339     while (at > 0) {
    340         at--;
    341         newStr[at] = (str[at] == '/') ? '.' : str[at];
    342     }
    343 
    344     return newStr;
    345 }
    346 
    347 /*
    348  * Return a newly-allocated string for the type descriptor
    349  * corresponding to the "dot version" of the given class name. That
    350  * is, non-array names are surrounded by "L" and ";", and all
    351  * occurrences of '.' have been changed to '/'.
    352  *
    353  * "Dot version" names are used in the class loading machinery.
    354  */
    355 char* dvmDotToDescriptor(const char* str)
    356 {
    357     size_t length = strlen(str);
    358     int wrapElSemi = 0;
    359     char* newStr;
    360     char* at;
    361 
    362     if (str[0] != '[') {
    363         length += 2; /* for "L" and ";" */
    364         wrapElSemi = 1;
    365     }
    366 
    367     newStr = at = (char*)malloc(length + 1); /* + 1 for the '\0' */
    368 
    369     if (newStr == NULL) {
    370         return NULL;
    371     }
    372 
    373     if (wrapElSemi) {
    374         *(at++) = 'L';
    375     }
    376 
    377     while (*str) {
    378         char c = *(str++);
    379         if (c == '.') {
    380             c = '/';
    381         }
    382         *(at++) = c;
    383     }
    384 
    385     if (wrapElSemi) {
    386         *(at++) = ';';
    387     }
    388 
    389     *at = '\0';
    390     return newStr;
    391 }
    392 
    393 /*
    394  * Return a newly-allocated string for the internal-form class name for
    395  * the given type descriptor. That is, the initial "L" and final ";" (if
    396  * any) have been removed.
    397  */
    398 char* dvmDescriptorToName(const char* str)
    399 {
    400     if (str[0] == 'L') {
    401         size_t length = strlen(str) - 1;
    402         char* newStr = (char*)malloc(length);
    403 
    404         if (newStr == NULL) {
    405             return NULL;
    406         }
    407 
    408         strlcpy(newStr, str + 1, length);
    409         return newStr;
    410     }
    411 
    412     return strdup(str);
    413 }
    414 
    415 /*
    416  * Return a newly-allocated string for the type descriptor for the given
    417  * internal-form class name. That is, a non-array class name will get
    418  * surrounded by "L" and ";", while array names are left as-is.
    419  */
    420 char* dvmNameToDescriptor(const char* str)
    421 {
    422     if (str[0] != '[') {
    423         size_t length = strlen(str);
    424         char* descriptor = (char*)malloc(length + 3);
    425 
    426         if (descriptor == NULL) {
    427             return NULL;
    428         }
    429 
    430         descriptor[0] = 'L';
    431         strcpy(descriptor + 1, str);
    432         descriptor[length + 1] = ';';
    433         descriptor[length + 2] = '\0';
    434 
    435         return descriptor;
    436     }
    437 
    438     return strdup(str);
    439 }
    440 
    441 /*
    442  * Get a notion of the current time, in nanoseconds.  This is meant for
    443  * computing durations (e.g. "operation X took 52nsec"), so the result
    444  * should not be used to get the current date/time.
    445  */
    446 u8 dvmGetRelativeTimeNsec()
    447 {
    448 #ifdef HAVE_POSIX_CLOCKS
    449     struct timespec now;
    450     clock_gettime(CLOCK_MONOTONIC, &now);
    451     return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
    452 #else
    453     struct timeval now;
    454     gettimeofday(&now, NULL);
    455     return (u8)now.tv_sec*1000000000LL + now.tv_usec * 1000LL;
    456 #endif
    457 }
    458 
    459 /*
    460  * Get the per-thread CPU time, in nanoseconds.
    461  *
    462  * Only useful for time deltas.
    463  */
    464 u8 dvmGetThreadCpuTimeNsec()
    465 {
    466 #ifdef HAVE_POSIX_CLOCKS
    467     struct timespec now;
    468     clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
    469     return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
    470 #else
    471     return (u8) -1;
    472 #endif
    473 }
    474 
    475 /*
    476  * Get the per-thread CPU time, in nanoseconds, for the specified thread.
    477  */
    478 u8 dvmGetOtherThreadCpuTimeNsec(pthread_t thread)
    479 {
    480 #if 0 /*def HAVE_POSIX_CLOCKS*/
    481     int clockId;
    482 
    483     if (pthread_getcpuclockid(thread, &clockId) != 0)
    484         return (u8) -1;
    485 
    486     struct timespec now;
    487     clock_gettime(clockId, &now);
    488     return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
    489 #else
    490     return (u8) -1;
    491 #endif
    492 }
    493 
    494 
    495 /*
    496  * Call this repeatedly, with successively higher values for "iteration",
    497  * to sleep for a period of time not to exceed "maxTotalSleep".
    498  *
    499  * For example, when called with iteration==0 we will sleep for a very
    500  * brief time.  On the next call we will sleep for a longer time.  When
    501  * the sum total of all sleeps reaches "maxTotalSleep", this returns false.
    502  *
    503  * The initial start time value for "relStartTime" MUST come from the
    504  * dvmGetRelativeTimeUsec call.  On the device this must come from the
    505  * monotonic clock source, not the wall clock.
    506  *
    507  * This should be used wherever you might be tempted to call sched_yield()
    508  * in a loop.  The problem with sched_yield is that, for a high-priority
    509  * thread, the kernel might not actually transfer control elsewhere.
    510  *
    511  * Returns "false" if we were unable to sleep because our time was up.
    512  */
    513 bool dvmIterativeSleep(int iteration, int maxTotalSleep, u8 relStartTime)
    514 {
    515     /*
    516      * Minimum sleep is one millisecond, it is important to keep this value
    517      * low to ensure short GC pauses since dvmSuspendAllThreads() uses this
    518      * function.
    519      */
    520     const int minSleep = 1000;
    521     u8 curTime;
    522     int curDelay;
    523 
    524     /*
    525      * Get current time, and see if we've already exceeded the limit.
    526      */
    527     curTime = dvmGetRelativeTimeUsec();
    528     if (curTime >= relStartTime + maxTotalSleep) {
    529         LOGVV("exsl: sleep exceeded (start=%llu max=%d now=%llu)",
    530             relStartTime, maxTotalSleep, curTime);
    531         return false;
    532     }
    533 
    534     /*
    535      * Compute current delay.  We're bounded by "maxTotalSleep", so no
    536      * real risk of overflow assuming "usleep" isn't returning early.
    537      * (Besides, 2^30 usec is about 18 minutes by itself.)
    538      *
    539      * For iteration==0 we just call sched_yield(), so the first sleep
    540      * at iteration==1 is actually (minSleep * 2).
    541      */
    542     curDelay = minSleep;
    543     while (iteration-- > 0)
    544         curDelay *= 2;
    545     assert(curDelay > 0);
    546 
    547     if (curTime + curDelay >= relStartTime + maxTotalSleep) {
    548         LOGVV("exsl: reduced delay from %d to %d",
    549             curDelay, (int) ((relStartTime + maxTotalSleep) - curTime));
    550         curDelay = (int) ((relStartTime + maxTotalSleep) - curTime);
    551     }
    552 
    553     if (iteration == 0) {
    554         LOGVV("exsl: yield");
    555         sched_yield();
    556     } else {
    557         LOGVV("exsl: sleep for %d", curDelay);
    558         usleep(curDelay);
    559     }
    560     return true;
    561 }
    562 
    563 
    564 /*
    565  * Set the "close on exec" flag so we don't expose our file descriptors
    566  * to processes launched by us.
    567  */
    568 bool dvmSetCloseOnExec(int fd)
    569 {
    570     int flags;
    571 
    572     /*
    573      * There's presently only one flag defined, so getting the previous
    574      * value of the fd flags is probably unnecessary.
    575      */
    576     flags = fcntl(fd, F_GETFD);
    577     if (flags < 0) {
    578         ALOGW("Unable to get fd flags for fd %d", fd);
    579         return false;
    580     }
    581     if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
    582         ALOGW("Unable to set close-on-exec for fd %d", fd);
    583         return false;
    584     }
    585     return true;
    586 }
    587 
    588 #if (!HAVE_STRLCPY)
    589 /* Implementation of strlcpy() for platforms that don't already have it. */
    590 size_t strlcpy(char *dst, const char *src, size_t size) {
    591     size_t srcLength = strlen(src);
    592     size_t copyLength = srcLength;
    593 
    594     if (srcLength > (size - 1)) {
    595         copyLength = size - 1;
    596     }
    597 
    598     if (size != 0) {
    599         strncpy(dst, src, copyLength);
    600         dst[copyLength] = '\0';
    601     }
    602 
    603     return srcLength;
    604 }
    605 #endif
    606 
    607 /*
    608  *  Allocates a memory region using ashmem and mmap, initialized to
    609  *  zero.  Actual allocation rounded up to page multiple.  Returns
    610  *  NULL on failure.
    611  */
    612 void *dvmAllocRegion(size_t byteCount, int prot, const char *name) {
    613     void *base;
    614     int fd, ret;
    615 
    616     byteCount = ALIGN_UP_TO_PAGE_SIZE(byteCount);
    617     fd = ashmem_create_region(name, byteCount);
    618     if (fd == -1) {
    619         return NULL;
    620     }
    621     base = mmap(NULL, byteCount, prot, MAP_PRIVATE, fd, 0);
    622     ret = close(fd);
    623     if (base == MAP_FAILED) {
    624         return NULL;
    625     }
    626     if (ret == -1) {
    627         munmap(base, byteCount);
    628         return NULL;
    629     }
    630     return base;
    631 }
    632 
    633 /*
    634  * Get some per-thread stats.
    635  *
    636  * This is currently generated by opening the appropriate "stat" file
    637  * in /proc and reading the pile of stuff that comes out.
    638  */
    639 bool dvmGetThreadStats(ProcStatData* pData, pid_t tid)
    640 {
    641     /*
    642     int pid;
    643     char comm[128];
    644     char state;
    645     int ppid, pgrp, session, tty_nr, tpgid;
    646     unsigned long flags, minflt, cminflt, majflt, cmajflt, utime, stime;
    647     long cutime, cstime, priority, nice, zero, itrealvalue;
    648     unsigned long starttime, vsize;
    649     long rss;
    650     unsigned long rlim, startcode, endcode, startstack, kstkesp, kstkeip;
    651     unsigned long signal, blocked, sigignore, sigcatch, wchan, nswap, cnswap;
    652     int exit_signal, processor;
    653     unsigned long rt_priority, policy;
    654 
    655     scanf("%d %s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld "
    656           "%ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu "
    657           "%lu %lu %lu %d %d %lu %lu",
    658         &pid, comm, &state, &ppid, &pgrp, &session, &tty_nr, &tpgid,
    659         &flags, &minflt, &cminflt, &majflt, &cmajflt, &utime, &stime,
    660         &cutime, &cstime, &priority, &nice, &zero, &itrealvalue,
    661         &starttime, &vsize, &rss, &rlim, &startcode, &endcode,
    662         &startstack, &kstkesp, &kstkeip, &signal, &blocked, &sigignore,
    663         &sigcatch, &wchan, &nswap, &cnswap, &exit_signal, &processor,
    664         &rt_priority, &policy);
    665 
    666         (new: delayacct_blkio_ticks %llu (since Linux 2.6.18))
    667     */
    668 
    669     char nameBuf[64];
    670     int i, fd;
    671 
    672     /*
    673      * Open and read the appropriate file.  This is expected to work on
    674      * Linux but will fail on other platforms (e.g. Mac sim).
    675      */
    676     sprintf(nameBuf, "/proc/self/task/%d/stat", (int) tid);
    677     fd = open(nameBuf, O_RDONLY);
    678     if (fd < 0) {
    679         ALOGV("Unable to open '%s': %s", nameBuf, strerror(errno));
    680         return false;
    681     }
    682 
    683     char lineBuf[512];      /* > 2x typical */
    684     int cc = read(fd, lineBuf, sizeof(lineBuf)-1);
    685     if (cc <= 0) {
    686         const char* msg = (cc == 0) ? "unexpected EOF" : strerror(errno);
    687         ALOGI("Unable to read '%s': %s", nameBuf, msg);
    688         close(fd);
    689         return false;
    690     }
    691     close(fd);
    692     lineBuf[cc] = '\0';
    693 
    694     /*
    695      * Skip whitespace-separated tokens.  For the most part we can assume
    696      * that tokens do not contain spaces, and are separated by exactly one
    697      * space character.  The only exception is the second field ("comm")
    698      * which may contain spaces but is surrounded by parenthesis.
    699      */
    700     char* cp = strchr(lineBuf, ')');
    701     if (cp == NULL)
    702         goto parse_fail;
    703     cp += 2;
    704     pData->state = *cp++;
    705 
    706     for (i = 3; i < 13; i++) {
    707         cp = strchr(cp+1, ' ');
    708         if (cp == NULL)
    709             goto parse_fail;
    710     }
    711 
    712     /*
    713      * Grab utime/stime.
    714      */
    715     char* endp;
    716     pData->utime = strtoul(cp+1, &endp, 10);
    717     if (endp == cp+1)
    718         ALOGI("Warning: strtoul failed on utime ('%.30s...')", cp);
    719 
    720     cp = strchr(cp+1, ' ');
    721     if (cp == NULL)
    722         goto parse_fail;
    723 
    724     pData->stime = strtoul(cp+1, &endp, 10);
    725     if (endp == cp+1)
    726         ALOGI("Warning: strtoul failed on stime ('%.30s...')", cp);
    727 
    728     /*
    729      * Skip more stuff we don't care about.
    730      */
    731     for (i = 14; i < 38; i++) {
    732         cp = strchr(cp+1, ' ');
    733         if (cp == NULL)
    734             goto parse_fail;
    735     }
    736 
    737     /*
    738      * Grab processor number.
    739      */
    740     pData->processor = strtol(cp+1, &endp, 10);
    741     if (endp == cp+1)
    742         ALOGI("Warning: strtoul failed on processor ('%.30s...')", cp);
    743 
    744     return true;
    745 
    746 parse_fail:
    747     ALOGI("stat parse failed (%s)", lineBuf);
    748     return false;
    749 }
    750 
    751 /* documented in header file */
    752 const char* dvmPathToAbsolutePortion(const char* path) {
    753     if (path == NULL) {
    754         return NULL;
    755     }
    756 
    757     if (path[0] == '/') {
    758         /* It's a regular absolute path. Return it. */
    759         return path;
    760     }
    761 
    762     const char* sentinel = strstr(path, "/./");
    763 
    764     if (sentinel != NULL) {
    765         /* It's got the sentinel. Return a pointer to the second slash. */
    766         return sentinel + 2;
    767     }
    768 
    769     return NULL;
    770 }
    771 
    772 // From RE2.
    773 void StringAppendV(std::string* dst, const char* format, va_list ap) {
    774     // First try with a small fixed size buffer
    775     char space[1024];
    776 
    777     // It's possible for methods that use a va_list to invalidate
    778     // the data in it upon use.  The fix is to make a copy
    779     // of the structure before using it and use that copy instead.
    780     va_list backup_ap;
    781     va_copy(backup_ap, ap);
    782     int result = vsnprintf(space, sizeof(space), format, backup_ap);
    783     va_end(backup_ap);
    784 
    785     if ((result >= 0) && ((size_t) result < sizeof(space))) {
    786         // It fit
    787         dst->append(space, result);
    788         return;
    789     }
    790 
    791     // Repeatedly increase buffer size until it fits
    792     int length = sizeof(space);
    793     while (true) {
    794         if (result < 0) {
    795             // Older behavior: just try doubling the buffer size
    796             length *= 2;
    797         } else {
    798             // We need exactly "result+1" characters
    799             length = result+1;
    800         }
    801         char* buf = new char[length];
    802 
    803         // Restore the va_list before we use it again
    804         va_copy(backup_ap, ap);
    805         result = vsnprintf(buf, length, format, backup_ap);
    806         va_end(backup_ap);
    807 
    808         if ((result >= 0) && (result < length)) {
    809             // It fit
    810             dst->append(buf, result);
    811             delete[] buf;
    812             return;
    813         }
    814         delete[] buf;
    815     }
    816 }
    817 
    818 std::string StringPrintf(const char* fmt, ...) {
    819     va_list ap;
    820     va_start(ap, fmt);
    821     std::string result;
    822     StringAppendV(&result, fmt, ap);
    823     va_end(ap);
    824     return result;
    825 }
    826 
    827 void StringAppendF(std::string* dst, const char* format, ...) {
    828     va_list ap;
    829     va_start(ap, format);
    830     StringAppendV(dst, format, ap);
    831     va_end(ap);
    832 }
    833