Android開発のサービスマネージャ分析


Android開発のサービスマネージャ分析
Androidシステムで最も多く使われる通信メカニズムはBinderで、Binderは主にClient、Server、ServiceManager、Binderドライバから構成されています.Client、Service、ServiceManagerはユーザースペースで実行され、Binderドライバはカーネルスペースで実行されます.コアコンポーネントはBinderドライバであり、ServiceManagerはClientまたはServicesで通信する前にServiceManagerに連絡するサポート管理機能を提供します.ServiceManagerは、サーバを管理し、Clientにサーバを照会する機能を提供するデーモンです.
 
 init.rc servicemanager        ,    zygote    
service servicemanager /system/bin/servicemanager
	class core
	user system
	group system
	critical
	onrestart restart zygote
	onrestart restart media
	onrestart restart surfaceflinger
	onrestart restart drm

ソースの場所:frameworks/base/cmds/servicemanager/service_manager.c
int main(int argc, char** argv)
{
	struct binder_state *bs;
	void* svcmgr = BINDER_SERVICE_MANAGER;
	
	bs = binder_open(128*1024);
	
	binder_become_context_manager(bs);
	
	svcmgr_handle = svcmgr;
	
	binder_loop(bs, svcmgr_handler);
	
	return 0;
}

ここでmain関数には主に3つの機能があります.1)Binderデバイスファイルを開くには、まずこのstruct binder_を見てみましょう.state構造体struct binder_state{int fd;//ファイル記述子、/dev/binderデバイスvoid*mappedを開く;//デバイスファイル/dev/binderをプロセス空間の開始アドレスunsigned mapsizeにマッピングする;//メモリ空間のサイズをマッピングする};マクロ:#define BINDER_SERVICE_MANAGER(void*)0)は、ServiceManagerに対応するハンドルが0であり、表面自体がサーバ管理者であることを示します.他のServerプロセスハンドルの値は0より大きい.
struct binder_state* binder_open(unsigned mapsize)
{
	struct binder_state* bs;
	bs = malloc(sizeof(*bs));
	bs->fd = open("/dev/binder", O_RDWR);
	bs->mapsize = mapsize;
	bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
	return bs;
}	
        Binder  ,  128K       

 
2)Binderドライバ自身がBinderコンテキスト管理者であることを伝える
int binder_become_context_manager(struct binder_state *bs)
{
	return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
                BINDER_SET_CONTEXT_MGR

3)無線ループに入り、serverの役割を果たし、Clientの要求を待つ
void binder_loop(struct binder_state bs, binder_handler func)
{
	struct binder_write_read bwr;
	unsigned readbuf[32];
	
	bwr.write_size = 0;
	bwr.write_consumed = 0;
	bwr.write_buffer = 0;
	readbuf[0] = BC_ENTER_LOOPER;	//        LOOPER
	//   ioctl  ,  Binder  servicemanager    loop  
	binder_write(bs, readbuf, sizeof(unsigned));
	
	for(;;) {
		bwr.read_size = sizeof(readbuf);
		bwr.read_consumed = 0;
		bwr.read_buffer = (unsigned)readbuf;
		//   Binder     ,     IPC  
		ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
		//       binder_parse      
		binder_parse(bs, 0, readbuf, bwr.read_consumed, func);
	}
}

      struct binder_write_read     :
struct binder_write_read{
	signed long write_size;
	signed long write_consumed;	// bytes consumed by driver
	unsigned long write_buffer;
	signed long read_size;
	signed long read_consumed;	// bytes consumed by driver
	unsigned long read_buffer;
};

int binder_parse(struct binder_state *bs, struct binder_io *bio, uint32_t *ptr, 
			uint32_t size, binder_handler func)
{
	uint32_t *end = ptr + (size / 4);	
	while(ptr < end) {
		uint32_t cmd = *ptr++;
		switch(cmd) {
		......
		case BR_TRANSACTOIN:{	//         
			struct bindeer_txn *txn = (void*) ptr;
			if(func) {
				unsigned rdata[256/4];
				struct binder_io msg;
				struct binder_io reply;
				bio_init(&reply, rdata, sizeof(rdata), 4);
				bio_init_from_txn(&msg, txn);
				ret = func(bs, txn, &msg, &reply);
				binder_send_reply(bs, &reply, txn->data, res);
			}
			ptr += sizeof(*txn) / sizeof(uint32_t);
			break;
		}
		case BR_REPLY: { 	//        
			struct binder_txn *txn = (void*)ptr;
			if(bio) {
				bio_init_from_txn(bio, txn);
				bio = 0;
			}else {
				// to free buffer
			}
			ptr += sizeof(*txn) / sizeof(uint32_t);
			r = 0;
			break;
		}
		case BR_DEAD_BINDER: {
			struct binder_death* death = (void*)*ptr++;
			death->func(bs, death->ptr);
			break;
		}
		...
		}
	}
	return r;
}
/*  binder_parse     binder            bindeer_txn   ,         
   binder_io msg,      svcmgr_handler  ,      binder_io reply,   
  reply        。*/
