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

Commit c0c0c0e6 authored by Victoria Lease's avatar Victoria Lease Committed by Android (Google) Code Review
Browse files

Merge "Multiuser love for LocationManager" into jb-mr1-dev

parents e45c4e42 b711d57c
Loading
Loading
Loading
Loading
+29 −2
Original line number Diff line number Diff line
@@ -4052,7 +4052,20 @@ public final class Settings {
         * @return true if the provider is enabled
         */
        public static final boolean isLocationProviderEnabled(ContentResolver cr, String provider) {
            String allowedProviders = Settings.Secure.getString(cr, LOCATION_PROVIDERS_ALLOWED);
            return isLocationProviderEnabledForUser(cr, provider, UserHandle.myUserId());
        }

        /**
         * Helper method for determining if a location provider is enabled.
         * @param cr the content resolver to use
         * @param provider the location provider to query
         * @param userId the userId to query
         * @return true if the provider is enabled
         * @hide
         */
        public static final boolean isLocationProviderEnabledForUser(ContentResolver cr, String provider, int userId) {
            String allowedProviders = Settings.Secure.getStringForUser(cr,
                    LOCATION_PROVIDERS_ALLOWED, userId);
            return TextUtils.delimitedStringContains(allowedProviders, ',', provider);
        }

@@ -4064,6 +4077,19 @@ public final class Settings {
         */
        public static final void setLocationProviderEnabled(ContentResolver cr,
                String provider, boolean enabled) {
            setLocationProviderEnabledForUser(cr, provider, enabled, UserHandle.myUserId());
        }

        /**
         * Thread-safe method for enabling or disabling a single location provider.
         * @param cr the content resolver to use
         * @param provider the location provider to enable or disable
         * @param enabled true if the provider should be enabled
         * @param userId the userId for which to enable/disable providers
         * @hide
         */
        public static final void setLocationProviderEnabledForUser(ContentResolver cr,
                String provider, boolean enabled, int userId) {
            // 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.
@@ -4072,7 +4098,8 @@ public final class Settings {
            } else {
                provider = "-" + provider;
            }
            putString(cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, provider);
            putStringForUser(cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, provider,
                    userId);
        }
    }

+111 −73
Original line number Diff line number Diff line
@@ -226,7 +226,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
                   updateProvidersLocked();
               }
            }
        });
        }, UserHandle.USER_ALL);
        mPackageMonitor.register(mContext, Looper.myLooper(), true);

        // listen for user change
@@ -289,7 +289,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
                mContext,
                LocationManager.NETWORK_PROVIDER,
                NETWORK_LOCATION_SERVICE_ACTION,
                providerPackageNames, mLocationHandler);
                providerPackageNames, mLocationHandler, mCurrentUserId);
        if (networkProvider != null) {
            mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
            mProxyProviders.add(networkProvider);
@@ -303,7 +303,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
                mContext,
                LocationManager.FUSED_PROVIDER,
                FUSED_LOCATION_SERVICE_ACTION,
                providerPackageNames, mLocationHandler);
                providerPackageNames, mLocationHandler, mCurrentUserId);
        if (fusedLocationProvider != null) {
            addProviderLocked(fusedLocationProvider);
            mProxyProviders.add(fusedLocationProvider);
@@ -314,7 +314,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
        }

        // bind to geocoder provider
        mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames);
        mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames,
                mCurrentUserId);
        if (mGeocodeProvider == null) {
            Slog.e(TAG,  "no geocoder provider found");
        }
@@ -326,11 +327,14 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
     */
    private void switchUser(int userId) {
        mBlacklist.switchUser(userId);
        //Log.d("LocationManagerService", "switchUser(" + mCurrentUserId + " -> " + userId + ")"); // TODO: remove this
        synchronized (mLock) {
            // TODO: inform previous user's Receivers that they will no longer receive updates
            mLastLocation.clear();
            for (LocationProviderInterface p : mProviders) {
                updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
                p.switchUser(userId);
            }
            mCurrentUserId = userId;
            // TODO: inform new user's Receivers that they are back on the update train
            updateProvidersLocked();
        }
    }

