Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 542c5237 authored by Maggie Wang's avatar Maggie Wang Committed by android-build-merger
Browse files

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

am: 4f79a18c

Change-Id: I1f9bc8a7e1c750c6f24ec4a6fee93e976b014ce2
parents e6e60c99 4f79a18c
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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);
+21 −61
Original line number Diff line number Diff line
@@ -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);
        }
        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(",");
        try {
            mService.setLocationEnabledForUser(enabled, userHandle.getIdentifier());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        // 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;
        }
        final List<String> providerList = Arrays.asList(allowedProviders.split(","));
        for(String provider : getAllProviders()) {
            if (provider.equals(PASSIVE_PROVIDER)) {
                continue;
            }
            if (providerList.contains(provider)) {
                return true;
            }
        try {
            return mService.isLocationEnabledForUser(userHandle.getIdentifier());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        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());
    }

    /**
+209 −6
Original line number Diff line number Diff line
@@ -1344,15 +1344,28 @@ public class LocationManagerService extends ILocationManager.Stub {
     * @param provider the name of the location provider
     */
    private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
        return isAllowedByUserSettingsLockedForUser(provider, mCurrentUserId);
    }

    /**
     * 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 userId   the user id to query
     */
    private boolean isAllowedByUserSettingsLockedForUser(String provider, int userId) {
        if (mEnabledProviders.contains(provider)) {
            return true;
        }
        if (mDisabledProviders.contains(provider)) {
            return false;
        }
        return isLocationProviderEnabledForUser(provider, mCurrentUserId);
        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
@@ -1360,12 +1373,13 @@ public class LocationManagerService extends ILocationManager.Stub {
     *
     * @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 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) {