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

Commit 1af5ac1b authored by Nick Pelly's avatar Nick Pelly Committed by Android (Google) Code Review
Browse files

Merge "DO NOT MERGE. Add package-name-prefix blacklist for location updates." into jb-dev

parents 28b452fd 48c5eb01
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -361,10 +361,10 @@ class ContextImpl extends Context {
                    return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
                }});

        registerService(LOCATION_SERVICE, new StaticServiceFetcher() {
                public Object createStaticService() {
        registerService(LOCATION_SERVICE, new ServiceFetcher() {
                public Object createService(ContextImpl ctx) {
                    IBinder b = ServiceManager.getService(LOCATION_SERVICE);
                    return new LocationManager(ILocationManager.Stub.asInterface(b));
                    return new LocationManager(ctx, ILocationManager.Stub.asInterface(b));
                }});

        registerService(NETWORK_POLICY_SERVICE, new ServiceFetcher() {
+6 −6
Original line number Diff line number Diff line
@@ -39,11 +39,11 @@ interface ILocationManager
    boolean providerMeetsCriteria(String provider, in Criteria criteria);

    void requestLocationUpdates(String provider, in Criteria criteria, long minTime, float minDistance,
        boolean singleShot, in ILocationListener listener);
        boolean singleShot, in ILocationListener listener, String packageName);
    void requestLocationUpdatesPI(String provider, in Criteria criteria, long minTime, float minDistance,
        boolean singleShot, in PendingIntent intent);
    void removeUpdates(in ILocationListener listener);
    void removeUpdatesPI(in PendingIntent intent);
        boolean singleShot, in PendingIntent intent, String packageName);
    void removeUpdates(in ILocationListener listener, String packageName);
    void removeUpdatesPI(in PendingIntent intent, String packageName);

    boolean addGpsStatusListener(IGpsStatusListener listener);
    void removeGpsStatusListener(IGpsStatusListener listener);
@@ -54,13 +54,13 @@ interface ILocationManager
    boolean sendExtraCommand(String provider, String command, inout Bundle extras);

    void addProximityAlert(double latitude, double longitude, float distance,
        long expiration, in PendingIntent intent);
        long expiration, in PendingIntent intent, String packageName);
    void removeProximityAlert(in PendingIntent intent);

    Bundle getProviderInfo(String provider);
    boolean isProviderEnabled(String provider);

    Location getLastKnownLocation(String provider);
    Location getLastKnownLocation(String provider, String packageName);

    // Used by location providers to tell the location manager when it has a new location.
    // Passive is true if the location is coming from the passive provider, in which case
+13 −7
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.location;

import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Looper;
@@ -160,6 +161,8 @@ public class LocationManager {
     */
    public static final String EXTRA_GPS_ENABLED = "enabled";

    private final Context mContext;

    // Map from LocationListeners to their associated ListenerTransport objects
    private HashMap<LocationListener,ListenerTransport> mListeners =
        new HashMap<LocationListener,ListenerTransport>();
@@ -260,8 +263,9 @@ public class LocationManager {
     * right way to create an instance of this class is using the
     * factory Context.getSystemService.
     */
    public LocationManager(ILocationManager service) {
    public LocationManager(Context context, ILocationManager service) {
        mService = service;
        mContext = context;
    }

    private LocationProvider createProvider(String name, Bundle info) {
@@ -657,7 +661,8 @@ public class LocationManager {
                    transport = new ListenerTransport(listener, looper);
                }
                mListeners.put(listener, transport);
                mService.requestLocationUpdates(provider, criteria, minTime, minDistance, singleShot, transport);
                mService.requestLocationUpdates(provider, criteria, minTime, minDistance,
                        singleShot, transport, mContext.getPackageName());
            }
        } catch (RemoteException ex) {
            Log.e(TAG, "requestLocationUpdates: DeadObjectException", ex);
@@ -837,7 +842,8 @@ public class LocationManager {
        }

        try {
            mService.requestLocationUpdatesPI(provider, criteria, minTime, minDistance, singleShot, intent);
            mService.requestLocationUpdatesPI(provider, criteria, minTime, minDistance, singleShot,
                    intent, mContext.getPackageName());
        } catch (RemoteException ex) {
            Log.e(TAG, "requestLocationUpdates: RemoteException", ex);
        }
@@ -1005,7 +1011,7 @@ public class LocationManager {
        try {
            ListenerTransport transport = mListeners.remove(listener);
            if (transport != null) {
                mService.removeUpdates(transport);
                mService.removeUpdates(transport, mContext.getPackageName());
            }
        } catch (RemoteException ex) {
            Log.e(TAG, "removeUpdates: DeadObjectException", ex);
@@ -1028,7 +1034,7 @@ public class LocationManager {
            Log.d(TAG, "removeUpdates: intent = " + intent);
        }
        try {
            mService.removeUpdatesPI(intent);
            mService.removeUpdatesPI(intent, mContext.getPackageName());
        } catch (RemoteException ex) {
            Log.e(TAG, "removeUpdates: RemoteException", ex);
        }
@@ -1087,7 +1093,7 @@ public class LocationManager {
        }
        try {
            mService.addProximityAlert(latitude, longitude, radius,
                                       expiration, intent);
                                       expiration, intent, mContext.getPackageName());
        } catch (RemoteException ex) {
            Log.e(TAG, "addProximityAlert: RemoteException", ex);
        }
@@ -1153,7 +1159,7 @@ public class LocationManager {
            throw new IllegalArgumentException("provider==null");
        }
        try {
            return mService.getLastKnownLocation(provider);
            return mService.getLastKnownLocation(provider, mContext.getPackageName());
        } catch (RemoteException ex) {
            Log.e(TAG, "getLastKnowLocation: RemoteException", ex);
            return null;
+168 −23
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.content.pm.ResolveInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.database.Cursor;
import android.location.Address;
import android.location.Criteria;
@@ -79,6 +80,8 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Observable;
@@ -109,6 +112,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
    private static final String INSTALL_LOCATION_PROVIDER =
        android.Manifest.permission.INSTALL_LOCATION_PROVIDER;

    private static final String BLACKLIST_CONFIG_NAME = "locationPackagePrefixBlacklist";
    private static final String WHITELIST_CONFIG_NAME = "locationPackagePrefixWhitelist";

    // Location Providers may sometimes deliver location updates
    // slightly faster that requested - provide grace period so
    // we don't unnecessarily filter events that are otherwise on
@@ -193,6 +199,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run

    private int mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;

    // for prefix blacklist
    private String[] mWhitelist = new String[0];
    private String[] mBlacklist = new String[0];

    // for Settings change notification
    private ContentQueryMap mSettings;

@@ -205,20 +215,23 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
        final PendingIntent mPendingIntent;
        final Object mKey;
        final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
        final String mPackageName;

        int mPendingBroadcasts;
        String mRequiredPermissions;

        Receiver(ILocationListener listener) {
        Receiver(ILocationListener listener, String packageName) {
            mListener = listener;
            mPendingIntent = null;
            mKey = listener.asBinder();
            mPackageName = packageName;
        }

        Receiver(PendingIntent intent) {
        Receiver(PendingIntent intent, String packageName) {
            mPendingIntent = intent;
            mListener = null;
            mKey = intent;
            mPackageName = packageName;
        }

        @Override
@@ -601,6 +614,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run

        // Load providers
        loadProviders();
        loadBlacklist();

        // Register for Network (Wifi or Mobile) updates
        IntentFilter intentFilter = new IntentFilter();
@@ -1110,11 +1124,11 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
        }
    }

    private Receiver getReceiver(ILocationListener listener) {
    private Receiver getReceiver(ILocationListener listener, String packageName) {
        IBinder binder = listener.asBinder();
        Receiver receiver = mReceivers.get(binder);
        if (receiver == null) {
            receiver = new Receiver(listener);
            receiver = new Receiver(listener, packageName);
            mReceivers.put(binder, receiver);

            try {
@@ -1129,10 +1143,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
        return receiver;
    }

    private Receiver getReceiver(PendingIntent intent) {
    private Receiver getReceiver(PendingIntent intent, String packageName) {
        Receiver receiver = mReceivers.get(intent);
        if (receiver == null) {
            receiver = new Receiver(intent);
            receiver = new Receiver(intent, packageName);
            mReceivers.put(intent, receiver);
        }
        return receiver;
@@ -1157,7 +1171,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
    }

    public void requestLocationUpdates(String provider, Criteria criteria,
        long minTime, float minDistance, boolean singleShot, ILocationListener listener) {
        long minTime, float minDistance, boolean singleShot, ILocationListener listener,
        String packageName) {
        checkPackageName(Binder.getCallingUid(), packageName);
        if (criteria != null) {
            // FIXME - should we consider using multiple providers simultaneously
            // rather than only the best one?
@@ -1170,7 +1186,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
        try {
            synchronized (mLock) {
                requestLocationUpdatesLocked(provider, minTime, minDistance, singleShot,
                        getReceiver(listener));
                        getReceiver(listener, packageName));
            }
        } catch (SecurityException se) {
            throw se;
@@ -1194,7 +1210,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
    }

    public void requestLocationUpdatesPI(String provider, Criteria criteria,
            long minTime, float minDistance, boolean singleShot, PendingIntent intent) {
            long minTime, float minDistance, boolean singleShot, PendingIntent intent,
            String packageName) {
        checkPackageName(Binder.getCallingUid(), packageName);
        validatePendingIntent(intent);
        if (criteria != null) {
            // FIXME - should we consider using multiple providers simultaneously
@@ -1208,7 +1226,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
        try {
            synchronized (mLock) {
                requestLocationUpdatesLocked(provider, minTime, minDistance, singleShot,
                        getReceiver(intent));
                        getReceiver(intent, packageName));
            }
        } catch (SecurityException se) {
            throw se;
@@ -1270,10 +1288,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
        }
    }

    public void removeUpdates(ILocationListener listener) {
    public void removeUpdates(ILocationListener listener, String packageName) {
        try {
            synchronized (mLock) {
                removeUpdatesLocked(getReceiver(listener));
                removeUpdatesLocked(getReceiver(listener, packageName));
            }
        } catch (SecurityException se) {
            throw se;
@@ -1284,10 +1302,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
        }
    }

    public void removeUpdatesPI(PendingIntent intent) {
    public void removeUpdatesPI(PendingIntent intent, String packageName) {
        try {
            synchronized (mLock) {
                removeUpdatesLocked(getReceiver(intent));
                removeUpdatesLocked(getReceiver(intent, packageName));
            }
        } catch (SecurityException se) {
            throw se;
@@ -1446,15 +1464,17 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
        final long mExpiration;
        final PendingIntent mIntent;
        final Location mLocation;
        final String mPackageName;

        public ProximityAlert(int uid, double latitude, double longitude,
            float radius, long expiration, PendingIntent intent) {
            float radius, long expiration, PendingIntent intent, String packageName) {
            mUid = uid;
            mLatitude = latitude;
            mLongitude = longitude;
            mRadius = radius;
            mExpiration = expiration;
            mIntent = intent;
            mPackageName = packageName;

            mLocation = new Location("");
            mLocation.setLatitude(latitude);
@@ -1522,6 +1542,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
                PendingIntent intent = alert.getIntent();
                long expiration = alert.getExpiration();

                if (inBlacklist(alert.mPackageName)) {
                    continue;
                }

                if ((expiration == -1) || (now <= expiration)) {
                    boolean entered = mProximitiesEntered.contains(alert);
                    boolean inProximity =
@@ -1632,11 +1656,12 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
    }

    public void addProximityAlert(double latitude, double longitude,
        float radius, long expiration, PendingIntent intent) {
        float radius, long expiration, PendingIntent intent, String packageName) {
        validatePendingIntent(intent);
        try {
            synchronized (mLock) {
                addProximityAlertLocked(latitude, longitude, radius, expiration, intent);
                addProximityAlertLocked(latitude, longitude, radius, expiration, intent,
                        packageName);
            }
        } catch (SecurityException se) {
            throw se;
@@ -1648,7 +1673,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
    }

    private void addProximityAlertLocked(double latitude, double longitude,
        float radius, long expiration, PendingIntent intent) {
        float radius, long expiration, PendingIntent intent, String packageName) {
        if (LOCAL_LOGV) {
            Slog.v(TAG, "addProximityAlert: latitude = " + latitude +
                    ", longitude = " + longitude +
@@ -1656,6 +1681,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
                    ", intent = " + intent);
        }

        checkPackageName(Binder.getCallingUid(), packageName);

        // Require ability to access all providers for now
        if (!isAllowedProviderSafe(LocationManager.GPS_PROVIDER) ||
            !isAllowedProviderSafe(LocationManager.NETWORK_PROVIDER)) {
@@ -1666,12 +1693,12 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
            expiration += System.currentTimeMillis();
        }
        ProximityAlert alert = new ProximityAlert(Binder.getCallingUid(),
                latitude, longitude, radius, expiration, intent);
                latitude, longitude, radius, expiration, intent, packageName);
        mProximityAlerts.put(intent, alert);

        if (mProximityReceiver == null) {
            mProximityListener = new ProximityListener();
            mProximityReceiver = new Receiver(mProximityListener);
            mProximityReceiver = new Receiver(mProximityListener, packageName);

            for (int i = mProviders.size() - 1; i >= 0; i--) {
                LocationProviderInterface provider = mProviders.get(i);
@@ -1787,13 +1814,13 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
        return isAllowedBySettingsLocked(provider);
    }

    public Location getLastKnownLocation(String provider) {
    public Location getLastKnownLocation(String provider, String packageName) {
        if (LOCAL_LOGV) {
            Slog.v(TAG, "getLastKnownLocation: " + provider);
        }
        try {
            synchronized (mLock) {
                return _getLastKnownLocationLocked(provider);
                return _getLastKnownLocationLocked(provider, packageName);
            }
        } catch (SecurityException se) {
            throw se;
@@ -1803,8 +1830,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
        }
    }

    private Location _getLastKnownLocationLocked(String provider) {
    private Location _getLastKnownLocationLocked(String provider, String packageName) {
        checkPermissionsSafe(provider, null);
        checkPackageName(Binder.getCallingUid(), packageName);

        LocationProviderInterface p = mProvidersByName.get(provider);
        if (p == null) {
@@ -1815,6 +1843,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
            return null;
        }

        if (inBlacklist(packageName)) {
            return null;
        }

        return mLastKnownLocation.get(provider);
    }

@@ -1877,6 +1909,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
            Receiver receiver = r.mReceiver;
            boolean receiverDead = false;

            if (inBlacklist(receiver.mPackageName)) {
                continue;
            }

            Location lastLoc = r.mLastFixBroadcast;
            if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
                if (lastLoc == null) {
@@ -2315,6 +2351,113 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
        }
    }

    public class BlacklistObserver extends ContentObserver {
        public BlacklistObserver(Handler handler) {
            super(handler);
        }
        @Override
        public void onChange(boolean selfChange) {
            reloadBlacklist();
        }
    }

    private void loadBlacklist() {
        // Register for changes
        BlacklistObserver observer = new BlacklistObserver(mLocationHandler);
        mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
                BLACKLIST_CONFIG_NAME), false, observer);
        mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
                WHITELIST_CONFIG_NAME), false, observer);
        reloadBlacklist();
    }

    private void reloadBlacklist() {
        String blacklist[] = getStringArray(BLACKLIST_CONFIG_NAME);
        String whitelist[] = getStringArray(WHITELIST_CONFIG_NAME);
        synchronized (mLock) {
            mWhitelist = whitelist;
            Slog.i(TAG, "whitelist: " + arrayToString(mWhitelist));
            mBlacklist = blacklist;
            Slog.i(TAG, "blacklist: " + arrayToString(mBlacklist));
        }
    }

    private static String arrayToString(String[] array) {
        StringBuilder s = new StringBuilder();
        s.append('[');
        boolean first = true;
        for (String a : array) {
            if (!first) s.append(',');
            first = false;
            s.append(a);
        }
        s.append(']');
        return s.toString();
    }

    private String[] getStringArray(String key) {
        String flatString = Settings.Secure.getString(mContext.getContentResolver(), key);
        if (flatString == null) {
            return new String[0];
        }
        String[] splitStrings = flatString.split(",");
        ArrayList<String> result = new ArrayList<String>();
        for (String pkg : splitStrings) {
            pkg = pkg.trim();
            if (pkg.isEmpty()) {
                continue;
            }
            result.add(pkg);
        }
        return result.toArray(new String[result.size()]);
    }

    /**
     * Return true if in blacklist, and not in whitelist.
     */
    private boolean inBlacklist(String packageName) {
        synchronized (mLock) {
            for (String black : mBlacklist) {
                if (packageName.startsWith(black)) {
                    if (inWhitelist(packageName)) {
                        continue;
                    } else {
                        if (LOCAL_LOGV) Log.d(TAG, "dropping location (blacklisted): "
                                + packageName + " matches " + black);
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * Return true if any of packages are in whitelist
     */
    private boolean inWhitelist(String pkg) {
        synchronized (mLock) {
            for (String white : mWhitelist) {
                if (pkg.startsWith(white)) return true;
            }
        }
        return false;
    }

    private void checkPackageName(int uid, String packageName) {
        if (packageName == null) {
            throw new SecurityException("packageName cannot be null");
        }
        String[] packages = mPackageManager.getPackagesForUid(uid);
        if (packages == null) {
            throw new SecurityException("invalid UID " + uid);
        }
        for (String pkg : packages) {
            if (packageName.equals(pkg)) return;
        }
        throw new SecurityException("invalid package name");
    }

    private void log(String log) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Slog.d(TAG, log);
@@ -2346,6 +2489,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
                    j.getValue().dump(pw, "        ");
                }
            }
            pw.println("  Package blacklist:" + arrayToString(mBlacklist));
            pw.println("  Package whitelist:" + arrayToString(mWhitelist));
            pw.println("  Records by Provider:");
            for (Map.Entry<String, ArrayList<UpdateRecord>> i
                    : mRecordsByProvider.entrySet()) {