• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.permission.cts;
18 
19 import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
20 import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
21 import static android.Manifest.permission.ACCESS_FINE_LOCATION;
22 import static android.app.AppOpsManager.MODE_ALLOWED;
23 import static android.app.AppOpsManager.MODE_FOREGROUND;
24 import static android.app.AppOpsManager.MODE_IGNORED;
25 import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
26 import static android.content.pm.PermissionInfo.PROTECTION_INTERNAL;
27 import static android.health.connect.HealthPermissions.HEALTH_PERMISSION_GROUP;
28 import static android.permission.cts.PermissionUtils.getAppOp;
29 import static android.permission.cts.PermissionUtils.grantPermission;
30 import static android.permission.cts.PermissionUtils.install;
31 import static android.permission.cts.PermissionUtils.uninstallApp;
32 
33 import static com.android.compatibility.common.util.SystemUtil.eventually;
34 
35 import static com.google.common.truth.Truth.assertThat;
36 import static com.google.common.truth.Truth.assertWithMessage;
37 
38 import static org.junit.Assert.assertNotEquals;
39 import static org.junit.Assert.assertNotNull;
40 import static org.junit.Assert.assertTrue;
41 
42 import android.app.AppOpsManager;
43 import android.app.UiAutomation;
44 import android.content.Context;
45 import android.content.pm.PackageInfo;
46 import android.content.pm.PackageManager;
47 import android.content.pm.PermissionInfo;
48 import android.os.Build;
49 import android.permission.flags.Flags;
50 import android.platform.test.annotations.AppModeFull;
51 import android.platform.test.annotations.RequiresFlagsEnabled;
52 import android.platform.test.flag.junit.CheckFlagsRule;
53 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
54 import android.util.ArrayMap;
55 import android.util.Log;
56 
57 import androidx.test.filters.SdkSuppress;
58 import androidx.test.platform.app.InstrumentationRegistry;
59 import androidx.test.runner.AndroidJUnit4;
60 
61 import org.junit.After;
62 import org.junit.Rule;
63 import org.junit.Test;
64 import org.junit.runner.RunWith;
65 
66 @RunWith(AndroidJUnit4.class)
67 public class BackgroundPermissionsTest {
68     private static final String LOG_TAG = BackgroundPermissionsTest.class.getSimpleName();
69 
70     /** The package name of all apps used in the test */
71     private static final String APP_PKG = "android.permission.cts.appthatrequestpermission";
72 
73     private static final String TMP_DIR = "/data/local/tmp/cts-permission/";
74     private static final String APK_LOCATION_BACKGROUND_29 =
75             TMP_DIR + "CtsAppThatRequestsLocationAndBackgroundPermission29.apk";
76     private static final String APK_LOCATION_29v4 =
77             TMP_DIR + "CtsAppThatRequestsLocationPermission29v4.apk";
78 
79     private static final Context sContext =
80             InstrumentationRegistry.getInstrumentation().getTargetContext();
81     private static final UiAutomation sUiAutomation =
82             InstrumentationRegistry.getInstrumentation().getUiAutomation();
83 
84     @Rule
85     public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
86 
87     @After
uninstallTestApp()88     public void uninstallTestApp() {
89         uninstallApp(APP_PKG);
90     }
91 
92     @Test
93     @AppModeFull(reason = "Instant apps cannot read properties of other packages")
verifyBackgroundPropertiesForPlatformPermissions()94     public void verifyBackgroundPropertiesForPlatformPermissions() throws Exception {
95         verifyBackgroundPermissionsProperties("android");
96     }
97 
98     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava")
99     @RequiresFlagsEnabled({Flags.FLAG_REPLACE_BODY_SENSOR_PERMISSION_ENABLED})
100     @Test
101     @AppModeFull(reason = "Instant apps cannot read properties of other packages")
verifyBackgroundPropertiesForHealthPermissions()102     public void verifyBackgroundPropertiesForHealthPermissions() throws Exception {
103         String healthPackageName = sContext.getPackageManager().getPermissionGroupInfo(
104             HEALTH_PERMISSION_GROUP, /* flags= */ 0).packageName;
105         verifyBackgroundPermissionsProperties(healthPackageName);
106     }
107 
verifyBackgroundPermissionsProperties(String packageName)108     private void verifyBackgroundPermissionsProperties(String packageName)
109         throws Exception {
110         PackageInfo pkg = sContext.getPackageManager().getPackageInfo(
111                 packageName, PackageManager.GET_PERMISSIONS);
112         ArrayMap<String, String> potentialBackgroundPermissionsToGroup = new ArrayMap<>();
113 
114         int numPermissions = pkg.permissions.length;
115         for (int i = 0; i < numPermissions; i++) {
116             PermissionInfo permission = pkg.permissions[i];
117 
118             // background permissions must be dangerous or ungrantable or role
119             if ((permission.getProtection() & PROTECTION_DANGEROUS) != 0
120                     || (permission.getProtection() == PROTECTION_INTERNAL
121                             && (permission.getProtectionFlags() == 0
122                     || permission.getProtectionFlags() == PermissionInfo.PROTECTION_FLAG_ROLE))) {
123                 potentialBackgroundPermissionsToGroup.put(permission.name, permission.group);
124             }
125         }
126 
127         int backgroundPermissionCount = 0;
128         for (int i = 0; i < numPermissions; i++) {
129             PermissionInfo permission = pkg.permissions[i];
130             String backgroundPermissionName = permission.backgroundPermission;
131 
132             if (backgroundPermissionName != null) {
133                 backgroundPermissionCount += 1;
134                 Log.i(LOG_TAG, permission.name + "->" + backgroundPermissionName);
135 
136                 // foreground permissions must be dangerous
137                 assertNotEquals(0, permission.getProtection() & PROTECTION_DANGEROUS);
138 
139                 // All foreground permissions need an app op
140                 assertNotNull(AppOpsManager.permissionToOp(permission.name));
141 
142                 // the background permission must exist
143                 assertTrue(potentialBackgroundPermissionsToGroup
144                         .containsKey(backgroundPermissionName));
145             }
146         }
147         // Tested packages must have at least one permission linked with a background permission.
148         assertThat(backgroundPermissionCount).isGreaterThan(0);
149     }
150 
151     /**
152      * If a bg permission is lost during an upgrade, the app-op should downgrade to foreground
153      */
154     @Test
155     @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed "
156             + "to grant permissions to them. Also instant apps are never updated, hence the test "
157             + "is useless.")
appOpGetsDowngradedWhenBgPermIsNotRequestedAnymore()158     public void appOpGetsDowngradedWhenBgPermIsNotRequestedAnymore() throws Exception {
159         install(APK_LOCATION_BACKGROUND_29);
160         grantPermission(APP_PKG, ACCESS_COARSE_LOCATION);
161 
162         install(APK_LOCATION_29v4);
163 
164         eventually(() -> assertWithMessage("foreground app-op").that(
165                 getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_FOREGROUND));
166     }
167 
168     /**
169      * Make sure location switch-op is set if no location access is granted.
170      */
171     @Test
172     @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed "
173             + "to grant permissions to them. Also instant apps are never updated, hence the test "
174             + "is useless.")
appOpIsSetIfNoLocPermIsGranted()175     public void appOpIsSetIfNoLocPermIsGranted() {
176         install(APK_LOCATION_BACKGROUND_29);
177 
178         // Wait until the system sets the app-op automatically
179         eventually(() -> assertWithMessage("loc app-op").that(
180                 getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_IGNORED));
181     }
182 
183     /**
184      * Make sure location switch-op is set if only coarse location is granted
185      */
186     @Test
187     @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed "
188             + "to grant permissions to them. Also instant apps are never updated, hence the test "
189             + "is useless.")
appOpIsSetIfOnlyCoarseLocPermIsGranted()190     public void appOpIsSetIfOnlyCoarseLocPermIsGranted() {
191         install(APK_LOCATION_BACKGROUND_29);
192         sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_COARSE_LOCATION);
193 
194         // Wait until the system sets the app-op automatically
195         eventually(() -> assertWithMessage("loc app-op").that(
196                 getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_FOREGROUND));
197     }
198 
199     /**
200      * Make sure location switch-op is set if coarse location with background access is granted.
201      */
202     @Test
203     @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed "
204             + "to grant permissions to them. Also instant apps are never updated, hence the test "
205             + "is useless.")
appOpIsSetIfCoarseAndBgLocPermIsGranted()206     public void appOpIsSetIfCoarseAndBgLocPermIsGranted() {
207         install(APK_LOCATION_BACKGROUND_29);
208         sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_COARSE_LOCATION);
209         sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_BACKGROUND_LOCATION);
210 
211         // Wait until the system sets the app-op automatically
212         eventually(() -> assertWithMessage("loc app-op").that(
213                 getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_ALLOWED));
214     }
215 
216     /**
217      * Make sure location switch-op is set if only fine location is granted
218      */
219     @Test
220     @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed "
221             + "to grant permissions to them. Also instant apps are never updated, hence the test "
222             + "is useless.")
appOpIsSetIfOnlyFineLocPermIsGranted()223     public void appOpIsSetIfOnlyFineLocPermIsGranted() {
224         install(APK_LOCATION_BACKGROUND_29);
225         sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_FINE_LOCATION);
226 
227         // Wait until the system sets the app-op automatically
228         // Fine location uses background location to limit access
229         eventually(() -> assertWithMessage("loc app-op").that(
230                 getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_FOREGROUND));
231     }
232 
233     /**
234      * Make sure location switch-op is set if fine location with background access is granted.
235      */
236     @Test
237     @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed "
238             + "to grant permissions to them. Also instant apps are never updated, hence the test "
239             + "is useless.")
appOpIsSetIfFineAndBgLocPermIsGranted()240     public void appOpIsSetIfFineAndBgLocPermIsGranted() {
241         install(APK_LOCATION_BACKGROUND_29);
242         sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_FINE_LOCATION);
243         sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_BACKGROUND_LOCATION);
244 
245         // Wait until the system sets the app-op automatically
246         eventually(() -> assertWithMessage("loc app-op").that(
247                 getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_ALLOWED));
248     }
249 
250     /**
251      * Make sure location switch-op is set if fine and coarse location access is granted.
252      */
253     @Test
254     @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed "
255             + "to grant permissions to them. Also instant apps are never updated, hence the test "
256             + "is useless.")
appOpIsSetIfFineAndCoarseLocPermIsGranted()257     public void appOpIsSetIfFineAndCoarseLocPermIsGranted() {
258         install(APK_LOCATION_BACKGROUND_29);
259         sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_FINE_LOCATION);
260         sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_COARSE_LOCATION);
261 
262         // Wait until the system sets the app-op automatically
263         eventually(() -> assertWithMessage("loc app-op").that(
264                 getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_FOREGROUND));
265     }
266 
267     /**
268      * Make sure location switch-op is set if fine and coarse location with background access is
269      * granted.
270      */
271     @Test
272     @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed "
273             + "to grant permissions to them. Also instant apps are never updated, hence the test "
274             + "is useless.")
appOpIsSetIfFineCoarseAndBgLocPermIsGranted()275     public void appOpIsSetIfFineCoarseAndBgLocPermIsGranted() {
276         install(APK_LOCATION_BACKGROUND_29);
277         sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_FINE_LOCATION);
278         sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_COARSE_LOCATION);
279         sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_BACKGROUND_LOCATION);
280 
281         // Wait until the system sets the app-op automatically
282         eventually(() -> assertWithMessage("loc app-op").that(
283                 getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_ALLOWED));
284     }
285 }
286