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 <endian.h>
     18 #include <errno.h>
     19 #include <fcntl.h>
     20 #include <inttypes.h>
     21 #include <poll.h>
     22 #include <stdarg.h>
     23 #include <stdatomic.h>
     24 #include <stdio.h>
     25 #include <stdlib.h>
     26 #include <string.h>
     27 #include <sys/socket.h>
     28 #include <sys/stat.h>
     29 #include <sys/types.h>
     30 #include <sys/un.h>
     31 #include <time.h>
     32 #include <unistd.h>
     33 
     34 #include <cutils/sockets.h>
     35 #include <private/android_filesystem_config.h>
     36 #include <private/android_logger.h>
     37 
     38 #include "config_write.h"
     39 #include "log_portability.h"
     40 #include "logger.h"
     41 
     42 /* branchless on many architectures. */
     43 #define min(x, y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
     44 
     45 static int logdAvailable(log_id_t LogId);
     46 static int logdOpen();
     47 static void logdClose();
     48 static int logdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec,
     49                      size_t nr);
     50 
     51 LIBLOG_HIDDEN struct android_log_transport_write logdLoggerWrite = {
     52   .node = { &logdLoggerWrite.node, &logdLoggerWrite.node },
     53   .context.sock = -EBADF,
     54   .name = "logd",
     55   .available = logdAvailable,
     56   .open = logdOpen,
     57   .close = logdClose,
     58   .write = logdWrite,
     59 };
     60 
     61 /* log_init_lock assumed */
     62 static int logdOpen() {
     63   int i, ret = 0;
     64 
     65   i = atomic_load(&logdLoggerWrite.context.sock);
     66   if (i < 0) {
     67     int sock = TEMP_FAILURE_RETRY(
     68         socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
     69     if (sock < 0) {
     70       ret = -errno;
     71     } else {
     72       struct sockaddr_un un;
     73       memset(&un, 0, sizeof(struct sockaddr_un));
     74       un.sun_family = AF_UNIX;
     75       strcpy(un.sun_path, "/dev/socket/logdw");
     76 
     77       if (TEMP_FAILURE_RETRY(connect(sock, (struct sockaddr*)&un,
     78                                      sizeof(struct sockaddr_un))) < 0) {
     79         ret = -errno;
     80         switch (ret) {
     81           case -ENOTCONN:
     82           case -ECONNREFUSED:
     83           case -ENOENT:
     84             i = atomic_exchange(&logdLoggerWrite.context.sock, ret);
     85           /* FALLTHRU */
     86           default:
     87             break;
     88         }
     89         close(sock);
     90       } else {
     91         ret = atomic_exchange(&logdLoggerWrite.context.sock, sock);
     92         if ((ret >= 0) && (ret != sock)) {
     93           close(ret);
     94         }
     95         ret = 0;
     96       }
     97     }
     98   }
     99 
    100   return ret;
    101 }
    102 
    103 static void __logdClose(int negative_errno) {
    104   int sock = atomic_exchange(&logdLoggerWrite.context.sock, negative_errno);
    105   if (sock >= 0) {
    106     close(sock);
    107   }
    108 }
    109 
    110 static void logdClose() {
    111   __logdClose(-EBADF);
    112 }
    113 
    114 static int logdAvailable(log_id_t logId) {
    115   if (logId >= LOG_ID_MAX || logId == LOG_ID_KERNEL) {
    116     return -EINVAL;
    117   }
    118   if (atomic_load(&logdLoggerWrite.context.sock) < 0) {
    119     if (access("/dev/socket/logdw", W_OK) == 0) {
    120       return 0;
    121     }
    122     return -EBADF;
    123   }
    124   return 1;
    125 }
    126 
    127 static int logdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec,
    128                      size_t nr) {
    129   ssize_t ret;
    130   int sock;
    131   static const unsigned headerLength = 1;
    132   struct iovec newVec[nr + headerLength];
    133   android_log_header_t header;
    134   size_t i, payloadSize;
    135   static atomic_int_fast32_t dropped;
    136   static atomic_int_fast32_t droppedSecurity;
    137 
    138   sock = atomic_load(&logdLoggerWrite.context.sock);
    139   if (sock < 0) switch (sock) {
    140       case -ENOTCONN:
    141       case -ECONNREFUSED:
    142       case -ENOENT:
    143         break;
    144       default:
    145         return -EBADF;
    146     }
    147 
    148   /* logd, after initialization and priv drop */
    149   if (__android_log_uid() == AID_LOGD) {
    150     /*
    151      * ignore log messages we send to ourself (logd).
    152      * Such log messages are often generated by libraries we depend on
    153      * which use standard Android logging.
    154      */
    155     return 0;
    156   }
    157 
    158   /*
    159    *  struct {
    160    *      // what we provide to socket
    161    *      android_log_header_t header;
    162    *      // caller provides
    163    *      union {
    164    *          struct {
    165    *              char     prio;
    166    *              char     payload[];
    167    *          } string;
    168    *          struct {
    169    *              uint32_t tag
    170    *              char     payload[];
    171    *          } binary;
    172    *      };
    173    *  };
    174    */
    175 
    176   header.tid = gettid();
    177   header.realtime.tv_sec = ts->tv_sec;
    178   header.realtime.tv_nsec = ts->tv_nsec;
    179 
    180   newVec[0].iov_base = (unsigned char*)&header;
    181   newVec[0].iov_len = sizeof(header);
    182 
    183   if (sock >= 0) {
    184     int32_t snapshot =
    185         atomic_exchange_explicit(&droppedSecurity, 0, memory_order_relaxed);
    186     if (snapshot) {
    187       android_log_event_int_t buffer;
    188 
    189       header.id = LOG_ID_SECURITY;
    190       buffer.header.tag = htole32(LIBLOG_LOG_TAG);
    191       buffer.payload.type = EVENT_TYPE_INT;
    192       buffer.payload.data = htole32(snapshot);
    193 
    194       newVec[headerLength].iov_base = &buffer;
    195       newVec[headerLength].iov_len = sizeof(buffer);
    196 
    197       ret = TEMP_FAILURE_RETRY(writev(sock, newVec, 2));
    198       if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
    199         atomic_fetch_add_explicit(&droppedSecurity, snapshot,
    200                                   memory_order_relaxed);
    201       }
    202     }
    203     snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
    204     if (snapshot &&
    205         __android_log_is_loggable_len(ANDROID_LOG_INFO, "liblog",
    206                                       strlen("liblog"), ANDROID_LOG_VERBOSE)) {
    207       android_log_event_int_t buffer;
    208 
    209       header.id = LOG_ID_EVENTS;
    210       buffer.header.tag = htole32(LIBLOG_LOG_TAG);
    211       buffer.payload.type = EVENT_TYPE_INT;
    212       buffer.payload.data = htole32(snapshot);
    213 
    214       newVec[headerLength].iov_base = &buffer;
    215       newVec[headerLength].iov_len = sizeof(buffer);
    216 
    217       ret = TEMP_FAILURE_RETRY(writev(sock, newVec, 2));
    218       if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
    219         atomic_fetch_add_explicit(&dropped, snapshot, memory_order_relaxed);
    220       }
    221     }
    222   }
    223 
    224   header.id = logId;
    225 
    226   for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
    227     newVec[i].iov_base = vec[i - headerLength].iov_base;
    228     payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
    229 
    230     if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
    231       newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
    232       if (newVec[i].iov_len) {
    233         ++i;
    234       }
    235       break;
    236     }
    237   }
    238 
    239   /*
    240    * The write below could be lost, but will never block.
    241    *
    242    * ENOTCONN occurs if logd has died.
    243    * ENOENT occurs if logd is not running and socket is missing.
    244    * ECONNREFUSED occurs if we can not reconnect to logd.
    245    * EAGAIN occurs if logd is overloaded.
    246    */
    247   if (sock < 0) {
    248     ret = sock;
    249   } else {
    250     ret = TEMP_FAILURE_RETRY(writev(sock, newVec, i));
    251     if (ret < 0) {
    252       ret = -errno;
    253     }
    254   }
    255   switch (ret) {
    256     case -ENOTCONN:
    257     case -ECONNREFUSED:
    258     case -ENOENT:
    259       if (__android_log_trylock()) {
    260         return ret; /* in a signal handler? try again when less stressed */
    261       }
    262       __logdClose(ret);
    263       ret = logdOpen();
    264       __android_log_unlock();
    265 
    266       if (ret < 0) {
    267         return ret;
    268       }
    269 
    270       ret = TEMP_FAILURE_RETRY(
    271           writev(atomic_load(&logdLoggerWrite.context.sock), newVec, i));
    272       if (ret < 0) {
    273         ret = -errno;
    274       }
    275     /* FALLTHRU */
    276     default:
    277       break;
    278   }
    279 
    280   if (ret > (ssize_t)sizeof(header)) {
    281     ret -= sizeof(header);
    282   } else if (ret == -EAGAIN) {
    283     atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
    284     if (logId == LOG_ID_SECURITY) {
    285       atomic_fetch_add_explicit(&droppedSecurity, 1, memory_order_relaxed);
    286     }
    287   }
    288 
    289   return ret;
    290 }
    291