• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.media.metrics.cts;
18 
19 import static android.media.cts.MediaMetricsTestConstants.LOG_SESSION_ID_KEY;
20 
21 import static com.google.common.truth.Truth.assertThat;
22 import static com.google.common.truth.Truth.assertWithMessage;
23 
24 import android.cts.statsdatom.lib.AtomTestUtils;
25 import android.cts.statsdatom.lib.ConfigUtils;
26 import android.cts.statsdatom.lib.DeviceUtils;
27 import android.cts.statsdatom.lib.ReportUtils;
28 
29 import com.android.os.AtomsProto;
30 import com.android.os.StatsLog;
31 import com.android.tradefed.device.DeviceNotAvailableException;
32 import com.android.tradefed.invoker.TestInformation;
33 import com.android.tradefed.log.LogUtil;
34 import com.android.tradefed.metrics.proto.MetricMeasurement;
35 import com.android.tradefed.result.ITestInvocationListener;
36 import com.android.tradefed.result.TestDescription;
37 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
38 import com.android.tradefed.testtype.junit4.AfterClassWithInfo;
39 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
40 import com.android.tradefed.testtype.junit4.BeforeClassWithInfo;
41 import com.android.tradefed.util.RunUtil;
42 
43 import com.google.common.truth.Correspondence;
44 
45 import org.junit.After;
46 import org.junit.Before;
47 import org.junit.Test;
48 import org.junit.runner.RunWith;
49 
50 import java.io.FileNotFoundException;
51 import java.util.HashMap;
52 import java.util.List;
53 import java.util.function.Function;
54 import java.util.stream.Collectors;
55 
56 import javax.annotation.Nullable;
57 
58 @RunWith(DeviceJUnit4ClassRunner.class)
59 public class MediaMetricsAtomTests extends BaseHostJUnit4Test {
60 
61     private static final String TEST_RUNNER = "androidx.test.runner.AndroidJUnitRunner";
62     private static final String TAG = "MediaMetricsAtomTests";
63     public static final String TEST_APK = "CtsMediaMetricsHostTestApp.apk";
64     public static final String TEST_PKG = "android.media.metrics.cts";
65     private static final String FEATURE_AUDIO_OUTPUT = "android.hardware.audio.output";
66     private static final String FEATURE_MICROPHONE = "android.hardware.microphone";
67     private static final String FEATURE_MIDI = "android.software.midi";
68     private static final int MAX_BUFFER_CAPACITY = 30 * 1024 * 1024; // 30M
69 
70     @BeforeClassWithInfo
installApp(TestInformation testInfo)71     public static void installApp(TestInformation testInfo)
72             throws DeviceNotAvailableException, FileNotFoundException {
73         assertThat(testInfo.getBuildInfo()).isNotNull();
74         DeviceUtils.installTestApp(testInfo.getDevice(), TEST_APK, TEST_PKG,
75                 testInfo.getBuildInfo());
76     }
77 
78     @Before
setUp()79     public void setUp() throws Exception {
80         ConfigUtils.removeConfig(getDevice());
81         ReportUtils.clearReports(getDevice());
82         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
83     }
84 
85     @After
tearDown()86     public void tearDown() throws Exception {
87         ConfigUtils.removeConfig(getDevice());
88         ReportUtils.clearReports(getDevice());
89     }
90 
91     @AfterClassWithInfo
uninstallApp(TestInformation testInfo)92     public static void uninstallApp(TestInformation testInfo) throws Exception {
93         DeviceUtils.uninstallTestApp(testInfo.getDevice(), TEST_PKG);
94     }
95 
96     @Test
testPlaybackStateEvent_default()97     public void testPlaybackStateEvent_default() throws Exception {
98         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
99                 AtomsProto.Atom.MEDIA_PLAYBACK_STATE_CHANGED_FIELD_NUMBER);
100         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
101                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
102                 "testPlaybackStateEvent_default",
103                 new LogSessionIdListener());
104         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
105 
106         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
107 
108         assertThat(data.size()).isEqualTo(1);
109         assertThat(data.get(0).getAtom().hasMediaPlaybackStateChanged()).isTrue();
110         AtomsProto.MediaPlaybackStateChanged result = data.get(
111                 0).getAtom().getMediaPlaybackStateChanged();
112         assertThat(result.getPlaybackState().toString()).isEqualTo("NOT_STARTED");
113         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(-1L);
114     }
115 
116     @Test
testPlaybackStateEvent()117     public void testPlaybackStateEvent() throws Exception {
118         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
119                 AtomsProto.Atom.MEDIA_PLAYBACK_STATE_CHANGED_FIELD_NUMBER);
120         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
121                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testPlaybackStateEvent",
122                 new LogSessionIdListener());
123         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
124 
125         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
126 
127         assertThat(data.size()).isEqualTo(1);
128         assertThat(data.get(0).getAtom().hasMediaPlaybackStateChanged()).isTrue();
129         AtomsProto.MediaPlaybackStateChanged result = data.get(
130                 0).getAtom().getMediaPlaybackStateChanged();
131         assertThat(result.getPlaybackState().toString()).isEqualTo("JOINING_FOREGROUND");
132         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(1763L);
133     }
134 
135     // same as testPlaybackStateEvent, but we use the BundleSession transport.
136     @Test
testBundleSessionPlaybackStateEvent()137     public void testBundleSessionPlaybackStateEvent() throws Exception {
138         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
139                 AtomsProto.Atom.MEDIA_PLAYBACK_STATE_CHANGED_FIELD_NUMBER);
140         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
141                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
142                 "testBundleSessionPlaybackStateEvent",
143                 new LogSessionIdListener());
144         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
145 
146         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
147 
148         assertThat(data.size()).isEqualTo(1);
149         assertThat(data.get(0).getAtom().hasMediaPlaybackStateChanged()).isTrue();
150         AtomsProto.MediaPlaybackStateChanged result = data.get(
151                 0).getAtom().getMediaPlaybackStateChanged();
152         assertThat(result.getPlaybackState().toString()).isEqualTo("JOINING_FOREGROUND");
153         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(1763L);
154     }
155 
156     @Test
testPlaybackErrorEvent_default()157     public void testPlaybackErrorEvent_default() throws Exception {
158         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
159                 AtomsProto.Atom.MEDIA_PLAYBACK_ERROR_REPORTED_FIELD_NUMBER);
160         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
161                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
162                 "testPlaybackErrorEvent_default",
163                 new LogSessionIdListener());
164         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
165 
166         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
167 
168         assertThat(data.size()).isEqualTo(1);
169         assertThat(data.get(0).getAtom().hasMediaPlaybackErrorReported()).isTrue();
170         AtomsProto.MediaPlaybackErrorReported result = data.get(
171                 0).getAtom().getMediaPlaybackErrorReported();
172 
173         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(-1L);
174         assertThat(result.getErrorCode().toString()).isEqualTo("ERROR_CODE_UNKNOWN");
175         assertThat(result.getSubErrorCode()).isEqualTo(0);
176         assertThat(result.getExceptionStack().startsWith(
177                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests"
178                         + ".testPlaybackErrorEvent")).isTrue();
179     }
180 
181     @Test
testPlaybackErrorEvent()182     public void testPlaybackErrorEvent() throws Exception {
183         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
184                 AtomsProto.Atom.MEDIA_PLAYBACK_ERROR_REPORTED_FIELD_NUMBER);
185         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
186                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testPlaybackErrorEvent",
187                 new LogSessionIdListener());
188         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
189 
190         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
191 
192         assertThat(data.size()).isEqualTo(1);
193         assertThat(data.get(0).getAtom().hasMediaPlaybackErrorReported()).isTrue();
194         AtomsProto.MediaPlaybackErrorReported result = data.get(
195                 0).getAtom().getMediaPlaybackErrorReported();
196 
197         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(17630000L);
198         assertThat(result.getErrorCode().toString()).isEqualTo("ERROR_CODE_RUNTIME");
199         assertThat(result.getSubErrorCode()).isEqualTo(378);
200         assertThat(result.getExceptionStack().startsWith(
201                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests"
202                         + ".testPlaybackErrorEvent")).isTrue();
203     }
204 
205     @Test
testTrackChangeEvent_default()206     public void testTrackChangeEvent_default() throws Exception {
207         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
208                 AtomsProto.Atom.MEDIA_PLAYBACK_TRACK_CHANGED_FIELD_NUMBER);
209         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
210                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
211                 "testTrackChangeEvent_default",
212                 new LogSessionIdListener());
213         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
214 
215         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
216 
217         assertThat(data.size()).isEqualTo(1);
218         assertThat(data.get(0).getAtom().hasMediaPlaybackTrackChanged()).isTrue();
219         AtomsProto.MediaPlaybackTrackChanged result = data.get(
220                 0).getAtom().getMediaPlaybackTrackChanged();
221 
222         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(-1L);
223         assertThat(result.getState().toString()).isEqualTo("OFF");
224         assertThat(result.getReason().toString()).isEqualTo("REASON_UNKNOWN");
225         assertThat(result.getContainerMimeType()).isEqualTo("");
226         assertThat(result.getSampleMimeType()).isEqualTo("");
227         assertThat(result.getCodecName()).isEqualTo("");
228         assertThat(result.getBitrate()).isEqualTo(-1);
229         assertThat(result.getType().toString()).isEqualTo("AUDIO");
230         assertThat(result.getLanguage()).isEqualTo("");
231         assertThat(result.getLanguageRegion()).isEqualTo("");
232         assertThat(result.getSampleRate()).isEqualTo(-1);
233         assertThat(result.getChannelCount()).isEqualTo(-1);
234     }
235 
236     @Test
testTrackChangeEvent_text()237     public void testTrackChangeEvent_text() throws Exception {
238         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
239                 AtomsProto.Atom.MEDIA_PLAYBACK_TRACK_CHANGED_FIELD_NUMBER);
240         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
241                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
242                 "testTrackChangeEvent_text",
243                 new LogSessionIdListener());
244         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
245 
246         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
247 
248         assertThat(data.size()).isEqualTo(1);
249         assertThat(data.get(0).getAtom().hasMediaPlaybackTrackChanged()).isTrue();
250         AtomsProto.MediaPlaybackTrackChanged result = data.get(
251                 0).getAtom().getMediaPlaybackTrackChanged();
252 
253         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(37278L);
254         assertThat(result.getState().toString()).isEqualTo("ON");
255         assertThat(result.getReason().toString()).isEqualTo("REASON_MANUAL");
256         assertThat(result.getContainerMimeType()).isEqualTo("text/foo");
257         assertThat(result.getSampleMimeType()).isEqualTo("text/plain");
258         assertThat(result.getCodecName()).isEqualTo("codec_1");
259         assertThat(result.getBitrate()).isEqualTo(1024);
260         assertThat(result.getType().toString()).isEqualTo("TEXT");
261         assertThat(result.getLanguage()).isEqualTo("EN");
262         assertThat(result.getLanguageRegion()).isEqualTo("US");
263     }
264 
265     @Test
testTrackChangeEvent_audio()266     public void testTrackChangeEvent_audio() throws Exception {
267         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
268                 AtomsProto.Atom.MEDIA_PLAYBACK_TRACK_CHANGED_FIELD_NUMBER);
269         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
270                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
271                 "testTrackChangeEvent_audio",
272                 new LogSessionIdListener());
273         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
274 
275         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
276 
277         assertThat(data.size()).isEqualTo(1);
278         assertThat(data.get(0).getAtom().hasMediaPlaybackTrackChanged()).isTrue();
279         AtomsProto.MediaPlaybackTrackChanged result = data.get(
280                 0).getAtom().getMediaPlaybackTrackChanged();
281 
282         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(37278L);
283         assertThat(result.getState().toString()).isEqualTo("OFF");
284         assertThat(result.getReason().toString()).isEqualTo("REASON_INITIAL");
285         assertThat(result.getContainerMimeType()).isEqualTo("audio/foo");
286         assertThat(result.getSampleMimeType()).isEqualTo("audio/avc");
287         assertThat(result.getCodecName()).isEqualTo("codec_2");
288         assertThat(result.getBitrate()).isEqualTo(1025);
289         assertThat(result.getType().toString()).isEqualTo("AUDIO");
290         assertThat(result.getLanguage()).isEqualTo("EN");
291         assertThat(result.getLanguageRegion()).isEqualTo("US");
292         assertThat(result.getSampleRate()).isEqualTo(89);
293         assertThat(result.getChannelCount()).isEqualTo(3);
294     }
295 
296     @Test
testTrackChangeEvent_video()297     public void testTrackChangeEvent_video() throws Exception {
298         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
299                 AtomsProto.Atom.MEDIA_PLAYBACK_TRACK_CHANGED_FIELD_NUMBER);
300         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
301                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
302                 "testTrackChangeEvent_video",
303                 new LogSessionIdListener());
304         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
305 
306         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
307 
308         assertThat(data.size()).isEqualTo(1);
309         assertThat(data.get(0).getAtom().hasMediaPlaybackTrackChanged()).isTrue();
310         AtomsProto.MediaPlaybackTrackChanged result = data.get(
311                 0).getAtom().getMediaPlaybackTrackChanged();
312 
313         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(37278L);
314         assertThat(result.getState().toString()).isEqualTo("OFF");
315         assertThat(result.getReason().toString()).isEqualTo("REASON_INITIAL");
316         assertThat(result.getContainerMimeType()).isEqualTo("video/foo");
317         assertThat(result.getSampleMimeType()).isEqualTo("video/mpeg");
318         assertThat(result.getCodecName()).isEqualTo("codec_3");
319         assertThat(result.getBitrate()).isEqualTo(1025);
320         assertThat(result.getType().toString()).isEqualTo("VIDEO");
321         assertThat(result.getLanguage()).isEqualTo("EN");
322         assertThat(result.getLanguageRegion()).isEqualTo("US");
323         assertThat(result.getHeight()).isEqualTo(1080);
324         assertThat(result.getWidth()).isEqualTo(1440);
325         assertThat(result.getVideoFrameRate()).isEqualTo(60);
326     }
327 
328     @Test
testNetworkEvent_default()329     public void testNetworkEvent_default() throws Exception {
330         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
331                 AtomsProto.Atom.MEDIA_NETWORK_INFO_CHANGED_FIELD_NUMBER);
332         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
333                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
334                 "testNetworkEvent_default",
335                 new LogSessionIdListener());
336         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
337 
338         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
339 
340         assertThat(data.size()).isEqualTo(1);
341         assertThat(data.get(0).getAtom().hasMediaNetworkInfoChanged()).isTrue();
342         AtomsProto.MediaNetworkInfoChanged result = data.get(
343                 0).getAtom().getMediaNetworkInfoChanged();
344 
345         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(-1L);
346         assertThat(result.getType().toString()).isEqualTo("NETWORK_TYPE_UNKNOWN");
347     }
348 
349     @Test
testNetworkEvent()350     public void testNetworkEvent() throws Exception {
351         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
352                 AtomsProto.Atom.MEDIA_NETWORK_INFO_CHANGED_FIELD_NUMBER);
353         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
354                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testNetworkEvent",
355                 new LogSessionIdListener());
356         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
357 
358         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
359 
360         assertThat(data.size()).isEqualTo(1);
361         assertThat(data.get(0).getAtom().hasMediaNetworkInfoChanged()).isTrue();
362         AtomsProto.MediaNetworkInfoChanged result = data.get(
363                 0).getAtom().getMediaNetworkInfoChanged();
364 
365         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(3032L);
366         assertThat(result.getType().toString()).isEqualTo("NETWORK_TYPE_WIFI");
367     }
368 
369     @Test
testPlaybackMetrics_default()370     public void testPlaybackMetrics_default() throws Exception {
371         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
372                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
373         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
374                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
375                 "testPlaybackMetrics_default",
376                 new LogSessionIdListener());
377         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
378 
379         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
380         int appUid = DeviceUtils.getAppUid(getDevice(), TEST_PKG);
381 
382         assertThat(data.size()).isEqualTo(1);
383         assertThat(data.get(0).getAtom().hasMediametricsPlaybackReported()).isTrue();
384         AtomsProto.MediametricsPlaybackReported result = data.get(
385                 0).getAtom().getMediametricsPlaybackReported();
386 
387         assertThat(result.getUid()).isEqualTo(appUid);
388         assertThat(result.getMediaDurationMillis()).isEqualTo(-1L);
389         assertThat(result.getStreamSource().toString()).isEqualTo("STREAM_SOURCE_UNKNOWN");
390         assertThat(result.getStreamType().toString()).isEqualTo("STREAM_TYPE_UNKNOWN");
391         assertThat(result.getPlaybackType().toString()).isEqualTo("PLAYBACK_TYPE_UNKNOWN");
392         assertThat(result.getDrmType().toString()).isEqualTo("DRM_TYPE_NONE");
393         assertThat(result.getContentType().toString()).isEqualTo("CONTENT_TYPE_UNKNOWN");
394         assertThat(result.getPlayerName()).isEqualTo("");
395         assertThat(result.getPlayerVersion()).isEqualTo("");
396         assertThat(result.getVideoFramesPlayed()).isEqualTo(-1);
397         assertThat(result.getVideoFramesDropped()).isEqualTo(-1);
398         assertThat(result.getAudioUnderrunCount()).isEqualTo(-1);
399         assertThat(result.getNetworkBytesRead()).isEqualTo(-1);
400         assertThat(result.getLocalBytesRead()).isEqualTo(-1);
401         assertThat(result.getNetworkTransferDurationMillis()).isEqualTo(-1);
402         assertThat(result.getExperimentIds().getExperimentsList().size()).isEqualTo(0);
403         assertThat(result.getDrmSessionId().length()).isEqualTo(0);
404     }
405 
406     @Test
testPlaybackMetrics()407     public void testPlaybackMetrics() throws Exception {
408         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
409                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
410         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
411                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testPlaybackMetrics",
412                 new LogSessionIdListener());
413         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
414 
415         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
416         int appUid = DeviceUtils.getAppUid(getDevice(), TEST_PKG);
417 
418         assertThat(data.size()).isEqualTo(1);
419         assertThat(data.get(0).getAtom().hasMediametricsPlaybackReported()).isTrue();
420         AtomsProto.MediametricsPlaybackReported result = data.get(
421                 0).getAtom().getMediametricsPlaybackReported();
422 
423         assertThat(result.getUid()).isEqualTo(appUid);
424         assertThat(result.getMediaDurationMillis()).isEqualTo(233L);
425         assertThat(result.getStreamSource().toString()).isEqualTo("STREAM_SOURCE_NETWORK");
426         assertThat(result.getStreamType().toString()).isEqualTo("STREAM_TYPE_OTHER");
427         assertThat(result.getPlaybackType().toString()).isEqualTo("PLAYBACK_TYPE_LIVE");
428         assertThat(result.getDrmType().toString()).isEqualTo("DRM_TYPE_WV_L1");
429         assertThat(result.getContentType().toString()).isEqualTo("CONTENT_TYPE_MAIN");
430         assertThat(result.getPlayerName()).isEqualTo("ExoPlayer");
431         assertThat(result.getPlayerVersion()).isEqualTo("1.01x");
432         assertThat(result.getVideoFramesPlayed()).isEqualTo(1024);
433         assertThat(result.getVideoFramesDropped()).isEqualTo(32);
434         assertThat(result.getAudioUnderrunCount()).isEqualTo(22);
435         assertThat(result.getNetworkBytesRead()).isEqualTo(102400);
436         assertThat(result.getLocalBytesRead()).isEqualTo(2000);
437         assertThat(result.getNetworkTransferDurationMillis()).isEqualTo(6000);
438         // TODO: fix missing experiment ID impl
439         assertThat(result.getExperimentIds()).isNotEqualTo(null);
440         // TODO: needs Base64 decoders to verify the data
441         assertThat(result.getDrmSessionId()).isNotEqualTo(null);
442     }
443 
444     @Test
testSessionId()445     public void testSessionId() throws Exception {
446         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
447                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
448         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
449                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testSessionId",
450                 new LogSessionIdListener());
451         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
452 
453         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
454         assertThat(data).isEmpty();
455     }
456 
457     @Test
testRecordingSession()458     public void testRecordingSession() throws Exception {
459         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
460                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
461         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
462                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testRecordingSession",
463                 new LogSessionIdListener());
464         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
465 
466         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
467         assertThat(data).isEmpty();
468     }
469 
470     @Test
testEditingSession()471     public void testEditingSession() throws Exception {
472         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
473                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
474         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
475                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testEditingSession",
476                 new LogSessionIdListener());
477         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
478 
479         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
480         assertThat(data).isEmpty();
481     }
482 
483     @Test
testTranscodingSession()484     public void testTranscodingSession() throws Exception {
485         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
486                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
487         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
488                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testTranscodingSession",
489                 new LogSessionIdListener());
490         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
491 
492         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
493         assertThat(data).isEmpty();
494     }
495 
496     @Test
testBundleSession()497     public void testBundleSession() throws Exception {
498         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
499                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
500         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
501                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testBundleSession",
502                 new LogSessionIdListener());
503         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
504 
505         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
506         assertThat(data).isEmpty();
507     }
508 
509     @Test
testAppBlocklist()510     public void testAppBlocklist() throws Exception {
511         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
512                 AtomsProto.Atom.MEDIA_PLAYBACK_STATE_CHANGED_FIELD_NUMBER);
513         LogSessionIdListener listener = new LogSessionIdListener();
514         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
515                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testAppBlocklist",
516                 listener);
517         String logSessionId = listener.getLogSessionId();
518         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
519 
520         assertWithMessage("log session id").that(logSessionId).isNotEmpty();
521         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
522         List<AtomsProto.MediametricsPlaybackReported> playbackReportedList = toMyAtoms(data,
523                 AtomsProto.Atom::getMediametricsPlaybackReported);
524         assertThat(playbackReportedList).comparingElementsUsing(Correspondence.transforming(
525                 AtomsProto.MediametricsPlaybackReported::getLogSessionId,
526                 "getLogSessionId")).doesNotContain(logSessionId);
527     }
528 
529     @Test
testAttributionBlocklist()530     public void testAttributionBlocklist() throws Exception {
531         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
532                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
533         LogSessionIdListener listener = new LogSessionIdListener();
534         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
535                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
536                 "testAttributionBlocklist",
537                 listener);
538         String logSessionId = listener.getLogSessionId();
539         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
540 
541         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
542         assertWithMessage("log session id").that(logSessionId).isNotEmpty();
543         List<AtomsProto.MediametricsPlaybackReported> playbackReportedList = toMyAtoms(data,
544                 AtomsProto.Atom::getMediametricsPlaybackReported);
545         assertThat(playbackReportedList).comparingElementsUsing(Correspondence.transforming(
546                 AtomsProto.MediametricsPlaybackReported::getLogSessionId,
547                 "getLogSessionId")).contains(logSessionId);
548 
549         AtomsProto.MediametricsPlaybackReported result = playbackReportedList.stream().filter(
550                 a -> a.getLogSessionId().equals(logSessionId)).findFirst().orElseThrow();
551 
552         assertThat(result.getUid()).isEqualTo(0); // UID is not logged. Should be 0.
553         assertThat(result.getMediaDurationMillis()).isEqualTo(233L);
554         assertThat(result.getStreamSource().toString()).isEqualTo("STREAM_SOURCE_NETWORK");
555         assertThat(result.getStreamType().toString()).isEqualTo("STREAM_TYPE_OTHER");
556         assertThat(result.getPlaybackType().toString()).isEqualTo("PLAYBACK_TYPE_LIVE");
557         assertThat(result.getDrmType().toString()).isEqualTo("DRM_TYPE_WV_L1");
558         assertThat(result.getContentType().toString()).isEqualTo("CONTENT_TYPE_MAIN");
559         assertThat(result.getPlayerName()).isEqualTo("ExoPlayer");
560         assertThat(result.getPlayerVersion()).isEqualTo("1.01x");
561         assertThat(result.getVideoFramesPlayed()).isEqualTo(1024);
562         assertThat(result.getVideoFramesDropped()).isEqualTo(32);
563         assertThat(result.getAudioUnderrunCount()).isEqualTo(22);
564         assertThat(result.getNetworkBytesRead()).isEqualTo(102400);
565         assertThat(result.getLocalBytesRead()).isEqualTo(2000);
566         assertThat(result.getNetworkTransferDurationMillis()).isEqualTo(6000);
567     }
568 
569     @Test
testAppAllowlist()570     public void testAppAllowlist() throws Exception {
571         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
572                 AtomsProto.Atom.MEDIA_PLAYBACK_STATE_CHANGED_FIELD_NUMBER);
573         LogSessionIdListener listener = new LogSessionIdListener();
574         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
575                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testAppAllowlist",
576                 listener);
577         String logSessionId = listener.getLogSessionId();
578         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
579 
580         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
581         assertWithMessage("log session id").that(logSessionId).isNotEmpty();
582         List<AtomsProto.MediaPlaybackStateChanged> stateChangedList = toMyAtoms(data,
583                 AtomsProto.Atom::getMediaPlaybackStateChanged);
584         assertThat(stateChangedList).comparingElementsUsing(
585                 Correspondence.transforming(AtomsProto.MediaPlaybackStateChanged::getLogSessionId,
586                         "getLogSessionId")).contains(logSessionId);
587 
588         AtomsProto.MediaPlaybackStateChanged result = stateChangedList.stream().filter(
589                 a -> a.getLogSessionId().equals(logSessionId)).findFirst().orElseThrow();
590         assertThat(result.getPlaybackState().toString()).isEqualTo("JOINING_FOREGROUND");
591         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(1763L);
592     }
593 
594     @Test
testAttributionAllowlist()595     public void testAttributionAllowlist() throws Exception {
596         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
597                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
598         LogSessionIdListener listener = new LogSessionIdListener();
599         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
600                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
601                 "testAttributionAllowlist",
602                 listener);
603         String logSessionId = listener.getLogSessionId();
604         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
605 
606         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
607         assertWithMessage("log session id").that(logSessionId).isNotEmpty();
608         List<AtomsProto.MediametricsPlaybackReported> playbackReportedList = toMyAtoms(data,
609                 AtomsProto.Atom::getMediametricsPlaybackReported);
610         assertThat(playbackReportedList).comparingElementsUsing(Correspondence.transforming(
611                 AtomsProto.MediametricsPlaybackReported::getLogSessionId,
612                 "getLogSessionId")).contains(logSessionId);
613 
614         AtomsProto.MediametricsPlaybackReported result = playbackReportedList.stream().filter(
615                 a -> a.getLogSessionId().equals(logSessionId)).findFirst().orElseThrow();
616 
617         assertThat(result.getUid()).isEqualTo(0); // UID is not logged. Should be 0.
618         assertThat(result.getMediaDurationMillis()).isEqualTo(233L);
619         assertThat(result.getStreamSource().toString()).isEqualTo("STREAM_SOURCE_NETWORK");
620         assertThat(result.getStreamType().toString()).isEqualTo("STREAM_TYPE_OTHER");
621         assertThat(result.getPlaybackType().toString()).isEqualTo("PLAYBACK_TYPE_LIVE");
622         assertThat(result.getDrmType().toString()).isEqualTo("DRM_TYPE_WV_L1");
623         assertThat(result.getContentType().toString()).isEqualTo("CONTENT_TYPE_MAIN");
624         assertThat(result.getPlayerName()).isEqualTo("ExoPlayer");
625         assertThat(result.getPlayerVersion()).isEqualTo("1.01x");
626         assertThat(result.getVideoFramesPlayed()).isEqualTo(1024);
627         assertThat(result.getVideoFramesDropped()).isEqualTo(32);
628         assertThat(result.getAudioUnderrunCount()).isEqualTo(22);
629         assertThat(result.getNetworkBytesRead()).isEqualTo(102400);
630         assertThat(result.getLocalBytesRead()).isEqualTo(2000);
631         assertThat(result.getNetworkTransferDurationMillis()).isEqualTo(6000);
632     }
633 
validateAAudioStreamAtom(String direction)634     private void validateAAudioStreamAtom(String direction) throws Exception {
635         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
636 
637         assertThat(data).isNotEmpty();
638 
639         int appUid = DeviceUtils.getAppUid(getDevice(), TEST_PKG);
640 
641         for (StatsLog.EventMetricData event : data) {
642             AtomsProto.MediametricsAAudioStreamReported atom =
643                     event.getAtom().getMediametricsAaudiostreamReported();
644             assertThat(atom.getBufferCapacity()).isGreaterThan(0);
645             assertThat(atom.getBufferCapacity()).isLessThan(MAX_BUFFER_CAPACITY);
646             assertThat(atom.getBufferSize()).isGreaterThan(0);
647             assertThat(atom.getBufferSize()).isAtMost(atom.getBufferCapacity());
648             assertThat(atom.getFramesPerBurst()).isGreaterThan(0);
649             assertThat(atom.getFramesPerBurst()).isLessThan(atom.getBufferCapacity());
650             assertThat(atom.getUid()).isEqualTo(appUid);
651             assertThat(atom.getDirection().toString()).isEqualTo(direction);
652             assertThat(atom.getChannelCountHardware()).isGreaterThan(0);
653             assertThat(atom.getSampleRateHardware()).isGreaterThan(0);
654             assertThat(atom.getFormatHardware()).isNotEqualTo(0);
655             assertThat(atom.getTotalFramesTransferred()).isGreaterThan(0);
656             assertThat(atom.getXrunCount()).isEqualTo(0);
657         }
658     }
659 
runAAudioTestAndValidate(String requiredFeature, String direction, String testFunctionName)660     private void runAAudioTestAndValidate(String requiredFeature, String direction,
661             String testFunctionName) throws Exception {
662         if (!DeviceUtils.hasFeature(getDevice(), requiredFeature)) {
663             return;
664         }
665         ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG,
666                 AtomsProto.Atom.MEDIAMETRICS_AAUDIOSTREAM_REPORTED_FIELD_NUMBER);
667 
668         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
669                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", testFunctionName,
670                 new LogSessionIdListener());
671         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
672 
673         validateAAudioStreamAtom(direction);
674     }
675 
676     /**
677      * The test try to create and then close aaudio input stream with low latency via media metrics
678      * atom host side test app on the DUT.
679      * After that, the event metric data for MediametricsAAudioStreamReported is pushed to verify
680      * the data is collected correctly.
681      */
682     @Test
testAAudioLowLatencyInputStream()683     public void testAAudioLowLatencyInputStream() throws Exception {
684         runAAudioTestAndValidate(FEATURE_MICROPHONE,
685                 "DIRECTION_INPUT",
686                 "testAAudioLowLatencyInputStream");
687     }
688 
689     /**
690      * The test try to create and then close aaudio output stream with low latency via media metrics
691      * atom host side test app on the DUT.
692      * After that, the event metric data for MediametricsAAudioStreamReported is pushed to verify
693      * the data is collected correctly.
694      */
695     @Test
testAAudioLowLatencyOutputStream()696     public void testAAudioLowLatencyOutputStream() throws Exception {
697         runAAudioTestAndValidate(FEATURE_AUDIO_OUTPUT,
698                 "DIRECTION_OUTPUT",
699                 "testAAudioLowLatencyOutputStream");
700     }
701 
702     /**
703      * The test try to create and then close aaudio input stream with legacy path via media metrics
704      * atom host side test app on the DUT.
705      * After that, the event metric data for MediametricsAAudioStreamReported is pushed to verify
706      * the data is collected correctly.
707      */
708     @Test
testAAudioLegacyInputStream()709     public void testAAudioLegacyInputStream() throws Exception {
710         runAAudioTestAndValidate(FEATURE_MICROPHONE,
711                 "DIRECTION_INPUT",
712                 "testAAudioLegacyInputStream");
713     }
714 
715     /**
716      * The test try to create and then close aaudio output stream with legacy path via media metrics
717      * atom host side test app on the DUT.
718      * After that, the event metric data for MediametricsAAudioStreamReported is pushed to verify
719      * the data is collected correctly.
720      */
721     @Test
testAAudioLegacyOutputStream()722     public void testAAudioLegacyOutputStream() throws Exception {
723         runAAudioTestAndValidate(FEATURE_AUDIO_OUTPUT,
724                 "DIRECTION_OUTPUT",
725                 "testAAudioLegacyOutputStream");
726     }
727 
728     /**
729      * The test try to create and then close a midi stream via media metrics
730      * atom host side test app on the DUT.
731      * After that, the event metric data for MediametricsMidiDeviceCloseReported is pushed to verify
732      * the data is collected correctly.
733      */
734     @Test
testMidiMetrics()735     public void testMidiMetrics() throws Exception {
736         if (!DeviceUtils.hasFeature(getDevice(), FEATURE_MIDI)) {
737             return;
738         }
739         ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG,
740                 AtomsProto.Atom.MEDIAMETRICS_MIDI_DEVICE_CLOSE_REPORTED_FIELD_NUMBER);
741 
742         DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
743                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testMidiMetrics",
744                 new LogSessionIdListener());
745         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
746 
747         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
748         List<AtomsProto.MediametricsMidiDeviceCloseReported> eventList = toMyAtoms(data,
749                 AtomsProto.Atom::getMediametricsMidiDeviceCloseReported);
750 
751         assertThat(eventList).isNotEmpty();
752 
753         int appUid = DeviceUtils.getAppUid(getDevice(), TEST_PKG);
754         AtomsProto.MediametricsMidiDeviceCloseReported result = eventList.get(0);
755 
756         assertThat(result.getUid()).isEqualTo(appUid);
757         assertThat(result.getMidiDeviceId()).isGreaterThan(0);
758         assertThat(result.getInputPortCount()).isEqualTo(1);
759         assertThat(result.getOutputPortCount()).isEqualTo(1);
760         assertThat(result.getDeviceType().toString()).isEqualTo("MIDI_DEVICE_INFO_TYPE_VIRTUAL");
761         assertThat(result.getIsShared()).isTrue();
762         assertThat(result.getSupportsUmp()).isFalse();
763         assertThat(result.getUsingAlsa()).isFalse();
764         assertThat(result.getDurationNs()).isGreaterThan(0);
765         assertThat(result.getOpenedCount()).isGreaterThan(0);
766         assertThat(result.getClosedCount()).isGreaterThan(0);
767         assertThat(result.getDeviceDisconnected()).isFalse();
768         assertThat(result.getTotalInputBytes()).isGreaterThan(0);
769         assertThat(result.getTotalOutputBytes()).isGreaterThan(0);
770     }
771 
toMyAtoms(List<StatsLog.EventMetricData> data, Function<AtomsProto.Atom, T> mapper)772     private static <T> List<T> toMyAtoms(List<StatsLog.EventMetricData> data,
773             Function<AtomsProto.Atom, T> mapper) {
774         return data.stream().map(StatsLog.EventMetricData::getAtom).map(mapper).collect(
775                 Collectors.toUnmodifiableList());
776     }
777 
778     private static final class LogSessionIdListener implements ITestInvocationListener {
779 
780         @Nullable
781         private String mLogSessionId;
782 
783         @Nullable
getLogSessionId()784         public String getLogSessionId() {
785             return mLogSessionId;
786         }
787 
788         @Override
testEnded(TestDescription test, long endTime, HashMap<String, MetricMeasurement.Metric> testMetrics)789         public void testEnded(TestDescription test, long endTime,
790                 HashMap<String, MetricMeasurement.Metric> testMetrics) {
791             LogUtil.CLog.i("testEnded  MetricMeasurement.Metric " + testMetrics);
792             MetricMeasurement.Metric metric = testMetrics.get(LOG_SESSION_ID_KEY);
793             mLogSessionId = metric == null ? null : metric.getMeasurements().getSingleString();
794         }
795     }
796 }