Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2017 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 <fcntl.h> |
| 19 | #include <pthread.h> |
| 20 | #if !defined(__MINGW32__) |
| 21 | #include <pwd.h> |
| 22 | #endif |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 23 | #include <log/uio.h> |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 24 | #include <sched.h> |
| 25 | #include <stdlib.h> |
| 26 | #include <string.h> |
| 27 | #include <sys/types.h> |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 28 | |
| 29 | #include <cutils/list.h> /* template, no library dependency */ |
Mark Salyzyn | 81321a7 | 2017-03-09 07:28:29 -0800 | [diff] [blame] | 30 | #include <log/log_transport.h> |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 31 | #include <private/android_filesystem_config.h> |
| 32 | #include <private/android_logger.h> |
| 33 | #include <system/thread_defs.h> |
| 34 | |
| 35 | #include "config_read.h" |
| 36 | #include "config_write.h" |
| 37 | #include "log_portability.h" |
| 38 | #include "logger.h" |
| 39 | |
| 40 | static const char baseServiceName[] = "android.logd"; |
| 41 | |
| 42 | static int writeToLocalInit(); |
| 43 | static int writeToLocalAvailable(log_id_t logId); |
| 44 | static void writeToLocalReset(); |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 45 | static int writeToLocalWrite(log_id_t logId, struct timespec* ts, |
| 46 | struct iovec* vec, size_t nr); |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 47 | |
| 48 | LIBLOG_HIDDEN struct android_log_transport_write localLoggerWrite = { |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 49 | .node = { &localLoggerWrite.node, &localLoggerWrite.node }, |
Mark Salyzyn | 04bbc8e | 2017-03-08 15:03:20 -0800 | [diff] [blame] | 50 | .context.priv = NULL, |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 51 | .name = "local", |
| 52 | .available = writeToLocalAvailable, |
| 53 | .open = writeToLocalInit, |
| 54 | .close = writeToLocalReset, |
| 55 | .write = writeToLocalWrite, |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 56 | }; |
| 57 | |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 58 | static int writeToLocalVersion(struct android_log_logger* logger, |
| 59 | struct android_log_transport_context* transp); |
| 60 | static int writeToLocalRead(struct android_log_logger_list* logger_list, |
| 61 | struct android_log_transport_context* transp, |
| 62 | struct log_msg* log_msg); |
| 63 | static int writeToLocalPoll(struct android_log_logger_list* logger_list, |
| 64 | struct android_log_transport_context* transp); |
| 65 | static void writeToLocalClose(struct android_log_logger_list* logger_list, |
| 66 | struct android_log_transport_context* transp); |
| 67 | static int writeToLocalClear(struct android_log_logger* logger, |
| 68 | struct android_log_transport_context* transp); |
| 69 | static ssize_t writeToLocalGetSize(struct android_log_logger* logger, |
| 70 | struct android_log_transport_context* transp); |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 71 | static ssize_t writeToLocalSetSize( |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 72 | struct android_log_logger* logger, |
| 73 | struct android_log_transport_context* transp __unused, size_t size); |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 74 | static ssize_t writeToLocalGetReadbleSize( |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 75 | struct android_log_logger* logger, |
| 76 | struct android_log_transport_context* transp); |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 77 | |
| 78 | struct android_log_transport_read localLoggerRead = { |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 79 | .node = { &localLoggerRead.node, &localLoggerRead.node }, |
| 80 | .name = "local", |
| 81 | .available = writeToLocalAvailable, |
| 82 | .version = writeToLocalVersion, |
| 83 | .read = writeToLocalRead, |
| 84 | .poll = writeToLocalPoll, |
| 85 | .close = writeToLocalClose, |
| 86 | .clear = writeToLocalClear, |
| 87 | .getSize = writeToLocalGetSize, |
| 88 | .setSize = writeToLocalSetSize, |
| 89 | .getReadableSize = writeToLocalGetReadbleSize, |
| 90 | .getPrune = NULL, |
| 91 | .setPrune = NULL, |
| 92 | .getStats = NULL, |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 93 | }; |
| 94 | |
| 95 | struct LogBufferElement { |
| 96 | struct listnode node; |
| 97 | log_id_t logId; |
| 98 | pid_t tid; |
| 99 | log_time timestamp; |
| 100 | unsigned short len; |
| 101 | char msg[]; |
| 102 | }; |
| 103 | |
| 104 | static const size_t MAX_SIZE_DEFAULT = 32768; |
| 105 | |
| 106 | /* |
| 107 | * Number of log buffers we support with the following assumption: |
| 108 | * . . . |
| 109 | * LOG_ID_SECURITY = 5, // security logs go to the system logs only |
| 110 | * LOG_ID_KERNEL = 6, // place last, third-parties can not use it |
| 111 | * LOG_ID_MAX |
| 112 | * } log_id_t; |
| 113 | * |
| 114 | * Confirm the following should <log/log_id.h> be adjusted in the future. |
| 115 | */ |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 116 | #define NUMBER_OF_LOG_BUFFERS \ |
| 117 | ((LOG_ID_SECURITY == (LOG_ID_MAX - 2)) ? LOG_ID_SECURITY : LOG_ID_KERNEL) |
| 118 | #define BLOCK_LOG_BUFFERS(id) \ |
| 119 | (((id) == LOG_ID_SECURITY) || ((id) == LOG_ID_KERNEL)) |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 120 | |
| 121 | static struct LogBuffer { |
| 122 | struct listnode head; |
| 123 | pthread_rwlock_t listLock; |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 124 | char* serviceName; /* Also indicates ready by having a value */ |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 125 | /* Order and proximity important for memset */ |
| 126 | size_t number[NUMBER_OF_LOG_BUFFERS]; /* clear memset */ |
| 127 | size_t size[NUMBER_OF_LOG_BUFFERS]; /* clear memset */ |
| 128 | size_t totalSize[NUMBER_OF_LOG_BUFFERS]; /* init memset */ |
| 129 | size_t maxSize[NUMBER_OF_LOG_BUFFERS]; /* init MAX_SIZE_DEFAULT */ |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 130 | struct listnode* last[NUMBER_OF_LOG_BUFFERS]; /* init &head */ |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 131 | } logbuf = { |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 132 | .head = { &logbuf.head, &logbuf.head }, .listLock = PTHREAD_RWLOCK_INITIALIZER, |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 133 | }; |
| 134 | |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 135 | static void LogBufferInit(struct LogBuffer* log) { |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 136 | size_t i; |
| 137 | |
| 138 | pthread_rwlock_wrlock(&log->listLock); |
| 139 | list_init(&log->head); |
| 140 | memset(log->number, 0, |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 141 | sizeof(log->number) + sizeof(log->size) + sizeof(log->totalSize)); |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 142 | for (i = 0; i < NUMBER_OF_LOG_BUFFERS; ++i) { |
| 143 | log->maxSize[i] = MAX_SIZE_DEFAULT; |
| 144 | log->last[i] = &log->head; |
| 145 | } |
| 146 | #ifdef __BIONIC__ |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 147 | asprintf(&log->serviceName, "%s@%d:%d", baseServiceName, __android_log_uid(), |
| 148 | getpid()); |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 149 | #else |
| 150 | char buffer[sizeof(baseServiceName) + 1 + 5 + 1 + 5 + 8]; |
| 151 | snprintf(buffer, sizeof(buffer), "%s@%d:%d", baseServiceName, |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 152 | __android_log_uid(), getpid()); |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 153 | log->serviceName = strdup(buffer); |
| 154 | #endif |
| 155 | pthread_rwlock_unlock(&log->listLock); |
| 156 | } |
| 157 | |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 158 | static void LogBufferClear(struct LogBuffer* log) { |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 159 | size_t i; |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 160 | struct listnode* node; |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 161 | |
| 162 | pthread_rwlock_wrlock(&log->listLock); |
| 163 | memset(log->number, 0, sizeof(log->number) + sizeof(log->size)); |
| 164 | for (i = 0; i < NUMBER_OF_LOG_BUFFERS; ++i) { |
| 165 | log->last[i] = &log->head; |
| 166 | } |
| 167 | while ((node = list_head(&log->head)) != &log->head) { |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 168 | struct LogBufferElement* element; |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 169 | |
| 170 | element = node_to_item(node, struct LogBufferElement, node); |
| 171 | list_remove(node); |
| 172 | free(element); |
| 173 | } |
| 174 | pthread_rwlock_unlock(&log->listLock); |
| 175 | } |
| 176 | |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 177 | static inline void LogBufferFree(struct LogBuffer* log) { |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 178 | pthread_rwlock_wrlock(&log->listLock); |
| 179 | free(log->serviceName); |
| 180 | log->serviceName = NULL; |
| 181 | pthread_rwlock_unlock(&log->listLock); |
| 182 | LogBufferClear(log); |
| 183 | } |
| 184 | |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 185 | static int LogBufferLog(struct LogBuffer* log, |
| 186 | struct LogBufferElement* element) { |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 187 | log_id_t logId = element->logId; |
| 188 | |
| 189 | pthread_rwlock_wrlock(&log->listLock); |
| 190 | log->number[logId]++; |
| 191 | log->size[logId] += element->len; |
| 192 | log->totalSize[logId] += element->len; |
| 193 | /* prune entry(s) until enough space is available */ |
| 194 | if (log->last[logId] == &log->head) { |
| 195 | log->last[logId] = list_tail(&log->head); |
| 196 | } |
| 197 | while (log->size[logId] > log->maxSize[logId]) { |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 198 | struct listnode* node = log->last[logId]; |
| 199 | struct LogBufferElement* e; |
| 200 | struct android_log_logger_list* logger_list; |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 201 | |
| 202 | e = node_to_item(node, struct LogBufferElement, node); |
| 203 | log->number[logId]--; |
| 204 | log->size[logId] -= e->len; |
| 205 | logger_list_rdlock(); |
| 206 | logger_list_for_each(logger_list) { |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 207 | struct android_log_transport_context* transp; |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 208 | |
| 209 | transport_context_for_each(transp, logger_list) { |
| 210 | if ((transp->transport == &localLoggerRead) && |
| 211 | (transp->context.node == node)) { |
| 212 | if (node == &log->head) { |
| 213 | transp->context.node = &log->head; |
| 214 | } else { |
| 215 | transp->context.node = node->next; |
| 216 | } |
| 217 | } |
| 218 | } |
| 219 | } |
| 220 | logger_list_unlock(); |
| 221 | if (node != &log->head) { |
| 222 | log->last[logId] = node->prev; |
| 223 | } |
| 224 | list_remove(node); |
Ting-Yuan Huang | 249bd05 | 2017-08-15 17:01:33 -0700 | [diff] [blame] | 225 | LOG_ALWAYS_FATAL_IF(node == log->last[logId], "corrupted list"); |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 226 | free(e); |
| 227 | } |
| 228 | /* add entry to list */ |
| 229 | list_add_head(&log->head, &element->node); |
| 230 | /* ToDo: wake up all readers */ |
| 231 | pthread_rwlock_unlock(&log->listLock); |
| 232 | |
| 233 | return element->len; |
| 234 | } |
| 235 | |
| 236 | /* |
| 237 | * return zero if permitted to log directly to logd, |
| 238 | * return 1 if binder server started and |
| 239 | * return negative error number if failed to start binder server. |
| 240 | */ |
| 241 | static int writeToLocalInit() { |
| 242 | pthread_attr_t attr; |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 243 | struct LogBuffer* log; |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 244 | |
| 245 | if (writeToLocalAvailable(LOG_ID_MAIN) < 0) { |
| 246 | return -EPERM; |
| 247 | } |
| 248 | |
| 249 | log = &logbuf; |
| 250 | if (!log->serviceName) { |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 251 | LogBufferInit(log); |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 252 | } |
| 253 | |
| 254 | if (!log->serviceName) { |
| 255 | LogBufferFree(log); |
| 256 | return -ENOMEM; |
| 257 | } |
| 258 | |
| 259 | return EPERM; /* successful local-only logging */ |
| 260 | } |
| 261 | |
| 262 | static void writeToLocalReset() { |
| 263 | LogBufferFree(&logbuf); |
| 264 | } |
| 265 | |
| 266 | static int writeToLocalAvailable(log_id_t logId) { |
| 267 | #if !defined(__MINGW32__) |
| 268 | uid_t uid; |
| 269 | #endif |
| 270 | |
| 271 | if ((logId >= NUMBER_OF_LOG_BUFFERS) || BLOCK_LOG_BUFFERS(logId)) { |
| 272 | return -EINVAL; |
| 273 | } |
| 274 | |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 275 | /* Android hard coded permitted, system goes to logd */ |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 276 | #if !defined(__MINGW32__) |
Mark Salyzyn | 81321a7 | 2017-03-09 07:28:29 -0800 | [diff] [blame] | 277 | if (__android_log_transport == LOGGER_DEFAULT) { |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 278 | uid = __android_log_uid(); |
| 279 | if ((uid < AID_APP) && (getpwuid(uid) != NULL)) { |
| 280 | return -EPERM; |
| 281 | } |
| 282 | } |
| 283 | #endif |
| 284 | |
| 285 | /* ToDo: Ask package manager for LOGD permissions */ |
| 286 | /* Assume we do _not_ have permissions to go to LOGD, so must go local */ |
| 287 | return 0; |
| 288 | } |
| 289 | |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 290 | static int writeToLocalWrite(log_id_t logId, struct timespec* ts, |
| 291 | struct iovec* vec, size_t nr) { |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 292 | size_t len, i; |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 293 | struct LogBufferElement* element; |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 294 | |
| 295 | if ((logId >= NUMBER_OF_LOG_BUFFERS) || BLOCK_LOG_BUFFERS(logId)) { |
| 296 | return -EINVAL; |
| 297 | } |
| 298 | |
| 299 | len = 0; |
| 300 | for (i = 0; i < nr; ++i) { |
| 301 | len += vec[i].iov_len; |
| 302 | } |
| 303 | |
| 304 | if (len > LOGGER_ENTRY_MAX_PAYLOAD) { |
| 305 | len = LOGGER_ENTRY_MAX_PAYLOAD; |
| 306 | } |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 307 | element = (struct LogBufferElement*)calloc( |
| 308 | 1, sizeof(struct LogBufferElement) + len + 1); |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 309 | if (!element) { |
| 310 | return errno ? -errno : -ENOMEM; |
| 311 | } |
| 312 | element->timestamp.tv_sec = ts->tv_sec; |
| 313 | element->timestamp.tv_nsec = ts->tv_nsec; |
| 314 | #ifdef __BIONIC__ |
| 315 | element->tid = gettid(); |
| 316 | #else |
| 317 | element->tid = getpid(); |
| 318 | #endif |
| 319 | element->logId = logId; |
| 320 | element->len = len; |
| 321 | |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 322 | char* cp = element->msg; |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 323 | for (i = 0; i < nr; ++i) { |
| 324 | size_t iov_len = vec[i].iov_len; |
| 325 | if (iov_len > len) { |
| 326 | iov_len = len; |
| 327 | } |
| 328 | memcpy(cp, vec[i].iov_base, iov_len); |
| 329 | len -= iov_len; |
| 330 | if (len == 0) { |
| 331 | break; |
| 332 | } |
| 333 | cp += iov_len; |
| 334 | } |
| 335 | |
| 336 | return LogBufferLog(&logbuf, element); |
| 337 | } |
| 338 | |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 339 | static int writeToLocalVersion(struct android_log_logger* logger __unused, |
| 340 | struct android_log_transport_context* transp |
| 341 | __unused) { |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 342 | return 3; |
| 343 | } |
| 344 | |
| 345 | /* within reader lock, serviceName already validated */ |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 346 | static struct listnode* writeToLocalNode( |
| 347 | struct android_log_logger_list* logger_list, |
| 348 | struct android_log_transport_context* transp) { |
| 349 | struct listnode* node; |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 350 | unsigned logMask; |
| 351 | unsigned int tail; |
| 352 | |
| 353 | node = transp->context.node; |
| 354 | if (node) { |
| 355 | return node; |
| 356 | } |
| 357 | |
| 358 | if (!logger_list->tail) { |
| 359 | return transp->context.node = &logbuf.head; |
| 360 | } |
| 361 | |
| 362 | logMask = transp->logMask; |
| 363 | tail = logger_list->tail; |
| 364 | |
| 365 | for (node = list_head(&logbuf.head); node != &logbuf.head; node = node->next) { |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 366 | struct LogBufferElement* element; |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 367 | log_id_t logId; |
| 368 | |
| 369 | element = node_to_item(node, struct LogBufferElement, node); |
| 370 | logId = element->logId; |
| 371 | |
| 372 | if ((logMask & (1 << logId)) && !--tail) { |
| 373 | node = node->next; |
| 374 | break; |
| 375 | } |
| 376 | } |
| 377 | return transp->context.node = node; |
| 378 | } |
| 379 | |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 380 | static int writeToLocalRead(struct android_log_logger_list* logger_list, |
| 381 | struct android_log_transport_context* transp, |
| 382 | struct log_msg* log_msg) { |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 383 | int ret; |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 384 | struct listnode* node; |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 385 | unsigned logMask; |
| 386 | |
| 387 | pthread_rwlock_rdlock(&logbuf.listLock); |
| 388 | if (!logbuf.serviceName) { |
| 389 | pthread_rwlock_unlock(&logbuf.listLock); |
| 390 | return (logger_list->mode & ANDROID_LOG_NONBLOCK) ? -ENODEV : 0; |
| 391 | } |
| 392 | |
| 393 | logMask = transp->logMask; |
| 394 | |
| 395 | node = writeToLocalNode(logger_list, transp); |
| 396 | |
| 397 | ret = 0; |
| 398 | |
| 399 | while (node != list_head(&logbuf.head)) { |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 400 | struct LogBufferElement* element; |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 401 | log_id_t logId; |
| 402 | |
| 403 | node = node->prev; |
| 404 | element = node_to_item(node, struct LogBufferElement, node); |
| 405 | logId = element->logId; |
| 406 | |
| 407 | if (logMask & (1 << logId)) { |
| 408 | ret = log_msg->entry_v3.len = element->len; |
| 409 | log_msg->entry_v3.hdr_size = sizeof(log_msg->entry_v3); |
| 410 | log_msg->entry_v3.pid = getpid(); |
| 411 | log_msg->entry_v3.tid = element->tid; |
| 412 | log_msg->entry_v3.sec = element->timestamp.tv_sec; |
| 413 | log_msg->entry_v3.nsec = element->timestamp.tv_nsec; |
| 414 | log_msg->entry_v3.lid = logId; |
| 415 | memcpy(log_msg->entry_v3.msg, element->msg, ret); |
| 416 | ret += log_msg->entry_v3.hdr_size; |
| 417 | break; |
| 418 | } |
| 419 | } |
| 420 | |
| 421 | transp->context.node = node; |
| 422 | |
| 423 | /* ToDo: if blocking, and no entry, put reader to sleep */ |
| 424 | pthread_rwlock_unlock(&logbuf.listLock); |
| 425 | return ret; |
| 426 | } |
| 427 | |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 428 | static int writeToLocalPoll(struct android_log_logger_list* logger_list, |
| 429 | struct android_log_transport_context* transp) { |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 430 | int ret = (logger_list->mode & ANDROID_LOG_NONBLOCK) ? -ENODEV : 0; |
| 431 | |
| 432 | pthread_rwlock_rdlock(&logbuf.listLock); |
| 433 | |
| 434 | if (logbuf.serviceName) { |
| 435 | unsigned logMask = transp->logMask; |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 436 | struct listnode* node = writeToLocalNode(logger_list, transp); |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 437 | |
| 438 | ret = (node != list_head(&logbuf.head)); |
| 439 | if (ret) { |
| 440 | do { |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 441 | ret = !!(logMask & |
| 442 | (1 << (node_to_item(node->prev, struct LogBufferElement, node)) |
| 443 | ->logId)); |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 444 | } while (!ret && ((node = node->prev) != list_head(&logbuf.head))); |
| 445 | } |
| 446 | |
| 447 | transp->context.node = node; |
| 448 | } |
| 449 | |
| 450 | pthread_rwlock_unlock(&logbuf.listLock); |
| 451 | |
| 452 | return ret; |
| 453 | } |
| 454 | |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 455 | static void writeToLocalClose(struct android_log_logger_list* logger_list |
| 456 | __unused, |
| 457 | struct android_log_transport_context* transp) { |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 458 | pthread_rwlock_wrlock(&logbuf.listLock); |
| 459 | transp->context.node = list_head(&logbuf.head); |
| 460 | pthread_rwlock_unlock(&logbuf.listLock); |
| 461 | } |
| 462 | |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 463 | static int writeToLocalClear(struct android_log_logger* logger, |
| 464 | struct android_log_transport_context* unused |
| 465 | __unused) { |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 466 | log_id_t logId = logger->logId; |
| 467 | struct listnode *node, *n; |
| 468 | |
| 469 | if ((logId >= NUMBER_OF_LOG_BUFFERS) || BLOCK_LOG_BUFFERS(logId)) { |
| 470 | return -EINVAL; |
| 471 | } |
| 472 | |
| 473 | pthread_rwlock_wrlock(&logbuf.listLock); |
| 474 | logbuf.number[logId] = 0; |
| 475 | logbuf.last[logId] = &logbuf.head; |
| 476 | list_for_each_safe(node, n, &logbuf.head) { |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 477 | struct LogBufferElement* element; |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 478 | element = node_to_item(node, struct LogBufferElement, node); |
| 479 | |
| 480 | if (logId == element->logId) { |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 481 | struct android_log_logger_list* logger_list; |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 482 | |
| 483 | logger_list_rdlock(); |
| 484 | logger_list_for_each(logger_list) { |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 485 | struct android_log_transport_context* transp; |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 486 | |
| 487 | transport_context_for_each(transp, logger_list) { |
| 488 | if ((transp->transport == &localLoggerRead) && |
| 489 | (transp->context.node == node)) { |
| 490 | transp->context.node = node->next; |
| 491 | } |
| 492 | } |
| 493 | } |
| 494 | logger_list_unlock(); |
| 495 | list_remove(node); |
| 496 | free(element); |
| 497 | } |
| 498 | } |
| 499 | |
| 500 | pthread_rwlock_unlock(&logbuf.listLock); |
| 501 | |
| 502 | return 0; |
| 503 | } |
| 504 | |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 505 | static ssize_t writeToLocalGetSize(struct android_log_logger* logger, |
| 506 | struct android_log_transport_context* transp |
| 507 | __unused) { |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 508 | ssize_t ret = -EINVAL; |
| 509 | log_id_t logId = logger->logId; |
| 510 | |
| 511 | if ((logId < NUMBER_OF_LOG_BUFFERS) && !BLOCK_LOG_BUFFERS(logId)) { |
| 512 | pthread_rwlock_rdlock(&logbuf.listLock); |
| 513 | ret = logbuf.maxSize[logId]; |
| 514 | pthread_rwlock_unlock(&logbuf.listLock); |
| 515 | } |
| 516 | |
| 517 | return ret; |
| 518 | } |
| 519 | |
| 520 | static ssize_t writeToLocalSetSize( |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 521 | struct android_log_logger* logger, |
| 522 | struct android_log_transport_context* transp __unused, size_t size) { |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 523 | ssize_t ret = -EINVAL; |
| 524 | |
| 525 | if ((size > LOGGER_ENTRY_MAX_LEN) || (size < (4 * 1024 * 1024))) { |
| 526 | log_id_t logId = logger->logId; |
| 527 | if ((logId < NUMBER_OF_LOG_BUFFERS) || !BLOCK_LOG_BUFFERS(logId)) { |
| 528 | pthread_rwlock_wrlock(&logbuf.listLock); |
| 529 | ret = logbuf.maxSize[logId] = size; |
| 530 | pthread_rwlock_unlock(&logbuf.listLock); |
| 531 | } |
| 532 | } |
| 533 | |
| 534 | return ret; |
| 535 | } |
| 536 | |
| 537 | static ssize_t writeToLocalGetReadbleSize( |
Mark Salyzyn | 2ed51d7 | 2017-03-09 08:09:43 -0800 | [diff] [blame] | 538 | struct android_log_logger* logger, |
| 539 | struct android_log_transport_context* transp __unused) { |
Mark Salyzyn | 7100288 | 2016-03-08 16:18:26 -0800 | [diff] [blame] | 540 | ssize_t ret = -EINVAL; |
| 541 | log_id_t logId = logger->logId; |
| 542 | |
| 543 | if ((logId < NUMBER_OF_LOG_BUFFERS) && !BLOCK_LOG_BUFFERS(logId)) { |
| 544 | pthread_rwlock_rdlock(&logbuf.listLock); |
| 545 | ret = logbuf.serviceName ? (ssize_t)logbuf.size[logId] : -EBADF; |
| 546 | pthread_rwlock_unlock(&logbuf.listLock); |
| 547 | } |
| 548 | |
| 549 | return ret; |
| 550 | } |