• 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 
17 #include "include/stats_event_list.h"
18 
19 #include <string.h>
20 #include <sys/time.h>
21 #include "statsd_writer.h"
22 
23 #define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
24 
25 typedef struct {
26     uint32_t tag;
27     unsigned pos;                                    /* Read/write position into buffer */
28     unsigned count[ANDROID_MAX_LIST_NEST_DEPTH + 1]; /* Number of elements   */
29     unsigned list[ANDROID_MAX_LIST_NEST_DEPTH + 1];  /* pos for list counter */
30     unsigned list_nest_depth;
31     unsigned len; /* Length or raw buffer. */
32     bool overflow;
33     bool list_stop; /* next call decrement list_nest_depth and issue a stop */
34     enum {
35         kAndroidLoggerRead = 1,
36         kAndroidLoggerWrite = 2,
37     } read_write_flag;
38     uint8_t storage[LOGGER_ENTRY_MAX_PAYLOAD];
39 } android_log_context_internal;
40 
41 extern struct android_log_transport_write statsdLoggerWrite;
42 
43 static int __write_to_statsd_init(struct iovec* vec, size_t nr);
44 int (*write_to_statsd)(struct iovec* vec, size_t nr) = __write_to_statsd_init;
45 
46 // Similar to create_android_logger(), but instead of allocation a new buffer,
47 // this function resets the buffer for resuse.
reset_log_context(android_log_context ctx)48 void reset_log_context(android_log_context ctx) {
49     if (!ctx) {
50         return;
51     }
52     android_log_context_internal* context = (android_log_context_internal*)(ctx);
53     uint32_t tag = context->tag;
54     memset(context, 0, sizeof(android_log_context_internal));
55 
56     context->tag = tag;
57     context->read_write_flag = kAndroidLoggerWrite;
58     size_t needed = sizeof(uint8_t) + sizeof(uint8_t);
59     if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
60         context->overflow = true;
61     }
62     /* Everything is a list */
63     context->storage[context->pos + 0] = EVENT_TYPE_LIST;
64     context->list[0] = context->pos + 1;
65     context->pos += needed;
66 }
67 
stats_write_list(android_log_context ctx)68 int stats_write_list(android_log_context ctx) {
69     android_log_context_internal* context;
70     const char* msg;
71     ssize_t len;
72 
73     context = (android_log_context_internal*)(ctx);
74     if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
75         return -EBADF;
76     }
77 
78     if (context->list_nest_depth) {
79         return -EIO;
80     }
81 
82     /* NB: if there was overflow, then log is truncated. Nothing reported */
83     context->storage[1] = context->count[0];
84     len = context->len = context->pos;
85     msg = (const char*)context->storage;
86     /* it's not a list */
87     if (context->count[0] <= 1) {
88         len -= sizeof(uint8_t) + sizeof(uint8_t);
89         if (len < 0) {
90             len = 0;
91         }
92         msg += sizeof(uint8_t) + sizeof(uint8_t);
93     }
94 
95     struct iovec vec[2];
96     vec[0].iov_base = &context->tag;
97     vec[0].iov_len = sizeof(context->tag);
98     vec[1].iov_base = (void*)msg;
99     vec[1].iov_len = len;
100     return write_to_statsd(vec, 2);
101 }
102 
write_to_logger(android_log_context ctx,log_id_t id)103 int write_to_logger(android_log_context ctx, log_id_t id) {
104     int retValue = 0;
105 
106     if (WRITE_TO_LOGD) {
107         retValue = android_log_write_list(ctx, id);
108     }
109 
110     if (WRITE_TO_STATSD) {
111         // log_event_list's cast operator is overloaded.
112         int ret = stats_write_list(ctx);
113         // In debugging phase, we may write to both logd and statsd. Prefer to
114         // return statsd socket write error code here.
115         if (ret < 0) {
116             retValue = ret;
117         }
118     }
119 
120     return retValue;
121 }
122 
note_log_drop(int error,int tag)123 void note_log_drop(int error, int tag) {
124     statsdLoggerWrite.noteDrop(error, tag);
125 }
126 
stats_log_close()127 void stats_log_close() {
128     statsd_writer_init_lock();
129     write_to_statsd = __write_to_statsd_init;
130     if (statsdLoggerWrite.close) {
131         (*statsdLoggerWrite.close)();
132     }
133     statsd_writer_init_unlock();
134 }
135 
136 /* log_init_lock assumed */
__write_to_statsd_initialize_locked()137 static int __write_to_statsd_initialize_locked() {
138     if (!statsdLoggerWrite.open || ((*statsdLoggerWrite.open)() < 0)) {
139         if (statsdLoggerWrite.close) {
140             (*statsdLoggerWrite.close)();
141             return -ENODEV;
142         }
143     }
144     return 1;
145 }
146 
__write_to_stats_daemon(struct iovec * vec,size_t nr)147 static int __write_to_stats_daemon(struct iovec* vec, size_t nr) {
148     int save_errno;
149     struct timespec ts;
150     size_t len, i;
151 
152     for (len = i = 0; i < nr; ++i) {
153         len += vec[i].iov_len;
154     }
155     if (!len) {
156         return -EINVAL;
157     }
158 
159     save_errno = errno;
160 #if defined(__ANDROID__)
161     clock_gettime(CLOCK_REALTIME, &ts);
162 #else
163     struct timeval tv;
164     gettimeofday(&tv, NULL);
165     ts.tv_sec = tv.tv_sec;
166     ts.tv_nsec = tv.tv_usec * 1000;
167 #endif
168 
169     int ret = (int)(*statsdLoggerWrite.write)(&ts, vec, nr);
170     errno = save_errno;
171     return ret;
172 }
173 
__write_to_statsd_init(struct iovec * vec,size_t nr)174 static int __write_to_statsd_init(struct iovec* vec, size_t nr) {
175     int ret, save_errno = errno;
176 
177     statsd_writer_init_lock();
178 
179     if (write_to_statsd == __write_to_statsd_init) {
180         ret = __write_to_statsd_initialize_locked();
181         if (ret < 0) {
182             statsd_writer_init_unlock();
183             errno = save_errno;
184             return ret;
185         }
186 
187         write_to_statsd = __write_to_stats_daemon;
188     }
189 
190     statsd_writer_init_unlock();
191 
192     ret = write_to_statsd(vec, nr);
193     errno = save_errno;
194     return ret;
195 }
196 
copy4LE(uint8_t * buf,uint32_t val)197 static inline void copy4LE(uint8_t* buf, uint32_t val) {
198     buf[0] = val & 0xFF;
199     buf[1] = (val >> 8) & 0xFF;
200     buf[2] = (val >> 16) & 0xFF;
201     buf[3] = (val >> 24) & 0xFF;
202 }
203 
204 // Note: this function differs from android_log_write_string8_len in that the length passed in
205 // should be treated as actual length and not max length.
android_log_write_char_array(android_log_context ctx,const char * value,size_t actual_len)206 int android_log_write_char_array(android_log_context ctx, const char* value, size_t actual_len) {
207     size_t needed;
208     ssize_t len = actual_len;
209     android_log_context_internal* context;
210 
211     context = (android_log_context_internal*)ctx;
212     if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
213         return -EBADF;
214     }
215     if (context->overflow) {
216         return -EIO;
217     }
218     if (!value) {
219         value = "";
220         len = 0;
221     }
222     needed = sizeof(uint8_t) + sizeof(int32_t) + len;
223     if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
224         /* Truncate string for delivery */
225         len = MAX_EVENT_PAYLOAD - context->pos - 1 - sizeof(int32_t);
226         if (len <= 0) {
227             context->overflow = true;
228             return -EIO;
229         }
230     }
231     context->count[context->list_nest_depth]++;
232     context->storage[context->pos + 0] = EVENT_TYPE_STRING;
233     copy4LE(&context->storage[context->pos + 1], len);
234     if (len) {
235         memcpy(&context->storage[context->pos + 5], value, len);
236     }
237     context->pos += needed;
238     return len;
239 }
240