Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Andorid Binder進程間通信---啟動ServiceManager

Andorid Binder進程間通信---啟動ServiceManager

編輯:關於Android編程

本文參考《Android系統源代碼情景分析》,作者羅升陽。

一、~/Android/frameworks/base/cmd/servicemanager

-----binder.h

-----binder.c

-----service_manager.c

~/Android//kernel/goldfish/drivers/staging/android

-----binder.c

-----binder.h


二、源碼分析

1、從service_manager.c的main開始執行。

----~/Android/frameworks/base/cmd/servicemanager/service_manager.c

int main(int argc, char **argv)
{
    struct binder_state *bs;
    void *svcmgr = BINDER_SERVICE_MANAGER;

    bs = binder_open(128*1024);

    if (binder_become_context_manager(bs)) {
        LOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1; 
    }   

    svcmgr_handle = svcmgr;//注意svcmgr_handle與下面的svcmgr_handler不一樣,svcmgr_handle為全局變量,目前為空的函數指針,((void*)0)
    binder_loop(bs, svcmgr_handler);//svcmgr_handler是一個函數指針,指向具體的函數
    return 0;
}
----~/Android/frameworks/base/cmd/servicemanager/binder.c

struct binder_state
{       
    int fd;
    void *mapped;
    unsigned mapsize;
};
----~/Android/frameworks/base/cmd/servicemanager/binder.h

#define BINDER_SERVICE_MANAGER ((void*) 0)
ServiceManager的啟動過程由三個步驟組成:第一是調用函數binder_open打開設備文件/dev/binder,以及將它映射到本進程地址空間;第二是調用binder_become_context_manager將自己注冊為Binder進程間通信機制的上下文管理者;第三步是調用函數binder_loop來循環等待和處理Client進程的通信要求。


2、打開和映射Binder設備文件

----~/Android/frameworks/base/cmd/servicemanager/binder.c

struct binder_state *binder_open(unsigned mapsize)
{       
    struct binder_state *bs;

    bs = malloc(sizeof(*bs));
    if (!bs) {
        errno = ENOMEM;
        return 0;
    }

    bs->fd = open("/dev/binder", O_RDWR);//文件描述符保存在fd中
    if (bs->fd < 0) {
        fprintf(stderr,"binder: cannot open device (%s)\n",
                strerror(errno));
        goto fail_open;
    }
        
    bs->mapsize = mapsize;//128*1024
    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);//映射到本進程地址空間
    if (bs->mapped == MAP_FAILED) {
        fprintf(stderr,"binder: cannot map device (%s)\n",
                strerror(errno));
        goto fail_map;
    }

        /* TODO: check version */

    return bs;

fail_map:
    close(bs->fd);
fail_open:
    free(bs);
    return 0;
} 
其中open("/dev/binder", O_RDWR)映射到binder驅動程序binder_open方法。

binder_open方法位於~/Android/kernel/goldfish/drivers/staging/android/binder.c

static int binder_open(struct inode *nodp, struct file *filp)
{
        struct binder_proc *proc;      

        if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE)
                printk(KERN_INFO "binder_open: %d:%d\n", current->group_leader->pid, current->pid);

        proc = kzalloc(sizeof(*proc), GFP_KERNEL);//創建binder_proc結構體
        if (proc == NULL)     
                return -ENOMEM;                
        get_task_struct(current);      
        proc->tsk = current;  //初始化各個參數
        INIT_LIST_HEAD(&proc->todo);   
        init_waitqueue_head(&proc->wait);
        proc->default_priority = task_nice(current);
        mutex_lock(&binder_lock);      
        binder_stats.obj_created[BINDER_STAT_PROC]++;
        hlist_add_head(&proc->proc_node, &binder_procs);//將binder_proc結構體proc加入到一個全局hash隊列binder_procs中
        proc->pid = current->group_leader->pid;
        INIT_LIST_HEAD(&proc->delivered_death);
        filp->private_data = proc;//將binder_proc結構體proc保存在參數filp的成員變量private_data中  
        mutex_unlock(&binder_lock);    

        if (binder_proc_dir_entry_proc) {//如果存在/proc/binder/proc目錄
                char strbuf[11];
                snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
                remove_proc_entry(strbuf, binder_proc_dir_entry_proc);
                create_proc_read_entry(strbuf, S_IRUGO, binder_proc_dir_entry_proc, binder_read_proc_proc, proc);//在/proc/binder/proc目錄下創建一個以進程ID為名稱的只讀文件
        }

        return 0;
}
創建了binder_proc結構體,分別初始化各個參數,將binder_proc結構體proc加入到一個全局hash隊列binder_procs中。Binder驅動程序將所有打開了設備文件/dev/binder的進程都加入全局hash隊列binder_procs中,因此,通過遍歷這個hash隊列就知道系統當前有多少進程在使用Binder進程間通信機制。然後將binder_proc結構體proc保存在參數filp的成員變量private_data中。最後在/proc/binder/proc目錄下創建一個以進程ID為名稱的只讀文件,並且以函數binder_read_proc_proc作為它的文件內容讀取函數。通過讀取文件/proc/binder/proc/的內容,我們就可以獲得進程的Binder線程池,Binder實體對象,Binder引用對象,以及內核緩沖區等信息。

