Android 5.0 Phone初始化分析


已經更新至個人blog:http://dxjia.cn/2015/07/android-5-0-phone-init-analysis/

persistent屬性

要想了解phone的框架,首先需要了解android app的persistent屬性。在AndroidManifest.xml定義中,application有這么一個屬性android:persistent,被android:persistent=”true”修飾的應用會在系統啟動之后被AM(ActivityManagerService)啟動。

AM首先在systemready后去PM(PackageManagerService)中查找設置了android:persistent的應用,代碼如下:

 

public void systemReady(final Runnable goingCallback) {
............

        synchronized (this) {
            if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
                try {
                    List apps = AppGlobals.getPackageManager().
                        getPersistentApplications(STOCK_PM_FLAGS);
                    if (apps != null) {
                        int N = apps.size();
                        int i;
                        for (i=0; i<N; i++) {
                            ApplicationInfo info
                                = (ApplicationInfo)apps.get(i);
                            if (info != null &&
                                    !info.packageName.equals("android")) {
                                addAppLocked(info, false, null /* ABI override */);
                           }
                        }
                    }
                } catch (RemoteException ex) {
                    // pm is in same process, this will never happen.
                }
            }
........

}

 

 

 

addAppLocked方法會檢測應用是否有起來,如果沒有將啟動,這樣persist屬性的應用就跑起來了。注意上面的判斷

!info.packageName.equals("android")

因為name為android的persist app是 framework-res,所以排除在外。

 

Android5.0中有persistent=true的模塊有下面幾個:

./packages/services/Telecomm/AndroidManifest.xml:            android:persistent="true"

./packages/services/Telephony/AndroidManifest.xml:                 android:persistent="true"

./packages/apps/Nfc/AndroidManifest.xml:                 android:persistent="true"

./frameworks/base/packages/FakeOemFeatures/AndroidManifest.xml:        android:persistent="true"

./frameworks/base/packages/Keyguard/AndroidManifest.xml:        android:persistent="true"

./frameworks/base/packages/SystemUI/AndroidManifest.xml:        android:persistent="true"

./frameworks/base/core/res/AndroidManifest.xml:                 android:persistent="true"

./hardware/intel/common/utils/ituxd/AndroidManifest.xml:    <application android:name=".ituxdApp" android:persistent="true">

 

 

跟Telephony框架有關的就是前面兩個,Telecom和Telephony,這兩個模塊的代碼位置及在手機中實際編譯出的apk如下:

./packages/services/Telecom                     priv-app/Telecom.apk

./packages/services/Telephony                    priv-app/Teleservice.apk

 

 

Teleservice模塊包含全部的PhoneApp及整個Phone框架,而Telecom主要是一些call相關的receiver、activity以及service等,看起來google是想把應用與Phone框架分的開一些,原先都是在一起的,只是從目前5.0的代碼來看,還只是弄了一小部分,估計是在進行中,可能后續版本這里還會有變化。

 

Phone框架/PhoneApp

從Teleservice模塊的manifest.xml里可以看出其實他目前還是叫做PhoneApp,這主要是因為之前一直以來Phone框架跟phone app是揉在一起的,估計等以后版本將Telecom和Telephony分的更開的時候,這里就不會叫這個名字啦。

    <application android:name="PhoneApp"

                 android:persistent="true"

                 android:label="@string/phoneAppLabel"

                 android:icon="@mipmap/ic_launcher_phone"

                 android:allowBackup="false"

                 android:supportsRtl="true">

 

我們先從PhoneApp的啟動看起

 

PhoneApp.java

(packages\services\telephony\src\com\android\phone)

  

  public void onCreate() {

        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();

        }

}

 

 

TelephonyGlobals 是5.0新增的,初步來看是跟賬戶控制以及tty有關的。后面再來研究他的作用,先看PhoneGloabals。

PhoneGloabals

PhoneGlobals繼承ContextWrapper,而且還是單例,提供全局性的信息,包含的信息很多,下面是其內部管理的關鍵實例,這些實例相互關聯才構建其手機的通信功能。

private static PhoneGlobals sMe;

CallController callController;

CallManager mCM;

CallNotifier notifier;

