hello,亲,你好,我叫王菜鸟,菜鸟前段时间迷茫了,因为现在是在做app相关,而且陷入了公司的业务逻辑,所以和系统与功能实现还有Android脱轨了,迷茫要不要继续学framework,要不要直接去做功能,因为framework了解的越深,越有助于解决功能性能,优化,还有方法等一系列疑难杂症,所以菜鸟觉得,不能放弃学framework,而且菜鸟现在系统水平和尴尬,你说知道吧,掌握不透,你说不知道吧还知道一点,但是我觉得越来越清晰,我再一次看的时候我觉得我有的就理解了,所以菜鸟觉得应该坚持下去。
菜鸟这段时间抽风,买了单反,报名吉他,打算充实一些业余生活,菜鸟觉得,应该学会发现美,也许过段时间可能我还会一周来一次直播,直播弹吉他,直播解决我所学的问题。从下周我也开始上传我拍的一些美美照片和大家分享,哈哈,有想法就去实现,就算是现在一无所有也要去实现,人生就那么短,三分之一已经过去了,还有三分之一已经干不动啥了,剩下这三分之一要不去做一些想干的事情,我觉得我会留下遗憾。加油菜鸟,加油大家。
本文未解决问题:
-
IBinder b = ServiceManager.getService("activity");
得到BinderProxy对象 - 在android_os_BinderProxy_transact中
IBinder* target = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject);
保存的是new BpBinder(handle)对象
gBinderProxyOffsets.mObject中保存的是BpBinder对象, 这是开机时Zygote调用AndroidRuntime::startReg方法来完成jni方法的注册.
- IPCThreadState::transact中flags |= TF_ACCEPT_FDS是干啥的?
- BpBinder::transact中
IPCThreadState::self()->transact( mHandle, code, data, reply, flags);
这个mHandle是从何而来干啥的? - IPCThreadState::writeTransactionData() mOut.write(&tr, sizeof(tr)); //写入binder_transaction_data数据
基础知识
IActivityManager相关类
IActivityManager.png- Activity的管理采用binder机制,管理Activity的接口是IActivityManager
- ActivityManagerService实现了Activity管理功能,位于system_server进程,ActivityManagerProxy对象是ActivityManagerService在普通应用进程的一个代理对象,应用进程通过ActivityManagerProxy对象调用ActivityManagerService提供的功能
- 应用进程并不会直接创建ActivityManagerProxy对象,而是通过调用ActiviyManagerNative类的工具方法getDefault方法得到ActivityManagerProxy对象。所以在应用进程里通常这样启动Activty:
ActivityManagerNative.getDefault().startActivity()
IApplicationThread相关类
image.png- 应用进程需要调用ActivityManagerService提供的功能,而ActivityManagerService也需要主动调用应用进程以控制应用进程并完成指定操作。这样ActivityManagerService也需要应用进程的一个Binder代理对象,而这个代理对象就是ApplicationThreadProxy对象。
- ActivityManagerService通过IApplicationThread接口管理应用进程,ApplicationThread类实现了IApplicationThread接口,实现了管理应用的操作,ApplicationThread对象运行在应用进程里。
- ApplicationThreadProxy对象是ApplicationThread对象在ActivityManagerService线程 (ActivityManagerService线程运行在system_server进程)内的代理对象,ActivityManagerService通过ApplicationThreadProxy对象调用ApplicationThread提供的功能,比如让应用进程启动某个Activity。
AMS
image.png-
mProcessNames:数据类型为ProcessMap,以进程名和userId为key来记录ProcessRecord;
- 添加进程,addProcessNameLocked()
- 删除进程,removeProcessNameLocked()
-
mPidsSelfLocked: 数据类型为SparseArray,以进程pid为key来记录ProcessRecord;
- startProcessLocked(),移除已存在进程,增加新创建进程pid信息;
- removeProcessLocked,processStartTimedOutLocked,cleanUpApplicationRecordLocked移除进程;
-
mLruProcesses:数据类型为ArrayList,以进程最近使用情况来排序记录ProcessRecord;
其中第一个元素代表的便是最近最少使用的进程; - updateLruProcessLocked()更新进程队列位置;
- mRemovedProcesses:数据类型为ArrayList,记录所有需要强制移除的进程;
- mProcessesToGc:数据类型为ArrayList,记录系统进入idle状态需执行gc操作的进程;
- mPendingPssProcesses:数据类型为ArrayList,记录将要收集内存使用数据PSS的进程;
- mProcessesOnHold:数据类型为ArrayList,记录刚开机过程,系统还没与偶准备就绪的情况下, 所有需要启动的进程都放入到该队列;
- mPersistentStartingProcesses:数据类型ArrayList,正在启动的persistent进程;
- mHomeProcess: 记录包含home Activity所在的进程;
- mPreviousProcess:记录用户上一次刚访问的进程;其中mPreviousProcessVisibleTime记录上一个进程的用户访问时间;
- mProcessList: 数据类型ProcessList,用于进程管理,Adj常量定义位于该文件;
其中最为常见的是mProcessNames,mPidsSelfLocked,mLruProcesses这3个对象
进程与组件的关系
系统AMS这边是由ProcessRecord对象记录进程,进程自身比较重要成员变量如下:
- processName:记录进程名,默认情况下进程名和该进程运行的第一个apk的包名是相同的,当然也可以自定义进程名;
- pid: 记录进程pid,该值在由进程创建时内核所分配的。
- thread:执行完attachApplicationLocked()方法,会把客户端进程ApplicationThread的binder服务的代理端传递到 AMS,并保持到ProcessRecord的成员变量thread;
- ProcessRecord.makeActive,赋值;
- ProcessRecord.makeInactive,清空;
- info:记录运行在该进程的第一个应用;
- pkgList: 记录运行在该进程中所有的包名,比如通过addPackage()添加;
- pkgDeps:记录该进程所依赖的包名,比如通过addPackageDependency()添加;
- lastActivityTime:每次updateLruProcessLocked()过程会更新该值;
- killedByAm:当值为true,意味着该进程是被AMS所杀,而非由于内存低而被LMK所杀;
- killed:当值为true,意味着该进程被杀,不论是AMS还是其他方式;
先将进程信息填写完成,然后继续填充组件信息,各个组件在system_server的核心信息记录如下:
- Service的信息记录在ActiveServices和AMS
- Broadcast信息记录在BroadcastQueue和AMS
- Activity信息记录在ActivityStack,ActivityStackSupervisor,以及AMS;
- Provider信息记录在ProviderMap和AMS;
APP端的组件信息
App端的组件信息,都保存在ActivityThread和LoadedApk这两个对象,主要保存信息:
- ActivityThread:记录provider, activity, service在客户端的相关信息;
- LoadedApk: 记录动态注册的广播接收器,以及bind方式启动service在客户端的相关信息;
理解Binder通信
理解mRemote方法的诞生
我们理解Binder通信,一般APP开发者一般都是看到ContextImpl对应就截止了
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, String callingPackage, int userId) throws RemoteException
{
//获取或创建Parcel对象
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
service.writeToParcel(data, 0);
//写入Parcel数据
data.writeString(resolvedType);
data.writeString(callingPackage);
data.writeInt(userId);
//通过Binder传递数据
mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);
//读取应答消息的异常情况
reply.readException();
//根据reply数据来创建ComponentName对象
ComponentName res = ComponentName.readFromParcel(reply);
data.recycle();
reply.recycle();
return res;
}
其中创建了两个Parcel 对象,一个用于读,一个用于写,通过mRemote进行通信,那么mRemote究竟是什么呢?
这个细节我们就讲讲mRemote究竟是何物。
首先我们找个切入点说起,显然此时ContextImpl已经不是我们的切入了,我们就从根源说起。我们知道AMP给AMS通信,AMP在什么时候创建呢?
ActivityManagerNative.java
static public IActivityManager getDefault() {
return gDefault.get();
}
private static final Singleton gDefault = new Singleton() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
public abstract class Singleton {
private T mInstance;
protected abstract T create();
public final T get() {
synchronized (this) {
if (mInstance == null) {
mInstance = create();
}
return mInstance;
}
}
}
所以gDefault.get()乍看返回的是下面代码:
IBinder b = ServiceManager.getService("activity");
IActivityManager am = asInterface(b);
return am;
我们暂时理解到ServiceManager.getService(“activity”)返回的是指向目标服务AMS的代理对象BinderProxy对象,由该代理对象可以找到目标服务AMS所在进程
然后看asInterface()方法:
public abstract class ActivityManagerNative extends Binder implements IActivityManager
{
static public IActivityManager asInterface(IBinder obj) {
if (obj == null) {
return null;
}
//此处obj = BinderProxy, descriptor = "android.app.IActivityManager";
IActivityManager in = (IActivityManager)obj.queryLocalInterface(descriptor);
if (in != null) { //此处为null
return in;
}
return new ActivityManagerProxy(obj);
}
...
}
上面调用的是BinderProxy.queryLocalInterface()
final class BinderProxy implements IBinder {
//BinderProxy对象的调用, 则返回值为空
public IInterface queryLocalInterface(String descriptor) {
return null;
}
}
所以
IBinder b = ServiceManager.getService("activity");
IActivityManager am = asInterface(b);
这两句意思是首先得到描述AMS的BinderProxy,然后返回空之后创建一个ActivityManagerProxy对象。最终得到AMP对象返回出去,并且此时AMP已经包装了AMS的BinderProxy了。
所以我们继续看下AMP的构造:
class ActivityManagerProxy implements IActivityManager
{
public ActivityManagerProxy(IBinder remote)
{
mRemote = remote;
}
}
我们要的结果出来了mRemote原来就是AMS的BinderProxy对象。所以我们后面研究mRemote就直接在BinderProxy中找代码。
现在我们要研究transact方法,看看当初在ComtextImp中调用startService()使用了什么:
mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);
mRemote中方法的理解
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, String callingPackage, int userId) throws RemoteException
{
//获取或创建Parcel对象
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
service.writeToParcel(data, 0);
//写入Parcel数据
data.writeString(resolvedType);
data.writeString(callingPackage);
data.writeInt(userId);
//通过Binder传递数据
mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);
//读取应答消息的异常情况
reply.readException();
//根据reply数据来创建ComponentName对象
ComponentName res = ComponentName.readFromParcel(reply);
data.recycle();
reply.recycle();
return res;
}
Binder.java ::BinderProxy
final class BinderProxy implements IBinder {
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
//用于检测Parcel大小是否大于800k
Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
return transactNative(code, data, reply, flags);
}
}
android_util_Binder.cpp::android_os_BinderProxy_transact
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags)
{
...
//将java Parcel转为c++ Parcel
Parcel* data = parcelForJavaObject(env, dataObj);
Parcel* reply = parcelForJavaObject(env, replyObj);
//gBinderProxyOffsets.mObject中保存的是new BpBinder(handle)对象
IBinder* target = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject);
...
//此处便是BpBinder::transact()
status_t err = target->transact(code, *data, reply, flags);
...
//最后根据transact执行具体情况,抛出相应的Exception
signalExceptionForError(env, obj, err, true , data->dataSize());
return JNI_FALSE;
}
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
if (mAlive) {
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
IPCThreadState::self()采用单例模式,保证每个线程只有一个实例对象
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
status_t err = data.errorCheck(); //数据错误检查
flags |= TF_ACCEPT_FDS;
....
if (err == NO_ERROR) {
// 传输数据
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
}
if (err != NO_ERROR) {
if (reply) reply->setError(err);
return (mLastError = err);
}
// 默认情况下,都是采用非oneway的方式, 也就是需要等待服务端的返回结果
if ((flags & TF_ONE_WAY) == 0) {
if (reply) {
//reply对象不为空
err = waitForResponse(reply);
}else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
} else {
err = waitForResponse(NULL, NULL);
}
return err;
}
这个过程涉及到通过writeTransactionData()方法传递数据,同时我们注意到分两种方式,一种oneway一种非oneway。还有对于err如果生成返回的。并且在一开头就有代码 flags |= TF_ACCEPT_FDS;是干啥的。
- 此时我们就理解 flags |= TF_ACCEPT_FDS是处理后的flags吧。
对于writeTransactionData方法传递数据我们得看源码
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;
tr.target.ptr = 0;
tr.target.handle = handle; // handle指向AMS
tr.code = code; // START_SERVICE_TRANSACTION
tr.flags = binderFlags; // 0
tr.cookie = 0;
tr.sender_pid = 0;
tr.sender_euid = 0;
const status_t err = data.errorCheck();
if (err == NO_ERROR) {
// data为startService相关信息
tr.data_size = data.ipcDataSize(); // mDataSize
tr.data.ptr.buffer = data.ipcData(); // mData指针
tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t); //mObjectsSize
tr.data.ptr.offsets = data.ipcObjects(); //mObjects指针
}
...
mOut.writeInt32(cmd); //cmd = BC_TRANSACTION
mOut.write(&tr, sizeof(tr)); //写入binder_transaction_data数据
return NO_ERROR;
}
也就是说,将我们的data数据还有传递的cmd,flags等数据封装到binder_transaction_data中,然后将此结构体通过mOut写入。
此时我们还不知道mOut是什么?
没关系,我们先预留问题在这里稍后会回答。
那我们继续看那些err怎么传递来的吧
IPC.waitForResponse
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
int32_t cmd;
int32_t err;
while (1) {
if ((err=talkWithDriver()) < NO_ERROR) break;
err = mIn.errorCheck();
if (err < NO_ERROR) break; //当存在error则退出循环
//每当跟Driver交互一次,若mIn收到数据则往下执行一次BR命令
if (mIn.dataAvail() == 0) continue;
cmd = mIn.readInt32();
switch (cmd) {
case BR_TRANSACTION_COMPLETE:
//只有当不需要reply, 也就是oneway时 才会跳出循环,否则还需要等待.
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_REPLY: ... goto finish;
default:
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
break;
}
}
finish:
if (err != NO_ERROR) {
if (reply) reply->setError(err); //将发送的错误代码返回给最初的调用者
}
return err;
}
我们比较细致的说下这个方法,首先一直循环,卡在talkWithDriver这里,如果talkWithDriver返回一个err则立马退出循环,如果talkWithDriver没有返回一个err继续执行,也就是此时不存在错误。然后从mIn回写的值里面获取数据,如果首先拿出来的是err则返回,如果不是看dataAvail()这个值如果是0就继续与内核交互调用talkWithDriver(),如果不是0,那么就读一个cmd,然后区分cmd,区分也分情况,比较重要的是executeCommand处理命令,当然如果不需要reply也就是oneway的时候,会走breank。因为oneway是异步的不需要结果,没有错误,不需要结果,那还循环个毛线线。
里面包含几个命令是直接结束Binder通信的:
- 非oneway也就是同步并且命令是BR_TRANSACTION_COMPLETE(交互完毕)!reply && !acquireResult时候,意思就是binder认为这次任务完成了,结果也给reply了,也不需要请求了,那还继续给毛线线。
- BR_DEAD_REPLY
- BR_FAILED_REPLY
- BR_REPLY:Binder驱动向Client端发送回应消息; 对于非oneway transaction时,当收到该消息,则完整地完成本次Binder通信;
都标志着结束。
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR;
switch ((uint32_t)cmd) {
case BR_ERROR: ...
case BR_OK: ...
case BR_ACQUIRE: ...
case BR_RELEASE: ...
case BR_INCREFS: ...
case BR_TRANSACTION: ... //Binder驱动向Server端发送消息
case BR_DEAD_BINDER: ...
case BR_CLEAR_DEATH_NOTIFICATION_DONE: ...
case BR_NOOP: ...
case BR_SPAWN_LOOPER: ... //创建新binder线程
default: ...
}
}
那继续看看这些命令如何返回到这里的:
//mOut有数据,mIn还没有数据。doReceive默认值为true
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
binder_write_read
// 游标位置大于等于数据大小,说明读入的数据都已经被消化了
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data();
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;
}
// 当同时没有输入和输出数据则直接返回
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
//ioctl执行binder读写操作,经过syscall,进入Binder驱动。调用Binder_ioctl【小节3.1】
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
...
} while (err == -EINTR);
if (err >= NO_ERROR) {
if (bwr.write_consumed > 0) {
if (bwr.write_consumed < mOut.dataSize())
mOut.remove(0, bwr.write_consumed);
else
mOut.setDataSize(0);
}
if (bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);
}
return NO_ERROR;
}
return err;
}
我们看到是用ioctl与内核进行通信,由于linux系统是完全的驱动注册系统,所以Binder作为一个驱动也不例外,只不过特殊的一点是这个驱动不需要和硬件驱动硬件,操作的是字符设备。
到目前为止我们至少从流程上已经清楚,从app到除了内核之外的通信过程,是不是感觉还是不明白,因为我们没有接触内核,接触内核怎么写就很清楚,原来Binder如此巧妙高效可爱。。。我编不下去了。。。
Binder内核通信
我们到了内核通信,就不用再和framework那样细致了,我们只是简单说流程,让我们明白那些点从而理解通信本质。
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;
//当binder_stop_on_user_error>=2时,则该线程加入等待队列并进入休眠状态. 该值默认为0
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
...
binder_lock(__func__);
//查找或创建binder_thread结构体
thread = binder_get_thread(proc);
...
switch (cmd) {
case BINDER_WRITE_READ:
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
break;
...
}
ret = 0;
err:
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
binder_unlock(__func__);
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
return ret;
}
从文件指针中获取binder_proc,然后通过binder_get_thread获取thread方法。
我们继续看吧
static int binder_ioctl_write_read(struct file *filp,
unsigned int cmd, unsigned long arg,
struct binder_thread *thread)
{
int ret = 0;
struct binder_proc *proc = filp->private_data;
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
struct binder_write_read bwr;
if (size != sizeof(struct binder_write_read)) {
ret = -EINVAL;
goto out;
}
//将用户空间bwr结构体拷贝到内核空间
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
if (bwr.write_size > 0) {
//将数据放入目标进程
ret = binder_thread_write(proc, thread,
bwr.write_buffer,
bwr.write_size,
&bwr.write_consumed);
//当执行失败,则直接将内核bwr结构体写回用户空间,并跳出该方法
if (ret < 0) {
bwr.read_consumed = 0;
if (copy_to_user_preempt_disabled(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto out;
}
}
if (bwr.read_size > 0) {
//读取自己队列的数据
ret = binder_thread_read(proc, thread, bwr.read_buffer,
bwr.read_size,
&bwr.read_consumed,
filp->f_flags & O_NONBLOCK);
//当进程的todo队列有数据,则唤醒在该队列等待的进程
if (!list_empty(&proc->todo))
wake_up_interruptible(&proc->wait);
//当执行失败,则直接将内核bwr结构体写回用户空间,并跳出该方法
if (ret < 0) {
if (copy_to_user_preempt_disabled(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto out;
}
}
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
out:
return ret;
}
我们首先需要将用户空间的bwr拷贝到内核空间才可以用。
我们这里也有一个问题binder_thread_write是将数据写入目标进程,那么怎么写到目标进程里面去了,目前我们一直在当前进程运行,只是把数据通过了AMP->AMS也就是system_server进程。哪里来的目标进程
,所以这里我们并不懂,需要追寻源码
然后我们在说说,读取自己数据使用的是binder_thread_read,这里是利用bwr.write_size与bwr.read_size来进行区分读写的。
static int binder_thread_write(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed)
{
uint32_t cmd;
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
while (ptr < end && thread->return_error == BR_OK) {
//拷贝用户空间的cmd命令,此时为BC_TRANSACTION
if (get_user(cmd, (uint32_t __user *)ptr)) -EFAULT;
ptr += sizeof(uint32_t);
switch (cmd) {
case BC_TRANSACTION:
case BC_REPLY: {
struct binder_transaction_data tr;
//拷贝用户空间的binder_transaction_data
if (copy_from_user(&tr, ptr, sizeof(tr))) return -EFAULT;
ptr += sizeof(tr);
binder_transaction(proc, thread, &tr, cmd == BC_REPLY);
break;
}
...
}
*consumed = ptr - buffer;
}
return 0;
}
拷贝用户空间的cmd,然后调用binder_transaction
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply){
struct binder_transaction *t;
struct binder_work *tcomplete;
binder_size_t *offp, *off_end;
binder_size_t off_min;
struct binder_proc *target_proc;
struct binder_thread *target_thread = NULL;
struct binder_node *target_node = NULL;
struct list_head *target_list;
wait_queue_head_t *target_wait;
struct binder_transaction *in_reply_to = NULL;
if (reply) {
...
}else {
if (tr->target.handle) {
struct binder_ref *ref;
// 由handle 找到相应 binder_ref, 由binder_ref 找到相应 binder_node
ref = binder_get_ref(proc, tr->target.handle);
target_node = ref->node;
} else {
target_node = binder_context_mgr_node;
}
// 由binder_node 找到相应 binder_proc
target_proc = target_node->proc;
}
if (target_thread) {
e->to_thread = target_thread->pid;
target_list = &target_thread->todo;
target_wait = &target_thread->wait;
} else {
//首次执行target_thread为空
target_list = &target_proc->todo;
target_wait = &target_proc->wait;
}
t = kzalloc(sizeof(*t), GFP_KERNEL);
tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
//非oneway的通信方式,把当前thread保存到transaction的from字段
if (!reply && !(tr->flags & TF_ONE_WAY))
t->from = thread;
else
t->from = NULL;
t->sender_euid = task_euid(proc->tsk);
t->to_proc = target_proc; //此次通信目标进程为system_server
t->to_thread = target_thread;
t->code = tr->code; //此次通信code = START_SERVICE_TRANSACTION
t->flags = tr->flags; // 此次通信flags = 0
t->priority = task_nice(current);
//从目标进程target_proc中分配内存空间=
t->buffer = binder_alloc_buf(target_proc, tr->data_size,
tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));
t->buffer->allow_user_free = 0;
t->buffer->transaction = t;
t->buffer->target_node = target_node;
if (target_node)
binder_inc_node(target_node, 1, 0, NULL); //引用计数加1
//binder对象的偏移量
offp = (binder_size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));
//分别拷贝用户空间的binder_transaction_data中ptr.buffer和ptr.offsets到目标进程的binder_buffer
copy_from_user(t->buffer->data,
(const void __user *)(uintptr_t)tr->data.ptr.buffer, tr->data_size);
copy_from_user(offp,
(const void __user *)(uintptr_t)tr->data.ptr.offsets, tr->offsets_size);
off_end = (void *)offp + tr->offsets_size;
for (; offp < off_end; offp++) {
struct flat_binder_object *fp;
fp = (struct flat_binder_object *)(t->buffer->data + *offp);
off_min = *offp + sizeof(struct flat_binder_object);
switch (fp->type) {
...
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE: {
//处理引用计数情况
struct binder_ref *ref = binder_get_ref(proc, fp->handle);
if (ref->node->proc == target_proc) {
if (fp->type == BINDER_TYPE_HANDLE)
fp->type = BINDER_TYPE_BINDER;
else
fp->type = BINDER_TYPE_WEAK_BINDER;
fp->binder = ref->node->ptr;
fp->cookie = ref->node->cookie;
binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL);
} else {
struct binder_ref *new_ref;
new_ref = binder_get_ref_for_node(target_proc, ref->node);
fp->handle = new_ref->desc;
binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);
}
} break;
...
default:
return_error = BR_FAILED_REPLY;
goto err_bad_object_type;
}
}
if (reply) {
//BC_REPLY的过程
binder_pop_transaction(target_thread, in_reply_to);
} else if (!(t->flags & TF_ONE_WAY)) {
//BC_TRANSACTION 且 非oneway,则设置事务栈信息
t->need_reply = 1;
t->from_parent = thread->transaction_stack;
thread->transaction_stack = t;
} else {
//BC_TRANSACTION 且 oneway,则加入异步todo队列
if (target_node->has_async_transaction) {
target_list = &target_node->async_todo;
target_wait = NULL;
} else
target_node->has_async_transaction = 1;
}
//将BINDER_WORK_TRANSACTION添加到目标队列,即target_proc->todo
t->work.type = BINDER_WORK_TRANSACTION;
list_add_tail(&t->work.entry, target_list);
//将BINDER_WORK_TRANSACTION_COMPLETE添加到当前线程队列,即thread->todo
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
list_add_tail(&tcomplete->entry, &thread->todo);
//唤醒等待队列,本次通信的目标队列为target_proc->wait
if (target_wait)
wake_up_interruptible(target_wait);
return;
}
tr->target.handle,这个是目标handle,通过这个可以在Binder引用红黑树里面找到对应的binder引用节点。由binder_node找到对应目标节点的进程,对应进程找到目标节点的todo队列,和wait队列。
如果是非oneway也就是同步的时候要将当前线程保存到t->from:struct binder_transaction *t;
我们这个时候要明白目标进程是谁,是syatem_server。
我们将目标进程结构体,目标线程结构体,还有通信的code优先级等信息封装到binder_transaction *t中。然后将我们需要传递的数据拷贝到目标进程中去,剩下的事情就是交给todo队列了。就是按照onyway和非oneway区分,看加入到异步队列还是同步任务栈中,最后将任务类型进行修改需要执行,并且添加到目标进程的目标线程的todo队列中去。然后进行唤醒。
我们小结这段:
- 查询目标进程的过程: handle -> binder_ref -> binder_node -> binder_proc
- 将BINDER_WORK_TRANSACTION添加到目标队列target_list:
- call事务, 则目标队列target_list=target_proc->todo;
- reply事务,则目标队列target_list=target_thread->todo;
- async事务,则目标队列target_list=target_node->async_todo.
- 数据拷贝
- 将用户空间binder_transaction_data中ptr.buffer和ptr.offsets拷贝到目标进程的binder_buffer->data;
- 这就是只拷贝一次的真理所在;
- 设置事务栈信息
- BC_TRANSACTION且非oneway, 则将当前事务添加到thread->transaction_stack;
- 事务分发过程:
- 将BINDER_WORK_TRANSACTION添加到目标队列(此时为target_proc->todo队列);
- 将BINDER_WORK_TRANSACTION_COMPLETE添加到当前线程thread->todo队列;
- 唤醒目标进程target_proc开始执行事务。
该方法中proc/thread是指当前发起方的进程信息,而binder_proc是指目标接收端进程。 此时当前线程thread的todo队列已经有事务, 接下来便会进入binder_thread_read来处理相关的事务.
这里已经把给target进程写数据说差不多了,我们回过头再看
IPCThreadState::talkWithDriver()
这个方法巧妙的利用一个结构体binder_write_read 与一个方法ioctl就实现了可以读可以写,是不是比较难理解,因为我们以往的认识都是比如socket有读端也有写端,比如管道也是。而Binder是通过一个结构体内部write_size 与read_size 来区分到底是读数据还是写数据。在内核中也就是binder_ioctl-->binder_ioctl_write_read中如果bwr.write_size > 0则执行binder_thread_write,如果bwr.read_size > 0则执行binder_thread_read,这样的话在一个循环内,就可以把数据写完和读完从而达到进程交互的目的。
binder内核读数据
binder_thread_read(){
//当已使用字节数为0时,将BR_NOOP响应码放入指针ptr
if (*consumed == 0) {
if (put_user(BR_NOOP, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
}
retry:
//binder_transaction()已设置transaction_stack不为空,则wait_for_proc_work为false.
wait_for_proc_work = thread->transaction_stack == NULL &&
list_empty(&thread->todo);
thread->looper |= BINDER_LOOPER_STATE_WAITING;
if (wait_for_proc_work)
proc->ready_threads++; //进程中空闲binder线程加1
//只有当前线程todo队列为空,并且transaction_stack也为空,才会开始处于当前进程的事务
if (wait_for_proc_work) {
if (non_block) {
...
} else
//当进程todo队列没有数据,则进入休眠等待状态
ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
} else {
if (non_block) {
...
} else
//当线程todo队列有数据则执行往下执行;当线程todo队列没有数据,则进入休眠等待状态
ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));
}
if (wait_for_proc_work)
proc->ready_threads--; //退出等待状态, 则进程中空闲binder线程减1
thread->looper &= ~BINDER_LOOPER_STATE_WAITING;
...
while (1) {
uint32_t cmd;
struct binder_transaction_data tr;
struct binder_work *w;
struct binder_transaction *t = NULL;
//先从线程todo队列获取事务数据
if (!list_empty(&thread->todo)) {
w = list_first_entry(&thread->todo, struct binder_work, entry);
// 线程todo队列没有数据, 则从进程todo对获取事务数据
} else if (!list_empty(&proc->todo) && wait_for_proc_work) {
w = list_first_entry(&proc->todo, struct binder_work, entry);
} else {
//没有数据,则返回retry
if (ptr - buffer == 4 &&
!(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))
goto retry;
break;
}
switch (w->type) {
case BINDER_WORK_TRANSACTION:
//获取transaction数据
t = container_of(w, struct binder_transaction, work);
break;
case BINDER_WORK_TRANSACTION_COMPLETE:
cmd = BR_TRANSACTION_COMPLETE;
//将BR_TRANSACTION_COMPLETE写入*ptr,并跳出循环。
put_user(cmd, (uint32_t __user *)ptr);
list_del(&w->entry);
kfree(w);
break;
case BINDER_WORK_NODE: ... break;
case BINDER_WORK_DEAD_BINDER:
case BINDER_WORK_DEAD_BINDER_AND_CLEAR:
case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: ... break;
}
//只有BINDER_WORK_TRANSACTION命令才能继续往下执行
if (!t)
continue;
if (t->buffer->target_node) {
//获取目标node
struct binder_node *target_node = t->buffer->target_node;
tr.target.ptr = target_node->ptr;
tr.cookie = target_node->cookie;
t->saved_priority = task_nice(current);
...
cmd = BR_TRANSACTION; //设置命令为BR_TRANSACTION
} else {
tr.target.ptr = NULL;
tr.cookie = NULL;
cmd = BR_REPLY; //设置命令为BR_REPLY
}
tr.code = t->code;
tr.flags = t->flags;
tr.sender_euid = t->sender_euid;
if (t->from) {
struct task_struct *sender = t->from->proc->tsk;
//当非oneway的情况下,将调用者进程的pid保存到sender_pid
tr.sender_pid = task_tgid_nr_ns(sender,
current->nsproxy->pid_ns);
} else {
//当oneway的的情况下,则该值为0
tr.sender_pid = 0;
}
tr.data_size = t->buffer->data_size;
tr.offsets_size = t->buffer->offsets_size;
tr.data.ptr.buffer = (void *)t->buffer->data + proc->user_buffer_offset;
tr.data.ptr.offsets = tr.data.ptr.buffer +
ALIGN(t->buffer->data_size, sizeof(void *));
//将cmd和数据写回用户空间
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
if (copy_to_user(ptr, &tr, sizeof(tr)))
return -EFAULT;
ptr += sizeof(tr);
list_del(&t->work.entry);
t->buffer->allow_user_free = 1;
if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {
t->to_parent = thread->transaction_stack;
t->to_thread = thread;
thread->transaction_stack = t;
} else {
t->buffer->transaction = NULL;
kfree(t); //通信完成,则运行释放
}
break;
}
done:
*consumed = ptr - buffer;
//当满足请求线程加已准备线程数等于0,已启动线程数小于最大线程数(15),
//且looper状态为已注册或已进入时创建新的线程。
if (proc->requested_threads + proc->ready_threads == 0 &&
proc->requested_threads_started < proc->max_threads &&
(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
BINDER_LOOPER_STATE_ENTERED))) {
proc->requested_threads++;
// 生成BR_SPAWN_LOOPER命令,用于创建新的线程
put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer);
}
return 0;
}
首先当transaction_stack不空且todo队列空闲才执行任务,当进程todo队列没有数据,则会进入休眠状态(wait_event_freezable_exclusive),然后进入循环如果todo有数据则获取事务(binder_work)没有数据则继续到之前的那个步骤再次等待被唤醒。既然现在有数据,则通过type看具体需要对数据做什么操作。如果是BINDER_WORK_TRANSACTION_COMPLETE说明是正常结束,则将数据写到*ptr也就是用户空间,只有命令是BINDER_WORK_TRANSACTION才继续执行,首先找到目标node,将数据都设置tr中,完了cmd变成BR_REPLY,当命令是BR_XX的时候是驱动主动和用户态进行交互。然后用t->from区分是oneway还是非oneway。因为之前在写的时候如果是非oneway也就是同步的时候要将当前线程保存到t->from:struct binder_transaction *t;现在如果是oneway则tr.sender_pid=0,非oneway要讲调用者的进程id保存到sender_pid中。然后还是继续设置tr那些数据,完了将cmd和数据写到用户空间。
到现在我们推测出每个进程都有一个todo队列,这个todo队列一直在循环,如果有数据则当前进程要把数据放入对方进程的todo队列中,同理。
当数据返回到用户空间之后,就会执行IPC.executeCommand然后针对那些BR命令去做事情,比如执行BR_TRANSACTION的时候那就说明有数据到达用户空间,用户空间要对这些数据进行处理或者保存之类的操作,当处理完成之后就需要告诉驱动我处理完了所以就通过IPC.sendReply发送给驱动BC_REPLY,当驱动在binder_transaction收到是BC_REPLY消息的时候就会告诉目标进程我这边完成数据接收了。所以驱动就会给对方的目标todo中添加消息。 TIM截图20171113200142.png来我们再根据这个图回顾一下:
首先APP进程给驱动发送BC_TRANSACTION
static int binder_thread_write(){
while (ptr < end && thread->return_error == BR_OK) {
//拷贝用户空间的cmd命令,此时为BC_TRANSACTION
if (get_user(cmd, (uint32_t __user *)ptr)) -EFAULT;
ptr += sizeof(uint32_t);
switch (cmd) {
case BC_TRANSACTION:
case BC_REPLY: {
struct binder_transaction_data tr;
//拷贝用户空间的binder_transaction_data
if (copy_from_user(&tr, ptr, sizeof(tr))) return -EFAULT;
ptr += sizeof(tr);
binder_transaction(proc, thread, &tr, cmd == BC_REPLY);
break;
}
...
}
}
此方法处理BC_TRANSACTION,BR_REPLAY是一样的。
然后在binder_transaction()方法中做处理
static void binder_transaction(){}
做的事情是:
- 查询目标进程的过程: handle -> binder_ref -> binder_node -> binder_proc
- 将BINDER_WORK_TRANSACTION添加到目标队列target_list:
- call事务, 则目标队列target_list=target_proc->todo;
- reply事务,则目标队列target_list=target_thread->todo;
- async事务,则目标队列target_list=target_node->async_todo.
- 数据拷贝
- 将用户空间binder_transaction_data中ptr.buffer和ptr.offsets拷贝到目标进程的binder_buffer->data;这就是只拷贝一次的真理所在;
- 设置事务栈信息
- BC_TRANSACTION且非oneway, 则将当前事务添加到thread->transaction_stack;
- 事务分发过程:
- 将BINDER_WORK_TRANSACTION添加到目标队列(此时为target_proc->todo队列);
- 将BINDER_WORK_TRANSACTION_COMPLETE添加到当前线程thread->todo队列;
- 唤醒目标进程target_proc开始执行事务。
接着就是binder_thread_read读数据。
注意这里将BINDER_WORK_TRANSACTION_COMPLETE添加到当前线程thread->todo队列;
image.png
因为:
static int binder_ioctl_write_read()
{
if (bwr.write_size > 0) {
//将数据放入目标进程
ret = binder_thread_write(...);
}
if (bwr.read_size > 0) {
//读取自己队列的数据
ret = binder_thread_read(...);
...
}
}
}
在binder_thread_read中:
binder_thread_read(){
switch (w->type) {
...
case BINDER_WORK_TRANSACTION_COMPLETE:
cmd = BR_TRANSACTION_COMPLETE;
//将BR_TRANSACTION_COMPLETE写入*ptr,并跳出循环。
put_user(cmd, (uint32_t __user *)ptr);
list_del(&w->entry);
kfree(w);
break;
...
}
f (t->buffer->target_node) {
//获取目标node
struct binder_node *target_node = t->buffer->target_node;
tr.target.ptr = target_node->ptr;
tr.cookie = target_node->cookie;
t->saved_priority = task_nice(current);
...
cmd = BR_TRANSACTION; //设置命令为BR_TRANSACTION
}
//将cmd和数据写回用户空间
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
if (copy_to_user(ptr, &tr, sizeof(tr)))
return -EFAULT;
ptr += sizeof(tr);
...
}
看到木有,在写的过程中刚添加完这里就用到了,将命令设置成cmd,先放入到用户空间。
然后将目标进程节点找出来,将命令设置成BR_TRANSACTION,再后来就将命令回写到用户空间
这个时候就在用户空间中:
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
int32_t cmd;
int32_t err;
while (1) {
if ((err=talkWithDriver()) < NO_ERROR) break;
err = mIn.errorCheck();
if (err < NO_ERROR) break; //当存在error则退出循环
//每当跟Driver交互一次,若mIn收到数据则往下执行一次BR命令
if (mIn.dataAvail() == 0) continue;
cmd = mIn.readInt32();
switch (cmd) {
case BR_TRANSACTION_COMPLETE:
//只有当不需要reply, 也就是oneway时 才会跳出循环,否则还需要等待.
if (!reply && !acquireResult) goto finish; break;
...
default:
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
break;
}
}
}
所以这个时候APP这边就进入休眠了。
那么这个时候在AMS进程这边:
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR;
switch ((uint32_t)cmd) {
case BR_ERROR: ...
case BR_OK: ...
case BR_ACQUIRE: ...
case BR_RELEASE: ...
case BR_INCREFS: ...
case BR_TRANSACTION: ... //Binder驱动向Server端发送消息
if ((tr.flags & TF_ONE_WAY) == 0) {
if (error < NO_ERROR) reply.setError(error);
//对于非oneway, 需要reply通信过程,则向Binder驱动发送BC_REPLY命令
sendReply(reply, 0);
}
case BR_DEAD_BINDER: ...
case BR_CLEAR_DEATH_NOTIFICATION_DONE: ...
case BR_NOOP: ...
case BR_SPAWN_LOOPER: ... //创建新binder线程
default: ...
}
}
我们看到了BR_TRANSACTION,调用的是sendReply:
status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags)
{
status_t err;
status_t statusBuffer;
err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer);
if (err < NO_ERROR) return err;
return waitForResponse(NULL, NULL);
}
上面这行了writeTransactionData和waitForResponse两个方法
writeTransactionData这个方法中执行时候我们看参数是BC_REPLY,这个方法继续将cmd给驱动,我们继续看看驱动收到BC_REPLY时候做什么:
static int binder_thread_write(){
while (ptr < end && thread->return_error == BR_OK) {
//拷贝用户空间的cmd命令,此时为BC_TRANSACTION
if (get_user(cmd, (uint32_t __user *)ptr)) -EFAULT;
ptr += sizeof(uint32_t);
switch (cmd) {
case BC_TRANSACTION:
case BC_REPLY: {
struct binder_transaction_data tr;
//拷贝用户空间的binder_transaction_data
if (copy_from_user(&tr, ptr, sizeof(tr))) return -EFAULT;
ptr += sizeof(tr);
binder_transaction(proc, thread, &tr, cmd == BC_REPLY);
break;
}
...
}
}
其实和BC_TRANSACTION处理一样,
static void binder_transaction(){
//将BINDER_WORK_TRANSACTION添加到目标队列,本次通信的目标队列为target_thread->todo
t->work.type = BINDER_WORK_TRANSACTION;
list_add_tail(&t->work.entry, target_list);
//将BINDER_WORK_TRANSACTION_COMPLETE添加到当前线程的todo队列
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
list_add_tail(&tcomplete->entry, &thread->todo);
}
做的事情是:
- 查询目标进程的过程: handle -> binder_ref -> binder_node -> binder_proc
- 将BINDER_WORK_TRANSACTION添加到目标队列target_list:
- call事务, 则目标队列target_list=target_proc->todo;
- reply事务,则目标队列target_list=target_thread->todo;
- async事务,则目标队列target_list=target_node->async_todo.
- 数据拷贝
- 将用户空间binder_transaction_data中ptr.buffer和ptr.offsets拷贝到目标进程的binder_buffer->data;这就是只拷贝一次的真理所在;
- 设置事务栈信息
- BC_TRANSACTION且非oneway, 则将当前事务添加到thread->transaction_stack;
- 事务分发过程:
- 将BINDER_WORK_TRANSACTION添加到目标队列(此时为target_proc->todo队列);
- 将BINDER_WORK_TRANSACTION_COMPLETE添加到当前线程thread->todo队列;
- 唤醒目标进程target_proc开始执行事务。
image.png注意这里将BINDER_WORK_TRANSACTION_COMPLETE添加到当前线程thread->todo队列;
因为:
static int binder_ioctl_write_read()
{
if (bwr.write_size > 0) {
//将数据放入目标进程
ret = binder_thread_write(...);
}
if (bwr.read_size > 0) {
//读取自己队列的数据
ret = binder_thread_read(...);
...
}
}
}
在binder_thread_read中:
binder_thread_read(){
switch (w->type) {
...
case BINDER_WORK_TRANSACTION_COMPLETE:
cmd = BR_TRANSACTION_COMPLETE;
//将BR_TRANSACTION_COMPLETE写入*ptr,并跳出循环。
put_user(cmd, (uint32_t __user *)ptr);
list_del(&w->entry);
kfree(w);
break;
...
}
f (t->buffer->target_node) {
//获取目标node
struct binder_node *target_node = t->buffer->target_node;
tr.target.ptr = target_node->ptr;
tr.cookie = target_node->cookie;
t->saved_priority = task_nice(current);
...
cmd = BR_TRANSACTION; //设置命令为BR_TRANSACTION
}
//将cmd和数据写回用户空间
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
if (copy_to_user(ptr, &tr, sizeof(tr)))
return -EFAULT;
ptr += sizeof(tr);
...
}
看到木有,在写的过程中刚添加完这里就用到了,将命令设置成cmd,先放入到用户空间。
然后将目标进程节点找出来,将命令设置成BR_TRANSACTION,再后来就将命令回写到用户空间
这个时候就在用户空间中:
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
int32_t cmd;
int32_t err;
while (1) {
if ((err=talkWithDriver()) < NO_ERROR) break;
err = mIn.errorCheck();
if (err < NO_ERROR) break; //当存在error则退出循环
//每当跟Driver交互一次,若mIn收到数据则往下执行一次BR命令
if (mIn.dataAvail() == 0) continue;
cmd = mIn.readInt32();
switch (cmd) {
case BR_TRANSACTION_COMPLETE:
//只有当不需要reply, 也就是oneway时 才会跳出循环,否则还需要等待.
if (!reply && !acquireResult) goto finish; break;
...
default:
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
break;
}
}
}
所以这个时候AMS这边就进入休眠了。
小结使用接口
BC协议 | 调用方法 |
---|---|
BC_TRANSACTION | IPC.transact() |
BC_REPLY | IPC.sendReply() |
BC_FREE_BUFFER | IPC.freeBuffer() |
BC_REQUEST_DEATH_NOTIFICATION | IPC.requestDeathNotification() |
BC_CLEAR_DEATH_NOTIFICATION | IPC.clearDeathNotification() |
BC_DEAD_BINDER_DONE | IPC.execute() |
[图片上传中...(image.png-66ada5-1510577352862-0)]
网友评论