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