xref: /aosp_15_r20/system/logging/liblog/pmsg_writer.cpp (revision 598139dc91b21518d67c408eaea2644226490971)
1*598139dcSAndroid Build Coastguard Worker /*
2*598139dcSAndroid Build Coastguard Worker  * Copyright (C) 2007-2016 The Android Open Source Project
3*598139dcSAndroid Build Coastguard Worker  *
4*598139dcSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*598139dcSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*598139dcSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*598139dcSAndroid Build Coastguard Worker  *
8*598139dcSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*598139dcSAndroid Build Coastguard Worker  *
10*598139dcSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*598139dcSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*598139dcSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*598139dcSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*598139dcSAndroid Build Coastguard Worker  * limitations under the License.
15*598139dcSAndroid Build Coastguard Worker  */
16*598139dcSAndroid Build Coastguard Worker 
17*598139dcSAndroid Build Coastguard Worker #include "pmsg_writer.h"
18*598139dcSAndroid Build Coastguard Worker 
19*598139dcSAndroid Build Coastguard Worker #include <errno.h>
20*598139dcSAndroid Build Coastguard Worker #include <fcntl.h>
21*598139dcSAndroid Build Coastguard Worker #include <stdlib.h>
22*598139dcSAndroid Build Coastguard Worker #include <string.h>
23*598139dcSAndroid Build Coastguard Worker #include <sys/types.h>
24*598139dcSAndroid Build Coastguard Worker #include <time.h>
25*598139dcSAndroid Build Coastguard Worker 
26*598139dcSAndroid Build Coastguard Worker #include <log/log_properties.h>
27*598139dcSAndroid Build Coastguard Worker #include <private/android_logger.h>
28*598139dcSAndroid Build Coastguard Worker 
29*598139dcSAndroid Build Coastguard Worker #include "logger.h"
30*598139dcSAndroid Build Coastguard Worker #include "uio.h"
31*598139dcSAndroid Build Coastguard Worker 
32*598139dcSAndroid Build Coastguard Worker static atomic_int pmsg_fd;
33*598139dcSAndroid Build Coastguard Worker 
GetPmsgFd()34*598139dcSAndroid Build Coastguard Worker static void GetPmsgFd() {
35*598139dcSAndroid Build Coastguard Worker   // Note if open() fails and returns -1, that value is stored into pmsg_fd as an indication that
36*598139dcSAndroid Build Coastguard Worker   // pmsg is not available and open() should not be retried.
37*598139dcSAndroid Build Coastguard Worker   if (pmsg_fd != 0) {
38*598139dcSAndroid Build Coastguard Worker     return;
39*598139dcSAndroid Build Coastguard Worker   }
40*598139dcSAndroid Build Coastguard Worker 
41*598139dcSAndroid Build Coastguard Worker   int new_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
42*598139dcSAndroid Build Coastguard Worker 
43*598139dcSAndroid Build Coastguard Worker   // Unlikely that new_fd is 0, but that is synonymous with our uninitialized value, and we'd prefer
44*598139dcSAndroid Build Coastguard Worker   // STDIN_FILENO != stdin, so we call open() to get a new fd value in this case.
45*598139dcSAndroid Build Coastguard Worker   if (new_fd == 0) {
46*598139dcSAndroid Build Coastguard Worker     new_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
47*598139dcSAndroid Build Coastguard Worker     close(0);
48*598139dcSAndroid Build Coastguard Worker   }
49*598139dcSAndroid Build Coastguard Worker 
50*598139dcSAndroid Build Coastguard Worker   // pmsg_fd should only be opened once.  If we see that pmsg_fd is uninitialized, we open
51*598139dcSAndroid Build Coastguard Worker   // "/dev/pmsg0" then attempt to compare/exchange it into pmsg_fd.  If the compare/exchange was
52*598139dcSAndroid Build Coastguard Worker   // successful, then that will be the fd used for the duration of the program, otherwise a
53*598139dcSAndroid Build Coastguard Worker   // different thread has already opened and written the fd to the atomic, so close the new fd and
54*598139dcSAndroid Build Coastguard Worker   // return.
55*598139dcSAndroid Build Coastguard Worker   int uninitialized_value = 0;
56*598139dcSAndroid Build Coastguard Worker   if (!pmsg_fd.compare_exchange_strong(uninitialized_value, new_fd)) {
57*598139dcSAndroid Build Coastguard Worker     if (new_fd != -1) {
58*598139dcSAndroid Build Coastguard Worker       close(new_fd);
59*598139dcSAndroid Build Coastguard Worker     }
60*598139dcSAndroid Build Coastguard Worker   }
61*598139dcSAndroid Build Coastguard Worker }
62*598139dcSAndroid Build Coastguard Worker 
PmsgClose()63*598139dcSAndroid Build Coastguard Worker void PmsgClose() {
64*598139dcSAndroid Build Coastguard Worker   if (pmsg_fd > 0) {
65*598139dcSAndroid Build Coastguard Worker     close(pmsg_fd);
66*598139dcSAndroid Build Coastguard Worker   }
67*598139dcSAndroid Build Coastguard Worker   pmsg_fd = 0;
68*598139dcSAndroid Build Coastguard Worker }
69*598139dcSAndroid Build Coastguard Worker 
PmsgWrite(log_id_t logId,struct timespec * ts,struct iovec * vec,size_t nr)70*598139dcSAndroid Build Coastguard Worker int PmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
71*598139dcSAndroid Build Coastguard Worker   static const unsigned headerLength = 2;
72*598139dcSAndroid Build Coastguard Worker   struct iovec newVec[nr + headerLength];
73*598139dcSAndroid Build Coastguard Worker   android_log_header_t header;
74*598139dcSAndroid Build Coastguard Worker   android_pmsg_log_header_t pmsgHeader;
75*598139dcSAndroid Build Coastguard Worker   size_t i, payloadSize;
76*598139dcSAndroid Build Coastguard Worker   ssize_t ret;
77*598139dcSAndroid Build Coastguard Worker 
78*598139dcSAndroid Build Coastguard Worker   if (!ANDROID_DEBUGGABLE) {
79*598139dcSAndroid Build Coastguard Worker     if (logId != LOG_ID_EVENTS && logId != LOG_ID_SECURITY) {
80*598139dcSAndroid Build Coastguard Worker       return -1;
81*598139dcSAndroid Build Coastguard Worker     }
82*598139dcSAndroid Build Coastguard Worker 
83*598139dcSAndroid Build Coastguard Worker     if (logId == LOG_ID_EVENTS) {
84*598139dcSAndroid Build Coastguard Worker       if (vec[0].iov_len < 4) {
85*598139dcSAndroid Build Coastguard Worker         return -EINVAL;
86*598139dcSAndroid Build Coastguard Worker       }
87*598139dcSAndroid Build Coastguard Worker 
88*598139dcSAndroid Build Coastguard Worker       if (SNET_EVENT_LOG_TAG != *static_cast<uint32_t*>(vec[0].iov_base)) {
89*598139dcSAndroid Build Coastguard Worker         return -EPERM;
90*598139dcSAndroid Build Coastguard Worker       }
91*598139dcSAndroid Build Coastguard Worker     }
92*598139dcSAndroid Build Coastguard Worker   }
93*598139dcSAndroid Build Coastguard Worker 
94*598139dcSAndroid Build Coastguard Worker   GetPmsgFd();
95*598139dcSAndroid Build Coastguard Worker 
96*598139dcSAndroid Build Coastguard Worker   if (pmsg_fd <= 0) {
97*598139dcSAndroid Build Coastguard Worker     return -EBADF;
98*598139dcSAndroid Build Coastguard Worker   }
99*598139dcSAndroid Build Coastguard Worker 
100*598139dcSAndroid Build Coastguard Worker   /*
101*598139dcSAndroid Build Coastguard Worker    *  struct {
102*598139dcSAndroid Build Coastguard Worker    *      // what we provide to pstore
103*598139dcSAndroid Build Coastguard Worker    *      android_pmsg_log_header_t pmsgHeader;
104*598139dcSAndroid Build Coastguard Worker    *      // what we provide to file
105*598139dcSAndroid Build Coastguard Worker    *      android_log_header_t header;
106*598139dcSAndroid Build Coastguard Worker    *      // caller provides
107*598139dcSAndroid Build Coastguard Worker    *      union {
108*598139dcSAndroid Build Coastguard Worker    *          struct {
109*598139dcSAndroid Build Coastguard Worker    *              char     prio;
110*598139dcSAndroid Build Coastguard Worker    *              char     payload[];
111*598139dcSAndroid Build Coastguard Worker    *          } string;
112*598139dcSAndroid Build Coastguard Worker    *          struct {
113*598139dcSAndroid Build Coastguard Worker    *              uint32_t tag
114*598139dcSAndroid Build Coastguard Worker    *              char     payload[];
115*598139dcSAndroid Build Coastguard Worker    *          } binary;
116*598139dcSAndroid Build Coastguard Worker    *      };
117*598139dcSAndroid Build Coastguard Worker    *  };
118*598139dcSAndroid Build Coastguard Worker    */
119*598139dcSAndroid Build Coastguard Worker 
120*598139dcSAndroid Build Coastguard Worker   pmsgHeader.magic = LOGGER_MAGIC;
121*598139dcSAndroid Build Coastguard Worker   pmsgHeader.len = sizeof(pmsgHeader) + sizeof(header);
122*598139dcSAndroid Build Coastguard Worker   pmsgHeader.uid = getuid();
123*598139dcSAndroid Build Coastguard Worker   pmsgHeader.pid = getpid();
124*598139dcSAndroid Build Coastguard Worker 
125*598139dcSAndroid Build Coastguard Worker   header.id = logId;
126*598139dcSAndroid Build Coastguard Worker   header.tid = gettid();
127*598139dcSAndroid Build Coastguard Worker   header.realtime.tv_sec = ts->tv_sec;
128*598139dcSAndroid Build Coastguard Worker   header.realtime.tv_nsec = ts->tv_nsec;
129*598139dcSAndroid Build Coastguard Worker 
130*598139dcSAndroid Build Coastguard Worker   newVec[0].iov_base = (unsigned char*)&pmsgHeader;
131*598139dcSAndroid Build Coastguard Worker   newVec[0].iov_len = sizeof(pmsgHeader);
132*598139dcSAndroid Build Coastguard Worker   newVec[1].iov_base = (unsigned char*)&header;
133*598139dcSAndroid Build Coastguard Worker   newVec[1].iov_len = sizeof(header);
134*598139dcSAndroid Build Coastguard Worker 
135*598139dcSAndroid Build Coastguard Worker   for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
136*598139dcSAndroid Build Coastguard Worker     newVec[i].iov_base = vec[i - headerLength].iov_base;
137*598139dcSAndroid Build Coastguard Worker     payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
138*598139dcSAndroid Build Coastguard Worker 
139*598139dcSAndroid Build Coastguard Worker     if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
140*598139dcSAndroid Build Coastguard Worker       newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
141*598139dcSAndroid Build Coastguard Worker       if (newVec[i].iov_len) {
142*598139dcSAndroid Build Coastguard Worker         ++i;
143*598139dcSAndroid Build Coastguard Worker       }
144*598139dcSAndroid Build Coastguard Worker       payloadSize = LOGGER_ENTRY_MAX_PAYLOAD;
145*598139dcSAndroid Build Coastguard Worker       break;
146*598139dcSAndroid Build Coastguard Worker     }
147*598139dcSAndroid Build Coastguard Worker   }
148*598139dcSAndroid Build Coastguard Worker   pmsgHeader.len += payloadSize;
149*598139dcSAndroid Build Coastguard Worker 
150*598139dcSAndroid Build Coastguard Worker   ret = TEMP_FAILURE_RETRY(writev(pmsg_fd, newVec, i));
151*598139dcSAndroid Build Coastguard Worker   if (ret < 0) {
152*598139dcSAndroid Build Coastguard Worker     ret = errno ? -errno : -ENOTCONN;
153*598139dcSAndroid Build Coastguard Worker   }
154*598139dcSAndroid Build Coastguard Worker 
155*598139dcSAndroid Build Coastguard Worker   if (ret > (ssize_t)(sizeof(header) + sizeof(pmsgHeader))) {
156*598139dcSAndroid Build Coastguard Worker     ret -= sizeof(header) - sizeof(pmsgHeader);
157*598139dcSAndroid Build Coastguard Worker   }
158*598139dcSAndroid Build Coastguard Worker 
159*598139dcSAndroid Build Coastguard Worker   return ret;
160*598139dcSAndroid Build Coastguard Worker }
161*598139dcSAndroid Build Coastguard Worker 
162*598139dcSAndroid Build Coastguard Worker /*
163*598139dcSAndroid Build Coastguard Worker  * Virtual pmsg filesystem
164*598139dcSAndroid Build Coastguard Worker  *
165*598139dcSAndroid Build Coastguard Worker  * Payload will comprise the string "<basedir>:<basefile>\0<content>" to a
166*598139dcSAndroid Build Coastguard Worker  * maximum of LOGGER_ENTRY_MAX_PAYLOAD, but scaled to the last newline in the
167*598139dcSAndroid Build Coastguard Worker  * file.
168*598139dcSAndroid Build Coastguard Worker  *
169*598139dcSAndroid Build Coastguard Worker  * Will hijack the header.realtime.tv_nsec field for a sequence number in usec.
170*598139dcSAndroid Build Coastguard Worker  */
171*598139dcSAndroid Build Coastguard Worker 
strnrchr(const char * buf,size_t len,char c)172*598139dcSAndroid Build Coastguard Worker static inline const char* strnrchr(const char* buf, size_t len, char c) {
173*598139dcSAndroid Build Coastguard Worker   const char* cp = buf + len;
174*598139dcSAndroid Build Coastguard Worker   while ((--cp > buf) && (*cp != c))
175*598139dcSAndroid Build Coastguard Worker     ;
176*598139dcSAndroid Build Coastguard Worker   if (cp <= buf) {
177*598139dcSAndroid Build Coastguard Worker     return buf + len;
178*598139dcSAndroid Build Coastguard Worker   }
179*598139dcSAndroid Build Coastguard Worker   return cp;
180*598139dcSAndroid Build Coastguard Worker }
181*598139dcSAndroid Build Coastguard Worker 
182*598139dcSAndroid Build Coastguard Worker /* Write a buffer as filename references (tag = <basedir>:<basename>) */
__android_log_pmsg_file_write(log_id_t logId,char prio,const char * filename,const char * buf,size_t len)183*598139dcSAndroid Build Coastguard Worker ssize_t __android_log_pmsg_file_write(log_id_t logId, char prio, const char* filename,
184*598139dcSAndroid Build Coastguard Worker                                       const char* buf, size_t len) {
185*598139dcSAndroid Build Coastguard Worker   size_t length, packet_len;
186*598139dcSAndroid Build Coastguard Worker   const char* tag;
187*598139dcSAndroid Build Coastguard Worker   char *cp, *slash;
188*598139dcSAndroid Build Coastguard Worker   struct timespec ts;
189*598139dcSAndroid Build Coastguard Worker   struct iovec vec[3];
190*598139dcSAndroid Build Coastguard Worker 
191*598139dcSAndroid Build Coastguard Worker   /* Make sure the logId value is not a bad idea */
192*598139dcSAndroid Build Coastguard Worker   if ((logId == LOG_ID_KERNEL) ||   /* Verbotten */
193*598139dcSAndroid Build Coastguard Worker       (logId == LOG_ID_EVENTS) ||   /* Do not support binary content */
194*598139dcSAndroid Build Coastguard Worker       (logId == LOG_ID_SECURITY) || /* Bad idea to allow */
195*598139dcSAndroid Build Coastguard Worker       ((unsigned)logId >= 32)) {    /* fit within logMask on arch32 */
196*598139dcSAndroid Build Coastguard Worker     return -EINVAL;
197*598139dcSAndroid Build Coastguard Worker   }
198*598139dcSAndroid Build Coastguard Worker 
199*598139dcSAndroid Build Coastguard Worker   clock_gettime(CLOCK_REALTIME, &ts);
200*598139dcSAndroid Build Coastguard Worker 
201*598139dcSAndroid Build Coastguard Worker   cp = strdup(filename);
202*598139dcSAndroid Build Coastguard Worker   if (!cp) {
203*598139dcSAndroid Build Coastguard Worker     return -ENOMEM;
204*598139dcSAndroid Build Coastguard Worker   }
205*598139dcSAndroid Build Coastguard Worker 
206*598139dcSAndroid Build Coastguard Worker   tag = cp;
207*598139dcSAndroid Build Coastguard Worker   slash = strrchr(cp, '/');
208*598139dcSAndroid Build Coastguard Worker   if (slash) {
209*598139dcSAndroid Build Coastguard Worker     *slash = ':';
210*598139dcSAndroid Build Coastguard Worker     slash = strrchr(cp, '/');
211*598139dcSAndroid Build Coastguard Worker     if (slash) {
212*598139dcSAndroid Build Coastguard Worker       tag = slash + 1;
213*598139dcSAndroid Build Coastguard Worker     }
214*598139dcSAndroid Build Coastguard Worker   }
215*598139dcSAndroid Build Coastguard Worker 
216*598139dcSAndroid Build Coastguard Worker   length = strlen(tag) + 1;
217*598139dcSAndroid Build Coastguard Worker   packet_len = LOGGER_ENTRY_MAX_PAYLOAD - sizeof(char) - length;
218*598139dcSAndroid Build Coastguard Worker 
219*598139dcSAndroid Build Coastguard Worker   vec[0].iov_base = &prio;
220*598139dcSAndroid Build Coastguard Worker   vec[0].iov_len = sizeof(char);
221*598139dcSAndroid Build Coastguard Worker   vec[1].iov_base = (unsigned char*)tag;
222*598139dcSAndroid Build Coastguard Worker   vec[1].iov_len = length;
223*598139dcSAndroid Build Coastguard Worker 
224*598139dcSAndroid Build Coastguard Worker   for (ts.tv_nsec = 0, length = len; length; ts.tv_nsec += ANDROID_LOG_PMSG_FILE_SEQUENCE) {
225*598139dcSAndroid Build Coastguard Worker     ssize_t ret;
226*598139dcSAndroid Build Coastguard Worker     size_t transfer;
227*598139dcSAndroid Build Coastguard Worker 
228*598139dcSAndroid Build Coastguard Worker     if ((ts.tv_nsec / ANDROID_LOG_PMSG_FILE_SEQUENCE) >= ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE) {
229*598139dcSAndroid Build Coastguard Worker       len -= length;
230*598139dcSAndroid Build Coastguard Worker       break;
231*598139dcSAndroid Build Coastguard Worker     }
232*598139dcSAndroid Build Coastguard Worker 
233*598139dcSAndroid Build Coastguard Worker     transfer = length;
234*598139dcSAndroid Build Coastguard Worker     if (transfer > packet_len) {
235*598139dcSAndroid Build Coastguard Worker       transfer = strnrchr(buf, packet_len - 1, '\n') - buf;
236*598139dcSAndroid Build Coastguard Worker       if ((transfer < length) && (buf[transfer] == '\n')) {
237*598139dcSAndroid Build Coastguard Worker         ++transfer;
238*598139dcSAndroid Build Coastguard Worker       }
239*598139dcSAndroid Build Coastguard Worker     }
240*598139dcSAndroid Build Coastguard Worker 
241*598139dcSAndroid Build Coastguard Worker     vec[2].iov_base = (unsigned char*)buf;
242*598139dcSAndroid Build Coastguard Worker     vec[2].iov_len = transfer;
243*598139dcSAndroid Build Coastguard Worker 
244*598139dcSAndroid Build Coastguard Worker     ret = PmsgWrite(logId, &ts, vec, sizeof(vec) / sizeof(vec[0]));
245*598139dcSAndroid Build Coastguard Worker 
246*598139dcSAndroid Build Coastguard Worker     if (ret <= 0) {
247*598139dcSAndroid Build Coastguard Worker       free(cp);
248*598139dcSAndroid Build Coastguard Worker       return ret ? ret : (len - length);
249*598139dcSAndroid Build Coastguard Worker     }
250*598139dcSAndroid Build Coastguard Worker     length -= transfer;
251*598139dcSAndroid Build Coastguard Worker     buf += transfer;
252*598139dcSAndroid Build Coastguard Worker   }
253*598139dcSAndroid Build Coastguard Worker   free(cp);
254*598139dcSAndroid Build Coastguard Worker   return len;
255*598139dcSAndroid Build Coastguard Worker }
256