summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--location/java/android/location/ILocationManager.aidl2
-rw-r--r--location/java/android/location/LocationManager.java8
-rw-r--r--services/java/com/android/server/LocationManagerService.java49
-rw-r--r--services/java/com/android/server/location/GeofenceManager.java14
-rw-r--r--services/java/com/android/server/location/LocationBlacklist.java135
5 files changed, 194 insertions, 14 deletions
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index a2ce606de874..f663e0a04085 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -45,7 +45,7 @@ interface ILocationManager
in PendingIntent intent, String packageName);
void removeGeofence(in Geofence fence, in PendingIntent intent, String packageName);
- Location getLastLocation(in LocationRequest request);
+ Location getLastLocation(in LocationRequest request, String packageName);
boolean addGpsStatusListener(IGpsStatusListener listener);
void removeGpsStatusListener(IGpsStatusListener listener);
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 25da208e2ba0..bef363b75b8b 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1174,8 +1174,10 @@ public class LocationManager {
* @throws SecurityException if no suitable permission is present
*/
public Location getLastLocation() {
+ String packageName = mContext.getPackageName();
+
try {
- return mService.getLastLocation(null);
+ return mService.getLastLocation(null, packageName);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException", e);
return null;
@@ -1204,12 +1206,12 @@ public class LocationManager {
@Deprecated
public Location getLastKnownLocation(String provider) {
checkProvider(provider);
-
+ String packageName = mContext.getPackageName();
LocationRequest request = LocationRequest.createFromDeprecatedProvider(
provider, 0, 0, true);
try {
- return mService.getLastLocation(request);
+ return mService.getLastLocation(request, packageName);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException", e);
return null;
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index bb005d9ad2c6..8a564f7104e9 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -63,6 +63,7 @@ import com.android.internal.location.ProviderRequest;
import com.android.server.location.GeocoderProxy;
import com.android.server.location.GeofenceManager;
import com.android.server.location.GpsLocationProvider;
+import com.android.server.location.LocationBlacklist;
import com.android.server.location.LocationFudger;
import com.android.server.location.LocationProviderInterface;
import com.android.server.location.LocationProviderProxy;
@@ -132,8 +133,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs
private IGpsStatusProvider mGpsStatusProvider;
private INetInitiatedListener mNetInitiatedListener;
private LocationWorkerHandler mLocationHandler;
- // track the passive provider for some special cases
- private PassiveProvider mPassiveProvider;
+ private PassiveProvider mPassiveProvider; // track passive provider for special cases
+ private LocationBlacklist mBlacklist;
// --- fields below are protected by mWakeLock ---
private int mPendingBroadcasts;
@@ -208,7 +209,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs
synchronized (mLock) {
loadProvidersLocked();
}
- mGeofenceManager = new GeofenceManager(mContext);
+ mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
+ mBlacklist.init();
+ mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
mLocationFudger = new LocationFudger();
// Register for Network (Wifi or Mobile) updates
@@ -965,7 +968,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs
final int uid = Binder.getCallingUid();
Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
- // so wakelock calls will succeed (not totally sure this is still needed)
+ // providers may use public location API's, need to clear identity
long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -1015,7 +1018,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs
final int uid = Binder.getCallingUid();
Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
- // so wakelock calls will succeed (not totally sure this is still needed)
+ // providers may use public location API's, need to clear identity
long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -1063,10 +1066,17 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs
}
@Override
- public Location getLastLocation(LocationRequest request) {
+ public Location getLastLocation(LocationRequest request, String packageName) {
if (D) Log.d(TAG, "getLastLocation: " + request);
if (request == null) request = DEFAULT_LOCATION_REQUEST;
String perm = checkPermissionAndRequest(request);
+ checkPackageName(packageName);
+
+ if (mBlacklist.isBlacklisted(packageName)) {
+ if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
+ packageName);
+ return null;
+ }
synchronized (mLock) {
// Figure out the provider. Either its explicitly request (deprecated API's),
@@ -1097,7 +1107,14 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs
if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent);
- mGeofenceManager.addFence(request, geofence, intent, Binder.getCallingUid(), packageName);
+ // geo-fence manager uses the public location API, need to clear identity
+ int uid = Binder.getCallingUid();
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mGeofenceManager.addFence(request, geofence, intent, uid, packageName);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@Override
@@ -1108,7 +1125,13 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs
if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
- mGeofenceManager.removeFence(geofence, intent);
+ // geo-fence manager uses the public location API, need to clear identity
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mGeofenceManager.removeFence(geofence, intent);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@@ -1325,6 +1348,13 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs
for (UpdateRecord r : records) {
Receiver receiver = r.mReceiver;
boolean receiverDead = false;
+
+ if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
+ if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
+ receiver.mPackageName);
+ continue;
+ }
+
if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
location = lastLocation; // use fine location
} else {
@@ -1716,8 +1746,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs
for (String i : mDisabledProviders) {
pw.println(" " + i);
}
-
}
+ pw.append(" ");
+ mBlacklist.dump(pw);
if (mMockProviders.size() > 0) {
pw.println(" Mock Providers:");
for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
diff --git a/services/java/com/android/server/location/GeofenceManager.java b/services/java/com/android/server/location/GeofenceManager.java
index 338cd5d25b39..26d9c1555774 100644
--- a/services/java/com/android/server/location/GeofenceManager.java
+++ b/services/java/com/android/server/location/GeofenceManager.java
@@ -34,9 +34,13 @@ import android.os.Bundle;
import android.os.Looper;
import android.os.PowerManager;
import android.os.SystemClock;
+import android.util.Log;
+
+import com.android.server.LocationManagerService;
public class GeofenceManager implements LocationListener, PendingIntent.OnFinished {
private static final String TAG = "GeofenceManager";
+ private static final boolean D = LocationManagerService.D;
/**
* Assume a maximum land speed, as a heuristic to throttle location updates.
@@ -49,6 +53,7 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish
private final LocationManager mLocationManager;
private final PowerManager.WakeLock mWakeLock;
private final Looper mLooper; // looper thread to take location updates on
+ private final LocationBlacklist mBlacklist;
private Object mLock = new Object();
@@ -56,12 +61,13 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish
private Location mLastLocation;
private List<GeofenceState> mFences = new LinkedList<GeofenceState>();
- public GeofenceManager(Context context) {
+ public GeofenceManager(Context context, LocationBlacklist blacklist) {
mContext = context;
mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mLooper = Looper.myLooper();
+ mBlacklist = blacklist;
LocationRequest request = new LocationRequest()
.setQuality(LocationRequest.POWER_NONE)
@@ -145,6 +151,12 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish
removeExpiredFencesLocked();
for (GeofenceState state : mFences) {
+ if (mBlacklist.isBlacklisted(state.mPackageName)) {
+ if (D) Log.d(TAG, "skipping geofence processing for blacklisted app: " +
+ state.mPackageName);
+ continue;
+ }
+
int event = state.processLocation(location);
if ((event & GeofenceState.FLAG_ENTER) != 0) {
enterIntents.add(state.mIntent);
diff --git a/services/java/com/android/server/location/LocationBlacklist.java b/services/java/com/android/server/location/LocationBlacklist.java
new file mode 100644
index 000000000000..71fa9f98e31f
--- /dev/null
+++ b/services/java/com/android/server/location/LocationBlacklist.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.server.location;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.provider.Settings;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.server.LocationManagerService;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Allows applications to be blacklisted from location updates at run-time.
+ *
+ * This is a silent blacklist. Applications can still call Location Manager
+ * API's, but they just won't receive any locations.
+ */
+public final class LocationBlacklist extends ContentObserver {
+ private static final String TAG = "LocationBlacklist";
+ private static final boolean D = LocationManagerService.D;
+ private static final String BLACKLIST_CONFIG_NAME = "locationPackagePrefixBlacklist";
+ private static final String WHITELIST_CONFIG_NAME = "locationPackagePrefixWhitelist";
+
+ private final Context mContext;
+ private final Object mLock = new Object();
+
+ // all fields below synchronized on mLock
+ private String[] mWhitelist = new String[0];
+ private String[] mBlacklist = new String[0];
+
+ public LocationBlacklist(Context context, Handler handler) {
+ super(handler);
+ mContext = context;
+ }
+
+ public void init() {
+ mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
+ BLACKLIST_CONFIG_NAME), false, this);
+// mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
+// WHITELIST_CONFIG_NAME), false, this);
+ reloadBlacklist();
+ }
+
+ private void reloadBlacklist() {
+ String blacklist[] = getStringArray(BLACKLIST_CONFIG_NAME);
+ String whitelist[] = getStringArray(WHITELIST_CONFIG_NAME);
+ synchronized (mLock) {
+ mWhitelist = whitelist;
+ Slog.i(TAG, "whitelist: " + Arrays.toString(mWhitelist));
+ mBlacklist = blacklist;
+ Slog.i(TAG, "blacklist: " + Arrays.toString(mBlacklist));
+ }
+ }
+
+ /**
+ * Return true if in blacklist
+ * (package name matches blacklist, and does not match whitelist)
+ */
+ public boolean isBlacklisted(String packageName) {
+ synchronized (mLock) {
+ for (String black : mBlacklist) {
+ if (packageName.startsWith(black)) {
+ if (inWhitelist(packageName)) {
+ continue;
+ } else {
+ if (D) 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;
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ reloadBlacklist();
+ }
+
+ 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()]);
+ }
+
+ public void dump(PrintWriter pw) {
+ pw.println("mWhitelist=" + Arrays.toString(mWhitelist) + " mBlacklist=" +
+ Arrays.toString(mBlacklist));
+ }
+}