CallerInfoCache callerInfoCache;

NotificationMgr notificationMgr;

Phone phone;

PhoneInterfaceManager phoneMgr;

 

看其被PhoneApp.java調用的onCreate函數。

創建Phones

            // Initialize the telephony framework

            PhoneFactory.makeDefaultPhones(this);

 

 

使用工廠模式,創建phones,PhoneFactory提供的都是static方法,所有都是直接靜態調用。

首先看看PhoneFactory維護的本地變量:

    static private PhoneProxy[] sProxyPhones = null;

    static private PhoneProxy sProxyPhone = null;

 

    static private CommandsInterface[] sCommandsInterfaces = null;

 

    static private ProxyController mProxyController;

    static private UiccController mUiccController;

 

    static private CommandsInterface sCommandsInterface = null;

    static private SubInfoRecordUpdater sSubInfoRecordUpdater = null;

 

    static private boolean sMadeDefaults = false;

static private PhoneNotifier sPhoneNotifier;

 

 

可以注意到黃色部分,跟以往的版本比較,已經變成了數組了,這是因為google開始支持雙卡啦。。。啦啦啦。。。

1、             等待底層socket就緒,也就是init創建rild的socket完成;使用for循環+sleep的方式;

2、             創建PhoneNotifier以及獲取network mode和cdma subscription;

3、             獲取Phone個數設置

            /* In case of multi SIM mode two instances of PhoneProxy, RIL are created,

              where as in single SIM mode only instance. isMultiSimEnabled() function checks

              whether it is single SIM or multi SIM mode */

            int numPhones = TelephonyManager.getDefault().getPhoneCount();

            int[] networkModes = new int[numPhones];

            sProxyPhones = new PhoneProxy[numPhones];

            sCommandsInterfaces = new RIL[numPhones];

 

getPhoneCount()從setting設置中取

  

  /**

     * Returns the multi SIM variant

     * Returns DSDS for Dual SIM Dual Standby

     * Returns DSDA for Dual SIM Dual Active

     * Returns TSTS for Triple SIM Triple Standby

     * Returns UNKNOWN for others

     */

    /** {@hide} */

    public MultiSimVariants getMultiSimConfiguration() {

        String mSimConfig =

            SystemProperties.get(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG);

        if (mSimConfig.equals("dsds")) {

            return MultiSimVariants.DSDS;

        } else if (mSimConfig.equals("dsda")) {

            return MultiSimVariants.DSDA;

        } else if (mSimConfig.equals("tsts")) {

            return MultiSimVariants.TSTS;

        } else {

            return MultiSimVariants.UNKNOWN;

        }

}

 

 

4、             創建對應數量的RIL實例

 

for (int i = 0; i < numPhones; i++) {

//reads the system properties and makes commandsinterface

sCommandsInterfaces[i] = new RIL(context, networkModes[i], cdmaSubscription, i);

}

 

5、             初始化 SubscriptionController 和UiccControler,這兩個都是單例設計,這里創建好后,別的地方只需要getInstance進行調用

6、             創建Phone實例並保存

                for (int i = 0; i < numPhones; i++) {

                    PhoneBase phone = null;

                    int phoneType = TelephonyManager.getPhoneType(networkModes[i]);

                    if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {

                        phone = new GSMPhone(context,

                                sCommandsInterfaces[i], sPhoneNotifier, i);

                    } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {

                        phone = new CDMALTEPhone(context,

                                sCommandsInterfaces[i], sPhoneNotifier, i);

                    }

                    Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " sub = " + i);

 

                    sProxyPhones[i] = new PhoneProxy(phone);

                }

 

7、             創建ProxyControler

mProxyController = ProxyController.getInstance(context, sProxyPhones,

                        mUiccController, sCommandsInterfaces);

ProxyController也是5.0新增的,其作用是進行雙卡控制,內部實例化對icccard dct(data connction) phonebook 以及sms這些跟卡關系比較密切的功能,如下:

mDctController = DctController.makeDctController((PhoneProxy[])phoneProxy);

mUiccPhoneBookController = new UiccPhoneBookController(mProxyPhones);

mPhoneSubInfoController = new PhoneSubInfoController(mProxyPhones);

