1 /*
2 * Copyright (C) 2018 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 #define STATSD_DEBUG false // STOPSHIP if true
17 #include "Log.h"
18
19 #include <ctype.h>
20 #include <limits.h>
21 #include <stdio.h>
22 #include <sys/cdefs.h>
23 #include <sys/prctl.h>
24 #include <sys/socket.h>
25 #include <sys/types.h>
26 #include <sys/un.h>
27 #include <unistd.h>
28
29 #include <cutils/sockets.h>
30
31 #include "StatsSocketListener.h"
32 #include "guardrail/StatsdStats.h"
33 #include "stats_log_util.h"
34
35 namespace android {
36 namespace os {
37 namespace statsd {
38
StatsSocketListener(std::shared_ptr<LogEventQueue> queue,const std::shared_ptr<LogEventFilter> & logEventFilter)39 StatsSocketListener::StatsSocketListener(std::shared_ptr<LogEventQueue> queue,
40 const std::shared_ptr<LogEventFilter>& logEventFilter)
41 : SocketListener(getLogSocket(), false /*start listen*/),
42 mQueue(std::move(queue)),
43 mLogEventFilter(logEventFilter) {
44 }
45
onDataAvailable(SocketClient * cli)46 bool StatsSocketListener::onDataAvailable(SocketClient* cli) {
47 static bool name_set;
48 if (!name_set) {
49 prctl(PR_SET_NAME, "statsd.writer");
50 name_set = true;
51 }
52
53 // + 1 to ensure null terminator if MAX_PAYLOAD buffer is received
54 char buffer[sizeof(android_log_header_t) + LOGGER_ENTRY_MAX_PAYLOAD + 1];
55 struct iovec iov = {buffer, sizeof(buffer) - 1};
56
57 alignas(4) char control[CMSG_SPACE(sizeof(struct ucred))];
58 struct msghdr hdr = {
59 NULL, 0, &iov, 1, control, sizeof(control), 0,
60 };
61
62 int socket = cli->getSocket();
63
64 // To clear the entire buffer is secure/safe, but this contributes to 1.68%
65 // overhead under logging load. We are safe because we check counts, but
66 // still need to clear null terminator
67 // memset(buffer, 0, sizeof(buffer));
68 ssize_t n = recvmsg(socket, &hdr, 0);
69 if (n <= (ssize_t)(sizeof(android_log_header_t))) {
70 return false;
71 }
72
73 buffer[n] = 0;
74
75 struct ucred* cred = NULL;
76
77 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
78 while (cmsg != NULL) {
79 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) {
80 cred = (struct ucred*)CMSG_DATA(cmsg);
81 break;
82 }
83 cmsg = CMSG_NXTHDR(&hdr, cmsg);
84 }
85
86 struct ucred fake_cred;
87 if (cred == NULL) {
88 cred = &fake_cred;
89 cred->pid = 0;
90 cred->uid = DEFAULT_OVERFLOWUID;
91 }
92
93 uint8_t* ptr = ((uint8_t*)buffer) + sizeof(android_log_header_t);
94 n -= sizeof(android_log_header_t);
95
96 // When a log failed to write to statsd socket (e.g., due ot EBUSY), a special message would
97 // be sent to statsd when the socket communication becomes available again.
98 // The format is android_log_event_int_t with a single integer in the payload indicating the
99 // number of logs that failed. (*FORMAT MUST BE IN SYNC WITH system/core/libstats*)
100 // Note that all normal stats logs are in the format of event_list, so there won't be confusion.
101 //
102 // TODO(b/80538532): In addition to log it in StatsdStats, we should properly reset the config.
103 if (n == sizeof(android_log_event_long_t)) {
104 android_log_event_long_t* long_event = reinterpret_cast<android_log_event_long_t*>(ptr);
105 if (long_event->payload.type == EVENT_TYPE_LONG) {
106 int64_t composed_long = long_event->payload.data;
107
108 // format:
109 // |last_tag|dropped_count|
110 int32_t dropped_count = (int32_t)(0xffffffff & composed_long);
111 int32_t last_atom_tag = (int32_t)((0xffffffff00000000 & (uint64_t)composed_long) >> 32);
112
113 ALOGE("Found dropped events: %d error %d last atom tag %d from uid %d", dropped_count,
114 long_event->header.tag, last_atom_tag, cred->uid);
115 StatsdStats::getInstance().noteLogLost((int32_t)getWallClockSec(), dropped_count,
116 long_event->header.tag, last_atom_tag, cred->uid,
117 cred->pid);
118 return true;
119 }
120 }
121
122 // move past the 4-byte StatsEventTag
123 const uint8_t* msg = ptr + sizeof(uint32_t);
124 const uint32_t len = n - sizeof(uint32_t);
125 const uint32_t uid = cred->uid;
126 const uint32_t pid = cred->pid;
127
128 processMessage(msg, len, uid, pid, mQueue, mLogEventFilter);
129
130 return true;
131 }
132
processMessage(const uint8_t * msg,uint32_t len,uint32_t uid,uint32_t pid,const std::shared_ptr<LogEventQueue> & queue,const std::shared_ptr<LogEventFilter> & filter)133 void StatsSocketListener::processMessage(const uint8_t* msg, uint32_t len, uint32_t uid,
134 uint32_t pid, const std::shared_ptr<LogEventQueue>& queue,
135 const std::shared_ptr<LogEventFilter>& filter) {
136 std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(uid, pid);
137
138 if (filter && filter->getFilteringEnabled()) {
139 const LogEvent::BodyBufferInfo bodyInfo = logEvent->parseHeader(msg, len);
140 if (filter->isAtomInUse(logEvent->GetTagId())) {
141 logEvent->parseBody(bodyInfo);
142 }
143 } else {
144 logEvent->parseBuffer(msg, len);
145 }
146
147 const int32_t atomId = logEvent->GetTagId();
148 const bool isAtomSkipped = logEvent->isParsedHeaderOnly();
149 int64_t oldestTimestamp;
150 if (!queue->push(std::move(logEvent), &oldestTimestamp)) {
151 StatsdStats::getInstance().noteEventQueueOverflow(oldestTimestamp, atomId, isAtomSkipped);
152 }
153 }
154
getLogSocket()155 int StatsSocketListener::getLogSocket() {
156 static const char socketName[] = "statsdw";
157 int sock = android_get_control_socket(socketName);
158
159 if (sock < 0) { // statsd started up in init.sh
160 sock = socket_local_server(socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_DGRAM);
161
162 int on = 1;
163 if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
164 return -1;
165 }
166 }
167 return sock;
168 }
169
170 } // namespace statsd
171 } // namespace os
172 } // namespace android
173