Merge "Update location permission check for ConnectivityUtil"
diff --git a/core/java/com/android/internal/util/ConnectivityUtil.java b/core/java/com/android/internal/util/LocationPermissionChecker.java
similarity index 71%
rename from core/java/com/android/internal/util/ConnectivityUtil.java
rename to core/java/com/android/internal/util/LocationPermissionChecker.java
index b1d4fa0..dc318b4 100644
--- a/core/java/com/android/internal/util/ConnectivityUtil.java
+++ b/core/java/com/android/internal/util/LocationPermissionChecker.java
@@ -33,28 +33,59 @@
/**
- * Utility methods for common functionality using by different networks.
+ * The methods used for location permission and location mode checking.
*
* @hide
*/
-public class ConnectivityUtil {
+public class LocationPermissionChecker {
- private static final String TAG = "ConnectivityUtil";
+ private static final String TAG = "LocationPermissionChecker";
private final Context mContext;
- private final AppOpsManager mAppOps;
+ private final AppOpsManager mAppOpsManager;
private final UserManager mUserManager;
+ private final LocationManager mLocationManager;
- public ConnectivityUtil(Context context) {
+ public LocationPermissionChecker(Context context) {
mContext = context;
- mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+ mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ mLocationManager =
+ (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
}
/**
- * API to determine if the caller has fine/coarse location permission (depending on
- * config/targetSDK level) and the location mode is enabled for the user. SecurityException is
- * thrown if the caller has no permission or the location mode is disabled.
+ * Check location permission granted by the caller.
+ *
+ * This API check if the location mode enabled for the caller and the caller has
+ * ACCESS_COARSE_LOCATION permission is targetSDK<29, otherwise, has ACCESS_FINE_LOCATION.
+ *
+ * @param pkgName package name of the application requesting access
+ * @param featureId The feature in the package
+ * @param uid The uid of the package
+ * @param message A message describing why the permission was checked. Only needed if this is
+ * not inside of a two-way binder call from the data receiver
+ *
+ * @return {@code true} returns if the caller has location permission and the location mode is
+ * enabled.
+ */
+ public boolean checkLocationPermission(String pkgName, @Nullable String featureId,
+ int uid, @Nullable String message) {
+ try {
+ enforceLocationPermission(pkgName, featureId, uid, message);
+ return true;
+ } catch (SecurityException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Enforce the caller has location permission.
+ *
+ * This API determines if the location mode enabled for the caller and the caller has
+ * ACCESS_COARSE_LOCATION permission is targetSDK<29, otherwise, has ACCESS_FINE_LOCATION.
+ * SecurityException is thrown if the caller has no permission or the location mode is disabled.
+ *
* @param pkgName package name of the application requesting access
* @param featureId The feature in the package
* @param uid The uid of the package
@@ -62,31 +93,21 @@
* not inside of a two-way binder call from the data receiver
*/
public void enforceLocationPermission(String pkgName, @Nullable String featureId, int uid,
- @Nullable String message)
- throws SecurityException {
+ @Nullable String message) throws SecurityException {
+
checkPackage(uid, pkgName);
// Location mode must be enabled
if (!isLocationModeEnabled()) {
- // Location mode is disabled, scan results cannot be returned
throw new SecurityException("Location mode is disabled for the device");
}
// LocationAccess by App: caller must have Coarse/Fine Location permission to have access to
// location information.
- boolean canAppPackageUseLocation = checkCallersLocationPermission(pkgName, featureId,
- uid, /* coarseForTargetSdkLessThanQ */ true, message);
-
- // If neither caller or app has location access, there is no need to check
- // any other permissions. Deny access to scan results.
- if (!canAppPackageUseLocation) {
+ if (!checkCallersLocationPermission(pkgName, featureId,
+ uid, /* coarseForTargetSdkLessThanQ */ true, message)) {
throw new SecurityException("UID " + uid + " has no location permission");
}
- // If the User or profile is current, permission is granted
- // Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission.
- if (!isCurrentProfile(uid) && !checkInteractAcrossUsersFull(uid)) {
- throw new SecurityException("UID " + uid + " profile not permitted");
- }
}
/**
@@ -104,6 +125,7 @@
*/
public boolean checkCallersLocationPermission(String pkgName, @Nullable String featureId,
int uid, boolean coarseForTargetSdkLessThanQ, @Nullable String message) {
+
boolean isTargetSdkLessThanQ = isTargetSdkLessThan(pkgName, Build.VERSION_CODES.Q, uid);
String permissionType = Manifest.permission.ACCESS_FINE_LOCATION;
@@ -111,8 +133,7 @@
// Having FINE permission implies having COARSE permission (but not the reverse)
permissionType = Manifest.permission.ACCESS_COARSE_LOCATION;
}
- if (getUidPermission(permissionType, uid)
- == PackageManager.PERMISSION_DENIED) {
+ if (getUidPermission(permissionType, uid) == PackageManager.PERMISSION_DENIED) {
return false;
}
@@ -134,10 +155,8 @@
* Retrieves a handle to LocationManager (if not already done) and check if location is enabled.
*/
public boolean isLocationModeEnabled() {
- LocationManager locationManager =
- (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
try {
- return locationManager.isLocationEnabledForUser(UserHandle.of(
+ return mLocationManager.isLocationEnabledForUser(UserHandle.of(
getCurrentUser()));
} catch (Exception e) {
Log.e(TAG, "Failure to get location mode via API, falling back to settings", e);
@@ -166,28 +185,15 @@
private boolean noteAppOpAllowed(String op, String pkgName, @Nullable String featureId,
int uid, @Nullable String message) {
- return mAppOps.noteOp(op, uid, pkgName) == AppOpsManager.MODE_ALLOWED;
+ return mAppOpsManager.noteOp(op, uid, pkgName) == AppOpsManager.MODE_ALLOWED;
}
- private void checkPackage(int uid, String pkgName) throws SecurityException {
+ private void checkPackage(int uid, String pkgName)
+ throws SecurityException {
if (pkgName == null) {
throw new SecurityException("Checking UID " + uid + " but Package Name is Null");
}
- mAppOps.checkPackage(uid, pkgName);
- }
-
- private boolean isCurrentProfile(int uid) {
- UserHandle currentUser = UserHandle.of(getCurrentUser());
- UserHandle callingUser = UserHandle.getUserHandleForUid(uid);
- return currentUser.equals(callingUser)
- || mUserManager.isSameProfileGroup(
- currentUser.getIdentifier(), callingUser.getIdentifier());
- }
-
- private boolean checkInteractAcrossUsersFull(int uid) {
- return getUidPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, uid)
- == PackageManager.PERMISSION_GRANTED;
+ mAppOpsManager.checkPackage(uid, pkgName);
}
@VisibleForTesting
diff --git a/core/tests/utiltests/src/com/android/internal/util/ConnectivityUtilTest.java b/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java
similarity index 83%
rename from core/tests/utiltests/src/com/android/internal/util/ConnectivityUtilTest.java
rename to core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java
index 5564712..6a0a3dc 100644
--- a/core/tests/utiltests/src/com/android/internal/util/ConnectivityUtilTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java
@@ -27,6 +27,7 @@
import static org.mockito.Mockito.when;
import android.Manifest;
+import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -47,8 +48,8 @@
import java.util.HashMap;
-/** Unit tests for {@link ConnectivityUtil}. */
-public class ConnectivityUtilTest {
+/** Unit tests for {@link LocationPermissionChecker}. */
+public class LocationPermissionCheckerTest {
public static final String TAG = "ConnectivityUtilTest";
@@ -84,18 +85,7 @@
private boolean mThrowSecurityException;
private Answer<Integer> mReturnPermission;
private HashMap<String, Integer> mPermissionsList = new HashMap<String, Integer>();
-
- private class TestConnectivityUtil extends ConnectivityUtil {
-
- TestConnectivityUtil(Context context) {
- super(context);
- }
-
- @Override
- protected int getCurrentUser() {
- return mCurrentUser;
- }
- }
+ private LocationPermissionChecker mChecker;
@Before
public void setUp() {
@@ -140,11 +130,12 @@
mThrowSecurityException = true;
mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.M;
mIsLocationEnabled = false;
- mCurrentUser = UserHandle.USER_SYSTEM;
+ mCurrentUser = ActivityManager.getCurrentUser();
mCoarseLocationPermission = PackageManager.PERMISSION_DENIED;
mFineLocationPermission = PackageManager.PERMISSION_DENIED;
mAllowCoarseLocationApps = AppOpsManager.MODE_ERRORED;
mAllowFineLocationApps = AppOpsManager.MODE_ERRORED;
+ mChecker = new LocationPermissionChecker(mMockContext);
}
private void setupMockInterface() {
@@ -188,8 +179,7 @@
mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
mUid = mCurrentUser;
setupTestCase();
- new TestConnectivityUtil(mMockContext)
- .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null);
+ mChecker.enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null);
}
@Test
@@ -202,8 +192,7 @@
mAllowFineLocationApps = AppOpsManager.MODE_ALLOWED;
mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
setupTestCase();
- new TestConnectivityUtil(mMockContext)
- .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null);
+ mChecker.enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null);
}
@Test
@@ -216,22 +205,8 @@
setupTestCase();
assertThrows(SecurityException.class,
- () -> new TestConnectivityUtil(mMockContext)
- .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
- }
-
- @Test
- public void testenforceCanAccessScanResults_UserOrProfileNotCurrent() throws Exception {
- mIsLocationEnabled = true;
- mThrowSecurityException = false;
- mCoarseLocationPermission = PackageManager.PERMISSION_GRANTED;
- mAllowCoarseLocationApps = AppOpsManager.MODE_ALLOWED;
- mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
- setupTestCase();
-
- assertThrows(SecurityException.class,
- () -> new TestConnectivityUtil(mMockContext)
- .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
+ () -> mChecker.enforceLocationPermission(
+ TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
}
@Test
@@ -240,8 +215,8 @@
mIsLocationEnabled = true;
setupTestCase();
assertThrows(SecurityException.class,
- () -> new TestConnectivityUtil(mMockContext)
- .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
+ () -> mChecker.enforceLocationPermission(
+ TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
}
@Test
@@ -255,8 +230,8 @@
setupTestCase();
assertThrows(SecurityException.class,
- () -> new TestConnectivityUtil(mMockContext)
- .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
+ () -> mChecker.enforceLocationPermission(
+ TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
verify(mMockAppOps, never()).noteOp(anyInt(), anyInt(), anyString());
}
@@ -271,8 +246,8 @@
setupTestCase();
assertThrows(SecurityException.class,
- () -> new TestConnectivityUtil(mMockContext)
- .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
+ () -> mChecker.enforceLocationPermission(
+ TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
}
private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) {