原文相續,書接上一回。
在《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的各種流程,以實現更多有趣的功能,大家敬請關注。