1 /* 2 * Copyright (C) 2017 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 package android.appsecurity.cts; 17 18 import static org.junit.Assert.assertTrue; 19 import static org.junit.Assert.assertFalse; 20 21 import android.platform.test.annotations.AppModeFull; 22 23 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; 24 25 import org.junit.After; 26 import org.junit.Before; 27 import org.junit.Test; 28 import org.junit.runner.RunWith; 29 30 @RunWith(DeviceJUnit4ClassRunner.class) 31 @AppModeFull(reason = "Overlays cannot be instant apps") 32 public class OverlayHostTest extends BaseAppSecurityTest { 33 34 // Test applications 35 private static final String TARGET_OVERLAYABLE_APK = "CtsOverlayTarget.apk"; 36 private static final String TARGET_NO_OVERLAYABLE_APK = "CtsOverlayTargetNoOverlayable.apk"; 37 38 private static final String OVERLAY_ANDROID_APK = "CtsOverlayAndroid.apk"; 39 private static final String OVERLAY_ALL_APK = "CtsOverlayPolicyAll.apk"; 40 private static final String OVERLAY_ALL_HAS_CODE_APK = "CtsOverlayPolicyAllHasCode.apk"; 41 private static final String OVERLAY_ALL_NO_NAME_APK = "CtsOverlayPolicyAllNoName.apk"; 42 private static final String OVERLAY_ALL_NO_NAME_DIFFERENT_CERT_APK = 43 "CtsOverlayPolicyAllNoNameDifferentCert.apk"; 44 private static final String OVERLAY_ALL_PIE_APK = "CtsOverlayPolicyAllPie.apk"; 45 private static final String OVERLAY_PRODUCT_APK = "CtsOverlayPolicyProduct.apk"; 46 private static final String OVERLAY_SYSTEM_APK = "CtsOverlayPolicySystem.apk"; 47 private static final String OVERLAY_VENDOR_APK = "CtsOverlayPolicyVendor.apk"; 48 private static final String OVERLAY_DIFFERENT_SIGNATURE_APK = "CtsOverlayPolicySignatureDifferent.apk"; 49 50 // Test application package names 51 private static final String TARGET_PACKAGE = "com.android.cts.overlay.target"; 52 private static final String OVERLAY_ANDROID_PACKAGE = "com.android.cts.overlay.android"; 53 private static final String OVERLAY_ALL_PACKAGE = "com.android.cts.overlay.all"; 54 private static final String OVERLAY_PRODUCT_PACKAGE = "com.android.cts.overlay.policy.product"; 55 private static final String OVERLAY_SYSTEM_PACKAGE = "com.android.cts.overlay.policy.system"; 56 private static final String OVERLAY_VENDOR_PACKAGE = "com.android.cts.overlay.policy.vendor"; 57 private static final String OVERLAY_DIFFERENT_SIGNATURE_PACKAGE = "com.android.cts.overlay.policy.signature"; 58 59 // Test application test class 60 private static final String TEST_APP_APK = "CtsOverlayApp.apk"; 61 private static final String TEST_APP_PACKAGE = "com.android.cts.overlay.app"; 62 private static final String TEST_APP_CLASS = "com.android.cts.overlay.app.OverlayableTest"; 63 64 // Overlay states 65 private static final String STATE_DISABLED = "STATE_DISABLED"; 66 private static final String STATE_ENABLED = "STATE_ENABLED"; 67 private static final String STATE_NO_IDMAP = "STATE_NO_IDMAP"; 68 69 private static final long OVERLAY_WAIT_TIMEOUT = 10000; // 10 seconds 70 71 @Before setUp()72 public void setUp() throws Exception { 73 new InstallMultiple().addFile(TEST_APP_APK).run(); 74 } 75 76 @After tearDown()77 public void tearDown() throws Exception { 78 getDevice().uninstallPackage(TEST_APP_PACKAGE); 79 } 80 getStateForOverlay(String overlayPackage)81 private String getStateForOverlay(String overlayPackage) throws Exception { 82 String result = getDevice().executeShellCommand("cmd overlay dump"); 83 84 String overlayPackageForCurrentUser = overlayPackage + ":" + getDevice().getCurrentUser(); 85 86 int startIndex = result.indexOf(overlayPackageForCurrentUser); 87 if (startIndex < 0) { 88 return null; 89 } 90 91 int endIndex = result.indexOf('}', startIndex); 92 assertTrue(endIndex > startIndex); 93 94 int stateIndex = result.indexOf("mState", startIndex); 95 assertTrue(startIndex < stateIndex && stateIndex < endIndex); 96 97 int colonIndex = result.indexOf(':', stateIndex); 98 assertTrue(stateIndex < colonIndex && colonIndex < endIndex); 99 100 int endLineIndex = result.indexOf('\n', colonIndex); 101 assertTrue(colonIndex < endLineIndex && endLineIndex < endIndex); 102 return result.substring(colonIndex + 2, endLineIndex); 103 } 104 105 private void waitForOverlayState(String overlayPackage, String state) throws Exception { 106 boolean overlayFound = false; 107 long startTime = System.currentTimeMillis(); 108 109 while (!overlayFound && (System.currentTimeMillis() - startTime < OVERLAY_WAIT_TIMEOUT)) { 110 String result = getStateForOverlay(overlayPackage); 111 overlayFound = state.equals(result); 112 } 113 114 assertTrue(overlayFound); 115 } 116 117 private void assertFailToGenerateIdmap(String overlayApk, String overlayPackage) 118 throws Exception { 119 try { 120 getDevice().uninstallPackage(TARGET_PACKAGE); 121 getDevice().uninstallPackage(overlayPackage); 122 assertFalse(getDevice().getInstalledPackageNames().contains(OVERLAY_ALL_PACKAGE)); 123 assertFalse(getDevice().getInstalledPackageNames().contains(overlayPackage)); 124 125 new InstallMultiple().addFile(TARGET_OVERLAYABLE_APK).run(); 126 new InstallMultiple().addFile(overlayApk).run(); 127 128 waitForOverlayState(overlayPackage, STATE_NO_IDMAP); 129 getDevice().executeShellCommand("cmd overlay enable --user current " + overlayPackage); 130 waitForOverlayState(overlayPackage, STATE_NO_IDMAP); 131 } finally { 132 getDevice().uninstallPackage(TARGET_PACKAGE); 133 getDevice().uninstallPackage(overlayPackage); 134 } 135 } 136 137 private void runOverlayDeviceTest(String targetApk, String overlayApk, String overlayPackage, 138 String testMethod) 139 throws Exception { 140 try { 141 getDevice().uninstallPackage(TARGET_PACKAGE); 142 getDevice().uninstallPackage(overlayPackage); 143 assertFalse(getDevice().getInstalledPackageNames().contains(TARGET_PACKAGE)); 144 assertFalse(getDevice().getInstalledPackageNames().contains(overlayPackage)); 145 146 new InstallMultiple().addFile(overlayApk).run(); 147 new InstallMultiple().addFile(targetApk).run(); 148 149 waitForOverlayState(overlayPackage, STATE_DISABLED); 150 getDevice().executeShellCommand("cmd overlay enable --user current " + overlayPackage); 151 waitForOverlayState(overlayPackage, STATE_ENABLED); 152 153 runDeviceTests(TEST_APP_PACKAGE, TEST_APP_CLASS, testMethod, false /* instant */); 154 } finally { 155 getDevice().uninstallPackage(TARGET_PACKAGE); 156 getDevice().uninstallPackage(overlayPackage); 157 } 158 } 159 160 /** 161 * Overlays that target android and are not signed with the platform signature must not be 162 * installed successfully. 163 */ 164 @Test 165 public void testCannotInstallTargetAndroidNotPlatformSigned() throws Exception { 166 try { 167 getDevice().uninstallPackage(OVERLAY_ANDROID_PACKAGE); 168 assertFalse(getDevice().getInstalledPackageNames().contains(OVERLAY_ANDROID_PACKAGE)); 169 170 // Try to install the overlay, but expect an error. 171 new InstallMultiple().addFile(OVERLAY_ANDROID_APK).runExpectingFailure(); 172 173 // The install should have failed. 174 assertFalse(getDevice().getInstalledPackageNames().contains(OVERLAY_ANDROID_PACKAGE)); 175 176 // The package of the installed overlay should not appear in the overlay manager list. 177 assertFalse(getDevice().executeShellCommand("cmd overlay list --user current ") 178 .contains(" " + OVERLAY_ANDROID_PACKAGE + "\n")); 179 } finally { 180 getDevice().uninstallPackage(OVERLAY_ANDROID_PACKAGE); 181 } 182 } 183 184 /** 185 * Overlays that target a pre-Q sdk and that are not signed with the platform signature must not 186 * be installed. 187 **/ 188 @Test 189 public void testCannotInstallPieOverlayNotPlatformSigned() throws Exception { 190 try { 191 getDevice().uninstallPackage(OVERLAY_ALL_PACKAGE); 192 assertFalse(getDevice().getInstalledPackageNames().contains(OVERLAY_ALL_PACKAGE)); 193 194 // Try to install the overlay, but expect an error. 195 new InstallMultiple().addFile(OVERLAY_ALL_PIE_APK).runExpectingFailure(); 196 197 // The install should have failed. 198 assertFalse(getDevice().getInstalledPackageNames().contains(OVERLAY_ALL_PACKAGE)); 199 200 // The package of the installed overlay should not appear in the overlay manager list. 201 assertFalse(getDevice().executeShellCommand("cmd overlay list") 202 .contains(" " + OVERLAY_ALL_PACKAGE + "\n")); 203 } finally { 204 getDevice().uninstallPackage(OVERLAY_ALL_PACKAGE); 205 } 206 } 207 208 /** 209 * Overlays that target Q or higher, that do not specify an android:targetName, and that are 210 * not signed with the same signature as the target package must not be installed. 211 **/ 212 @Test 213 public void testCannotInstallDifferentSignaturesNoName() throws Exception { 214 try { 215 getDevice().uninstallPackage(TARGET_PACKAGE); 216 getDevice().uninstallPackage(OVERLAY_ALL_PACKAGE); 217 assertFalse(getDevice().getInstalledPackageNames().contains(TARGET_PACKAGE)); 218 assertFalse(getDevice().getInstalledPackageNames().contains(OVERLAY_ALL_PACKAGE)); 219 220 // Try to install the overlay, but expect an error. 221 new InstallMultiple().addFile(TARGET_NO_OVERLAYABLE_APK).run(); 222 new InstallMultiple().addFile( 223 OVERLAY_ALL_NO_NAME_DIFFERENT_CERT_APK).runExpectingFailure(); 224 225 // The install should have failed. 226 assertFalse(getDevice().getInstalledPackageNames().contains(OVERLAY_ALL_PACKAGE)); 227 228 // The package of the installed overlay should not appear in the overlay manager list. 229 assertFalse(getDevice().executeShellCommand("cmd overlay list --user current") 230 .contains(" " + OVERLAY_ALL_PACKAGE + "\n")); 231 } finally { 232 getDevice().uninstallPackage(OVERLAY_ALL_PACKAGE); 233 getDevice().uninstallPackage(TARGET_PACKAGE); 234 } 235 } 236 237 /** 238 * Overlays that target Q or higher, that do not specify an android:targetName, and are 239 * installed before the target must not be allowed to successfully generate an idmap if the 240 * overlay is not signed with the same signature as the target package. 241 **/ 242 @Test 243 public void testFailIdmapDifferentSignaturesNoName() throws Exception { 244 assertFailToGenerateIdmap(OVERLAY_ALL_NO_NAME_APK, OVERLAY_ALL_PACKAGE); 245 } 246 247 /** 248 * Overlays that target Q or higher, that do not specify an android:targetName, and are 249 * installed before the target must be allowed to successfully generate an idmap if the 250 * overlay is signed with the same signature as the target package. 251 **/ 252 @Test 253 public void testSameSignatureNoOverlayableSucceeds() throws Exception { 254 String testMethod = "testSameSignatureNoOverlayableSucceeds"; 255 runOverlayDeviceTest(TARGET_NO_OVERLAYABLE_APK, OVERLAY_ALL_NO_NAME_APK, 256 OVERLAY_ALL_PACKAGE, testMethod); 257 } 258 259 /** 260 * Overlays installed on the data partition may only overlay resources defined under the public 261 * and signature policies if the overlay is signed with the same signature as the target. 262 */ 263 @Test 264 public void testOverlayPolicyAll() throws Exception { 265 String testMethod = "testOverlayPolicyAll"; 266 runOverlayDeviceTest(TARGET_OVERLAYABLE_APK, OVERLAY_ALL_APK, OVERLAY_ALL_PACKAGE, 267 testMethod); 268 } 269 270 @Test 271 public void testOverlayCodeNotLoaded() throws Exception { 272 String testMethod = "testOverlayCodeNotLoaded"; 273 runOverlayDeviceTest(TARGET_OVERLAYABLE_APK, OVERLAY_ALL_HAS_CODE_APK, OVERLAY_ALL_PACKAGE, 274 testMethod); 275 } 276 277 @Test 278 public void testOverlayPolicyAllNoNameFails() throws Exception { 279 assertFailToGenerateIdmap(OVERLAY_ALL_NO_NAME_APK, OVERLAY_ALL_PACKAGE); 280 } 281 282 @Test 283 public void testOverlayPolicyProductFails() throws Exception { 284 assertFailToGenerateIdmap(OVERLAY_PRODUCT_APK, OVERLAY_PRODUCT_PACKAGE); 285 } 286 287 @Test 288 public void testOverlayPolicySystemFails() throws Exception { 289 assertFailToGenerateIdmap(OVERLAY_SYSTEM_APK, OVERLAY_SYSTEM_PACKAGE); 290 } 291 292 @Test 293 public void testOverlayPolicyVendorFails() throws Exception { 294 assertFailToGenerateIdmap(OVERLAY_VENDOR_APK, OVERLAY_VENDOR_PACKAGE); 295 } 296 297 @Test 298 public void testOverlayPolicyDifferentSignatureFails() throws Exception { 299 assertFailToGenerateIdmap(OVERLAY_DIFFERENT_SIGNATURE_APK, 300 OVERLAY_DIFFERENT_SIGNATURE_PACKAGE); 301 } 302 303 @Test 304 public void testFrameworkDoesNotDefineOverlayable() throws Exception { 305 String testMethod = "testFrameworkDoesNotDefineOverlayable"; 306 runDeviceTests(TEST_APP_PACKAGE, TEST_APP_CLASS, testMethod, false /* instant */); 307 } 308 309 /** Overlays must not overlay assets. */ 310 @Test 311 public void testCannotOverlayAssets() throws Exception { 312 String testMethod = "testCannotOverlayAssets"; 313 runOverlayDeviceTest(TARGET_OVERLAYABLE_APK, OVERLAY_ALL_APK, OVERLAY_ALL_PACKAGE, 314 testMethod); 315 } 316 } 317