• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
reportVendorAtom(const std::shared_ptr<IStats> & stats_client,VendorAtom event)60 void reportVendorAtom(const std::shared_ptr<IStats> &stats_client, VendorAtom event) {
61     // consecutive Atom calls should be at least 10 milliseconds apart
62     usleep(10000);
63     if (!stats_client->reportVendorAtom(event).isOk()) {
64         ALOGE("Unable to report %d to Stats service", event.atomId);
65         return;
66     }
67 }
68 
reportSpeakerImpedance(const std::shared_ptr<IStats> & stats_client,const PixelAtoms::VendorSpeakerImpedance & speakerImpedance)69 void reportSpeakerImpedance(const std::shared_ptr<IStats> &stats_client,
70                             const PixelAtoms::VendorSpeakerImpedance &speakerImpedance) {
71     // Load values array
72     std::vector<VendorAtomValue> values(2);
73     VendorAtomValue tmp;
74     tmp.set<VendorAtomValue::intValue>(speakerImpedance.speaker_location());
75     values[0] = tmp;
76     tmp.set<VendorAtomValue::intValue>(speakerImpedance.impedance());
77     values[1] = tmp;
78 
79     // Send vendor atom to IStats HAL
80     VendorAtom event = {.reverseDomainName = "",
81                         .atomId = PixelAtoms::Atom::kVendorSpeakerImpedance,
82                         .values = std::move(values)};
83     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
84     if (!ret.isOk())
85         ALOGE("Unable to report VendorSpeakerImpedance to Stats service");
86 }
87 
reportSpeakerHealthStat(const std::shared_ptr<IStats> & stats_client,const PixelAtoms::VendorSpeakerStatsReported & speakerHealthStat)88 void reportSpeakerHealthStat(const std::shared_ptr<IStats> &stats_client,
89                              const PixelAtoms::VendorSpeakerStatsReported &speakerHealthStat) {
90     // Load values array
91     std::vector<VendorAtomValue> values(5);
92     VendorAtomValue tmp;
93     tmp.set<VendorAtomValue::intValue>(speakerHealthStat.speaker_location());
94     values[0] = tmp;
95     tmp.set<VendorAtomValue::intValue>(speakerHealthStat.impedance());
96     values[1] = tmp;
97     tmp.set<VendorAtomValue::intValue>(speakerHealthStat.max_temperature());
98     values[2] = tmp;
99     tmp.set<VendorAtomValue::intValue>(speakerHealthStat.excursion());
100     values[3] = tmp;
101     tmp.set<VendorAtomValue::intValue>(speakerHealthStat.heartbeat());
102     values[4] = tmp;
103 
104     // Send vendor atom to IStats HAL
105     VendorAtom event = {.reverseDomainName = "",
106                         .atomId = PixelAtoms::Atom::kVendorSpeakerStatsReported,
107                         .values = std::move(values)};
108     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
109     if (!ret.isOk())
110         ALOGE("Unable to report VendorSpeakerStatsReported to Stats service");
111 }
112 
reportSlowIo(const std::shared_ptr<IStats> & stats_client,const PixelAtoms::VendorSlowIo & slowIo)113 void reportSlowIo(const std::shared_ptr<IStats> &stats_client,
114                   const PixelAtoms::VendorSlowIo &slowIo) {
115     // Load values array
116     std::vector<VendorAtomValue> values(2);
117     VendorAtomValue tmp;
118     tmp.set<VendorAtomValue::intValue>(slowIo.operation());
119     values[0] = tmp;
120     tmp.set<VendorAtomValue::intValue>(slowIo.count());
121     values[1] = tmp;
122 
123     // Send vendor atom to IStats HAL
124     VendorAtom event = {.reverseDomainName = "",
125                         .atomId = PixelAtoms::Atom::kVendorSlowIo,
126                         .values = std::move(values)};
127     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
128     if (!ret.isOk())
129         ALOGE("Unable to report VendorSlowIo to Stats service");
130 }
131 
reportChargeCycles(const std::shared_ptr<IStats> & stats_client,const std::vector<int32_t> & chargeCycles)132 void reportChargeCycles(const std::shared_ptr<IStats> &stats_client,
133                         const std::vector<int32_t> &chargeCycles) {
134     // Load values array
135     const int32_t kChargeCyclesBucketsCount =
136             PixelAtoms::VendorChargeCycles::kCycleBucket10FieldNumber - kVendorAtomOffset + 1;
137     std::vector<VendorAtomValue> values(kChargeCyclesBucketsCount);
138     VendorAtomValue tmp;
139     for (int32_t bucketIdx = 0; bucketIdx < kChargeCyclesBucketsCount; ++bucketIdx) {
140         tmp.set<VendorAtomValue::intValue>(chargeCycles[bucketIdx]);
141         values[bucketIdx] = tmp;
142     }
143 
144     // Send vendor atom to IStats HAL
145     VendorAtom event = {.reverseDomainName = "",
146                         .atomId = PixelAtoms::Atom::kVendorChargeCycles,
147                         .values = std::move(values)};
148     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
149     if (!ret.isOk())
150         ALOGE("Unable to report VendorChargeCycles to Stats service");
151 }
152 
reportHardwareFailed(const std::shared_ptr<IStats> & stats_client,const PixelAtoms::VendorHardwareFailed & failure)153 void reportHardwareFailed(const std::shared_ptr<IStats> &stats_client,
154                           const PixelAtoms::VendorHardwareFailed &failure) {
155     // Load values array
156     std::vector<VendorAtomValue> values(3);
157     VendorAtomValue tmp;
158     tmp.set<VendorAtomValue::intValue>(failure.hardware_type());
159     values[0] = tmp;
160     tmp.set<VendorAtomValue::intValue>(failure.hardware_location());
161     values[1] = tmp;
162     tmp.set<VendorAtomValue::intValue>(failure.failure_code());
163     values[2] = tmp;
164 
165     // Send vendor atom to IStats HAL
166     VendorAtom event = {.reverseDomainName = "",
167                         .atomId = PixelAtoms::Atom::kVendorHardwareFailed,
168                         .values = std::move(values)};
169     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
170     if (!ret.isOk())
171         ALOGE("Unable to report VendorHardwareFailed to Stats service");
172 }
173 
reportSpeechDspStat(const std::shared_ptr<IStats> & stats_client,const PixelAtoms::VendorSpeechDspStat & dsp_stats)174 void reportSpeechDspStat(const std::shared_ptr<IStats> &stats_client,
175                          const PixelAtoms::VendorSpeechDspStat &dsp_stats) {
176     // Load values array
177     std::vector<VendorAtomValue> values(4);
178     VendorAtomValue tmp;
179     tmp.set<VendorAtomValue::intValue>(dsp_stats.total_uptime_millis());
180     values[0] = tmp;
181     tmp.set<VendorAtomValue::intValue>(dsp_stats.total_downtime_millis());
182     values[1] = tmp;
183     tmp.set<VendorAtomValue::intValue>(dsp_stats.total_crash_count());
184     values[2] = tmp;
185     tmp.set<VendorAtomValue::intValue>(dsp_stats.total_recover_count());
186     values[3] = tmp;
187 
188     // Send vendor atom to IStats HAL
189     VendorAtom event = {.reverseDomainName = "",
190                         .atomId = PixelAtoms::Atom::kVendorSpeechDspStat,
191                         .values = std::move(values)};
192     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
193     if (!ret.isOk())
194         ALOGE("Unable to report VendorSpeechDspStat to Stats service");
195 }
196 
reportUsbPortOverheat(const std::shared_ptr<IStats> & stats_client,const PixelAtoms::VendorUsbPortOverheat & overheat_info)197 void reportUsbPortOverheat(const std::shared_ptr<IStats> &stats_client,
198                            const PixelAtoms::VendorUsbPortOverheat &overheat_info) {
199     // Load values array
200     std::vector<VendorAtomValue> values(5);
201     VendorAtomValue tmp;
202     tmp.set<VendorAtomValue::intValue>(overheat_info.plug_temperature_deci_c());
203     values[0] = tmp;
204     tmp.set<VendorAtomValue::intValue>(overheat_info.max_temperature_deci_c());
205     values[1] = tmp;
206     tmp.set<VendorAtomValue::intValue>(overheat_info.time_to_overheat_secs());
207     values[2] = tmp;
208     tmp.set<VendorAtomValue::intValue>(overheat_info.time_to_hysteresis_secs());
209     values[3] = tmp;
210     tmp.set<VendorAtomValue::intValue>(overheat_info.time_to_inactive_secs());
211     values[4] = tmp;
212 
213     // Send vendor atom to IStats HAL
214     VendorAtom event = {.reverseDomainName = "",
215                         .atomId = PixelAtoms::Atom::kVendorUsbPortOverheat,
216                         .values = std::move(values)};
217     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
218     if (!ret.isOk())
219         ALOGE("Unable to report VendorUsbPortOverheat to Stats service");
220 }
221 
reportUsbDataSessionEvent(const std::shared_ptr<IStats> & stats_client,const PixelAtoms::VendorUsbDataSessionEvent & usb_data_event)222 void reportUsbDataSessionEvent(const std::shared_ptr<IStats> &stats_client,
223                                const PixelAtoms::VendorUsbDataSessionEvent &usb_data_event) {
224     // Load values array
225     std::vector<VendorAtomValue> values(4);
226     VendorAtomValue tmp;
227     tmp.set<VendorAtomValue::intValue>(usb_data_event.usb_role());
228     values[0] = tmp;
229     tmp.set<VendorAtomValue::repeatedIntValue>(std::vector<int32_t>(
230             usb_data_event.usb_states().begin(), usb_data_event.usb_states().end()));
231     values[1] = tmp;
232     tmp.set<VendorAtomValue::repeatedLongValue>(std::vector<int64_t>(
233             usb_data_event.elapsed_time_ms().begin(), usb_data_event.elapsed_time_ms().end()));
234     values[2] = tmp;
235     tmp.set<VendorAtomValue::longValue>(usb_data_event.duration_ms());
236     values[3] = tmp;
237 
238     // Send vendor atom to IStats HAL
239     VendorAtom event = {.reverseDomainName = "",
240                         .atomId = PixelAtoms::Atom::kVendorUsbDataSessionEvent,
241                         .values = std::move(values)};
242     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
243     if (!ret.isOk())
244         ALOGE("Unable to report VendorUsbDataSessionEvent to Stats service");
245 }
246 
readLogbuffer(const std::string & buf_path,int num_fields,uint16_t code,enum ReportEventFormat format,unsigned int last_check_time,std::vector<std::vector<uint32_t>> & events)247 void readLogbuffer(const std::string &buf_path, int num_fields, uint16_t code,
248                    enum ReportEventFormat format, unsigned int last_check_time,
249                    std::vector<std::vector<uint32_t>> &events) {
250     std::istringstream ss;
251     std::string file_contents, line;
252     int num, field_idx, pos, read;
253     unsigned int ts, addr, val;
254     unsigned int reported = 0;
255     uint16_t type;
256     std::vector<uint32_t> vect(num_fields);
257 
258     if (!ReadFileToString(buf_path, &file_contents)) {
259         ALOGE("Unable to read logbuffer path: %s - %s", buf_path.c_str(), strerror(errno));
260         return;
261     }
262 
263     ss.str(file_contents);
264     while (getline(ss, line)) {
265         num = sscanf(line.c_str(), "[%u.%*u] %hx%n", &ts, &type, &pos);
266         if (num != 2 || type != code)
267             continue;
268 
269         if (last_check_time != 0 && ts <= last_check_time) {
270             reported++;
271             continue;
272         }
273 
274         std::fill(vect.begin(), vect.end(), 0);
275         for (field_idx = 0; field_idx < num_fields; field_idx++, pos += read) {
276             if (format == FormatAddrWithVal) {
277                 num = sscanf(&line.c_str()[pos], "%x:%x%n", &addr, &val, &read);
278                 if (num != 2 || (num_fields - field_idx < 2))
279                     break;
280                 vect[field_idx++] = addr;
281                 vect[field_idx] = val;
282             } else if (format == FormatIgnoreAddr) {
283                 num = sscanf(&line.c_str()[pos], "%*[^:]:%x%n", &val, &read);
284                 if (num != 1)
285                     break;
286                 vect[field_idx] = val;
287             } else if (format == FormatOnlyVal) {
288                 num = sscanf(&line.c_str()[pos], "%x%n", &val, &read);
289                 if (num != 1)
290                     break;
291                 vect[field_idx] = val;
292             } else {
293                 break;
294             }
295         }
296 
297         if (field_idx == num_fields || format == FormatOnlyVal)
298             events.push_back(vect);
299     }
300     if (events.size() > 0 || reported > 0)
301         ALOGD("0x%04X: new:%zu, reported:%d", code, events.size(), reported);
302 
303     return;
304 }
305 
setAtomFieldValue(std::vector<VendorAtomValue> * values,int offset,int content)306 void setAtomFieldValue(std::vector<VendorAtomValue> *values, int offset, int content) {
307     std::vector<VendorAtomValue> &val = *values;
308 
309     if (offset - kVendorAtomOffset < val.size())
310         val[offset - kVendorAtomOffset].set<VendorAtomValue::intValue>(content);
311 }
312 
313 }  // namespace pixel
314 }  // namespace google
315 }  // namespace hardware
316 }  // namespace android
317