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