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