Merge "Fix test location provider bug" into pi-dev

This commit is contained in:
Maggie Wang
2018-04-03 20:44:29 +00:00
committed by Android (Google) Code Review
3 changed files with 240 additions and 73 deletions

View File

@@ -89,6 +89,10 @@ interface ILocationManager
ProviderProperties getProviderProperties(String provider);
String getNetworkProviderPackage();
boolean isProviderEnabledForUser(String provider, int userId);
boolean setProviderEnabledForUser(String provider, boolean enabled, int userId);
boolean isLocationEnabledForUser(int userId);
void setLocationEnabledForUser(boolean enabled, int userId);
void addTestProvider(String name, in ProviderProperties properties, String opPackageName);
void removeTestProvider(String provider, String opPackageName);
void setTestProviderLocation(String provider, in Location loc, String opPackageName);

View File

@@ -1249,40 +1249,11 @@ public class LocationManager {
@SystemApi
@RequiresPermission(WRITE_SECURE_SETTINGS)
public void setLocationEnabledForUser(boolean enabled, UserHandle userHandle) {
final List<String> allProvidersList = getAllProviders();
// Update all providers on device plus gps and network provider when disabling location.
Set<String> allProvidersSet = new ArraySet<>(allProvidersList.size() + 2);
allProvidersSet.addAll(allProvidersList);
// When disabling location, disable gps and network provider that could have been enabled by
// location mode api.
if (enabled == false) {
allProvidersSet.add(GPS_PROVIDER);
allProvidersSet.add(NETWORK_PROVIDER);
try {
mService.setLocationEnabledForUser(enabled, userHandle.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
if (allProvidersSet.isEmpty()) {
return;
}
// to ensure thread safety, we write the provider name with a '+' or '-'
// and let the SettingsProvider handle it rather than reading and modifying
// the list of enabled providers.
final String prefix = enabled ? "+" : "-";
StringBuilder locationProvidersAllowed = new StringBuilder();
for (String provider : allProvidersSet) {
checkProvider(provider);
if (provider.equals(PASSIVE_PROVIDER)) {
continue;
}
locationProvidersAllowed.append(prefix);
locationProvidersAllowed.append(provider);
locationProvidersAllowed.append(",");
}
// Remove the trailing comma
locationProvidersAllowed.setLength(locationProvidersAllowed.length() - 1);
Settings.Secure.putStringForUser(
mContext.getContentResolver(),
Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
locationProvidersAllowed.toString(),
userHandle.getIdentifier());
}
/**
@@ -1295,22 +1266,11 @@ public class LocationManager {
*/
@SystemApi
public boolean isLocationEnabledForUser(UserHandle userHandle) {
final String allowedProviders = Settings.Secure.getStringForUser(
mContext.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
userHandle.getIdentifier());
if (allowedProviders == null) {
return false;
try {
return mService.isLocationEnabledForUser(userHandle.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
final List<String> providerList = Arrays.asList(allowedProviders.split(","));
for(String provider : getAllProviders()) {
if (provider.equals(PASSIVE_PROVIDER)) {
continue;
}
if (providerList.contains(provider)) {
return true;
}
}
return false;
}
/**
@@ -1362,9 +1322,12 @@ public class LocationManager {
@SystemApi
public boolean isProviderEnabledForUser(String provider, UserHandle userHandle) {
checkProvider(provider);
String allowedProviders = Settings.Secure.getStringForUser(mContext.getContentResolver(),
Settings.Secure.LOCATION_PROVIDERS_ALLOWED, userHandle.getIdentifier());
return TextUtils.delimitedStringContains(allowedProviders, ',', provider);
try {
return mService.isProviderEnabledForUser(provider, userHandle.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
@@ -1383,16 +1346,13 @@ public class LocationManager {
public boolean setProviderEnabledForUser(
String provider, boolean enabled, UserHandle userHandle) {
checkProvider(provider);
// to ensure thread safety, we write the provider name with a '+' or '-'
// and let the SettingsProvider handle it rather than reading and modifying
// the list of enabled providers.
if (enabled) {
provider = "+" + provider;
} else {
provider = "-" + provider;
try {
return mService.setProviderEnabledForUser(
provider, enabled, userHandle.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
return Settings.Secure.putStringForUser(mContext.getContentResolver(),
Settings.Secure.LOCATION_PROVIDERS_ALLOWED, provider, userHandle.getIdentifier());
}
/**

View File

@@ -1344,13 +1344,7 @@ public class LocationManagerService extends ILocationManager.Stub {
* @param provider the name of the location provider
*/
private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
if (mEnabledProviders.contains(provider)) {
return true;
}
if (mDisabledProviders.contains(provider)) {
return false;
}
return isLocationProviderEnabledForUser(provider, mCurrentUserId);
return isAllowedByUserSettingsLockedForUser(provider, mCurrentUserId);
}
/**
@@ -1359,13 +1353,33 @@ public class LocationManagerService extends ILocationManager.Stub {
* processes belonging to background users.
*
* @param provider the name of the location provider
* @param uid the requestor's UID
* @param userId the user id to query
*/
private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
private boolean isAllowedByUserSettingsLockedForUser(String provider, int userId) {
if (mEnabledProviders.contains(provider)) {
return true;
}
if (mDisabledProviders.contains(provider)) {
return false;
}
return isLocationProviderEnabledForUser(provider, userId);
}
/**
* Returns "true" if access to the specified location provider is allowed by the specified
* user's settings. Access to all location providers is forbidden to non-location-provider
* processes belonging to background users.
*
* @param provider the name of the location provider
* @param uid the requestor's UID
* @param userId the user id to query
*/
private boolean isAllowedByUserSettingsLocked(String provider, int uid, int userId) {
if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
return false;
}
return isAllowedByCurrentUserSettingsLocked(provider);
return isAllowedByUserSettingsLockedForUser(provider, userId);
}
/**
@@ -1572,7 +1586,8 @@ public class LocationManagerService extends ILocationManager.Stub {
continue;
}
if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
if (enabledOnly
&& !isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) {
continue;
}
if (criteria != null && !LocationProvider.propertiesMeetCriteria(
@@ -2098,7 +2113,7 @@ public class LocationManagerService extends ILocationManager.Stub {
oldRecord.disposeLocked(false);
}
boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid, mCurrentUserId);
if (isProviderEnabled) {
applyRequirementsLocked(name);
} else {
@@ -2219,7 +2234,7 @@ public class LocationManagerService extends ILocationManager.Stub {
LocationProviderInterface provider = mProvidersByName.get(name);
if (provider == null) return null;
if (!isAllowedByUserSettingsLocked(name, uid)) return null;
if (!isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) return null;
Location location;
if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
@@ -2539,6 +2554,173 @@ public class LocationManagerService extends ILocationManager.Stub {
return null;
}
/**
* Returns the current location enabled/disabled status for a user
*
* @param userId the id of the user
* @return true if location is enabled
*/
@Override
public boolean isLocationEnabledForUser(int userId) {
// Check INTERACT_ACROSS_USERS permission if userId is not current user id.
checkInteractAcrossUsersPermission(userId);
long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
final String allowedProviders = Settings.Secure.getStringForUser(
mContext.getContentResolver(),
Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
userId);
if (allowedProviders == null) {
return false;
}
final List<String> providerList = Arrays.asList(allowedProviders.split(","));
for(String provider : mRealProviders.keySet()) {
if (provider.equals(LocationManager.PASSIVE_PROVIDER)
|| provider.equals(LocationManager.FUSED_PROVIDER)) {
continue;
}
if (providerList.contains(provider)) {
return true;
}
}
return false;
}
} finally {
Binder.restoreCallingIdentity(identity);
}
}
/**
* Enable or disable location for a user
*
* @param enabled true to enable location, false to disable location
* @param userId the id of the user
*/
@Override
public void setLocationEnabledForUser(boolean enabled, int userId) {
mContext.enforceCallingPermission(
android.Manifest.permission.WRITE_SECURE_SETTINGS,
"Requires WRITE_SECURE_SETTINGS permission");
// Check INTERACT_ACROSS_USERS permission if userId is not current user id.
checkInteractAcrossUsersPermission(userId);
long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
final Set<String> allRealProviders = mRealProviders.keySet();
// Update all providers on device plus gps and network provider when disabling
// location
Set<String> allProvidersSet = new ArraySet<>(allRealProviders.size() + 2);
allProvidersSet.addAll(allRealProviders);
// When disabling location, disable gps and network provider that could have been
// enabled by location mode api.
if (enabled == false) {
allProvidersSet.add(LocationManager.GPS_PROVIDER);
allProvidersSet.add(LocationManager.NETWORK_PROVIDER);
}
if (allProvidersSet.isEmpty()) {
return;
}
// to ensure thread safety, we write the provider name with a '+' or '-'
// and let the SettingsProvider handle it rather than reading and modifying
// the list of enabled providers.
final String prefix = enabled ? "+" : "-";
StringBuilder locationProvidersAllowed = new StringBuilder();
for (String provider : allProvidersSet) {
if (provider.equals(LocationManager.PASSIVE_PROVIDER)
|| provider.equals(LocationManager.FUSED_PROVIDER)) {
continue;
}
locationProvidersAllowed.append(prefix);
locationProvidersAllowed.append(provider);
locationProvidersAllowed.append(",");
}
// Remove the trailing comma
locationProvidersAllowed.setLength(locationProvidersAllowed.length() - 1);
Settings.Secure.putStringForUser(
mContext.getContentResolver(),
Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
locationProvidersAllowed.toString(),
userId);
}
} finally {
Binder.restoreCallingIdentity(identity);
}
}
/**
* Returns the current enabled/disabled status of a location provider and user
*
* @param provider name of the provider
* @param userId the id of the user
* @return true if the provider exists and is enabled
*/
@Override
public boolean isProviderEnabledForUser(String provider, int userId) {
// Check INTERACT_ACROSS_USERS permission if userId is not current user id.
checkInteractAcrossUsersPermission(userId);
// Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
// so we discourage its use
if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
int uid = Binder.getCallingUid();
synchronized (mLock) {
LocationProviderInterface p = mProvidersByName.get(provider);
return p != null
&& isAllowedByUserSettingsLocked(provider, uid, userId);
}
}
/**
* Enable or disable a single location provider.
*
* @param provider name of the provider
* @param enabled true to enable the provider. False to disable the provider
* @param userId the id of the user to set
* @return true if the value was set, false on errors
*/
@Override
public boolean setProviderEnabledForUser(String provider, boolean enabled, int userId) {
mContext.enforceCallingPermission(
android.Manifest.permission.WRITE_SECURE_SETTINGS,
"Requires WRITE_SECURE_SETTINGS permission");
// Check INTERACT_ACROSS_USERS permission if userId is not current user id.
checkInteractAcrossUsersPermission(userId);
// Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
// so we discourage its use
if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
// No such provider exists
if (!mProvidersByName.containsKey(provider)) return false;
// If it is a test provider, do not write to Settings.Secure
if (mMockProviders.containsKey(provider)) {
setTestProviderEnabled(provider, enabled);
return true;
}
// to ensure thread safety, we write the provider name with a '+' or '-'
// and let the SettingsProvider handle it rather than reading and modifying
// the list of enabled providers.
String providerChange = (enabled ? "+" : "-") + provider;
return Settings.Secure.putStringForUser(
mContext.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
providerChange, userId);
}
} finally {
Binder.restoreCallingIdentity(identity);
}
}
/**
* Read location provider status from Settings.Secure
*
@@ -2559,6 +2741,23 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
/**
* Method for checking INTERACT_ACROSS_USERS permission if specified user id is not the same as
* current user id
*
* @param userId the user id to get or set value
*/
private void checkInteractAcrossUsersPermission(int userId) {
int uid = Binder.getCallingUid();
if (UserHandle.getUserId(uid) != userId) {
if (ActivityManager.checkComponentPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS, uid, -1, true)
!= PERMISSION_GRANTED) {
throw new SecurityException("Requires INTERACT_ACROSS_USERS permission");
}
}
}
/**
* Returns "true" if the UID belongs to a bound location provider.
*
@@ -3076,7 +3275,11 @@ public class LocationManagerService extends ILocationManager.Stub {
if (!canCallerAccessMockLocation(opPackageName)) {
return;
}
setTestProviderEnabled(provider, enabled);
}
/** Enable or disable a test location provider. */
private void setTestProviderEnabled(String provider, boolean enabled) {
synchronized (mLock) {
MockProvider mockProvider = mMockProviders.get(provider);
if (mockProvider == null) {