最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android 10 啟動(dòng)之servicemanager源碼解析

 更新時(shí)間:2022年10月10日 14:38:17   作者:格子里的夢(mèng)  
這篇文章主要為大家介紹了Android 10 啟動(dòng)之servicemanager源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

正文

上一篇文章:

Android 10 啟動(dòng)分析之Init篇 (一)

在前文提到,init進(jìn)程會(huì)在在Trigger 為init的Action中,啟動(dòng)servicemanager服務(wù),這篇文章我們就來(lái)具體分析一下servicemanager服務(wù),它到底做了哪些事情。

servicemanager服務(wù)的源碼位于/frameworks/native/cmds/servicemanager/service_manager.c,我們將從這個(gè)類的入口開(kāi)始看起。

int main(int argc, char** argv)
{
    struct binder_state *bs;
    union selinux_callback cb;
    char *driver;
    if (argc > 1) {
        driver = argv[1];
    } else {
        //啟動(dòng)時(shí)默認(rèn)無(wú)參數(shù),走這個(gè)分支
        driver = "/dev/binder";
    }
    //打開(kāi)binder驅(qū)動(dòng),并設(shè)置mmap的內(nèi)存大小為128k
    bs = binder_open(driver, 128*1024);
    ...
   if (binder_become_context_manager(bs)) {
        ALOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1;
    }
    cb.func_audit = audit_callback;
    selinux_set_callback(SELINUX_CB_AUDIT, cb);
#ifdef VENDORSERVICEMANAGER
    cb.func_log = selinux_vendor_log_callback;
#else
    cb.func_log = selinux_log_callback;
#endif
    selinux_set_callback(SELINUX_CB_LOG, cb);
#ifdef VENDORSERVICEMANAGER
    sehandle = selinux_android_vendor_service_context_handle();
#else
    sehandle = selinux_android_service_context_handle();
#endif
    selinux_status_open(true);
    if (sehandle == NULL) {
        ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n");
        abort();
    }
    if (getcon(&service_manager_context) != 0) {
        ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");
        abort();
    }
     /* binder_loop已封裝如下步驟:
    while (1)
    {
        /* read data */
        /* parse data, and process */
        /* reply */
    }
    */
    binder_loop(bs, svcmgr_handler);
    return 0;
}

從main函數(shù)中可以看出,它主要做了三件事情:

  • 打開(kāi)/dev/binder設(shè)備,并在內(nèi)存中映射128K的空間。
  • 通知Binder設(shè)備,把自己變成context_manager,其他用戶進(jìn)程都通過(guò)0號(hào)句柄訪問(wèn)ServiceManager。
  • 進(jìn)入循環(huán),不停的去讀Binder設(shè)備,看是否有對(duì)service的請(qǐng)求,如果有的話,就去調(diào)用svcmgr_handler函數(shù)回調(diào)處理請(qǐng)求。

我們?cè)賮?lái)看看svcmgr_handler函數(shù)的實(shí)現(xiàn):

