• 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.mediapc.cts.common;
18 
19 import static android.util.DisplayMetrics.DENSITY_HIGH;
20 
21 import static org.junit.Assume.assumeTrue;
22 
23 import android.app.ActivityManager;
24 import android.content.Context;
25 import android.content.pm.PackageManager;
26 import android.hardware.display.DisplayManager;
27 import android.media.MediaCodec;
28 import android.media.MediaCodecInfo;
29 import android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint;
30 import android.media.MediaFormat;
31 import android.os.Build;
32 import android.os.SystemProperties;
33 import android.util.DisplayMetrics;
34 import android.util.Log;
35 import android.view.Display;
36 
37 import androidx.test.platform.app.InstrumentationRegistry;
38 
39 import com.android.compatibility.common.util.ApiLevelUtil;
40 
41 import java.io.IOException;
42 import java.util.Arrays;
43 import java.util.Comparator;
44 import java.util.List;
45 import java.util.stream.Stream;
46 
47 /** Test utilities. */
48 public final class Utils {
49 
50     public static final int DISPLAY_DPI;
51     public static final int DISPLAY_LONG_PIXELS;
52     public static final int DISPLAY_SHORT_PIXELS;
53     public static final boolean IS_HDR;
54     public static final float HDR_DISPLAY_AVERAGE_LUMINANCE;
55     public static final long TOTAL_MEMORY_MB;
56     private static final int sPc;
57 
58     private static final String TAG = "PerformanceClassTestUtils";
59     private static final String MEDIA_PERF_CLASS_KEY = "media-performance-class";
60 
61     private static final boolean MEETS_AVC_CODEC_PRECONDITIONS;
62     static {
63         // with a default-media-performance-class that can be configured through a command line
64         // argument.
65         android.os.Bundle args;
66         try {
67             args = InstrumentationRegistry.getArguments();
68         } catch (Exception e) {
69             args = null;
70         }
71         if (args != null) {
72             String mediaPerfClassArg = args.getString(MEDIA_PERF_CLASS_KEY);
73             if (mediaPerfClassArg != null) {
Log.d(TAG, "Running the tests with performance class set to " + mediaPerfClassArg)74                 Log.d(TAG, "Running the tests with performance class set to " + mediaPerfClassArg);
75                 sPc = Integer.parseInt(mediaPerfClassArg);
76             } else {
77                 sPc = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S)
78                         ? Build.VERSION.MEDIA_PERFORMANCE_CLASS
79                         : SystemProperties.getInt("ro.odm.build.media_performance_class", 0);
80             }
Log.d(TAG, "performance class is " + sPc)81             Log.d(TAG, "performance class is " + sPc);
82         } else {
83             sPc = 0;
84         }
85 
86         Context context;
87         try {
88             context = InstrumentationRegistry.getInstrumentation().getContext();
89         } catch (Exception e) {
90             context = null;
91         }
92         // When used from ItsService, context will be null
93         if (context != null) {
94             DisplayManager displayManager = context.getSystemService(DisplayManager.class);
95             Display defaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
96             Display.Mode maxResolutionDisplayMode =
97                     Arrays.stream(displayManager.getDisplays())
98                             .map(Display::getSupportedModes)
99                             .flatMap(Stream::of)
100                             .max(Comparator.comparing(Display.Mode::getPhysicalHeight))
101                             .orElseThrow(
102                                     () -> new RuntimeException("Failed to determine max height"));
103             int maxWidthPixels = maxResolutionDisplayMode.getPhysicalWidth();
104             int maxHeightPixels = maxResolutionDisplayMode.getPhysicalHeight();
105             DISPLAY_LONG_PIXELS = Math.max(maxWidthPixels, maxHeightPixels);
106             DISPLAY_SHORT_PIXELS = Math.min(maxWidthPixels, maxHeightPixels);
107 
108             int widthPixels = defaultDisplay.getMode().getPhysicalWidth();
109             int heightPixels = defaultDisplay.getMode().getPhysicalHeight();
110 
111             DisplayMetrics metrics = context.getResources().getDisplayMetrics();
112             final double widthInch = (double) widthPixels / (double) metrics.xdpi;
113             final double heightInch = (double) heightPixels / (double) metrics.ydpi;
114             final double diagonalInch = Math.sqrt(widthInch * widthInch + heightInch * heightInch);
115             final double maxDiagonalPixels =
116                     Math.sqrt(maxWidthPixels * maxWidthPixels + maxHeightPixels * maxHeightPixels);
117             // Use max of computed dpi and advertised dpi as these values differ in some devices.
118             DISPLAY_DPI = Math.max((int) (maxDiagonalPixels / diagonalInch),
119                     context.getResources().getConfiguration().densityDpi);
120 
121             IS_HDR = defaultDisplay.isHdr();
122             HDR_DISPLAY_AVERAGE_LUMINANCE =
123                 defaultDisplay.getHdrCapabilities().getDesiredMaxAverageLuminance();
124 
125             ActivityManager activityManager = context.getSystemService(ActivityManager.class);
126             ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
127             activityManager.getMemoryInfo(memoryInfo);
128             TOTAL_MEMORY_MB = memoryInfo.totalMem / 1024 / 1024;
129         } else {
130             DISPLAY_DPI = 0;
131             DISPLAY_LONG_PIXELS = 0;
132             DISPLAY_SHORT_PIXELS = 0;
133             TOTAL_MEMORY_MB = 0;
134             IS_HDR = false;
135             HDR_DISPLAY_AVERAGE_LUMINANCE = 0;
136         }
137         MEETS_AVC_CODEC_PRECONDITIONS = meetsAvcCodecPreconditions();
138     }
139 
140     /**
141      * First defined media performance class.
142      */
143     private static final int FIRST_PERFORMANCE_CLASS = Build.VERSION_CODES.R;
144 
isRPerfClass()145     public static boolean isRPerfClass() {
146         return sPc == Build.VERSION_CODES.R;
147     }
148 
isSPerfClass()149     public static boolean isSPerfClass() {
150         return sPc == Build.VERSION_CODES.S;
151     }
152 
isTPerfClass()153     public static boolean isTPerfClass() {
154         return sPc == Build.VERSION_CODES.TIRAMISU;
155     }
156 
isBeforeTPerfClass()157     public static boolean isBeforeTPerfClass() {
158         return sPc < Build.VERSION_CODES.TIRAMISU;
159     }
160 
isUPerfClass()161     public static boolean isUPerfClass() {
162         return sPc == Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
163     }
164 
isVPerfClass()165     public static boolean isVPerfClass() {
166         return sPc == Build.VERSION_CODES.VANILLA_ICE_CREAM;
167     }
168 
169     /**
170      * Latest defined media performance class.
171      */
172     private static final int LAST_PERFORMANCE_CLASS = Build.VERSION_CODES.VANILLA_ICE_CREAM;
173 
isHandheld()174     public static boolean isHandheld() {
175         // handheld nature is not exposed to package manager, for now
176         // we check for touchscreen and NOT watch and NOT tv
177         PackageManager pm =
178                 InstrumentationRegistry.getInstrumentation().getContext().getPackageManager();
179         return pm.hasSystemFeature(pm.FEATURE_TOUCHSCREEN)
180                 && !pm.hasSystemFeature(pm.FEATURE_WATCH)
181                 && !pm.hasSystemFeature(pm.FEATURE_TELEVISION)
182                 && !pm.hasSystemFeature(pm.FEATURE_AUTOMOTIVE);
183     }
184 
meetsAvcCodecPreconditions(boolean isEncoder)185     private static boolean meetsAvcCodecPreconditions(boolean isEncoder) {
186         // Latency tests need the following instances of codecs at 30 fps
187         // 1920x1080 encoder in MediaRecorder for load conditions
188         // 1920x1080 decoder and 1920x1080 encoder for load conditions
189         // 1920x1080 encoder for initialization test
190         // Since there is no way to know if encoder and decoder are supported concurrently at their
191         // maximum load, we will test the above combined requirements are met for both encoder and
192         // decoder (so a minimum of 4 instances required for both encoder and decoder)
193         int minInstancesRequired = 4;
194         int width = 1920;
195         int height = 1080;
196         double fps = 30 /* encoder for media recorder */
197                 + 30 /* 1080p decoder for transcoder */
198                 + 30 /* 1080p encoder for transcoder */
199                 + 30 /* 1080p encoder for latency test */;
200 
201         String avcMediaType = MediaFormat.MIMETYPE_VIDEO_AVC;
202         PerformancePoint pp1080p = new PerformancePoint(width, height, (int) fps);
203         MediaCodec codec;
204         try {
205             codec = isEncoder ? MediaCodec.createEncoderByType(avcMediaType) :
206                     MediaCodec.createDecoderByType(avcMediaType);
207         } catch (IOException e) {
208             Log.d(TAG, "Unable to create codec " + e);
209             return false;
210         }
211         MediaCodecInfo info = codec.getCodecInfo();
212         MediaCodecInfo.CodecCapabilities caps = info.getCapabilitiesForType(avcMediaType);
213         List<PerformancePoint> pps =
214                 caps.getVideoCapabilities().getSupportedPerformancePoints();
215         if (pps == null || pps.size() == 0) {
216             Log.w(TAG, info.getName() + " doesn't advertise performance points. Assuming codec "
217                     + "meets the requirements");
218             codec.release();
219             return true;
220         }
221         boolean supportsRequiredRate = false;
222         for (PerformancePoint pp : pps) {
223             if (pp.covers(pp1080p)) {
224                 supportsRequiredRate = true;
225             }
226         }
227 
228         boolean supportsRequiredSize = caps.getVideoCapabilities().isSizeSupported(width, height);
229         boolean supportsRequiredInstances = caps.getMaxSupportedInstances() >= minInstancesRequired;
230         codec.release();
231         Log.d(TAG, info.getName() + " supports required FPS : " + supportsRequiredRate
232                 + ", supports required size : " + supportsRequiredSize
233                 + ", supports required instances : " + supportsRequiredInstances);
234         return supportsRequiredRate && supportsRequiredSize && supportsRequiredInstances;
235     }
236 
meetsAvcCodecPreconditions()237     private static boolean meetsAvcCodecPreconditions() {
238         return meetsAvcCodecPreconditions(/* isEncoder */ true)
239                 && meetsAvcCodecPreconditions(/* isEncoder */ false);
240     }
241 
getPerfClass()242     public static int getPerfClass() {
243         return sPc;
244     }
245 
isPerfClass()246     public static boolean isPerfClass() {
247         return sPc >= FIRST_PERFORMANCE_CLASS &&
248                sPc <= LAST_PERFORMANCE_CLASS;
249     }
250 
251     /**
252      * Does the device meet the preconditions for Media Performance Class.
253      *
254      * <p>Failing to meet these thresholds means we know that the device can't meet any performance
255      * class requirement. If the device doesn't meet these, we save time for everyone by skipping
256      * the tests that we know the device will fail.
257      *
258      * <p>The numbers here are slightly reduced from the strict thresholds so that we can gather
259      * some information about "almost performance class" devices. This won't impact CTS results, but
260      * will increase CTS runtime for those devices.
261      */
meetsPerformanceClassPreconditions()262     public static boolean meetsPerformanceClassPreconditions() {
263         if (isPerfClass()) {
264             return true;
265         }
266 
267         // If device doesn't advertise performance class, check if this can be ruled out as a
268         // candidate for performance class tests.
269         return isHandheld()
270                 // Setting the minimum memory to 2.5G so we get statistics on "Mid Tier Devices"
271                 // As of 2025 Q1 this is about 80% of daily active devices.
272                 && TOTAL_MEMORY_MB >= (long)(2.5 * 1024L)
273                 // MPC requires 400 DPI. lowering to HIGH (320) to report statistics on
274                 // "mid tier" devices
275                 // As of 2025 Q1 this is about 85% of daily active devices.
276                 && DISPLAY_DPI >= DENSITY_HIGH
277                 // MPC requires 1920. lowering to 1280 to report statistics on "mid tier" devices
278                 // As of 2025 Q1 this is about 99% of daily active devices.
279                 && DISPLAY_LONG_PIXELS >= 1280
280                 // MPC requires 1080. lowering to 720 to report statistics on "mid tier" devices
281                 // As of 2025 Q1 this is about 99% of daily active devices.
282                 && DISPLAY_SHORT_PIXELS >= 720;
283     }
284 
285     /**
286      * Throws an {@link org.junit.AssumptionViolatedException} if the device does not {@link
287      * #meetsPerformanceClassPreconditions()}
288      */
assumeDeviceMeetsPerformanceClassPreconditions()289     public static void assumeDeviceMeetsPerformanceClassPreconditions() {
290         assumeTrue(
291                 "Test skipped because the device does not meet the hardware requirements for "
292                         + "performance class.",
293                 meetsPerformanceClassPreconditions());
294     }
295 
Utils()296     private Utils() {}
297 }
298