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 #define LOG_TAG "pixelstats: BatteryFGReporter"
18
19 #include <log/log.h>
20 #include <time.h>
21 #include <utils/Timers.h>
22 #include <cinttypes>
23 #include <cmath>
24
25 #include <android-base/file.h>
26 #include <pixelstats/BatteryFGReporter.h>
27 #include <pixelstats/StatsHelper.h>
28 #include <hardware/google/pixel/pixelstats/pixelatoms.pb.h>
29
30 namespace android {
31 namespace hardware {
32 namespace google {
33 namespace pixel {
34
35 using aidl::android::frameworks::stats::VendorAtom;
36 using aidl::android::frameworks::stats::VendorAtomValue;
37 using android::base::ReadFileToString;
38 using android::hardware::google::pixel::PixelAtoms::BatteryEEPROM;
39 using android::hardware::google::pixel::PixelAtoms::FuelGaugeAbnormalityReported;
40
41
BatteryFGReporter()42 BatteryFGReporter::BatteryFGReporter() {}
43
getTimeSecs()44 int64_t BatteryFGReporter::getTimeSecs() {
45 return nanoseconds_to_seconds(systemTime(SYSTEM_TIME_BOOTTIME));
46 }
47
reportFGEvent(const std::shared_ptr<IStats> & stats_client,struct BatteryFGPipeline & data)48 void BatteryFGReporter::reportFGEvent(const std::shared_ptr<IStats> &stats_client,
49 struct BatteryFGPipeline &data) {
50 // Load values array
51 std::vector<VendorAtomValue> values(kNumFGPipelineFields);
52
53 if (data.event >= kNumMaxEvents) {
54 ALOGE("Exceed max number of events, expected=%d, event=%d",
55 kNumMaxEvents, data.event);
56 return;
57 }
58
59 /* save time when trigger, calculate duration when clear */
60 if (data.state == 1 && ab_trigger_time_[data.event] == 0) {
61 ab_trigger_time_[data.event] = getTimeSecs();
62 } else {
63 data.duration = getTimeSecs() - ab_trigger_time_[data.event];
64 ab_trigger_time_[data.event] = 0;
65 }
66
67 ALOGD("reportEvent: event=%d, state=%d, duration=%d, addr01=%04X, data01=%04X, "
68 "addr02=%04X, data02=%04X, addr03=%04X, data03=%04X, addr04=%04X, data04=%04X, "
69 "addr05=%04X, data05=%04X, addr06=%04X, data06=%04X, addr07=%04X, data07=%04X, "
70 "addr08=%04X, data08=%04X, addr09=%04X, data09=%04X, addr10=%04X, data10=%04X, "
71 "addr11=%04X, data11=%04X, addr12=%04X, data12=%04X, addr13=%04X, data13=%04X, "
72 "addr14=%04X, data14=%04X, addr15=%04X, data15=%04X, addr16=%04X, data16=%04X",
73 data.event, data.state, data.duration, data.addr01, data.data01,
74 data.addr02, data.data02, data.addr03, data.data03, data.addr04, data.data04,
75 data.addr05, data.data05, data.addr06, data.data06, data.addr07, data.data07,
76 data.addr08, data.data08, data.addr09, data.data09, data.addr10, data.data10,
77 data.addr11, data.data11, data.addr12, data.data12, data.addr13, data.data13,
78 data.addr14, data.data14, data.addr15, data.data15, data.addr16, data.data16);
79
80
81 /*
82 * state=0 -> untrigger, state=1 -> trigger
83 * Since atom enum reserves unknown value at 0, offset by 1 here
84 * state=1-> untrigger, state=2 -> trigger
85 */
86 data.state += 1;
87
88 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kEventFieldNumber, data.event);
89 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kEventStateFieldNumber, data.state);
90 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kDurationSecsFieldNumber,
91 data.duration);
92 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress1FieldNumber,
93 data.addr01);
94 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData1FieldNumber,
95 data.data01);
96 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress2FieldNumber,
97 data.addr02);
98 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData2FieldNumber,
99 data.data02);
100 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress3FieldNumber,
101 data.addr03);
102 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData3FieldNumber,
103 data.data03);
104 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress4FieldNumber,
105 data.addr04);
106 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData4FieldNumber,
107 data.data04);
108 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress5FieldNumber,
109 data.addr05);
110 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData5FieldNumber,
111 data.data05);
112 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress6FieldNumber,
113 data.addr06);
114 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData6FieldNumber,
115 data.data06);
116 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress7FieldNumber,
117 data.addr07);
118 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData7FieldNumber,
119 data.data07);
120 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress8FieldNumber,
121 data.addr08);
122 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData8FieldNumber,
123 data.data08);
124 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress9FieldNumber,
125 data.addr09);
126 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData9FieldNumber,
127 data.data09);
128 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress10FieldNumber,
129 data.addr10);
130 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData10FieldNumber,
131 data.data10);
132 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress11FieldNumber,
133 data.addr11);
134 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData11FieldNumber,
135 data.data11);
136 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress12FieldNumber,
137 data.addr12);
138 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData12FieldNumber,
139 data.data12);
140 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress13FieldNumber,
141 data.addr13);
142 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData13FieldNumber,
143 data.data13);
144 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress14FieldNumber,
145 data.addr14);
146 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData14FieldNumber,
147 data.data14);
148 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress15FieldNumber,
149 data.addr15);
150 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData15FieldNumber,
151 data.data15);
152 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress16FieldNumber,
153 data.addr16);
154 setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData16FieldNumber,
155 data.data16);
156
157 VendorAtom event = {.reverseDomainName = "",
158 .atomId = PixelAtoms::Atom::kFuelGaugeAbnormalityReported,
159 .values = std::move(values)};
160 reportVendorAtom(stats_client, event);
161 }
162
checkAndReportFGAbnormality(const std::shared_ptr<IStats> & stats_client,const std::vector<std::string> & paths)163 void BatteryFGReporter::checkAndReportFGAbnormality(const std::shared_ptr<IStats> &stats_client,
164 const std::vector<std::string> &paths) {
165 std::string path;
166 struct timespec boot_time;
167 std::vector<std::vector<uint32_t>> events;
168
169 if (paths.empty())
170 return;
171
172 for (int i = 0; i < paths.size(); i++) {
173 if (fileExists(paths[i])) {
174 path = paths[i];
175 break;
176 }
177 }
178
179 clock_gettime(CLOCK_MONOTONIC, &boot_time);
180 readLogbuffer(path, kNumFGPipelineFields, EvtFGAbnormalEvent, FormatOnlyVal, last_ab_check_,
181 events);
182 for (int seq = 0; seq < events.size(); seq++) {
183 if (events[seq].size() == kNumFGPipelineFields) {
184 struct BatteryFGPipeline data;
185 std::copy(events[seq].begin(), events[seq].end(), (int32_t *)&data);
186 reportFGEvent(stats_client, data);
187 } else {
188 ALOGE("Not support %zu fields for FG abnormal event", events[seq].size());
189 }
190 }
191
192 last_ab_check_ = (unsigned int)boot_time.tv_sec;
193 }
194
195 } // namespace pixel
196 } // namespace google
197 } // namespace hardware
198 } // namespace android
199