int svcmgr_handler(struct binder_state *bs,
                  struct binder_transaction_data_secctx *txn_secctx,
                  struct binder_io *msg,
                  struct binder_io *reply)
{
   struct svcinfo *si;
   uint16_t *s;
   size_t len;
   uint32_t handle;
   uint32_t strict_policy;
   int allow_isolated;
   uint32_t dumpsys_priority;
   struct binder_transaction_data *txn = &txn_secctx->transaction_data;
   if (txn->target.ptr != BINDER_SERVICE_MANAGER)
       return -1;
   if (txn->code == PING_TRANSACTION)
       return 0;
   ...
   switch(txn->code) {
   case SVC_MGR_GET_SERVICE:
   case SVC_MGR_CHECK_SERVICE:
       s = bio_get_string16(msg, &len);
       if (s == NULL) {
           return -1;
       }
       handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid,
                                (const char*) txn_secctx->secctx);
       if (!handle)
           break;
       bio_put_ref(reply, handle);
       return 0;
   case SVC_MGR_ADD_SERVICE:
       s = bio_get_string16(msg, &len);
       if (s == NULL) {
           return -1;
       }
       handle = bio_get_ref(msg);
       allow_isolated = bio_get_uint32(msg) ? 1 : 0;
       dumpsys_priority = bio_get_uint32(msg);
       if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority,
                          txn->sender_pid, (const char*) txn_secctx->secctx))
           return -1;
       break;
   case SVC_MGR_LIST_SERVICES: {
       uint32_t n = bio_get_uint32(msg);
       uint32_t req_dumpsys_priority = bio_get_uint32(msg);
       if (!svc_can_list(txn->sender_pid, (const char*) txn_secctx->secctx, txn->sender_euid)) {
           ALOGE("list_service() uid=%d - PERMISSION DENIED\n",
                   txn->sender_euid);
           return -1;
       }
       si = svclist;
       // walk through the list of services n times skipping services that
       // do not support the requested priority
       while (si) {
           if (si->dumpsys_priority & req_dumpsys_priority) {
               if (n == 0) break;
               n--;
           }
           si = si->next;
       }
       if (si) {
           bio_put_string16(reply, si->name);
           return 0;
       }
       return -1;
   }
   default:
       ALOGE("unknown code %d\n", txn->code);
       return -1;
   }
   bio_put_uint32(reply, 0);
   return 0;
}

我們先來(lái)認(rèn)識(shí)一下binder的數(shù)據(jù)傳輸載體binder_transaction_data:

struct binder_transaction_data {
  union {
  /* 當(dāng)binder_transaction_data是由用戶空間的進(jìn)程發(fā)送給Binder驅(qū)動(dòng)時(shí),
 handle是該事務(wù)的發(fā)送目標(biāo)在Binder驅(qū)動(dòng)中的信息,即該事務(wù)會(huì)交給handle來(lái)處理;
  handle的值是目標(biāo)在Binder驅(qū)動(dòng)中的Binder引用。*/
    __u32 handle; 
    /* 當(dāng)binder_transaction_data是有Binder驅(qū)動(dòng)反饋給用戶空間進(jìn)程時(shí),
   ptr是該事務(wù)的發(fā)送目標(biāo)在用戶空間中的信息,即該事務(wù)會(huì)交給ptr對(duì)應(yīng)的服務(wù)來(lái)處理;
   ptr是處理該事務(wù)的服務(wù)的服務(wù)在用戶空間的本地Binder對(duì)象。*/
    binder_uintptr_t ptr;
  } target;  // 該事務(wù)的目標(biāo)對(duì)象(即,該事務(wù)數(shù)據(jù)包是給該target來(lái)處理的)
  // 只有當(dāng)事務(wù)是由Binder驅(qū)動(dòng)傳遞給用戶空間時(shí),cookie才有意思,它的值是處理該事務(wù)的ServerC++層的本地Binder對(duì)象
  binder_uintptr_t cookie;
  // 事務(wù)編碼。如果是請(qǐng)求,則以BC_開(kāi)頭;如果是回復(fù),則以BR_開(kāi)頭。
  __u32 code;
  /* General information about the transaction. */
  __u32 flags;
  //表示事務(wù)發(fā)起者的pid和uid。
  pid_t sender_pid;
  uid_t sender_euid;
  // 數(shù)據(jù)大小
  binder_size_t data_size;
  //數(shù)據(jù)偏移量
  binder_size_t offsets_size;
  //data是一個(gè)共用體,當(dāng)通訊數(shù)據(jù)很小的時(shí),可以直接使用buf[8]來(lái)保存數(shù)據(jù)。當(dāng)夠大時(shí),只能用指針buffer來(lái)描述一個(gè)申請(qǐng)的數(shù)據(jù)緩沖區(qū)。
  union {
    struct {
       /* transaction data */
      binder_uintptr_t buffer;
      binder_uintptr_t offsets;
    } ptr;
    __u8 buf[8];
  } data;
};

可以看到,svcmgr_handler函數(shù)中對(duì)binder data的事務(wù)編碼進(jìn)行了判斷,并分別對(duì)SVC_MGR_GET_SERVICE(SVC_MGR_CHECK_SERVICE)、SVC_MGR_ADD_SERVICESVC_MGR_LIST_SERVICES三種類型的事務(wù)編碼做了業(yè)務(wù)處理。

獲取服務(wù)

  case SVC_MGR_CHECK_SERVICE:  
          s = bio_get_string16(msg, &len);  
          ptr = do_find_service(bs, s, len);  
          if (!ptr)  
              break;  
          bio_put_ref(reply, ptr);  
          return 0;

do_find_service函數(shù)中主要執(zhí)行service的查找,并把找到的服務(wù)句柄寫入reply,返回給客戶端。

uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid, const char* sid)
{
    struct svcinfo *si = find_svc(s, len);
    ...
    return si->handle;
}

我們繼續(xù)看find_svc函數(shù):

struct svcinfo *find_svc(const uint16_t *s16, size_t len)
{
    struct svcinfo *si;
    for (si = svclist; si; si = si->next) {
        if ((len == si->len) &&
            !memcmp(s16, si->name, len * sizeof(uint16_t))) {
            return si;
        }
    }
    return NULL;
}

svclist 是一個(gè)單向鏈表,儲(chǔ)存了所有向servicemanager注冊(cè)的服務(wù)信息。find_svc遍歷svclist鏈表,通過(guò)服務(wù)名稱作為索引條件,最終找到符合條件的服務(wù)。

注冊(cè)服務(wù)

    case SVC_MGR_ADD_SERVICE:
        s = bio_get_string16(msg, &len);
        if (s == NULL) {
            return -1;
        }
        handle = bio_get_ref(msg);
        allow_isolated = bio_get_uint32(msg) ? 1 : 0;
        dumpsys_priority = bio_get_uint32(msg);
        if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority,
        txn->sender_pid, (const char*) txn_secctx->secctx))
            return -1;

我們繼續(xù)看do_add_service函數(shù)中做了哪些事情。

在該函數(shù)中,首先會(huì)去檢查客戶端是否有權(quán)限注冊(cè)service,如果沒(méi)有權(quán)限就直接返回,不能注冊(cè)。

 if (!svc_can_register(s, len, spid, sid, uid)) {
        ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",
             str8(s, len), handle, uid);
        return -1;
    }

然后會(huì)去檢查該service是否已經(jīng)注冊(cè)過(guò)了,如果已經(jīng)注冊(cè)過(guò),那么就不能再注冊(cè)了。

 si = find_svc(s, len);
    if (si) {
        if (si->handle) {
            ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n",
                 str8(s, len), handle, uid);
            svcinfo_death(bs, si);
        }
        si->handle = handle;
    } 

再判斷內(nèi)存是否足夠。

 si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
        if (!si) {
            ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n",
                 str8(s, len), handle, uid);
            return -1;
        }

如果都沒(méi)什么問(wèn)題,會(huì)注冊(cè)該service,并加入到svcList鏈表中。

綜上所述,servicemanager主要負(fù)責(zé)查詢和注冊(cè)其他的系統(tǒng)服務(wù),是系統(tǒng)服務(wù)的管理者。

文章的最后,留給大家一個(gè)問(wèn)題進(jìn)行思考:

為什么Android需要設(shè)計(jì)servicemanager做中轉(zhuǎn)來(lái)添加和獲取系統(tǒng)服務(wù),而不直接讓客戶端去獲取服務(wù)端句柄?

