MediaPlayerService的代码位于frameworks/base/media/mediaserver/main_mediaserver.cpp文件中:
只关心下面的5行代码, 下面一一对这个5行代码分析
int main(int argc, char** argv)
{
sp proc(ProcessState::self());
sp sm = defaultServiceManager();
MediaPlayerService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
分析sp
ProcessState类的在frameworks/base/include/binder/ProcessState.h中定义:
class ProcessState : public virtual RefBase
{
public:
static sp self();
void setContextObject(const sp& object);
sp getContextObject(const sp& caller);
void setContextObject(const sp& object, const String16& name);
sp getContextObject(const String16& name,const sp& caller);
void startThreadPool();
typedef bool (*context_check_func)(const String16& name,const sp& caller,void* userData);
bool isContextManager(void) const;
bool becomeContextManager(context_check_func checkFunc, void* userData);
sp getStrongProxyForHandle(int32_t handle);
wp getWeakProxyForHandle(int32_t handle);
void expungeHandle(int32_t handle, IBinder* binder);
.....
void spawnPooledThread(bool isMain);
private:
friend class IPCThreadState;//IPCThreadState是它的友元类,所以IPCThreadState可以调用它的相关函数
ProcessState();
~ProcessState();
ProcessState(const ProcessState& o);
struct handle_entry {IBinder* binder; RefBase::weakref_type* refs;};
handle_entry* lookupHandleLocked(int32_t handle);
int mDriverFD;//binder驱动的文件描述符
void* mVMStart; //映射的内存指针
mutable Mutex mLock; // protects everything below.
VectormHandleToObject;
bool mManagesContexts;
context_check_func mBinderContextCheckFunc;
void* mBinderContextUserData;
KeyedVector > mContexts;
String8 mRootDir;
bool mThreadPoolStarted;
volatile int32_t mThreadPoolSeq;
};
sp
sp ProcessState::self()
{
//gProcess:全局对象指针,如果这个指针已被赋值则返回它
//gProcess在Static.cpp中定义 :sp gProcess;
if (gProcess != NULL) return gProcess;
AutoMutex _l(gProcessMutex);
//否则的话,则构造ProcessState对象,并付给gProcess
if (gProcess == NULL) gProcess = new ProcessState;
return gProcess;
}
new ProcessState,则调用它的构造函数,构造函数的简化形式如下:
ProcessState::ProcessState()
: mDriverFD(open_driver())
, mVMStart(MAP_FAILED)
, mManagesContexts(false)
, mBinderContextCheckFunc(NULL)
, mBinderContextUserData(NULL)
, mThreadPoolStarted(false)
, mThreadPoolSeq(1)
{
if (mDriverFD >= 0)
{
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
}
}
说明:构造函数主要做一下内容,先对成员变量进行处理,其中最重要的一个就是,打开binder驱动,并对驱动的文件描述符付给mDriverFD.
然后,通过mmap函数,映射出binder驱动对应的映射内存缓冲区付给mVMStart.
看open_driver函数的实现:
static int open_driver()
{
int fd = open("/dev/binder", O_RDWR);//打开binder驱动
if (fd >= 0)
{
fcntl(fd, F_SETFD, FD_CLOEXEC);//设置文件操作的一些属性
//通过ioctl+BINDER_VERSION命令,获取binder驱动的版本
int vers;
status_t result = ioctl(fd, BINDER_VERSION, &vers);
//通过ioctl+BINDER_SET_MAX_THREADS命令,告诉binder驱动最大线程数
size_t maxThreads = 15;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
}
return fd;
}
这个函数做了一下工作:
1、同binder驱动建立链接
2、获得驱动的版本。
3、通知驱动,我最多可同时启动15个线程来处理Client端的请求
我们来看一下ioctl文件操作函数执行BINDER_VERSION和BINDER_SET_MAX_THREADS命令的过程,这个函数调用最终进入到Binder驱动程序的binder_ioctl函数中,我们只关注相关的部分逻辑:
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
//每open一个binder驱动,都会有一个专门的binder_proc管理当前进程的信息,包括进程的ID,当前进程由mmap所映射出的buffer信息
//以及当前进程所允许的最大线程量,binder_proc会加入到系统的全局链表binder_procs中去
struct binder_proc *proc = filp->private_data;
//打开binder驱动的进程可以存在多线程,因此binder驱动使用binder_thread来管理对应的线程信息,主要包括线程所属的binder_proc
//当前状态looper以及一个transaction_stack(我的理解是负责着实际进程间通信交互的源头和目的地)
struct binder_thread *thread;
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
mutex_lock(&binder_lock);
//第一次时,会创建一个binder_thread结构保存线程信息,保存到对应的进程binder_proc->threads红黑树中
//第二次时,根据proc里的线程信息去到该进程binder_proc->threads红黑树中去查询,如果有则返回这个结构指针
thread = binder_get_thread(proc);
switch (cmd) {
//获取版本命令
case BINDER_VERSION:
//将BINDER_CURRENT_PROTOCOL_VERSION写入到传入的参数arg指向的用户缓冲区中去就返回了
if (put_user(BINDER_CURRENT_PROTOCOL_VERSION, &((struct binder_version *)ubuf)->protocol_version)) {
ret = -EINVAL;
goto err;
}
break;
//设置最大线程数命令
case BINDER_SET_MAX_THREADS:
//把该进程的最大线程数写入该进程的binder_proc结构里
if (copy_from_user(&proc->max_threads, ubuf, sizeof(proc->max_threads))) {
ret = -EINVAL;
goto err;
}
break;
default:
ret = -EINVAL;
goto err;
}
ret = 0;
return ret;
}
总结:这句代码按顺序主要做了下面的工作:
1、构建ProcessState全局对象gProcess.
2、打开binder驱动,建立链接。
3、在驱动内部创建该进程的binder_proc、binder_thread结构,保存该进程的进程信息和线程信息。并加入到系统的红黑树。
4、获得驱动的版本信息。
5、把该进程最到可同时启动的线程数告诉驱动,并保存到该进程的binder_proc结构中。
6、把设备文件/dev/binder映射到内存中