1 /*
2 * Copyright (C) 2024 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_battery_stats_reader.h"
18
19 #include <chrono>
20 #include <cstdint>
21 #include <ctime>
22 #include <optional>
23 #include <utility>
24
25 #include "perfetto/base/status.h"
26 #include "perfetto/ext/base/status_or.h"
27 #include "perfetto/ext/base/string_utils.h"
28 #include "perfetto/ext/base/string_view.h"
29 #include "perfetto/ext/base/string_view_splitter.h"
30 #include "protos/perfetto/trace/clock_snapshot.pbzero.h"
31 #include "src/trace_processor/importers/android_bugreport/android_battery_stats_history_string_tracker.h"
32 #include "src/trace_processor/importers/android_bugreport/android_dumpstate_event.h"
33 #include "src/trace_processor/importers/common/clock_tracker.h"
34 #include "src/trace_processor/sorter/trace_sorter.h"
35 #include "src/trace_processor/types/trace_processor_context.h"
36 #include "src/trace_processor/util/status_macros.h"
37
38 namespace perfetto::trace_processor {
39
40 namespace {
41
StringToStatusOrInt64(base::StringView str)42 base::StatusOr<int64_t> StringToStatusOrInt64(base::StringView str) {
43 std::optional<int64_t> possible_result = base::StringViewToInt64(str);
44 if (!possible_result.has_value()) {
45 return base::ErrStatus("Failed to convert string to int64_t");
46 }
47 return possible_result.value();
48 }
49 } // namespace
50
AndroidBatteryStatsReader(TraceProcessorContext * context)51 AndroidBatteryStatsReader::AndroidBatteryStatsReader(
52 TraceProcessorContext* context)
53 : context_(context) {}
54
55 AndroidBatteryStatsReader::~AndroidBatteryStatsReader() = default;
56
ParseLine(base::StringView line)57 base::Status AndroidBatteryStatsReader::ParseLine(base::StringView line) {
58 base::StringViewSplitter splitter(line, ',');
59
60 // consume the legacy version number which we expect to be at the start of
61 // every line.
62 if (splitter.NextToken() != "9") {
63 return base::ErrStatus("Unexpected start of battery stats checkin line");
64 }
65
66 base::StringView possible_event_type = splitter.NextToken();
67
68 if (possible_event_type == "hsp") {
69 ASSIGN_OR_RETURN(int64_t index,
70 StringToStatusOrInt64(splitter.NextToken()));
71 std::optional<int32_t> possible_uid =
72 base::StringViewToInt32(splitter.NextToken());
73 if (!possible_uid) {
74 // This can happen if the bugreport is redacted incorrectly (i.e.
75 // '[PHONE_NUMBER]').
76 return base::OkStatus();
77 }
78
79 // the next element is quoted and can contain commas. Instead of
80 // implementing general logic to parse quoted CSV elements just grab the
81 // rest of the line, which is possible since this element should be the
82 // last one on the line.
83 base::StringView remainder = splitter.remainder();
84 // remove the leading and trailing quotes from the hsp string
85 size_t substr_start = remainder.find('"') + 1;
86 size_t substr_end = remainder.rfind('"');
87 base::StringView hsp_string =
88 remainder.substr(substr_start, substr_end - substr_start);
89 AndroidBatteryStatsHistoryStringTracker::GetOrCreate(context_)
90 ->SetStringPoolItem(index, possible_uid.value(),
91 hsp_string.ToStdString());
92 } else if (possible_event_type == "h") {
93 const base::StringView time_adjustment_marker = ":TIME:";
94 const base::StringView possible_timestamp = splitter.NextToken();
95 size_t time_marker_index = possible_timestamp.find(time_adjustment_marker);
96 if (time_marker_index != base::StringView::npos) {
97 // Special case timestamp adjustment event.
98 ASSIGN_OR_RETURN(current_timestamp_ms_,
99 StringToStatusOrInt64(possible_timestamp.substr(
100 time_marker_index + time_adjustment_marker.size())));
101 return base::OkStatus();
102 }
103 if (possible_timestamp.find(":START") != base::StringView::npos) {
104 // Ignore line
105 return base::OkStatus();
106 }
107 if (possible_timestamp.find(":SHUTDOWN") != base::StringView::npos) {
108 // Ignore line
109 return base::OkStatus();
110 }
111 ASSIGN_OR_RETURN(int64_t parsed_timestamp_delta,
112 StringToStatusOrInt64(possible_timestamp));
113 current_timestamp_ms_ += parsed_timestamp_delta;
114 for (base::StringView item = splitter.NextToken(); !item.empty();
115 item = splitter.NextToken()) {
116 RETURN_IF_ERROR(ProcessBatteryStatsHistoryEvent(item));
117 }
118
119 } else if (possible_event_type == "0") {
120 const base::StringView metadata_type = splitter.NextToken();
121 if (metadata_type == "i") {
122 const base::StringView info_type = splitter.NextToken();
123 if (info_type == "vers") {
124 ASSIGN_OR_RETURN(int64_t battery_stats_version,
125 StringToStatusOrInt64(splitter.NextToken()));
126 AndroidBatteryStatsHistoryStringTracker::GetOrCreate(context_)
127 ->battery_stats_version(
128 static_cast<uint32_t>(battery_stats_version));
129 }
130 }
131 } else {
132 // TODO Implement UID parsing and other kinds of events.
133 }
134
135 return base::OkStatus();
136 }
137
ProcessBatteryStatsHistoryEvent(base::StringView raw_event)138 base::Status AndroidBatteryStatsReader::ProcessBatteryStatsHistoryEvent(
139 base::StringView raw_event) {
140 AndroidDumpstateEvent event{
141 AndroidDumpstateEvent::EventType::kBatteryStatsHistoryEvent,
142 raw_event.ToStdString()};
143 return SendToSorter(std::chrono::milliseconds(current_timestamp_ms_), event);
144 }
145
SendToSorter(std::chrono::nanoseconds event_ts,AndroidDumpstateEvent event)146 base::Status AndroidBatteryStatsReader::SendToSorter(
147 std::chrono::nanoseconds event_ts,
148 AndroidDumpstateEvent event) {
149 ASSIGN_OR_RETURN(
150 int64_t trace_ts,
151 context_->clock_tracker->ToTraceTime(
152 protos::pbzero::ClockSnapshot::Clock::REALTIME, event_ts.count()));
153 context_->sorter->PushAndroidDumpstateEvent(trace_ts, std::move(event));
154 return base::OkStatus();
155 }
156
EndOfStream(base::StringView)157 void AndroidBatteryStatsReader::EndOfStream(base::StringView) {}
158
159 } // namespace perfetto::trace_processor
160