blob: f5d19cadb27ab8dc8d6574e3bc553ccf06ff7b2b [file] [log] [blame]
Mark Salyzyn018a96d2016-03-01 13:45:42 -08001/*
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
Tom Cherry21bb36c2020-01-08 15:18:26 -080017#include "logd_writer.h"
18
Mark Salyzyn018a96d2016-03-01 13:45:42 -080019#include <errno.h>
20#include <fcntl.h>
21#include <inttypes.h>
22#include <poll.h>
23#include <stdarg.h>
24#include <stdatomic.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
Mark Salyzyn2ed51d72017-03-09 08:09:43 -080028#include <sys/socket.h>
Mark Salyzyn018a96d2016-03-01 13:45:42 -080029#include <sys/stat.h>
30#include <sys/types.h>
Mark Salyzyn018a96d2016-03-01 13:45:42 -080031#include <sys/un.h>
32#include <time.h>
33#include <unistd.h>
34
Mark Salyzyn018a96d2016-03-01 13:45:42 -080035#include <private/android_filesystem_config.h>
36#include <private/android_logger.h>
37
Mark Salyzyn018a96d2016-03-01 13:45:42 -080038#include "logger.h"
Tom Cherry6f6ef392019-01-16 14:17:08 -080039#include "uio.h"
Mark Salyzyn018a96d2016-03-01 13:45:42 -080040
Tom Cherry7acfba22020-04-24 17:15:26 -070041static atomic_int logd_socket;
Mark Salyzyn018a96d2016-03-01 13:45:42 -080042
Tom Cherry7acfba22020-04-24 17:15:26 -070043// Note that it is safe to call connect() multiple times on DGRAM Unix domain sockets, so this
44// function is used to reconnect to logd without requiring a new socket.
45static void LogdConnect() {
Tom Cherry2a6811b2019-12-11 12:56:01 -080046 sockaddr_un un = {};
47 un.sun_family = AF_UNIX;
48 strcpy(un.sun_path, "/dev/socket/logdw");
Tom Cherry7acfba22020-04-24 17:15:26 -070049 TEMP_FAILURE_RETRY(connect(logd_socket, reinterpret_cast<sockaddr*>(&un), sizeof(sockaddr_un)));
Mark Salyzyn2ed51d72017-03-09 08:09:43 -080050}
51
Tom Cherry7acfba22020-04-24 17:15:26 -070052// logd_socket should only be opened once. If we see that logd_socket is uninitialized, we create a
53// new socket and attempt to exchange it into the atomic logd_socket. If the compare/exchange was
54// successful, then that will be the socket used for the duration of the program, otherwise a
55// different thread has already opened and written the socket to the atomic, so close the new socket
56// and return.
57static void GetSocket() {
58 if (logd_socket != 0) {
Tom Cherry2a6811b2019-12-11 12:56:01 -080059 return;
60 }
61
Tom Cherryc5282c22020-08-12 10:51:27 -070062 int new_socket = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0));
Tom Cherry7acfba22020-04-24 17:15:26 -070063 if (new_socket <= 0) {
Tom Cherry2a6811b2019-12-11 12:56:01 -080064 return;
Mark Salyzyn2ed51d72017-03-09 08:09:43 -080065 }
Tom Cherry7acfba22020-04-24 17:15:26 -070066
67 int uninitialized_value = 0;
68 if (!logd_socket.compare_exchange_strong(uninitialized_value, new_socket)) {
69 close(new_socket);
70 return;
71 }
72
73 LogdConnect();
Mark Salyzyn2ed51d72017-03-09 08:09:43 -080074}
75
Tom Cherry7acfba22020-04-24 17:15:26 -070076// This is the one exception to the above. Zygote uses this to clean up open FD's after fork() and
77// before specialization. It is single threaded at this point and therefore this function is
78// explicitly not thread safe. It sets logd_socket to 0, so future logs will be safely initialized
79// whenever they happen.
Tom Cherry21bb36c2020-01-08 15:18:26 -080080void LogdClose() {
Tom Cherry2a6811b2019-12-11 12:56:01 -080081 if (logd_socket > 0) {
82 close(logd_socket);
83 }
84 logd_socket = 0;
85}
86
Tom Cherry21bb36c2020-01-08 15:18:26 -080087int LogdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
Mark Salyzyn2ed51d72017-03-09 08:09:43 -080088 ssize_t ret;
Mark Salyzyn2ed51d72017-03-09 08:09:43 -080089 static const unsigned headerLength = 1;
90 struct iovec newVec[nr + headerLength];
91 android_log_header_t header;
92 size_t i, payloadSize;
Mark Salyzyn2ed51d72017-03-09 08:09:43 -080093
Tom Cherry7acfba22020-04-24 17:15:26 -070094 GetSocket();
Tom Cherry2a6811b2019-12-11 12:56:01 -080095
96 if (logd_socket <= 0) {
97 return -EBADF;
98 }
Mark Salyzyn018a96d2016-03-01 13:45:42 -080099
Mark Salyzyn2ed51d72017-03-09 08:09:43 -0800100 /* logd, after initialization and priv drop */
Tom Cherryb47aa2a2020-01-08 15:34:14 -0800101 if (getuid() == AID_LOGD) {
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800102 /*
Mark Salyzyn2ed51d72017-03-09 08:09:43 -0800103 * ignore log messages we send to ourself (logd).
104 * Such log messages are often generated by libraries we depend on
105 * which use standard Android logging.
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800106 */
Mark Salyzyn2ed51d72017-03-09 08:09:43 -0800107 return 0;
108 }
109
Tom Cherryc5282c22020-08-12 10:51:27 -0700110 header.id = logId;
Mark Salyzyn2ed51d72017-03-09 08:09:43 -0800111 header.tid = gettid();
112 header.realtime.tv_sec = ts->tv_sec;
113 header.realtime.tv_nsec = ts->tv_nsec;
114
115 newVec[0].iov_base = (unsigned char*)&header;
116 newVec[0].iov_len = sizeof(header);
117
Mark Salyzyn2ed51d72017-03-09 08:09:43 -0800118 for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
119 newVec[i].iov_base = vec[i - headerLength].iov_base;
120 payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
121
122 if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
123 newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
124 if (newVec[i].iov_len) {
125 ++i;
126 }
127 break;
128 }
129 }
130
Tom Cherry2a6811b2019-12-11 12:56:01 -0800131 ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, i));
Tom Cherryc5282c22020-08-12 10:51:27 -0700132 if (ret < 0) {
Tom Cherry7acfba22020-04-24 17:15:26 -0700133 LogdConnect();
Tom Cherry2a6811b2019-12-11 12:56:01 -0800134
135 ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, i));
Mark Salyzyn2ed51d72017-03-09 08:09:43 -0800136 }
Mark Salyzyn65e1e622017-01-03 13:28:18 -0800137
Tom Cherry2a6811b2019-12-11 12:56:01 -0800138 if (ret < 0) {
139 ret = -errno;
Mark Salyzyn2ed51d72017-03-09 08:09:43 -0800140 }
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800141
Mark Salyzyn2ed51d72017-03-09 08:09:43 -0800142 return ret;
Mark Salyzyn018a96d2016-03-01 13:45:42 -0800143}