struc binder_io
{
	char* data;		//   read/write   
	uint32_t *offs;		//     
	uint32_t data_avail;	// data       
	uint32_t offs_avail;	//           
	char* data0;		// data    
	uint32_t *offs0;	//   buffer     
	uint32_t flags;
	uint32_t unused;
};
           svcmgr_handler,            :

int svcmgr_handler(struct binder_state* bs, struct binder_txn *txn, 
		struct binder_io *msg, struct binder_io *reply)
{
	struct svcinfo *si;
	uint16_t *s;
	unsigned len;
	void* ptr;
	uint32_t strict_policy;
	
	if(txn->target != svcmgr_handler)
		return -1;	//                  
	strict_policy = bio_get_uint32(msg);
	s = bio_get_string16(msg, &len);
	switch(txn->code) {
	case SVC_MGR_GET_SERVICE:
	case SVC_MGR_CHECK_SERVICE:
		s = bio_get_string16(msg, &len);	//           
		ptr = do_find_service(bs, s, len);	//           
		bio_put_ref(reply, ptr);
		return 0;
	case SVC_MGR_ADD_SERVICE: 			//     
		s = bio_get_string16(msg, &len);
		ptr = bio_get_ref(msg);
		do_add_service(bs, s, len, ptr, txn->sender_euid);
		bio_put_uint32(reply, 0);	//       
		return 0;
	....
	}
	return 0;
}

まず、BinderがどのようにBinder伝達メッセージのデータ構造を組織しているかを見なければなりません.Binderドライバを呼び出すとvoid*ptr構造体が得られ、binder_に強制的に変換されます.txn*txn,そしてこのtxnに基づいてBinderの入出力構造体binder_を得た.io *bio.最後に,要求を処理しても返信を送信しても,このbio構造を処理する.我々のBinder通信のbinder構造はbinder_objectが組織しbinder_を指すio構造内data.まず、BinderがどのようにBinder伝達メッセージのデータ構造を組織しているかを見なければなりません.Binderドライバを呼び出すとvoid*ptr構造体が得られ、binder_に強制的に変換されます.txn*txn,そしてこのtxnに基づいてBinderの入出力構造体binder_を得た.io *bio.最後に,要求を処理しても返信を送信しても,このbio構造を処理する.我々のBinder通信のbinder構造はbinder_objectが組織しbinder_を指すio構造内data.
struct binder_object
{
	uint32_t type;
	uint32_t flags;
	void* pointer;
	void* cookie;
};

上のbinder_object構造体の内容は、私たちのコードのbio_に順次対応しています.get_uint32(msg); bio_get_string16(msg, &len); bio_get_string16(msg, &len); bio_get_ref(msg); 上のbinder_object構造体の内容は、私たちのコードのbio_に順次対応しています.get_uint32(msg); bio_get_string16(msg, &len); bio_get_string16(msg, &len); bio_get_ref(msg);
クライアントがサービスを追加する必要がある場合:SVC_MGR_ADD_SERVICE 1)まずbio_を呼び出すget_string 16()binder_からioでサービス名を取得します.2)bio_を呼び出すget_ref()binder_からioでサービスを受けるbinderエンティティstruct binder_object
void* bio_get_ref(struct binder_io* bio)
{
	struct binder_object* obj;
	obj = _bio_get_obj(bio);//           	void* ptr = bio->data;	
	return obj->pointer;
}

3)do_を呼び出すadd_サービス()は、上のBinderエンティティ参照をサービスに書き込み、名前でグローバルチェーンテーブルに追加します.
int do_add_service(struct binder_state* bs, uint16_t *s, unsigned len, void* ptr, unsigned uid)
{
	struct svcinfo *si;
	
	svc_can_register(uid, s);	//     
	
	si = find_svc(s, len);
	//         ,        
	si = malloc(sizeof(*si) + (len+1)*sizeof(uin16_t));
	si->ptr = ptr;	//     binder_object pointer   Binder  
	memcpy(si->name, s, (len+1)*sizeof(uint16_t));
	si->name[len] = '\0';
	si->death.func = svcinfo_death;
	si->death.ptr = si;
	si->next = svclist;
	svclist = si;
	
	binder_acquire(bs, ptr);
	binder_link_to_death(bs, ptr, &si->death);
	return 0;
}

クライアントがサービスを問い合わせる必要がある場合:1)bio_get_string 16()サービス名2)do_find_サービス()は、グローバルチェーンテーブルsvclistを巡回し、サービス名に基づいて対応するサービスを見つけて返します.2)bio_put_ref(reply, ptr);ここでreplyはクライアントに返す必要がある構造体であり,ptrはターゲットBinderエンティティを指す.
void bio_put_ref(struct binder_io* bio, void* ptr)
{
	struct binder_object *obj;
	obj = bio_alloc(bio);
	obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
	obj->type = BINDER_TYPE_HANDLE;
	obj->pointer = ptr;
	obj->cookie = 0;
}

binderに戻るparse関数では、実行:binder_send_reply()はBinderドライバに通知します.