blob: d456ef0bac8274bcc0980d2afe27a82a7b39433b [file] [log] [blame]
Yao Chenf7bc6ab2018-04-18 13:45:48 -07001/*
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 "stats_event_list.h"
18
19#include "statsd_writer.h"
20
21namespace android {
22namespace util {
23
24enum ReadWriteFlag {
25 kAndroidLoggerRead = 1,
26 kAndroidLoggerWrite = 2,
27};
28
29typedef struct {
30 uint32_t tag;
31 unsigned pos; /* Read/write position into buffer */
32 unsigned count[ANDROID_MAX_LIST_NEST_DEPTH + 1]; /* Number of elements */
33 unsigned list[ANDROID_MAX_LIST_NEST_DEPTH + 1]; /* pos for list counter */
34 unsigned list_nest_depth;
35 unsigned len; /* Length or raw buffer. */
36 bool overflow;
37 bool list_stop; /* next call decrement list_nest_depth and issue a stop */
38 ReadWriteFlag read_write_flag;
39 uint8_t storage[LOGGER_ENTRY_MAX_PAYLOAD];
40} android_log_context_internal;
41
42extern struct android_log_transport_write statsdLoggerWrite;
43
44static int __write_to_statsd_init(struct iovec* vec, size_t nr);
45static int (*write_to_statsd)(struct iovec* vec,
46 size_t nr) = __write_to_statsd_init;
47
48int stats_write_list(android_log_context ctx) {
49 android_log_context_internal* context;
50 const char* msg;
51 ssize_t len;
52
53 context = (android_log_context_internal*)(ctx);
54 if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
55 return -EBADF;
56 }
57
58 if (context->list_nest_depth) {
59 return -EIO;
60 }
61
62 /* NB: if there was overflow, then log is truncated. Nothing reported */
63 context->storage[1] = context->count[0];
64 len = context->len = context->pos;
65 msg = (const char*)context->storage;
66 /* it's not a list */
67 if (context->count[0] <= 1) {
68 len -= sizeof(uint8_t) + sizeof(uint8_t);
69 if (len < 0) {
70 len = 0;
71 }
72 msg += sizeof(uint8_t) + sizeof(uint8_t);
73 }
74
75 struct iovec vec[2];
76 vec[0].iov_base = &context->tag;
77 vec[0].iov_len = sizeof(context->tag);
78 vec[1].iov_base = (void*)msg;
79 vec[1].iov_len = len;
80 return write_to_statsd(vec, 2);
81}
82
83int stats_event_list::write_to_logger(android_log_context ctx, log_id_t id) {
84 int retValue = 0;
85
86 if (WRITE_TO_LOGD) {
87 retValue = android_log_write_list(ctx, id);
88 }
89
90 if (WRITE_TO_STATSD) {
91 // log_event_list's cast operator is overloaded.
92 int ret = stats_write_list(static_cast<android_log_context>(*this));
93 // In debugging phase, we may write to both logd and statsd. Prefer to return
94 // statsd socket write error code here.
95 if (ret < 0) {
96 retValue = ret;
97 }
98 }
99
100 return retValue;
101}
102
103/* log_init_lock assumed */
104static int __write_to_statsd_initialize_locked() {
105 if (!statsdLoggerWrite.open || ((*statsdLoggerWrite.open)() < 0)) {
106 if (statsdLoggerWrite.close) {
107 (*statsdLoggerWrite.close)();
108 return -ENODEV;
109 }
110 }
111 return 1;
112}
113
114static int __write_to_stats_daemon(struct iovec* vec, size_t nr) {
115 int ret, save_errno;
116 struct timespec ts;
117 size_t len, i;
118
119 for (len = i = 0; i < nr; ++i) {
120 len += vec[i].iov_len;
121 }
122 if (!len) {
123 return -EINVAL;
124 }
125
126 save_errno = errno;
127 clock_gettime(CLOCK_REALTIME, &ts);
128
129 ret = 0;
130
131 ssize_t retval;
132 retval = (*statsdLoggerWrite.write)(&ts, vec, nr);
133 if (ret >= 0) {
134 ret = retval;
135 }
136
137 errno = save_errno;
138 return ret;
139}
140
141static int __write_to_statsd_init(struct iovec* vec, size_t nr) {
142 int ret, save_errno = errno;
143
144 statsd_writer_init_lock();
145
146 if (write_to_statsd == __write_to_statsd_init) {
147 ret = __write_to_statsd_initialize_locked();
148 if (ret < 0) {
149 statsd_writer_init_unlock();
150 errno = save_errno;
151 return ret;
152 }
153
154 write_to_statsd = __write_to_stats_daemon;
155 }
156
157 statsd_writer_init_unlock();
158
159 ret = write_to_statsd(vec, nr);
160 errno = save_errno;
161 return ret;
162}
163
164} // namespace util
165} // namespace android