原文相续,书接上一回。
在《Android RIL层实现来电拦截的技术原理(一)》(以下简称《一》),已经详细分析了来电的在RIL层的逻辑走向,但缺少了一个强有力的DEMO作为验证。于是花了些时间,把DEMO也弄出来了,也验证了这个方案的技术可性性。在DEMO的开发过程中,也发现了一些在《一》中错误,等下会说明。
在《一》中,通过JAVA的反射机制,取出位于CallManager中的mIncomingRingRegistrants字段,再通过自定义的ProxyHandler,把定义在mIncomingRingRegistrants里的Handler替换掉,以实现“截获”这个动作。再回顾一下之前的代码实现:
class ProxyHandler extends Handler {
private Handler mInnter;
public ProxyHandler(Handler h){
mInnter = h;
}
@Override
public void handleMessage(Message msg) {
//做爱做的事
// ......
// ......
mInnter.handlerMessage(msg);
}
}
CallManager instance = CallManager.getInstance();
//通过反射,拿到其字段mIncomingRingRegistrants
RegistrantList mIncomingRingRegistrants = instance.mIncomingRingRegistrants;
for(int i=0; i<mIncomingRingRegistrants.size(); i++){
Registrant item = mIncomingRingRegistrants.get(i);
Handler handler = item.getHandler();
//通过反射,拿到其字段refH
item.refH = new WeakReference(new ProxyHandler(handler)); //完成注入
}
这里存在三个问题,如下:
1. ProxyHandler的构造函数,由于是在一个非Looper线程上执行,因为会发生异常,应该改 为
public ProxyHandler(Handler h){
super(h.getLooper);
mInnter = h;
}
确保我们的ProxyHandler是挂载到原来Handler的线程上。
2. Registrant 中的refH,类型WeakReference,即是说我们的ProxyHandler有可能被回收掉;
3. 通过修改mIncomingRingRegistrants只能监控EVENT_INCOMING_RING一种事件,但在整个来电流程中,是涉及多种事件处理的,因此并不能对整个流程进行把控;
因此需要再寻找其它地方进行注入。再回顾一下事件的流程走现,从RIL层开始,如下:
RIL$RILReceiver.run
RIL.readRilMessage
RIL.processResponse
RIL.processUnsolicited
Registrant.notifyRegistrant
Registrant.internalNotifyRegistrant
Handler.sendMessage
Handler.handleMessage
PhoneBase.handleMessage
PhoneBase.notifyIncmoingRing
RegistrantList.notifyRegistrants
RegistrantList.internalNotifyRegistrants
Registrant.internalNotifyRegistrant
Handler.sendMessage
Handler.handleMessage
CallManager.mHandler.handlerMessage(原来是CallManager.handlerMessage,分析有误)
RegistrantList.notifyRegistrants
RegistrantList.internalNotifyRegistrants
Registrant.internalNotifyRegistrant
Handler.sendMessage
Handler.handleMessage
CallNotifier.handleMessage
Ringer.ring(响铃)
...
之前提到的三个可注入点,这次我们选择第二个注入点,即替换CallManager.mHandler中的Handler,这样所有Phone的事件响应,都会经过我们的ProxyHandler(即蓝色的部分的流程),示意代码如下:
CallManager callmanager = CallManager.getInstance();
try{
Field field = CallManager.class.getDeclaredField("mHandler");
field.setAccessible(true);
List phones = new ArrayList(callmanager.getAllPhones()); //第一步,必须先拿到各个phone的引用
//第二步,然后遍历unregister。必须先unregister,然后才能进行第三步
//如果反过来操作,那unregister以及重新register都会有问题
for(Phone phone : phones){
Log.i("NNNN", "unregister phone: " + phone.toString());
callmanager.unregisterPhone(phone);
}
//第三步,通过反射,把CallManager中的mHandler替换到我们的ProxyHandler
Handler handler = (Handler) field.get(callmanager);
Log.i("NNNN", "org: " + handler.toString());
handler = new ProxyHandler(handler);
field.set(callmanager, handler);
handler = (Handler) field.get(callmanager);
Log.i("NNNN", "hook: " + handler.toString());
//第四步,重新注册。这里必须用往第一步的phones,而不是通过callmanager.getAllPhones()
//因为unregisterPhone和registerPhone会直接修改callmanager中的mPhones,因此第一步必须先保存各个phone的引用
for(Phone phone : phones){
Log.i("NNNN", "register phone: " + phone.toString());
callmanager.registerPhone(phone);
}
}catch(Exception e){
e.printStackTrace();
}
接下来是Demo的主要代码,主要是把各种事件打印出来,并且实现了一个很简单的“全拦截”功能,效果是手机没有任何闪屏、响铃或者振动现象。下面是修改后的ProxyHandler完整代码:
public final class ProxyHandler extends Handler {
private SparseArray mTable = new SparseArray();
private Handler mInnterHandler;
public ProxyHandler(Handler handler){
super(handler.getLooper());
mInnterHandler = handler;
mTable.put(100, "EVENT_DISCONNECT");
mTable.put(101, "EVENT_PRECISE_CALL_STATE_CHANGED");
mTable.put(102, "EVENT_NEW_RINGING_CONNECTION");
mTable.put(103, "EVENT_UNKNOWN_CONNECTION");
mTable.put(104, "EVENT_INCOMING_RING");
mTable.put(105, "EVENT_RINGBACK_TONE");
mTable.put(106, "EVENT_IN_CALL_VOICE_PRIVACY_ON");
mTable.put(107, "EVENT_IN_CALL_VOICE_PRIVACY_OFF");
mTable.put(108, "EVENT_CALL_WAITING");
mTable.put(109, "EVENT_DISPLAY_INFO");
mTable.put(110, "EVENT_SIGNAL_INFO");
mTable.put(111, "EVENT_CDMA_OTA_STATUS_CHANGE");
mTable.put(112, "EVENT_RESEND_INCALL_MUTE");
mTable.put(113, "EVENT_MMI_INITIATE");
mTable.put(114, "EVENT_MMI_COMPLETE");
mTable.put(115, "EVENT_ECM_TIMER_RESET");
mTable.put(116, "EVENT_SUBSCRIPTION_INFO_READY");
mTable.put(117, "EVENT_SUPP_SERVICE_FAILED");
mTable.put(118, "EVENT_SERVICE_STATE_CHANGED");
mTable.put(119, "EVENT_POST_DIAL_CHARACTER");
}
@Override
public void handleMessage(Message msg) {
if(msg.what >= 100 && msg.what <= 119){
Log.i("ProxyPhone", "Event: " + mTable.get(msg.what));
}
Phone phone = CallManager.getInstance().getAllPhones().get(0);
Call ringingCall = phone.getRingingCall();
String incomingNumber = null;
if (ringingCall != null && ringingCall.getEarliestConnection() != null) {
incomingNumber = ringingCall.getEarliestConnection().getAddress();
}
Log.i("ProxyPhone", "incomingNumber: " + incomingNumber);
if(incomingNumber != null){ //遇到有号码则直接返回
return;
}
mInnterHandler.handleMessage(msg);
}
@Override
public String toString() {
return "Proxy " + mInnterHandler.toString();
}
}
代码很简单,在此不做详细分析。
下面进行日志分析
来电,对方挂断:
10-31 10:54:03.748: I/ProxyPhone(5339): Event: EVENT_SERVICE_STATE_CHANGED
10-31 10:54:13.838: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:54:13.898: I/ProxyPhone(5339): Event: EVENT_IN_CALL_VOICE_PRIVACY_OFF
10-31 10:54:13.898: I/ProxyPhone(5339): Event: EVENT_NEW_RINGING_CONNECTION
10-31 10:54:13.898: I/ProxyPhone(5339): Event: EVENT_PRECISE_CALL_STATE_CHANGED
10-31 10:54:14.338: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:54:14.548: I/ProxyPhone(5339): Event: EVENT_PRECISE_CALL_STATE_CHANGED
10-31 10:54:14.678: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:54:14.888: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:54:15.078: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:54:15.408: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:54:15.598: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:54:15.888: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:54:16.078: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:54:16.398: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:54:16.608: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:54:21.568: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:54:21.728: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:54:22.058: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:54:22.208: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:54:22.588: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:54:22.668: I/ProxyPhone(5339): Event: EVENT_IN_CALL_VOICE_PRIVACY_OFF
10-31 10:54:22.758: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:54:23.008: I/ProxyPhone(5339): Event: EVENT_DISCONNECT
10-31 10:54:23.358: I/ProxyPhone(5339): Event: EVENT_PRECISE_CALL_STATE_CHANGED
来电,我方挂断:
10-31 10:57:12.478: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:57:12.568: I/ProxyPhone(5339): Event: EVENT_IN_CALL_VOICE_PRIVACY_OFF
10-31 10:57:12.568: I/ProxyPhone(5339): Event: EVENT_NEW_RINGING_CONNECTION
10-31 10:57:12.568: I/ProxyPhone(5339): Event: EVENT_PRECISE_CALL_STATE_CHANGED
10-31 10:57:13.198: I/ProxyPhone(5339): Event: EVENT_PRECISE_CALL_STATE_CHANGED
10-31 10:57:13.228: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:57:13.228: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:57:13.758: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:57:13.758: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:57:14.238: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:57:14.238: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:57:14.748: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:57:14.748: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:57:15.268: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:57:15.268: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:57:15.788: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:57:15.788: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:57:16.328: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:57:16.328: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:57:16.548: I/ProxyPhone(5339): Event: EVENT_PRECISE_CALL_STATE_CHANGED
10-31 10:57:16.678: I/ProxyPhone(5339): Event: EVENT_IN_CALL_VOICE_PRIVACY_OFF
10-31 10:57:16.688: I/ProxyPhone(5339): Event: EVENT_PRECISE_CALL_STATE_CHANGED
10-31 10:57:16.808: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:57:16.808: I/ProxyPhone(5339): Event: EVENT_INCOMING_RING
10-31 10:57:16.998: I/ProxyPhone(5339): Event: EVENT_DISCONNECT
10-31 10:57:17.248: I/ProxyPhone(5339): Event: EVENT_PRECISE_CALL_STATE_CHANGED
去电,我方挂断:
10-31 11:01:02.648: I/ProxyPhone(5339): Event: EVENT_PRECISE_CALL_STATE_CHANGED
10-31 11:01:02.648: I/ProxyPhone(5339): Event: EVENT_PRECISE_CALL_STATE_CHANGED
10-31 11:01:02.918: I/ProxyPhone(5339): Event: EVENT_IN_CALL_VOICE_PRIVACY_OFF
10-31 11:01:02.918: I/ProxyPhone(5339): Event: EVENT_IN_CALL_VOICE_PRIVACY_OFF
10-31 11:01:02.938: I/ProxyPhone(5339): Event: EVENT_PRECISE_CALL_STATE_CHANGED
10-31 11:01:02.938: I/ProxyPhone(5339): Event: EVENT_PRECISE_CALL_STATE_CHANGED
10-31 11:01:08.588: I/ProxyPhone(5339): Event: EVENT_IN_CALL_VOICE_PRIVACY_OFF
10-31 11:01:08.588: I/ProxyPhone(5339): Event: EVENT_PRECISE_CALL_STATE_CHANGED
10-31 11:01:15.068: I/ProxyPhone(5339): Event: EVENT_PRECISE_CALL_STATE_CHANGED
10-31 11:01:15.158: I/ProxyPhone(5339): Event: EVENT_IN_CALL_VOICE_PRIVACY_OFF
10-31 11:01:15.158: I/ProxyPhone(5339): Event: EVENT_PRECISE_CALL_STATE_CHANGED
10-31 11:01:15.468: I/ProxyPhone(5339): Event: EVENT_DISCONNECT
10-31 11:01:15.788: I/ProxyPhone(5339): Event: EVENT_PRECISE_CALL_STATE_CHANGED
去电,对方挂断:
10-31 11:03:21.258: I/ProxyPhone(5339): Event: EVENT_PRECISE_CALL_STATE_CHANGED
10-31 11:03:21.258: I/ProxyPhone(5339): Event: EVENT_PRECISE_CALL_STATE_CHANGED
10-31 11:03:21.528: I/ProxyPhone(5339): Event: EVENT_IN_CALL_VOICE_PRIVACY_OFF
10-31 11:03:21.528: I/ProxyPhone(5339): Event: EVENT_IN_CALL_VOICE_PRIVACY_OFF
10-31 11:03:21.548: I/ProxyPhone(5339): Event: EVENT_PRECISE_CALL_STATE_CHANGED
10-31 11:03:21.548: I/ProxyPhone(5339): Event: EVENT_PRECISE_CALL_STATE_CHANGED
10-31 11:03:27.298: I/ProxyPhone(5339): Event: EVENT_IN_CALL_VOICE_PRIVACY_OFF
10-31 11:03:27.298: I/ProxyPhone(5339): Event: EVENT_PRECISE_CALL_STATE_CHANGED
10-31 11:03:34.088: I/ProxyPhone(5339): Event: EVENT_IN_CALL_VOICE_PRIVACY_OFF
10-31 11:03:34.798: I/ProxyPhone(5339): Event: EVENT_IN_CALL_VOICE_PRIVACY_OFF
10-31 11:03:35.658: I/ProxyPhone(5339): Event: EVENT_PRECISE_CALL_STATE_CHANGED
10-31 11:03:35.758: I/ProxyPhone(5339): Event: EVENT_IN_CALL_VOICE_PRIVACY_OFF
10-31 11:03:35.758: I/ProxyPhone(5339): Event: EVENT_PRECISE_CALL_STATE_CHANGED
10-31 11:03:36.088: I/ProxyPhone(5339): Event: EVENT_DISCONNECT
10-31 11:03:36.438: I/ProxyPhone(5339): Event: EVENT_PRECISE_CALL_STATE_CHANGED
来电日志(打印incomingNumber):
10-31 14:42:17.829: I/ProxyPhone(13253): Event: EVENT_SERVICE_STATE_CHANGED
10-31 14:42:17.829: I/ProxyPhone(13253): incomingNumber: null
10-31 14:42:30.789: I/ProxyPhone(13253): Event: EVENT_INCOMING_RING
10-31 14:42:30.789: I/ProxyPhone(13253): incomingNumber: null
10-31 14:42:30.839: I/ProxyPhone(13253): Event: EVENT_IN_CALL_VOICE_PRIVACY_OFF
10-31 14:42:30.839: I/ProxyPhone(13253): incomingNumber: null
10-31 14:42:30.859: I/ProxyPhone(13253): Event: EVENT_NEW_RINGING_CONNECTION
10-31 14:42:30.859: I/ProxyPhone(13253): incomingNumber: 13512720516
10-31 14:42:30.859: I/ProxyPhone(13253): Event: EVENT_PRECISE_CALL_STATE_CHANGED
10-31 14:42:30.859: I/ProxyPhone(13253): incomingNumber: 13512720516
10-31 14:42:31.289: I/ProxyPhone(13253): Event: EVENT_INCOMING_RING
10-31 14:42:31.289: I/ProxyPhone(13253): incomingNumber: 13512720516
10-31 14:42:31.349: I/ProxyPhone(13253): Event: EVENT_INCOMING_RING
10-31 14:42:37.889: I/ProxyPhone(13253): incomingNumber: 13512720516
10-31 14:42:38.109: I/ProxyPhone(13253): Event: EVENT_DISCONNECT
10-31 14:42:38.109: I/ProxyPhone(13253): incomingNumber: 13512720516
10-31 14:42:46.669: I/ProxyPhone(13253): Event: EVENT_INCOMING_RING
10-31 14:42:46.669: I/ProxyPhone(13253): incomingNumber: 13512720516
10-31 14:42:46.729: I/ProxyPhone(13253): Event: EVENT_IN_CALL_VOICE_PRIVACY_OFF
10-31 14:42:46.729: I/ProxyPhone(13253): incomingNumber: 13512720516
10-31 14:42:46.749: I/ProxyPhone(13253): Event: EVENT_NEW_RINGING_CONNECTION
10-31 14:42:46.749: I/ProxyPhone(13253): incomingNumber: 13512720516
10-31 14:42:46.749: I/ProxyPhone(13253): Event: EVENT_PRECISE_CALL_STATE_CHANGED
10-31 14:42:46.749: I/ProxyPhone(13253): incomingNumber: 13512720516
10-31 14:42:47.189: I/ProxyPhone(13253): Event: EVENT_INCOMING_RING
10-31 14:42:52.189: I/ProxyPhone(13253): incomingNumber: 13512720516
10-31 14:42:52.259: I/ProxyPhone(13253): Event: EVENT_INCOMING_RING
10-31 14:42:52.259: I/ProxyPhone(13253): incomingNumber: 13512720516
10-31 14:42:52.489: I/ProxyPhone(13253): Event: EVENT_DISCONNECT
10-31 14:42:52.489: I/ProxyPhone(13253): incomingNumber: 13512720516
通过日志分析得出如下结论:
1. 来电过程中不断会有EVENT_INCOMING_RING事件;
2. 无论去电还是来电,无论对方还是我方,挂断都是EVENT_DISCONNECT事件;
3. 在EVENT_NEW_RINGING_CONNECTION事件发生后,能可以获取incomingNumber;
因此想更一步完善Demo,可以通过根据EVENT_NEW_RINGING_CONNECTION后,才去获取号码。由于Demo
在接下来的《三》里,我会进一步分析RIL的各种流程,以实现更多有趣的功能,大家敬请关注。