其中mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0)映射到binder驅動程序binder_mmap方法,暫時先不分析。


3、注冊為Binder上下文管理者

---~/Android/frameworks/base/cmd/servicemanager/binder.c

int binder_become_context_manager(struct binder_state *bs)
{   
    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
ioctl方法映射到binder驅動程序binder_ioctl方法。

binder_ioctl位於~/Android/kernel/goldfish/drivers/staging/android/binder.c

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	int ret;
	struct binder_proc *proc = filp->private_data;//獲取剛剛在open中創建的binder_proc結構體
	struct binder_thread *thread;
	unsigned int size = _IOC_SIZE(cmd);//命令的大小
	void __user *ubuf = (void __user *)arg;//參數地址

	.........

	mutex_lock(&binder_lock);
	thread = binder_get_thread(proc);//獲取或者創建一個binder_thread結構體
	if (thread == NULL) {
		ret = -ENOMEM;
		goto err;
	}

	switch (cmd) {
	............
	case BINDER_SET_CONTEXT_MGR:
		if (binder_context_mgr_node != NULL) {
			.........
		}
		if (binder_context_mgr_uid != -1) {
			.........
		} else
			binder_context_mgr_uid = current->cred->euid;//初始化進程有效用戶ID
		binder_context_mgr_node = binder_new_node(proc, NULL, NULL);//初始化一個Binder實體對象
		if (binder_context_mgr_node == NULL) {
			ret = -ENOMEM;
			goto err;
		}
		binder_context_mgr_node->local_weak_refs++;//強弱指針,待以後分析
		binder_context_mgr_node->local_strong_refs++;
		binder_context_mgr_node->has_strong_ref = 1;
		binder_context_mgr_node->has_weak_ref = 1;
		break;
	.............
	}
	ret = 0;
err:
	if (thread)
		thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
	mutex_unlock(&binder_lock);
	.............
	return ret;
}
binder_get_thread實現如下:

~/Android/kernel/goldfish/drivers/staging/android/binder.c

static struct binder_thread *binder_get_thread(struct binder_proc *proc)
{
	struct binder_thread *thread = NULL;
	struct rb_node *parent = NULL;
	struct rb_node **p = &proc->threads.rb_node;

	while (*p) {//根據當前主線程pid,來查找是否已經分配了binder_thread結構體
		parent = *p;
		thread = rb_entry(parent, struct binder_thread, rb_node);

		if (current->pid < thread->pid)
			p = &(*p)->rb_left;
		else if (current->pid > thread->pid)
			p = &(*p)->rb_right;
		else
			break;
	}
	if (*p == NULL) {//如果沒有找到
		thread = kzalloc(sizeof(*thread), GFP_KERNEL);//分配binder_thread結構體
		if (thread == NULL)
			return NULL;
		binder_stats.obj_created[BINDER_STAT_THREAD]++;
		thread->proc = proc;//初始化各個變量
		thread->pid = current->pid;
		init_waitqueue_head(&thread->wait);
		INIT_LIST_HEAD(&thread->todo);
		rb_link_node(&thread->rb_node, parent, p);//根據pid將thread->rb_node插入到proc->threads維護的紅黑樹中
		rb_insert_color(&thread->rb_node, &proc->threads);
		thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN;
		thread->return_error = BR_OK;
		thread->return_error2 = BR_OK;
	}
	return thread;
}
一個進程會有很多線程,所以thread->rb_node為proc->threads維護的紅黑數中的一個節點。thread按照pid大小將rb_node插入到proc->threads維護的紅黑樹的對應節點處。所以首先根據當前主線程pid,來查找是否已經分配了binder_thread結構體。如果沒有那麼分配binder_thread結構體,初始化各個變量,根據pid將thread->rb_node插入到proc->threads維護的紅黑樹中。將looper狀態設備為BINDER_LOOPER_STATE_NEED_RETURN,表示該線程在完成當前操作之後,需要馬上返回到用戶空間,而不可以去處理進程間的通信請求。

