天天看點

《Android的設計與實作:卷I》——第3章 3.4.4解析Servicedefine list_declare(name) \

3.4.4 解析service

1.parse_service

解析service先從parse_service開始,代碼如下:

static void parse_service(struct parse_state state,int nargs, charargs)

{

struct servicesvc;//service結構體,用于儲存目前解析出的service

……//省略錯誤處理代碼

nargs -= 2;

/為service配置設定存儲空間/

svc = calloc(1, sizeof(svc) + sizeof(char) nargs);

/用解析到的内容構造service結構體/

svc->name = args[1];

svc->classname = "default";

memcpy(svc->args, args + 2, sizeof(char) nargs);

svc->args[nargs] = 0;

svc->nargs = nargs;

svc->onrestart.name = "onrestart";

/初始化service中restart option的commands連結清單,然後

将servic的節點slist放入service_list雙向連結清單/

list_init(&svc->onrestart.commands);

/将service節點的指針部分放入service_list中/

list_add_tail(&service_list, &svc->slist);

return svc;

}

parse_service函數主要做了三項工作:1)為建立的service配置設定存儲空間,2)初始化service,

3)将service放入一個service_list連結清單。其中涉及幾個重要的資料類型和函數:service_list、list_init和list_add_tail,以及service結構體。

(1)service_list

service_list由list_declare定義,list_declare實際上是一個宏,位于/system/core/include/cutils/list.h。其源碼如下:

service_list聲明了一個雙向連結清單,存儲了前向和後向指針。

(2)list_init和list_add_tail

list_init和list_add_tail的實作代碼位于/system/core/libcutils/list.c中,提供了基本的雙向連結清單操作。list_init的源碼如下:

void list_init(struct listnode node)

node->next = node;

node->prev = node;

list_add_tail的源碼如下:

void list_add_tail(struct listnode head, struct listnode item)

item->next = head;

item->prev = head->prev;

head->prev->next = item;

head->prev = item;

list_add_tail隻是将item加入到雙向連結清單的尾部。

注意 android借鑒了linux核心中常用的連結清單實作方法。把連結清單的指針部分和資料部分分離。

   首先定義了node結構體:

   struct listnode

   {

   struct listnode *next;

   struct listnode *prev;

   };

   将連結清單的前向指針和後項指針放入這個struct listnode的結構中。當需要處理不同資料節點時,就把這個listnode嵌入不同的資料節點中。這樣操作連結清單就是操作這個listnode,與具體的資料無關。如parse_service函數中,list_add_tail(&service_list, &svc->slist);便是将service節點的listnode指針部分放入service_list連結清單。當需要操作listnode對應的資料時,就可通過成員偏移量找到對應的資料,這部分以後分析。

(3)service結構體

parse_service中最重要的一個資料類型便是service,它存儲了service這個section的内容。service結構體定義在/system/core/init/init.h中,代碼如下:

struct service {

/ list of all services /

struct listnode slist;

const char *name; //service的名字

const char *classname; //service的分類名

unsigned flags; //service的屬性标志

pid_t pid; //service的程序号

time_t time_started; //上次啟動時間

time_t time_crashed; //上次異常退出的時間

int nr_crashed; //異常退出的次數

uid_t uid; //使用者id

gid_t gid; //組id

gid_t supp_gids[nr_svc_supp_gids];

size_t nr_supp_gids;

struct socketinfo sockets; //service使用的socket

struct svcenvinfo esnvvars; //service使用的環境變量

/service重新開機時要執行的action。這裡其實是由關鍵字onrestart聲明的option。由于onrestart

}; /args 必須位于結構體末端 /

可見,service需要填充的内容很多,parse_service函數隻是初始化了service的基本資訊,詳細資訊需要由parse_line_service填充。

2.parse_line_service

parse_line_service的源碼如下:

static void parse_line_service(struct parse_state state, int nargs, charargs)

……//省略部分case語句

default: //隻支援固定的關鍵字,否則出錯

到這裡service就解析完了,接着分析action的解析過程。

繼續閱讀