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 }
logDisplayStats(const std::shared_ptr<IStats> & stats_client,const std::vector<std::string> & display_stats_paths,const display_stats_type stats_type)323 void DisplayStatsReporter::logDisplayStats(const std::shared_ptr<IStats> &stats_client,
324 const std::vector<std::string> &display_stats_paths,
325 const display_stats_type stats_type) {
326 switch (stats_type) {
327 case DISP_PANEL_STATE:
328 logDisplayPanelErrorStats(stats_client, display_stats_paths);
329 break;
330 case DISP_PORT_STATE:
331 logDisplayPortErrorStats(stats_client, display_stats_paths);
332 break;
333 case HDCP_STATE:
334 logHDCPAuthTypeStats(stats_client, display_stats_paths);
335 break;
336 default:
337 ALOGE("Unsupport display state type(%d)", stats_type);
338 }
339 }
340
341 } // namespace pixel
342 } // namespace google
343 } // namespace hardware
344 } // namespace android
345