Android 5.0 Default SMS App以及運營商受權SMS App

已同步更新至我的bloghttp://dxjia.cn/2015/08/android-5-default-sms-app/android

 

 

題外話:博友們有沒有好用的寫博客客戶端推薦啊,cnblogs推薦的windows live writer和word都試過,都不是很好用啊,本地看着還能夠,但發佈出來排版就不是那麼好看了。數據庫

 

正題:windows

  Android中短信的接收是這樣的一個過程:緩存

  底層先將短信報給FW,FW處理事後,會將短信經過intent廣播的形式廣播出來,而註冊了接收短信廣播的APP們,就能收到並處理短信app

Default SMS App

  而android在4.2開始,對操做SMS的app進行了限制,增長了default sms app的概念,只有default app才能夠操做短信,並且default sms app能夠由用戶來指定。框架

  先來看看整個系統初始化時,是如何來初始化default sms app的:函數

  依然在FW的phone框架初始化裏,PhoneFactory. makeDefaultPhoneui

首先調用一次SmsApplication.getDefaultSmsApplication方法,而且指定第二個參數updateIfNeeded爲true,就是若是沒有設置過就自動指定一個。url

關於getApplication函數我在 《Android 5.0 雙模phone初始化分析》 一文中有講到,其指定default SMS App的規則:spa

  • 首先嚐試從用戶指定的默認app,對應的系統setting key爲:sms_default_application;
  • 其次看是否有Google的官方 默認sms app;
  • 若是以上兩個都沒有,那麼就從PM中獲取全部註冊有完整sms有關的broadcast receiver的app,從中找一個優先級最高的,並將其設定爲default app。

  default sms app的值保存在setting db中, Settings.Secure.SMS_DEFAULT_APPLICATION

固然,SmsApplication也提供了set方法來讓用戶能夠手動設置他想使用的default sms app

 

  另外,在PhoneFactory初始化裏咱們還看到在調用一次getDefaultSmsApplication後,還調用了另一個方法:

  這個方法會監聽應用程序的安裝與卸載,並在有應用被安裝或者移除的時候,可以及時自動更新default sms app,已保證default sms app是隨時都有設定的。

 

運營商受權SMS App

  後來的版本,android又增長了運營商受權SMS App的實現,原則是若是全部的sms app裏,若是有一個是運營商受權指定的短信處理app,那麼它就會有第一優先級,無論default app設定的是誰,都會只使用這個受權app來收發和管理顯示短信。

  那麼這個運營商受權APP是在哪裏指定的呢?答案是:是固化在icc卡里的,也就是運營商給你的手機卡(no-uim和no-sim的手機目前是處理不了的),卡在出廠的時候,會在卡里的某個固定單元文件寫上受權app的package name以及其簽名hash校驗值,在卡初始化完成後讀取這些值解析後保存,若是手機裏有這個package name的app,而且簽名hash也一致,那麼就說明該App是運營商受權sms app。

  完成這些信息初始化的類爲 UiccCarrierPrivilegeRules,其內部完成對卡上文件進行讀取和解析,保存信息,並提供對外接口。

由於跟卡直接相關,因此UiccCarrierPrivilegeRules在UiccCard被建立後初始化。

  在UiccCard.update()函數裏建立:

UiccCarrierPrivilegeRules

  先看看該類的class註釋,

  在構造函數中開啓讀取文件的流程,事件驅動。

 

  註釋裏對該類的功能進行了講解,並且給出了使用到的icc card文件讀取和解析的spec規範文檔 GPD_SE_Access_Control_v1.0.20.pdf,惋惜他給的連接無效了,能夠在百度文庫上找到該spec,地址: GPD_SE_Access_Control_v1.0.20.pdf

  具體讀取icc文件和解析這裏就不分析了,都是依照spec的實現。只說明下幾個接口和內部變量:

AccessRule

內部類,用來保存解析到的rules,內部維護單個rule的package name和簽名hash值。

List<AccessRule> mAccessRules;

保存全部的rules在list,看來能夠支持多個運營商指定app

areCarrierPriviligeRulesLoaded()

是否已經準備好

getCarrierPrivilegeStatus()

驗證指定的package name的app是否有運營商受權

getCarrierPrivilegeStatusForCurrentTransaction()

驗證當前進程裏是否存在有運營商受權的app(多個app能夠經過共享id的形式運行在同一個進程裏)

getCarrierPackageNamesForIntent()

經過從package manager中取出全部符合傳入的Intent的app,也就是取出全部能夠處理傳入的Intent的app,並檢查這些app裏是否有符合運營商受權的,並返回符合的list

具體使用示例

  以一條新短信的接收爲例:

  在InboundSmsHandler裏的processMessagePart()函數中,processMessagePart()函數用來將緩存的短信分段進行組裝,若是已經收全,就會將短信廣播出去,固然,若是是單段的獨立短信該函數也就直接廣播了,來看打包Intent廣播的部分:

  注意上面代碼中黃色高亮的部分,首先是新建一個intent,而這個intent的action直接指定爲Intents.SMS_FILTER_ACTION?這個是什麼鬼,之前沒見過啊。。。跳轉過去:

  註釋已經很清晰明瞭了,這個action只會發送給carrier app,並且carrier app能夠經過set result爲RESULT_CANCELED來終止這個廣播,這樣別的app就永遠沒有機會收到這個廣播了。

  回到以前的打包intent的代碼,其會去UiccCard裏經過 getCarrierPackageNamesForIntent()方法來獲得能夠處理SMS_FILTER_ACTION的符合運營商受權的app name list,若是能取到,那麼就將intent的目標package直接設定爲那個app,這樣這個短信廣播就只會發送給這個受權app;

intent.setPackage(carrierPackages.get(0));

  而若是沒有運營商受權app,那麼就會調用setAndDirectIntent (intent, destPort);來設定廣播app,這裏才輪到default sms app:

  短信的desPort都是-1,因此能夠只看上面這個if分支,首先先將intent的action修改成 Intents.SMS_DELIVER_ACTION, 這個是android的新短信常規intent action,頂替掉以前的SMS_FILTER_ACTION;而後經過getDefaultSmsApplication獲取到default sms app,若是能取到,那麼經過intent.setComponent(componentName)設置目標package爲這個app,若是沒有,那麼就setComponent(null),這樣就能夠廣播給全部能夠接收SMS_DELIVER_ACTION的app。

 

另外,提一點另外的細節,打包廣播短信的地方:

  dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS,

  AppOpsManager.OP_RECEIVE_SMS, resultReceiver, UserHandle.OWNER);

  第4個參數,傳入的resultReceiver,是個內部類SmsBroadcastReceiver對象,用來處理短信廣播的結果,對每種intent action廣播出去以後的處理結果都有分別處理,如從緩存數據庫總刪除短信、更新短信內容等。也用來若是發出去的廣播沒人處理,則使用最低級的SMS_RECEIVED_ACTION從新將廣播廣播出去等機制。。

 

總結

  FW初始化時,首先嚐試設定一個default sms app,同時,在卡槽的icc卡準備好後,開始讀取卡上的運營商受權app數據,並保存下來;新短信接收時首先經過接口獲取到運營商受權app,若是沒有,再經過接口獲取到default sms app,若是尚未,就直接廣播啦。

  運營商受權app的優先級大於default sms app。

相關文章
相關標籤/搜索