• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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