diff --git a/assets/meta.xml b/assets/meta.xml index 690182124..3120b9f8c 100644 --- a/assets/meta.xml +++ b/assets/meta.xml @@ -102,6 +102,9 @@ + + + @@ -159,7 +162,7 @@ - + @@ -197,6 +200,8 @@ + + diff --git a/src/android/location/ILocationListener.java b/src/android/location/ILocationListener.java index 1ce0b5b7e..ffbf60ac0 100644 --- a/src/android/location/ILocationListener.java +++ b/src/android/location/ILocationListener.java @@ -5,9 +5,9 @@ public interface ILocationListener extends android.os.IInterface { void onLocationChanged(Location location); - void onProviderDisabled(String provider); + void onStatusChanged(String provider, int status, Bundle extras); void onProviderEnabled(String provider); - void onStatusChanged(String provider, int status, Bundle extras); + void onProviderDisabled(String provider); } diff --git a/src/biz/bokhorst/xprivacy/XPrivacy.java b/src/biz/bokhorst/xprivacy/XPrivacy.java index d786cf4f8..5f4286055 100644 --- a/src/biz/bokhorst/xprivacy/XPrivacy.java +++ b/src/biz/bokhorst/xprivacy/XPrivacy.java @@ -113,6 +113,9 @@ public void initZygote(StartupParam startupParam) throws Throwable { // System properties hookAll(XSystemProperties.getInstances()); + // Telephony registry + hookAll(XTelephonyRegistry.getInstances()); + // Thread hookAll(XThread.getInstances()); diff --git a/src/biz/bokhorst/xprivacy/XTelephonyManager.java b/src/biz/bokhorst/xprivacy/XTelephonyManager.java index 30f1edd44..59321714e 100644 --- a/src/biz/bokhorst/xprivacy/XTelephonyManager.java +++ b/src/biz/bokhorst/xprivacy/XTelephonyManager.java @@ -114,6 +114,8 @@ public static List getInstances(Object instance) { listHook.add(new XTelephonyManager(Methods.getSubscriberId, PrivacyManager.cPhone, className)); listHook.add(new XTelephonyManager(Methods.getVoiceMailAlphaTag, PrivacyManager.cPhone, className)); listHook.add(new XTelephonyManager(Methods.getVoiceMailNumber, PrivacyManager.cPhone, className)); + + listHook.add(new XTelephonyManager(Methods.listen, PrivacyManager.cLocation, className)); listHook.add(new XTelephonyManager(Methods.listen, PrivacyManager.cPhone, className)); // No permissions required diff --git a/src/biz/bokhorst/xprivacy/XTelephonyRegistry.java b/src/biz/bokhorst/xprivacy/XTelephonyRegistry.java new file mode 100644 index 000000000..5b6bc4840 --- /dev/null +++ b/src/biz/bokhorst/xprivacy/XTelephonyRegistry.java @@ -0,0 +1,189 @@ +package biz.bokhorst.xprivacy; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; + +import com.android.internal.telephony.IPhoneStateListener; + +import android.content.Context; +import android.os.Binder; +import android.os.Bundle; +import android.os.IBinder; +import android.telephony.CellInfo; +import android.telephony.PhoneStateListener; +import android.telephony.ServiceState; +import android.telephony.SignalStrength; +import android.util.Log; + +import de.robv.android.xposed.XC_MethodHook.MethodHookParam; + +import static de.robv.android.xposed.XposedHelpers.findField; + +public class XTelephonyRegistry extends XHook { + private Methods mMethod; + private static final Map mListener = new WeakHashMap(); + + private XTelephonyRegistry(Methods method, String restrictionName) { + super(restrictionName, method.name(), String.format("Srv.%s", method.name())); + mMethod = method; + } + + private XTelephonyRegistry(Methods method, String restrictionName, int sdk) { + super(restrictionName, method.name(), String.format("Srv.%s", method.name()), sdk); + mMethod = method; + } + + public String getClassName() { + return "com.android.server.TelephonyRegistry"; + } + + // @formatter:off + + // public void listen(String pkgForDebug, IPhoneStateListener callback, int events, boolean notifyNow) + // frameworks/base/services/java/com/android/server/TelephonyRegistry.java + // http://developer.android.com/reference/android/telephony/TelephonyManager.html + + // @formatter:on + + private enum Methods { + listen + }; + + public static List getInstances() { + List listHook = new ArrayList(); + listHook.add(new XTelephonyRegistry(Methods.listen, PrivacyManager.cLocation)); + listHook.add(new XTelephonyRegistry(Methods.listen, PrivacyManager.cPhone)); + return listHook; + } + + @Override + protected void before(MethodHookParam param) throws Throwable { + if (mMethod == Methods.listen) + replacePhoneStateListener(param); + else + Util.log(this, Log.WARN, "Unknown method=" + param.method.getName()); + } + + private void replacePhoneStateListener(MethodHookParam param) throws Throwable { + if (param.args.length > 2 && param.args[1] != null) { + IPhoneStateListener listener = (IPhoneStateListener) param.args[1]; + int event = (Integer) param.args[2]; + if (listener != null) + if (isRestricted(param)) { + if (event == PhoneStateListener.LISTEN_NONE) { + // Remove + synchronized (mListener) { + XIPhoneStateListener xlistener = mListener.get(listener); + if (xlistener == null) + Util.log(this, Log.WARN, "Not found count=" + mListener.size()); + else { + param.args[1] = xlistener; + mListener.remove(listener); + } + } + } else { + // Replace + XIPhoneStateListener xListener = new XIPhoneStateListener(listener); + synchronized (mListener) { + mListener.put(listener, xListener); + Util.log(this, Log.INFO, "Added count=" + mListener.size()); + } + param.args[1] = xListener; + } + } + } + } + + @Override + protected void after(MethodHookParam param) throws Throwable { + // Do nothing + } + + @Override + protected boolean isRestricted(MethodHookParam param) throws Throwable { + Context context = null; + + try { + Field fieldContext = findField(param.thisObject.getClass(), "mContext"); + context = (Context) fieldContext.get(param.thisObject); + } catch (NoSuchFieldError ex) { + } catch (Throwable ex) { + Util.bug(this, ex); + } + + int uid = Binder.getCallingUid(); + return getRestricted(context, uid, true); + } + + private class XIPhoneStateListener implements IPhoneStateListener { + private IPhoneStateListener mListener; + + public XIPhoneStateListener(IPhoneStateListener listener) { + mListener = listener; + } + + @Override + public void onCallForwardingIndicatorChanged(boolean cfi) { + mListener.onCallForwardingIndicatorChanged(cfi); + } + + @Override + public void onCallStateChanged(int state, String incomingNumber) { + mListener.onCallStateChanged(state, + (String) PrivacyManager.getDefacedProp(Binder.getCallingUid(), "PhoneNumber")); + } + + @Override + public void onCellInfoChanged(List cellInfo) { + mListener.onCellInfoChanged(new ArrayList()); + } + + @Override + public void onCellLocationChanged(Bundle location) { + mListener.onCellLocationChanged(new Bundle()); + } + + @Override + public void onDataActivity(int direction) { + mListener.onDataActivity(direction); + } + + @Override + public void onDataConnectionStateChanged(int state, int networkType) { + mListener.onDataConnectionStateChanged(state, networkType); + } + + @Override + public void onMessageWaitingIndicatorChanged(boolean mwi) { + mListener.onMessageWaitingIndicatorChanged(mwi); + } + + @Override + public void onServiceStateChanged(ServiceState serviceState) { + mListener.onServiceStateChanged(serviceState); + } + + @Override + public void onSignalStrengthChanged(int asu) { + mListener.onSignalStrengthChanged(asu); + } + + @Override + public void onSignalStrengthsChanged(SignalStrength signalStrength) { + mListener.onSignalStrengthsChanged(signalStrength); + } + + @Override + public void onOtaspChanged(int otaspMode) { + mListener.onOtaspChanged(otaspMode); + } + + @Override + public IBinder asBinder() { + return mListener.asBinder(); + } + } +} diff --git a/src/com/android/internal/telephony/IPhoneStateListener.java b/src/com/android/internal/telephony/IPhoneStateListener.java new file mode 100644 index 000000000..1cce84ce4 --- /dev/null +++ b/src/com/android/internal/telephony/IPhoneStateListener.java @@ -0,0 +1,34 @@ +package com.android.internal.telephony; + +import java.util.List; + +import android.os.Bundle; +import android.telephony.CellInfo; +import android.telephony.ServiceState; +import android.telephony.SignalStrength; + +public interface IPhoneStateListener extends android.os.IInterface { + void onServiceStateChanged(ServiceState serviceState); + + void onSignalStrengthChanged(int asu); + + void onMessageWaitingIndicatorChanged(boolean mwi); + + void onCallForwardingIndicatorChanged(boolean cfi); + + // we use bundle here instead of CellLocation so it can get the right + // subclass + void onCellLocationChanged(Bundle location); + + void onCallStateChanged(int state, String incomingNumber); + + void onDataConnectionStateChanged(int state, int networkType); + + void onDataActivity(int direction); + + void onSignalStrengthsChanged(SignalStrength signalStrength); + + void onOtaspChanged(int otaspMode); + + void onCellInfoChanged(List cellInfo); +}