1 /*
2 * Copyright (C) 2021 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 <cinttypes>
18 #include <android/binder_manager.h>
19 #include <android-base/file.h>
20 #include <pixelstats/StatsHelper.h>
21
22 #define LOG_TAG "pixelstats-vendor"
23
24 #include <utils/Log.h>
25
26 namespace android {
27 namespace hardware {
28 namespace google {
29 namespace pixel {
30
31 using aidl::android::frameworks::stats::VendorAtom;
32 using aidl::android::frameworks::stats::VendorAtomValue;
33 using android::base::ReadFileToString;
34
35 // Proto messages are 1-indexed and VendorAtom field numbers start at 2, so
36 // store everything in the values array at the index of the field number
37 // -2.
38 const int kVendorAtomOffset = 2;
39
fileExists(const std::string & path)40 bool fileExists(const std::string &path) {
41 struct stat sb;
42
43 return stat(path.c_str(), &sb) == 0;
44 }
45
getStatsService()46 std::shared_ptr<IStats> getStatsService() {
47 const std::string instance = std::string() + IStats::descriptor + "/default";
48 static bool isStatsDeclared = false;
49 if (!isStatsDeclared) {
50 // It is good to cache the result - it would not be changed
51 isStatsDeclared = AServiceManager_isDeclared(instance.c_str());
52 if (!isStatsDeclared) {
53 ALOGE("Stats service is not registered.");
54 return nullptr;
55 }
56 }
57 return IStats::fromBinder(ndk::SpAIBinder(AServiceManager_waitForService(instance.c_str())));
58 }
59
reportSpeakerImpedance(const std::shared_ptr<IStats> & stats_client,const PixelAtoms::VendorSpeakerImpedance & speakerImpedance)60 void reportSpeakerImpedance(const std::shared_ptr<IStats> &stats_client,
61 const PixelAtoms::VendorSpeakerImpedance &speakerImpedance) {
62 // Load values array
63 std::vector<VendorAtomValue> values(2);
64 VendorAtomValue tmp;
65 tmp.set<VendorAtomValue::intValue>(speakerImpedance.speaker_location());
66 values[0] = tmp;
67 tmp.set<VendorAtomValue::intValue>(speakerImpedance.impedance());
68 values[1] = tmp;
69
70 // Send vendor atom to IStats HAL
71 VendorAtom event = {.reverseDomainName = "",
72 .atomId = PixelAtoms::Atom::kVendorSpeakerImpedance,
73 .values = std::move(values)};
74 const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
75 if (!ret.isOk())
76 ALOGE("Unable to report VendorSpeakerImpedance to Stats service");
77 }
78
reportSpeakerHealthStat(const std::shared_ptr<IStats> & stats_client,const PixelAtoms::VendorSpeakerStatsReported & speakerHealthStat)79 void reportSpeakerHealthStat(const std::shared_ptr<IStats> &stats_client,
80 const PixelAtoms::VendorSpeakerStatsReported &speakerHealthStat) {
81 // Load values array
82 std::vector<VendorAtomValue> values(5);
83 VendorAtomValue tmp;
84 tmp.set<VendorAtomValue::intValue>(speakerHealthStat.speaker_location());
85 values[0] = tmp;
86 tmp.set<VendorAtomValue::intValue>(speakerHealthStat.impedance());
87 values[1] = tmp;
88 tmp.set<VendorAtomValue::intValue>(speakerHealthStat.max_temperature());
89 values[2] = tmp;
90 tmp.set<VendorAtomValue::intValue>(speakerHealthStat.excursion());
91 values[3] = tmp;
92 tmp.set<VendorAtomValue::intValue>(speakerHealthStat.heartbeat());
93 values[4] = tmp;
94
95 // Send vendor atom to IStats HAL
96 VendorAtom event = {.reverseDomainName = "",
97 .atomId = PixelAtoms::Atom::kVendorSpeakerStatsReported,
98 .values = std::move(values)};
99 const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
100 if (!ret.isOk())
101 ALOGE("Unable to report VendorSpeakerStatsReported to Stats service");
102 }
103
reportSlowIo(const std::shared_ptr<IStats> & stats_client,const PixelAtoms::VendorSlowIo & slowIo)104 void reportSlowIo(const std::shared_ptr<IStats> &stats_client,
105 const PixelAtoms::VendorSlowIo &slowIo) {
106 // Load values array
107 std::vector<VendorAtomValue> values(2);
108 VendorAtomValue tmp;
109 tmp.set<VendorAtomValue::intValue>(slowIo.operation());
110 values[0] = tmp;
111 tmp.set<VendorAtomValue::intValue>(slowIo.count());
112 values[1] = tmp;
113
114 // Send vendor atom to IStats HAL
115 VendorAtom event = {.reverseDomainName = "",
116 .atomId = PixelAtoms::Atom::kVendorSlowIo,
117 .values = std::move(values)};
118 const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
119 if (!ret.isOk())
120 ALOGE("Unable to report VendorSlowIo to Stats service");
121 }
122
reportChargeCycles(const std::shared_ptr<IStats> & stats_client,const std::vector<int32_t> & chargeCycles)123 void reportChargeCycles(const std::shared_ptr<IStats> &stats_client,
124 const std::vector<int32_t> &chargeCycles) {
125 // Load values array
126 const int32_t kChargeCyclesBucketsCount =
127 PixelAtoms::VendorChargeCycles::kCycleBucket10FieldNumber - kVendorAtomOffset + 1;
128 std::vector<VendorAtomValue> values(kChargeCyclesBucketsCount);
129 VendorAtomValue tmp;
130 for (int32_t bucketIdx = 0; bucketIdx < kChargeCyclesBucketsCount; ++bucketIdx) {
131 tmp.set<VendorAtomValue::intValue>(chargeCycles[bucketIdx]);
132 values[bucketIdx] = tmp;
133 }
134
135 // Send vendor atom to IStats HAL
136 VendorAtom event = {.reverseDomainName = "",
137 .atomId = PixelAtoms::Atom::kVendorChargeCycles,
138 .values = std::move(values)};
139 const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
140 if (!ret.isOk())
141 ALOGE("Unable to report VendorChargeCycles to Stats service");
142 }
143
reportHardwareFailed(const std::shared_ptr<IStats> & stats_client,const PixelAtoms::VendorHardwareFailed & failure)144 void reportHardwareFailed(const std::shared_ptr<IStats> &stats_client,
145 const PixelAtoms::VendorHardwareFailed &failure) {
146 // Load values array
147 std::vector<VendorAtomValue> values(3);
148 VendorAtomValue tmp;
149 tmp.set<VendorAtomValue::intValue>(failure.hardware_type());
150 values[0] = tmp;
151 tmp.set<VendorAtomValue::intValue>(failure.hardware_location());
152 values[1] = tmp;
153 tmp.set<VendorAtomValue::intValue>(failure.failure_code());
154 values[2] = tmp;
155
156 // Send vendor atom to IStats HAL
157 VendorAtom event = {.reverseDomainName = "",
158 .atomId = PixelAtoms::Atom::kVendorHardwareFailed,
159 .values = std::move(values)};
160 const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
161 if (!ret.isOk())
162 ALOGE("Unable to report VendorHardwareFailed to Stats service");
163 }
164
reportSpeechDspStat(const std::shared_ptr<IStats> & stats_client,const PixelAtoms::VendorSpeechDspStat & dsp_stats)165 void reportSpeechDspStat(const std::shared_ptr<IStats> &stats_client,
166 const PixelAtoms::VendorSpeechDspStat &dsp_stats) {
167 // Load values array
168 std::vector<VendorAtomValue> values(4);
169 VendorAtomValue tmp;
170 tmp.set<VendorAtomValue::intValue>(dsp_stats.total_uptime_millis());
171 values[0] = tmp;
172 tmp.set<VendorAtomValue::intValue>(dsp_stats.total_downtime_millis());
173 values[1] = tmp;
174 tmp.set<VendorAtomValue::intValue>(dsp_stats.total_crash_count());
175 values[2] = tmp;
176 tmp.set<VendorAtomValue::intValue>(dsp_stats.total_recover_count());
177 values[3] = tmp;
178
179 // Send vendor atom to IStats HAL
180 VendorAtom event = {.reverseDomainName = "",
181 .atomId = PixelAtoms::Atom::kVendorSpeechDspStat,
182 .values = std::move(values)};
183 const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
184 if (!ret.isOk())
185 ALOGE("Unable to report VendorSpeechDspStat to Stats service");
186 }
187
reportUsbPortOverheat(const std::shared_ptr<IStats> & stats_client,const PixelAtoms::VendorUsbPortOverheat & overheat_info)188 void reportUsbPortOverheat(const std::shared_ptr<IStats> &stats_client,
189 const PixelAtoms::VendorUsbPortOverheat &overheat_info) {
190 // Load values array
191 std::vector<VendorAtomValue> values(5);
192 VendorAtomValue tmp;
193 tmp.set<VendorAtomValue::intValue>(overheat_info.plug_temperature_deci_c());
194 values[0] = tmp;
195 tmp.set<VendorAtomValue::intValue>(overheat_info.max_temperature_deci_c());
196 values[1] = tmp;
197 tmp.set<VendorAtomValue::intValue>(overheat_info.time_to_overheat_secs());
198 values[2] = tmp;
199 tmp.set<VendorAtomValue::intValue>(overheat_info.time_to_hysteresis_secs());
200 values[3] = tmp;
201 tmp.set<VendorAtomValue::intValue>(overheat_info.time_to_inactive_secs());
202 values[4] = tmp;
203
204 // Send vendor atom to IStats HAL
205 VendorAtom event = {.reverseDomainName = "",
206 .atomId = PixelAtoms::Atom::kVendorUsbPortOverheat,
207 .values = std::move(values)};
208 const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
209 if (!ret.isOk())
210 ALOGE("Unable to report VendorUsbPortOverheat to Stats service");
211 }
212
reportUsbDataSessionEvent(const std::shared_ptr<IStats> & stats_client,const PixelAtoms::VendorUsbDataSessionEvent & usb_data_event)213 void reportUsbDataSessionEvent(const std::shared_ptr<IStats> &stats_client,
214 const PixelAtoms::VendorUsbDataSessionEvent &usb_data_event) {
215 // Load values array
216 std::vector<VendorAtomValue> values(4);
217 VendorAtomValue tmp;
218 tmp.set<VendorAtomValue::intValue>(usb_data_event.usb_role());
219 values[0] = tmp;
220 tmp.set<VendorAtomValue::repeatedIntValue>(std::vector<int32_t>(
221 usb_data_event.usb_states().begin(), usb_data_event.usb_states().end()));
222 values[1] = tmp;
223 tmp.set<VendorAtomValue::repeatedLongValue>(std::vector<int64_t>(
224 usb_data_event.elapsed_time_ms().begin(), usb_data_event.elapsed_time_ms().end()));
225 values[2] = tmp;
226 tmp.set<VendorAtomValue::longValue>(usb_data_event.duration_ms());
227 values[3] = tmp;
228
229 // Send vendor atom to IStats HAL
230 VendorAtom event = {.reverseDomainName = "",
231 .atomId = PixelAtoms::Atom::kVendorUsbDataSessionEvent,
232 .values = std::move(values)};
233 const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
234 if (!ret.isOk())
235 ALOGE("Unable to report VendorUsbDataSessionEvent to Stats service");
236 }
237
readLogbuffer(const std::string & buf_path,int num_fields,uint16_t code,enum ReportEventFormat format,unsigned int last_check_time,std::vector<std::vector<uint16_t>> & events)238 void readLogbuffer(const std::string &buf_path, int num_fields, uint16_t code,
239 enum ReportEventFormat format, unsigned int last_check_time,
240 std::vector<std::vector<uint16_t>> &events) {
241 char hex_str[16];
242
243 snprintf(hex_str, sizeof(hex_str), "0x%X", code);
244
245 return readLogbuffer(buf_path, num_fields, hex_str, format, last_check_time, events);
246 }
247
readLogbuffer(const std::string & buf_path,int num_fields,const char * code,enum ReportEventFormat format,unsigned int last_check_time,std::vector<std::vector<uint16_t>> & events)248 void readLogbuffer(const std::string &buf_path, int num_fields, const char *code,
249 enum ReportEventFormat format, unsigned int last_check_time,
250 std::vector<std::vector<uint16_t>> &events) {
251 std::istringstream ss;
252 std::string file_contents, line;
253 int num, field_idx, pos, read;
254 unsigned int ts, reported = 0;
255 uint16_t addr, val;
256 char type[16];
257 std::vector<uint16_t> vect(num_fields);
258
259 if (!ReadFileToString(buf_path, &file_contents)) {
260 ALOGE("Unable to read logbuffer path: %s - %s", buf_path.c_str(), strerror(errno));
261 return;
262 }
263
264 ss.str(file_contents);
265 while (getline(ss, line)) {
266 num = sscanf(line.c_str(), "[%u.%*u] %15s%n", &ts, type, &pos);
267 if (num != 2 || strncmp(type, code, strlen(code)))
268 continue;
269
270 if (ts <= last_check_time) {
271 reported++;
272 continue;
273 }
274
275 for (field_idx = 0; field_idx < num_fields; field_idx++, pos += read) {
276 if (format == FormatAddrWithVal) {
277 num = sscanf(&line.c_str()[pos], " %2" SCNx16 ":%4" SCNx16 "%n", &addr, &val,
278 &read);
279 if (num != 2 || (num_fields - field_idx < 2))
280 break;
281 vect[field_idx++] = addr;
282 vect[field_idx] = val;
283 } else if (format == FormatIgnoreAddr) {
284 num = sscanf(&line.c_str()[pos], " %*2" SCNx16 ":%4" SCNx16 "%n", &val, &read);
285 if (num != 1)
286 break;
287 vect[field_idx] = val;
288 } else if (format == FormatNoAddr) {
289 num = sscanf(&line.c_str()[pos], " %4" SCNx16 "%n", &val, &read);
290 if (num != 1)
291 break;
292 vect[field_idx] = val;
293 } else {
294 break;
295 }
296 }
297
298 if (field_idx == num_fields)
299 events.push_back(vect);
300 }
301 if (events.size() > 0 || reported > 0)
302 ALOGD("%s: new:%zu, reported:%d", code, events.size(), reported);
303
304 return;
305 }
306
307 } // namespace pixel
308 } // namespace google
309 } // namespace hardware
310 } // namespace android
311