• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_bugreport_reader.h"
18 
19 #include <algorithm>
20 #include <cstddef>
21 #include <cstdint>
22 #include <optional>
23 #include <string>
24 #include <vector>
25 
26 #include "perfetto/base/status.h"
27 #include "perfetto/ext/base/string_utils.h"
28 #include "perfetto/ext/base/string_view.h"
29 #include "protos/perfetto/common/builtin_clock.pbzero.h"
30 #include "src/trace_processor/importers/android_bugreport/android_dumpstate_reader.h"
31 #include "src/trace_processor/importers/android_bugreport/android_log_reader.h"
32 #include "src/trace_processor/importers/common/clock_tracker.h"
33 #include "src/trace_processor/importers/common/trace_file_tracker.h"
34 #include "src/trace_processor/types/trace_processor_context.h"
35 #include "src/trace_processor/util/status_macros.h"
36 #include "src/trace_processor/util/trace_type.h"
37 #include "src/trace_processor/util/zip_reader.h"
38 
39 namespace perfetto::trace_processor {
40 namespace {
41 
42 using ZipFileVector = std::vector<util::ZipFile>;
43 
IsBugReportFile(const util::ZipFile & zip)44 bool IsBugReportFile(const util::ZipFile& zip) {
45   return base::StartsWith(zip.name(), "bugreport-") &&
46          base::EndsWith(zip.name(), ".txt");
47 }
48 
IsLogFile(const util::ZipFile & file)49 bool IsLogFile(const util::ZipFile& file) {
50   return base::StartsWith(file.name(), "FS/data/misc/logd/logcat") &&
51          !base::EndsWith(file.name(), "logcat.id");
52 }
53 
54 // Extracts the year field from the bugreport-xxx.txt file name.
55 // This is because logcat events have only the month and day.
56 // This is obviously bugged for cases of bugreports collected across new year
57 // but we'll live with that.
ExtractYearFromBugReportFilename(const std::string & filename)58 std::optional<int32_t> ExtractYearFromBugReportFilename(
59     const std::string& filename) {
60   // Typical name: "bugreport-product-TP1A.220623.001-2022-06-24-16-24-37.txt".
61   auto year_str =
62       filename.substr(filename.size() - strlen("2022-12-31-23-59-00.txt"), 4);
63   return base::StringToInt32(year_str);
64 }
65 
66 struct FindBugReportFileResult {
67   size_t file_index;
68   int32_t year;
69 };
70 
FindBugReportFile(const ZipFileVector & files)71 std::optional<FindBugReportFileResult> FindBugReportFile(
72     const ZipFileVector& files) {
73   for (size_t i = 0; i < files.size(); ++i) {
74     if (!IsBugReportFile(files[i])) {
75       continue;
76     }
77     std::optional<int32_t> year =
78         ExtractYearFromBugReportFilename(files[i].name());
79     if (!year.has_value()) {
80       continue;
81     }
82 
83     return FindBugReportFileResult{i, *year};
84   }
85 
86   return std::nullopt;
87 }
88 
89 }  // namespace
90 
91 // static
IsAndroidBugReport(const std::vector<util::ZipFile> & files)92 bool AndroidBugreportReader::IsAndroidBugReport(
93     const std::vector<util::ZipFile>& files) {
94   return FindBugReportFile(files).has_value();
95 }
96 
97 // static
Parse(TraceProcessorContext * context,std::vector<util::ZipFile> files)98 base::Status AndroidBugreportReader::Parse(TraceProcessorContext* context,
99                                            std::vector<util::ZipFile> files) {
100   auto res = FindBugReportFile(files);
101   if (!res.has_value()) {
102     return base::ErrStatus("Not a bug report");
103   }
104 
105   // Move the file to the end move it out of the list and pop the back.
106   std::swap(files[res->file_index], files.back());
107   auto id = context->trace_file_tracker->AddFile(files.back().name());
108   BugReportFile bug_report{id, res->year, std::move(files.back())};
109   files.pop_back();
110 
111   std::set<LogFile> ordered_log_files;
112   for (size_t i = 0; i < files.size(); ++i) {
113     id = context->trace_file_tracker->AddFile(files[i].name());
114     // Set size in case we end up not parsing this file.
115     context->trace_file_tracker->SetSize(id, files[i].compressed_size());
116     if (!IsLogFile(files[i])) {
117       continue;
118     }
119 
120     int64_t timestamp = files[i].GetDatetime();
121     ordered_log_files.insert(LogFile{id, timestamp, std::move(files[i])});
122   }
123 
124   return AndroidBugreportReader(context, std::move(bug_report),
125                                 std::move(ordered_log_files))
126       .ParseImpl();
127 }
128 
AndroidBugreportReader(TraceProcessorContext * context,BugReportFile bug_report,std::set<LogFile> ordered_log_files)129 AndroidBugreportReader::AndroidBugreportReader(
130     TraceProcessorContext* context,
131     BugReportFile bug_report,
132     std::set<LogFile> ordered_log_files)
133     : context_(context),
134       bug_report_(std::move(bug_report)),
135       ordered_log_files_(std::move(ordered_log_files)) {}
136 
137 AndroidBugreportReader::~AndroidBugreportReader() = default;
138 
ParseImpl()139 base::Status AndroidBugreportReader::ParseImpl() {
140   // All logs in Android bugreports use wall time (which creates problems
141   // in case of early boot events before NTP kicks in, which get emitted as
142   // 1970), but that is the state of affairs.
143   context_->clock_tracker->SetTraceTimeClock(
144       protos::pbzero::BUILTIN_CLOCK_REALTIME);
145 
146   ASSIGN_OR_RETURN(std::vector<TimestampedAndroidLogEvent> logcat_events,
147                    ParseDumpstateTxt());
148   return ParsePersistentLogcat(std::move(logcat_events));
149 }
150 
151 base::StatusOr<std::vector<TimestampedAndroidLogEvent>>
ParseDumpstateTxt()152 AndroidBugreportReader::ParseDumpstateTxt() {
153   context_->trace_file_tracker->StartParsing(bug_report_.id,
154                                              kAndroidDumpstateTraceType);
155   AndroidDumpstateReader reader(context_, bug_report_.year);
156   base::Status status = bug_report_.file.DecompressLines(
157       [&](const std::vector<base::StringView>& lines) {
158         for (const base::StringView& line : lines) {
159           reader.ParseLine(line);
160         }
161       });
162 
163   std::vector<TimestampedAndroidLogEvent> logcat_events =
164       std::move(reader.log_reader()).ConsumeBufferedEvents();
165   context_->trace_file_tracker->DoneParsing(
166       bug_report_.id, bug_report_.file.uncompressed_size());
167   RETURN_IF_ERROR(status);
168   return logcat_events;
169 }
170 
ParsePersistentLogcat(std::vector<TimestampedAndroidLogEvent> logcat_events)171 base::Status AndroidBugreportReader::ParsePersistentLogcat(
172     std::vector<TimestampedAndroidLogEvent> logcat_events) {
173   DedupingAndroidLogReader log_reader(context_, bug_report_.year,
174                                       std::move(logcat_events));
175 
176   // Push all events into the AndroidLogParser. It will take care of string
177   // interning into the pool. Appends entries into `log_events`.
178   for (const auto& log_file : ordered_log_files_) {
179     context_->trace_file_tracker->StartParsing(log_file.id,
180                                                kAndroidLogcatTraceType);
181     RETURN_IF_ERROR(log_file.file.DecompressLines(
182         [&](const std::vector<base::StringView>& lines) {
183           for (const auto& line : lines) {
184             log_reader.ParseLine(line);
185           }
186         }));
187     context_->trace_file_tracker->DoneParsing(
188         log_file.id, log_file.file.uncompressed_size());
189   }
190 
191   return base::OkStatus();
192 }
193 
194 }  // namespace perfetto::trace_processor
195