PageRenderTime 57ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/liblog/fake_log_device.c

https://gitlab.com/infraredbg/android_system_core-mt6589
C | 691 lines | 443 code | 90 blank | 158 comment | 118 complexity | 8f4a5683abdbb184871a589f47dc796a MD5 | raw file
  1. /*
  2. * Copyright (C) 2008-2014 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. * Intercepts log messages intended for the Android log device.
  18. * When running in the context of the simulator, the messages are
  19. * passed on to the underlying (fake) log device. When not in the
  20. * simulator, messages are printed to stderr.
  21. */
  22. #include "fake_log_device.h"
  23. #include <ctype.h>
  24. #include <errno.h>
  25. #include <fcntl.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <log/logd.h>
  29. #ifdef HAVE_PTHREADS
  30. #include <pthread.h>
  31. #endif
  32. #ifndef __unused
  33. #define __unused __attribute__((__unused__))
  34. #endif
  35. #define kMaxTagLen 16 /* from the long-dead utils/Log.cpp */
  36. #define kTagSetSize 16 /* arbitrary */
  37. #if 0
  38. #define TRACE(...) printf("fake_log_device: " __VA_ARGS__)
  39. #else
  40. #define TRACE(...) ((void)0)
  41. #endif
  42. /* from the long-dead utils/Log.cpp */
  43. typedef enum {
  44. FORMAT_OFF = 0,
  45. FORMAT_BRIEF,
  46. FORMAT_PROCESS,
  47. FORMAT_TAG,
  48. FORMAT_THREAD,
  49. FORMAT_RAW,
  50. FORMAT_TIME,
  51. FORMAT_THREADTIME,
  52. FORMAT_LONG
  53. } LogFormat;
  54. /*
  55. * Log driver state.
  56. */
  57. typedef struct LogState {
  58. /* the fake fd that's seen by the user */
  59. int fakeFd;
  60. /* a printable name for this fake device */
  61. char *debugName;
  62. /* nonzero if this is a binary log */
  63. int isBinary;
  64. /* global minimum priority */
  65. int globalMinPriority;
  66. /* output format */
  67. LogFormat outputFormat;
  68. /* tags and priorities */
  69. struct {
  70. char tag[kMaxTagLen];
  71. int minPriority;
  72. } tagSet[kTagSetSize];
  73. } LogState;
  74. #ifdef HAVE_PTHREADS
  75. /*
  76. * Locking. Since we're emulating a device, we need to be prepared
  77. * to have multiple callers at the same time. This lock is used
  78. * to both protect the fd list and to prevent LogStates from being
  79. * freed out from under a user.
  80. */
  81. static pthread_mutex_t fakeLogDeviceLock = PTHREAD_MUTEX_INITIALIZER;
  82. static void lock()
  83. {
  84. pthread_mutex_lock(&fakeLogDeviceLock);
  85. }
  86. static void unlock()
  87. {
  88. pthread_mutex_unlock(&fakeLogDeviceLock);
  89. }
  90. #else // !HAVE_PTHREADS
  91. #define lock() ((void)0)
  92. #define unlock() ((void)0)
  93. #endif // !HAVE_PTHREADS
  94. /*
  95. * File descriptor management.
  96. */
  97. #define FAKE_FD_BASE 10000
  98. #define MAX_OPEN_LOGS 16
  99. static LogState *openLogTable[MAX_OPEN_LOGS];
  100. /*
  101. * Allocate an fd and associate a new LogState with it.
  102. * The fd is available via the fakeFd field of the return value.
  103. */
  104. static LogState *createLogState()
  105. {
  106. size_t i;
  107. for (i = 0; i < sizeof(openLogTable); i++) {
  108. if (openLogTable[i] == NULL) {
  109. openLogTable[i] = calloc(1, sizeof(LogState));
  110. openLogTable[i]->fakeFd = FAKE_FD_BASE + i;
  111. return openLogTable[i];
  112. }
  113. }
  114. return NULL;
  115. }
  116. /*
  117. * Translate an fd to a LogState.
  118. */
  119. static LogState *fdToLogState(int fd)
  120. {
  121. if (fd >= FAKE_FD_BASE && fd < FAKE_FD_BASE + MAX_OPEN_LOGS) {
  122. return openLogTable[fd - FAKE_FD_BASE];
  123. }
  124. return NULL;
  125. }
  126. /*
  127. * Unregister the fake fd and free the memory it pointed to.
  128. */
  129. static void deleteFakeFd(int fd)
  130. {
  131. LogState *ls;
  132. lock();
  133. ls = fdToLogState(fd);
  134. if (ls != NULL) {
  135. openLogTable[fd - FAKE_FD_BASE] = NULL;
  136. free(ls->debugName);
  137. free(ls);
  138. }
  139. unlock();
  140. }
  141. /*
  142. * Configure logging based on ANDROID_LOG_TAGS environment variable. We
  143. * need to parse a string that looks like
  144. *
  145. * *:v jdwp:d dalvikvm:d dalvikvm-gc:i dalvikvmi:i
  146. *
  147. * The tag (or '*' for the global level) comes first, followed by a colon
  148. * and a letter indicating the minimum priority level we're expected to log.
  149. * This can be used to reveal or conceal logs with specific tags.
  150. *
  151. * We also want to check ANDROID_PRINTF_LOG to determine how the output
  152. * will look.
  153. */
  154. static void configureInitialState(const char* pathName, LogState* logState)
  155. {
  156. static const int kDevLogLen = sizeof("/dev/log/") - 1;
  157. logState->debugName = strdup(pathName);
  158. /* identify binary logs */
  159. if (strcmp(pathName + kDevLogLen, "events") == 0) {
  160. logState->isBinary = 1;
  161. }
  162. /* global min priority defaults to "info" level */
  163. logState->globalMinPriority = ANDROID_LOG_INFO;
  164. /*
  165. * This is based on the the long-dead utils/Log.cpp code.
  166. */
  167. const char* tags = getenv("ANDROID_LOG_TAGS");
  168. TRACE("Found ANDROID_LOG_TAGS='%s'\n", tags);
  169. if (tags != NULL) {
  170. int entry = 0;
  171. while (*tags != '\0') {
  172. char tagName[kMaxTagLen];
  173. int i, minPrio;
  174. while (isspace(*tags))
  175. tags++;
  176. i = 0;
  177. while (*tags != '\0' && !isspace(*tags) && *tags != ':' &&
  178. i < kMaxTagLen)
  179. {
  180. tagName[i++] = *tags++;
  181. }
  182. if (i == kMaxTagLen) {
  183. TRACE("ERROR: env tag too long (%d chars max)\n", kMaxTagLen-1);
  184. return;
  185. }
  186. tagName[i] = '\0';
  187. /* default priority, if there's no ":" part; also zero out '*' */
  188. minPrio = ANDROID_LOG_VERBOSE;
  189. if (tagName[0] == '*' && tagName[1] == '\0') {
  190. minPrio = ANDROID_LOG_DEBUG;
  191. tagName[0] = '\0';
  192. }
  193. if (*tags == ':') {
  194. tags++;
  195. if (*tags >= '0' && *tags <= '9') {
  196. if (*tags >= ('0' + ANDROID_LOG_SILENT))
  197. minPrio = ANDROID_LOG_VERBOSE;
  198. else
  199. minPrio = *tags - '\0';
  200. } else {
  201. switch (*tags) {
  202. case 'v': minPrio = ANDROID_LOG_VERBOSE; break;
  203. case 'd': minPrio = ANDROID_LOG_DEBUG; break;
  204. case 'i': minPrio = ANDROID_LOG_INFO; break;
  205. case 'w': minPrio = ANDROID_LOG_WARN; break;
  206. case 'e': minPrio = ANDROID_LOG_ERROR; break;
  207. case 'f': minPrio = ANDROID_LOG_FATAL; break;
  208. case 's': minPrio = ANDROID_LOG_SILENT; break;
  209. default: minPrio = ANDROID_LOG_DEFAULT; break;
  210. }
  211. }
  212. tags++;
  213. if (*tags != '\0' && !isspace(*tags)) {
  214. TRACE("ERROR: garbage in tag env; expected whitespace\n");
  215. TRACE(" env='%s'\n", tags);
  216. return;
  217. }
  218. }
  219. if (tagName[0] == 0) {
  220. logState->globalMinPriority = minPrio;
  221. TRACE("+++ global min prio %d\n", logState->globalMinPriority);
  222. } else {
  223. logState->tagSet[entry].minPriority = minPrio;
  224. strcpy(logState->tagSet[entry].tag, tagName);
  225. TRACE("+++ entry %d: %s:%d\n",
  226. entry,
  227. logState->tagSet[entry].tag,
  228. logState->tagSet[entry].minPriority);
  229. entry++;
  230. }
  231. }
  232. }
  233. /*
  234. * Taken from the long-dead utils/Log.cpp
  235. */
  236. const char* fstr = getenv("ANDROID_PRINTF_LOG");
  237. LogFormat format;
  238. if (fstr == NULL) {
  239. format = FORMAT_BRIEF;
  240. } else {
  241. if (strcmp(fstr, "brief") == 0)
  242. format = FORMAT_BRIEF;
  243. else if (strcmp(fstr, "process") == 0)
  244. format = FORMAT_PROCESS;
  245. else if (strcmp(fstr, "tag") == 0)
  246. format = FORMAT_PROCESS;
  247. else if (strcmp(fstr, "thread") == 0)
  248. format = FORMAT_PROCESS;
  249. else if (strcmp(fstr, "raw") == 0)
  250. format = FORMAT_PROCESS;
  251. else if (strcmp(fstr, "time") == 0)
  252. format = FORMAT_PROCESS;
  253. else if (strcmp(fstr, "long") == 0)
  254. format = FORMAT_PROCESS;
  255. else
  256. format = (LogFormat) atoi(fstr); // really?!
  257. }
  258. logState->outputFormat = format;
  259. }
  260. /*
  261. * Return a human-readable string for the priority level. Always returns
  262. * a valid string.
  263. */
  264. static const char* getPriorityString(int priority)
  265. {
  266. /* the first character of each string should be unique */
  267. static const char* priorityStrings[] = {
  268. "Verbose", "Debug", "Info", "Warn", "Error", "Assert"
  269. };
  270. int idx;
  271. idx = (int) priority - (int) ANDROID_LOG_VERBOSE;
  272. if (idx < 0 ||
  273. idx >= (int) (sizeof(priorityStrings) / sizeof(priorityStrings[0])))
  274. return "?unknown?";
  275. return priorityStrings[idx];
  276. }
  277. #ifndef HAVE_WRITEV
  278. /*
  279. * Some platforms like WIN32 do not have writev().
  280. * Make up something to replace it.
  281. */
  282. static ssize_t fake_writev(int fd, const struct iovec *iov, int iovcnt) {
  283. ssize_t result = 0;
  284. const struct iovec* end = iov + iovcnt;
  285. for (; iov < end; iov++) {
  286. ssize_t w = write(fd, iov->iov_base, iov->iov_len);
  287. if (w != (ssize_t) iov->iov_len) {
  288. if (w < 0)
  289. return w;
  290. return result + w;
  291. }
  292. result += w;
  293. }
  294. return result;
  295. }
  296. #define writev fake_writev
  297. #endif
  298. /*
  299. * Write a filtered log message to stderr.
  300. *
  301. * Log format parsing taken from the long-dead utils/Log.cpp.
  302. */
  303. static void showLog(LogState *state,
  304. int logPrio, const char* tag, const char* msg)
  305. {
  306. #if defined(HAVE_LOCALTIME_R)
  307. struct tm tmBuf;
  308. #endif
  309. struct tm* ptm;
  310. char timeBuf[32];
  311. char prefixBuf[128], suffixBuf[128];
  312. char priChar;
  313. time_t when;
  314. pid_t pid, tid;
  315. TRACE("LOG %d: %s %s", logPrio, tag, msg);
  316. priChar = getPriorityString(logPrio)[0];
  317. when = time(NULL);
  318. pid = tid = getpid(); // find gettid()?
  319. /*
  320. * Get the current date/time in pretty form
  321. *
  322. * It's often useful when examining a log with "less" to jump to
  323. * a specific point in the file by searching for the date/time stamp.
  324. * For this reason it's very annoying to have regexp meta characters
  325. * in the time stamp. Don't use forward slashes, parenthesis,
  326. * brackets, asterisks, or other special chars here.
  327. */
  328. #if defined(HAVE_LOCALTIME_R)
  329. ptm = localtime_r(&when, &tmBuf);
  330. #else
  331. ptm = localtime(&when);
  332. #endif
  333. //strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
  334. strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
  335. /*
  336. * Construct a buffer containing the log header and log message.
  337. */
  338. size_t prefixLen, suffixLen;
  339. switch (state->outputFormat) {
  340. case FORMAT_TAG:
  341. prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
  342. "%c/%-8s: ", priChar, tag);
  343. strcpy(suffixBuf, "\n"); suffixLen = 1;
  344. break;
  345. case FORMAT_PROCESS:
  346. prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
  347. "%c(%5d) ", priChar, pid);
  348. suffixLen = snprintf(suffixBuf, sizeof(suffixBuf),
  349. " (%s)\n", tag);
  350. break;
  351. case FORMAT_THREAD:
  352. prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
  353. "%c(%5d:%5d) ", priChar, pid, tid);
  354. strcpy(suffixBuf, "\n"); suffixLen = 1;
  355. break;
  356. case FORMAT_RAW:
  357. prefixBuf[0] = 0; prefixLen = 0;
  358. strcpy(suffixBuf, "\n"); suffixLen = 1;
  359. break;
  360. case FORMAT_TIME:
  361. prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
  362. "%s %-8s\n\t", timeBuf, tag);
  363. strcpy(suffixBuf, "\n"); suffixLen = 1;
  364. break;
  365. case FORMAT_THREADTIME:
  366. prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
  367. "%s %5d %5d %c %-8s \n\t", timeBuf, pid, tid, priChar, tag);
  368. strcpy(suffixBuf, "\n"); suffixLen = 1;
  369. break;
  370. case FORMAT_LONG:
  371. prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
  372. "[ %s %5d:%5d %c/%-8s ]\n",
  373. timeBuf, pid, tid, priChar, tag);
  374. strcpy(suffixBuf, "\n\n"); suffixLen = 2;
  375. break;
  376. default:
  377. prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
  378. "%c/%-8s(%5d): ", priChar, tag, pid);
  379. strcpy(suffixBuf, "\n"); suffixLen = 1;
  380. break;
  381. }
  382. /*
  383. * Figure out how many lines there will be.
  384. */
  385. const char* end = msg + strlen(msg);
  386. size_t numLines = 0;
  387. const char* p = msg;
  388. while (p < end) {
  389. if (*p++ == '\n') numLines++;
  390. }
  391. if (p > msg && *(p-1) != '\n') numLines++;
  392. /*
  393. * Create an array of iovecs large enough to write all of
  394. * the lines with a prefix and a suffix.
  395. */
  396. const size_t INLINE_VECS = 6;
  397. const size_t MAX_LINES = ((size_t)~0)/(3*sizeof(struct iovec*));
  398. struct iovec stackVec[INLINE_VECS];
  399. struct iovec* vec = stackVec;
  400. size_t numVecs;
  401. if (numLines > MAX_LINES)
  402. numLines = MAX_LINES;
  403. numVecs = numLines*3; // 3 iovecs per line.
  404. if (numVecs > INLINE_VECS) {
  405. vec = (struct iovec*)malloc(sizeof(struct iovec)*numVecs);
  406. if (vec == NULL) {
  407. msg = "LOG: write failed, no memory";
  408. numVecs = 3;
  409. numLines = 1;
  410. vec = stackVec;
  411. }
  412. }
  413. /*
  414. * Fill in the iovec pointers.
  415. */
  416. p = msg;
  417. struct iovec* v = vec;
  418. int totalLen = 0;
  419. while (numLines > 0 && p < end) {
  420. if (prefixLen > 0) {
  421. v->iov_base = prefixBuf;
  422. v->iov_len = prefixLen;
  423. totalLen += prefixLen;
  424. v++;
  425. }
  426. const char* start = p;
  427. while (p < end && *p != '\n') p++;
  428. if ((p-start) > 0) {
  429. v->iov_base = (void*)start;
  430. v->iov_len = p-start;
  431. totalLen += p-start;
  432. v++;
  433. }
  434. if (*p == '\n') p++;
  435. if (suffixLen > 0) {
  436. v->iov_base = suffixBuf;
  437. v->iov_len = suffixLen;
  438. totalLen += suffixLen;
  439. v++;
  440. }
  441. numLines -= 1;
  442. }
  443. /*
  444. * Write the entire message to the log file with a single writev() call.
  445. * We need to use this rather than a collection of printf()s on a FILE*
  446. * because of multi-threading and multi-process issues.
  447. *
  448. * If the file was not opened with O_APPEND, this will produce interleaved
  449. * output when called on the same file from multiple processes.
  450. *
  451. * If the file descriptor is actually a network socket, the writev()
  452. * call may return with a partial write. Putting the writev() call in
  453. * a loop can result in interleaved data. This can be alleviated
  454. * somewhat by wrapping the writev call in the Mutex.
  455. */
  456. for(;;) {
  457. int cc = writev(fileno(stderr), vec, v-vec);
  458. if (cc == totalLen) break;
  459. if (cc < 0) {
  460. if(errno == EINTR) continue;
  461. /* can't really log the failure; for now, throw out a stderr */
  462. fprintf(stderr, "+++ LOG: write failed (errno=%d)\n", errno);
  463. break;
  464. } else {
  465. /* shouldn't happen when writing to file or tty */
  466. fprintf(stderr, "+++ LOG: write partial (%d of %d)\n", cc, totalLen);
  467. break;
  468. }
  469. }
  470. /* if we allocated storage for the iovecs, free it */
  471. if (vec != stackVec)
  472. free(vec);
  473. }
  474. /*
  475. * Receive a log message. We happen to know that "vector" has three parts:
  476. *
  477. * priority (1 byte)
  478. * tag (N bytes -- null-terminated ASCII string)
  479. * message (N bytes -- null-terminated ASCII string)
  480. */
  481. static ssize_t logWritev(int fd, const struct iovec* vector, int count)
  482. {
  483. LogState* state;
  484. /* Make sure that no-one frees the LogState while we're using it.
  485. * Also guarantees that only one thread is in showLog() at a given
  486. * time (if it matters).
  487. */
  488. lock();
  489. state = fdToLogState(fd);
  490. if (state == NULL) {
  491. errno = EBADF;
  492. goto error;
  493. }
  494. if (state->isBinary) {
  495. TRACE("%s: ignoring binary log\n", state->debugName);
  496. goto bail;
  497. }
  498. if (count != 3) {
  499. TRACE("%s: writevLog with count=%d not expected\n",
  500. state->debugName, count);
  501. goto error;
  502. }
  503. /* pull out the three fields */
  504. int logPrio = *(const char*)vector[0].iov_base;
  505. const char* tag = (const char*) vector[1].iov_base;
  506. const char* msg = (const char*) vector[2].iov_base;
  507. /* see if this log tag is configured */
  508. int i;
  509. int minPrio = state->globalMinPriority;
  510. for (i = 0; i < kTagSetSize; i++) {
  511. if (state->tagSet[i].minPriority == ANDROID_LOG_UNKNOWN)
  512. break; /* reached end of configured values */
  513. if (strcmp(state->tagSet[i].tag, tag) == 0) {
  514. //TRACE("MATCH tag '%s'\n", tag);
  515. minPrio = state->tagSet[i].minPriority;
  516. break;
  517. }
  518. }
  519. if (logPrio >= minPrio) {
  520. showLog(state, logPrio, tag, msg);
  521. } else {
  522. //TRACE("+++ NOLOG(%d): %s %s", logPrio, tag, msg);
  523. }
  524. bail:
  525. unlock();
  526. return vector[0].iov_len + vector[1].iov_len + vector[2].iov_len;
  527. error:
  528. unlock();
  529. return -1;
  530. }
  531. /*
  532. * Free up our state and close the fake descriptor.
  533. */
  534. static int logClose(int fd)
  535. {
  536. deleteFakeFd(fd);
  537. return 0;
  538. }
  539. /*
  540. * Open a log output device and return a fake fd.
  541. */
  542. static int logOpen(const char* pathName, int flags __unused)
  543. {
  544. LogState *logState;
  545. int fd = -1;
  546. lock();
  547. logState = createLogState();
  548. if (logState != NULL) {
  549. configureInitialState(pathName, logState);
  550. fd = logState->fakeFd;
  551. } else {
  552. errno = ENFILE;
  553. }
  554. unlock();
  555. return fd;
  556. }
  557. /*
  558. * Runtime redirection. If this binary is running in the simulator,
  559. * just pass log messages to the emulated device. If it's running
  560. * outside of the simulator, write the log messages to stderr.
  561. */
  562. static int (*redirectOpen)(const char *pathName, int flags) = NULL;
  563. static int (*redirectClose)(int fd) = NULL;
  564. static ssize_t (*redirectWritev)(int fd, const struct iovec* vector, int count)
  565. = NULL;
  566. static void setRedirects()
  567. {
  568. const char *ws;
  569. /* Wrapsim sets this environment variable on children that it's
  570. * created using its LD_PRELOAD wrapper.
  571. */
  572. ws = getenv("ANDROID_WRAPSIM");
  573. if (ws != NULL && strcmp(ws, "1") == 0) {
  574. /* We're running inside wrapsim, so we can just write to the device. */
  575. redirectOpen = (int (*)(const char *pathName, int flags))open;
  576. redirectClose = close;
  577. redirectWritev = writev;
  578. } else {
  579. /* There's no device to delegate to; handle the logging ourselves. */
  580. redirectOpen = logOpen;
  581. redirectClose = logClose;
  582. redirectWritev = logWritev;
  583. }
  584. }
  585. int fakeLogOpen(const char *pathName, int flags)
  586. {
  587. if (redirectOpen == NULL) {
  588. setRedirects();
  589. }
  590. return redirectOpen(pathName, flags);
  591. }
  592. int fakeLogClose(int fd)
  593. {
  594. /* Assume that open() was called first. */
  595. return redirectClose(fd);
  596. }
  597. ssize_t fakeLogWritev(int fd, const struct iovec* vector, int count)
  598. {
  599. /* Assume that open() was called first. */
  600. return redirectWritev(fd, vector, count);
  601. }