• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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