全局變量binder_context_mgr_node用來描述一個Binder實體對象,如果它的值不為NULL,說明已經注冊了Binder進程間通信上下文管理者了。全局變量binder_context_mgr_uid用來描述進程有效用戶ID,如果它的值不等於-1,說明已經注冊了Binder進程間通信上下文管理者了。目前沒有Binder進程間通信上下文管理者,所以binder_context_mgr_uid和binder_context_mgr_node都要初始化。


binder_context_mgr_node實現如下:

-----~/Android/kernel/goldfish/drivers/staging/android/binder.c

static struct binder_node *
binder_new_node(struct binder_proc *proc, void __user *ptr, void __user *cookie)
{
	struct rb_node **p = &proc->nodes.rb_node;
	struct rb_node *parent = NULL;
	struct binder_node *node;

	while (*p) {//根據node的ptr,來查找是否已經分配了binder_node結構體
		parent = *p;
		node = rb_entry(parent, struct binder_node, rb_node);

		if (ptr < node->ptr)
			p = &(*p)->rb_left;
		else if (ptr > node->ptr)
			p = &(*p)->rb_right;
		else
			return NULL;
	}

	node = kzalloc(sizeof(*node), GFP_KERNEL);//如果沒有找到,分配binder_node結構體
	if (node == NULL)
		return NULL;
	binder_stats.obj_created[BINDER_STAT_NODE]++;
	rb_link_node(&node->rb_node, parent, p);//根據ptr將node->rb_node插入proc->nodes中
	rb_insert_color(&node->rb_node, &proc->nodes);
	node->debug_id = ++binder_last_id;//初始化各個變量
	node->proc = proc;
	node->ptr = ptr;//NULL
	node->cookie = cookie;//NULL
	node->work.type = BINDER_WORK_NODE;
	INIT_LIST_HEAD(&node->work.entry);
	INIT_LIST_HEAD(&node->async_todo);
	if (binder_debug_mask & BINDER_DEBUG_INTERNAL_REFS)
		printk(KERN_INFO "binder: %d:%d node %d u%p c%p created\n",
		       proc->pid, current->pid, node->debug_id,
		       node->ptr, node->cookie);
	return node;
}
一個進程會有很多實體對象,所以node->rb_node為proc->nodes維護的紅黑數中的一個節點。node按照ptr地址大小將rb_node插入到proc->threads維護的紅黑樹的對應節點處。所以首先根據當前node的ptr,來查找是否已經分配了binder_node結構體。如果沒有那麼分配binder_node結構體,初始化各個變量,根據ptr將thread->rb_node插入到proc->threads維護的紅黑樹中。

然後返回binder_ioctl中,會將thread->looper狀態位BINDER_LOOPER_STATE_NEED_RETURN清零。


4、循環等待Client進程請求

返回用戶空間,main函數開始執行binder_loop,實現如下:

---~/Android/frameworks/base/cmd/servicemanager/binder.c

void binder_loop(struct binder_state *bs, binder_handler func)
{
    int res;
    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;//首先將BC_ENTER_LOOPER協議寫入緩沖區readbuf中
    binder_write(bs, readbuf, sizeof(unsigned));//調用binder_write將它發送到Binder驅動程序中

    for (;;) {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (unsigned) readbuf;

        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);//bwr.write_size為0,bwr.read_size不為0

        if (res < 0) {
            LOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
            break;
        }

        res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func);
        if (res == 0) {
            LOGE("binder_loop: unexpected reply?!\n");
            break;
        }
        if (res < 0) {
            LOGE("binder_loop: io error %d %s\n", res, strerror(errno));
            break;
        }
    }
}
首先將BC_ENTER_LOOPER協議寫入緩沖區readbuf中,接著調用binder_write將它發送到Binder驅動程序中。函數binder_write的實現如下:

---~/Android/frameworks/base/cmd/servicemanager/binder.c

int binder_write(struct binder_state *bs, void *data, unsigned len)
{
    struct binder_write_read bwr;
    int res;
    bwr.write_size = len;
    bwr.write_consumed = 0;
    bwr.write_buffer = (unsigned) data;
    bwr.read_size = 0;
    bwr.read_consumed = 0;
    bwr.read_buffer = 0;
    res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);//bwr的write_size不為0,read_size為0
    if (res < 0) {
        fprintf(stderr,"binder_write: ioctl failed (%s)\n",
                strerror(errno));
    }
    return res;
}
ioctl方法同樣映射到binder驅動程序binder_ioctl方法。
binder_ioctl位於~/Android/kernel/goldfish/drivers/staging/android/binder.c

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	int ret;
	struct binder_proc *proc = filp->private_data;
	struct binder_thread *thread;
	unsigned int size = _IOC_SIZE(cmd);
	void __user *ubuf = (void __user *)arg;

	.........

	mutex_lock(&binder_lock);
	thread = binder_get_thread(proc);//上次獲取的thread,looper為0
	if (thread == NULL) {
		ret = -ENOMEM;
		goto err;
	}

	switch (cmd) {//cmd為上面傳遞過來的BINDER_WRITE_READ
	case BINDER_WRITE_READ: {
		struct binder_write_read bwr;
		if (size != sizeof(struct binder_write_read)) {
			ret = -EINVAL;
			goto err;
		}
		if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {//從用戶空間傳進來的一個binder_write_read結構體拷貝出來,並且保存在變量bwr中
			ret = -EFAULT;
			goto err;
		}
                .........
		if (bwr.write_size > 0) {//bwr.write_size大於0,執行這裡
			ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
			if (ret < 0) {
				bwr.read_consumed = 0;
				if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
					ret = -EFAULT;
				goto err;
			}
		}
		if (bwr.read_size > 0) {//bwr.read_size等於0,不執行這裡
			ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);
			if (!list_empty(&proc->todo))
				wake_up_interruptible(&proc->wait);
			if (ret < 0) {
				if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
					ret = -EFAULT;
				goto err;
			}
		}
                ...........
		if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {//將結果返回用戶空間bwr
			ret = -EFAULT;
			goto err;
		}
		break;
	}
	..........
	ret = 0;
err:
	if (thread)
		thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;//looper為BINDER_LOOPER_STATE_ENTERED,由於對應位已經為0,此時執行此句無效果
	mutex_unlock(&binder_lock);
        ...........
	return ret;
}
由於bwr.write_size大於0,開始執行binder_thread_write,實現如下:

binder_ioctl位於~/Android/kernel/goldfish/drivers/staging/android/binder.c

int
binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
		    void __user *buffer, int size, signed long *consumed)
{
	uint32_t cmd;
	void __user *ptr = buffer + *consumed;//起始位置
	void __user *end = buffer + size;//結束位置

	while (ptr < end && thread->return_error == BR_OK) {
		if (get_user(cmd, (uint32_t __user *)ptr))//cmd為BC_ENTER_LOOPER
			return -EFAULT;
		ptr += sizeof(uint32_t);//由於只有一個cmd,此時ptr已經等於end
		............
		switch (cmd) {
		...........
		case BC_ENTER_LOOPER:
		        ..............
			if (thread->looper & BINDER_LOOPER_STATE_REGISTERED) {//此時looper為0,不會執行這裡
				thread->looper |= BINDER_LOOPER_STATE_INVALID;
				binder_user_error("binder: %d:%d ERROR:"
					" BC_ENTER_LOOPER called after "
					"BC_REGISTER_LOOPER\n",
					proc->pid, thread->pid);
			}
			thread->looper |= BINDER_LOOPER_STATE_ENTERED;//執行本次寫操作,最終的目的居然是looper設置成BINDER_LOOPER_STATE_ENTERED
			break;
		.........
		*consumed = ptr - buffer;//由於只有一個cmd,consumed為size
	}
	return 0;
}
返回binder_ioctl,bwr.read_size等於0,不會執行,最後將結果返回用戶空間bwr。

返回用戶空間,接著執行binder_loop,從上面我們看出來,驅動程序是否執行讀、寫操作,取決於用戶空間write_size,read_size的大小。此時write_size為0,read_size不為0, ioctl方法同樣映射到binder驅動程序binder_ioctl方法。
binder_ioctl位於~/Android/kernel/goldfish/drivers/staging/android/binder.c

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	int ret;
	struct binder_proc *proc = filp->private_data;
	struct binder_thread *thread;
	unsigned int size = _IOC_SIZE(cmd);
	void __user *ubuf = (void __user *)arg;

	.........

	mutex_lock(&binder_lock);
	thread = binder_get_thread(proc);//上次獲取的thread,looper為BINDER_LOOPER_STATE_ENTERED
	if (thread == NULL) {
		ret = -ENOMEM;
		goto err;
	}

	switch (cmd) {//cmd為上面傳遞過來的BINDER_WRITE_READ
	case BINDER_WRITE_READ: {
		struct binder_write_read bwr;
		if (size != sizeof(struct binder_write_read)) {
			ret = -EINVAL;
			goto err;
		}
		if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {//從用戶空間傳進來的一個binder_write_read結構體拷貝出來,並且保存在變量bwr中
			ret = -EFAULT;
			goto err;
		}
                .........
		if (bwr.write_size > 0) {//bwr.write_size等於0,不執行這裡
			ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
			if (ret < 0) {
				bwr.read_consumed = 0;
				if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
					ret = -EFAULT;
				goto err;
			}
		}
		if (bwr.read_size > 0) {//bwr.read_size大於0,執行這裡
			ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);
			if (!list_empty(&proc->todo))
				wake_up_interruptible(&proc->wait);
			if (ret < 0) {
				if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
					ret = -EFAULT;
				goto err;
			}
		}
                ...........
		if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {//將結果返回用戶空間bwr
			ret = -EFAULT;
			goto err;
		}
		break;
	}
	..........
	ret = 0;
err:
	if (thread)
		thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
	mutex_unlock(&binder_lock);
        ...........
	return ret;
}

由於bwr.read_size大於0,開始執行binder_thread_read,實現如下:

binder_ioctl位於~/Android/kernel/goldfish/drivers/staging/android/binder.c

static int
binder_thread_read(struct binder_proc *proc, struct binder_thread *thread,
	void  __user *buffer, int size, signed long *consumed, int non_block)
{
	void __user *ptr = buffer + *consumed;//起始位置
	void __user *end = buffer + size;//結束位置

	int ret = 0;
	int wait_for_proc_work;

	if (*consumed == 0) {
		if (put_user(BR_NOOP, (uint32_t __user *)ptr))//BR_NOOP存入剛才的局部變量中
			return -EFAULT;
		ptr += sizeof(uint32_t);
	}

retry:
	wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo);//wait_for_proc_work目前為1,表示線程沒有要處理的任務

	if (thread->return_error != BR_OK && ptr < end) {
		..........
	}


	thread->looper |= BINDER_LOOPER_STATE_WAITING;//looper為BINDER_LOOPER_STATE_ENTERED,BINDER_LOOPER_STATE_WAITING
	if (wait_for_proc_work)//為1
		proc->ready_threads++;//ready_threads為1,進程多了一個空閒線程
	mutex_unlock(&binder_lock);
	if (wait_for_proc_work) {//為1
		if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
					BINDER_LOOPER_STATE_ENTERED))) {     // 此時為false
		      ...............
		}
		binder_set_nice(proc->default_priority);//把當前線程的優先級設置為它所屬進程的優先級
		if (non_block) {//非阻塞要立刻返回處理結果
			if (!binder_has_proc_work(proc, thread))//有任務就接著往下執行,沒有任務就返回
				ret = -EAGAIN;
		} else
			ret = wait_event_interruptible_exclusive(proc->wait, binder_has_proc_work(proc, thread));//睡眠等待直到其所屬的進程有新的未處理項為止
	} else {
		if (non_block) {//非阻塞要立刻返回處理結果
			if (!binder_has_thread_work(thread))有任務就接下往下執行,沒有任務就返回
				ret = -EAGAIN;
		} else
			ret = wait_event_interruptible(thread->wait, binder_has_thread_work(thread));//睡眠等待直到線程有新的未處理項為止
	}
	mutex_lock(&binder_lock);
	if (wait_for_proc_work)//為1
		proc->ready_threads--;//ready_thread為0
	thread->looper &= ~BINDER_LOOPER_STATE_WAITING;//looper為BINDER_LOOPER_STATE_ENTERED

	if (ret)
		return ret;

	while (1) {
		........
	}

done:

	*consumed = ptr - buffer;
	..........
	return 0;
}

static int
binder_has_proc_work(struct binder_proc *proc, struct binder_thread *thread)
{
	return !list_empty(&proc->todo) || (thread->looper & BINDER_LOOPER_STATE_NEED_RETURN);
}

static int
binder_has_thread_work(struct binder_thread *thread)
{
	return !list_empty(&thread->todo) || thread->return_error != BR_OK ||
		(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN);
}
如果線程thread中沒有要處理的數據,那麼就處理進程proc上等待的數據。如果進程上沒有數據要處理,那麼睡眠等待直到其所屬的進程有新的未處理項為止。

如果線程thread中有要處理的數據,那麼就處理線程thread上的數據。如果線程上沒有數據要處理,那麼睡眠等待直到線程有新的未處理項為止。

如果是非阻塞訪問,如果沒有數據,就立刻返回,不會睡眠等待。如果有數據,就繼續往下執行。

目前由於線程thread沒有要處理的數據,進程上也沒有要處理的數據,那麼睡眠等待直到其所屬的進程有新的未處理項為止。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved