天天看點

OHOS标準系統的SAMGR代碼解讀(v3.1)--2--samgrOHOS标準系統的SAMGR代碼解讀(v3.1)--2--samgr

::: hljs-center

OHOS标準系統的SAMGR代碼解讀(v3.1)--2--samgr

梁開祝 20220907

:::

前文:

OHOS标準系統的SAMGR代碼解讀(v3.1)--0--前言

OHOS标準系統的SAMGR代碼解讀(v3.1)--1--safwk

  OHOS标準系統的samgr元件位于3.1分支代碼的//foundation/distributedschedule/samgr/目錄下,在最新的master分支代碼則是//foundation/systemabilitymgr/samgr/目錄下。

1. samgr 元件的全景圖

先看samgr元件的全景圖(附件有大圖)

從上圖中的代碼目錄結構和編譯腳本部分,可以看到5個編譯目标以及它們各自編譯的代碼:

  • samgr_common:公共部分,提供SA Profile的解析工具、動态連結庫的加載和解除安裝等功能,主要用在上一篇分析的safwk的工作流程中,本文不再贅述。
  • lsamgr:local samgr的用戶端代理,主要用于按需啟動指定的SA;該功能也同時編譯進samgr_proxy子產品中(一并在samgr_proxy中分析)。
  • samgr_proxy:samgr的用戶端代理。SA通過該代理提供的接口與samgr服務進行互動,同時也為samgr服務向SA用戶端回報SA的加載結果、訂閱的SA的狀态變化等功能提供Stub接口。
  • samgr_init:samgr服務自啟動的配置檔案,與samgr可執行程式配套使用。
  • samgr:samgr服務的可執行程式實體,結合samgr_init的配置,在系統啟動的早期自動運作,拉起samgr服務。同時也通過Proxy向SA用戶端回報SA的加載結果、訂閱的SA的狀态變化事件等消息。

全景圖中雖然畫出了IPC相關的結構,但本文暫不深入IPC/RPC的分析,是以,下文重點看samgr服務的實作和samgr_proxy用戶端的實作。

2. samgr 服務的啟動流程

  samgr服務在OHOS系統中幾乎是最早啟動的系統服務,它在OHOS中占據了通信中樞的重要位置(可以參考我分析的samgr_lite系列文章來進行了解)。

  samgr服務的啟動流程如全景圖左下角部分所示,看起來還是比較簡單的。

  在完成 SystemAbilityManager 類對象manager的建立和Init()之後,就生成了全景圖右下角部分所示的結構;然後通過IPCSkeleton::SetContextObject()将 manager 作為遠端對象注冊到IPC子產品,為以後的IPC/RPC提供IRemoteObject;最後samgr服務的主線程進入loop,開始為整個系統中的SA提供服務。

接下來的内容,請結合samgr元件的全景圖和下面的IPC互動示意圖進行了解。

OHOS标準系統的SAMGR代碼解讀(v3.1)--2--samgrOHOS标準系統的SAMGR代碼解讀(v3.1)--2--samgr

3. samgr 服務端的類結構

  samgr 服務端主要的類結構和繼承關系,見全景圖的右下角以ohos_executable("samgr")為起點的部分。

3.1 SA死亡回調相關的成員和RPC回調相關的成員

  在 SystemAbilityManager::Init() 中建立并初始化的與SA死亡回調相關的成員、RPC回調相關的成員,這裡先放下不說,請小夥伴先自行閱讀代碼了解。

3.2 SystemAbilityLoadCallbackProxy 和 SystemAbilityStatusChangeProxy

  在 SystemAbilityManager 類提供的服務中,samgr會根據需要調用相關的接口向samgr_proxy發送IPC消息,以此向Proxy回報SA的加載狀态、上線離線狀态等資訊,見4.2節的簡介。

3.3 SystemAbilityManagerStub 和 SystemAbilityManager

  samgr服務端的主要工作在這兩個類中。

  在samgr程序啟動過程中建立SystemAbilityManager對象時,在SystemAbilityManagerStub的構造函數中就會初始化一個 memberFuncMap_,将Stub要處理的消息代碼與處理函數關聯起來。

  SystemAbilityManagerStub在接收到SystemAbilityManagerProxy發過來的IPC消息後,直接在memberFuncMap_中比對消息代碼,然後轉為調用子類SystemAbilityManager的函數來做具體的服務工作,如有需要也會把處理結果傳回給SystemAbilityManagerProxy。

  3.1和3.2中的工作,也是由SystemAbilityManager類發起調用或者直接進行處理的。

4. samgr_proxy的類結構

  samgr_proxy相關的類結構和繼承關系,見全景圖的中以ohos_shared_library("samgr_proxy")為起點的部分。

4.1 LocalAbilityManagerProxy

  LocalAbilityManagerProxy類提供了向指定程序發送IPC消息拉起按需啟動的SA的Proxy接口,由指定程序中的LocalAbilityManagerStub接收消息,并執行動态拉起SA的具體動作(如上一篇分析4.3節分析所示)。

  例如,不管是同裝置内的程序還是跨裝置的程序,在調用:

sptr<IRemoteObject> SystemAbilityManager::CheckSystemAbility(int32_t systemAbilityId, bool& isExist)
           

向samgr查詢SA時,samgr會先在已啟動的 abilityMap_ 中查找目标SA,能找到,則表明SA已經啟動了;找不到,則繼續在正在啟動的 startingAbilityMap_ 中查找目标SA,能找到,則表明SA正在啟動中;還找不到,則會嘗試調用StartOnDemandAbility(SAID)來啟動目标SA(即按需啟動SA)。StartOnDemandAbility(SAID)會在登記到onDemandAbilityMap_中的按需啟動的SA清單中查找比對SAID的記錄,并通過SystemAbilityManager::StartOnDemandAbilityInner()向SAID所在程序發送IPC消息,要求該程序拉起對應的SA,如下代碼片段所示:

void SystemAbilityManager::StartOnDemandAbilityInner(const std::u16string& procName, int32_t systemAbilityId,
    AbilityItem& abilityItem)
{
    ......
    //從 systemProcessMap_ 中擷取 LocalAbilityManagerProxy procObject
    sptr<ILocalAbilityManager> procObject =
        iface_cast<ILocalAbilityManager>(GetSystemProcess(procName));
    ......
    //調用 LocalAbilityManagerProxy::StartAbility 
    //向 LocalAbilityManagerStub 發送IPC消息拉起參數指定的SA
    procObject->StartAbility(systemAbilityId);
    ......
}

           

4.2 SystemAbilityLoadCallbackStub 和 SystemAbilityStatusChangeStub

  當程序A向samgr注冊SA_a時,samgr會調用:

void SystemAbilityManager::SendSystemAbilityAddedMsg(int32_t systemAbilityId, const sptr<IRemoteObject>& remoteObject)
{
    ......
    auto notifyAddedTask = [systemAbilityId, remoteObject, this]() {
        FindSystemAbilityNotify(systemAbilityId, ADD_SYSTEM_ABILITY_TRANSACTION);
        NotifySystemAbilityLoaded(systemAbilityId, remoteObject);
    };
    bool ret = workHandler_->PostTask(notifyAddedTask);
    ......
}
           

  其中的FindSystemAbilityNotify()會在 listenerMap_ 中查找監聽SA_a狀态變化的監聽者,并調用listener的回調函數,通過SystemAbilityStatusChangeProxy向SystemAbilityStatusChangeStub發送SA_a上線或離線的消息。listener所在的程序B、程序C......的SystemAbilityStatusChangeStub就可以收到該消息并做針對性地處理。

  其中的NotifySystemAbilityLoaded()也會通過SystemAbilityLoadCallbackProxy向SystemAbilityLoadCallbackStub 發送SA_a加載成功的IPC消息到查詢SA_a的程序B中,這樣程序B中的SystemAbilityLoadCallbackStub 就可以收到該消息并做針對性地處理。

4.3 SystemAbilityManagerProxy和 SystemAbilityManagerClient

  程序A必須要通過代理才能與samgr進行互動(如注冊SA、查詢SA等)。

  如程序A在啟動SA_a時,必須要先通過CheckSystemAbilityManagerReady() 确認samgr可以通路:

bool LocalAbilityManager::CheckSystemAbilityManagerReady()
{
    ......
    //擷取samgr的代理:SystemAbilityManagerProxy
    sptr<ISystemAbilityManager> samgrProxy = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
    while (samgrProxy == nullptr) {
        HILOGI(TAG, "waiting for SAMGR...get 'samgrProxy'...");
        if (timeout > 0) {
            usleep(duration);
            samgrProxy = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
        } else {
            HILOGE(TAG, "waiting for SAMGR...timeout[10s]...NGNGNG");
            return false;
        }
        timeout--;
    }
    ......
    return true;
}
           

即能夠成功擷取samgr的代理SystemAbilityManagerProxy,這樣SA_a才能注冊到samgr中,否則表示samgr還沒有能夠正常工作,所有的SA_x都無法注冊,是以可以說samgr程序是最早啟動的系統服務程序了。

  類似的,在系統中各個程序需要與samgr進行互動的時候,都是按下面這個流程進行的:

//先擷取samgr的代理:SystemAbilityManagerProxy
sptr<ISystemAbilityManager> samgrProxy = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();

//再通過該代理向samgr發送IPC消息,使用samgr提供的服務
samgrProxy->XxxYyy()
           

5.Proxy與Stub的IPC互動

  一圖勝千言,兩圖勝兩千言。

  請結合前面兩張圖自行閱讀代碼進行了解。

附件連結:https://ost.51cto.com/resource/2287

繼續閱讀