diff --git a/CHANGELOG.md b/CHANGELOG.md index 80cfc6062..643d09dc3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,7 @@ Changelog **Next release** -* ... +* Fixed location restriction in AOSP mode ([issue](/../../issues/2129)) [Open issues](https://github.com/M66B/XPrivacy/issues?state=open) diff --git a/src/biz/bokhorst/xprivacy/XLocationManager.java b/src/biz/bokhorst/xprivacy/XLocationManager.java index 653048c47..510ae732f 100644 --- a/src/biz/bokhorst/xprivacy/XLocationManager.java +++ b/src/biz/bokhorst/xprivacy/XLocationManager.java @@ -1,6 +1,9 @@ package biz.bokhorst.xprivacy; import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -10,6 +13,7 @@ import android.location.Location; import android.os.Binder; import android.os.Bundle; +import android.os.IInterface; import android.util.Log; import android.location.GpsSatellite; import android.location.GpsStatus; @@ -176,16 +180,16 @@ protected void before(XParam param) throws Throwable { case removeUpdates: if (isRestricted(param, PrivacyManager.cLocation, "requestLocationUpdates")) - unproxyLocationListener(param, 0); + unproxyLocationListener(param, 0, true); break; case requestLocationUpdates: if (param.args.length > 0 && param.args[0] instanceof String) { if (isRestrictedExtra(param, (String) param.args[0])) - proxyLocationListener(param, 3, LocationListener.class); + proxyLocationListener(param, 3, LocationListener.class, true); } else { if (isRestricted(param)) - proxyLocationListener(param, 3, LocationListener.class); + proxyLocationListener(param, 3, LocationListener.class, true); } break; @@ -193,7 +197,7 @@ protected void before(XParam param) throws Throwable { if (isRestricted(param, PrivacyManager.cLocation, "Srv_requestLocationUpdates")) if (param.args.length > 1) if (param.args[0] != null) // ILocationListener - unproxyLocationListener(param, 0); + unproxyLocationListener(param, 0, false); else if (param.args[1] != null) // PendingIntent param.setResult(null); break; @@ -202,7 +206,7 @@ else if (param.args[1] != null) // PendingIntent if (isRestricted(param)) if (param.args.length > 2) if (param.args[1] != null) // ILocationListener - proxyLocationListener(param, 1, Class.forName("android.location.ILocationListener")); + proxyLocationListener(param, 1, Class.forName("android.location.ILocationListener"), false); else if (param.args[2] != null) // PendingIntent param.setResult(null); break; @@ -210,10 +214,10 @@ else if (param.args[2] != null) // PendingIntent case requestSingleUpdate: if (param.args.length > 0 && param.args[0] instanceof String) { if (isRestrictedExtra(param, (String) param.args[0])) - proxyLocationListener(param, 1, LocationListener.class); + proxyLocationListener(param, 1, LocationListener.class, true); } else { if (isRestricted(param)) - proxyLocationListener(param, 1, LocationListener.class); + proxyLocationListener(param, 1, LocationListener.class, true); } break; @@ -317,51 +321,79 @@ protected void after(XParam param) throws Throwable { } } - private void proxyLocationListener(XParam param, int arg, Class interfaze) throws Throwable { + private void proxyLocationListener(XParam param, int arg, Class interfaze, boolean client) throws Throwable { if (param.args.length > arg) if (param.args[arg] instanceof PendingIntent) param.setResult(null); else if (param.args[arg] != null && param.thisObject != null) { - Object key = param.args[arg]; - synchronized (mMapProxy) { - // Reuse existing proxy - if (mMapProxy.containsKey(key)) { - Util.log(this, Log.INFO, "Reuse existing proxy uid=" + Binder.getCallingUid()); - param.args[arg] = mMapProxy.get(key); - return; + if (client) { + Object key = param.args[arg]; + synchronized (mMapProxy) { + // Reuse existing proxy + if (mMapProxy.containsKey(key)) { + Util.log(this, Log.INFO, "Reuse existing proxy uid=" + Binder.getCallingUid()); + param.args[arg] = mMapProxy.get(key); + return; + } + + // Already proxied + if (mMapProxy.containsValue(key)) { + Util.log(this, Log.INFO, "Already proxied uid=" + Binder.getCallingUid()); + return; + } } - // Already proxied - if (mMapProxy.containsValue(key)) { - Util.log(this, Log.INFO, "Already proxied uid=" + Binder.getCallingUid()); - return; - } - } + // Create proxy + Util.log(this, Log.INFO, "Creating proxy uid=" + Binder.getCallingUid()); + Object proxy = new ProxyLocationListener(Binder.getCallingUid(), (LocationListener) param.args[arg]); - // Create proxy - Util.log(this, Log.INFO, "Creating proxy uid=" + Binder.getCallingUid()); - Object proxy = new ProxyLocationListener(Binder.getCallingUid(), (LocationListener) param.args[arg]); - - // Use proxy - synchronized (mMapProxy) { - mMapProxy.put(key, proxy); + // Use proxy + synchronized (mMapProxy) { + mMapProxy.put(key, proxy); + } + param.args[arg] = proxy; + } else { + // Create proxy + ClassLoader cl = param.thisObject.getClass().getClassLoader(); + InvocationHandler ih = new OnLocationChangedHandler(Binder.getCallingUid(), param.args[arg]); + Object proxy = Proxy.newProxyInstance(cl, new Class[] { interfaze }, ih); + + Object key = param.args[arg]; + if (key instanceof IInterface) + key = ((IInterface) key).asBinder(); + + // Use proxy + synchronized (mMapProxy) { + mMapProxy.put(key, proxy); + } + param.args[arg] = proxy; } - param.args[arg] = proxy; } } - private void unproxyLocationListener(XParam param, int arg) { + private void unproxyLocationListener(XParam param, int arg, boolean client) { if (param.args.length > arg) if (param.args[arg] instanceof PendingIntent) param.setResult(null); else if (param.args[arg] != null) { - Object key = param.args[arg]; - synchronized (mMapProxy) { - if (mMapProxy.containsKey(key)) { - Util.log(this, Log.INFO, "Removing proxy uid=" + Binder.getCallingUid()); - param.args[arg] = mMapProxy.get(key); + if (client) { + Object key = param.args[arg]; + synchronized (mMapProxy) { + if (mMapProxy.containsKey(key)) { + Util.log(this, Log.INFO, "Removing proxy uid=" + Binder.getCallingUid()); + param.args[arg] = mMapProxy.get(key); + } + } + } else { + Object key = param.args[arg]; + if (key instanceof IInterface) + key = ((IInterface) key).asBinder(); + + synchronized (mMapProxy) { + if (mMapProxy.containsKey(key)) + param.args[arg] = mMapProxy.get(key); } } } @@ -398,4 +430,20 @@ public void onStatusChanged(String provider, int status, Bundle extras) { mListener.onStatusChanged(provider, status, extras); } } + + private class OnLocationChangedHandler implements InvocationHandler { + private int mUid; + private Object mTarget; + + public OnLocationChangedHandler(int uid, Object target) { + mUid = uid; + mTarget = target; + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if ("onLocationChanged".equals(method.getName())) + args[0] = PrivacyManager.getDefacedLocation(mUid, (Location) args[0]); + return method.invoke(mTarget, args); + } + } }