https://my.oschina.net/youranhongcha/blog/149575 侯 亮的Binder系列文章.
1、ProcessState
ProcessState::ProcessState() //构造
: mDriverFD(open_driver())//在初始化列表时打开驱动.
, mVMStart(MAP_FAILED)
, mManagesContexts(false)
, mBinderContextCheckFunc(NULL)
, mBinderContextUserData(NULL)
, mThreadPoolStarted(false)
, mThreadPoolSeq(1)
{
if (mDriverFD >= 0) {
// mmap the binder, providing a chunk of virtual address space to receive transactions.
//把设备文件映射到进程的虚拟地址空间.第一个好处,可以直接读写。
//BINDER_VM_SIZE = ((1*1024*1024) - (4096 *2)) 1M-8K
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
if (mVMStart == MAP_FAILED) {
//......
}
#else
mDriverFD = -1;
#endif
}
//......
}
struct handle_entry {
IBinder* binder;
RefBase::weakref_type* refs;
};
IPCThreadState* IPCThreadState::self()
{
if (gHaveTLS) {//第一次进来为false
restart:
const pthread_key_t k = gTLS;
//TLS是Thread Local Storage的意思.线程本地存储的意思(C层实现的和java层的ThreadLocal类一样),
//有pthread_getspecific,那么肯定有地方调用 pthread_setspecific。
IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
if (st) return st;
return new IPCThreadState;
}
//......
}
IPCThreadState::IPCThreadState()
: mProcess(ProcessState::self()),//很关键!!!
mMyThreadId(androidGetTid()),
mStrictModePolicy(0),
mLastTransactionBinderFlags(0)
{
pthread_setspecific(gTLS, this);//在构造中这个存入本地存储区.保证每个线程有自己的IPCThreadState.
clearCaller();
mIn.setDataCapacity(256);
mOut.setDataCapacity(256);
}
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
// Once a binder has died, it will never come back to life.
if (mAlive) {
//当是一个service通过service manager 调用addservice,然后到这里的时候.
//这里的mHandle为0,code为ADD_SERVICE_TRANSACTION。ADD_SERVICE_TRANSACTION是上面以参数形式传进来的,
//那mHandle的只是由前面实例化BpBinder传入的值决定的,一般在如:BpXXXX : public BpInterface
//而在实例化BpXXX的时候构造中都会需要传入一个IBinder对象,在跨进程调用的时候这个对象就是此处的BpBinder
//传入这个BpBinder的时候由于模板类BpInterface就会去实例化BpRefBase最终实例化这个BpBinder的相关变量.
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
status_t err = data.errorCheck();
//IPCThreadState::transact函数的参数flags ==0 ,这是因为在BpBinder中默认参数列表传入的0.
flags |= TF_ACCEPT_FDS;//TF_ACCEPT_FDS = 0x10 ,binder.h linux中
//......
if (err == NO_ERROR) {
//准备好一个struct binder_transaction_data结构体变量,这个是等一下要传输给Binder驱动程序的数据.
//这里就是发送数据的地方.把它的handle,code,data封装好然后写入到IPCThreadState的mOut中
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
}
//......
//如果没有设置TF_ONE_WAY这个置也就是需要回复。
if ((flags & TF_ONE_WAY) == 0) {//0x10&0x01确实会进入.
//......
//等待回复,如果reply可以用就直接用,否则自己新建一个.
if (reply) {
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
//......
} else {
//不需要回复的时候会走到这里.
err = waitForResponse(NULL, NULL);
}
return err;
}
status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
binder_transaction_data tr;//代表Binder传输过程中的数据.
//这个结构体的初始化设置.tr.target.ptr = 0; /* Don't pass uninitialized stack data to a remote process */
tr.target.handle = handle;
tr.code = code;//注意!!!!这个code会存入到封装的binder_transaction_data结构体当中!!!!!注意和cmd的区别
tr.flags = binderFlags;
tr.cookie = 0;
tr.sender_pid = 0;
tr.sender_euid = 0;
const status_t err = data.errorCheck();
if (err == NO_ERROR) {
tr.data_size = data.ipcDataSize();
//data.ipcData();就相当于.
//writeInt32(IPCThreadState::self()->getStrictModePolicy() | STRICT_MODE_PENALTY_GATHER);
//writeString16("android.os.IServiceManager");
//writeString16("media.player");
//writeStrongBinder(new MediaPlayerService());
tr.data.ptr.buffer = data.ipcData();
//真正要传输的数据保存的地方.tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
//记录一下偏移量.tr.data.ptr.offsets = data.ipcObjects();
} else if (statusBuffer) {
//......
} else {
return (mLastError = err);
}
//Parcel mOut 往驱动发送的数据最终都存入到mOut.
mOut.writeInt32(cmd);//cmd为BC_TRANSACTION直接存入到mOut当中,在binder_thread_write方法中读取.
mOut.write(&tr, sizeof(tr));
return NO_ERROR;
}
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
int32_t cmd;
int32_t err;
while (1) {
//
最后bwr.write_size和bwr.read_size均为0,IPCThreadState::talkWithDriver函数什么也不做,返回到IPCThreadState::waitForResponse函 中// 在IPCThreadState::waitForResponse函数,又继续从mIn读出一个整数,这个便是BR_TRANSACTION_COMPLETE.// 进入到Binder驱动程序中的binder_ioctl函数中。由于bwr.write_size为0,bwr.read_size不为0,这次 直接就进入到binder_thread_read //函数中。这时候,//thread->transaction_stack!=0,thread- >todo为空,线程通过: wait_event_interruptible(thread->wait, binder_has_thread_work(thread))//进入睡眠状态,等待Service Manager来唤醒了。(!!!!反正最终又是要等待Service Manager来唤醒,注意此时Service Manager已经被唤醒)//主要调用了talkWithDriver函数来与Binder驱动程序进行交互
if ((err=talkWithDriver()) < NO_ERROR) break;
//从驱动返回以后,这里开始操作mIn了,看来talkWithDriver中把mOut发出去,然后从driver中读到数据放到mIn中了。
err = mIn.errorCheck();//addservice时候,mIn读出一个整数,这个便是BR_NOOP了,这是一个空操作,什么也不做。
if (err < NO_ERROR) break;
if (mIn.dataAvail() == 0) continue;
cmd = mIn.readInt32();//取出来驱动放入的命令.
//......
switch (cmd) {
case BR_TRANSACTION_COMPLETE:
if (!reply && !acquireResult) goto finish;
break;
case BR_DEAD_REPLY:
err = DEAD_OBJECT;
goto finish;
case BR_FAILED_REPLY:
err = FAILED_TRANSACTION;
goto finish;
case BR_ACQUIRE_RESULT:
{
ALOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
const int32_t result = mIn.readInt32();
if (!acquireResult) continue;
*acquireResult = result ? NO_ERROR : INVALID_OPERATION;
}
goto finish;
case BR_REPLY:
{
binder_transaction_data tr;
err = mIn.read(&tr, sizeof(tr));
ALOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
if (err != NO_ERROR) goto finish;
if (reply) {
if ((tr.flags & TF_STATUS_CODE) == 0) {
reply->ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t),
freeBuffer, this);
} else {
err = *reinterpret_cast<const status_t*>(tr.data.ptr.buffer);
freeBuffer(NULL,
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), this);
}
} else {
freeBuffer(NULL,
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), this);
continue;
}
}
goto finish;
default:
err = executeCommand(cmd);//注意!
if (err != NO_ERROR) goto finish;
break;
}
}
finish:
//......
return err;
}
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
if (mProcess->mDriverFD <= 0) {
return -EBADF;
}
// binder_write_read是用来与Binder设备交换数据的结构,
binder_write_read bwr;//来换传入Binder命令的时候就会用到这个结构体.
// Is the read buffer empty?
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
// We don't want to write anything if we are still reading
// from data left in the input buffer and the caller
// has requested to read the next data.
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
//先是在写的缓冲区写入要发送给驱动的数据,
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data();//!!!非常重要,看出来把前面的cmd和
binder_transaction_data放入到了buffer
// This is what we'll read.
if (doReceive && needRead) {
//接收数据缓冲区信息的填充。如果以后收到数据,就直接填在mIn中了。
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
bwr.read_size = 0;
bwr.read_buffer = 0;
}
//......
// Return immediately if there is nothing to do.
status_t err;
do {
//......
#if defined(HAVE_ANDROID_OS)
//看来不是read/write调用去和Binder设备文件进行通信,而是ioctl方式。
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)//最终去和驱动进行通信.
err = NO_ERROR;
else
err = -errno;
#else
err = INVALID_OPERATION;
#endif
if (mProcess->mDriverFD <= 0) {
err = -EBADF;
}
//......
} while (err == -EINTR);//应该是只要有数据就会一直循环的往外发送,通过ioctl的返回值判断的.
//......
if (err >= NO_ERROR) {
//到这里从驱动中回来了,回复数据就在bwr中了,bmr接收回复数据的buffer就是mIn提供的
if (bwr.write_consumed > 0) {
if (bwr.write_consumed < mOut.dataSize())
mOut.remove(0, bwr.write_consumed);
else
mOut.setDataSize(0);//从驱动回来以后,首先是把mOut的数据清空.方便下一次操作啊.
}
if (bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);//然后设置已经读取的内容的大小.
mIn.setDataPosition(0);
}
//......
return NO_ERROR;
}
//然后就返回到了waitForResponse当中.我们去看一下.
//在addservice流程中到这里,我们发送addService的流程就彻底走完了。
return err;
}
void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
if (!mThreadPoolStarted) {
mThreadPoolStarted = true;
spawnPooledThread(true);
}
}
void ProcessState::spawnPooledThread(bool isMain)
{
if (mThreadPoolStarted) {
String8 name = makeBinderThreadName();
ALOGV("Spawning new pooled thread, name=%s\n", name.string());
//创建线程池,然后run起来,和java的Thread何其像也。
sp<Thread> t = new PoolThread(isMain);//会去实例化父类Thread.
t->run(name.string());//调用PoolThread::run,实际调用了父类Thread的run
}
}
virtual bool threadLoop()
{
//此时mIsMain为true.
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
}
void IPCThreadState::joinThreadPool(bool isMain)
{
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
set_sched_policy(mMyThreadId, SP_FOREGROUND);
status_t result;
do {//进入到这个循环中.
processPendingDerefs();
// now get the next command to be processed, waiting if necessary
result = getAndExecuteCommand();//去里面读取
if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
......
}
// Let this thread exit the thread pool if it is no longer
// needed and it is not the main process thread.
if(result == TIMED_OUT && !isMain) {
break;
}
} while (result != -ECONNREFUSED && result != -EBADF);
......
mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);
}
status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
int32_t cmd;
result = talkWithDriver();
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();
if (IN < sizeof(int32_t)) return result;
cmd = mIn.readInt32();
IF_LOG_COMMANDS() {
alog << "Processing top-level Command: "
<< getReturnString(cmd) << endl;
}
result = executeCommand(cmd);
// After executing the command, ensure that the thread is returned to the
// foreground cgroup before rejoining the pool. The driver takes care of
// restoring the priority, but doesn't do anything with cgroups so we
// need to take care of that here in userspace. Note that we do make
// sure to go in the foreground after executing a transaction, but
// there are other callbacks into user code that could have changed
// our group so we want to make absolutely sure it is put back.
set_sched_policy(mMyThreadId, SP_FOREGROUND);
}
return result;
}
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR;
switch (cmd) {
......
default:
printf("*** BAD COMMAND %d received from Binder driver\n", cmd);
result = UNKNOWN_ERROR;
break;
}
if (result != NO_ERROR) {
mLastError = result;
}
return result;
}
case BR_TRANSACTION: //Binder通信
{
binder_transaction_data tr;
result = mIn.read(&tr, sizeof(tr));
ALOG_ASSERT(result == NO_ERROR,
"Not enough command data for brTRANSACTION");
if (result != NO_ERROR) break;
Parcel buffer;
buffer.ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), freeBuffer, this);
const pid_t origPid = mCallingPid;
const uid_t origUid = mCallingUid;
const int32_t origStrictModePolicy = mStrictModePolicy;
const int32_t origTransactionBinderFlags = mLastTransactionBinderFlags;
mCallingPid = tr.sender_pid;
mCallingUid = tr.sender_euid;
mLastTransactionBinderFlags = tr.flags;
int curPrio = getpriority(PRIO_PROCESS, mMyThreadId);
if (gDisableBackgroundScheduling) {
if (curPrio > ANDROID_PRIORITY_NORMAL) {
// We have inherited a reduced priority from the caller, but do not
// want to run in that state in this process. The driver set our
// priority already (though not our scheduling class), so bounce
// it back to the default before invoking the transaction.
setpriority(PRIO_PROCESS, mMyThreadId, ANDROID_PRIORITY_NORMAL);
}
} else {
if (curPrio >= ANDROID_PRIORITY_BACKGROUND) {
// We want to use the inherited priority from the caller.
// Ensure this thread is in the background scheduling class,
// since the driver won't modify scheduling classes for us.
// The scheduling group is reset to default by the caller
// once this method returns after the transaction is complete.
set_sched_policy(mMyThreadId, SP_BACKGROUND);
}
}
//ALOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid);
//前面是来了一个命令,解析成BR_TRANSACTION,然后读取后续的信息
Parcel reply;
status_t error;
IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BR_TRANSACTION thr " << (void*)pthread_self()
<< " / obj " << tr.target.ptr << " / code "
<< TypeCode(tr.code) << ": " << indent << buffer
<< dedent << endl
<< "Data addr = "
<< reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer)
<< ", offsets addr="
<< reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl;
}
if (tr.target.ptr) {
sp<BBinder> b((BBinder*)tr.cookie);//看来这个binder_transaction_data.cookie很关键啊!!!!!!!!
error = b->transact(tr.code, buffer, &reply, tr.flags);
} else {
/*
the_context_object是IPCThreadState.cpp中定义的一个全局变量,
可通过setTheContextObject函数设置
*/
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
}
//ALOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n",
// mCallingPid, origPid, origUid);
if ((tr.flags & TF_ONE_WAY) == 0) {
LOG_ONEWAY("Sending reply to %d!", mCallingPid);
if (error < NO_ERROR) reply.setError(error);
sendReply(reply, 0);
} else {
LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
}
mCallingPid = origPid;
mCallingUid = origUid;
mStrictModePolicy = origStrictModePolicy;
mLastTransactionBinderFlags = origTransactionBinderFlags;
IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
<< tr.target.ptr << ": " << indent << reply << dedent << endl;
}
}
break;
status_t BBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
data.setDataPosition(0);
status_t err = NO_ERROR;
switch (code) {
case PING_TRANSACTION:
reply->writeInt32(pingBinder());
break;
default:
err = onTransact(code, data, reply, flags);//就是调用自己的onTransact函数嘛,谁实例化的就调用谁!
break;
}
if (reply != NULL) {
reply->setDataPosition(0);
}
return err;
}