• 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_400;
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.graphics.Rect;
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.Log;
34 import android.view.WindowManager;
35 import android.view.WindowMetrics;
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.List;
43 
44 /**
45  * Test utilities.
46  */
47 public class Utils {
48     private static final int sPc;
49 
50     private static final String TAG = "PerformanceClassTestUtils";
51     private static final String MEDIA_PERF_CLASS_KEY = "media-performance-class";
52 
53     public static final int DISPLAY_DPI;
54     public static final int MIN_DISPLAY_CANDIDATE_DPI = DENSITY_400;
55     public static final int DISPLAY_LONG_PIXELS;
56     public static final int MIN_DISPLAY_LONG_CANDIDATE_PIXELS = 1920;
57     public static final int DISPLAY_SHORT_PIXELS;
58     public static final int MIN_DISPLAY_SHORT_CANDIDATE_PIXELS = 1080;
59 
60     public static final long TOTAL_MEMORY_MB;
61     // Media performance requires 6 GB minimum RAM, but keeping the following to 5 GB
62     // as activityManager.getMemoryInfo() returns around 5.4 GB on a 6 GB device.
63     public static final long MIN_MEMORY_PERF_CLASS_CANDIDATE_MB = 5 * 1024;
64     // Android T Media performance requires 8 GB min RAM, so setting lower as above
65     public static final long MIN_MEMORY_PERF_CLASS_T_MB = 7 * 1024;
66 
67     private static final boolean MEETS_AVC_CODEC_PRECONDITIONS;
68     static {
69         // with a default-media-performance-class that can be configured through a command line
70         // argument.
71         android.os.Bundle args;
72         try {
73             args = InstrumentationRegistry.getArguments();
74         } catch (Exception e) {
75             args = null;
76         }
77         if (args != null) {
78             String mediaPerfClassArg = args.getString(MEDIA_PERF_CLASS_KEY);
79             if (mediaPerfClassArg != null) {
Log.d(TAG, "Running the tests with performance class set to " + mediaPerfClassArg)80                 Log.d(TAG, "Running the tests with performance class set to " + mediaPerfClassArg);
81                 sPc = Integer.parseInt(mediaPerfClassArg);
82             } else {
83                 sPc = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S)
84                         ? Build.VERSION.MEDIA_PERFORMANCE_CLASS
85                         : SystemProperties.getInt("ro.odm.build.media_performance_class", 0);
86             }
Log.d(TAG, "performance class is " + sPc)87             Log.d(TAG, "performance class is " + sPc);
88         } else {
89             sPc = 0;
90         }
91 
92         Context context;
93         try {
94             context = InstrumentationRegistry.getInstrumentation().getContext();
95         } catch (Exception e) {
96             context = null;
97         }
98         // When used from ItsService, context will be null
99         if (context != null) {
100             WindowManager windowManager = context.getSystemService(WindowManager.class);
101             WindowMetrics metrics = windowManager.getMaximumWindowMetrics();
102             Rect displayBounds = metrics.getBounds();
103             int widthPixels = displayBounds.width();
104             int heightPixels = displayBounds.height();
105             DISPLAY_DPI = context.getResources().getConfiguration().densityDpi;
106             DISPLAY_LONG_PIXELS = Math.max(widthPixels, heightPixels);
107             DISPLAY_SHORT_PIXELS = Math.min(widthPixels, heightPixels);
108 
109             ActivityManager activityManager = context.getSystemService(ActivityManager.class);
110             ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
111             activityManager.getMemoryInfo(memoryInfo);
112             TOTAL_MEMORY_MB = memoryInfo.totalMem / 1024 / 1024;
113         } else {
114             DISPLAY_DPI = 0;
115             DISPLAY_LONG_PIXELS = 0;
116             DISPLAY_SHORT_PIXELS = 0;
117             TOTAL_MEMORY_MB = 0;
118         }
119         MEETS_AVC_CODEC_PRECONDITIONS = meetsAvcCodecPreconditions();
120     }
121 
122     /**
123      * First defined media performance class.
124      */
125     private static final int FIRST_PERFORMANCE_CLASS = Build.VERSION_CODES.R;
126 
isRPerfClass()127     public static boolean isRPerfClass() {
128         return sPc == Build.VERSION_CODES.R;
129     }
130 
isSPerfClass()131     public static boolean isSPerfClass() {
132         return sPc == Build.VERSION_CODES.S;
133     }
134 
isTPerfClass()135     public static boolean isTPerfClass() {
136         return sPc == Build.VERSION_CODES.TIRAMISU;
137     }
138 
139     /**
140      * Latest defined media performance class.
141      */
142     private static final int LAST_PERFORMANCE_CLASS = Build.VERSION_CODES.TIRAMISU;
143 
isHandheld()144     public static boolean isHandheld() {
145         // handheld nature is not exposed to package manager, for now
146         // we check for touchscreen and NOT watch and NOT tv
147         PackageManager pm =
148                 InstrumentationRegistry.getInstrumentation().getContext().getPackageManager();
149         return pm.hasSystemFeature(pm.FEATURE_TOUCHSCREEN)
150                 && !pm.hasSystemFeature(pm.FEATURE_WATCH)
151                 && !pm.hasSystemFeature(pm.FEATURE_TELEVISION)
152                 && !pm.hasSystemFeature(pm.FEATURE_AUTOMOTIVE);
153     }
154 
meetsAvcCodecPreconditions(boolean isEncoder)155     private static boolean meetsAvcCodecPreconditions(boolean isEncoder) {
156         // Latency tests need the following instances of codecs at 30 fps
157         // 1920x1080 encoder in MediaRecorder for load conditions
158         // 1920x1080 decoder and 1920x1080 encoder for load conditions
159         // 1920x1080 encoder for initialization test
160         // Since there is no way to know if encoder and decoder are supported concurrently at their
161         // maximum load, we will test the above combined requirements are met for both encoder and
162         // decoder (so a minimum of 4 instances required for both encoder and decoder)
163         int minInstancesRequired = 4;
164         int width = 1920;
165         int height = 1080;
166         double fps = 30 /* encoder for media recorder */
167                 + 30 /* 1080p decoder for transcoder */
168                 + 30 /* 1080p encoder for transcoder */
169                 + 30 /* 1080p encoder for latency test */;
170 
171         String avcMediaType = MediaFormat.MIMETYPE_VIDEO_AVC;
172         PerformancePoint pp1080p = new PerformancePoint(width, height, (int) fps);
173         MediaCodec codec;
174         try {
175             codec = isEncoder ? MediaCodec.createEncoderByType(avcMediaType) :
176                     MediaCodec.createDecoderByType(avcMediaType);
177         } catch (IOException e) {
178             Log.d(TAG, "Unable to create codec " + e);
179             return false;
180         }
181         MediaCodecInfo info = codec.getCodecInfo();
182         MediaCodecInfo.CodecCapabilities caps = info.getCapabilitiesForType(avcMediaType);
183         List<PerformancePoint> pps =
184                 caps.getVideoCapabilities().getSupportedPerformancePoints();
185         if (pps == null || pps.size() == 0) {
186             Log.w(TAG, info.getName() + " doesn't advertise performance points. Assuming codec "
187                     + "meets the requirements");
188             codec.release();
189             return true;
190         }
191         boolean supportsRequiredRate = false;
192         for (PerformancePoint pp : pps) {
193             if (pp.covers(pp1080p)) {
194                 supportsRequiredRate = true;
195             }
196         }
197 
198         boolean supportsRequiredSize = caps.getVideoCapabilities().isSizeSupported(width, height);
199         boolean supportsRequiredInstances = caps.getMaxSupportedInstances() >= minInstancesRequired;
200         codec.release();
201         Log.d(TAG, info.getName() + " supports required FPS : " + supportsRequiredRate
202                 + ", supports required size : " + supportsRequiredSize
203                 + ", supports required instances : " + supportsRequiredInstances);
204         return supportsRequiredRate && supportsRequiredSize && supportsRequiredInstances;
205     }
206 
meetsAvcCodecPreconditions()207     private static boolean meetsAvcCodecPreconditions() {
208         return meetsAvcCodecPreconditions(/* isEncoder */ true)
209                 && meetsAvcCodecPreconditions(/* isEncoder */ false);
210     }
211 
getPerfClass()212     public static int getPerfClass() {
213         return sPc;
214     }
215 
isPerfClass()216     public static boolean isPerfClass() {
217         return sPc >= FIRST_PERFORMANCE_CLASS &&
218                sPc <= LAST_PERFORMANCE_CLASS;
219     }
220 
meetsPerformanceClassPreconditions()221     public static boolean meetsPerformanceClassPreconditions() {
222         if (isPerfClass()) {
223             return true;
224         }
225 
226         // If device doesn't advertise performance class, check if this can be ruled out as a
227         // candidate for performance class tests.
228         if (!isHandheld()
229                 || TOTAL_MEMORY_MB < MIN_MEMORY_PERF_CLASS_CANDIDATE_MB
230                 || DISPLAY_DPI < MIN_DISPLAY_CANDIDATE_DPI
231                 || DISPLAY_LONG_PIXELS < MIN_DISPLAY_LONG_CANDIDATE_PIXELS
232                 || DISPLAY_SHORT_PIXELS < MIN_DISPLAY_SHORT_CANDIDATE_PIXELS
233                 || !MEETS_AVC_CODEC_PRECONDITIONS) {
234             return false;
235         }
236         return true;
237     }
238 
assumeDeviceMeetsPerformanceClassPreconditions()239     public static void assumeDeviceMeetsPerformanceClassPreconditions() {
240         assumeTrue(
241                 "Test skipped because the device does not meet the hardware requirements for "
242                         + "performance class.",
243                 meetsPerformanceClassPreconditions());
244     }
245 }
246