Home | History | Annotate | Download | only in liblog
      1 /*
      2  * Copyright (C) 2007-2016 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 #include <errno.h>
     18 #include <stdatomic.h>
     19 #include <stdlib.h>
     20 #include <string.h>
     21 #include <sys/time.h>
     22 
     23 #ifdef __BIONIC__
     24 #include <android/set_abort_message.h>
     25 #endif
     26 
     27 #include <log/event_tag_map.h>
     28 #include <log/log_transport.h>
     29 #include <private/android_filesystem_config.h>
     30 #include <private/android_logger.h>
     31 
     32 #include "config_read.h" /* __android_log_config_read_close() definition */
     33 #include "config_write.h"
     34 #include "log_portability.h"
     35 #include "logger.h"
     36 
     37 #define LOG_BUF_SIZE 1024
     38 
     39 static int __write_to_log_init(log_id_t, struct iovec* vec, size_t nr);
     40 static int (*write_to_log)(log_id_t, struct iovec* vec,
     41                            size_t nr) = __write_to_log_init;
     42 
     43 /*
     44  * This is used by the C++ code to decide if it should write logs through
     45  * the C code.  Basically, if /dev/socket/logd is available, we're running in
     46  * the simulator rather than a desktop tool and want to use the device.
     47  */
     48 static enum {
     49   kLogUninitialized,
     50   kLogNotAvailable,
     51   kLogAvailable
     52 } g_log_status = kLogUninitialized;
     53 
     54 static int check_log_uid_permissions() {
     55 #if defined(__ANDROID__)
     56   uid_t uid = __android_log_uid();
     57 
     58   /* Matches clientHasLogCredentials() in logd */
     59   if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
     60     uid = geteuid();
     61     if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
     62       gid_t gid = getgid();
     63       if ((gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) {
     64         gid = getegid();
     65         if ((gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) {
     66           int num_groups;
     67           gid_t* groups;
     68 
     69           num_groups = getgroups(0, NULL);
     70           if (num_groups <= 0) {
     71             return -EPERM;
     72           }
     73           groups = calloc(num_groups, sizeof(gid_t));
     74           if (!groups) {
     75             return -ENOMEM;
     76           }
     77           num_groups = getgroups(num_groups, groups);
     78           while (num_groups > 0) {
     79             if (groups[num_groups - 1] == AID_LOG) {
     80               break;
     81             }
     82             --num_groups;
     83           }
     84           free(groups);
     85           if (num_groups <= 0) {
     86             return -EPERM;
     87           }
     88         }
     89       }
     90     }
     91   }
     92 #endif
     93   return 0;
     94 }
     95 
     96 static void __android_log_cache_available(
     97     struct android_log_transport_write* node) {
     98   size_t i;
     99 
    100   if (node->logMask) {
    101     return;
    102   }
    103 
    104   for (i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
    105     if (node->write && (i != LOG_ID_KERNEL) &&
    106         ((i != LOG_ID_SECURITY) || (check_log_uid_permissions() == 0)) &&
    107         (!node->available || ((*node->available)(i) >= 0))) {
    108       node->logMask |= 1 << i;
    109     }
    110   }
    111 }
    112 
    113 LIBLOG_ABI_PUBLIC int __android_log_dev_available() {
    114   struct android_log_transport_write* node;
    115 
    116   if (list_empty(&__android_log_transport_write)) {
    117     return kLogUninitialized;
    118   }
    119 
    120   write_transport_for_each(node, &__android_log_transport_write) {
    121     __android_log_cache_available(node);
    122     if (node->logMask) {
    123       return kLogAvailable;
    124     }
    125   }
    126   return kLogNotAvailable;
    127 }
    128 
    129 #if defined(__ANDROID__)
    130 static atomic_uintptr_t tagMap;
    131 #endif
    132 
    133 /*
    134  * Release any logger resources. A new log write will immediately re-acquire.
    135  */
    136 LIBLOG_ABI_PUBLIC void __android_log_close() {
    137   struct android_log_transport_write* transport;
    138 #if defined(__ANDROID__)
    139   EventTagMap* m;
    140 #endif
    141 
    142   __android_log_lock();
    143 
    144   write_to_log = __write_to_log_init;
    145 
    146   /*
    147    * Threads that are actively writing at this point are not held back
    148    * by a lock and are at risk of dropping the messages with a return code
    149    * -EBADF. Prefer to return error code than add the overhead of a lock to
    150    * each log writing call to guarantee delivery. In addition, anyone
    151    * calling this is doing so to release the logging resources and shut down,
    152    * for them to do so with outstanding log requests in other threads is a
    153    * disengenuous use of this function.
    154    */
    155 
    156   write_transport_for_each(transport, &__android_log_persist_write) {
    157     if (transport->close) {
    158       (*transport->close)();
    159     }
    160   }
    161 
    162   write_transport_for_each(transport, &__android_log_transport_write) {
    163     if (transport->close) {
    164       (*transport->close)();
    165     }
    166   }
    167 
    168   __android_log_config_write_close();
    169 
    170 #if defined(__ANDROID__)
    171   /*
    172    * Additional risk here somewhat mitigated by immediately unlock flushing
    173    * the processor cache. The multi-threaded race that we choose to accept,
    174    * to minimize locking, is an atomic_load in a writer picking up a value
    175    * just prior to entering this routine. There will be an use after free.
    176    *
    177    * Again, anyone calling this is doing so to release the logging resources
    178    * is most probably going to quiesce then shut down; or to restart after
    179    * a fork so the risk should be non-existent. For this reason we
    180    * choose a mitigation stance for efficiency instead of incuring the cost
    181    * of a lock for every log write.
    182    */
    183   m = (EventTagMap*)atomic_exchange(&tagMap, (uintptr_t)0);
    184 #endif
    185 
    186   __android_log_unlock();
    187 
    188 #if defined(__ANDROID__)
    189   if (m != (EventTagMap*)(uintptr_t)-1LL) android_closeEventTagMap(m);
    190 #endif
    191 }
    192 
    193 /* log_init_lock assumed */
    194 static int __write_to_log_initialize() {
    195   struct android_log_transport_write* transport;
    196   struct listnode* n;
    197   int i = 0, ret = 0;
    198 
    199   __android_log_config_write();
    200   write_transport_for_each_safe(transport, n, &__android_log_transport_write) {
    201     __android_log_cache_available(transport);
    202     if (!transport->logMask) {
    203       list_remove(&transport->node);
    204       continue;
    205     }
    206     if (!transport->open || ((*transport->open)() < 0)) {
    207       if (transport->close) {
    208         (*transport->close)();
    209       }
    210       list_remove(&transport->node);
    211       continue;
    212     }
    213     ++ret;
    214   }
    215   write_transport_for_each_safe(transport, n, &__android_log_persist_write) {
    216     __android_log_cache_available(transport);
    217     if (!transport->logMask) {
    218       list_remove(&transport->node);
    219       continue;
    220     }
    221     if (!transport->open || ((*transport->open)() < 0)) {
    222       if (transport->close) {
    223         (*transport->close)();
    224       }
    225       list_remove(&transport->node);
    226       continue;
    227     }
    228     ++i;
    229   }
    230   if (!ret && !i) {
    231     return -ENODEV;
    232   }
    233 
    234   return ret;
    235 }
    236 
    237 /*
    238  * Extract a 4-byte value from a byte stream. le32toh open coded
    239  */
    240 static inline uint32_t get4LE(const uint8_t* src) {
    241   return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
    242 }
    243 
    244 static int __write_to_log_daemon(log_id_t log_id, struct iovec* vec, size_t nr) {
    245   struct android_log_transport_write* node;
    246   int ret, save_errno;
    247   struct timespec ts;
    248   size_t len, i;
    249 
    250   for (len = i = 0; i < nr; ++i) {
    251     len += vec[i].iov_len;
    252   }
    253   if (!len) {
    254     return -EINVAL;
    255   }
    256 
    257   save_errno = errno;
    258 #if defined(__ANDROID__)
    259   clock_gettime(android_log_clockid(), &ts);
    260 
    261   if (log_id == LOG_ID_SECURITY) {
    262     if (vec[0].iov_len < 4) {
    263       errno = save_errno;
    264       return -EINVAL;
    265     }
    266 
    267     ret = check_log_uid_permissions();
    268     if (ret < 0) {
    269       errno = save_errno;
    270       return ret;
    271     }
    272     if (!__android_log_security()) {
    273       /* If only we could reset downstream logd counter */
    274       errno = save_errno;
    275       return -EPERM;
    276     }
    277   } else if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
    278     const char* tag;
    279     size_t len;
    280     EventTagMap *m, *f;
    281 
    282     if (vec[0].iov_len < 4) {
    283       errno = save_errno;
    284       return -EINVAL;
    285     }
    286 
    287     tag = NULL;
    288     len = 0;
    289     f = NULL;
    290     m = (EventTagMap*)atomic_load(&tagMap);
    291 
    292     if (!m) {
    293       ret = __android_log_trylock();
    294       m = (EventTagMap*)atomic_load(&tagMap); /* trylock flush cache */
    295       if (!m) {
    296         m = android_openEventTagMap(NULL);
    297         if (ret) { /* trylock failed, use local copy, mark for close */
    298           f = m;
    299         } else {
    300           if (!m) { /* One chance to open map file */
    301             m = (EventTagMap*)(uintptr_t)-1LL;
    302           }
    303           atomic_store(&tagMap, (uintptr_t)m);
    304         }
    305       }
    306       if (!ret) { /* trylock succeeded, unlock */
    307         __android_log_unlock();
    308       }
    309     }
    310     if (m && (m != (EventTagMap*)(uintptr_t)-1LL)) {
    311       tag = android_lookupEventTag_len(m, &len, get4LE(vec[0].iov_base));
    312     }
    313     ret = __android_log_is_loggable_len(ANDROID_LOG_INFO, tag, len,
    314                                         ANDROID_LOG_VERBOSE);
    315     if (f) { /* local copy marked for close */
    316       android_closeEventTagMap(f);
    317     }
    318     if (!ret) {
    319       errno = save_errno;
    320       return -EPERM;
    321     }
    322   } else {
    323     /* Validate the incoming tag, tag content can not split across iovec */
    324     char prio = ANDROID_LOG_VERBOSE;
    325     const char* tag = vec[0].iov_base;
    326     size_t len = vec[0].iov_len;
    327     if (!tag) {
    328       len = 0;
    329     }
    330     if (len > 0) {
    331       prio = *tag;
    332       if (len > 1) {
    333         --len;
    334         ++tag;
    335       } else {
    336         len = vec[1].iov_len;
    337         tag = ((const char*)vec[1].iov_base);
    338         if (!tag) {
    339           len = 0;
    340         }
    341       }
    342     }
    343     /* tag must be nul terminated */
    344     if (tag && strnlen(tag, len) >= len) {
    345       tag = NULL;
    346     }
    347 
    348     if (!__android_log_is_loggable_len(prio, tag, len - 1, ANDROID_LOG_VERBOSE)) {
    349       errno = save_errno;
    350       return -EPERM;
    351     }
    352   }
    353 #else
    354   /* simulate clock_gettime(CLOCK_REALTIME, &ts); */
    355   {
    356     struct timeval tv;
    357     gettimeofday(&tv, NULL);
    358     ts.tv_sec = tv.tv_sec;
    359     ts.tv_nsec = tv.tv_usec * 1000;
    360   }
    361 #endif
    362 
    363   ret = 0;
    364   i = 1 << log_id;
    365   write_transport_for_each(node, &__android_log_transport_write) {
    366     if (node->logMask & i) {
    367       ssize_t retval;
    368       retval = (*node->write)(log_id, &ts, vec, nr);
    369       if (ret >= 0) {
    370         ret = retval;
    371       }
    372     }
    373   }
    374 
    375   write_transport_for_each(node, &__android_log_persist_write) {
    376     if (node->logMask & i) {
    377       (void)(*node->write)(log_id, &ts, vec, nr);
    378     }
    379   }
    380 
    381   errno = save_errno;
    382   return ret;
    383 }
    384 
    385 static int __write_to_log_init(log_id_t log_id, struct iovec* vec, size_t nr) {
    386   int ret, save_errno = errno;
    387 
    388   __android_log_lock();
    389 
    390   if (write_to_log == __write_to_log_init) {
    391     ret = __write_to_log_initialize();
    392     if (ret < 0) {
    393       __android_log_unlock();
    394       if (!list_empty(&__android_log_persist_write)) {
    395         __write_to_log_daemon(log_id, vec, nr);
    396       }
    397       errno = save_errno;
    398       return ret;
    399     }
    400 
    401     write_to_log = __write_to_log_daemon;
    402   }
    403 
    404   __android_log_unlock();
    405 
    406   ret = write_to_log(log_id, vec, nr);
    407   errno = save_errno;
    408   return ret;
    409 }
    410 
    411 LIBLOG_ABI_PUBLIC int __android_log_write(int prio, const char* tag,
    412                                           const char* msg) {
    413   return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
    414 }
    415 
    416 LIBLOG_ABI_PUBLIC int __android_log_buf_write(int bufID, int prio,
    417                                               const char* tag, const char* msg) {
    418   struct iovec vec[3];
    419   char tmp_tag[32];
    420 
    421   if (!tag) tag = "";
    422 
    423   /* XXX: This needs to go! */
    424   if (bufID != LOG_ID_RADIO) {
    425     switch (tag[0]) {
    426       case 'H':
    427         if (strcmp(tag + 1, "HTC_RIL" + 1)) break;
    428         goto inform;
    429       case 'R':
    430         /* Any log tag with "RIL" as the prefix */
    431         if (strncmp(tag + 1, "RIL" + 1, strlen("RIL") - 1)) break;
    432         goto inform;
    433       case 'Q':
    434         /* Any log tag with "QC_RIL" as the prefix */
    435         if (strncmp(tag + 1, "QC_RIL" + 1, strlen("QC_RIL") - 1)) break;
    436         goto inform;
    437       case 'I':
    438         /* Any log tag with "IMS" as the prefix */
    439         if (strncmp(tag + 1, "IMS" + 1, strlen("IMS") - 1)) break;
    440         goto inform;
    441       case 'A':
    442         if (strcmp(tag + 1, "AT" + 1)) break;
    443         goto inform;
    444       case 'G':
    445         if (strcmp(tag + 1, "GSM" + 1)) break;
    446         goto inform;
    447       case 'S':
    448         if (strcmp(tag + 1, "STK" + 1) && strcmp(tag + 1, "SMS" + 1)) break;
    449         goto inform;
    450       case 'C':
    451         if (strcmp(tag + 1, "CDMA" + 1)) break;
    452         goto inform;
    453       case 'P':
    454         if (strcmp(tag + 1, "PHONE" + 1)) break;
    455       /* FALLTHRU */
    456       inform:
    457         bufID = LOG_ID_RADIO;
    458         snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
    459         tag = tmp_tag;
    460       /* FALLTHRU */
    461       default:
    462         break;
    463     }
    464   }
    465 
    466 #if __BIONIC__
    467   if (prio == ANDROID_LOG_FATAL) {
    468     android_set_abort_message(msg);
    469   }
    470 #endif
    471 
    472   vec[0].iov_base = (unsigned char*)&prio;
    473   vec[0].iov_len = 1;
    474   vec[1].iov_base = (void*)tag;
    475   vec[1].iov_len = strlen(tag) + 1;
    476   vec[2].iov_base = (void*)msg;
    477   vec[2].iov_len = strlen(msg) + 1;
    478 
    479   return write_to_log(bufID, vec, 3);
    480 }
    481 
    482 LIBLOG_ABI_PUBLIC int __android_log_vprint(int prio, const char* tag,
    483                                            const char* fmt, va_list ap) {
    484   char buf[LOG_BUF_SIZE];
    485 
    486   vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
    487 
    488   return __android_log_write(prio, tag, buf);
    489 }
    490 
    491 LIBLOG_ABI_PUBLIC int __android_log_print(int prio, const char* tag,
    492                                           const char* fmt, ...) {
    493   va_list ap;
    494   char buf[LOG_BUF_SIZE];
    495 
    496   va_start(ap, fmt);
    497   vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
    498   va_end(ap);
    499 
    500   return __android_log_write(prio, tag, buf);
    501 }
    502 
    503 LIBLOG_ABI_PUBLIC int __android_log_buf_print(int bufID, int prio,
    504                                               const char* tag, const char* fmt,
    505                                               ...) {
    506   va_list ap;
    507   char buf[LOG_BUF_SIZE];
    508 
    509   va_start(ap, fmt);
    510   vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
    511   va_end(ap);
    512 
    513   return __android_log_buf_write(bufID, prio, tag, buf);
    514 }
    515 
    516 LIBLOG_ABI_PUBLIC void __android_log_assert(const char* cond, const char* tag,
    517                                             const char* fmt, ...) {
    518   char buf[LOG_BUF_SIZE];
    519 
    520   if (fmt) {
    521     va_list ap;
    522     va_start(ap, fmt);
    523     vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
    524     va_end(ap);
    525   } else {
    526     /* Msg not provided, log condition.  N.B. Do not use cond directly as
    527      * format string as it could contain spurious '%' syntax (e.g.
    528      * "%d" in "blocks%devs == 0").
    529      */
    530     if (cond)
    531       snprintf(buf, LOG_BUF_SIZE, "Assertion failed: %s", cond);
    532     else
    533       strcpy(buf, "Unspecified assertion failed");
    534   }
    535 
    536   // Log assertion failures to stderr for the benefit of "adb shell" users
    537   // and gtests (http://b/23675822).
    538   struct iovec iov[2] = {
    539     { buf, strlen(buf) }, { (char*)"\n", 1 },
    540   };
    541   TEMP_FAILURE_RETRY(writev(2, iov, 2));
    542 
    543   __android_log_write(ANDROID_LOG_FATAL, tag, buf);
    544   abort(); /* abort so we have a chance to debug the situation */
    545            /* NOTREACHED */
    546 }
    547 
    548 LIBLOG_ABI_PUBLIC int __android_log_bwrite(int32_t tag, const void* payload,
    549                                            size_t len) {
    550   struct iovec vec[2];
    551 
    552   vec[0].iov_base = &tag;
    553   vec[0].iov_len = sizeof(tag);
    554   vec[1].iov_base = (void*)payload;
    555   vec[1].iov_len = len;
    556 
    557   return write_to_log(LOG_ID_EVENTS, vec, 2);
    558 }
    559 
    560 LIBLOG_ABI_PUBLIC int __android_log_stats_bwrite(int32_t tag,
    561                                                  const void* payload,
    562                                                  size_t len) {
    563   struct iovec vec[2];
    564 
    565   vec[0].iov_base = &tag;
    566   vec[0].iov_len = sizeof(tag);
    567   vec[1].iov_base = (void*)payload;
    568   vec[1].iov_len = len;
    569 
    570   return write_to_log(LOG_ID_STATS, vec, 2);
    571 }
    572 
    573 LIBLOG_ABI_PUBLIC int __android_log_security_bwrite(int32_t tag,
    574                                                     const void* payload,
    575                                                     size_t len) {
    576   struct iovec vec[2];
    577 
    578   vec[0].iov_base = &tag;
    579   vec[0].iov_len = sizeof(tag);
    580   vec[1].iov_base = (void*)payload;
    581   vec[1].iov_len = len;
    582 
    583   return write_to_log(LOG_ID_SECURITY, vec, 2);
    584 }
    585 
    586 /*
    587  * Like __android_log_bwrite, but takes the type as well.  Doesn't work
    588  * for the general case where we're generating lists of stuff, but very
    589  * handy if we just want to dump an integer into the log.
    590  */
    591 LIBLOG_ABI_PUBLIC int __android_log_btwrite(int32_t tag, char type,
    592                                             const void* payload, size_t len) {
    593   struct iovec vec[3];
    594 
    595   vec[0].iov_base = &tag;
    596   vec[0].iov_len = sizeof(tag);
    597   vec[1].iov_base = &type;
    598   vec[1].iov_len = sizeof(type);
    599   vec[2].iov_base = (void*)payload;
    600   vec[2].iov_len = len;
    601 
    602   return write_to_log(LOG_ID_EVENTS, vec, 3);
    603 }
    604 
    605 /*
    606  * Like __android_log_bwrite, but used for writing strings to the
    607  * event log.
    608  */
    609 LIBLOG_ABI_PUBLIC int __android_log_bswrite(int32_t tag, const char* payload) {
    610   struct iovec vec[4];
    611   char type = EVENT_TYPE_STRING;
    612   uint32_t len = strlen(payload);
    613 
    614   vec[0].iov_base = &tag;
    615   vec[0].iov_len = sizeof(tag);
    616   vec[1].iov_base = &type;
    617   vec[1].iov_len = sizeof(type);
    618   vec[2].iov_base = &len;
    619   vec[2].iov_len = sizeof(len);
    620   vec[3].iov_base = (void*)payload;
    621   vec[3].iov_len = len;
    622 
    623   return write_to_log(LOG_ID_EVENTS, vec, 4);
    624 }
    625 
    626 /*
    627  * Like __android_log_security_bwrite, but used for writing strings to the
    628  * security log.
    629  */
    630 LIBLOG_ABI_PUBLIC int __android_log_security_bswrite(int32_t tag,
    631                                                      const char* payload) {
    632   struct iovec vec[4];
    633   char type = EVENT_TYPE_STRING;
    634   uint32_t len = strlen(payload);
    635 
    636   vec[0].iov_base = &tag;
    637   vec[0].iov_len = sizeof(tag);
    638   vec[1].iov_base = &type;
    639   vec[1].iov_len = sizeof(type);
    640   vec[2].iov_base = &len;
    641   vec[2].iov_len = sizeof(len);
    642   vec[3].iov_base = (void*)payload;
    643   vec[3].iov_len = len;
    644 
    645   return write_to_log(LOG_ID_SECURITY, vec, 4);
    646 }
    647 
    648 static int __write_to_log_null(log_id_t log_id, struct iovec* vec, size_t nr) {
    649   size_t len, i;
    650 
    651   if ((log_id < LOG_ID_MIN) || (log_id >= LOG_ID_MAX)) {
    652     return -EINVAL;
    653   }
    654 
    655   for (len = i = 0; i < nr; ++i) {
    656     len += vec[i].iov_len;
    657   }
    658   if (!len) {
    659     return -EINVAL;
    660   }
    661   return len;
    662 }
    663 
    664 /* Following functions need access to our internal write_to_log status */
    665 
    666 LIBLOG_HIDDEN int __android_log_transport;
    667 
    668 LIBLOG_ABI_PUBLIC int android_set_log_transport(int transport_flag) {
    669   int retval;
    670 
    671   if (transport_flag < 0) {
    672     return -EINVAL;
    673   }
    674 
    675   retval = LOGGER_NULL;
    676 
    677   __android_log_lock();
    678 
    679   if (transport_flag & LOGGER_NULL) {
    680     write_to_log = __write_to_log_null;
    681 
    682     __android_log_unlock();
    683 
    684     return retval;
    685   }
    686 
    687   __android_log_transport &= LOGGER_LOCAL | LOGGER_LOGD | LOGGER_STDERR;
    688 
    689   transport_flag &= LOGGER_LOCAL | LOGGER_LOGD | LOGGER_STDERR;
    690 
    691   if (__android_log_transport != transport_flag) {
    692     __android_log_transport = transport_flag;
    693     __android_log_config_write_close();
    694     __android_log_config_read_close();
    695 
    696     write_to_log = __write_to_log_init;
    697     /* generically we only expect these two values for write_to_log */
    698   } else if ((write_to_log != __write_to_log_init) &&
    699              (write_to_log != __write_to_log_daemon)) {
    700     write_to_log = __write_to_log_init;
    701   }
    702 
    703   retval = __android_log_transport;
    704 
    705   __android_log_unlock();
    706 
    707   return retval;
    708 }
    709 
    710 LIBLOG_ABI_PUBLIC int android_get_log_transport() {
    711   int ret = LOGGER_DEFAULT;
    712 
    713   __android_log_lock();
    714   if (write_to_log == __write_to_log_null) {
    715     ret = LOGGER_NULL;
    716   } else {
    717     __android_log_transport &= LOGGER_LOCAL | LOGGER_LOGD | LOGGER_STDERR;
    718     ret = __android_log_transport;
    719     if ((write_to_log != __write_to_log_init) &&
    720         (write_to_log != __write_to_log_daemon)) {
    721       ret = -EINVAL;
    722     }
    723   }
    724   __android_log_unlock();
    725 
    726   return ret;
    727 }
    728