在Android中ProcessState是客户端和服务端公共的部分,作为Binder通信的基础,ProcessState是一个singleton类,每个
进程只有一个对象,这个对象负责打开Binder驱动,建立线程池,让其进程里面的所有线程都能通过Binder通信。
与之相关的是IPCThreadState,每个线程都有一个IPCThreadState实例登记在Linux线程的上下文附属数据中,主要负责
Binder的读取,写入和请求处理框架。IPCThreadState在构造的时候获取进程的ProcessState并记录在自己的成员变量
mProcess中,通过mProcess可以获得Binder的句柄。

frameworks/base/include/binder/ProcessState.h
class ProcessState : public virtual RefBase
{
public:
static sp<ProcessState> self(); // 单例模式,获取实例 void setContextObject(const sp<IBinder>& object);
sp<IBinder> getContextObject(const sp<IBinder>& caller); void setContextObject(const sp<IBinder>& object, const String16& name);
sp<IBinder> getContextObject(const String16& name, const sp<IBinder>& caller); void startThreadePool(); typdef bool (*context_check_func)(const String16& name, const sp<IBinder>& caller, void* userData); bool isContextManager(void) const;
bool becomeContextManager(context_check_func checkFunc, void* userData); sp<IBinder> getStrongProxyForHandle(int32_t handle);
wp<IBinder> getWeakProxyForHandle(int32_t handle);
void espungeHandle(int32_t handle, IBinder* binder); void spawnPooledThread(boot isMain);
private:
friend class IPCThreadState;
ProcessState();
~ProcessState;
ProcessState(const ProcessState& o);
ProcessState& operator=(const ProcessState& o); struct hdndle_entry {
IBinder* binder;
RefBase::weakref_type* refs;
}; handle_entry* lookupHandleLocked(int32_t handle); int mDriverFD; // 打开的binder驱动文件描述符
void* mVMStart; Vector<handle_entry> mHandleToObject; bool mManagerContexts;
context_check_func mBinderContextCheckFunc;
void* mBinderContextUserData;
KeyedVector<String16, sp<IBinder> > mContexts; // 映射,服务名字 和 IBinder对应
bool mThreadPoolStarted; // 线程池是否已经创建
volatile int32_t mThreadPoolSeq; // 这个进程中启动线程个数
};

1)获得ProcessState的实例

sp<ProcessState> proc(ProcessState::self());
调用函数:
sp<ProcessState> ProcessState::self()
{
if (gProcess != NULL) return gProcess;
AutoMutext _l(gProcessMutex);
if(gProcess == NULL) gProcess = new ProcessState;
return gProcess;
}
进入构造函数:
ProcessState::ProcessState() : mDriverFD(open_driver())
, mVMStart(MAP_FAILED),
, mManagerContexts(false)
, mBinderContextCheckFunc(NULL)
, mBinderContextUserData(NULL)
, mThradPoolStarted(false)
, mThreadPoolSeq(1)
{ }

这个构造函数里面调用open_driver()打开了/dev/binder设备驱动文件,返回文件描述符。这样我们就能通过这个mDriverFd
来和binder驱动交互了。

2)创建线程ProcessState::self()->startThreadPool();

void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
if(!mThreadPoolStarted) {
mThreadPoolStarted = true;
spawnPooledThread(true);
}
}
void ProcessState::spawnPoolThread(bool isMain)
{
if (mThreadPoolStarted) {
int32_t s = android_atomic_add(1, &mThreadPoolSeq);
sp<Thread> t = new PoolThread(isMain);
t->run(buf);
}
}
其实这里就是创建一个线程PoolThread,而PoolThread是一个继承于Thread的类。所以调用t->run()之后相当于调用
PoolThread类的threadLoop()函数,我们来看看PoolThread类的threadLoop线程函数。
virtual bool threadLoop()
{
IPCThreadState::self()->joinThreadPool(mIsMain);
// 这里线程函数调用了一次IPCThreadState::self()->joinThreadPool()后就退出了
return false;
}

3)IPCThreadState::self()->joinThreadPool();

我们知道:进程调用spawnPoolThread()创建了一个线程,执行joinThreadPool(),而主线程也是调用这个函数。唯一区别
是参数,主线程调用的joinThreadPool(true),创建的线程调用的是jointThreadPool(false)。
下面我们来分析下这个函数,首先我们来看看IPCThreadState这个类

frameworks/base/include/IPCThreadState.h
class IPCThreadState
{
public:
static IPCThreadState* self();
sp<ProcessState> process();
......
void joinThradPool(bool isMain = true);
status_t transact(int32_t handle, uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
void incStrongHandle(int32_t handle);
void decStrongHandle(int32_t handle);
void incWeakHandle(int32_t handle);
void decWeakHandle(int32_t handle);
private:
IPCThraedState();
~IPCThreadState();
status_t sendReplay(const Parcel& reply, uint32_t flags);
status_t waitForResponse(Parcel& reply, status_t *acquireResult = NULL);
status_t talkWithDriver(bool doReceice = true);
status_t writeTransactionData();
status_t executeCommand();
private:
sp<ProcessState> mProcess;
Vector<BBinder> mPendingStrongDerefs;
Vector<RefBase::weakref_type*> mPendingWeakDerefs;
Parcel mIn;
Parcel mOut;
}
上面是IPCThreadState类常用的几个函数。
IPCThreadState* IPCThreadState::self()
{
if(gHaveTLS) { // 第一次进来肯定为false
restart:
const pthread_key_t k = gTLS;
IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
if(st) return st;
return new IPCThreadState; // new 一个IPCThreadState对象
} if(gShutdown) return NULL; pthread_mutex_lock(&gTLSMutex);
if(!gHaveTLS) {
// 第一个参数为指向一个键值的指针,第二个参数指明一个destructor函数,当线程结束时调用
if(phread_key_create(&gTLS, threadDestructor) != 0) {
pthread_mutex_unlock(&gTLSMutex);
return NULL;
}
gHaveTLS = true;
}
pthread_mutex_unlock(&gTLSMutex);
goto restart;
}

下面来说明下线程中特有的线程存储:Thread Specific Data.
在多线程中,所有线程共享程序中变量,如果每一个线程都希望单独拥有它,就需要线程存储了。即一个变量表面看起来是
全局变量,所有线程都可以使用它,它的值在每一个线程都是单独存储的。
用法:
       1)创建一个类型为pthread_key_t 类型变量
       2)pthread_key_create()创建改变量,第二个参数表上一个清理函数,用来在线程释放该线程存储的时候调用。
       3)当线程中需要存储特殊值的时候,可以用pthread_setspecific(),第一个参数为pthread_key_t 变量,第二个参数为void* 变量,可以存储任何类型的值。
       4)当需要取出存储值的时候,调用pthread_getspecific(),返回void*类型变量值。

好了我们现在知道pthread_key_t是干什么用的了?既然代码中有pthread_getspecific()获取IPCThreadState*对象的函数
那么肯定有设置这个变量值的地方?我们找到IPCThreadState的构造函数:

IPCThreadState:IPCThreadState()
: mProcess(ProcessState::self()),
mMyThreadId(androidGetTid()),
mStrictModePolicy(0),
mLastTransactionBinderFlags(0)
{
pthread_setspecific(gTLS, this); // 设置为当前this 指针
clearCaller();
mIn.setDataCapacity(256); // 这里mIn 和 mOut分别表示Binder输入输出的变量,我们后面分析
mOut.setDataCapacity(256);
}
最后进入IPCThreadState::joinThreadPool(bool isMain)
void IPCThreadState::joinThreadPool(bool isMain) // 默认为true
{
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
do {
int32_t cmd; if(mIn.dataPosition() >= mIn.dataSize()){
size_t numPending = mPendingWeakDerefs.size();
if(numPending > 0) {
for(size_t i = 0; i < numPending; i++) {
RefBase::weakref_type* refs = mPendingWeakDerefs[i];
refs->decWeak(mProcess.get);
}
mPendingWeakDerefs.clear();
}
numPending = mPendingStrongDerefs.size();
if(numPending > 0) {
for(sizt_t i = 0; i < numPending; i++) {
BBinder* obj = mPendingStrongDerefs[i];
obj->decStrong(mProcess.get);
}
mPendingStrongDerefs.clear();
}
}
// 读取下一个command进行处理
result = talkWithDriver();// 来等待Client的请求
if(result >= NO_ERROR) {
size_t IN = mIn.dataAvail();
if(IN < sizeof(int32_t)) continue;
cmd = mIn.readInt32();
}
result = executeCommand(cmd); if(result == TIMED_OUT && !isMain)
break;
} while(result != -ECONNREFUSED && result != -EBADF); mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);
}

这里的talkWithDriver()里面之际调用的是ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)从/dev/binder读取
Client端发过来的请求,然后调用executeCommand处理

status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR; switch(cmd) {
case BR_TRANSACTION:
binder_transaction_data tr;
result = mIn.read(&tr, sizeof(tr));
....
Parcel reply;
if(tr.target.ptr) {
sp<BBinder> b((BBinder*)tr.cookie);
const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);
}
....
break; }
}
最后又调用到BBinder 的transact()函数里面去了。
status_t BBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags )
{
data.setDataPosition(0);
switch(code)
{
case PING_TRANSACTION:
reply->writeInt32(pingBinder());
break;
default:
err = onTransact(code, data, reply, flags);
break;
}
return err;
}

到这里IPCThreadState类的流程就大概清楚了,线程调用joinThreadPool()从/dev/binder读取客户端的请求,然后调用
BBinder::transact()处理。那么这个BBinder是怎么来的呢?
上面代码中:sp<BBinder> b((BBinder*)tr.cookie)说明这个BBinder指针是从Binder驱动中获取到,肯定是客户端
发送过来的,那么它的实际类型又是什么呢?而BBinder调用的onTransact()函数只是一个虚函数,肯定由它的子类来实
现,那我们服务端又怎么找到这个BBinder的实际类型呢?
这些内容我们下一节通过MediaPlayer这个具体示例分析。

[置顶] Android开发之ProcessState和IPCThreadState类分析的更多相关文章

  1. [置顶] Android开发之MediaPlayerService服务详解(一)

    前面一节我们分析了Binder通信相关的两个重要类:ProcessState 和 IPCThreadState.ProcessState负责打开Binder 驱动,每个进程只有一个.而 IPCThre ...

  2. [置顶] Android开发之serviceManager分析

    Android 开发之serviceManager分析 在Android系统中用到最多的通信机制就是Binder,Binder主要由Client.Server.ServiceManager和Binde ...

  3. [置顶] Android开发之XML文件的解析

    Android系统开发之XML文件的解析 我们知道Http在网络传输中的数据组织方式有三种分别为:XML方式.HTML方式.JSON方式.其中XML为可扩展标记语言,如下: <?xml vers ...

  4. [置顶] Android开发之Thread类分析

    在我们Linux系统中创建线程函数为:pthread_create(),在Android中我们为线程封装了一个类Thread,实际调用的还是pthread_create() 当我们想创建线程的时候,只 ...

  5. [置顶]Python开发之路

    阅读目录   第一篇:python入门 第二篇:数据类型.字符编码.文件处理 第三篇:函数 第四篇:模块与包 第五篇:常用模块 第六篇:面向对象 第七篇:面向对象高级 第八篇:异常处理 第九篇:网络编 ...

  6. Android 开发之Matrix图片处理类的使用

    在Android中,对图片的处理需要使用到Matrix类,Matrix是一个3 x 3的矩阵,他对图片的处理分为四个基本类型: 1.Translate————平移变换 2.Scale————缩放变换 ...

  7. Android开发之java代码工具类。判断当前网络是否连接并请求下载图片

    package cc.jiusan.www.utils; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; ...

  8. 【Android UI】Android开发之View的几种布局方式及实践

    引言 通过前面两篇: Android 开发之旅:又见Hello World! Android 开发之旅:深入分析布局文件&又是“Hello World!” 我们对Android应用程序运行原理 ...

  9. Android开发之ViewPager+ActionBar+Fragment实现响应式可滑动Tab

     今天我们要实现的这个效果呢,在Android的应用中十分地常见,我们可以看到下面两张图,无论是系统内置的联系人应用,还是AnyView的阅读器应用,我们总能找到这样的影子,当我们滑动屏幕时,Tab可 ...

随机推荐

  1. codevs1002搭桥(建图+Prim)

    /* 先来个灌水法 然后建图跑最小生成树 注意观察题目中的规则 a[1][i]!=a[1][j]&&abs(a[2][i]-a[2][j])<=1 建图的时候可以每一个建筑物都看 ...

  2. 抓取锁的sql语句-第一次修改

    CREATE OR REPLACE PROCEDURE SOLVE_LOCK AS V_SQL VARCHAR2(3000); CUR_LOCK SYS_REFCURSOR; TYPE TP_LOCK ...

  3. iOSUI基础——懒加载

    1.懒加载基本 懒加载——也称为延迟加载,即在需要的时候才加载(效率低,占用内存小).所谓懒加载,写的是其get方法. 注意:如果是懒加载的话则一定要注意先判断是否已经有了,如果没有那么再去进行实例化 ...

  4. 第一章 Javascript基础

    一.Javascript概述(知道) a.一种基于对象和事件驱动的脚本语言 b.作用: 给页面添加动态效果 c.历史: 原名叫做livescript.W3c组织开发的标准叫ECMAscipt. d.特 ...

  5. 【COGS 56】质数取石子

    [问题描述] DD 和 MM 正在玩取石子游戏.他们的游戏规则是这样的:桌上有若干石子,DD 先取,轮流取,每次必须取质数个.如果某一时刻某一方无法从桌上的石子中取质数个,比如说剩下 0 个或 1 个 ...

  6. 【USACO 1.5.1】数字金字塔

    [题目描述] 观察下面的数字金字塔. 写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大.每一步可以走到左下方的点也可以到达右下方的点. 7 3 8 8 1 0 2 7 4 4 4 ...

  7. dbm数据库

    所有版本的linux以及大多数的UNIX版本都随系统带有一个基本的.但却非常搞笑的数据存储历程集,他被称为dbm数据库.适用于存储比较静态的索引化数据库,即使用索引来存储可变长的数据结构,然后通过索引 ...

  8. 13_FCITX输入法安装及问题排查解决

    使用linux最沮丧的事情莫过于中文输入法切换不出来,甚至有人错误地认为,要使用中文输入法,必须把“区域和语言”(Region & Language)设置为中国-中文.输入法只是一个软件,和区 ...

  9. (兼容IE6)又一个提示框思密达,腾讯UED 201401242352

    找乐子 仿QQ空间的,先来看下,别嫌代码垃圾,业余菜鸟一个,用到的话就当个乐子就行了 注意: 因为有同学说需要IE6便做了一下. 已经处理了IE6,可测试. 腾讯的东西,感觉还好吧:) 使用方法老简单 ...

  10. jQuery MVC 科室异步联动

    //科室改变,级联医生 js $("#DepartmentId").change(function () { if (isNaN($(this).val())) { $(" ...