xref: /aosp_15_r20/system/logging/logd/LogBufferElement.cpp (revision 598139dc91b21518d67c408eaea2644226490971)
1 /*
2  * Copyright (C) 2012-2014 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 "LogBufferElement.h"
18 
19 #include <ctype.h>
20 #include <endian.h>
21 #include <fcntl.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <time.h>
25 #include <unistd.h>
26 
27 #include <log/log_read.h>
28 #include <private/android_logger.h>
29 
30 #include "LogStatistics.h"
31 #include "LogUtils.h"
32 
LogBufferElement(log_id_t log_id,log_time realtime,uid_t uid,pid_t pid,pid_t tid,uint64_t sequence,const char * msg,uint16_t len)33 LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
34                                    pid_t tid, uint64_t sequence, const char* msg, uint16_t len)
35     : uid_(uid),
36       pid_(pid),
37       tid_(tid),
38       sequence_(sequence),
39       realtime_(realtime),
40       msg_len_(len),
41       log_id_(log_id) {
42     msg_ = new char[len];
43     memcpy(msg_, msg, len);
44 }
45 
LogBufferElement(const LogBufferElement & elem)46 LogBufferElement::LogBufferElement(const LogBufferElement& elem)
47     : uid_(elem.uid_),
48       pid_(elem.pid_),
49       tid_(elem.tid_),
50       sequence_(elem.sequence_),
51       realtime_(elem.realtime_),
52       msg_len_(elem.msg_len_),
53       log_id_(elem.log_id_) {
54     msg_ = new char[msg_len_];
55     memcpy(msg_, elem.msg_, msg_len_);
56 }
57 
LogBufferElement(LogBufferElement && elem)58 LogBufferElement::LogBufferElement(LogBufferElement&& elem) noexcept
59     : uid_(elem.uid_),
60       pid_(elem.pid_),
61       tid_(elem.tid_),
62       sequence_(elem.sequence_),
63       realtime_(elem.realtime_),
64       msg_len_(elem.msg_len_),
65       log_id_(elem.log_id_) {
66     msg_ = elem.msg_;
67     elem.msg_ = nullptr;
68 }
69 
~LogBufferElement()70 LogBufferElement::~LogBufferElement() {
71     delete[] msg_;
72 }
73 
GetTag() const74 uint32_t LogBufferElement::GetTag() const {
75     // Binary buffers have no tag.
76     if (!IsBinary(log_id())) {
77         return 0;
78     }
79     return MsgToTag(msg(), msg_len());
80 }
81 
ToLogStatisticsElement() const82 LogStatisticsElement LogBufferElement::ToLogStatisticsElement() const {
83     // Estimate the size of this element in the parent std::list<> by adding two void*'s
84     // corresponding to the next/prev pointers and aligning to 64 bit.
85     uint16_t element_in_list_size =
86             (sizeof(*this) + 2 * sizeof(void*) + sizeof(uint64_t) - 1) & -sizeof(uint64_t);
87     return LogStatisticsElement{
88             .uid = uid(),
89             .pid = pid(),
90             .tid = tid(),
91             .tag = GetTag(),
92             .realtime = realtime(),
93             .msg = msg(),
94             .msg_len = msg_len(),
95             .log_id = log_id(),
96             .total_len = static_cast<uint16_t>(element_in_list_size + msg_len()),
97     };
98 }
99 
100 // caller must own and free character string
tidToName(pid_t tid)101 char* android::tidToName(pid_t tid) {
102     char* retval = nullptr;
103     char buffer[256];
104     snprintf(buffer, sizeof(buffer), "/proc/%u/comm", tid);
105     int fd = open(buffer, O_RDONLY | O_CLOEXEC);
106     if (fd >= 0) {
107         ssize_t ret = read(fd, buffer, sizeof(buffer));
108         if (ret >= (ssize_t)sizeof(buffer)) {
109             ret = sizeof(buffer) - 1;
110         }
111         while ((ret > 0) && isspace(buffer[ret - 1])) {
112             --ret;
113         }
114         if (ret > 0) {
115             buffer[ret] = '\0';
116             retval = strdup(buffer);
117         }
118         close(fd);
119     }
120 
121     // if nothing for comm, check out cmdline
122     char* name = android::pidToName(tid);
123     if (!retval) {
124         retval = name;
125         name = nullptr;
126     }
127 
128     // check if comm is truncated, see if cmdline has full representation
129     if (name) {
130         // impossible for retval to be NULL if name not NULL
131         size_t retval_len = strlen(retval);
132         size_t name_len = strlen(name);
133         // KISS: ToDo: Only checks prefix truncated, not suffix, or both
134         if ((retval_len < name_len) &&
135             !fastcmp<strcmp>(retval, name + name_len - retval_len)) {
136             free(retval);
137             retval = name;
138         } else {
139             free(name);
140         }
141     }
142     return retval;
143 }
144 
FlushTo(LogWriter * writer)145 bool LogBufferElement::FlushTo(LogWriter* writer) {
146     struct logger_entry entry = {};
147 
148     entry.hdr_size = sizeof(struct logger_entry);
149     entry.lid = log_id_;
150     entry.pid = pid_;
151     entry.tid = tid_;
152     entry.uid = uid_;
153     entry.sec = realtime_.tv_sec;
154     entry.nsec = realtime_.tv_nsec;
155     entry.len = msg_len_;
156 
157     return writer->Write(entry, msg_);
158 }
159