1 /*
2 * Copyright (C) 2022 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 "src/trace_processor/importers/android_bugreport/android_dumpstate_reader.h"
18
19 #include <cstddef>
20 #include <cstdint>
21 #include <utility>
22 #include <vector>
23
24 #include "perfetto/base/status.h"
25 #include "perfetto/ext/base/string_view.h"
26 #include "protos/perfetto/common/builtin_clock.pbzero.h"
27 #include "src/trace_processor/importers/android_bugreport/android_battery_stats_reader.h"
28 #include "src/trace_processor/importers/android_bugreport/android_log_reader.h"
29 #include "src/trace_processor/importers/common/clock_tracker.h"
30 #include "src/trace_processor/storage/trace_storage.h"
31 #include "src/trace_processor/types/trace_processor_context.h"
32 #include "src/trace_processor/util/status_macros.h"
33
34 namespace perfetto::trace_processor {
35
AndroidDumpstateReader(TraceProcessorContext * context,int32_t year)36 AndroidDumpstateReader::AndroidDumpstateReader(TraceProcessorContext* context,
37 int32_t year)
38 : context_(context),
39 battery_stats_reader_(context),
40 log_reader_(context, year) {}
41
42 AndroidDumpstateReader::~AndroidDumpstateReader() = default;
43
ParseLine(base::StringView line)44 base::Status AndroidDumpstateReader::ParseLine(base::StringView line) {
45 context_->clock_tracker->SetTraceTimeClock(
46 protos::pbzero::BUILTIN_CLOCK_REALTIME);
47
48 // Dumpstate is organized in a two level hierarchy, beautifully flattened into
49 // one text file with load bearing ----- markers:
50 // 1. Various dumpstate sections, examples:
51 // ```
52 // ------ DUMPSYS CRITICAL (/system/bin/dumpsys) ------
53 // ...
54 // ------ SYSTEM LOG (logcat -v threadtime -v printable -v uid) ------
55 // ...
56 // ------ IPTABLES (iptables -L -nvx) ------
57 // ...
58 // ------ DUMPSYS HIGH (/system/bin/dumpsys) ------
59 // ...
60 // ------ DUMPSYS (/system/bin/dumpsys) ------
61 // ```
62 //
63 // 2. Within the "------ DUMPSYS" section (note dumpsys != dumpstate), there
64 // are multiple services. Note that there are at least 3 DUMPSYS sections
65 // (CRITICAL, HIGH and default), with multiple services in each:
66 // ```
67 // ------ DUMPSYS (/system/bin/dumpsys) ------
68 // DUMP OF SERVICE activity:
69 // ...
70 // ---------------------------------------------------------------------------
71 // DUMP OF SERVICE input_method:
72 // ...
73 // ---------------------------------------------------------------------------
74 // ```
75 // Here we put each line in a dedicated table, android_dumpstate, keeping
76 // track of the dumpstate `section` and dumpsys `service`.
77 static constexpr size_t npos = base::StringView::npos;
78 if (line.StartsWith("------ ") && line.EndsWith(" ------")) {
79 // These lines mark the beginning and end of dumpstate sections:
80 // ------ DUMPSYS CRITICAL (/system/bin/dumpsys) ------
81 // ------ 0.356s was the duration of 'DUMPSYS CRITICAL' ------
82 base::StringView section = line.substr(7);
83 section = section.substr(0, section.size() - 7);
84 bool end_marker = section.find("was the duration of") != npos;
85 current_service_id_ = StringId::Null();
86 if (end_marker) {
87 current_section_id_ = StringId::Null();
88 } else {
89 current_section_id_ = context_->storage->InternString(section);
90 current_section_ = Section::kOther;
91 if (section.StartsWith("DUMPSYS")) {
92 current_section_ = Section::kDumpsys;
93 } else if (section.StartsWith("SYSTEM LOG") ||
94 section.StartsWith("EVENT LOG") ||
95 section.StartsWith("RADIO LOG")) {
96 // KERNEL LOG is deliberately omitted because SYSTEM LOG is a
97 // superset. KERNEL LOG contains all dupes.
98 current_section_ = Section::kLog;
99 } else if (section.StartsWith("BLOCK STAT")) {
100 // Coalesce all the block stats into one section. Otherwise they
101 // pollute the table with one section per block device.
102 current_section_id_ = context_->storage->InternString("BLOCK STAT");
103 } else if (section.StartsWith("CHECKIN BATTERYSTATS")) {
104 current_section_ = Section::kBatteryStats;
105 }
106 }
107 return base::OkStatus();
108 }
109 // Skip end marker lines for dumpsys sections.
110 if (current_section_ == Section::kDumpsys && line.StartsWith("--------- ") &&
111 line.find("was the duration of dumpsys") != npos) {
112 current_service_id_ = StringId::Null();
113 return base::OkStatus();
114 }
115 if (current_section_ == Section::kDumpsys && current_service_id_.is_null() &&
116 line.StartsWith("----------------------------------------------")) {
117 return base::OkStatus();
118 }
119 // if we get the start of a standalone battery stats checkin, then set the
120 // section and deliberately fall though so we we can parse the line.
121 if (line.StartsWith("9,0,i,vers,")) {
122 current_section_ = Section::kBatteryStats;
123 }
124 if (current_section_ == Section::kDumpsys &&
125 line.StartsWith("DUMP OF SERVICE")) {
126 // DUMP OF SERVICE [CRITICAL|HIGH] ServiceName:
127 base::StringView svc = line.substr(line.rfind(' ') + 1);
128 svc = svc.substr(0, svc.size() - 1);
129 current_service_id_ = context_->storage->InternString(svc);
130 } else if (current_section_ == Section::kLog) {
131 RETURN_IF_ERROR(log_reader_.ParseLine(line));
132 } else if (current_section_ == Section::kBatteryStats) {
133 RETURN_IF_ERROR(battery_stats_reader_.ParseLine(line));
134 }
135
136 // Append the line to the android_dumpstate table.
137 context_->storage->mutable_android_dumpstate_table()->Insert(
138 {current_section_id_, current_service_id_,
139 context_->storage->InternString(line)});
140
141 return base::OkStatus();
142 }
143
EndOfStream(base::StringView)144 void AndroidDumpstateReader::EndOfStream(base::StringView) {}
145
146 } // namespace perfetto::trace_processor
147