• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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