標籤:
同上篇文章一樣,這裡只陳述結果,程式碼分析稍後給出
導讀:本文敘述如何先於某些偽殺毒軟體、病毒、常規軟體擷取到簡訊
眾所周知,android系統在收到簡訊息的時候會發送廣播,但是此廣播是有序廣播,也就是說:先接收到廣播的人,如果心情不好,它就不會向後傳遞此廣播,後面的人就不會知道有簡訊到來
這與無序廣播不同,無序廣播並不是真的沒有順序(只是似乎大家習慣這麼叫而已),無序廣播的接收者也是排隊等待廣播的,只不過是在傳遞過程中,大家必須遵守規則,一直把訊息傳遞給最後一個人才可以
關於無序廣播與靜態接收器搭配的接收順序,上一篇文章已經說的很清楚了
由於開機之後程式都沒有開始運行,所以想自動運行必須要接收
現在我們看看程式啟動之後的情況,我以大家關心的接收短訊息為例
想要在程式中接收簡訊,就要接收如下廣播
android.provider.Telephony.SMS_RECEIVED
系統把它作為有序廣播進行發送,那麼,誰第一個接收到簡訊將變得至關重要, 無論你是殺毒軟體、偽殺毒軟體、病毒還是普通程式
之前說過靜態接收器的接收順序
那麼動態接收器和靜態接收器相比呢?
如果是接收靜態廣播
答案是靜態接收器優先順序低於動態接收器,也就是說,無論多麼進階別的靜態接收器和多麼低層級的動態接收器都接收同一廣播,永遠都是動態接收器先接收到!
動態接收器是在代碼中設定的,所以,我們需要先啟動程式,才能接收廣播,這也是我們無法用它接收開機廣播的原因
如果是接收動態廣播
同優先順序的,動態接收器先接收到廣播,靜態後接收到
同樣的,動態接收器也可以設定優先權,高優先順序的接收器會在低優先順序的接收器之前接收到廣播
那麼,同樣優先順序的動態接收器,接收廣播的順序是怎樣的呢?
幸好,他們的規則與靜態接收器的規則不同
同樣優先順序的動態接收器,誰先註冊到系統,誰就搶先接收到廣播
上面雖然完全只是文字敘述,但我相信,大家也是看明白了的
下面總結一下,如何能保證自己的程式搶先於其他程式接收到簡訊
1.根據上一篇文章的做法,保證自己先於其他程式啟動
2.啟動第一個事情就要開啟服務,動態註冊廣播,並把優先順序設定為最高
代碼實現也非常簡單
一個接收器
private DynamicReceiver dynamicReceiver = new DynamicReceiver();public class DynamicReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { Log.e(SmsUtil.TAG, "dynamic receiver"); String action = intent.getAction(); if(SmsUtil.SMS_ACTION.equals(action)){ context.startService(SmsUtil.getIntent(context, MainService.class, intent, "dynamic receiver")); } }}
動態註冊
public static final String SMS_ACTION = "android.provider.Telephony.SMS_RECEIVED";IntentFilter intentFilter = new IntentFilter(SMS_ACTION);intentFilter.setPriority(Integer.MAX_VALUE);registerReceiver(dynamicReceiver, intentFilter);
最後總結一下,接收器接收廣播的順序
之前由於受之前記憶的影響,下了錯誤的結論,抱歉給大家帶來了困擾
後來整理原理的時候,仔細閱讀源碼才發現,特此糾正一下
普適原則
同等優先順序的動態接收器,先註冊的先接收
同等優先順序的靜態接收器,接收廣播的順序與String[] java.io.File.list()順序一致
ordered廣播
假設有如下優先順序的5個接收器
1.動態A(優先順序=1)
2.動態B(優先順序=2)
3.動態C(優先順序=2)
4.靜態D(優先順序=1)
5.靜態E(優先順序=2)
並且B先於C註冊
那麼實際接收順序應為
B C E A D
也就是說,如果靜態接收器的優先順序高於動態接收器的優先順序,那麼還是靜態接收器先接收到廣播(比如接收簡訊)
非ordered廣播
動態接收器高優先順序 > 動態接收器低優先順序 > 靜態接收器高優先順序 > 靜態接收器低優先順序
結束之前說點題外話
有些廣播,我們無法用靜態接收器接收
比如ACTION_SCREEN_ON,當螢幕被點亮的時候系統發送此廣播
如果你嘗試在manifest中註冊receiver來接收,那麼會失敗,這是為什麼呢
我們來看看系統是如何發送此廣播的
void com.android.server.PowerManagerService.initInThread()
void initInThread() { …… mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON); mScreenOnIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF); mScreenOffIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); ……}
他們在Intent中都設定了Intent.FLAG_RECEIVER_REGISTERED_ONLY,所以,如果要接收,必須動態註冊廣播接收器
ACTION_SCREEN_OFF也是如此
(這段說明應該放的之前的android安全問題(三) 釣魚程式 中,現在補上)
關於FLAG_RECEIVER_REGISTERED_ONLY的說明
public static final int FLAG_RECEIVER_REGISTERED_ONLYAdded in API level 1
If set, when sending a broadcast only registered receivers will be called -- no BroadcastReceiver components will be launched.
Constant Value: 1073741824 (0x40000000)
在來看一個廣播,ACTION_BATTERY_CHANGED
電池電量發生變化的時候,系統發送此廣播
void com.android.server.BatteryService.sendIntent()
private final void sendIntent() { // Pack up the values and broadcast them to everyone Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_REPLACE_PENDING); ……}
所以我們必須動態接收
Android安全問題 搶先攔截簡訊