blob: 49f3ffc82e1c492778b5e79866a656bef4974b3c [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/traced/probes/android_log/android_log_data_source.h"
#include "perfetto/tracing/core/data_source_config.h"
#include "src/base/test/test_task_runner.h"
#include "src/tracing/core/trace_writer_for_testing.h"
#include "test/gtest_and_gmock.h"
#include "protos/perfetto/common/android_log_constants.gen.h"
#include "protos/perfetto/config/android/android_log_config.gen.h"
#include "protos/perfetto/trace/android/android_log.gen.h"
using ::perfetto::protos::gen::AndroidLogConfig;
using ::perfetto::protos::gen::AndroidLogId;
using ::testing::Invoke;
using ::testing::Return;
namespace perfetto {
namespace {
class TestAndroidLogDataSource : public AndroidLogDataSource {
public:
TestAndroidLogDataSource(const DataSourceConfig& config,
base::TaskRunner* task_runner,
TracingSessionID id,
std::unique_ptr<TraceWriter> writer)
: AndroidLogDataSource(config, task_runner, id, std::move(writer)) {}
MOCK_METHOD(std::string, ReadEventLogDefinitions, (), (override));
MOCK_METHOD(base::UnixSocketRaw, ConnectLogdrSocket, (), (override));
};
class AndroidLogDataSourceTest : public ::testing::Test {
protected:
AndroidLogDataSourceTest() {}
void CreateInstance(const DataSourceConfig& cfg) {
auto writer =
std::unique_ptr<TraceWriterForTesting>(new TraceWriterForTesting());
writer_raw_ = writer.get();
data_source_.reset(
new TestAndroidLogDataSource(cfg, &task_runner_, 0, std::move(writer)));
}
void StartAndSimulateLogd(
const std::vector<std::vector<uint8_t>>& fake_events) {
base::UnixSocketRaw send_sock;
base::UnixSocketRaw recv_sock;
// In theory this should be a kSeqPacket. We use kDgram here so that the
// test can run also on MacOS (which doesn't support SOCK_SEQPACKET).
std::tie(send_sock, recv_sock) = base::UnixSocketRaw::CreatePairPosix(
base::SockFamily::kUnix, base::SockType::kDgram);
ASSERT_TRUE(send_sock);
ASSERT_TRUE(recv_sock);
EXPECT_CALL(*data_source_, ConnectLogdrSocket())
.WillOnce(Invoke([&recv_sock] { return std::move(recv_sock); }));
data_source_->Start();
char cmd[64]{};
EXPECT_GT(send_sock.Receive(cmd, sizeof(cmd) - 1), 0);
EXPECT_STREQ("stream tail=1 lids=0,2,3,4,7", cmd);
// Send back log messages emulating Android's logdr socket.
for (const auto& buf : fake_events)
send_sock.Send(buf.data(), buf.size());
auto on_flush = task_runner_.CreateCheckpoint("on_flush");
data_source_->Flush(1, on_flush);
task_runner_.RunUntilCheckpoint("on_flush");
}
base::TestTaskRunner task_runner_;
std::unique_ptr<TestAndroidLogDataSource> data_source_;
TraceWriterForTesting* writer_raw_;
const std::vector<std::vector<uint8_t>> kValidTextEvents{
// 12-29 23:13:59.679 7546 8991 I ActivityManager:
// Killing 11660:com.google.android.videos/u0a168 (adj 985): empty #17
{0x55, 0x00, 0x1c, 0x00, 0x7a, 0x1d, 0x00, 0x00, 0x1f, 0x23, 0x00, 0x00,
0xb7, 0xff, 0x27, 0x5c, 0xe6, 0x58, 0x7b, 0x28, 0x03, 0x00, 0x00, 0x00,
0xe8, 0x03, 0x00, 0x00, 0x04, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74,
0x79, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x00, 0x4b, 0x69, 0x6c,
0x6c, 0x69, 0x6e, 0x67, 0x20, 0x31, 0x31, 0x36, 0x36, 0x30, 0x3a, 0x63,
0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x6e,
0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x73,
0x2f, 0x75, 0x30, 0x61, 0x31, 0x36, 0x38, 0x20, 0x28, 0x61, 0x64, 0x6a,
0x20, 0x39, 0x38, 0x35, 0x29, 0x3a, 0x20, 0x65, 0x6d, 0x70, 0x74, 0x79,
0x20, 0x23, 0x31, 0x37, 0x00},
// 12-29 23:13:59.683 7546 7570 W libprocessgroup:
// kill(-11660, 9) failed: No such process
{0x39, 0x00, 0x1c, 0x00, 0x7a, 0x1d, 0x00, 0x00, 0x92, 0x1d, 0x00,
0x00, 0xb7, 0xff, 0x27, 0x5c, 0x12, 0xf3, 0xbd, 0x28, 0x00, 0x00,
0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, 0x05, 0x6c, 0x69, 0x62, 0x70,
0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x6f, 0x75, 0x70,
0x00, 0x6b, 0x69, 0x6c, 0x6c, 0x28, 0x2d, 0x31, 0x31, 0x36, 0x36,
0x30, 0x2c, 0x20, 0x39, 0x29, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65,
0x64, 0x3a, 0x20, 0x4e, 0x6f, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20,
0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x00},
// 12-29 23:13:59.719 7415 7415 I Zygote:
// Process 11660 exited due to signal (9)
{0x2f, 0x00, 0x1c, 0x00, 0xf7, 0x1c, 0x00, 0x00, 0xf7, 0x1c, 0x00,
0x00, 0xb7, 0xff, 0x27, 0x5c, 0x7c, 0x11, 0xe2, 0x2a, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5a, 0x79, 0x67, 0x6f,
0x74, 0x65, 0x00, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x20,
0x31, 0x31, 0x36, 0x36, 0x30, 0x20, 0x65, 0x78, 0x69, 0x74, 0x65,
0x64, 0x20, 0x64, 0x75, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x69,
0x67, 0x6e, 0x61, 0x6c, 0x20, 0x28, 0x39, 0x29, 0x00},
};
const std::vector<std::vector<uint8_t>> kValidBinaryEvents{
// 12-30 10:22:08.914 29981 30962 I am_kill :
// [0,31730,android.process.acore,985,empty #17]
{0x3d, 0x00, 0x1c, 0x00, 0x1d, 0x75, 0x00, 0x00, 0xf2, 0x78, 0x00, 0x00,
0x50, 0x9c, 0x28, 0x5c, 0xdb, 0x77, 0x7e, 0x36, 0x02, 0x00, 0x00, 0x00,
0xe8, 0x03, 0x00, 0x00, 0x47, 0x75, 0x00, 0x00, 0x03, 0x05, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xf2, 0x7b, 0x00, 0x00, 0x02, 0x15, 0x00, 0x00,
0x00, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x70, 0x72, 0x6f,
0x63, 0x65, 0x73, 0x73, 0x2e, 0x61, 0x63, 0x6f, 0x72, 0x65, 0x00, 0xd9,
0x03, 0x00, 0x00, 0x02, 0x09, 0x00, 0x00, 0x00, 0x65, 0x6d, 0x70, 0x74,
0x79, 0x20, 0x23, 0x31, 0x37},
// 12-30 10:22:08.946 29981 30962 I am_uid_stopped: 10018
{0x09, 0x00, 0x1c, 0x00, 0x1d, 0x75, 0x00, 0x00, 0xf2, 0x78,
0x00, 0x00, 0x50, 0x9c, 0x28, 0x5c, 0x24, 0x5a, 0x66, 0x38,
0x02, 0x00, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, 0x65, 0x75,
0x00, 0x00, 0x00, 0x22, 0x27, 0x00, 0x00},
// 12-30 10:22:08.960 29981 29998 I am_pss :
// [1417,10098,com.google.android.connectivitymonitor,4831232,3723264,0,56053760,0,9,39]
{0x72, 0x00, 0x1c, 0x00, 0x1d, 0x75, 0x00, 0x00, 0x2e, 0x75, 0x00, 0x00,
0x50, 0x9c, 0x28, 0x5c, 0xf4, 0xd7, 0x44, 0x39, 0x02, 0x00, 0x00, 0x00,
0xe8, 0x03, 0x00, 0x00, 0x5f, 0x75, 0x00, 0x00, 0x03, 0x0a, 0x00, 0x89,
0x05, 0x00, 0x00, 0x00, 0x72, 0x27, 0x00, 0x00, 0x02, 0x26, 0x00, 0x00,
0x00, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x6e,
0x65, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x6d, 0x6f, 0x6e, 0x69,
0x74, 0x6f, 0x72, 0x01, 0x00, 0xb8, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0xd0, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x50, 0x57, 0x03, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
0x00, 0x01, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
};
TEST_F(AndroidLogDataSourceTest, ParseEventLogDefinitions) {
CreateInstance(DataSourceConfig());
static const char kContents[] = R"(
42 answer (to life the universe etc|3)
314 pi
1003 auditd (avc|3)
1004 chatty (dropped|3)
1005 tag_def (tag|1),(name|3),(format|3)
2718 e
2732 storaged_disk_stats (type|3),(start_time|2|3),(end_time|2|3),(read_ios|2|1),(read_merges|2|1),(read_sectors|2|1),(read_ticks|2|3),(write_ios|2|1),(write_merges|2|1),(write_sectors|2|1),(write_ticks|2|3),(o_in_flight|2|1),(io_ticks|2|3),(io_in_queue|2|1)
invalid_line (
9999 invalid_line2 (
1937006964 stats_log (atom_id|1|5),(data|4)
)";
EXPECT_CALL(*data_source_, ReadEventLogDefinitions())
.WillOnce(Return(kContents));
data_source_->ParseEventLogDefinitions();
auto* fmt = data_source_->GetEventFormat(42);
ASSERT_NE(fmt, nullptr);
ASSERT_EQ(fmt->name, "answer");
ASSERT_EQ(fmt->fields.size(), 1u);
ASSERT_EQ(fmt->fields[0], "to life the universe etc");
fmt = data_source_->GetEventFormat(314);
ASSERT_NE(fmt, nullptr);
ASSERT_EQ(fmt->name, "pi");
ASSERT_EQ(fmt->fields.size(), 0u);
fmt = data_source_->GetEventFormat(1005);
ASSERT_NE(fmt, nullptr);
ASSERT_EQ(fmt->name, "tag_def");
ASSERT_EQ(fmt->fields.size(), 3u);
ASSERT_EQ(fmt->fields[0], "tag");
ASSERT_EQ(fmt->fields[1], "name");
ASSERT_EQ(fmt->fields[2], "format");
fmt = data_source_->GetEventFormat(1937006964);
ASSERT_NE(fmt, nullptr);
ASSERT_EQ(fmt->name, "stats_log");
ASSERT_EQ(fmt->fields.size(), 2u);
ASSERT_EQ(fmt->fields[0], "atom_id");
ASSERT_EQ(fmt->fields[1], "data");
}
TEST_F(AndroidLogDataSourceTest, TextEvents) {
DataSourceConfig cfg;
CreateInstance(cfg);
EXPECT_CALL(*data_source_, ReadEventLogDefinitions()).WillOnce(Return(""));
StartAndSimulateLogd(kValidTextEvents);
// Read back the data that would have been written into the trace. One packet
// with the events, one with stats.
auto packets = writer_raw_->GetAllTracePackets();
ASSERT_TRUE(packets.size() == 2);
auto event_packet = packets[0];
auto stats_packet = packets[1];
EXPECT_TRUE(stats_packet.android_log().has_stats());
EXPECT_EQ(event_packet.android_log().events_size(), 3);
const auto& decoded = event_packet.android_log().events();
EXPECT_EQ(decoded[0].log_id(), protos::gen::AndroidLogId::LID_SYSTEM);
EXPECT_EQ(decoded[0].pid(), 7546);
EXPECT_EQ(decoded[0].tid(), 8991);
EXPECT_EQ(decoded[0].uid(), 1000);
EXPECT_EQ(decoded[0].prio(), protos::gen::AndroidLogPriority::PRIO_INFO);
EXPECT_EQ(decoded[0].timestamp(), 1546125239679172326ULL);
EXPECT_EQ(decoded[0].tag(), "ActivityManager");
EXPECT_EQ(
decoded[0].message(),
"Killing 11660:com.google.android.videos/u0a168 (adj 985): empty #17");
EXPECT_EQ(decoded[1].log_id(), protos::gen::AndroidLogId::LID_DEFAULT);
EXPECT_EQ(decoded[1].pid(), 7546);
EXPECT_EQ(decoded[1].tid(), 7570);
EXPECT_EQ(decoded[1].uid(), 1000);
EXPECT_EQ(decoded[1].prio(), protos::gen::AndroidLogPriority::PRIO_WARN);
EXPECT_EQ(decoded[1].timestamp(), 1546125239683537170ULL);
EXPECT_EQ(decoded[1].tag(), "libprocessgroup");
EXPECT_EQ(decoded[1].message(), "kill(-11660, 9) failed: No such process");
EXPECT_EQ(decoded[2].log_id(), protos::gen::AndroidLogId::LID_DEFAULT);
EXPECT_EQ(decoded[2].pid(), 7415);
EXPECT_EQ(decoded[2].tid(), 7415);
EXPECT_EQ(decoded[2].uid(), 0);
EXPECT_EQ(decoded[2].prio(), protos::gen::AndroidLogPriority::PRIO_INFO);
EXPECT_EQ(decoded[2].timestamp(), 1546125239719458684ULL);
EXPECT_EQ(decoded[2].tag(), "Zygote");
EXPECT_EQ(decoded[2].message(), "Process 11660 exited due to signal (9)");
}
TEST_F(AndroidLogDataSourceTest, TextEventsWithTagFiltering) {
DataSourceConfig cfg;
AndroidLogConfig acfg;
acfg.add_filter_tags("Zygote");
acfg.add_filter_tags("ActivityManager");
acfg.add_filter_tags("Unmatched");
acfg.add_filter_tags("libprocessgroupZZ");
cfg.set_android_log_config_raw(acfg.SerializeAsString());
CreateInstance(cfg);
EXPECT_CALL(*data_source_, ReadEventLogDefinitions()).WillOnce(Return(""));
StartAndSimulateLogd(kValidTextEvents);
auto packets = writer_raw_->GetAllTracePackets();
ASSERT_TRUE(packets.size() == 2);
auto event_packet = packets[0];
auto stats_packet = packets[1];
EXPECT_TRUE(stats_packet.android_log().has_stats());
EXPECT_EQ(event_packet.android_log().events_size(), 2);
const auto& decoded = event_packet.android_log().events();
EXPECT_EQ(decoded[0].tag(), "ActivityManager");
EXPECT_EQ(decoded[1].tag(), "Zygote");
}
TEST_F(AndroidLogDataSourceTest, TextEventsWithPrioFiltering) {
DataSourceConfig cfg;
AndroidLogConfig acfg;
acfg.set_min_prio(protos::gen::AndroidLogPriority::PRIO_WARN);
cfg.set_android_log_config_raw(acfg.SerializeAsString());
CreateInstance(cfg);
EXPECT_CALL(*data_source_, ReadEventLogDefinitions()).WillOnce(Return(""));
StartAndSimulateLogd(kValidTextEvents);
auto packets = writer_raw_->GetAllTracePackets();
ASSERT_TRUE(packets.size() == 2);
auto event_packet = packets[0];
auto stats_packet = packets[1];
EXPECT_TRUE(stats_packet.android_log().has_stats());
EXPECT_EQ(event_packet.android_log().events_size(), 1);
const auto& decoded = event_packet.android_log().events();
EXPECT_EQ(decoded[0].tag(), "libprocessgroup");
}
TEST_F(AndroidLogDataSourceTest, BinaryEvents) {
DataSourceConfig cfg;
CreateInstance(cfg);
static const char kDefs[] = R"(
30023 am_kill (User|1|5),(PID|1|5),(Process Name|3),(OomAdj|1|5),(Reason|3)
30053 am_uid_stopped (UID|1|5)
30047 am_pss (Pid|1|5),(UID|1|5),(Process Name|3),(Pss|2|2),(Uss|2|2),(SwapPss|2|2),(Rss|2|2),(StatType|1|5),(ProcState|1|5),(TimeToCollect|2|2)
)";
EXPECT_CALL(*data_source_, ReadEventLogDefinitions()).WillOnce(Return(kDefs));
StartAndSimulateLogd(kValidBinaryEvents);
// Read back the data that would have been written into the trace. One packet
// with the events, one with stats.
auto packets = writer_raw_->GetAllTracePackets();
ASSERT_TRUE(packets.size() == 2);
auto event_packet = packets[0];
auto stats_packet = packets[1];
EXPECT_TRUE(stats_packet.android_log().has_stats());
EXPECT_EQ(event_packet.android_log().events_size(), 3);
const auto& decoded = event_packet.android_log().events();
EXPECT_EQ(decoded[0].log_id(), protos::gen::AndroidLogId::LID_EVENTS);
EXPECT_EQ(decoded[0].pid(), 29981);
EXPECT_EQ(decoded[0].tid(), 30962);
EXPECT_EQ(decoded[0].uid(), 1000);
EXPECT_EQ(decoded[0].timestamp(), 1546165328914257883ULL);
EXPECT_EQ(decoded[0].tag(), "am_kill");
ASSERT_EQ(decoded[0].args_size(), 5);
EXPECT_EQ(decoded[0].args()[0].name(), "User");
EXPECT_EQ(decoded[0].args()[0].int_value(), 0);
EXPECT_EQ(decoded[0].args()[1].name(), "PID");
EXPECT_EQ(decoded[0].args()[1].int_value(), 31730);
EXPECT_EQ(decoded[0].args()[2].name(), "Process Name");
EXPECT_EQ(decoded[0].args()[2].string_value(), "android.process.acore");
EXPECT_EQ(decoded[0].args()[3].name(), "OomAdj");
EXPECT_EQ(decoded[0].args()[3].int_value(), 985);
EXPECT_EQ(decoded[0].args()[4].name(), "Reason");
EXPECT_EQ(decoded[0].args()[4].string_value(), "empty #17");
EXPECT_EQ(decoded[1].log_id(), protos::gen::AndroidLogId::LID_EVENTS);
EXPECT_EQ(decoded[1].pid(), 29981);
EXPECT_EQ(decoded[1].tid(), 30962);
EXPECT_EQ(decoded[1].uid(), 1000);
EXPECT_EQ(decoded[1].timestamp(), 1546165328946231844ULL);
EXPECT_EQ(decoded[1].tag(), "am_uid_stopped");
ASSERT_EQ(decoded[1].args_size(), 1);
EXPECT_EQ(decoded[1].args()[0].name(), "UID");
EXPECT_EQ(decoded[1].args()[0].int_value(), 10018);
EXPECT_EQ(decoded[2].log_id(), protos::gen::AndroidLogId::LID_EVENTS);
EXPECT_EQ(decoded[2].pid(), 29981);
EXPECT_EQ(decoded[2].tid(), 29998);
EXPECT_EQ(decoded[2].uid(), 1000);
EXPECT_EQ(decoded[2].timestamp(), 1546165328960813044ULL);
EXPECT_EQ(decoded[2].tag(), "am_pss");
ASSERT_EQ(decoded[2].args_size(), 10);
EXPECT_EQ(decoded[2].args()[0].name(), "Pid");
EXPECT_EQ(decoded[2].args()[0].int_value(), 1417);
EXPECT_EQ(decoded[2].args()[1].name(), "UID");
EXPECT_EQ(decoded[2].args()[1].int_value(), 10098);
EXPECT_EQ(decoded[2].args()[2].name(), "Process Name");
EXPECT_EQ(decoded[2].args()[2].string_value(),
"com.google.android.connectivitymonitor");
EXPECT_EQ(decoded[2].args()[3].name(), "Pss");
EXPECT_EQ(decoded[2].args()[3].int_value(), 4831232);
EXPECT_EQ(decoded[2].args()[4].name(), "Uss");
EXPECT_EQ(decoded[2].args()[4].int_value(), 3723264);
EXPECT_EQ(decoded[2].args()[5].name(), "SwapPss");
EXPECT_EQ(decoded[2].args()[5].int_value(), 0);
EXPECT_EQ(decoded[2].args()[6].name(), "Rss");
EXPECT_EQ(decoded[2].args()[6].int_value(), 56053760);
EXPECT_EQ(decoded[2].args()[7].name(), "StatType");
EXPECT_EQ(decoded[2].args()[7].int_value(), 0);
EXPECT_EQ(decoded[2].args()[8].name(), "ProcState");
EXPECT_EQ(decoded[2].args()[8].int_value(), 9);
EXPECT_EQ(decoded[2].args()[9].name(), "TimeToCollect");
EXPECT_EQ(decoded[2].args()[9].int_value(), 39);
}
TEST_F(AndroidLogDataSourceTest, BinaryEventsWithTagFiltering) {
DataSourceConfig cfg;
AndroidLogConfig acfg;
acfg.add_filter_tags("not mached");
acfg.add_filter_tags("am_uid_stopped");
cfg.set_android_log_config_raw(acfg.SerializeAsString());
CreateInstance(cfg);
static const char kDefs[] = R"(
30023 am_kill (User|1|5),(PID|1|5),(Process Name|3),(OomAdj|1|5),(Reason|3)
30053 am_uid_stopped (UID|1|5)
30047 am_pss (Pid|1|5),(UID|1|5),(Process Name|3),(Pss|2|2),(Uss|2|2),(SwapPss|2|2),(Rss|2|2),(StatType|1|5),(ProcState|1|5),(TimeToCollect|2|2)
)";
EXPECT_CALL(*data_source_, ReadEventLogDefinitions()).WillOnce(Return(kDefs));
StartAndSimulateLogd(kValidBinaryEvents);
// Read back the data that would have been written into the trace. One packet
// with the events, one with stats.
auto packets = writer_raw_->GetAllTracePackets();
ASSERT_TRUE(packets.size() == 2);
auto event_packet = packets[0];
auto stats_packet = packets[1];
EXPECT_TRUE(stats_packet.android_log().has_stats());
EXPECT_EQ(event_packet.android_log().events_size(), 1);
const auto& decoded = event_packet.android_log().events();
EXPECT_EQ(decoded[0].timestamp(), 1546165328946231844ULL);
EXPECT_EQ(decoded[0].tag(), "am_uid_stopped");
}
} // namespace
} // namespace perfetto