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