更多關(guān)于Android 10 啟動(dòng)之servicemanager的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 初步編寫IDEA\AndroidStudio翻譯插件的方法

    初步編寫IDEA\AndroidStudio翻譯插件的方法

    這篇文章主要介紹了初步編寫IDEA\AndroidStudio翻譯插件,本文通過(guò)實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12
  • Android?Room數(shù)據(jù)庫(kù)加密詳解

    Android?Room數(shù)據(jù)庫(kù)加密詳解

    這篇文章主要為大家詳細(xì)介紹了Android?Room數(shù)據(jù)庫(kù)加密,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • Android實(shí)現(xiàn)跳轉(zhuǎn)第三方百度地圖導(dǎo)航

    Android實(shí)現(xiàn)跳轉(zhuǎn)第三方百度地圖導(dǎo)航

    在眾多地圖導(dǎo)航產(chǎn)品中,百度地圖以其精準(zhǔn)的導(dǎo)航和豐富的本地生活數(shù)據(jù)受到廣泛歡迎,本項(xiàng)目介紹如何在 Android 中構(gòu)造 Intent 調(diào)用百度地圖導(dǎo)航,希望對(duì)大家有所幫助
    2025-04-04
  • GridView實(shí)現(xiàn)桌面圖標(biāo)顯示案例

    GridView實(shí)現(xiàn)桌面圖標(biāo)顯示案例

    這篇文章主要為大家詳細(xì)介紹了GridView實(shí)現(xiàn)桌面圖標(biāo)顯示案例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • 基于Android實(shí)現(xiàn)仿QQ5.0側(cè)滑

    基于Android實(shí)現(xiàn)仿QQ5.0側(cè)滑

    本課程將帶領(lǐng)大家通過(guò)自定義控件實(shí)現(xiàn)QQ5.0側(cè)滑菜單,課程將循序漸進(jìn),首先實(shí)現(xiàn)最普通的側(cè)滑菜單,然后引入屬性動(dòng)畫與拖動(dòng)菜單效果相結(jié)合,最終實(shí)現(xiàn)QQ5.0側(cè)滑菜單效果。通過(guò)本課程大家會(huì)對(duì)側(cè)滑菜單有更深層次的了解,通過(guò)自定義控件和屬性動(dòng)畫打造千變?nèi)f化的側(cè)滑菜單效果
    2015-12-12
  • android編程開(kāi)發(fā)之全屏和退出全屏的實(shí)現(xiàn)方法

    android編程開(kāi)發(fā)之全屏和退出全屏的實(shí)現(xiàn)方法

    這篇文章主要介紹了android編程開(kāi)發(fā)之全屏和退出全屏的實(shí)現(xiàn)方法,以實(shí)例形式較為詳細(xì)的分析了Android全屏及退出全屏的頁(yè)面布局與功能實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-11-11
  • Android Studio應(yīng)用開(kāi)發(fā)集成百度語(yǔ)音合成使用方法實(shí)例講解

    Android Studio應(yīng)用開(kāi)發(fā)集成百度語(yǔ)音合成使用方法實(shí)例講解

    這篇文章主要介紹了Android Studio應(yīng)用開(kāi)發(fā)集成百度語(yǔ)音合成使用方法實(shí)例講解的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-11-11
  • Android編程之json解析實(shí)例詳解

    Android編程之json解析實(shí)例詳解

    這篇文章主要介紹了Android編程之json解析,結(jié)合實(shí)例形式較為詳細(xì)的分析了了Android針對(duì)json格式數(shù)據(jù)的創(chuàng)建、讀取與解析技巧,需要的朋友可以參考下
    2015-12-12
  • Android開(kāi)發(fā)之禁止下拉通知欄的方法

    Android開(kāi)發(fā)之禁止下拉通知欄的方法

    這篇文章主要介紹了Android開(kāi)發(fā)之禁止下拉通知欄的方法,實(shí)例分析了Android權(quán)限控制與Activity相應(yīng)設(shè)置技巧,需要的朋友可以參考下
    2016-01-01
  • Android開(kāi)發(fā)懸浮按鈕 Floating ActionButton的實(shí)現(xiàn)方法

    Android開(kāi)發(fā)懸浮按鈕 Floating ActionButton的實(shí)現(xiàn)方法

    這篇文章主要介紹了Android開(kāi)發(fā)懸浮按鈕 Floating ActionButton的實(shí)現(xiàn)方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-09-09

最新評(píng)論

临江市| 凤翔县| 略阳县| 延庆县| 樟树市| 山阴县| 民权县| 北碚区| 鄯善县| 手游| 乾安县| 友谊县| 梨树县| 金山区| 无锡市| 广昌县| 宜黄县| 姜堰市| 花莲市| 兰州市| 那坡县| 苍南县| 宣化县| 龙州县| 当涂县| 白河县| 重庆市| 德兴市| 迁安市| 白朗县| 遂宁市| 虹口区| 湛江市| 三江| 台江县| 田东县| 定西市| 普兰店市| 广南县| 松原市| 昭平县|