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

Commit 48c5eb01 authored by Nick Pelly's avatar Nick Pelly
Browse files

DO NOT MERGE. Add package-name-prefix blacklist for location updates.

The Settings.Secure value locationPackagePrefixBlacklist and
locationPackagePrefixWhitelist contains comma seperated package-name
prefixes.

Location & geo-fence updates are silently dropped if the receiving
package name has a prefix on the blacklist. Status updates are
not affected. All other API's work as before.

A content observer is used so run-time updates to the blacklist
apply immediately. There is both a blacklist and a whitelist.
The blacklist applies first, and then exemptions are allowed
from the whitelist. In other words, if your package name prefix
matches both the black AND white list, then it is allowed.

Change-Id: I4ea2ad56fa6bd75d32151bc250ac25c26a5777c4
parent 47db02ba
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()) {