1 /* 2 * Copyright (C) 2013 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.hardware.cts; 18 19 import static android.content.res.Configuration.SCREENLAYOUT_SIZE_LARGE; 20 import static android.content.res.Configuration.SCREENLAYOUT_SIZE_NORMAL; 21 import static android.content.res.Configuration.SCREENLAYOUT_SIZE_SMALL; 22 import static android.content.res.Configuration.SCREENLAYOUT_SIZE_XLARGE; 23 import static android.util.DisplayMetrics.DENSITY_400; 24 import static android.util.DisplayMetrics.DENSITY_560; 25 import static android.util.DisplayMetrics.DENSITY_HIGH; 26 import static android.util.DisplayMetrics.DENSITY_LOW; 27 import static android.util.DisplayMetrics.DENSITY_MEDIUM; 28 import static android.util.DisplayMetrics.DENSITY_TV; 29 import static android.util.DisplayMetrics.DENSITY_XHIGH; 30 31 import static org.junit.Assert.assertFalse; 32 import static org.junit.Assert.assertTrue; 33 34 import android.app.ActivityManager; 35 import android.content.Context; 36 import android.content.pm.PackageManager; 37 import android.content.res.Configuration; 38 import android.os.Build; 39 import android.os.StatFs; 40 import android.util.DisplayMetrics; 41 import android.util.Log; 42 import android.view.WindowManager; 43 44 import androidx.test.InstrumentationRegistry; 45 import androidx.test.runner.AndroidJUnit4; 46 47 import com.android.compatibility.common.util.CddTest; 48 49 import org.junit.Before; 50 import org.junit.Test; 51 import org.junit.runner.RunWith; 52 53 import java.io.File; 54 55 /** 56 * Tests that devices with low RAM specify themselves as Low RAM devices 57 */ 58 @RunWith(AndroidJUnit4.class) 59 public class LowRamDeviceTest { 60 61 private static final long ONE_MEGABYTE = 1048576L; 62 private static final String TAG = "LowRamDeviceTest"; 63 private static final long LOW_RAM_MAX = 1024; 64 private static final float MIN_APP_DATA_PARTITION_SIZE_GB = 4f; 65 private static final float MIN_APP_DATA_PARTITION_SIZE_LOW_RAM_GB = 1.1f; 66 private static final float MIN_SHARED_DATA_PARTITION_SIZE_GB = 1f; 67 private static final long GB_TO_BYTES_MULTIPLIER = 1024 * 1024 * 1024; 68 69 private Context mContext; 70 private PackageManager mPackageManager; 71 private ActivityManager mActivityManager; 72 private DisplayMetrics mDisplayMetrics; 73 74 @Before setUp()75 public void setUp() throws Exception { 76 mContext = InstrumentationRegistry.getTargetContext(); 77 mPackageManager = mContext.getPackageManager(); 78 mActivityManager = 79 (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); 80 81 mDisplayMetrics = new DisplayMetrics(); 82 WindowManager windowManager = 83 (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); 84 windowManager.getDefaultDisplay().getMetrics(mDisplayMetrics); 85 } 86 87 /** 88 * Test the devices reported memory to ensure it meets the minimum values described 89 * in CDD 7.6.1. 90 */ 91 @Test 92 @CddTest(requirement="7.6.1") testMinimumMemory()93 public void testMinimumMemory() { 94 int density = mDisplayMetrics.densityDpi; 95 Boolean supports64Bit = supportsSixtyFourBit(); 96 int screenSize = getScreenSize(); 97 Boolean lowRamDevice = mActivityManager.isLowRamDevice(); 98 Boolean watch = mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH); 99 100 Log.i(TAG, String.format("density=%d, supports64Bit=%s, screenSize=%d, watch=%s", 101 density, supports64Bit, screenSize, watch)); 102 103 if (watch) { 104 assertFalse("Device is not expected to be 64-bit", supports64Bit); 105 assertMinMemoryMb(416); 106 } else if (lessThanDpi(density, DENSITY_HIGH, screenSize, 107 SCREENLAYOUT_SIZE_NORMAL, SCREENLAYOUT_SIZE_SMALL) || 108 lessThanDpi(density, DENSITY_MEDIUM, screenSize, SCREENLAYOUT_SIZE_LARGE) || 109 lessThanDpi(density, DENSITY_LOW, screenSize, SCREENLAYOUT_SIZE_XLARGE)) { 110 111 if (supports64Bit) { 112 assertMinMemoryMb(816); 113 } else { 114 assertMinMemoryMb(416); 115 } 116 } else if (greaterThanDpi(density, DENSITY_560, screenSize, 117 SCREENLAYOUT_SIZE_NORMAL, SCREENLAYOUT_SIZE_SMALL) || 118 greaterThanDpi(density, DENSITY_400, screenSize, SCREENLAYOUT_SIZE_LARGE) || 119 greaterThanDpi(density, DENSITY_XHIGH, screenSize, SCREENLAYOUT_SIZE_XLARGE)) { 120 121 if (supports64Bit) { 122 assertMinMemoryMb(1824); 123 } else { 124 assertMinMemoryMb(1344); 125 } 126 } else if (greaterThanDpi(density, DENSITY_400, screenSize, 127 SCREENLAYOUT_SIZE_NORMAL, SCREENLAYOUT_SIZE_SMALL) || 128 greaterThanDpi(density, DENSITY_XHIGH, screenSize, SCREENLAYOUT_SIZE_LARGE) || 129 greaterThanDpi(density, DENSITY_TV, screenSize, SCREENLAYOUT_SIZE_XLARGE)) { 130 131 if (supports64Bit) { 132 assertMinMemoryMb(1280); 133 } else { 134 assertMinMemoryMb(896); 135 } 136 } else if (greaterThanDpi(density, DENSITY_XHIGH, screenSize, 137 SCREENLAYOUT_SIZE_NORMAL, SCREENLAYOUT_SIZE_SMALL) || 138 greaterThanDpi(density, DENSITY_TV, screenSize, SCREENLAYOUT_SIZE_LARGE) || 139 greaterThanDpi(density, DENSITY_MEDIUM, screenSize, SCREENLAYOUT_SIZE_XLARGE)) { 140 141 if (supports64Bit) { 142 assertMinMemoryMb(944); 143 } else { 144 assertMinMemoryMb(592); 145 } 146 } 147 } 148 149 @Test 150 @CddTest(requirement="7.6.2") testMinSharedDataPartitionSize()151 public void testMinSharedDataPartitionSize() { 152 assertDataPartitionMinimumSize( 153 "Shared data", 154 mContext.getExternalFilesDir(null), 155 MIN_SHARED_DATA_PARTITION_SIZE_GB); 156 } 157 158 @Test 159 @CddTest(requirement="7.6.1/H-9-2,7.6.1/H-10-1") testMinDataPartitionSize()160 public void testMinDataPartitionSize() { 161 long totalMemoryMb = getTotalMemory() / ONE_MEGABYTE; 162 boolean lowRam = totalMemoryMb <= LOW_RAM_MAX; 163 164 if (lowRam) { 165 assertDataPartitionMinimumSize( 166 "Application data", 167 mContext.getFilesDir(), 168 MIN_APP_DATA_PARTITION_SIZE_LOW_RAM_GB); 169 } else { 170 assertDataPartitionMinimumSize( 171 "Application data", mContext.getFilesDir(), MIN_APP_DATA_PARTITION_SIZE_GB); 172 } 173 } 174 175 /** 176 * @return the total memory accessible by the kernel as defined by 177 * {@code ActivityManager.MemoryInfo}. 178 */ getTotalMemory()179 private long getTotalMemory() { 180 ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo(); 181 mActivityManager.getMemoryInfo(memoryInfo); 182 return memoryInfo.totalMem; 183 } 184 185 /** @return the screen size as defined in {@Configuration}. */ getScreenSize()186 private int getScreenSize() { 187 Configuration config = mContext.getResources().getConfiguration(); 188 return config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK; 189 } 190 191 /** @return true iff this device supports 64 bit ABIs */ supportsSixtyFourBit()192 private static boolean supportsSixtyFourBit() { 193 return Build.SUPPORTED_64_BIT_ABIS.length > 0; 194 } 195 196 /** Asserts that the given values conform to the specs in CDD 7.6.1 */ assertMinMemoryMb(long minMb)197 private void assertMinMemoryMb(long minMb) { 198 199 long totalMemoryMb = getTotalMemory() / ONE_MEGABYTE; 200 boolean lowRam = totalMemoryMb <= LOW_RAM_MAX; 201 boolean lowRamDevice = mActivityManager.isLowRamDevice(); 202 203 Log.i(TAG, String.format("minMb=%,d", minMb)); 204 Log.i(TAG, String.format("totalMemoryMb=%,d", totalMemoryMb)); 205 Log.i(TAG, "lowRam=" + lowRam); 206 Log.i(TAG, "lowRamDevice=" + lowRamDevice); 207 208 assertTrue(String.format("Does not meet minimum memory requirements (CDD 7.6.1)." 209 + "Found = %d, Minimum = %d", totalMemoryMb, minMb), totalMemoryMb >= minMb); 210 211 assertTrue("Device must specify low RAM property: ro.config.low_ram=true", 212 !lowRam || (lowRam && lowRamDevice)); 213 } 214 lessThanDpi(int actualDensityDpi, int expectedDensityDpi, int actualScreenSize, int... expectedScreenSizes)215 private static boolean lessThanDpi(int actualDensityDpi, int expectedDensityDpi, 216 int actualScreenSize, int... expectedScreenSizes) { 217 return actualDensityDpi <= expectedDensityDpi && 218 contains(expectedScreenSizes, actualScreenSize); 219 } 220 greaterThanDpi(int actualDensityDpi, int expectedDensityDpi, int actualScreenSize, int... expectedScreenSizes)221 private static boolean greaterThanDpi(int actualDensityDpi, int expectedDensityDpi, 222 int actualScreenSize, int... expectedScreenSizes) { 223 return actualDensityDpi >= expectedDensityDpi && 224 contains(expectedScreenSizes, actualScreenSize); 225 } 226 227 /** @return true iff the {@code array} contains the {@code target} */ contains(int [] array, int target)228 private static boolean contains(int [] array, int target) { 229 for(int a : array) { 230 if (a == target) { 231 return true; 232 } 233 } 234 return false; 235 } 236 assertDataPartitionMinimumSize( String partitionName, File fileInPartition, float minPartitionSizeGb)237 private void assertDataPartitionMinimumSize( 238 String partitionName, File fileInPartition, float minPartitionSizeGb) { 239 StatFs statFs = new StatFs(fileInPartition.getAbsolutePath()); 240 long size = statFs.getTotalBytes(); 241 long minSizeBytes = (long) minPartitionSizeGb * GB_TO_BYTES_MULTIPLIER; 242 243 assertTrue( 244 String.format("%s partition size does not meet requirement. " 245 + "Found = %d, Minimum = %d", partitionName, size, minSizeBytes), 246 size > minSizeBytes); 247 } 248 } 249