@@ -587,7 +591,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
    }


    private boolean isAllowedBySettingsLocked(String provider) {
    private boolean isAllowedBySettingsLocked(String provider, int userId) {
        if (userId != mCurrentUserId) {
            return false;
        }
        if (mEnabledProviders.contains(provider)) {
            return true;
        }
@@ -597,7 +604,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
        // Use system settings
        ContentResolver resolver = mContext.getContentResolver();

        return Settings.Secure.isLocationProviderEnabled(resolver, provider);
        return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
    }

    /**
@@ -695,6 +702,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
    @Override
    public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
        ArrayList<String> out;
        int callingUserId = UserHandle.getCallingUserId();
        long identity = Binder.clearCallingIdentity();
        try {
            synchronized (mLock) {
                out = new ArrayList<String>(mProviders.size());
                for (LocationProviderInterface provider : mProviders) {
@@ -703,7 +713,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
                        continue;
                    }
                    if (isAllowedProviderSafe(name)) {
                    if (enabledOnly && !isAllowedBySettingsLocked(name)) {
                        if (enabledOnly && !isAllowedBySettingsLocked(name, callingUserId)) {
                            continue;
                        }
                        if (criteria != null && !LocationProvider.propertiesMeetCriteria(
@@ -714,6 +724,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
                    }
                }
            }
        } finally {
            Binder.restoreCallingIdentity(identity);
        }

        if (D) Log.d(TAG, "getProviders()=" + out);
        return out;
@@ -778,12 +791,12 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
            LocationProviderInterface p = mProviders.get(i);
            boolean isEnabled = p.isEnabled();
            String name = p.getName();
            boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
            boolean shouldBeEnabled = isAllowedBySettingsLocked(name, mCurrentUserId);
            if (isEnabled && !shouldBeEnabled) {
                updateProviderListenersLocked(name, false);
                updateProviderListenersLocked(name, false, mCurrentUserId);
                changesMade = true;
            } else if (!isEnabled && shouldBeEnabled) {
                updateProviderListenersLocked(name, true);
                updateProviderListenersLocked(name, true, mCurrentUserId);
                changesMade = true;
            }
        }
@@ -793,7 +806,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
        }
    }

    private void updateProviderListenersLocked(String provider, boolean enabled) {
    private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
        int listeners = 0;

        LocationProviderInterface p = mProvidersByName.get(provider);
@@ -806,6 +819,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
            final int N = records.size();
            for (int i = 0; i < N; i++) {
                UpdateRecord record = records.get(i);
                if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
                    // Sends a notification message to the receiver
                    if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
                        if (deadReceivers == null) {
@@ -816,6 +830,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
                    listeners++;
                }
            }
        }

        if (deadReceivers != null) {
            for (int i = deadReceivers.size() - 1; i >= 0; i--) {
@@ -843,14 +858,15 @@ public class LocationManagerService extends ILocationManager.Stub implements Run

        if (records != null) {
            for (UpdateRecord record : records) {
                if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
                    LocationRequest locationRequest = record.mRequest;

                    providerRequest.locationRequests.add(locationRequest);
                    if (locationRequest.getInterval() < providerRequest.interval) {
                        providerRequest.reportLocation = true;
                        providerRequest.interval = locationRequest.getInterval();
                    }
                }
            }

            if (providerRequest.reportLocation) {
                // calculate who to blame for power
@@ -860,6 +876,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
                // under that threshold.
                long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
                for (UpdateRecord record : records) {
                    if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
                        LocationRequest locationRequest = record.mRequest;
                        if (locationRequest.getInterval() <= thresholdInterval) {
                            worksource.add(record.mReceiver.mUid);
@@ -867,6 +884,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
                    }
                }
            }
        }

        if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
        p.setRequest(providerRequest, worksource);
@@ -1084,7 +1102,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
            oldRecord.disposeLocked(false);
        }

        boolean isProviderEnabled = isAllowedBySettingsLocked(name);
        boolean isProviderEnabled = isAllowedBySettingsLocked(name, UserHandle.getUserId(uid));
        if (isProviderEnabled) {
            applyRequirementsLocked(name);
        } else {
@@ -1141,7 +1159,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
        // update provider
        for (String provider : providers) {
            // If provider is already disabled, don't need to do anything
            if (!isAllowedBySettingsLocked(provider)) {
            if (!isAllowedBySettingsLocked(provider, mCurrentUserId)) {
                continue;
            }

@@ -1156,6 +1174,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
        String perm = checkPermissionAndRequest(request);
        checkPackageName(packageName);

        long identity = Binder.clearCallingIdentity();
        try {
            if (mBlacklist.isBlacklisted(packageName)) {
                if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
                        packageName);
@@ -1170,7 +1190,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
                LocationProviderInterface provider = mProvidersByName.get(name);
                if (provider == null) return null;

            if (!isAllowedBySettingsLocked(name)) return null;
                if (!isAllowedBySettingsLocked(name, mCurrentUserId)) return null;

                Location location = mLastLocation.get(name);
                if (location == null) {
@@ -1186,6 +1206,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
                }
            }
            return null;
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }

    @Override
@@ -1321,11 +1344,16 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
                    "\" provider requires ACCESS_FINE_LOCATION permission");
        }

        long identity = Binder.clearCallingIdentity();
        try {
            synchronized (mLock) {
                LocationProviderInterface p = mProvidersByName.get(provider);
                if (p == null) return false;

            return isAllowedBySettingsLocked(provider);
                return isAllowedBySettingsLocked(provider, mCurrentUserId);
            }
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }

@@ -1461,6 +1489,16 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
            Receiver receiver = r.mReceiver;
            boolean receiverDead = false;

            int receiverUserId = UserHandle.getUserId(receiver.mUid);
            if (receiverUserId != mCurrentUserId) {
                if (D) {
                    Log.d(TAG, "skipping loc update for background user " + receiverUserId +
                            " (current user: " + mCurrentUserId + ", app: " +
                            receiver.mPackageName + ")");
                }
                continue;
            }

            if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
                if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
                        receiver.mPackageName);
@@ -1551,7 +1589,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
        }

        synchronized (mLock) {
            if (isAllowedBySettingsLocked(provider)) {
            if (isAllowedBySettingsLocked(provider, mCurrentUserId)) {
                handleLocationChangedLocked(location, passive);
            }
        }
+50 −35
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.os.Handler;
import android.os.IBinder;
import android.os.UserHandle;
import android.util.Log;

import com.android.internal.content.PackageMonitor;
@@ -58,15 +59,17 @@ public class ServiceWatcher implements ServiceConnection {
    private IBinder mBinder;   // connected service
    private String mPackageName;  // current best package
    private int mVersion;  // current best version
    private int mCurrentUserId;

    public ServiceWatcher(Context context, String logTag, String action,
            List<String> initialPackageNames, Runnable newServiceWork, Handler handler) {
            List<String> initialPackageNames, Runnable newServiceWork, Handler handler, int userId) {
        mContext = context;
        mTag = logTag;
        mAction = action;
        mPm = mContext.getPackageManager();
        mNewServiceWork = newServiceWork;
        mHandler = handler;
        mCurrentUserId = userId;

        mSignatureSets = new ArrayList<HashSet<Signature>>();
        for (int i=0; i < initialPackageNames.size(); i++) {
@@ -85,9 +88,11 @@ public class ServiceWatcher implements ServiceConnection {
    }

    public boolean start() {
        if (!bindBestPackage(null)) return false;
        synchronized (mLock) {
            if (!bindBestPackageLocked(null)) return false;
        }

        mPackageMonitor.register(mContext, null, true);
        mPackageMonitor.register(mContext, null, UserHandle.ALL, true);
        return true;
    }

@@ -98,13 +103,13 @@ public class ServiceWatcher implements ServiceConnection {
     * is null.
     * Return true if a new package was found to bind to.
     */
    private boolean bindBestPackage(String justCheckThisPackage) {
    private boolean bindBestPackageLocked(String justCheckThisPackage) {
        Intent intent = new Intent(mAction);
        if (justCheckThisPackage != null) {
            intent.setPackage(justCheckThisPackage);
        }
        List<ResolveInfo> rInfos = mPm.queryIntentServices(new Intent(mAction),
                PackageManager.GET_META_DATA);
        List<ResolveInfo> rInfos = mPm.queryIntentServicesAsUser(new Intent(mAction),
                PackageManager.GET_META_DATA, mCurrentUserId);
        int bestVersion = Integer.MIN_VALUE;
        String bestPackage = null;
        for (ResolveInfo rInfo : rInfos) {
@@ -141,36 +146,32 @@ public class ServiceWatcher implements ServiceConnection {
                (bestPackage == null ? "no new best package" : "new best packge: " + bestPackage)));

        if (bestPackage != null) {
            bindToPackage(bestPackage, bestVersion);
            bindToPackageLocked(bestPackage, bestVersion);
            return true;
        }
        return false;
    }

    private void unbind() {
    private void unbindLocked() {
        String pkg;
        synchronized (mLock) {
        pkg = mPackageName;
        mPackageName = null;
        mVersion = Integer.MIN_VALUE;
        }
        if (pkg != null) {
            if (D) Log.d(mTag, "unbinding " + pkg);
            mContext.unbindService(this);
        }
    }

    private void bindToPackage(String packageName, int version) {
        unbind();
    private void bindToPackageLocked(String packageName, int version) {
        unbindLocked();
        Intent intent = new Intent(mAction);
        intent.setPackage(packageName);
        synchronized (mLock) {
        mPackageName = packageName;
        mVersion = version;
        }
        if (D) Log.d(mTag, "binding " + packageName + " (version " + version + ")");
        mContext.bindService(intent, this, Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
                | Context.BIND_ALLOW_OOM_MANAGEMENT | Context.BIND_NOT_VISIBLE);
                | Context.BIND_ALLOW_OOM_MANAGEMENT | Context.BIND_NOT_VISIBLE, mCurrentUserId);
    }

    private boolean isSignatureMatch(Signature[] signatures) {
@@ -197,31 +198,37 @@ public class ServiceWatcher implements ServiceConnection {
         */
        @Override
        public void onPackageUpdateFinished(String packageName, int uid) {
            synchronized (mLock) {
                if (packageName.equals(mPackageName)) {
                    // package updated, make sure to rebind
                unbind();
                    unbindLocked();
                }
                // check the updated package in case it is better
            bindBestPackage(packageName);
                bindBestPackageLocked(packageName);
            }
        }

        @Override
        public void onPackageAdded(String packageName, int uid) {
            synchronized (mLock) {
                if (packageName.equals(mPackageName)) {
                    // package updated, make sure to rebind
                unbind();
                    unbindLocked();
                }
                // check the new package is case it is better
            bindBestPackage(packageName);
                bindBestPackageLocked(packageName);
            }
        }

        @Override
        public void onPackageRemoved(String packageName, int uid) {
            synchronized (mLock) {
                if (packageName.equals(mPackageName)) {
                unbind();
                    unbindLocked();
                    // the currently bound package was removed,
                    // need to search for a new package
                bindBestPackage(null);
                    bindBestPackageLocked(null);
                }
            }
        }
    };
@@ -271,4 +278,12 @@ public class ServiceWatcher implements ServiceConnection {
            return mBinder;
        }
    }

    public void switchUser(int userId) {
        synchronized (mLock) {
            unbindLocked();
            mCurrentUserId = userId;
            bindBestPackageLocked(null);
        }
    }
}
+5 −4
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.location.Address;
import android.location.GeocoderParams;
import android.location.IGeocodeProvider;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;

import com.android.server.ServiceWatcher;
@@ -38,8 +39,8 @@ public class GeocoderProxy {
    private final ServiceWatcher mServiceWatcher;

    public static GeocoderProxy createAndBind(Context context,
            List<String> initialPackageNames) {
        GeocoderProxy proxy = new GeocoderProxy(context, initialPackageNames);
            List<String> initialPackageNames, int userId) {
        GeocoderProxy proxy = new GeocoderProxy(context, initialPackageNames, userId);
        if (proxy.bind()) {
            return proxy;
        } else {
@@ -47,11 +48,11 @@ public class GeocoderProxy {
        }
    }

    public GeocoderProxy(Context context, List<String> initialPackageNames) {
    public GeocoderProxy(Context context, List<String> initialPackageNames, int userId) {
        mContext = context;

        mServiceWatcher = new ServiceWatcher(mContext, TAG, SERVICE_ACTION, initialPackageNames,
                null, null);
                null, null, userId);
    }

    private boolean bind () {
+5 −0
Original line number Diff line number Diff line
@@ -783,6 +783,11 @@ public class GpsLocationProvider implements LocationProviderInterface {
        sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));
    }

    @Override
    public void switchUser(int userId) {
        // nothing to do here
    }

    private void handleSetRequest(ProviderRequest request, WorkSource source) {
        if (DEBUG) Log.d(TAG, "setRequest " + request);

Loading