短信攔截,如何搶先於QQ通訊錄,360

最近寫一個應用(A),需要攔截短信分析。一般是這樣實現的:註冊一個接受短信Intent-Filter,獲取短信廣播,分析短信內容然後相應處理。對特定短信終止廣播繼續(abort方法),阻止其進入收件箱。大致就是這麼一個過程。


但上述方式,在QQ通訊錄/360/飛信存在的情況下,攔截短信失敗~也就是說它們搶先拿到了收短信的廣播,並將其中斷了。那麼如何解決這個問題呢~


本來以爲騰訊是攔截ril層的消息,然後阻止廣播繼續,但是這種方式要修改framework才能實現。


後來發現存在廣播接收器(Receiver)的Intent-Filter的優先級(priority),SDK裏說Prioruty的範圍是-1000~1000,若設爲一千以上好像跟1000的效果一樣。然後我在A應用中的Manifest裏將Receiver的Intent-Filter優先級設爲1000,但測試結果還是被QQ通訊錄搶先。


進一步Google後,得到下面的結論:

反編譯QQ通訊錄/360手機衛士,發現些許奧祕。貌似這個涉及到Broadcast的分發機制,參考底層代碼應該比較好解釋~

廣播分爲2中,無序和有序。可以理解爲散列和隊列。


首先無序廣播,不能中斷,所有註冊相應Intent-Filter的Reciver都可以接收到~


其次是有序廣播,可以中斷。它的消息是按優先級傳送的,任何一個Receiver在接收後,可以使用abort將其停止,這樣就導致了後續的Receiver不能收到廣播。


下面是一個猜想,做了些測試,也基本符合~


假設廣播接收器的優先級都設爲最大整型2147483647,首先動態註冊優先級最高,其次是靜態註冊。在動態註冊中,最早註冊的優先級最高。在靜態註冊中,最早安裝的程序,優先級最高(注:安裝apk會解析af.xml,把其加入隊列)


在反編譯360後,發現其靜態註冊的廣播接收器裏設置的優先級數值爲2147483647,然後再廣播中啓動一個service,在service中註冊一個優先級爲2147483647的同樣地廣播接收器。也就是說,假設現在進程全殺,那麼短信來了,360和QQ通訊錄,誰先安裝,誰的靜態註冊廣播接收器就會先啓動,然後把廣播中斷,而且它還啓動了一個service又動態註冊一個Receiver。這樣,它的優先級就排在了所有靜態接收器之前了。


所以,我們做個試驗,以同樣的方式:

首先寫一個應用,註冊一個開機完成的Receiver

  1. <receiver android:name=".MyBrocast" android:permission="android.permission.BROADCAST_SMS">  
  2.              <intent-filter android:priority="2147483647">  
  3.                  <action android:name="android.provider.Telephony.SMS_RECEIVED" />  
  4.              </intent-filter>  
  5.              <intent-filter android:priority="2147483647">  
  6.                  <action android:name="android.intent.action.BOOT_COMPLETED" />  
  7.              </intent-filter>  
  8.  </receiver>  
  9.    
<receiver android:name=".MyBrocast" android:permission="android.permission.BROADCAST_SMS">
             <intent-filter android:priority="2147483647">
                 <action android:name="android.provider.Telephony.SMS_RECEIVED" />
             </intent-filter>
             <intent-filter android:priority="2147483647">
                 <action android:name="android.intent.action.BOOT_COMPLETED" />
             </intent-filter>
 </receiver>
 


然後再這個Receiver接收到開機廣播後,立即啓動一個service

  1. public void onReceive(Context context, Intent intent) {  
  2.    
  3.                 Log.v("MyBrocast.onReceive""testtttttttttttt");  
  4.    
  5.                 if(intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)){  
  6.    
  7.                         Intent service=new Intent(context, MyService.class);  
  8.    
  9.                         context.startService(service);  
  10.    
  11.                 }  
  12.    
  13. }  
public void onReceive(Context context, Intent intent) {
 
                Log.v("MyBrocast.onReceive", "testtttttttttttt");
 
                if(intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)){
 
                        Intent service=new Intent(context, MyService.class);
 
                        context.startService(service);
 
                }
 
}


然後在service中重新動態註冊一個Receiver,優先級爲2147483647

  1. IntentFilter localIntentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");  
  2.    
  3. localIntentFilter.setPriority(2147483647);  
  4.    
  5. MyBrocast localMessageReceiver =new MyBrocast();  
  6.    
  7. Log.v("MyBrocast.onReceive""onCreate");  
  8.    
  9. Intent localIntent = registerReceiver(localMessageReceiver, localIntentFilter);  
IntentFilter localIntentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
 
localIntentFilter.setPriority(2147483647);
 
MyBrocast localMessageReceiver =new MyBrocast();
 
Log.v("MyBrocast.onReceive", "onCreate");
 
Intent localIntent = registerReceiver(localMessageReceiver, localIntentFilter);


 

重啓手機就OK了,搶先360、QQ攔截短信~因爲360/QQ並沒有在接受開機廣播後,動態註冊短信廣播的接收器。這樣重啓後A應用就可以在它們之前攔截到短信了~


但上述搶先方式,付出的代價是,A應用需要一直有這麼一個service後臺運行。一旦被殺,優先權又回被360/QQ搶佔,只有等到下次重啓。除非A應用在QQ/360之前安裝到手機上~


總結一下:

具體的順~ 代碼動態註冊的Intent-Filter高於manifest靜態註冊的Intent-Filter。動態註冊中的Intent-Filter在相同優先級下(如整型的最大值),接受順序是按照動態註冊的時間順序。靜態註冊中Intent-Filter在相同優先級下,接受順序是apk的安裝順序。

發佈了2 篇原創文章 · 獲贊 4 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章