• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
dvmPrintHexDumpEx(int priority,const char * tag,const void * vaddr,size_t length,HexDumpMode mode)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  */
dvmCreateLogOutputTarget(DebugOutputTarget * target,int priority,const char * tag)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  */
dvmCreateFileOutputTarget(DebugOutputTarget * target,FILE * fp)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  */
dvmFreeOutputTarget(DebugOutputTarget * target)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  */
dvmPrintDebugMessage(const DebugOutputTarget * target,const char * format,...)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  */
dvmDotToSlash(const char * str)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 
dvmHumanReadableDescriptor(const char * descriptor)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 
dvmHumanReadableType(const Object * obj)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 
dvmHumanReadableField(const Field * field)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 
dvmHumanReadableMethod(const Method * method,bool withSignature)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  */
dvmDescriptorToDot(const char * str)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  */
dvmDotToDescriptor(const char * str)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  */
dvmDescriptorToName(const char * str)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  */
dvmNameToDescriptor(const char * str)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  */
dvmGetRelativeTimeNsec()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  */
dvmGetThreadCpuTimeNsec()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  */
dvmGetOtherThreadCpuTimeNsec(pthread_t thread)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  */
dvmIterativeSleep(int iteration,int maxTotalSleep,u8 relStartTime)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  */
dvmSetCloseOnExec(int fd)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. */
strlcpy(char * dst,const char * src,size_t size)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  */
dvmAllocRegion(size_t byteCount,int prot,const char * name)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         return NULL;
628     }
629     return base;
630 }
631 
632 /*
633  * Get some per-thread stats.
634  *
635  * This is currently generated by opening the appropriate "stat" file
636  * in /proc and reading the pile of stuff that comes out.
637  */
dvmGetThreadStats(ProcStatData * pData,pid_t tid)638 bool dvmGetThreadStats(ProcStatData* pData, pid_t tid)
639 {
640     /*
641     int pid;
642     char comm[128];
643     char state;
644     int ppid, pgrp, session, tty_nr, tpgid;
645     unsigned long flags, minflt, cminflt, majflt, cmajflt, utime, stime;
646     long cutime, cstime, priority, nice, zero, itrealvalue;
647     unsigned long starttime, vsize;
648     long rss;
649     unsigned long rlim, startcode, endcode, startstack, kstkesp, kstkeip;
650     unsigned long signal, blocked, sigignore, sigcatch, wchan, nswap, cnswap;
651     int exit_signal, processor;
652     unsigned long rt_priority, policy;
653 
654     scanf("%d %s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld "
655           "%ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu "
656           "%lu %lu %lu %d %d %lu %lu",
657         &pid, comm, &state, &ppid, &pgrp, &session, &tty_nr, &tpgid,
658         &flags, &minflt, &cminflt, &majflt, &cmajflt, &utime, &stime,
659         &cutime, &cstime, &priority, &nice, &zero, &itrealvalue,
660         &starttime, &vsize, &rss, &rlim, &startcode, &endcode,
661         &startstack, &kstkesp, &kstkeip, &signal, &blocked, &sigignore,
662         &sigcatch, &wchan, &nswap, &cnswap, &exit_signal, &processor,
663         &rt_priority, &policy);
664 
665         (new: delayacct_blkio_ticks %llu (since Linux 2.6.18))
666     */
667 
668     char nameBuf[64];
669     int i, fd;
670 
671     /*
672      * Open and read the appropriate file.  This is expected to work on
673      * Linux but will fail on other platforms (e.g. Mac sim).
674      */
675     sprintf(nameBuf, "/proc/self/task/%d/stat", (int) tid);
676     fd = open(nameBuf, O_RDONLY);
677     if (fd < 0) {
678         ALOGV("Unable to open '%s': %s", nameBuf, strerror(errno));
679         return false;
680     }
681 
682     char lineBuf[512];      /* > 2x typical */
683     int cc = read(fd, lineBuf, sizeof(lineBuf)-1);
684     if (cc <= 0) {
685         const char* msg = (cc == 0) ? "unexpected EOF" : strerror(errno);
686         ALOGI("Unable to read '%s': %s", nameBuf, msg);
687         close(fd);
688         return false;
689     }
690     close(fd);
691     lineBuf[cc] = '\0';
692 
693     /*
694      * Skip whitespace-separated tokens.  For the most part we can assume
695      * that tokens do not contain spaces, and are separated by exactly one
696      * space character.  The only exception is the second field ("comm")
697      * which may contain spaces but is surrounded by parenthesis.
698      */
699     char* cp = strchr(lineBuf, ')');
700     if (cp == NULL)
701         goto parse_fail;
702     cp += 2;
703     pData->state = *cp++;
704 
705     for (i = 3; i < 13; i++) {
706         cp = strchr(cp+1, ' ');
707         if (cp == NULL)
708             goto parse_fail;
709     }
710 
711     /*
712      * Grab utime/stime.
713      */
714     char* endp;
715     pData->utime = strtoul(cp+1, &endp, 10);
716     if (endp == cp+1)
717         ALOGI("Warning: strtoul failed on utime ('%.30s...')", cp);
718 
719     cp = strchr(cp+1, ' ');
720     if (cp == NULL)
721         goto parse_fail;
722 
723     pData->stime = strtoul(cp+1, &endp, 10);
724     if (endp == cp+1)
725         ALOGI("Warning: strtoul failed on stime ('%.30s...')", cp);
726 
727     /*
728      * Skip more stuff we don't care about.
729      */
730     for (i = 14; i < 38; i++) {
731         cp = strchr(cp+1, ' ');
732         if (cp == NULL)
733             goto parse_fail;
734     }
735 
736     /*
737      * Grab processor number.
738      */
739     pData->processor = strtol(cp+1, &endp, 10);
740     if (endp == cp+1)
741         ALOGI("Warning: strtoul failed on processor ('%.30s...')", cp);
742 
743     return true;
744 
745 parse_fail:
746     ALOGI("stat parse failed (%s)", lineBuf);
747     return false;
748 }
749 
750 /* documented in header file */
dvmPathToAbsolutePortion(const char * path)751 const char* dvmPathToAbsolutePortion(const char* path) {
752     if (path == NULL) {
753         return NULL;
754     }
755 
756     if (path[0] == '/') {
757         /* It's a regular absolute path. Return it. */
758         return path;
759     }
760 
761     const char* sentinel = strstr(path, "/./");
762 
763     if (sentinel != NULL) {
764         /* It's got the sentinel. Return a pointer to the second slash. */
765         return sentinel + 2;
766     }
767 
768     return NULL;
769 }
770 
771 // From RE2.
StringAppendV(std::string * dst,const char * format,va_list ap)772 void StringAppendV(std::string* dst, const char* format, va_list ap) {
773     // First try with a small fixed size buffer
774     char space[1024];
775 
776     // It's possible for methods that use a va_list to invalidate
777     // the data in it upon use.  The fix is to make a copy
778     // of the structure before using it and use that copy instead.
779     va_list backup_ap;
780     va_copy(backup_ap, ap);
781     int result = vsnprintf(space, sizeof(space), format, backup_ap);
782     va_end(backup_ap);
783 
784     if ((result >= 0) && ((size_t) result < sizeof(space))) {
785         // It fit
786         dst->append(space, result);
787         return;
788     }
789 
790     // Repeatedly increase buffer size until it fits
791     int length = sizeof(space);
792     while (true) {
793         if (result < 0) {
794             // Older behavior: just try doubling the buffer size
795             length *= 2;
796         } else {
797             // We need exactly "result+1" characters
798             length = result+1;
799         }
800         char* buf = new char[length];
801 
802         // Restore the va_list before we use it again
803         va_copy(backup_ap, ap);
804         result = vsnprintf(buf, length, format, backup_ap);
805         va_end(backup_ap);
806 
807         if ((result >= 0) && (result < length)) {
808             // It fit
809             dst->append(buf, result);
810             delete[] buf;
811             return;
812         }
813         delete[] buf;
814     }
815 }
816 
StringPrintf(const char * fmt,...)817 std::string StringPrintf(const char* fmt, ...) {
818     va_list ap;
819     va_start(ap, fmt);
820     std::string result;
821     StringAppendV(&result, fmt, ap);
822     va_end(ap);
823     return result;
824 }
825 
StringAppendF(std::string * dst,const char * format,...)826 void StringAppendF(std::string* dst, const char* format, ...) {
827     va_list ap;
828     va_start(ap, format);
829     StringAppendV(dst, format, ap);
830     va_end(ap);
831 }
832