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 }