1 /*
2  * Copyright (C) 2023 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: DisplayStats"
18 
19 #include <aidl/android/frameworks/stats/IStats.h>
20 #include <android-base/file.h>
21 #include <android-base/parseint.h>
22 #include <android-base/properties.h>
23 #include <android-base/stringprintf.h>
24 #include <android-base/strings.h>
25 #include <android/binder_manager.h>
26 #include <hardware/google/pixel/pixelstats/pixelatoms.pb.h>
27 #include <pixelstats/DisplayStatsReporter.h>
28 #include <utils/Log.h>
29 
30 #include <cinttypes>
31 
32 namespace android {
33 namespace hardware {
34 namespace google {
35 namespace pixel {
36 
37 using aidl::android::frameworks::stats::IStats;
38 using aidl::android::frameworks::stats::VendorAtom;
39 using aidl::android::frameworks::stats::VendorAtomValue;
40 using android::base::ReadFileToString;
41 using android::hardware::google::pixel::PixelAtoms::DisplayPanelErrorStats;
42 
DisplayStatsReporter()43 DisplayStatsReporter::DisplayStatsReporter() {}
44 
readDisplayErrorCount(const std::string & path,int64_t * val)45 bool DisplayStatsReporter::readDisplayErrorCount(const std::string &path, int64_t *val) {
46     std::string file_contents;
47 
48     if (path.empty()) {
49         return false;
50     }
51 
52     if (!ReadFileToString(path.c_str(), &file_contents)) {
53         if (errno != ENOENT) {
54             ALOGD("readDisplayErrorCount Unable to read %s - %s", path.c_str(), strerror(errno));
55         }
56         return false;
57     } else {
58         file_contents = android::base::Trim(file_contents);
59         if (!android::base::ParseInt(file_contents, val)) {
60             return false;
61         }
62     }
63 
64     return true;
65 }
66 
verifyCount(int val,bool * report_stats)67 int DisplayStatsReporter::verifyCount(int val, bool *report_stats) {
68     if (val < 0) {
69         ALOGE("Invalid display stats value(%d)", val);
70         return -EINVAL;
71     } else {
72         *report_stats |= (val != 0);
73     }
74 
75     return 0;
76 }
77 
captureDisplayPanelErrorStats(const std::vector<std::string> & display_stats_paths,struct DisplayPanelErrorStats * pcur_data)78 bool DisplayStatsReporter::captureDisplayPanelErrorStats(
79         const std::vector<std::string> &display_stats_paths,
80         struct DisplayPanelErrorStats *pcur_data) {
81     bool report_stats = false;
82     std::string path;
83 
84     if (display_stats_paths.size() < kNumOfDisplayPanelErrorStats) {
85         ALOGE("Number of display stats paths (%zu) is less than expected (%d)",
86               display_stats_paths.size(), kNumOfDisplayPanelErrorStats);
87         return false;
88     }
89 
90     int64_t index = PixelAtoms::DisplayPanelErrorStats::kPrimaryErrorCountTeFieldNumber;
91     index = index - kVendorAtomOffset;
92     path = display_stats_paths[index];
93 
94     // Read primary panel error stats.
95     if (!readDisplayErrorCount(path, &(pcur_data->primary_error_count_te))) {
96         pcur_data->primary_error_count_te = prev_panel_data_.primary_error_count_te;
97     } else {
98         report_stats |=
99                 (pcur_data->primary_error_count_te > prev_panel_data_.primary_error_count_te);
100     }
101 
102     index = PixelAtoms::DisplayPanelErrorStats::kPrimaryErrorCountUnknownFieldNumber;
103     index = index - kVendorAtomOffset;
104     path = display_stats_paths[index];
105     if (!readDisplayErrorCount(path, &(pcur_data->primary_error_count_unknown))) {
106         pcur_data->primary_error_count_unknown = prev_panel_data_.primary_error_count_unknown;
107     } else {
108         report_stats |= (pcur_data->primary_error_count_unknown >
109                          prev_panel_data_.primary_error_count_unknown);
110     }
111 
112     // Read secondary panel error stats.
113     index = PixelAtoms::DisplayPanelErrorStats::kSecondaryErrorCountTeFieldNumber;
114     index = index - kVendorAtomOffset;
115     path = display_stats_paths[index];
116     if (!readDisplayErrorCount(path, &(pcur_data->secondary_error_count_te))) {
117         pcur_data->secondary_error_count_te = prev_panel_data_.secondary_error_count_te;
118     } else {
119         report_stats |=
120                 (pcur_data->secondary_error_count_te > prev_panel_data_.secondary_error_count_te);
121     }
122 
123     index = PixelAtoms::DisplayPanelErrorStats::kSecondaryErrorCountUnknownFieldNumber;
124     index = index - kVendorAtomOffset;
125     path = display_stats_paths[index];
126     if (!readDisplayErrorCount(path, &(pcur_data->secondary_error_count_unknown))) {
127         pcur_data->secondary_error_count_unknown = prev_panel_data_.secondary_error_count_unknown;
128     } else {
129         report_stats |= (pcur_data->secondary_error_count_unknown >
130                          prev_panel_data_.secondary_error_count_unknown);
131     }
132 
133     return report_stats;
134 }
135 
logDisplayPanelErrorStats(const std::shared_ptr<IStats> & stats_client,const std::vector<std::string> & display_stats_paths)136 void DisplayStatsReporter::logDisplayPanelErrorStats(
137         const std::shared_ptr<IStats> &stats_client,
138         const std::vector<std::string> &display_stats_paths) {
139     struct DisplayPanelErrorStats cur_data = prev_panel_data_;
140     bool report_stats = false;
141 
142     if (!captureDisplayPanelErrorStats(display_stats_paths, &cur_data)) {
143         prev_panel_data_ = cur_data;
144         return;
145     }
146 
147     VendorAtomValue tmp;
148     int64_t max_error_count = static_cast<int64_t>(INT32_MAX);
149     int error_count;
150     std::vector<VendorAtomValue> values(kNumOfDisplayPanelErrorStats);
151 
152     error_count = std::min<int64_t>(
153             cur_data.primary_error_count_te - prev_panel_data_.primary_error_count_te,
154             max_error_count);
155     if (verifyCount(error_count, &report_stats) < 0)
156         return;
157 
158     tmp.set<VendorAtomValue::intValue>(error_count);
159     int64_t index = PixelAtoms::DisplayPanelErrorStats::kPrimaryErrorCountTeFieldNumber;
160     index = index - kVendorAtomOffset;
161     values[index] = tmp;
162 
163     error_count = std::min<int64_t>(
164             cur_data.primary_error_count_unknown - prev_panel_data_.primary_error_count_unknown,
165             max_error_count);
166     if (verifyCount(error_count, &report_stats) < 0)
167         return;
168 
169     tmp.set<VendorAtomValue::intValue>(error_count);
170     index = PixelAtoms::DisplayPanelErrorStats::kPrimaryErrorCountUnknownFieldNumber;
171     index = index - kVendorAtomOffset;
172     values[index] = tmp;
173 
174     prev_panel_data_ = cur_data;
175 
176     if (!report_stats)
177         return;
178 
179     ALOGD("Report updated display panel metrics to stats service");
180     // Send vendor atom to IStats HAL
181     VendorAtom event = {.reverseDomainName = "",
182                         .atomId = PixelAtoms::Atom::kDisplayPanelErrorStats,
183                         .values = std::move(values)};
184     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
185     if (!ret.isOk())
186         ALOGE("Unable to report display Display Panel stats to Stats service");
187 }
188 
captureDisplayPortErrorStats(const std::vector<std::string> & displayport_stats_paths,int64_t * pcur_data)189 bool DisplayStatsReporter::captureDisplayPortErrorStats(
190         const std::vector<std::string> &displayport_stats_paths, int64_t *pcur_data) {
191     int64_t path_index;
192     bool report_stats = false;
193     std::string path;
194 
195     if (displayport_stats_paths.size() < DISPLAY_PORT_ERROR_STATS_SIZE)
196         return false;
197 
198     for (int i = 0; i < DISPLAY_PORT_ERROR_STATS_SIZE; i++) {
199         path_index = display_port_error_path_index[i];
200         path_index = path_index - kVendorAtomOffset;
201         path = displayport_stats_paths[path_index];
202 
203         if (!readDisplayErrorCount(path, &(pcur_data[i]))) {
204             pcur_data[i] = prev_dp_data_[i];
205         } else {
206             report_stats |= (pcur_data[i] > prev_dp_data_[i]);
207         }
208     }
209 
210     return report_stats;
211 }
212 
logDisplayPortErrorStats(const std::shared_ptr<IStats> & stats_client,const std::vector<std::string> & displayport_stats_paths)213 void DisplayStatsReporter::logDisplayPortErrorStats(
214         const std::shared_ptr<IStats> &stats_client,
215         const std::vector<std::string> &displayport_stats_paths) {
216     int64_t cur_data[DISPLAY_PORT_ERROR_STATS_SIZE];
217     int64_t path_index;
218     bool report_stats = false;
219 
220     memcpy(cur_data, prev_dp_data_, sizeof(prev_dp_data_));
221     if (!captureDisplayPortErrorStats(displayport_stats_paths, &cur_data[0])) {
222         memcpy(prev_dp_data_, cur_data, sizeof(cur_data));
223         return;
224     }
225 
226     VendorAtomValue tmp;
227     int64_t max_error_count = static_cast<int64_t>(INT32_MAX);
228     int error_count;
229     std::vector<VendorAtomValue> values(DISPLAY_PORT_ERROR_STATS_SIZE);
230 
231     for (int i = 0; i < DISPLAY_PORT_ERROR_STATS_SIZE; i++) {
232         error_count = std::min<int64_t>(cur_data[i] - prev_dp_data_[i], max_error_count);
233         if (verifyCount(error_count, &report_stats) < 0)
234             return;
235 
236         tmp.set<VendorAtomValue::intValue>(error_count);
237         path_index = display_port_error_path_index[i];
238         path_index = path_index - kVendorAtomOffset;
239         values[path_index] = tmp;
240     }
241 
242     memcpy(prev_dp_data_, cur_data, sizeof(cur_data));
243 
244     if (!report_stats)
245         return;
246 
247     ALOGD("Report updated displayport metrics to stats service");
248     // Send vendor atom to IStats HAL
249     VendorAtom event = {.reverseDomainName = "",
250                         .atomId = PixelAtoms::Atom::kDisplayPortErrorStats,
251                         .values = std::move(values)};
252     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
253     if (!ret.isOk())
254         ALOGE("Unable to report DisplayPort stats to Stats service");
255 }
256 
captureHDCPAuthTypeStats(const std::vector<std::string> & hdcp_stats_paths,int64_t * pcur_data)257 bool DisplayStatsReporter::captureHDCPAuthTypeStats(
258         const std::vector<std::string> &hdcp_stats_paths, int64_t *pcur_data) {
259     int64_t path_index;
260     bool report_stats = false;
261     std::string path;
262 
263     if (hdcp_stats_paths.size() < HDCP_AUTH_TYPE_STATS_SIZE)
264         return false;
265 
266     for (int i = 0; i < HDCP_AUTH_TYPE_STATS_SIZE; i++) {
267         path_index = hdcp_auth_type_path_index[i];
268         path_index = path_index - kVendorAtomOffset;
269         path = hdcp_stats_paths[path_index];
270 
271         if (!readDisplayErrorCount(path, &(pcur_data[i]))) {
272             pcur_data[i] = prev_hdcp_data_[i];
273         } else {
274             report_stats |= (pcur_data[i] > prev_hdcp_data_[i]);
275         }
276     }
277 
278     return report_stats;
279 }
280 
logHDCPAuthTypeStats(const std::shared_ptr<IStats> & stats_client,const std::vector<std::string> & hdcp_stats_paths)281 void DisplayStatsReporter::logHDCPAuthTypeStats(const std::shared_ptr<IStats> &stats_client,
282                                                 const std::vector<std::string> &hdcp_stats_paths) {
283     int64_t cur_data[HDCP_AUTH_TYPE_STATS_SIZE];
284     int64_t path_index;
285     bool report_stats = false;
286 
287     memcpy(cur_data, prev_hdcp_data_, sizeof(prev_hdcp_data_));
288     if (!captureHDCPAuthTypeStats(hdcp_stats_paths, &cur_data[0])) {
289         memcpy(prev_hdcp_data_, cur_data, sizeof(cur_data));
290         return;
291     }
292 
293     VendorAtomValue tmp;
294     int64_t max_error_count = static_cast<int64_t>(INT32_MAX);
295     int error_count;
296     std::vector<VendorAtomValue> values(HDCP_AUTH_TYPE_STATS_SIZE);
297 
298     for (int i = 0; i < HDCP_AUTH_TYPE_STATS_SIZE; i++) {
299         error_count = std::min<int64_t>(cur_data[i] - prev_hdcp_data_[i], max_error_count);
300         if (verifyCount(error_count, &report_stats) < 0)
301             return;
302 
303         tmp.set<VendorAtomValue::intValue>(error_count);
304         path_index = hdcp_auth_type_path_index[i];
305         path_index = path_index - kVendorAtomOffset;
306         values[path_index] = tmp;
307     }
308 
309     memcpy(prev_hdcp_data_, cur_data, sizeof(cur_data));
310 
311     if (!report_stats)
312         return;
313 
314     ALOGD("Report updated hdcp metrics to stats service");
315     // Send vendor atom to IStats HAL
316     VendorAtom event = {.reverseDomainName = "",
317                         .atomId = PixelAtoms::Atom::kHdcpAuthTypeStats,
318                         .values = std::move(values)};
319     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
320     if (!ret.isOk())
321         ALOGE("Unable to report hdcp stats to Stats service");
322 }
323 
324 // Capture dsc/fec support from sysfs nodes
captureDisplayPortFECDSCStats(const std::vector<std::string> & displayport_fecdsc_stats_paths,int64_t * pcur_data)325 bool DisplayStatsReporter::captureDisplayPortFECDSCStats(
326         const std::vector<std::string> &displayport_fecdsc_stats_paths, int64_t *pcur_data) {
327     bool report_stats = false;
328     std::string path;
329 
330     if (displayport_fecdsc_stats_paths.size() < DISPLAY_PORT_DSC_STATS_SIZE) {
331         ALOGE("Number of displayport dsc support stats paths (%zu) is less than expected (%d)",
332               displayport_fecdsc_stats_paths.size(), DISPLAY_PORT_DSC_STATS_SIZE);
333         return false;
334     }
335 
336     // Iterate over the sysfs nodes and collect the data
337     for (int i = 0; i < DISPLAY_PORT_DSC_STATS_SIZE; i++) {
338         // Get the sysfs path from the stats path array
339         path = displayport_fecdsc_stats_paths[i];
340 
341         if (!readDisplayErrorCount(path, &(pcur_data[i]))) {
342             // Failed to read new data, keep previous data that was saved.
343             pcur_data[i] = prev_dp_dsc_data_[i];
344         } else {
345             report_stats |= (pcur_data[i] > prev_dp_dsc_data_[i]);
346         }
347     }
348 
349     return report_stats;
350 }
351 
logDisplayPortFECDSCStats(const std::shared_ptr<IStats> & stats_client,const std::vector<std::string> & displayport_fecdsc_stats_paths)352 void DisplayStatsReporter::logDisplayPortFECDSCStats(
353         const std::shared_ptr<IStats> &stats_client,
354         const std::vector<std::string> &displayport_fecdsc_stats_paths) {
355     int64_t cur_data[DISPLAY_PORT_DSC_STATS_SIZE];
356     bool report_stats = false;
357 
358     memcpy(cur_data, prev_dp_dsc_data_, sizeof(prev_dp_dsc_data_));
359     if (!captureDisplayPortFECDSCStats(displayport_fecdsc_stats_paths, &cur_data[0])) {
360         memcpy(prev_dp_dsc_data_, cur_data, sizeof(cur_data));
361         return;
362     }
363 
364     VendorAtomValue tmp;
365     int64_t max_use_count = static_cast<int64_t>(INT32_MAX);
366     int use_count;
367     std::vector<VendorAtomValue> values(DISPLAY_PORT_DSC_STATS_SIZE);
368 
369     for (int i = 0; i < DISPLAY_PORT_DSC_STATS_SIZE; i++) {
370         use_count = std::min<int64_t>(cur_data[i] - prev_dp_dsc_data_[i], max_use_count);
371         if (verifyCount(use_count, &report_stats) < 0)
372             return;
373 
374         tmp.set<VendorAtomValue::intValue>(use_count);
375         values[i] = tmp;
376     }
377 
378     memcpy(prev_dp_dsc_data_, cur_data, sizeof(cur_data));
379 
380     if (!report_stats)
381         return;
382 
383     ALOGD("Report updated DisplayPort FEC/DSC metrics to stats service");
384     // Send vendor atom to IStats HAL
385     VendorAtom event = {.reverseDomainName = "",
386                         .atomId = PixelAtoms::Atom::kDisplayPortDscSupportStats,
387                         .values = std::move(values)};
388     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
389     if (!ret.isOk())
390         ALOGE("Unable to report DisplayPort FEC/DSC stats to Stats service");
391 }
392 
393 // Capture maximum resolution support from sysfs nodes
captureDisplayPortMaxResStats(const std::vector<std::string> & displayport_max_res_stats_paths,int64_t * pcur_data)394 bool DisplayStatsReporter::captureDisplayPortMaxResStats(
395         const std::vector<std::string> &displayport_max_res_stats_paths, int64_t *pcur_data) {
396     bool report_stats = false;
397     std::string path;
398 
399     if (displayport_max_res_stats_paths.size() < DISPLAY_PORT_MAX_RES_STATS_SIZE) {
400         ALOGE("Number of displayport maximum resolution stats paths (%zu) is less than expected "
401               "(%d)",
402               displayport_max_res_stats_paths.size(), DISPLAY_PORT_MAX_RES_STATS_SIZE);
403         return false;
404     }
405 
406     // Iterate over the sysfs nodes and collect the data
407     for (int i = 0; i < DISPLAY_PORT_MAX_RES_STATS_SIZE; i++) {
408         // Get the sysfs path from the stats path array
409         path = displayport_max_res_stats_paths[i];
410 
411         if (!readDisplayErrorCount(path, &(pcur_data[i]))) {
412             // Failed to read new data, keep previous data that was saved.
413             pcur_data[i] = prev_dp_max_res_data_[i];
414         } else {
415             report_stats |= (pcur_data[i] > prev_dp_max_res_data_[i]);
416         }
417     }
418 
419     return report_stats;
420 }
421 
logDisplayPortMaxResStats(const std::shared_ptr<IStats> & stats_client,const std::vector<std::string> & displayport_max_res_stats_paths)422 void DisplayStatsReporter::logDisplayPortMaxResStats(
423         const std::shared_ptr<IStats> &stats_client,
424         const std::vector<std::string> &displayport_max_res_stats_paths) {
425     int64_t cur_data[DISPLAY_PORT_MAX_RES_STATS_SIZE];
426     bool report_stats = false;
427 
428     memcpy(cur_data, prev_dp_max_res_data_, sizeof(prev_dp_max_res_data_));
429     if (!captureDisplayPortMaxResStats(displayport_max_res_stats_paths, &cur_data[0])) {
430         memcpy(prev_dp_max_res_data_, cur_data, sizeof(cur_data));
431         return;
432     }
433 
434     VendorAtomValue tmp;
435     int64_t max_use_count = static_cast<int64_t>(INT32_MAX);
436     int use_count;
437     std::vector<VendorAtomValue> values(DISPLAY_PORT_MAX_RES_STATS_SIZE);
438 
439     for (int i = 0; i < DISPLAY_PORT_MAX_RES_STATS_SIZE; i++) {
440         use_count = std::min<int64_t>(cur_data[i] - prev_dp_max_res_data_[i], max_use_count);
441         if (verifyCount(use_count, &report_stats) < 0)
442             return;
443 
444         tmp.set<VendorAtomValue::intValue>(use_count);
445         values[i] = tmp;
446     }
447 
448     memcpy(prev_dp_max_res_data_, cur_data, sizeof(cur_data));
449 
450     if (!report_stats)
451         return;
452 
453     ALOGD("Report updated displayport maximum resolution metrics to stats service");
454     // Send vendor atom to IStats HAL
455     VendorAtom event = {.reverseDomainName = "",
456                         .atomId = PixelAtoms::Atom::kDisplayPortMaxResolutionStats,
457                         .values = std::move(values)};
458     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
459     if (!ret.isOk())
460         ALOGE("Unable to report DisplayPort maximum resolution stats to Stats service");
461 }
462 
logDisplayStats(const std::shared_ptr<IStats> & stats_client,const std::vector<std::string> & display_stats_paths,const display_stats_type stats_type)463 void DisplayStatsReporter::logDisplayStats(const std::shared_ptr<IStats> &stats_client,
464                                            const std::vector<std::string> &display_stats_paths,
465                                            const display_stats_type stats_type) {
466     switch (stats_type) {
467         case DISP_PANEL_STATE:
468             logDisplayPanelErrorStats(stats_client, display_stats_paths);
469             break;
470         case DISP_PORT_STATE:
471             logDisplayPortErrorStats(stats_client, display_stats_paths);
472             break;
473         case HDCP_STATE:
474             logHDCPAuthTypeStats(stats_client, display_stats_paths);
475             break;
476         case DISP_PORT_DSC_STATE:
477             logDisplayPortFECDSCStats(stats_client, display_stats_paths);
478             break;
479         case DISP_PORT_MAX_RES_STATE:
480             logDisplayPortMaxResStats(stats_client, display_stats_paths);
481             break;
482         default:
483             ALOGE("Unsupport display state type(%d)", stats_type);
484     }
485 }
486 
487 }  // namespace pixel
488 }  // namespace google
489 }  // namespace hardware
490 }  // namespace android
491