1 /*
2  * Copyright (C) 2019 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_NDEBUG 0
18 #define LOG_TAG "statsd_codec"
19 #include <utils/Log.h>
20 
21 #include <dirent.h>
22 #include <inttypes.h>
23 #include <pthread.h>
24 #include <pwd.h>
25 #include <stdint.h>
26 #include <string>
27 #include <string.h>
28 #include <sys/stat.h>
29 #include <sys/time.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32 
33 #include <stats_media_metrics.h>
34 #include <stats_event.h>
35 
36 #include <frameworks/proto_logging/stats/message/mediametrics_message.pb.h>
37 #include <mediametricsservice/cleaner.h>
38 #include <mediametricsservice/iface_statsd.h>
39 #include <mediametricsservice/MediaMetricsService.h>
40 #include <mediametricsservice/StringUtils.h>
41 #include <mediametricsservice/ValidateId.h>
42 
43 namespace android {
44 
45 using stats::media_metrics::stats_write;
46 using stats::media_metrics::MEDIA_CODEC_RENDERED;
47 using stats::media_metrics::MEDIA_CODEC_RENDERED__CODEC__CODEC_UNKNOWN;
48 using stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_INVALID;
49 using stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_ZERO;
50 using stats::media_metrics::MEDIA_CODEC_RENDERED__CONTENT_FRAMERATE__FRAMERATE_UNKNOWN;
51 using stats::media_metrics::MEDIA_CODEC_RENDERED__CONTENT_FRAMERATE__FRAMERATE_UNDETERMINED;
52 using stats::media_metrics::MEDIA_CODEC_RENDERED__CONTENT_FRAMERATE__FRAMERATE_24_3_2_PULLDOWN;
53 using stats::media_metrics::MEDIA_CODEC_RENDERED__HDR_FORMAT__HDR_FORMAT_NONE;
54 using stats::media_metrics::MEDIA_CODEC_RENDERED__HDR_FORMAT__HDR_FORMAT_HLG;
55 using stats::media_metrics::MEDIA_CODEC_RENDERED__HDR_FORMAT__HDR_FORMAT_HDR10;
56 using stats::media_metrics::MEDIA_CODEC_RENDERED__HDR_FORMAT__HDR_FORMAT_HDR10_PLUS;
57 using stats::media_metrics::MEDIA_CODEC_RENDERED__HDR_FORMAT__HDR_FORMAT_DOLBY_VISION;
58 
59 static const int BITRATE_UNKNOWN =
60         stats::media_metrics::MEDIA_CODEC_RENDERED__BITRATE__BITRATE_UNKNOWN;
61 
62 static const std::pair<char const *, int> CODEC_LOOKUP[] = {
63     { "avc", stats::media_metrics::MEDIA_CODEC_RENDERED__CODEC__CODEC_AVC },
64     { "h264", stats::media_metrics::MEDIA_CODEC_RENDERED__CODEC__CODEC_AVC },
65     { "hevc", stats::media_metrics::MEDIA_CODEC_RENDERED__CODEC__CODEC_HEVC },
66     { "h265", stats::media_metrics::MEDIA_CODEC_RENDERED__CODEC__CODEC_HEVC },
67     { "vp8", stats::media_metrics::MEDIA_CODEC_RENDERED__CODEC__CODEC_VP8 },
68     { "vp9", stats::media_metrics::MEDIA_CODEC_RENDERED__CODEC__CODEC_VP9 },
69     { "av1", stats::media_metrics::MEDIA_CODEC_RENDERED__CODEC__CODEC_AV1 },
70     { "av01", stats::media_metrics::MEDIA_CODEC_RENDERED__CODEC__CODEC_AV1 },
71     { "dolby-vision", stats::media_metrics::MEDIA_CODEC_RENDERED__CODEC__CODEC_HEVC },
72 };
73 
74 static const int32_t RESOLUTION_LOOKUP[] = {
75     stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_MAX_SIZE,
76     stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_32K,
77     stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_16K,
78     stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_8K_UHD,
79     stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_8K_UHD_ALMOST,
80     stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_4K_UHD_ALMOST,
81     stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_1440X2560,
82     stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_1080X2400,
83     stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_1080X2340,
84     stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_1080P_FHD,
85     stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_1080P_FHD_ALMOST,
86     stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_720P_HD,
87     stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_720P_HD_ALMOST,
88     stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_576X1024,
89     stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_540X960,
90     stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_480X854,
91     stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_480X640,
92     stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_360X640,
93     stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_352X640,
94     stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_VERY_LOW,
95     stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_SMALLEST,
96     stats::media_metrics::MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_ZERO,
97 };
98 
99 static const int32_t FRAMERATE_LOOKUP[] = {
100     stats::media_metrics::MEDIA_CODEC_RENDERED__CONTENT_FRAMERATE__FRAMERATE_24,
101     stats::media_metrics::MEDIA_CODEC_RENDERED__CONTENT_FRAMERATE__FRAMERATE_25,
102     stats::media_metrics::MEDIA_CODEC_RENDERED__CONTENT_FRAMERATE__FRAMERATE_30,
103     stats::media_metrics::MEDIA_CODEC_RENDERED__CONTENT_FRAMERATE__FRAMERATE_50,
104     stats::media_metrics::MEDIA_CODEC_RENDERED__CONTENT_FRAMERATE__FRAMERATE_60,
105     stats::media_metrics::MEDIA_CODEC_RENDERED__CONTENT_FRAMERATE__FRAMERATE_120,
106 };
107 
getMetricsCodecEnum(const std::string & mime,const std::string & componentName)108 static int32_t getMetricsCodecEnum(const std::string &mime, const std::string &componentName) {
109     for (const auto & codecStrAndEnum : CODEC_LOOKUP) {
110         if (strcasestr(mime.c_str(), codecStrAndEnum.first) != nullptr ||
111             strcasestr(componentName.c_str(), codecStrAndEnum.first) != nullptr) {
112             return codecStrAndEnum.second;
113         }
114     }
115     return MEDIA_CODEC_RENDERED__CODEC__CODEC_UNKNOWN;
116 }
117 
getMetricsResolutionEnum(int32_t width,int32_t height)118 static int32_t getMetricsResolutionEnum(int32_t width, int32_t height) {
119     if (width == 0 || height == 0) {
120         return MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_ZERO;
121     }
122     int64_t pixels = int64_t(width) * height / 1000;
123     if (width < 0 || height < 0 || pixels > RESOLUTION_LOOKUP[0]) {
124         return MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_INVALID;
125     }
126     for (int32_t resolutionEnum : RESOLUTION_LOOKUP) {
127         if (pixels > resolutionEnum) {
128             return resolutionEnum;
129         }
130     }
131     return MEDIA_CODEC_RENDERED__RESOLUTION__RESOLUTION_ZERO;
132 }
133 
getMetricsFramerateEnum(float inFramerate)134 static int32_t getMetricsFramerateEnum(float inFramerate) {
135     if (inFramerate == -1.0f) {
136         return MEDIA_CODEC_RENDERED__CONTENT_FRAMERATE__FRAMERATE_UNDETERMINED;
137     }
138     if (inFramerate == -2.0f) {
139         return MEDIA_CODEC_RENDERED__CONTENT_FRAMERATE__FRAMERATE_24_3_2_PULLDOWN;
140     }
141     int framerate = int(inFramerate * 100); // Table is in hundredths of frames per second
142     static const int framerateTolerance = 40; // Tolerance is 0.4 frames per second - table is 100s
143     for (int32_t framerateEnum : FRAMERATE_LOOKUP) {
144         if (abs(framerate - framerateEnum) < framerateTolerance) {
145             return framerateEnum;
146         }
147     }
148     return MEDIA_CODEC_RENDERED__CONTENT_FRAMERATE__FRAMERATE_UNKNOWN;
149 }
150 
getMetricsHdrFormatEnum(std::string & mime,std::string & componentName,int32_t configColorTransfer,int32_t parsedColorTransfer,int32_t hdr10StaticInfo,int32_t hdr10PlusInfo)151 static int32_t getMetricsHdrFormatEnum(std::string &mime, std::string &componentName,
152                                        int32_t configColorTransfer, int32_t parsedColorTransfer,
153                                        int32_t hdr10StaticInfo, int32_t hdr10PlusInfo) {
154     if (hdr10PlusInfo) {
155         return MEDIA_CODEC_RENDERED__HDR_FORMAT__HDR_FORMAT_HDR10_PLUS;
156     }
157     if (hdr10StaticInfo) {
158         return MEDIA_CODEC_RENDERED__HDR_FORMAT__HDR_FORMAT_HDR10;
159     }
160     // 7 = COLOR_TRANSFER_HLG in MediaCodecConstants.h
161     if (configColorTransfer == 7 || parsedColorTransfer == 7) {
162         return MEDIA_CODEC_RENDERED__HDR_FORMAT__HDR_FORMAT_HLG;
163     }
164     if (strcasestr(mime.c_str(), "dolby-vision") != nullptr ||
165         strcasestr(componentName.c_str(), "dvhe") != nullptr ||
166         strcasestr(componentName.c_str(), "dvav") != nullptr ||
167         strcasestr(componentName.c_str(), "dav1") != nullptr) {
168         return MEDIA_CODEC_RENDERED__HDR_FORMAT__HDR_FORMAT_DOLBY_VISION;
169     }
170     return MEDIA_CODEC_RENDERED__HDR_FORMAT__HDR_FORMAT_NONE;
171 }
172 
parseVector(const std::string & str,std::vector<int32_t> * vector)173 static void parseVector(const std::string &str, std::vector<int32_t> *vector) {
174     if (!mediametrics::stringutils::parseVector(str, vector)) {
175         ALOGE("failed to parse integer vector from '%s'", str.c_str());
176     }
177 }
178 
statsd_codec(const std::shared_ptr<const mediametrics::Item> & item,const std::shared_ptr<mediametrics::StatsdLog> & statsdLog)179 bool statsd_codec(const std::shared_ptr<const mediametrics::Item>& item,
180         const std::shared_ptr<mediametrics::StatsdLog>& statsdLog)
181 {
182     if (item == nullptr) return false;
183 
184     AStatsEvent* event = AStatsEvent_obtain();
185     AStatsEvent_setAtomId(event, stats::media_metrics::MEDIA_CODEC_REPORTED);
186 
187     const nsecs_t timestampNanos = MediaMetricsService::roundTime(item->getTimestamp());
188     AStatsEvent_writeInt64(event, timestampNanos);
189 
190     // packageName deprecated for calling_uid and statsd support as of U-QPR2
191     std::string packageName = "";
192     AStatsEvent_writeString(event, packageName.c_str());
193 
194     // packageVersion depreccated for calling_uid and statsd support as of U-QPR2
195     int64_t packageVersionCode = 0;
196     AStatsEvent_writeInt64(event, packageVersionCode);
197 
198     int64_t mediaApexVersion = 0;
199     AStatsEvent_writeInt64(event, mediaApexVersion);
200 
201     // the rest into our own proto
202     //
203     ::android::stats::mediametrics_message::CodecData metrics_proto;
204 
205     // flesh out the protobuf we'll hand off with our data
206     //
207     std::string codec;
208     if (item->getString("android.media.mediacodec.codec", &codec)) {
209         metrics_proto.set_codec(codec);
210     }
211     AStatsEvent_writeString(event, codec.c_str());
212 
213     std::string mime;
214     if (item->getString("android.media.mediacodec.mime", &mime)) {
215         metrics_proto.set_mime(mime);
216     }
217     AStatsEvent_writeString(event, mime.c_str());
218 
219     std::string mode;
220     if (item->getString("android.media.mediacodec.mode", &mode)) {
221         metrics_proto.set_mode(mode);
222     }
223     AStatsEvent_writeString(event, mode.c_str());
224 
225     int32_t isEncoder = -1;
226     if (item->getInt32("android.media.mediacodec.encoder", &isEncoder)) {
227         metrics_proto.set_encoder(isEncoder);
228     }
229     AStatsEvent_writeInt32(event, isEncoder);
230 
231     int32_t isSecure = -1;
232     if (item->getInt32("android.media.mediacodec.secure", &isSecure)) {
233         metrics_proto.set_secure(isSecure);
234     }
235     AStatsEvent_writeInt32(event, isSecure);
236 
237     int32_t isHardware = -1;
238     item->getInt32("android.media.mediacodec.hardware", &isHardware);
239     // not logged to MediaCodecReported or MediametricsCodecReported
240 
241     int32_t isTunneled = -1;
242     item->getInt32("android.media.mediacodec.tunneled", &isTunneled);
243     // not logged to MediaCodecReported or MediametricsCodecReported
244 
245     int32_t width = -1;
246     if (item->getInt32("android.media.mediacodec.width", &width)) {
247         metrics_proto.set_width(width);
248     }
249     AStatsEvent_writeInt32(event, width);
250 
251     int32_t height = -1;
252     if (item->getInt32("android.media.mediacodec.height", &height)) {
253         metrics_proto.set_height(height);
254     }
255     AStatsEvent_writeInt32(event, height);
256 
257     int32_t rotation = -1;
258     if (item->getInt32("android.media.mediacodec.rotation-degrees", &rotation)) {
259         metrics_proto.set_rotation(rotation);
260     }
261     AStatsEvent_writeInt32(event, rotation);
262 
263     int32_t crypto = -1;
264     if (item->getInt32("android.media.mediacodec.crypto", &crypto)) {
265         metrics_proto.set_crypto(crypto);
266     }
267     AStatsEvent_writeInt32(event, crypto);
268 
269     int32_t profile = -1;
270     if (item->getInt32("android.media.mediacodec.profile", &profile)) {
271         metrics_proto.set_profile(profile);
272     }
273     AStatsEvent_writeInt32(event, profile);
274 
275     int32_t level = -1;
276     if (item->getInt32("android.media.mediacodec.level", &level)) {
277         metrics_proto.set_level(level);
278     }
279     AStatsEvent_writeInt32(event, level);
280 
281 
282     int32_t maxWidth = -1;
283     if ( item->getInt32("android.media.mediacodec.maxwidth", &maxWidth)) {
284         metrics_proto.set_max_width(maxWidth);
285     }
286     AStatsEvent_writeInt32(event, maxWidth);
287 
288     int32_t maxHeight = -1;
289     if ( item->getInt32("android.media.mediacodec.maxheight", &maxHeight)) {
290         metrics_proto.set_max_height(maxHeight);
291     }
292     AStatsEvent_writeInt32(event, maxHeight);
293 
294     int32_t errorCode = -1;
295     if ( item->getInt32("android.media.mediacodec.errcode", &errorCode)) {
296         metrics_proto.set_error_code(errorCode);
297     }
298     AStatsEvent_writeInt32(event, errorCode);
299 
300     std::string errorState;
301     if ( item->getString("android.media.mediacodec.errstate", &errorState)) {
302         metrics_proto.set_error_state(errorState);
303     }
304     AStatsEvent_writeString(event, errorState.c_str());
305 
306     int64_t latencyMax = -1;
307     if (item->getInt64("android.media.mediacodec.latency.max", &latencyMax)) {
308         metrics_proto.set_latency_max(latencyMax);
309     }
310     AStatsEvent_writeInt64(event, latencyMax);
311 
312     int64_t latencyMin = -1;
313     if (item->getInt64("android.media.mediacodec.latency.min", &latencyMin)) {
314         metrics_proto.set_latency_min(latencyMin);
315     }
316     AStatsEvent_writeInt64(event, latencyMin);
317 
318     int64_t latencyAvg = -1;
319     if (item->getInt64("android.media.mediacodec.latency.avg", &latencyAvg)) {
320         metrics_proto.set_latency_avg(latencyAvg);
321     }
322     AStatsEvent_writeInt64(event, latencyAvg);
323 
324     int64_t latencyCount = -1;
325     if (item->getInt64("android.media.mediacodec.latency.n", &latencyCount)) {
326         metrics_proto.set_latency_count(latencyCount);
327     }
328     AStatsEvent_writeInt64(event, latencyCount);
329 
330     int64_t latencyUnknown = -1;
331     if (item->getInt64("android.media.mediacodec.latency.unknown", &latencyUnknown)) {
332         metrics_proto.set_latency_unknown(latencyUnknown);
333     }
334     AStatsEvent_writeInt64(event, latencyUnknown);
335 
336     int32_t queueSecureInputBufferError = -1;
337     if (item->getInt32("android.media.mediacodec.queueSecureInputBufferError",
338             &queueSecureInputBufferError)) {
339         metrics_proto.set_queue_secure_input_buffer_error(queueSecureInputBufferError);
340     }
341     AStatsEvent_writeInt32(event, queueSecureInputBufferError);
342 
343     int32_t queueInputBufferError = -1;
344     if (item->getInt32("android.media.mediacodec.queueInputBufferError", &queueInputBufferError)) {
345         metrics_proto.set_queue_input_buffer_error(queueInputBufferError);
346     }
347     AStatsEvent_writeInt32(event, queueInputBufferError);
348 
349     std::string bitrateMode;
350     if (item->getString("android.media.mediacodec.bitrate_mode", &bitrateMode)) {
351         metrics_proto.set_bitrate_mode(bitrateMode);
352     }
353     AStatsEvent_writeString(event, bitrateMode.c_str());
354 
355     int32_t bitrate = -1;
356     if (item->getInt32("android.media.mediacodec.bitrate", &bitrate)) {
357         metrics_proto.set_bitrate(bitrate);
358     }
359     AStatsEvent_writeInt32(event, bitrate);
360 
361     int64_t lifetimeMillis = -1;
362     if (item->getInt64("android.media.mediacodec.lifetimeMs", &lifetimeMillis)) {
363         lifetimeMillis = mediametrics::bucket_time_minutes(lifetimeMillis);
364         metrics_proto.set_lifetime_millis(lifetimeMillis);
365     }
366     AStatsEvent_writeInt64(event, lifetimeMillis);
367 
368     int64_t playbackDurationSec = -1;
369     item->getInt64("android.media.mediacodec.playback-duration-sec", &playbackDurationSec);
370     // DO NOT record  playback-duration in the metrics_proto - it should only
371     // exist in the flattened atom
372     AStatsEvent_writeInt64(event, playbackDurationSec);
373 
374     std::string sessionId;
375     if (item->getString("android.media.mediacodec.log-session-id", &sessionId)) {
376         sessionId = mediametrics::ValidateId::get()->validateId(sessionId);
377         metrics_proto.set_log_session_id(sessionId);
378     }
379     AStatsEvent_writeString(event, sessionId.c_str());
380 
381     int32_t channelCount = -1;
382     if (item->getInt32("android.media.mediacodec.channelCount", &channelCount)) {
383         metrics_proto.set_channel_count(channelCount);
384     }
385     AStatsEvent_writeInt32(event, channelCount);
386 
387     int32_t sampleRate = -1;
388     if (item->getInt32("android.media.mediacodec.sampleRate", &sampleRate)) {
389         metrics_proto.set_sample_rate(sampleRate);
390     }
391     AStatsEvent_writeInt32(event, sampleRate);
392 
393     // TODO PWG may want these fuzzed up a bit to obscure some precision
394     int64_t bytes = -1;
395     if (item->getInt64("android.media.mediacodec.vencode.bytes", &bytes)) {
396         metrics_proto.set_video_encode_bytes(bytes);
397     }
398     AStatsEvent_writeInt64(event, bytes);
399 
400     int64_t frames = -1;
401     if (item->getInt64("android.media.mediacodec.vencode.frames", &frames)) {
402         metrics_proto.set_video_encode_frames(frames);
403     }
404     AStatsEvent_writeInt64(event, frames);
405 
406     int64_t inputBytes = -1;
407     if (item->getInt64("android.media.mediacodec.video.input.bytes", &inputBytes)) {
408         metrics_proto.set_video_input_bytes(inputBytes);
409     }
410     AStatsEvent_writeInt64(event, inputBytes);
411 
412     int64_t inputFrames = -1;
413     if (item->getInt64("android.media.mediacodec.video.input.frames", &inputFrames)) {
414         metrics_proto.set_video_input_frames(inputFrames);
415     }
416     AStatsEvent_writeInt64(event, inputFrames);
417 
418     int64_t durationUs = -1;
419     if (item->getInt64("android.media.mediacodec.vencode.durationUs", &durationUs)) {
420         metrics_proto.set_video_encode_duration_us(durationUs);
421     }
422     AStatsEvent_writeInt64(event, durationUs);
423 
424     int32_t colorFormat = -1;
425     if (item->getInt32("android.media.mediacodec.color-format", &colorFormat)) {
426         metrics_proto.set_color_format(colorFormat);
427     }
428     AStatsEvent_writeInt32(event, colorFormat);
429 
430     double frameRate = -1.0;
431     if (item->getDouble("android.media.mediacodec.frame-rate", &frameRate)) {
432         metrics_proto.set_frame_rate(frameRate);
433     }
434     AStatsEvent_writeFloat(event, (float) frameRate);
435 
436     double captureRate = -1.0;
437     if (item->getDouble("android.media.mediacodec.capture-rate", &captureRate)) {
438         metrics_proto.set_capture_rate(captureRate);
439     }
440     AStatsEvent_writeFloat(event, (float) captureRate);
441 
442     double operatingRate = -1.0;
443     if (item->getDouble("android.media.mediacodec.operating-rate", &operatingRate)) {
444         metrics_proto.set_operating_rate(operatingRate);
445     }
446     AStatsEvent_writeFloat(event, (float) operatingRate);
447 
448     int32_t priority = -1;
449     if (item->getInt32("android.media.mediacodec.priority", &priority)) {
450         metrics_proto.set_priority(priority);
451     }
452     AStatsEvent_writeInt32(event, priority);
453 
454     int32_t qpIMin = -1;
455     if (item->getInt32("android.media.mediacodec.video-qp-i-min", &qpIMin)) {
456         metrics_proto.set_video_qp_i_min(qpIMin);
457     }
458     AStatsEvent_writeInt32(event, qpIMin);
459 
460     int32_t qpIMax = -1;
461     if (item->getInt32("android.media.mediacodec.video-qp-i-max", &qpIMax)) {
462         metrics_proto.set_video_qp_i_max(qpIMax);
463     }
464     AStatsEvent_writeInt32(event, qpIMax);
465 
466     int32_t qpPMin = -1;
467     if (item->getInt32("android.media.mediacodec.video-qp-p-min", &qpPMin)) {
468         metrics_proto.set_video_qp_p_min(qpPMin);
469     }
470     AStatsEvent_writeInt32(event, qpPMin);
471 
472     int32_t qpPMax = -1;
473     if (item->getInt32("android.media.mediacodec.video-qp-p-max", &qpPMax)) {
474         metrics_proto.set_video_qp_p_max(qpPMax);
475     }
476     AStatsEvent_writeInt32(event, qpPMax);
477 
478     int32_t qpBMin = -1;
479     if (item->getInt32("android.media.mediacodec.video-qp-b-min", &qpBMin)) {
480         metrics_proto.set_video_qp_b_min(qpBMin);
481     }
482     AStatsEvent_writeInt32(event, qpBMin);
483 
484     int32_t qpBMax = -1;
485     if (item->getInt32("android.media.mediacodec.video-qp-b-max", &qpBMax)) {
486         metrics_proto.set_video_qp_b_max(qpBMax);
487     }
488     AStatsEvent_writeInt32(event, qpBMax);
489 
490     int32_t originalBitrate = -1;
491     if (item->getInt32("android.media.mediacodec.original.bitrate", &originalBitrate)) {
492         metrics_proto.set_original_bitrate(originalBitrate);
493     }
494     AStatsEvent_writeInt32(event, originalBitrate);
495 
496     int32_t shapingEnhanced = -1;
497     if ( item->getInt32("android.media.mediacodec.shaped", &shapingEnhanced)) {
498         metrics_proto.set_shaping_enhanced(shapingEnhanced);
499     }
500     AStatsEvent_writeInt32(event, shapingEnhanced);
501 
502     int32_t qpIMinOri = -1;
503     if ( item->getInt32("android.media.mediacodec.original-video-qp-i-min", &qpIMinOri)) {
504         metrics_proto.set_original_video_qp_i_min(qpIMinOri);
505     }
506     AStatsEvent_writeInt32(event, qpIMinOri);
507 
508     int32_t qpIMaxOri = -1;
509     if ( item->getInt32("android.media.mediacodec.original-video-qp-i-max", &qpIMaxOri)) {
510         metrics_proto.set_original_video_qp_i_max(qpIMaxOri);
511     }
512     AStatsEvent_writeInt32(event, qpIMaxOri);
513 
514     int32_t qpPMinOri = -1;
515     if ( item->getInt32("android.media.mediacodec.original-video-qp-p-min", &qpPMinOri)) {
516         metrics_proto.set_original_video_qp_p_min(qpPMinOri);
517     }
518     AStatsEvent_writeInt32(event, qpPMinOri);
519 
520     int32_t qpPMaxOri = -1;
521     if ( item->getInt32("android.media.mediacodec.original-video-qp-p-max", &qpPMaxOri)) {
522         metrics_proto.set_original_video_qp_p_max(qpPMaxOri);
523     }
524     AStatsEvent_writeInt32(event, qpPMaxOri);
525 
526     int32_t qpBMinOri = -1;
527     if ( item->getInt32("android.media.mediacodec.original-video-qp-b-min", &qpBMinOri)) {
528         metrics_proto.set_original_video_qp_b_min(qpBMinOri);
529     }
530     AStatsEvent_writeInt32(event, qpBMinOri);
531 
532     int32_t qpBMaxOri = -1;
533     if ( item->getInt32("android.media.mediacodec.original-video-qp-b-max", &qpBMaxOri)) {
534         metrics_proto.set_original_video_qp_b_max(qpBMaxOri);
535     }
536     AStatsEvent_writeInt32(event, qpBMaxOri);
537 
538     int32_t configColorStandard = -1;
539     if (item->getInt32("android.media.mediacodec.config-color-standard", &configColorStandard)) {
540         metrics_proto.set_config_color_standard(configColorStandard);
541     }
542     AStatsEvent_writeInt32(event, configColorStandard);
543 
544     int32_t configColorRange = -1;
545     if (item->getInt32("android.media.mediacodec.config-color-range", &configColorRange)) {
546         metrics_proto.set_config_color_range(configColorRange);
547     }
548     AStatsEvent_writeInt32(event, configColorRange);
549 
550     int32_t configColorTransfer = -1;
551     if (item->getInt32("android.media.mediacodec.config-color-transfer", &configColorTransfer)) {
552         metrics_proto.set_config_color_transfer(configColorTransfer);
553     }
554     AStatsEvent_writeInt32(event, configColorTransfer);
555 
556     int32_t parsedColorStandard = -1;
557     if (item->getInt32("android.media.mediacodec.parsed-color-standard", &parsedColorStandard)) {
558         metrics_proto.set_parsed_color_standard(parsedColorStandard);
559     }
560     AStatsEvent_writeInt32(event, parsedColorStandard);
561 
562     int32_t parsedColorRange = -1;
563     if (item->getInt32("android.media.mediacodec.parsed-color-range", &parsedColorRange)) {
564         metrics_proto.set_parsed_color_range(parsedColorRange);
565     }
566     AStatsEvent_writeInt32(event, parsedColorRange);
567 
568     int32_t parsedColorTransfer = -1;
569     if (item->getInt32("android.media.mediacodec.parsed-color-transfer", &parsedColorTransfer)) {
570         metrics_proto.set_parsed_color_transfer(parsedColorTransfer);
571     }
572     AStatsEvent_writeInt32(event, parsedColorTransfer);
573 
574     int32_t hdrStaticInfo = -1;
575     if (item->getInt32("android.media.mediacodec.hdr-static-info", &hdrStaticInfo)) {
576         metrics_proto.set_hdr_static_info(hdrStaticInfo);
577     }
578     AStatsEvent_writeInt32(event, hdrStaticInfo);
579 
580     int32_t hdr10PlusInfo = -1;
581     if (item->getInt32("android.media.mediacodec.hdr10-plus-info", &hdr10PlusInfo)) {
582         metrics_proto.set_hdr10_plus_info(hdr10PlusInfo);
583     }
584     AStatsEvent_writeInt32(event, hdr10PlusInfo);
585 
586     int32_t hdrFormat = -1;
587     if (item->getInt32("android.media.mediacodec.hdr-format", &hdrFormat)) {
588         metrics_proto.set_hdr_format(hdrFormat);
589     }
590     AStatsEvent_writeInt32(event, hdrFormat);
591 
592     int64_t codecId = 0;
593     if (item->getInt64("android.media.mediacodec.id", &codecId)) {
594         metrics_proto.set_codec_id(codecId);
595     }
596     AStatsEvent_writeInt64(event, codecId);
597 
598     int32_t arrayMode = -1;
599     if (item->getInt32("android.media.mediacodec.array-mode", &arrayMode)) {
600         metrics_proto.set_array_mode(arrayMode);
601     }
602     AStatsEvent_writeInt32(event, arrayMode);
603 
604     int32_t operationMode = -1;
605     if (item->getInt32("android.media.mediacodec.operation-mode", &operationMode)) {
606         metrics_proto.set_operation_mode(operationMode);
607     }
608     AStatsEvent_writeInt32(event, operationMode);
609 
610     int32_t outputSurface = -1;
611     if (item->getInt32("android.media.mediacodec.output-surface", &outputSurface)) {
612         metrics_proto.set_output_surface(outputSurface);
613     }
614     AStatsEvent_writeInt32(event, outputSurface);
615 
616     int32_t appMaxInputSize = -1;
617     if (item->getInt32("android.media.mediacodec.app-max-input-size", &appMaxInputSize)) {
618         metrics_proto.set_app_max_input_size(appMaxInputSize);
619     }
620     AStatsEvent_writeInt32(event, appMaxInputSize);
621 
622     int32_t usedMaxInputSize = -1;
623     if (item->getInt32("android.media.mediacodec.used-max-input-size", &usedMaxInputSize)) {
624         metrics_proto.set_used_max_input_size(usedMaxInputSize);
625     }
626     AStatsEvent_writeInt32(event, usedMaxInputSize);
627 
628     int32_t codecMaxInputSize = -1;
629     if (item->getInt32("android.media.mediacodec.codec-max-input-size", &codecMaxInputSize)) {
630         metrics_proto.set_codec_max_input_size(codecMaxInputSize);
631     }
632     AStatsEvent_writeInt32(event, codecMaxInputSize);
633 
634     int32_t flushCount = -1;
635     if (item->getInt32("android.media.mediacodec.flush-count", &flushCount)) {
636         metrics_proto.set_flush_count(flushCount);
637     }
638     AStatsEvent_writeInt32(event, flushCount);
639 
640     int32_t setSurfaceCount = -1;
641     if (item->getInt32("android.media.mediacodec.set-surface-count", &setSurfaceCount)) {
642         metrics_proto.set_set_surface_count(setSurfaceCount);
643     }
644     AStatsEvent_writeInt32(event, setSurfaceCount);
645 
646     int32_t resolutionChangeCount = -1;
647     if (item->getInt32("android.media.mediacodec.resolution-change-count",
648             &resolutionChangeCount)) {
649         metrics_proto.set_resolution_change_count(resolutionChangeCount);
650     }
651     AStatsEvent_writeInt32(event, resolutionChangeCount);
652 
653     int32_t componentColorFormat = -1;
654     if (item->getInt32("android.media.mediacodec.component-color-format", &componentColorFormat)) {
655         metrics_proto.set_component_color_format(componentColorFormat);
656     }
657     AStatsEvent_writeInt32(event, componentColorFormat);
658 
659     uid_t app_uid = item->getUid();
660     metrics_proto.set_caller_uid(app_uid);
661     AStatsEvent_writeInt32(event, app_uid);
662 
663     int64_t pixelFormat = -1;
664     if (item->getInt64("android.media.mediacodec.pixel-format", &pixelFormat)) {
665         metrics_proto.set_pixel_format(pixelFormat);
666     }
667     AStatsEvent_writeInt64(event, pixelFormat);
668 
669     int64_t firstRenderTimeUs = -1;
670     item->getInt64("android.media.mediacodec.first-render-time-us", &firstRenderTimeUs);
671     int64_t framesReleased = -1;
672     item->getInt64("android.media.mediacodec.frames-released", &framesReleased);
673     int64_t framesRendered = -1;
674     item->getInt64("android.media.mediacodec.frames-rendered", &framesRendered);
675     int64_t framesDropped = -1;
676     item->getInt64("android.media.mediacodec.frames-dropped", &framesDropped);
677     int64_t framesSkipped = -1;
678     item->getInt64("android.media.mediacodec.frames-skipped", &framesSkipped);
679     double framerateContent = -1;
680     item->getDouble("android.media.mediacodec.framerate-content", &framerateContent);
681     double framerateActual = -1;
682     item->getDouble("android.media.mediacodec.framerate-actual", &framerateActual);
683     int64_t freezeScore = -1;
684     item->getInt64("android.media.mediacodec.freeze-score", &freezeScore);
685     double freezeRate = -1;
686     item->getDouble("android.media.mediacodec.freeze-rate", &freezeRate);
687     std::string freezeScoreHistogramStr;
688     item->getString("android.media.mediacodec.freeze-score-histogram", &freezeScoreHistogramStr);
689     std::string freezeScoreHistogramBucketsStr;
690     item->getString("android.media.mediacodec.freeze-score-histogram-buckets",
691                     &freezeScoreHistogramBucketsStr);
692     std::string freezeDurationMsHistogramStr;
693     item->getString("android.media.mediacodec.freeze-duration-ms-histogram",
694                     &freezeDurationMsHistogramStr);
695     std::string freezeDurationMsHistogramBucketsStr;
696     item->getString("android.media.mediacodec.freeze-duration-ms-histogram-buckets",
697                     &freezeDurationMsHistogramBucketsStr);
698     std::string freezeDistanceMsHistogramStr;
699     item->getString("android.media.mediacodec.freeze-distance-ms-histogram",
700                     &freezeDistanceMsHistogramStr);
701     std::string freezeDistanceMsHistogramBucketsStr;
702     item->getString("android.media.mediacodec.freeze-distance-ms-histogram-buckets",
703                     &freezeDistanceMsHistogramBucketsStr);
704     int64_t judderScore = -1;
705     item->getInt64("android.media.mediacodec.judder-score", &judderScore);
706     double judderRate = -1;
707     item->getDouble("android.media.mediacodec.judder-rate", &judderRate);
708     std::string judderScoreHistogramStr;
709     item->getString("android.media.mediacodec.judder-score-histogram", &judderScoreHistogramStr);
710     std::string judderScoreHistogramBucketsStr;
711     item->getString("android.media.mediacodec.judder-score-histogram-buckets",
712                     &judderScoreHistogramBucketsStr);
713 
714     int err = AStatsEvent_write(event);
715     if (err < 0) {
716       ALOGE("Failed to write codec metrics to statsd (%d)", err);
717     }
718     AStatsEvent_release(event);
719 
720     if (framesRendered > 0) {
721         int32_t statsUid = item->getUid();
722         int64_t statsCodecId = codecId;
723         char const *statsLogSessionId = sessionId.c_str();
724         int32_t statsIsHardware = isHardware;
725         int32_t statsIsSecure = isSecure;
726         int32_t statsIsTunneled = isTunneled;
727         int32_t statsCodec = getMetricsCodecEnum(mime, codec);
728         int32_t statsResolution = getMetricsResolutionEnum(width, height);
729         int32_t statsBitrate = BITRATE_UNKNOWN;
730         int32_t statsContentFramerate = getMetricsFramerateEnum(framerateContent);
731         int32_t statsActualFramerate = getMetricsFramerateEnum(framerateActual);
732         int32_t statsHdrFormat = getMetricsHdrFormatEnum(mime, codec, configColorTransfer,
733                                                          parsedColorTransfer, hdrStaticInfo,
734                                                          hdr10PlusInfo);
735         int64_t statsFirstRenderTimeUs = firstRenderTimeUs;
736         int64_t statsPlaybackDurationSeconds = playbackDurationSec;
737         int64_t statsFramesTotal = framesReleased + framesSkipped;
738         int64_t statsFramesReleased = framesReleased;
739         int64_t statsFramesRendered = framesRendered;
740         int64_t statsFramesDropped = framesDropped;
741         int64_t statsFramesSkipped = framesSkipped;
742         float statsFrameDropRate = float(double(framesDropped) / statsFramesTotal);
743         float statsFrameSkipRate = float(double(framesSkipped) / statsFramesTotal);
744         float statsFrameSkipDropRate = float(double(framesSkipped + framesDropped) /
745                                              statsFramesTotal);
746         int64_t statsFreezeScore = freezeScore;
747         float statsFreezeRate = freezeRate;
748         std::vector<int32_t> statsFreezeDurationMsHistogram;
749         parseVector(freezeDurationMsHistogramStr, &statsFreezeDurationMsHistogram);
750         std::vector<int32_t> statsFreezeDurationMsHistogramBuckets;
751         parseVector(freezeDurationMsHistogramBucketsStr, &statsFreezeDurationMsHistogramBuckets);
752         std::vector<int32_t> statsFreezeDistanceMsHistogram;
753         parseVector(freezeDistanceMsHistogramStr, &statsFreezeDistanceMsHistogram);
754         std::vector<int32_t> statsFreezeDistanceMsHistogramBuckets;
755         parseVector(freezeDistanceMsHistogramBucketsStr, &statsFreezeDistanceMsHistogramBuckets);
756         int64_t statsJudderScore = judderScore;
757         float statsJudderRate = judderRate;
758         std::vector<int32_t> statsJudderScoreHistogram;
759         parseVector(judderScoreHistogramStr, &statsJudderScoreHistogram);
760         std::vector<int32_t> statsJudderScoreHistogramBuckets;
761         parseVector(judderScoreHistogramBucketsStr, &statsJudderScoreHistogramBuckets);
762         int result = stats_write(
763             MEDIA_CODEC_RENDERED,
764             statsUid,
765             statsCodecId,
766             statsLogSessionId,
767             statsIsHardware,
768             statsIsSecure,
769             statsIsTunneled,
770             statsCodec,
771             statsResolution,
772             statsBitrate,
773             statsContentFramerate,
774             statsActualFramerate,
775             statsHdrFormat,
776             statsFirstRenderTimeUs,
777             statsPlaybackDurationSeconds,
778             statsFramesTotal,
779             statsFramesReleased,
780             statsFramesRendered,
781             statsFramesDropped,
782             statsFramesSkipped,
783             statsFrameDropRate,
784             statsFrameSkipRate,
785             statsFrameSkipDropRate,
786             statsFreezeScore,
787             statsFreezeRate,
788             statsFreezeDurationMsHistogram,
789             statsFreezeDurationMsHistogramBuckets,
790             statsFreezeDistanceMsHistogram,
791             statsFreezeDistanceMsHistogramBuckets,
792             statsJudderScore,
793             statsJudderRate,
794             statsJudderScoreHistogram,
795             statsJudderScoreHistogramBuckets);
796         ALOGE_IF(result < 0, "Failed to record MEDIA_CODEC_RENDERED atom (%d)", result);
797     }
798 
799     std::string serialized;
800     if (!metrics_proto.SerializeToString(&serialized)) {
801         ALOGE("Failed to serialize codec metrics");
802         return false;
803     }
804     const stats::media_metrics::BytesField bf_serialized(serialized.c_str(), serialized.size());
805     const int result = stats::media_metrics::stats_write(stats::media_metrics::MEDIAMETRICS_CODEC_REPORTED,
806                                timestampNanos, packageName.c_str(), packageVersionCode,
807                                mediaApexVersion,
808                                bf_serialized);
809 
810     std::stringstream log;
811     log << "result:" << result << " {"
812             << " mediametrics_codec_reported:"
813             << stats::media_metrics::MEDIAMETRICS_CODEC_REPORTED
814             << " timestamp_nanos:" << timestampNanos
815             << " package_name:" << packageName
816             << " package_version_code:" << packageVersionCode
817             << " media_apex_version:" << mediaApexVersion
818             << " codec:" << codec
819             << " mime:" << mime
820             << " mode:" << mode
821             << " encoder:" << isEncoder
822             << " secure:" << isSecure
823             << " width:" << width
824             << " height:" << height
825             << " rotation:" << rotation
826             << " crypto:" << crypto
827             << " profile:" << profile
828             << " level:" << level
829             << " max_width:" << maxWidth
830             << " max_height:" << maxHeight
831             << " error_code:" << errorCode
832             << " error_state:" << errorState
833             << " latency_max:" << latencyMax
834             << " latency_min:" << latencyMin
835             << " latency_avg:" << latencyAvg
836             << " latency_count:" << latencyCount
837             << " latency_unknown:" << latencyUnknown
838             << " queue_input_buffer_error:" << queueInputBufferError
839             << " queue_secure_input_buffer_error:" << queueSecureInputBufferError
840             << " bitrate_mode:" << bitrateMode
841             << " bitrate:" << bitrate
842             << " original_bitrate:" << originalBitrate
843             << " lifetime_millis:" << lifetimeMillis
844             << " playback_duration_seconds:" << playbackDurationSec
845             << " log_session_id:" << sessionId
846             << " channel_count:" << channelCount
847             << " sample_rate:" << sampleRate
848             << " encode_bytes:" << bytes
849             << " encode_frames:" << frames
850             << " encode_duration_us:" << durationUs
851             << " color_format:" << colorFormat
852             << " frame_rate:" << frameRate
853             << " capture_rate:" << captureRate
854             << " operating_rate:" << operatingRate
855             << " priority:" << priority
856             << " shaping_enhanced:" << shapingEnhanced
857             << " qp_i_min:" << qpIMin
858             << " qp_i_max:" << qpIMax
859             << " qp_p_min:" << qpPMin
860             << " qp_p_max:" << qpPMax
861             << " qp_b_min:" << qpBMin
862             << " qp_b_max:" << qpBMax
863             << " original_qp_i_min:" << qpIMinOri
864             << " original_qp_i_max:" << qpIMaxOri
865             << " original_qp_p_min:" << qpPMinOri
866             << " original_qp_p_max:" << qpPMaxOri
867             << " original_qp_b_min:" << qpBMinOri
868             << " original_qp_b_max:" << qpBMaxOri
869             << " app_uid:" << app_uid
870             << " }";
871     statsdLog->log(stats::media_metrics::MEDIAMETRICS_CODEC_REPORTED, log.str());
872 
873 
874     return true;
875 }
876 
877 } // namespace android
878