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 package android.media.metrics.cts;
18 
19 import static android.media.cts.MediaMetricsTestConstants.LOG_SESSION_ID_KEY;
20 import static android.os.statsd.media.MediaEditingExtensionAtoms.MEDIA_EDITING_ENDED_REPORTED_FIELD_NUMBER;
21 
22 import static com.google.common.truth.Truth.assertThat;
23 import static com.google.common.truth.Truth.assertWithMessage;
24 
25 import android.cts.statsdatom.lib.AtomTestUtils;
26 import android.cts.statsdatom.lib.ConfigUtils;
27 import android.cts.statsdatom.lib.DeviceUtils;
28 import android.cts.statsdatom.lib.ReportUtils;
29 import android.os.statsd.media.MediaEditingExtensionAtoms;
30 
31 import com.android.os.AtomsProto;
32 import com.android.os.StatsLog;
33 import com.android.tradefed.device.DeviceNotAvailableException;
34 import com.android.tradefed.invoker.TestInformation;
35 import com.android.tradefed.log.LogUtil;
36 import com.android.tradefed.metrics.proto.MetricMeasurement;
37 import com.android.tradefed.result.ITestInvocationListener;
38 import com.android.tradefed.result.TestDescription;
39 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
40 import com.android.tradefed.testtype.junit4.AfterClassWithInfo;
41 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
42 import com.android.tradefed.testtype.junit4.BeforeClassWithInfo;
43 import com.android.tradefed.util.RunUtil;
44 
45 import com.google.common.truth.Correspondence;
46 import com.google.protobuf.ExtensionRegistry;
47 
48 import org.junit.After;
49 import org.junit.Before;
50 import org.junit.Test;
51 import org.junit.runner.RunWith;
52 
53 import java.io.FileNotFoundException;
54 import java.util.HashMap;
55 import java.util.List;
56 import java.util.function.Function;
57 import java.util.stream.Collectors;
58 
59 import javax.annotation.Nullable;
60 
61 @RunWith(DeviceJUnit4ClassRunner.class)
62 public class MediaMetricsAtomTests extends BaseHostJUnit4Test {
63 
64     private static final String TEST_RUNNER = "androidx.test.runner.AndroidJUnitRunner";
65     private static final String TAG = "MediaMetricsAtomTests";
66     public static final String TEST_APK = "CtsMediaMetricsHostTestApp.apk";
67     public static final String TEST_PKG = "android.media.metrics.cts";
68     private static final String FEATURE_AUDIO_OUTPUT = "android.hardware.audio.output";
69     private static final String FEATURE_MICROPHONE = "android.hardware.microphone";
70     private static final String FEATURE_MIDI = "android.software.midi";
71     private static final int MAX_BUFFER_CAPACITY = 30 * 1024 * 1024; // 30M
72 
73     @BeforeClassWithInfo
installApp(TestInformation testInfo)74     public static void installApp(TestInformation testInfo)
75             throws DeviceNotAvailableException, FileNotFoundException {
76         assertThat(testInfo.getBuildInfo()).isNotNull();
77         DeviceUtils.installTestApp(testInfo.getDevice(), TEST_APK, TEST_PKG,
78                 testInfo.getBuildInfo());
79     }
80 
81     @Before
setUp()82     public void setUp() throws Exception {
83         ConfigUtils.removeConfig(getDevice());
84         ReportUtils.clearReports(getDevice());
85         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
86     }
87 
88     @After
tearDown()89     public void tearDown() throws Exception {
90         ConfigUtils.removeConfig(getDevice());
91         ReportUtils.clearReports(getDevice());
92     }
93 
94     @AfterClassWithInfo
uninstallApp(TestInformation testInfo)95     public static void uninstallApp(TestInformation testInfo) throws Exception {
96         DeviceUtils.uninstallTestApp(testInfo.getDevice(), TEST_PKG);
97     }
98 
99     @Test
testPlaybackStateEvent_default()100     public void testPlaybackStateEvent_default() throws Exception {
101         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
102                 AtomsProto.Atom.MEDIA_PLAYBACK_STATE_CHANGED_FIELD_NUMBER);
103         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
104                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
105                 "testPlaybackStateEvent_default",
106                 new LogSessionIdListener());
107         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
108 
109         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
110 
111         assertThat(data.size()).isEqualTo(1);
112         assertThat(data.get(0).getAtom().hasMediaPlaybackStateChanged()).isTrue();
113         AtomsProto.MediaPlaybackStateChanged result = data.get(
114                 0).getAtom().getMediaPlaybackStateChanged();
115         assertThat(result.getPlaybackState().toString()).isEqualTo("NOT_STARTED");
116         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(-1L);
117     }
118 
119     @Test
testPlaybackStateEvent()120     public void testPlaybackStateEvent() throws Exception {
121         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
122                 AtomsProto.Atom.MEDIA_PLAYBACK_STATE_CHANGED_FIELD_NUMBER);
123         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
124                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testPlaybackStateEvent",
125                 new LogSessionIdListener());
126         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
127 
128         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
129 
130         assertThat(data.size()).isEqualTo(1);
131         assertThat(data.get(0).getAtom().hasMediaPlaybackStateChanged()).isTrue();
132         AtomsProto.MediaPlaybackStateChanged result = data.get(
133                 0).getAtom().getMediaPlaybackStateChanged();
134         assertThat(result.getPlaybackState().toString()).isEqualTo("JOINING_FOREGROUND");
135         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(1763L);
136     }
137 
138     // same as testPlaybackStateEvent, but we use the BundleSession transport.
139     @Test
testBundleSessionPlaybackStateEvent()140     public void testBundleSessionPlaybackStateEvent() throws Exception {
141         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
142                 AtomsProto.Atom.MEDIA_PLAYBACK_STATE_CHANGED_FIELD_NUMBER);
143         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
144                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
145                 "testBundleSessionPlaybackStateEvent",
146                 new LogSessionIdListener());
147         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
148 
149         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
150 
151         assertThat(data.size()).isEqualTo(1);
152         assertThat(data.get(0).getAtom().hasMediaPlaybackStateChanged()).isTrue();
153         AtomsProto.MediaPlaybackStateChanged result = data.get(
154                 0).getAtom().getMediaPlaybackStateChanged();
155         assertThat(result.getPlaybackState().toString()).isEqualTo("JOINING_FOREGROUND");
156         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(1763L);
157     }
158 
159     @Test
testPlaybackErrorEvent_default()160     public void testPlaybackErrorEvent_default() throws Exception {
161         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
162                 AtomsProto.Atom.MEDIA_PLAYBACK_ERROR_REPORTED_FIELD_NUMBER);
163         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
164                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
165                 "testPlaybackErrorEvent_default",
166                 new LogSessionIdListener());
167         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
168 
169         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
170 
171         assertThat(data.size()).isEqualTo(1);
172         assertThat(data.get(0).getAtom().hasMediaPlaybackErrorReported()).isTrue();
173         AtomsProto.MediaPlaybackErrorReported result = data.get(
174                 0).getAtom().getMediaPlaybackErrorReported();
175 
176         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(-1L);
177         assertThat(result.getErrorCode().toString()).isEqualTo("ERROR_CODE_UNKNOWN");
178         assertThat(result.getSubErrorCode()).isEqualTo(0);
179         assertThat(result.getExceptionStack().startsWith(
180                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests"
181                         + ".testPlaybackErrorEvent")).isTrue();
182     }
183 
184     @Test
testPlaybackErrorEvent()185     public void testPlaybackErrorEvent() throws Exception {
186         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
187                 AtomsProto.Atom.MEDIA_PLAYBACK_ERROR_REPORTED_FIELD_NUMBER);
188         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
189                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testPlaybackErrorEvent",
190                 new LogSessionIdListener());
191         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
192 
193         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
194 
195         assertThat(data.size()).isEqualTo(1);
196         assertThat(data.get(0).getAtom().hasMediaPlaybackErrorReported()).isTrue();
197         AtomsProto.MediaPlaybackErrorReported result = data.get(
198                 0).getAtom().getMediaPlaybackErrorReported();
199 
200         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(17630000L);
201         assertThat(result.getErrorCode().toString()).isEqualTo("ERROR_CODE_RUNTIME");
202         assertThat(result.getSubErrorCode()).isEqualTo(378);
203         assertThat(result.getExceptionStack().startsWith(
204                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests"
205                         + ".testPlaybackErrorEvent")).isTrue();
206     }
207 
208     @Test
testTrackChangeEvent_default()209     public void testTrackChangeEvent_default() throws Exception {
210         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
211                 AtomsProto.Atom.MEDIA_PLAYBACK_TRACK_CHANGED_FIELD_NUMBER);
212         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
213                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
214                 "testTrackChangeEvent_default",
215                 new LogSessionIdListener());
216         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
217 
218         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
219 
220         assertThat(data.size()).isEqualTo(1);
221         assertThat(data.get(0).getAtom().hasMediaPlaybackTrackChanged()).isTrue();
222         AtomsProto.MediaPlaybackTrackChanged result = data.get(
223                 0).getAtom().getMediaPlaybackTrackChanged();
224 
225         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(-1L);
226         assertThat(result.getState().toString()).isEqualTo("OFF");
227         assertThat(result.getReason().toString()).isEqualTo("REASON_UNKNOWN");
228         assertThat(result.getContainerMimeType()).isEqualTo("");
229         assertThat(result.getSampleMimeType()).isEqualTo("");
230         assertThat(result.getCodecName()).isEqualTo("");
231         assertThat(result.getBitrate()).isEqualTo(-1);
232         assertThat(result.getType().toString()).isEqualTo("AUDIO");
233         assertThat(result.getLanguage()).isEqualTo("");
234         assertThat(result.getLanguageRegion()).isEqualTo("");
235         assertThat(result.getSampleRate()).isEqualTo(-1);
236         assertThat(result.getChannelCount()).isEqualTo(-1);
237     }
238 
239     @Test
testTrackChangeEvent_text()240     public void testTrackChangeEvent_text() throws Exception {
241         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
242                 AtomsProto.Atom.MEDIA_PLAYBACK_TRACK_CHANGED_FIELD_NUMBER);
243         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
244                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
245                 "testTrackChangeEvent_text",
246                 new LogSessionIdListener());
247         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
248 
249         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
250 
251         assertThat(data.size()).isEqualTo(1);
252         assertThat(data.get(0).getAtom().hasMediaPlaybackTrackChanged()).isTrue();
253         AtomsProto.MediaPlaybackTrackChanged result = data.get(
254                 0).getAtom().getMediaPlaybackTrackChanged();
255 
256         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(37278L);
257         assertThat(result.getState().toString()).isEqualTo("ON");
258         assertThat(result.getReason().toString()).isEqualTo("REASON_MANUAL");
259         assertThat(result.getContainerMimeType()).isEqualTo("text/foo");
260         assertThat(result.getSampleMimeType()).isEqualTo("text/plain");
261         assertThat(result.getCodecName()).isEqualTo("codec_1");
262         assertThat(result.getBitrate()).isEqualTo(1024);
263         assertThat(result.getType().toString()).isEqualTo("TEXT");
264         assertThat(result.getLanguage()).isEqualTo("EN");
265         assertThat(result.getLanguageRegion()).isEqualTo("US");
266     }
267 
268     @Test
testTrackChangeEvent_audio()269     public void testTrackChangeEvent_audio() throws Exception {
270         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
271                 AtomsProto.Atom.MEDIA_PLAYBACK_TRACK_CHANGED_FIELD_NUMBER);
272         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
273                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
274                 "testTrackChangeEvent_audio",
275                 new LogSessionIdListener());
276         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
277 
278         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
279 
280         assertThat(data.size()).isEqualTo(1);
281         assertThat(data.get(0).getAtom().hasMediaPlaybackTrackChanged()).isTrue();
282         AtomsProto.MediaPlaybackTrackChanged result = data.get(
283                 0).getAtom().getMediaPlaybackTrackChanged();
284 
285         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(37278L);
286         assertThat(result.getState().toString()).isEqualTo("OFF");
287         assertThat(result.getReason().toString()).isEqualTo("REASON_INITIAL");
288         assertThat(result.getContainerMimeType()).isEqualTo("audio/foo");
289         assertThat(result.getSampleMimeType()).isEqualTo("audio/avc");
290         assertThat(result.getCodecName()).isEqualTo("codec_2");
291         assertThat(result.getBitrate()).isEqualTo(1025);
292         assertThat(result.getType().toString()).isEqualTo("AUDIO");
293         assertThat(result.getLanguage()).isEqualTo("EN");
294         assertThat(result.getLanguageRegion()).isEqualTo("US");
295         assertThat(result.getSampleRate()).isEqualTo(89);
296         assertThat(result.getChannelCount()).isEqualTo(3);
297     }
298 
299     @Test
testTrackChangeEvent_video()300     public void testTrackChangeEvent_video() throws Exception {
301         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
302                 AtomsProto.Atom.MEDIA_PLAYBACK_TRACK_CHANGED_FIELD_NUMBER);
303         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
304                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
305                 "testTrackChangeEvent_video",
306                 new LogSessionIdListener());
307         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
308 
309         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
310 
311         assertThat(data.size()).isEqualTo(1);
312         assertThat(data.get(0).getAtom().hasMediaPlaybackTrackChanged()).isTrue();
313         AtomsProto.MediaPlaybackTrackChanged result = data.get(
314                 0).getAtom().getMediaPlaybackTrackChanged();
315 
316         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(37278L);
317         assertThat(result.getState().toString()).isEqualTo("OFF");
318         assertThat(result.getReason().toString()).isEqualTo("REASON_INITIAL");
319         assertThat(result.getContainerMimeType()).isEqualTo("video/foo");
320         assertThat(result.getSampleMimeType()).isEqualTo("video/mpeg");
321         assertThat(result.getCodecName()).isEqualTo("codec_3");
322         assertThat(result.getBitrate()).isEqualTo(1025);
323         assertThat(result.getType().toString()).isEqualTo("VIDEO");
324         assertThat(result.getLanguage()).isEqualTo("EN");
325         assertThat(result.getLanguageRegion()).isEqualTo("US");
326         assertThat(result.getHeight()).isEqualTo(1080);
327         assertThat(result.getWidth()).isEqualTo(1440);
328         assertThat(result.getVideoFrameRate()).isEqualTo(60);
329     }
330 
331     @Test
testNetworkEvent_default()332     public void testNetworkEvent_default() throws Exception {
333         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
334                 AtomsProto.Atom.MEDIA_NETWORK_INFO_CHANGED_FIELD_NUMBER);
335         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
336                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
337                 "testNetworkEvent_default",
338                 new LogSessionIdListener());
339         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
340 
341         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
342 
343         assertThat(data.size()).isEqualTo(1);
344         assertThat(data.get(0).getAtom().hasMediaNetworkInfoChanged()).isTrue();
345         AtomsProto.MediaNetworkInfoChanged result = data.get(
346                 0).getAtom().getMediaNetworkInfoChanged();
347 
348         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(-1L);
349         assertThat(result.getType().toString()).isEqualTo("NETWORK_TYPE_UNKNOWN");
350     }
351 
352     @Test
testNetworkEvent()353     public void testNetworkEvent() throws Exception {
354         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
355                 AtomsProto.Atom.MEDIA_NETWORK_INFO_CHANGED_FIELD_NUMBER);
356         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
357                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testNetworkEvent",
358                 new LogSessionIdListener());
359         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
360 
361         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
362 
363         assertThat(data.size()).isEqualTo(1);
364         assertThat(data.get(0).getAtom().hasMediaNetworkInfoChanged()).isTrue();
365         AtomsProto.MediaNetworkInfoChanged result = data.get(
366                 0).getAtom().getMediaNetworkInfoChanged();
367 
368         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(3032L);
369         assertThat(result.getType().toString()).isEqualTo("NETWORK_TYPE_WIFI");
370     }
371 
372     @Test
testPlaybackMetrics_default()373     public void testPlaybackMetrics_default() throws Exception {
374         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
375                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
376         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
377                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
378                 "testPlaybackMetrics_default",
379                 new LogSessionIdListener());
380         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
381 
382         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
383         int appUid = DeviceUtils.getAppUid(getDevice(), TEST_PKG);
384 
385         assertThat(data.size()).isEqualTo(1);
386         assertThat(data.get(0).getAtom().hasMediametricsPlaybackReported()).isTrue();
387         AtomsProto.MediametricsPlaybackReported result = data.get(
388                 0).getAtom().getMediametricsPlaybackReported();
389 
390         assertThat(result.getUid()).isEqualTo(appUid);
391         assertThat(result.getMediaDurationMillis()).isEqualTo(-1L);
392         assertThat(result.getStreamSource().toString()).isEqualTo("STREAM_SOURCE_UNKNOWN");
393         assertThat(result.getStreamType().toString()).isEqualTo("STREAM_TYPE_UNKNOWN");
394         assertThat(result.getPlaybackType().toString()).isEqualTo("PLAYBACK_TYPE_UNKNOWN");
395         assertThat(result.getDrmType().toString()).isEqualTo("DRM_TYPE_NONE");
396         assertThat(result.getContentType().toString()).isEqualTo("CONTENT_TYPE_UNKNOWN");
397         assertThat(result.getPlayerName()).isEqualTo("");
398         assertThat(result.getPlayerVersion()).isEqualTo("");
399         assertThat(result.getVideoFramesPlayed()).isEqualTo(-1);
400         assertThat(result.getVideoFramesDropped()).isEqualTo(-1);
401         assertThat(result.getAudioUnderrunCount()).isEqualTo(-1);
402         assertThat(result.getNetworkBytesRead()).isEqualTo(-1);
403         assertThat(result.getLocalBytesRead()).isEqualTo(-1);
404         assertThat(result.getNetworkTransferDurationMillis()).isEqualTo(-1);
405         assertThat(result.getExperimentIds().getExperimentsList().size()).isEqualTo(0);
406         assertThat(result.getDrmSessionId().length()).isEqualTo(0);
407     }
408 
409     @Test
testPlaybackMetrics()410     public void testPlaybackMetrics() throws Exception {
411         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
412                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
413         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
414                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testPlaybackMetrics",
415                 new LogSessionIdListener());
416         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
417 
418         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
419         int appUid = DeviceUtils.getAppUid(getDevice(), TEST_PKG);
420 
421         assertThat(data.size()).isEqualTo(1);
422         assertThat(data.get(0).getAtom().hasMediametricsPlaybackReported()).isTrue();
423         AtomsProto.MediametricsPlaybackReported result = data.get(
424                 0).getAtom().getMediametricsPlaybackReported();
425 
426         assertThat(result.getUid()).isEqualTo(appUid);
427         assertThat(result.getMediaDurationMillis()).isEqualTo(233L);
428         assertThat(result.getStreamSource().toString()).isEqualTo("STREAM_SOURCE_NETWORK");
429         assertThat(result.getStreamType().toString()).isEqualTo("STREAM_TYPE_OTHER");
430         assertThat(result.getPlaybackType().toString()).isEqualTo("PLAYBACK_TYPE_LIVE");
431         assertThat(result.getDrmType().toString()).isEqualTo("DRM_TYPE_WV_L1");
432         assertThat(result.getContentType().toString()).isEqualTo("CONTENT_TYPE_MAIN");
433         assertThat(result.getPlayerName()).isEqualTo("ExoPlayer");
434         assertThat(result.getPlayerVersion()).isEqualTo("1.01x");
435         assertThat(result.getVideoFramesPlayed()).isEqualTo(1024);
436         assertThat(result.getVideoFramesDropped()).isEqualTo(32);
437         assertThat(result.getAudioUnderrunCount()).isEqualTo(22);
438         assertThat(result.getNetworkBytesRead()).isEqualTo(102400);
439         assertThat(result.getLocalBytesRead()).isEqualTo(2000);
440         assertThat(result.getNetworkTransferDurationMillis()).isEqualTo(6000);
441         // TODO: fix missing experiment ID impl
442         assertThat(result.getExperimentIds()).isNotEqualTo(null);
443         // TODO: needs Base64 decoders to verify the data
444         assertThat(result.getDrmSessionId()).isNotEqualTo(null);
445     }
446 
447     @Test
testEditingEndedEvent_default()448     public void testEditingEndedEvent_default() throws Exception {
449         ConfigUtils.uploadConfigForPushedAtom(
450                 getDevice(), TEST_PKG, MEDIA_EDITING_ENDED_REPORTED_FIELD_NUMBER);
451         ExtensionRegistry registry = ExtensionRegistry.newInstance();
452         MediaEditingExtensionAtoms.registerAllExtensions(registry);
453 
454         DeviceUtils.runDeviceTests(
455                 getDevice(),
456                 TEST_PKG,
457                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
458                 "testEditingEndedEvent_default",
459                 new LogSessionIdListener());
460         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
461 
462         List<StatsLog.EventMetricData> data =
463                 ReportUtils.getEventMetricDataList(getDevice(), registry);
464         assertThat(data).hasSize(1);
465         MediaEditingExtensionAtoms.MediaEditingEndedReported atom =
466                 data.get(0)
467                         .getAtom()
468                         .getExtension(MediaEditingExtensionAtoms.mediaEditingEndedReported);
469         assertThat(atom.getFinalProgressPercent()).isEqualTo(-1f);
470         assertThat(atom.getTimeSinceEditingCreatedMillis()).isEqualTo(-1L);
471         assertThat(atom.getExporterName()).isEqualTo("");
472         assertThat(atom.getMuxerName()).isEqualTo("");
473         assertThat(atom.getFinalState().toString()).isEqualTo("FINAL_STATE_SUCCEEDED");
474         assertThat(atom.getErrorCode().toString()).isEqualTo("ERROR_CODE_NONE");
475     }
476 
477     @Test
testEditingEndedEvent_error()478     public void testEditingEndedEvent_error() throws Exception {
479         ConfigUtils.uploadConfigForPushedAtom(
480                 getDevice(), TEST_PKG, MEDIA_EDITING_ENDED_REPORTED_FIELD_NUMBER);
481         ExtensionRegistry registry = ExtensionRegistry.newInstance();
482         MediaEditingExtensionAtoms.registerAllExtensions(registry);
483 
484         DeviceUtils.runDeviceTests(
485                 getDevice(),
486                 TEST_PKG,
487                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
488                 "testEditingEndedEvent_error",
489                 new LogSessionIdListener());
490         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
491 
492         List<StatsLog.EventMetricData> data =
493                 ReportUtils.getEventMetricDataList(getDevice(), registry);
494         assertThat(data).hasSize(1);
495         MediaEditingExtensionAtoms.MediaEditingEndedReported atom =
496                 data.get(0)
497                         .getAtom()
498                         .getExtension(MediaEditingExtensionAtoms.mediaEditingEndedReported);
499         assertThat(atom.getTimeSinceEditingCreatedMillis()).isEqualTo(17630000L);
500         assertThat(atom.getExporterName()).isEqualTo("");
501         assertThat(atom.getMuxerName()).isEqualTo("androidx.media3:media3-muxer:1.2.1");
502         assertThat(atom.getFinalState().toString()).isEqualTo("FINAL_STATE_ERROR");
503         assertThat(atom.getFinalProgressPercent()).isEqualTo(10f);
504         assertThat(atom.getErrorCode().toString()).isEqualTo("ERROR_CODE_FAILED_RUNTIME_CHECK");
505         assertThat(atom.getOperationTypeVideoTranscode()).isFalse();
506         assertThat(atom.getOperationTypeAudioTranscode()).isFalse();
507         assertThat(atom.getOperationTypeVideoEdit()).isTrue();
508         assertThat(atom.getOperationTypeAudioEdit()).isFalse();
509         assertThat(atom.getOperationTypeVideoTransmux()).isFalse();
510         assertThat(atom.getOperationTypeAudioTransmux()).isTrue();
511         assertThat(atom.getOperationTypeWasPaused()).isFalse();
512         assertThat(atom.getOperationTypeWasResumed()).isFalse();
513     }
514 
515     @Test
testEditingEndedEvent_transcodeAndClip()516     public void testEditingEndedEvent_transcodeAndClip() throws Exception {
517         ConfigUtils.uploadConfigForPushedAtom(
518                 getDevice(), TEST_PKG, MEDIA_EDITING_ENDED_REPORTED_FIELD_NUMBER);
519         ExtensionRegistry registry = ExtensionRegistry.newInstance();
520         MediaEditingExtensionAtoms.registerAllExtensions(registry);
521 
522         DeviceUtils.runDeviceTests(
523                 getDevice(),
524                 TEST_PKG,
525                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
526                 "testEditingEndedEvent_transcodeAndClip",
527                 new LogSessionIdListener());
528         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
529 
530         List<StatsLog.EventMetricData> data =
531                 ReportUtils.getEventMetricDataList(getDevice(), registry);
532         assertThat(data).hasSize(1);
533         MediaEditingExtensionAtoms.MediaEditingEndedReported atom =
534                 data.get(0)
535                         .getAtom()
536                         .getExtension(MediaEditingExtensionAtoms.mediaEditingEndedReported);
537         assertThat(atom.getTimeSinceEditingCreatedMillis()).isEqualTo(2_000L);
538         assertThat(atom.getExporterName())
539                 .isEqualTo("androidx.media3:media3-transformer:1.3.0-beta01");
540         assertThat(atom.getMuxerName()).isEqualTo("androidx.media3:media3-muxer:1.3.0-beta01");
541         assertThat(atom.getFinalState().toString()).isEqualTo("FINAL_STATE_SUCCEEDED");
542         assertThat(atom.getFinalProgressPercent()).isEqualTo(100f);
543         assertThat(atom.getErrorCode().toString()).isEqualTo("ERROR_CODE_NONE");
544         assertThat(atom.getInputMediaItemCount()).isEqualTo(1);
545         assertThat(atom.getInputMediaItem1SourceType().toString()).isEqualTo("SOURCE_TYPE_CAMERA");
546         assertThat(atom.getInputMediaItem1HasDataTypeImage()).isFalse();
547         assertThat(atom.getInputMediaItem1HasDataTypeVideo()).isTrue();
548         assertThat(atom.getInputMediaItem1HasDataTypeAudio()).isTrue();
549         assertThat(atom.getInputMediaItem1HasDataTypeMetadata()).isFalse();
550         assertThat(atom.getInputMediaItem1HasDataTypeDepth()).isFalse();
551         assertThat(atom.getInputMediaItem1HasDataTypeGainMap()).isFalse();
552         assertThat(atom.getInputMediaItem1HasDataTypeHighFrameRate()).isFalse();
553         assertThat(atom.getInputMediaItem1HasDataTypeCuePoints()).isFalse();
554         assertThat(atom.getInputMediaItem1HasDataTypeGapless()).isFalse();
555         assertThat(atom.getInputMediaItem1HasDataTypeSpatialAudio()).isFalse();
556         assertThat(atom.getInputMediaItem1HasDataTypeHighDynamicRangeVideo()).isTrue();
557         assertThat(atom.getInputMediaItem1DurationMillis()).isEqualTo(3_750L);
558         assertThat(atom.getInputMediaItem1ClipDurationMillis()).isEqualTo(1_875L);
559         assertThat(atom.getInputMediaItem1ContainerMimeType()).isEqualTo("video/mp4");
560         assertThat(atom.getInputMediaItem1AudioSampleMimeType()).isEqualTo("audio/mp4a-latm");
561         assertThat(atom.getInputMediaItem1VideoSampleMimeType()).isEqualTo("video/hevc");
562         assertThat(atom.getInputMediaItem1CommonVideoCodec().toString()).isEqualTo("CODEC_HEVC");
563         assertThat(atom.getInputMediaItem1CodecName1()).isEqualTo("c2.android.hevc.decoder");
564         assertThat(atom.getInputMediaItem1CodecName2()).isEqualTo("c2.android.aac.decoder");
565         assertThat(atom.getInputMediaItem1AudioSampleRateHz()).isEqualTo(44100);
566         assertThat(atom.getInputMediaItem1AudioChannelCount()).isEqualTo(2);
567         assertThat(atom.getInputMediaItem1AudioSampleCount()).isEqualTo(10_000L);
568         assertThat(atom.getInputMediaItem1VideoRawWidthPixels()).isEqualTo(1080);
569         assertThat(atom.getInputMediaItem1VideoRawHeightPixels()).isEqualTo(1920);
570         assertThat(atom.getInputMediaItem1VideoResolution().toString())
571                 .isEqualTo("RESOLUTION_1080P_FHD");
572         assertThat(atom.getInputMediaItem1VideoResolutionAspectRatio().toString())
573                 .isEqualTo("RESOLUTION_ASPECT_RATIO_PORTRAIT");
574         assertThat(atom.getInputMediaItem1VideoDataSpace())
575                 .isEqualTo(/* BT2020 | HLG | FULL */ 0b1010000001100000000000000000);
576         assertThat(atom.getInputMediaItem1VideoFrameRate()).isEqualTo(25);
577         assertThat(atom.getThroughputFps()).isEqualTo(50);
578         assertThat(atom.getOutputMediaItemHasDataTypeImage()).isFalse();
579         assertThat(atom.getOutputMediaItemHasDataTypeVideo()).isTrue();
580         assertThat(atom.getOutputMediaItemHasDataTypeAudio()).isTrue();
581         assertThat(atom.getOutputMediaItemHasDataTypeMetadata()).isFalse();
582         assertThat(atom.getOutputMediaItemHasDataTypeDepth()).isFalse();
583         assertThat(atom.getOutputMediaItemHasDataTypeGainMap()).isFalse();
584         assertThat(atom.getOutputMediaItemHasDataTypeHighFrameRate()).isFalse();
585         assertThat(atom.getOutputMediaItemHasDataTypeCuePoints()).isFalse();
586         assertThat(atom.getOutputMediaItemHasDataTypeGapless()).isFalse();
587         assertThat(atom.getOutputMediaItemHasDataTypeSpatialAudio()).isFalse();
588         assertThat(atom.getOutputMediaItemHasDataTypeHighDynamicRangeVideo()).isFalse();
589         assertThat(atom.getOutputMediaItemDurationMillis()).isEqualTo(1_875L);
590         assertThat(atom.getOutputMediaItemContainerMimeType()).isEqualTo("video/mp4");
591         assertThat(atom.getOutputMediaItemAudioSampleMimeType()).isEqualTo("audio/mp4a-latm");
592         assertThat(atom.getOutputMediaItemVideoSampleMimeType()).isEqualTo("video/avc");
593         assertThat(atom.getOutputMediaItemCommonVideoCodec().toString()).isEqualTo("CODEC_AVC");
594         assertThat(atom.getOutputMediaItemCodecName1()).isEqualTo("c2.android.avc.encoder");
595         assertThat(atom.getOutputMediaItemCodecName2()).isEqualTo("c2.android.aac.encoder");
596         assertThat(atom.getOutputMediaItemAudioSampleRateHz()).isEqualTo(44100);
597         assertThat(atom.getOutputMediaItemAudioChannelCount()).isEqualTo(2);
598         assertThat(atom.getOutputMediaItemAudioSampleCount()).isEqualTo(10_000L);
599         assertThat(atom.getOutputMediaItemVideoRawWidthPixels()).isEqualTo(720);
600         assertThat(atom.getOutputMediaItemVideoRawHeightPixels()).isEqualTo(1280);
601         assertThat(atom.getOutputMediaItemVideoResolution().toString())
602                 .isEqualTo("RESOLUTION_720P_HD");
603         assertThat(atom.getOutputMediaItemVideoResolutionAspectRatio().toString())
604                 .isEqualTo("RESOLUTION_ASPECT_RATIO_PORTRAIT");
605         assertThat(atom.getOutputMediaItemVideoDataSpace())
606                 .isEqualTo(/* BT709 | LINEAR | FULL */ 0b1000010000010000000000000000);
607         assertThat(atom.getOutputMediaItemVideoFrameRate()).isEqualTo(25);
608     }
609 
610     @Test
testSessionId()611     public void testSessionId() throws Exception {
612         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
613                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
614         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
615                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testSessionId",
616                 new LogSessionIdListener());
617         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
618 
619         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
620         assertThat(data).isEmpty();
621     }
622 
623     @Test
testRecordingSession()624     public void testRecordingSession() throws Exception {
625         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
626                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
627         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
628                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testRecordingSession",
629                 new LogSessionIdListener());
630         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
631 
632         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
633         assertThat(data).isEmpty();
634     }
635 
636     @Test
testEditingSession()637     public void testEditingSession() throws Exception {
638         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
639                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
640         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
641                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testEditingSession",
642                 new LogSessionIdListener());
643         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
644 
645         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
646         assertThat(data).isEmpty();
647     }
648 
649     @Test
testTranscodingSession()650     public void testTranscodingSession() throws Exception {
651         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
652                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
653         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
654                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testTranscodingSession",
655                 new LogSessionIdListener());
656         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
657 
658         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
659         assertThat(data).isEmpty();
660     }
661 
662     @Test
testBundleSession()663     public void testBundleSession() throws Exception {
664         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
665                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
666         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
667                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testBundleSession",
668                 new LogSessionIdListener());
669         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
670 
671         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
672         assertThat(data).isEmpty();
673     }
674 
675     @Test
testAppBlocklist()676     public void testAppBlocklist() throws Exception {
677         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
678                 AtomsProto.Atom.MEDIA_PLAYBACK_STATE_CHANGED_FIELD_NUMBER);
679         LogSessionIdListener listener = new LogSessionIdListener();
680         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
681                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testAppBlocklist",
682                 listener);
683         String logSessionId = listener.getLogSessionId();
684         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
685 
686         assertWithMessage("log session id").that(logSessionId).isNotEmpty();
687         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
688         List<AtomsProto.MediametricsPlaybackReported> playbackReportedList = toMyAtoms(data,
689                 AtomsProto.Atom::getMediametricsPlaybackReported);
690         assertThat(playbackReportedList).comparingElementsUsing(Correspondence.transforming(
691                 AtomsProto.MediametricsPlaybackReported::getLogSessionId,
692                 "getLogSessionId")).doesNotContain(logSessionId);
693     }
694 
695     @Test
testAttributionBlocklist()696     public void testAttributionBlocklist() throws Exception {
697         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
698                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
699         LogSessionIdListener listener = new LogSessionIdListener();
700         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
701                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
702                 "testAttributionBlocklist",
703                 listener);
704         String logSessionId = listener.getLogSessionId();
705         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
706 
707         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
708         assertWithMessage("log session id").that(logSessionId).isNotEmpty();
709         List<AtomsProto.MediametricsPlaybackReported> playbackReportedList = toMyAtoms(data,
710                 AtomsProto.Atom::getMediametricsPlaybackReported);
711         assertThat(playbackReportedList).comparingElementsUsing(Correspondence.transforming(
712                 AtomsProto.MediametricsPlaybackReported::getLogSessionId,
713                 "getLogSessionId")).contains(logSessionId);
714 
715         AtomsProto.MediametricsPlaybackReported result = playbackReportedList.stream().filter(
716                 a -> a.getLogSessionId().equals(logSessionId)).findFirst().orElseThrow();
717 
718         assertThat(result.getUid()).isEqualTo(0); // UID is not logged. Should be 0.
719         assertThat(result.getMediaDurationMillis()).isEqualTo(233L);
720         assertThat(result.getStreamSource().toString()).isEqualTo("STREAM_SOURCE_NETWORK");
721         assertThat(result.getStreamType().toString()).isEqualTo("STREAM_TYPE_OTHER");
722         assertThat(result.getPlaybackType().toString()).isEqualTo("PLAYBACK_TYPE_LIVE");
723         assertThat(result.getDrmType().toString()).isEqualTo("DRM_TYPE_WV_L1");
724         assertThat(result.getContentType().toString()).isEqualTo("CONTENT_TYPE_MAIN");
725         assertThat(result.getPlayerName()).isEqualTo("ExoPlayer");
726         assertThat(result.getPlayerVersion()).isEqualTo("1.01x");
727         assertThat(result.getVideoFramesPlayed()).isEqualTo(1024);
728         assertThat(result.getVideoFramesDropped()).isEqualTo(32);
729         assertThat(result.getAudioUnderrunCount()).isEqualTo(22);
730         assertThat(result.getNetworkBytesRead()).isEqualTo(102400);
731         assertThat(result.getLocalBytesRead()).isEqualTo(2000);
732         assertThat(result.getNetworkTransferDurationMillis()).isEqualTo(6000);
733     }
734 
735     @Test
testAppAllowlist()736     public void testAppAllowlist() throws Exception {
737         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
738                 AtomsProto.Atom.MEDIA_PLAYBACK_STATE_CHANGED_FIELD_NUMBER);
739         LogSessionIdListener listener = new LogSessionIdListener();
740         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
741                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testAppAllowlist",
742                 listener);
743         String logSessionId = listener.getLogSessionId();
744         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
745 
746         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
747         assertWithMessage("log session id").that(logSessionId).isNotEmpty();
748         List<AtomsProto.MediaPlaybackStateChanged> stateChangedList = toMyAtoms(data,
749                 AtomsProto.Atom::getMediaPlaybackStateChanged);
750         assertThat(stateChangedList).comparingElementsUsing(
751                 Correspondence.transforming(AtomsProto.MediaPlaybackStateChanged::getLogSessionId,
752                         "getLogSessionId")).contains(logSessionId);
753 
754         AtomsProto.MediaPlaybackStateChanged result = stateChangedList.stream().filter(
755                 a -> a.getLogSessionId().equals(logSessionId)).findFirst().orElseThrow();
756         assertThat(result.getPlaybackState().toString()).isEqualTo("JOINING_FOREGROUND");
757         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(1763L);
758     }
759 
760     @Test
testAttributionAllowlist()761     public void testAttributionAllowlist() throws Exception {
762         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
763                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
764         LogSessionIdListener listener = new LogSessionIdListener();
765         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
766                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
767                 "testAttributionAllowlist",
768                 listener);
769         String logSessionId = listener.getLogSessionId();
770         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
771 
772         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
773         assertWithMessage("log session id").that(logSessionId).isNotEmpty();
774         List<AtomsProto.MediametricsPlaybackReported> playbackReportedList = toMyAtoms(data,
775                 AtomsProto.Atom::getMediametricsPlaybackReported);
776         assertThat(playbackReportedList).comparingElementsUsing(Correspondence.transforming(
777                 AtomsProto.MediametricsPlaybackReported::getLogSessionId,
778                 "getLogSessionId")).contains(logSessionId);
779 
780         AtomsProto.MediametricsPlaybackReported result = playbackReportedList.stream().filter(
781                 a -> a.getLogSessionId().equals(logSessionId)).findFirst().orElseThrow();
782 
783         assertThat(result.getUid()).isEqualTo(0); // UID is not logged. Should be 0.
784         assertThat(result.getMediaDurationMillis()).isEqualTo(233L);
785         assertThat(result.getStreamSource().toString()).isEqualTo("STREAM_SOURCE_NETWORK");
786         assertThat(result.getStreamType().toString()).isEqualTo("STREAM_TYPE_OTHER");
787         assertThat(result.getPlaybackType().toString()).isEqualTo("PLAYBACK_TYPE_LIVE");
788         assertThat(result.getDrmType().toString()).isEqualTo("DRM_TYPE_WV_L1");
789         assertThat(result.getContentType().toString()).isEqualTo("CONTENT_TYPE_MAIN");
790         assertThat(result.getPlayerName()).isEqualTo("ExoPlayer");
791         assertThat(result.getPlayerVersion()).isEqualTo("1.01x");
792         assertThat(result.getVideoFramesPlayed()).isEqualTo(1024);
793         assertThat(result.getVideoFramesDropped()).isEqualTo(32);
794         assertThat(result.getAudioUnderrunCount()).isEqualTo(22);
795         assertThat(result.getNetworkBytesRead()).isEqualTo(102400);
796         assertThat(result.getLocalBytesRead()).isEqualTo(2000);
797         assertThat(result.getNetworkTransferDurationMillis()).isEqualTo(6000);
798     }
799 
validateAAudioStreamAtom(String direction)800     private void validateAAudioStreamAtom(String direction) throws Exception {
801         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
802 
803         assertThat(data).isNotEmpty();
804 
805         int appUid = DeviceUtils.getAppUid(getDevice(), TEST_PKG);
806 
807         for (StatsLog.EventMetricData event : data) {
808             AtomsProto.MediametricsAAudioStreamReported atom =
809                     event.getAtom().getMediametricsAaudiostreamReported();
810             assertThat(atom.getBufferCapacity()).isGreaterThan(0);
811             assertThat(atom.getBufferCapacity()).isLessThan(MAX_BUFFER_CAPACITY);
812             assertThat(atom.getBufferSize()).isGreaterThan(0);
813             assertThat(atom.getBufferSize()).isAtMost(atom.getBufferCapacity());
814             assertThat(atom.getFramesPerBurst()).isGreaterThan(0);
815             assertThat(atom.getFramesPerBurst()).isLessThan(atom.getBufferCapacity());
816             assertThat(atom.getUid()).isEqualTo(appUid);
817             assertThat(atom.getDirection().toString()).isEqualTo(direction);
818             assertThat(atom.getChannelCountHardware()).isGreaterThan(0);
819             assertThat(atom.getSampleRateHardware()).isGreaterThan(0);
820             assertThat(atom.getFormatHardware()).isNotEqualTo(0);
821             assertThat(atom.getTotalFramesTransferred()).isGreaterThan(0);
822             assertThat(atom.getXrunCount()).isEqualTo(0);
823         }
824     }
825 
runAAudioTestAndValidate(String requiredFeature, String direction, String testFunctionName)826     private void runAAudioTestAndValidate(String requiredFeature, String direction,
827             String testFunctionName) throws Exception {
828         if (!DeviceUtils.hasFeature(getDevice(), requiredFeature)) {
829             return;
830         }
831         ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG,
832                 AtomsProto.Atom.MEDIAMETRICS_AAUDIOSTREAM_REPORTED_FIELD_NUMBER);
833 
834         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
835                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", testFunctionName,
836                 new LogSessionIdListener());
837         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
838 
839         validateAAudioStreamAtom(direction);
840     }
841 
842     /**
843      * The test try to create and then close aaudio input stream with low latency via media metrics
844      * atom host side test app on the DUT.
845      * After that, the event metric data for MediametricsAAudioStreamReported is pushed to verify
846      * the data is collected correctly.
847      */
848     @Test
testAAudioLowLatencyInputStream()849     public void testAAudioLowLatencyInputStream() throws Exception {
850         runAAudioTestAndValidate(FEATURE_MICROPHONE,
851                 "DIRECTION_INPUT",
852                 "testAAudioLowLatencyInputStream");
853     }
854 
855     /**
856      * The test try to create and then close aaudio output stream with low latency via media metrics
857      * atom host side test app on the DUT.
858      * After that, the event metric data for MediametricsAAudioStreamReported is pushed to verify
859      * the data is collected correctly.
860      */
861     @Test
testAAudioLowLatencyOutputStream()862     public void testAAudioLowLatencyOutputStream() throws Exception {
863         runAAudioTestAndValidate(FEATURE_AUDIO_OUTPUT,
864                 "DIRECTION_OUTPUT",
865                 "testAAudioLowLatencyOutputStream");
866     }
867 
868     /**
869      * The test try to create and then close aaudio input stream with legacy path via media metrics
870      * atom host side test app on the DUT.
871      * After that, the event metric data for MediametricsAAudioStreamReported is pushed to verify
872      * the data is collected correctly.
873      */
874     @Test
testAAudioLegacyInputStream()875     public void testAAudioLegacyInputStream() throws Exception {
876         runAAudioTestAndValidate(FEATURE_MICROPHONE,
877                 "DIRECTION_INPUT",
878                 "testAAudioLegacyInputStream");
879     }
880 
881     /**
882      * The test try to create and then close aaudio output stream with legacy path via media metrics
883      * atom host side test app on the DUT.
884      * After that, the event metric data for MediametricsAAudioStreamReported is pushed to verify
885      * the data is collected correctly.
886      */
887     @Test
testAAudioLegacyOutputStream()888     public void testAAudioLegacyOutputStream() throws Exception {
889         runAAudioTestAndValidate(FEATURE_AUDIO_OUTPUT,
890                 "DIRECTION_OUTPUT",
891                 "testAAudioLegacyOutputStream");
892     }
893 
894     /**
895      * The test try to create and then close a midi stream via media metrics
896      * atom host side test app on the DUT.
897      * After that, the event metric data for MediametricsMidiDeviceCloseReported is pushed to verify
898      * the data is collected correctly.
899      */
900     @Test
testMidiMetrics()901     public void testMidiMetrics() throws Exception {
902         if (!DeviceUtils.hasFeature(getDevice(), FEATURE_MIDI)) {
903             return;
904         }
905         ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG,
906                 AtomsProto.Atom.MEDIAMETRICS_MIDI_DEVICE_CLOSE_REPORTED_FIELD_NUMBER);
907 
908         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
909                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testMidiMetrics",
910                 new LogSessionIdListener());
911         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
912 
913         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
914         List<AtomsProto.MediametricsMidiDeviceCloseReported> eventList = toMyAtoms(data,
915                 AtomsProto.Atom::getMediametricsMidiDeviceCloseReported);
916 
917         assertThat(eventList).isNotEmpty();
918 
919         int appUid = DeviceUtils.getAppUid(getDevice(), TEST_PKG);
920         AtomsProto.MediametricsMidiDeviceCloseReported result = eventList.get(0);
921 
922         assertThat(result.getUid()).isEqualTo(appUid);
923         assertThat(result.getMidiDeviceId()).isGreaterThan(0);
924         assertThat(result.getInputPortCount()).isEqualTo(1);
925         assertThat(result.getOutputPortCount()).isEqualTo(1);
926         assertThat(result.getDeviceType().toString()).isEqualTo("MIDI_DEVICE_INFO_TYPE_VIRTUAL");
927         assertThat(result.getIsShared()).isTrue();
928         assertThat(result.getSupportsUmp()).isFalse();
929         assertThat(result.getUsingAlsa()).isFalse();
930         assertThat(result.getDurationNs()).isGreaterThan(0);
931         assertThat(result.getOpenedCount()).isGreaterThan(0);
932         assertThat(result.getClosedCount()).isGreaterThan(0);
933         assertThat(result.getDeviceDisconnected()).isFalse();
934         assertThat(result.getTotalInputBytes()).isGreaterThan(0);
935         assertThat(result.getTotalOutputBytes()).isGreaterThan(0);
936     }
937 
toMyAtoms(List<StatsLog.EventMetricData> data, Function<AtomsProto.Atom, T> mapper)938     private static <T> List<T> toMyAtoms(List<StatsLog.EventMetricData> data,
939             Function<AtomsProto.Atom, T> mapper) {
940         return data.stream().map(StatsLog.EventMetricData::getAtom).map(mapper).collect(
941                 Collectors.toUnmodifiableList());
942     }
943 
944     private static final class LogSessionIdListener implements ITestInvocationListener {
945 
946         @Nullable
947         private String mLogSessionId;
948 
949         @Nullable
getLogSessionId()950         public String getLogSessionId() {
951             return mLogSessionId;
952         }
953 
954         @Override
testEnded(TestDescription test, long endTime, HashMap<String, MetricMeasurement.Metric> testMetrics)955         public void testEnded(TestDescription test, long endTime,
956                 HashMap<String, MetricMeasurement.Metric> testMetrics) {
957             LogUtil.CLog.i("testEnded  MetricMeasurement.Metric " + testMetrics);
958             MetricMeasurement.Metric metric = testMetrics.get(LOG_SESSION_ID_KEY);
959             mLogSessionId = metric == null ? null : metric.getMeasurements().getSingleString();
960         }
961     }
962 }