mUiccSmsController = new UiccSmsController(mProxyPhones);

 

這些實例化的功能,會在各自的構造函數中將接口addService到servicemanager以便供APP調用。實現機制為binder.

比如UiccSmsController,這里是單實例的,但其內部接口使用帶subid參數的方式來支持雙卡

8、             獲取默認SMS應用

主動調用一次 SmsApplication.getDefaultSmsApplication(context, true );注意第二個參數為true,也就是如果手機沒有獲取到默認sms app,那么會嘗試去設定一個。設定的規則如下:

l  首先嘗試從用戶指定的默認app,對應的系統setting key為:sms_default_application;

l  其次看是否有goole的官方 默認sms app;

l  如果以上兩個都沒有,那么就從PM中獲取所有注冊有完整sms有關的broadcast receiver的app,從中找一個優先級最高的,並將其設定為default app。

9、             監控短信DefaultApp的變動

10、          監控Subscription的變化,跟卡有關,用來控制整個FW層對雙卡的區分。相關的幾個類是:SubscriptionManager  SubscriptionController  SubInfoRecordUpdater,管理default subid等,其default的策略是第一個檢測到的可用卡id;當然接口是Public的,也就是暴漏出來的,是可以在需要的地方進行setDefault來改變這個設定的,這些值最終都保存在setting數據庫中。

至此,PhoneFactory.makeDefaultPhones完成,接下來再回到PhoneGlobals...

 

Default Phone

 

            // Get the default phone

            phone = PhoneFactory.getDefaultPhone();

 

 

上面創建完phones之后,接下來就取出一個defaultphone,這里說明一下default phone的設定,第一次在PhoneFactory中創建出phones之后,將實例保存在數組里,   

static private PhoneProxy[] sProxyPhones = null;  //用於保存創建的Phones

static private PhoneProxy sProxyPhone = null;   //用於保存default phone

 

 

sProxyPhone的第一次賦值只是簡單的取 sProxyPhones[0],但PhoneFactory提供了接口,可以對這個default phone進行設定,接口為:setDefaultSubscription(int subId);當然其內部會根據雙模的具體情況進行決策,比如如果是雙模單通(同一時間只有一個active),那么default phone會自動設定成那個active的,如果是雙模雙通,那么就設定成參數值int subId(當然會將subid轉換為對應的Phoneid,也就是sProxyPhones數組下標)。

 

創建關鍵實例

接下來在PhoneGlobals中會創建很多關鍵實例,依次是:

CallManager

NotificationMgr

PowerManager

KeyguardManager

CallLogger

CallGatewayManager

CallController

CallerInfoCache

BluetoothManager

PhoneInterfaceManager

CallNotifier

 

 

雙模通道打通

上面的初始化過程結束之后,其實已經對各模建立起來各自的通道,盡管5.0還沒有徹底支持完整,還是以一個例子來描述流程:

PhoneInterfaceManager是一個servcie,App可以遠程訪問其內部的接口,以下面這個接口為例,其實現中提供了一些以subId作為參數的接口,subId是long型,你可以把它看作是卡的身份標識,具體獲得過程以后再分析。

    public void toggleRadioOnOffForSubscriber(long subId) {

        enforceModifyPermission();

        getPhone(subId).setRadioPower(!isRadioOnForSubscriber(subId));

}

 

GetPhone(subId)會獲取到對應的Phone實例,並調用對應phone實例的setRadioPower接口,可惜這里5.0還沒有進行實現,只是簡單的return defaultPhone

    // returns phone associated with the subId.

    // getPhone(0) returns default phone in single SIM mode.

    private Phone getPhone(long subId) {

        // FIXME: hack for the moment

        return mPhone;

        // return PhoneUtils.getPhoneForSubscriber(subId);

    }

前面說過了,會根據phone的個數創建對應數量的RILJ實例,也就是CommandInterface實例,並傳給具體的Phone實例,CDMAPhone或GsmPhone,而各自的RILJ實例在初始化的時候,又會自動鏈接上RILD的對應socket[RILD由init進程啟動,並根據init.rc里的設定創建對應的socket],那么各自的phone跟底層modem的通信就建立了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM