需求
Android多用戶下,要讓每個用戶都能看到移動網絡相關設置(首先網絡類型/APN等)。
現狀
- Android默認的多用戶實現中,只有主用戶(primary user)是可以看到的,如果新建一個另外的用戶,則沒有權限去看這些東西,參見WirelessSettings.java中的判斷(boolean isSecondaryUser = myUserId != UserHandle.USER_OWNER;如果是SecondaryUser,則不顯示相關設置)。
- Primary user即user 0,是指開機進入的那個用戶,這個用戶的權限是最高的,framework,phone和其他的所有core service都是在這個用戶下創建和初始化的。
- 無線相關(即phone對象和無線相關的服務),PhoneApp初始化的時候,會判斷是否在primary user(見下面),如果是user 0,那么會初始化這些對象;如果非0用戶,則會在此用戶創建一個新的空實現的Phone對象,因為在oncreate里面什么都沒做。所以不能在另外的用戶中直接調用phone相關的對象。
if (UserHandle.myUserId() == 0) {
// We are running as the primary user, so should bring up the
// global phone state.
mPhoneGlobals = new PhoneGlobals(this);
mPhoneGlobals.onCreate();
mTelephonyGlobals = new TelephonyGlobals(this);
mTelephonyGlobals.onCreate();
}
方案
針對“現狀”中描述的情況,我們要在非primary user中顯示無線相關的信息,我們需要一個途徑來獲得我們需要的信息。有兩個解決辦法:
- 放開PhoneApp對于用戶的限制,在非primary user中也初始化好phone相關對象。
- 通過擴展primary user中的phone service來讓其他用戶獲得相關信息。
評估
方案1:在非primary user中也初始化phone相關對象。由于phone對象作為核心對象,從中初始化了很多其他相關的對象(例如sim卡,RIL等),這樣就涉及從上到下要全部打通才行,難度頗大。尤其是Android5.1-7.1中phone重構頗多,這個作為終極解決方案,但是在時間緊迫的前提下,我們只是簡單嘗試,沒事深入,感覺坑很多。后續會繼續探索,爭取在最新的安卓版本上搞定這個大事哈。感興趣的可以參考下面的鏈接,作者是在android4.2上做的,基本思路也是一致的。剩下的工作就是安卓版本差異上帶來的難度。
《android源碼探索----多用戶下phone進程問題》
http://blog.csdn.net/stephen8341/article/details/38079679
方案2:擴展“phone” service,讓其他user可以訪問到相關信息即可,畢竟只是setting展示,基本上需要的就是phone id/sub id之類的。這是個取巧的辦法,不完善,是在時間和項目的壓力下,妥協的方案。
方案2的實現
user 0中已經在開機的時候啟動的phone service(packages/services/Telephony/src/com/android/phone/PhoneInterfaceManager.java 的publish()函數),
private void publish() {
if (DBG) log("publish: " + this);
ServiceManager.addService("phone", this);
}
在其他user中需要使用的時候,通過如下方法調用
ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
我們的做法就是擴展這個phone service,需要改動如下幾個文件:
- frameworks/base/telephony/java/com/android/internal/telephony/ITelephony.aidl 定義service提供的函數的aidl,把擴展的函數加進去
- packages/services/Telephony/src/com/android/phone/PhoneInterfaceManager.java 這個ITelephoy.aidl的實現
- 對于要回傳結果的場景,例如設置網絡,新建ITelephonyAdapter.aidl文件,定義回掉接口。并把這個aidl加入到framework/base下的Android.mk文件中,保證系統會編譯這個文件。
- 添加ITelephonyAdapter.aidl的實現文件TelephonyAdapter.java
- 剩下的就是判斷當前user,如果是非主用戶,通過service取相關信息,然后顯示相關UI。
總結
這里只是記錄一下解決問題的思路,思路對了,再慢也會完成相關功能。如果一開始就選了一個走不通的路,那么再努力也是徒勞。