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 package com.android.cts.applicationvisibility; 17 18 import static android.content.pm.PackageManager.MATCH_KNOWN_PACKAGES; 19 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertTrue; 22 import static org.junit.Assert.fail; 23 24 import android.app.UiAutomation; 25 import android.content.Context; 26 import android.content.pm.ApplicationInfo; 27 import android.content.pm.PackageInfo; 28 import android.content.pm.PackageManager; 29 import android.os.Bundle; 30 import android.os.Process; 31 import android.os.UserHandle; 32 33 import androidx.test.InstrumentationRegistry; 34 35 import org.junit.Before; 36 import org.junit.Test; 37 import org.junit.runner.RunWith; 38 import org.junit.runners.JUnit4; 39 40 import java.util.List; 41 import java.util.stream.Stream; 42 43 @RunWith(JUnit4.class) 44 public class ApplicationVisibilityCrossUserTest { 45 private String TINY_PKG = "android.appsecurity.cts.tinyapp"; 46 private Context mContext; 47 48 @Before setUp()49 public void setUp() throws Exception { 50 mContext = InstrumentationRegistry.getContext(); 51 } 52 53 /** Tests getting installed packages for the current user */ 54 @Test testPackageVisibility_currentUser()55 public void testPackageVisibility_currentUser() throws Exception { 56 final PackageManager pm = mContext.getPackageManager(); 57 final List<PackageInfo> packageList = 58 pm.getInstalledPackagesAsUser(0, mContext.getUserId()); 59 assertFalse(isAppInPackageList(TINY_PKG, packageList)); 60 } 61 62 /** Tests getting installed packages for all users, with cross user permission granted */ 63 @Test testPackageVisibility_anyUserCrossUserGrant()64 public void testPackageVisibility_anyUserCrossUserGrant() throws Exception { 65 final PackageManager pm = mContext.getPackageManager(); 66 final List<PackageInfo> packageList = 67 pm.getInstalledPackagesAsUser(MATCH_KNOWN_PACKAGES, mContext.getUserId()); 68 assertTrue(isAppInPackageList(TINY_PKG, packageList)); 69 } 70 71 /** Tests getting installed packages for all users, with cross user permission revoked */ 72 @Test testPackageVisibility_anyUserCrossUserNoGrant()73 public void testPackageVisibility_anyUserCrossUserNoGrant() throws Exception { 74 final PackageManager pm = mContext.getPackageManager(); 75 try { 76 ungrantAcrossUsersPermission(); 77 final List<PackageInfo> packageList = 78 pm.getInstalledPackagesAsUser(MATCH_KNOWN_PACKAGES, mContext.getUserId()); 79 fail("Should have received a security exception"); 80 } catch (SecurityException ignore) {} 81 } 82 83 /** Tests getting installed packages for another user, with cross user permission granted */ 84 @Test testPackageVisibility_otherUserGrant()85 public void testPackageVisibility_otherUserGrant() throws Exception { 86 final PackageManager pm = mContext.getPackageManager(); 87 final List<PackageInfo> packageList = 88 pm.getInstalledPackagesAsUser(0, getTestUser()); 89 assertTrue(isAppInPackageList(TINY_PKG, packageList)); 90 } 91 92 /** Tests getting installed packages for another user, with cross user permission revoked */ 93 @Test testPackageVisibility_otherUserNoGrant()94 public void testPackageVisibility_otherUserNoGrant() throws Exception { 95 final PackageManager pm = mContext.getPackageManager(); 96 try { 97 ungrantAcrossUsersPermission(); 98 final List<PackageInfo> packageList = 99 pm.getInstalledPackagesAsUser(0, getTestUser()); 100 fail("Should have received a security exception"); 101 } catch (SecurityException ignore) {} 102 } 103 104 /** Tests getting installed applications for the current user */ 105 @Test testApplicationVisibility_currentUser()106 public void testApplicationVisibility_currentUser() throws Exception { 107 final PackageManager pm = mContext.getPackageManager(); 108 final List<ApplicationInfo> applicationList = 109 pm.getInstalledApplicationsAsUser(0, mContext.getUserId()); 110 assertFalse(isAppInApplicationList(TINY_PKG, applicationList)); 111 } 112 113 /** Tests getting installed applications for all users, with cross user permission granted */ 114 @Test testApplicationVisibility_anyUserCrossUserGrant()115 public void testApplicationVisibility_anyUserCrossUserGrant() throws Exception { 116 final PackageManager pm = mContext.getPackageManager(); 117 final List<ApplicationInfo> applicationList = 118 pm.getInstalledApplicationsAsUser(MATCH_KNOWN_PACKAGES, mContext.getUserId()); 119 assertTrue(isAppInApplicationList(TINY_PKG, applicationList)); 120 } 121 122 /** Tests getting installed applications for all users, with cross user permission revoked */ 123 @Test testApplicationVisibility_anyUserCrossUserNoGrant()124 public void testApplicationVisibility_anyUserCrossUserNoGrant() throws Exception { 125 final PackageManager pm = mContext.getPackageManager(); 126 try { 127 ungrantAcrossUsersPermission(); 128 final List<ApplicationInfo> applicationList = 129 pm.getInstalledApplicationsAsUser(MATCH_KNOWN_PACKAGES, mContext.getUserId()); 130 fail("Should have received a security exception"); 131 } catch (SecurityException ignore) {} 132 } 133 134 /** Tests getting installed applications for another user, with cross user permission granted */ 135 @Test testApplicationVisibility_otherUserGrant()136 public void testApplicationVisibility_otherUserGrant() throws Exception { 137 final PackageManager pm = mContext.getPackageManager(); 138 final List<ApplicationInfo> applicationList = 139 pm.getInstalledApplicationsAsUser(0, getTestUser()); 140 assertTrue(isAppInApplicationList(TINY_PKG, applicationList)); 141 } 142 143 /** Tests getting installed applications for another user, with cross user permission revoked */ 144 @Test testApplicationVisibility_otherUserNoGrant()145 public void testApplicationVisibility_otherUserNoGrant() throws Exception { 146 final PackageManager pm = mContext.getPackageManager(); 147 try { 148 ungrantAcrossUsersPermission(); 149 final List<ApplicationInfo> applicationList = 150 pm.getInstalledApplicationsAsUser(0, getTestUser()); 151 fail("Should have received a security exception"); 152 } catch (SecurityException ignore) {} 153 } 154 155 /** Tests getting installed packages for the current user */ 156 @Test testGetPackagesForUidVisibility_currentUser()157 public void testGetPackagesForUidVisibility_currentUser() throws Exception { 158 final PackageManager pm = mContext.getPackageManager(); 159 final int userId = mContext.getUserId(); 160 final int firstAppUid = UserHandle.getUid(userId, Process.FIRST_APPLICATION_UID); 161 final int lastAppUid = UserHandle.getUid(userId, Process.LAST_APPLICATION_UID); 162 boolean found = false; 163 for (int appUid = firstAppUid; appUid < lastAppUid; appUid++) { 164 found = isAppInPackageNamesArray(TINY_PKG, pm.getPackagesForUid(appUid)); 165 if (found) break; 166 } 167 assertFalse(found); 168 } 169 170 /** Tests getting installed packages for primary user, with cross user permission granted */ 171 @Test testGetPackagesForUidVisibility_anotherUserCrossUserGrant()172 public void testGetPackagesForUidVisibility_anotherUserCrossUserGrant() throws Exception { 173 final PackageManager pm = mContext.getPackageManager(); 174 boolean found = false; 175 for (int appUid = Process.FIRST_APPLICATION_UID; appUid < Process.LAST_APPLICATION_UID; 176 appUid++) { 177 found = isAppInPackageNamesArray(TINY_PKG, pm.getPackagesForUid(appUid)); 178 if (found) break; 179 } 180 assertTrue(found); 181 } 182 183 /** Tests getting installed packages for primary user, with cross user permission revoked */ 184 @Test testGetPackagesForUidVisibility_anotherUserCrossUserNoGrant()185 public void testGetPackagesForUidVisibility_anotherUserCrossUserNoGrant() throws Exception { 186 final PackageManager pm = mContext.getPackageManager(); 187 ungrantAcrossUsersPermission(); 188 try { 189 for (int appUid = Process.FIRST_APPLICATION_UID; appUid < Process.LAST_APPLICATION_UID; 190 appUid++) { 191 isAppInPackageNamesArray(TINY_PKG, pm.getPackagesForUid(appUid)); 192 } 193 fail("Should have received a security exception"); 194 } catch (SecurityException e) {} 195 } 196 197 /** 198 * Tests getting the uid of the installed packages for the current user. 199 **/ 200 @Test testGetPackageUidVisibility_currentUser()201 public void testGetPackageUidVisibility_currentUser() { 202 final PackageManager pm = mContext.getPackageManager(); 203 try { 204 pm.getPackageUid(TINY_PKG, 0 /*flags*/); 205 fail("Should have received a NameNotFoundException"); 206 } catch (PackageManager.NameNotFoundException e) { 207 // Expected 208 } 209 } 210 211 /** 212 * Tests getting the uid of the installed packages for primary user, 213 * with cross user permission granted. 214 **/ 215 @Test testGetPackageUidVisibility_anotherUserCrossUserGrant()216 public void testGetPackageUidVisibility_anotherUserCrossUserGrant() { 217 final PackageManager pm = mContext.createContextAsUser(UserHandle.of(getTestUser()), 218 0 /*flags*/).getPackageManager(); 219 try { 220 pm.getPackageUid(TINY_PKG, MATCH_KNOWN_PACKAGES); 221 } catch (PackageManager.NameNotFoundException e) { 222 fail("Should not receive a NameNotFoundException"); 223 } 224 } 225 226 /** 227 * Tests getting the uid of the installed packages for primary user, 228 * with cross user permission revoked. 229 **/ 230 @Test testGetPackageUidVisibility_anotherUserCrossUserNoGrant()231 public void testGetPackageUidVisibility_anotherUserCrossUserNoGrant() 232 throws PackageManager.NameNotFoundException { 233 final PackageManager pm = mContext.createContextAsUser(UserHandle.of(getTestUser()), 234 0 /*flags*/).getPackageManager(); 235 ungrantAcrossUsersPermission(); 236 try { 237 pm.getPackageUid(TINY_PKG, MATCH_KNOWN_PACKAGES); 238 fail("Should have received a SecurityException"); 239 } catch (SecurityException e) { 240 // Expected 241 } 242 } 243 244 /** 245 * Tests getting the gids of the installed packages for the current user. 246 **/ 247 @Test testGetPackageGidsVisibility_currentUser()248 public void testGetPackageGidsVisibility_currentUser() { 249 final PackageManager pm = mContext.getPackageManager(); 250 try { 251 pm.getPackageGids(TINY_PKG, 0 /*flags*/); 252 fail("Should have received a NameNotFoundException"); 253 } catch (PackageManager.NameNotFoundException e) { 254 // Expected 255 } 256 } 257 258 /** 259 * Tests getting the gids of the installed packages for primary user, 260 * with cross user permission granted. 261 **/ 262 @Test testGetPackageGidsVisibility_anotherUserCrossUserGrant()263 public void testGetPackageGidsVisibility_anotherUserCrossUserGrant() { 264 final PackageManager pm = mContext.createContextAsUser(UserHandle.of(getTestUser()), 265 0 /*flags*/).getPackageManager(); 266 try { 267 pm.getPackageUid(TINY_PKG, MATCH_KNOWN_PACKAGES); 268 } catch (PackageManager.NameNotFoundException e) { 269 fail("Should not receive a NameNotFoundException"); 270 } 271 } 272 273 /** 274 * Tests getting the gids of the installed packages for primary user, 275 * with cross user permission revoked. 276 **/ 277 @Test testGetPackageGidsVisibility_anotherUserCrossUserNoGrant()278 public void testGetPackageGidsVisibility_anotherUserCrossUserNoGrant() 279 throws PackageManager.NameNotFoundException { 280 final PackageManager pm = mContext.createContextAsUser(UserHandle.of(getTestUser()), 281 0 /*flags*/).getPackageManager(); 282 ungrantAcrossUsersPermission(); 283 try { 284 pm.getPackageUid(TINY_PKG, MATCH_KNOWN_PACKAGES); 285 fail("Should have received a SecurityException"); 286 } catch (SecurityException e) { 287 // Expected 288 } 289 } 290 isAppInPackageList(String packageName, List<PackageInfo> packageList)291 private boolean isAppInPackageList(String packageName, 292 List<PackageInfo> packageList) { 293 for (PackageInfo pkgInfo : packageList) { 294 if (pkgInfo.packageName.equals(packageName)) { 295 return true; 296 } 297 } 298 return false; 299 } 300 isAppInApplicationList( String packageName, List<ApplicationInfo> applicationList)301 private boolean isAppInApplicationList( 302 String packageName, List<ApplicationInfo> applicationList) { 303 for (ApplicationInfo appInfo : applicationList) { 304 if (appInfo.packageName.equals(packageName)) { 305 return true; 306 } 307 } 308 return false; 309 } 310 isAppInPackageNamesArray(String packageName, String[] packageNames)311 private boolean isAppInPackageNamesArray(String packageName, String[] packageNames) { 312 return packageNames != null && Stream.of(packageNames).anyMatch( 313 name -> name.equals(packageName)); 314 } 315 getTestUser()316 private int getTestUser() { 317 final Bundle testArguments = InstrumentationRegistry.getArguments(); 318 if (testArguments.containsKey("testUser")) { 319 try { 320 return Integer.parseInt(testArguments.getString("testUser")); 321 } catch (NumberFormatException ignore) {} 322 } 323 return mContext.getUserId(); 324 } 325 ungrantAcrossUsersPermission()326 private static void ungrantAcrossUsersPermission() { 327 final Context context = InstrumentationRegistry.getContext(); 328 final PackageManager pm = context.getPackageManager(); 329 final UiAutomation uiAutomation = 330 InstrumentationRegistry.getInstrumentation().getUiAutomation(); 331 try { 332 uiAutomation.adoptShellPermissionIdentity(); 333 pm.revokeRuntimePermission(context.getPackageName(), 334 "android.permission.INTERACT_ACROSS_USERS", Process.myUserHandle()); 335 } finally { 336 uiAutomation.dropShellPermissionIdentity(); 337 } 338 } 339 } 340