blob: 412b6f1d74847e1610e95fd2375376af87d7efba [file] [log] [blame]
Tom Cherry43f3f762020-05-14 22:28:09 -07001/*
Tom Cherrye18346d2020-05-21 12:13:20 -07002 * Copyright (C) 2020 The Android Open Source Project
Tom Cherry43f3f762020-05-14 22:28:09 -07003 *
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
Tom Cherrye18346d2020-05-21 12:13:20 -070017#include "LogBufferTest.h"
Tom Cherry43f3f762020-05-14 22:28:09 -070018
19#include <unistd.h>
20
Tom Cherryb398a7c2020-05-20 12:09:22 -070021#include <limits>
Tom Cherry43f3f762020-05-14 22:28:09 -070022#include <memory>
Tom Cherryb398a7c2020-05-20 12:09:22 -070023#include <regex>
Tom Cherry43f3f762020-05-14 22:28:09 -070024#include <vector>
25
26#include <android-base/stringprintf.h>
27#include <android-base/strings.h>
Tom Cherry43f3f762020-05-14 22:28:09 -070028
Tom Cherry8319bb42020-06-11 14:06:58 -070029#include "LogBuffer.h"
Tom Cherry43f3f762020-05-14 22:28:09 -070030#include "LogReaderThread.h"
Tom Cherry43f3f762020-05-14 22:28:09 -070031#include "LogWriter.h"
32
33using android::base::Join;
Tom Cherryb398a7c2020-05-20 12:09:22 -070034using android::base::Split;
Tom Cherry43f3f762020-05-14 22:28:09 -070035using android::base::StringPrintf;
36
Tom Cherrya5151972020-05-15 11:39:58 -070037#ifndef __ANDROID__
38unsigned long __android_logger_get_buffer_size(log_id_t) {
39 return 1024 * 1024;
40}
41
42bool __android_logger_valid_buffer_size(unsigned long) {
43 return true;
44}
45#endif
46
Tom Cherry43f3f762020-05-14 22:28:09 -070047char* android::uidToName(uid_t) {
48 return nullptr;
49}
50
Tom Cherrye18346d2020-05-21 12:13:20 -070051static std::vector<std::string> CompareLoggerEntries(const logger_entry& expected,
52 const logger_entry& result, bool ignore_len) {
Tom Cherryb398a7c2020-05-20 12:09:22 -070053 std::vector<std::string> errors;
54 if (!ignore_len && expected.len != result.len) {
55 errors.emplace_back(
56 StringPrintf("len: expected %" PRIu16 " vs %" PRIu16, expected.len, result.len));
57 }
58 if (expected.hdr_size != result.hdr_size) {
59 errors.emplace_back(StringPrintf("hdr_size: %" PRIu16 " vs %" PRIu16, expected.hdr_size,
60 result.hdr_size));
61 }
62 if (expected.pid != result.pid) {
63 errors.emplace_back(
64 StringPrintf("pid: expected %" PRIi32 " vs %" PRIi32, expected.pid, result.pid));
65 }
66 if (expected.tid != result.tid) {
67 errors.emplace_back(
68 StringPrintf("tid: expected %" PRIu32 " vs %" PRIu32, expected.tid, result.tid));
69 }
70 if (expected.sec != result.sec) {
71 errors.emplace_back(
72 StringPrintf("sec: expected %" PRIu32 " vs %" PRIu32, expected.sec, result.sec));
73 }
74 if (expected.nsec != result.nsec) {
75 errors.emplace_back(
76 StringPrintf("nsec: expected %" PRIu32 " vs %" PRIu32, expected.nsec, result.nsec));
77 }
78 if (expected.lid != result.lid) {
79 errors.emplace_back(
80 StringPrintf("lid: expected %" PRIu32 " vs %" PRIu32, expected.lid, result.lid));
81 }
82 if (expected.uid != result.uid) {
83 errors.emplace_back(
84 StringPrintf("uid: expected %" PRIu32 " vs %" PRIu32, expected.uid, result.uid));
85 }
86 return errors;
87}
88
Tom Cherrye18346d2020-05-21 12:13:20 -070089static std::string MakePrintable(std::string in) {
Tom Cherryb398a7c2020-05-20 12:09:22 -070090 if (in.size() > 80) {
91 in = in.substr(0, 80) + "...";
92 }
93 std::string result;
94 for (const char c : in) {
95 if (isprint(c)) {
96 result.push_back(c);
97 } else {
98 result.append(StringPrintf("\\%02x", static_cast<int>(c) & 0xFF));
99 }
100 }
101 return result;
102}
103
Tom Cherrye18346d2020-05-21 12:13:20 -0700104static std::string CompareMessages(const std::string& expected, const std::string& result) {
Tom Cherryb398a7c2020-05-20 12:09:22 -0700105 if (expected == result) {
106 return {};
107 }
108 size_t diff_index = 0;
109 for (; diff_index < std::min(expected.size(), result.size()); ++diff_index) {
110 if (expected[diff_index] != result[diff_index]) {
111 break;
112 }
113 }
114
Tom Cherryb3e16332020-05-28 20:02:42 -0700115 if (diff_index < 80) {
Tom Cherryb398a7c2020-05-20 12:09:22 -0700116 auto expected_short = MakePrintable(expected);
117 auto result_short = MakePrintable(result);
118 return StringPrintf("msg: expected '%s' vs '%s'", expected_short.c_str(),
119 result_short.c_str());
120 }
121
122 auto expected_short = MakePrintable(expected.substr(diff_index));
123 auto result_short = MakePrintable(result.substr(diff_index));
124 return StringPrintf("msg: index %zu: expected '%s' vs '%s'", diff_index, expected_short.c_str(),
125 result_short.c_str());
126}
127
Tom Cherrye18346d2020-05-21 12:13:20 -0700128static std::string CompareRegexMessages(const std::string& expected, const std::string& result) {
Tom Cherryb398a7c2020-05-20 12:09:22 -0700129 auto expected_pieces = Split(expected, std::string("\0", 1));
130 auto result_pieces = Split(result, std::string("\0", 1));
131
132 if (expected_pieces.size() != 3 || result_pieces.size() != 3) {
133 return StringPrintf(
134 "msg: should have 3 null delimited strings found %d in expected, %d in result: "
135 "'%s' vs '%s'",
136 static_cast<int>(expected_pieces.size()), static_cast<int>(result_pieces.size()),
137 MakePrintable(expected).c_str(), MakePrintable(result).c_str());
138 }
139 if (expected_pieces[0] != result_pieces[0]) {
140 return StringPrintf("msg: tag/priority mismatch expected '%s' vs '%s'",
141 MakePrintable(expected_pieces[0]).c_str(),
142 MakePrintable(result_pieces[0]).c_str());
143 }
144 std::regex expected_tag_regex(expected_pieces[1]);
145 if (!std::regex_search(result_pieces[1], expected_tag_regex)) {
146 return StringPrintf("msg: message regex mismatch expected '%s' vs '%s'",
147 MakePrintable(expected_pieces[1]).c_str(),
148 MakePrintable(result_pieces[1]).c_str());
149 }
150 if (expected_pieces[2] != result_pieces[2]) {
151 return StringPrintf("msg: nothing expected after final null character '%s' vs '%s'",
152 MakePrintable(expected_pieces[2]).c_str(),
153 MakePrintable(result_pieces[2]).c_str());
154 }
155 return {};
156}
157
158void CompareLogMessages(const std::vector<LogMessage>& expected,
159 const std::vector<LogMessage>& result) {
160 EXPECT_EQ(expected.size(), result.size());
161 size_t end = std::min(expected.size(), result.size());
162 size_t num_errors = 0;
163 for (size_t i = 0; i < end; ++i) {
164 auto errors =
165 CompareLoggerEntries(expected[i].entry, result[i].entry, expected[i].regex_compare);
166 auto msg_error = expected[i].regex_compare
167 ? CompareRegexMessages(expected[i].message, result[i].message)
168 : CompareMessages(expected[i].message, result[i].message);
169 if (!msg_error.empty()) {
170 errors.emplace_back(msg_error);
171 }
172 if (!errors.empty()) {
173 GTEST_LOG_(ERROR) << "Mismatch log message " << i << "\n" << Join(errors, "\n");
174 ++num_errors;
175 }
176 }
177 EXPECT_EQ(0U, num_errors);
178}
179
Tom Cherrye18346d2020-05-21 12:13:20 -0700180void FixupMessages(std::vector<LogMessage>* messages) {
181 for (auto& [entry, message, _] : *messages) {
182 entry.hdr_size = sizeof(logger_entry);
183 entry.len = message.size();
Tom Cherry43f3f762020-05-14 22:28:09 -0700184 }
Tom Cherrye18346d2020-05-21 12:13:20 -0700185}
Tom Cherry43f3f762020-05-14 22:28:09 -0700186
Tom Cherrye18346d2020-05-21 12:13:20 -0700187TEST_P(LogBufferTest, smoke) {
Tom Cherryb398a7c2020-05-20 12:09:22 -0700188 std::vector<LogMessage> log_messages = {
Tom Cherry43f3f762020-05-14 22:28:09 -0700189 {{
190 .pid = 1,
191 .tid = 1,
192 .sec = 1234,
193 .nsec = 323001,
194 .lid = LOG_ID_MAIN,
195 .uid = 0,
196 },
197 "smoke test"},
198 };
199 FixupMessages(&log_messages);
200 LogMessages(log_messages);
201
Tom Cherryb398a7c2020-05-20 12:09:22 -0700202 std::vector<LogMessage> read_log_messages;
Tom Cherry43f3f762020-05-14 22:28:09 -0700203 std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, nullptr));
Tom Cherry855c7c82020-05-28 12:38:21 -0700204 std::unique_ptr<FlushToState> flush_to_state = log_buffer_->CreateFlushToState(1, kLogMaskAll);
205 EXPECT_TRUE(log_buffer_->FlushTo(test_writer.get(), *flush_to_state, nullptr));
206 EXPECT_EQ(2ULL, flush_to_state->start());
Tom Cherry43f3f762020-05-14 22:28:09 -0700207 CompareLogMessages(log_messages, read_log_messages);
208}
209
Tom Cherrye18346d2020-05-21 12:13:20 -0700210TEST_P(LogBufferTest, smoke_with_reader_thread) {
Tom Cherryb398a7c2020-05-20 12:09:22 -0700211 std::vector<LogMessage> log_messages = {
Tom Cherry43f3f762020-05-14 22:28:09 -0700212 {{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20001, .lid = LOG_ID_MAIN, .uid = 0},
213 "first"},
214 {{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20002, .lid = LOG_ID_MAIN, .uid = 0},
215 "second"},
216 {{.pid = 100, .tid = 2, .sec = 10000, .nsec = 20003, .lid = LOG_ID_KERNEL, .uid = 0},
217 "third"},
218 {{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20004, .lid = LOG_ID_MAIN, .uid = 0},
219 "fourth"},
220 {{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20005, .lid = LOG_ID_RADIO, .uid = 0},
221 "fifth"},
222 {{.pid = 2, .tid = 2, .sec = 10000, .nsec = 20006, .lid = LOG_ID_RADIO, .uid = 0},
223 "sixth"},
224 {{.pid = 3, .tid = 2, .sec = 10000, .nsec = 20007, .lid = LOG_ID_RADIO, .uid = 0},
225 "seventh"},
226 {{.pid = 4, .tid = 2, .sec = 10000, .nsec = 20008, .lid = LOG_ID_MAIN, .uid = 0},
227 "eighth"},
228 {{.pid = 5, .tid = 2, .sec = 10000, .nsec = 20009, .lid = LOG_ID_CRASH, .uid = 0},
229 "nineth"},
230 {{.pid = 6, .tid = 2, .sec = 10000, .nsec = 20011, .lid = LOG_ID_MAIN, .uid = 0},
231 "tenth"},
232 };
233 FixupMessages(&log_messages);
234 LogMessages(log_messages);
235
Tom Cherryb398a7c2020-05-20 12:09:22 -0700236 std::vector<LogMessage> read_log_messages;
Tom Cherry43f3f762020-05-14 22:28:09 -0700237 bool released = false;
238
239 {
240 auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
241 std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
242 std::unique_ptr<LogReaderThread> log_reader(
243 new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), true,
Tom Cherry8319bb42020-06-11 14:06:58 -0700244 0, kLogMaskAll, 0, {}, 1, {}));
Tom Cherry43f3f762020-05-14 22:28:09 -0700245 reader_list_.reader_threads().emplace_back(std::move(log_reader));
246 }
247
248 while (!released) {
249 usleep(5000);
250 }
251 {
252 auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
253 EXPECT_EQ(0U, reader_list_.reader_threads().size());
254 }
255 CompareLogMessages(log_messages, read_log_messages);
256}
257
258// Generate random messages, set the 'sec' parameter explicit though, to be able to track the
259// expected order of messages.
Tom Cherryb398a7c2020-05-20 12:09:22 -0700260LogMessage GenerateRandomLogMessage(uint32_t sec) {
Tom Cherry43f3f762020-05-14 22:28:09 -0700261 auto rand_uint32 = [](int max) -> uint32_t { return rand() % max; };
262 logger_entry entry = {
263 .hdr_size = sizeof(logger_entry),
264 .pid = rand() % 5000,
265 .tid = rand_uint32(5000),
266 .sec = sec,
267 .nsec = rand_uint32(NS_PER_SEC),
268 .lid = rand_uint32(LOG_ID_STATS),
269 .uid = rand_uint32(100000),
270 };
271
272 // See comment in ChattyLogBuffer::Log() for why this is disallowed.
273 if (entry.nsec % 1000 == 0) {
274 ++entry.nsec;
275 }
276
277 if (entry.lid == LOG_ID_EVENTS) {
278 entry.lid = LOG_ID_KERNEL;
279 }
280
281 std::string message;
282 char priority = ANDROID_LOG_INFO + rand() % 2;
283 message.push_back(priority);
284
285 int tag_length = 2 + rand() % 10;
286 for (int i = 0; i < tag_length; ++i) {
287 message.push_back('a' + rand() % 26);
288 }
289 message.push_back('\0');
290
291 int msg_length = 2 + rand() % 1000;
292 for (int i = 0; i < msg_length; ++i) {
293 message.push_back('a' + rand() % 26);
294 }
295 message.push_back('\0');
296
297 entry.len = message.size();
298
299 return {entry, message};
300}
301
Tom Cherrye18346d2020-05-21 12:13:20 -0700302TEST_P(LogBufferTest, random_messages) {
Tom Cherry43f3f762020-05-14 22:28:09 -0700303 srand(1);
Tom Cherryb398a7c2020-05-20 12:09:22 -0700304 std::vector<LogMessage> log_messages;
Tom Cherry43f3f762020-05-14 22:28:09 -0700305 for (size_t i = 0; i < 1000; ++i) {
306 log_messages.emplace_back(GenerateRandomLogMessage(i));
307 }
308 LogMessages(log_messages);
309
Tom Cherryb398a7c2020-05-20 12:09:22 -0700310 std::vector<LogMessage> read_log_messages;
Tom Cherry43f3f762020-05-14 22:28:09 -0700311 bool released = false;
312
313 {
314 auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
315 std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
316 std::unique_ptr<LogReaderThread> log_reader(
317 new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), true,
Tom Cherry8319bb42020-06-11 14:06:58 -0700318 0, kLogMaskAll, 0, {}, 1, {}));
Tom Cherry43f3f762020-05-14 22:28:09 -0700319 reader_list_.reader_threads().emplace_back(std::move(log_reader));
320 }
321
322 while (!released) {
323 usleep(5000);
324 }
325 {
326 auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
327 EXPECT_EQ(0U, reader_list_.reader_threads().size());
328 }
329 CompareLogMessages(log_messages, read_log_messages);
330}
Tom Cherryb398a7c2020-05-20 12:09:22 -0700331
Tom Cherry90e9ce02020-06-01 13:43:50 -0700332TEST_P(LogBufferTest, read_last_sequence) {
333 std::vector<LogMessage> log_messages = {
334 {{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20001, .lid = LOG_ID_MAIN, .uid = 0},
335 "first"},
336 {{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20002, .lid = LOG_ID_MAIN, .uid = 0},
337 "second"},
338 {{.pid = 100, .tid = 2, .sec = 10000, .nsec = 20003, .lid = LOG_ID_MAIN, .uid = 0},
339 "third"},
340 };
341 FixupMessages(&log_messages);
342 LogMessages(log_messages);
343
344 std::vector<LogMessage> read_log_messages;
345 bool released = false;
346
347 {
348 auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
349 std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
350 std::unique_ptr<LogReaderThread> log_reader(
351 new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), true,
Tom Cherry8319bb42020-06-11 14:06:58 -0700352 0, kLogMaskAll, 0, {}, 3, {}));
Tom Cherry90e9ce02020-06-01 13:43:50 -0700353 reader_list_.reader_threads().emplace_back(std::move(log_reader));
354 }
355
356 while (!released) {
357 usleep(5000);
358 }
359 {
360 auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
361 EXPECT_EQ(0U, reader_list_.reader_threads().size());
362 }
363 std::vector<LogMessage> expected_log_messages = {log_messages.back()};
364 CompareLogMessages(expected_log_messages, read_log_messages);
365}
366
Tom Cherry8319bb42020-06-11 14:06:58 -0700367TEST_P(LogBufferTest, clear_logs) {
368 // Log 3 initial logs.
369 std::vector<LogMessage> log_messages = {
370 {{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20001, .lid = LOG_ID_MAIN, .uid = 0},
371 "first"},
372 {{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20002, .lid = LOG_ID_MAIN, .uid = 0},
373 "second"},
374 {{.pid = 100, .tid = 2, .sec = 10000, .nsec = 20003, .lid = LOG_ID_MAIN, .uid = 0},
375 "third"},
376 };
377 FixupMessages(&log_messages);
378 LogMessages(log_messages);
379
380 std::vector<LogMessage> read_log_messages;
381 bool released = false;
382
383 // Connect a blocking reader.
384 {
385 auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
386 std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
387 std::unique_ptr<LogReaderThread> log_reader(
388 new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), false,
389 0, kLogMaskAll, 0, {}, 1, {}));
390 reader_list_.reader_threads().emplace_back(std::move(log_reader));
391 }
392
393 // Wait up to 250ms for the reader to read the first 3 logs.
394 constexpr int kMaxRetryCount = 50;
395 int count = 0;
396 for (; count < kMaxRetryCount; ++count) {
397 usleep(5000);
398 auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
399 if (reader_list_.reader_threads().back()->start() == 4) {
400 break;
401 }
402 }
403 ASSERT_LT(count, kMaxRetryCount);
404
405 // Clear the log buffer.
406 log_buffer_->Clear(LOG_ID_MAIN, 0);
407
408 // Log 3 more logs.
409 std::vector<LogMessage> after_clear_messages = {
410 {{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20001, .lid = LOG_ID_MAIN, .uid = 0},
411 "4th"},
412 {{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20002, .lid = LOG_ID_MAIN, .uid = 0},
413 "5th"},
414 {{.pid = 100, .tid = 2, .sec = 10000, .nsec = 20003, .lid = LOG_ID_MAIN, .uid = 0},
415 "6th"},
416 };
417 FixupMessages(&after_clear_messages);
418 LogMessages(after_clear_messages);
419
420 // Wait up to 250ms for the reader to read the 3 additional logs.
421 for (count = 0; count < kMaxRetryCount; ++count) {
422 usleep(5000);
423 auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
424 if (reader_list_.reader_threads().back()->start() == 7) {
425 break;
426 }
427 }
428 ASSERT_LT(count, kMaxRetryCount);
429
430 // Release the reader, wait for it to get the signal then check that it has been deleted.
431 {
432 auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
433 reader_list_.reader_threads().back()->release_Locked();
434 }
435 while (!released) {
436 usleep(5000);
437 }
438 {
439 auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
440 EXPECT_EQ(0U, reader_list_.reader_threads().size());
441 }
442
443 // Check that we have read all 6 messages.
444 std::vector<LogMessage> expected_log_messages = log_messages;
445 expected_log_messages.insert(expected_log_messages.end(), after_clear_messages.begin(),
446 after_clear_messages.end());
447 CompareLogMessages(expected_log_messages, read_log_messages);
448
449 // Finally, call FlushTo and ensure that only the 3 logs after the clear remain in the buffer.
450 std::vector<LogMessage> read_log_messages_after_clear;
451 std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages_after_clear, nullptr));
452 std::unique_ptr<FlushToState> flush_to_state = log_buffer_->CreateFlushToState(1, kLogMaskAll);
453 EXPECT_TRUE(log_buffer_->FlushTo(test_writer.get(), *flush_to_state, nullptr));
454 EXPECT_EQ(7ULL, flush_to_state->start());
455 CompareLogMessages(after_clear_messages, read_log_messages_after_clear);
456}
457
Tom Cherry8f613462020-05-12 12:46:43 -0700458INSTANTIATE_TEST_CASE_P(LogBufferTests, LogBufferTest, testing::Values("chatty", "simple"));