parent
							
								
									036a7633e5
								
							
						
					
					
						commit
						884b45508e
					
				| @ -0,0 +1,189 @@ | ||||
| --- | ||||
| 一次完整的 IPC 通信流程 | ||||
| --- | ||||
| 
 | ||||
| 1. 了解 binder 的整体架构原理 | ||||
| 2. 了解应用和 binder 驱动的交互方式 | ||||
| 3. 了解 IPC 过程中的通信协议 | ||||
| 
 | ||||
| ```c++ | ||||
| private static class Proxy implements inuker.com.library.IRemoteCaller{ | ||||
|     private android.os.IBinder mRemote; | ||||
|     public void call(int code) throws RemoteException{ | ||||
|         mRemote.transact(Stub.TRANSACTION_call, _data, _reply, 0); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| final class BinderProxy implements IBinder{ | ||||
|     public boolean transact(int code, Parcel data, Parcel reply, int flags){ | ||||
|         return transactNative(code, data, reply, flags); | ||||
|     } | ||||
| } | ||||
| jboolean android_os_BinderProxy_transact(INIEnv* env, jobject obj, jint code, jobject dataObj, jobject replyObj, jint flags){ | ||||
|     Parcel* data = parcelForJavaObject(env, dataObj); | ||||
|     Parcel* reply = parcelForJavaObject(env, replyObj); | ||||
|     IBinder* target = (IBinder)env->GetLongField(obj, gBinderProxyOffsets.mObject); | ||||
|     status_t err = target->transact(code, *data, reply, flags); | ||||
| } | ||||
| 
 | ||||
| status_t BpBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){ | ||||
|     status_t status = IPCThreadState::self()->transact(mHandle, code, data, reply, flags); | ||||
|     return status; | ||||
| } | ||||
| status_t IPCThreadState::transact(int32_t handle, ...){ | ||||
|     writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL); | ||||
|     if((flags&TF_ONE_WAY)==0){ | ||||
|         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, ...){ | ||||
|     binder_transaction_data tr; | ||||
|     tr.target.ptr = 0; | ||||
|     tr.target.handle = handle; | ||||
|     tr.code = code; | ||||
|     tr.flags = binderFlags; | ||||
|     tr.data.size = data.ipcDataSize(); | ||||
|     tr.data.ptr.buffer = data.ipcData(); | ||||
|     tr.data.ptr.offsets = data.ipcObjects(); | ||||
|      | ||||
|     mOut.writeInt32(cmd); | ||||
|     mOut.write(&tr, sizeof(tr)); | ||||
|     return NO_ERROR; | ||||
| } | ||||
| status_t IPCThreadState::waitForResponse(Parcel *reply, ...){ | ||||
|     while(1){ | ||||
|         talkWithDiver(); | ||||
|         cmd = (uint32_t)mln.readInt32(); | ||||
|         switch(cmd){ | ||||
|             case BR_TRANSACTION_COMPLETE: | ||||
|                 break; | ||||
|             case BR_REPLY:{ | ||||
|                 binder_transaction_data tr; | ||||
|                 mIn.read(&tr, sizeof(tr)); | ||||
|                 reply->ipcSetDataReference(tr.data.ptr.buffer, tr.data_size, ...); | ||||
|             }    | ||||
|             goto finish; | ||||
|         } | ||||
|     } | ||||
|     return err; | ||||
| } | ||||
| status_t IPCThreadState::talkWithDriver(bool doReceiver){ | ||||
|     binder_write_read bwr; | ||||
|     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){ | ||||
|         bwr.read_size = mIn.dataCapacity(); | ||||
|         bwr.read_buffer = (uintptr_t)mIn.data(); | ||||
|     }else{ | ||||
|         bwr.read_size = 0; | ||||
|         bwr.read_buffer = 0; | ||||
|     } | ||||
|     ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr); | ||||
|     return err; | ||||
| } | ||||
| static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){ | ||||
|     switch(cmd){ | ||||
|         case BINDER_WRITE_READ:{ | ||||
|             struct binder_write_read bwr; | ||||
|             if(bwr.write_size>0){ | ||||
|                 ret = binder_thread_write(proc, thread, bwr.write_buffer, ...); | ||||
|             } | ||||
|             if(bwr.read.size>0){ | ||||
|                 ret = binder_thread_read(proc, thread, bwr.read_buffer, bwr.read_size, ...); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| Service 端如何和 binder 交互的? | ||||
| 
 | ||||
| ```c++ | ||||
| virtual bool threadLoop(){ | ||||
| 	IPCThreadState::self()->joinThreadPool(mIsMain); | ||||
|     return false; | ||||
| } | ||||
| void IPCThreadState::joinThreadPool(bool isMain){ | ||||
|     mOut.writeInt32(isMain ? BC_ENTER_LOOPER:BC_REGISTER_LOOPER); | ||||
|     status_t result; | ||||
|     do{ | ||||
|         result = getAndExecuteCommand(); | ||||
|     }while(result != -ECONNREFUSED && result != -EBADF); | ||||
|     mOut.writeInt32(BC_EXIT_LOOPER); | ||||
|     talkWithDriver(false); | ||||
| } | ||||
| status_t IPCThreadState::getAndExecuteCommand(){ | ||||
|     // 1. 从驱动读取请求 | ||||
|     talkWithDriver(); | ||||
|     int32_t cmd = mIn.readInt32(); | ||||
|     // 2. 处理请求 | ||||
|     executeCommand(cmd); | ||||
| } | ||||
| status_t IPCThreadState::executeCommand(int32_t cmd){ | ||||
|     switch((uint32_t)cmd){ | ||||
|         case BR_TRANSACTION:{ | ||||
|             binder_transaction_data tr; | ||||
|             mIn.read(&tr, sizeof(tr)); | ||||
|              | ||||
|             Parcel buffer, reply; | ||||
|             buffer.ipcSetDataReference(...); | ||||
|              | ||||
|             sp<BBinder> b((BBinder*)tr.cookie); | ||||
|             b->transact(tr.code, buffer, &reply, tr.flags); | ||||
|             sendReply(reply, 0); | ||||
|         } | ||||
|     } | ||||
|     return result; | ||||
| } | ||||
| status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags){ | ||||
|     writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer); | ||||
|     return waitForResponse(NULL, NULL); | ||||
| } | ||||
| status_t BBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){ | ||||
|     switch(code){ | ||||
|         case PING_TRANNSACTION: | ||||
|             reply->writeInt32(pingBinder()); | ||||
|             break; | ||||
|         default: | ||||
|             err = onTransact(code, data, reply, flags); | ||||
|             break; | ||||
|     } | ||||
|     return err; | ||||
| } | ||||
| status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0){ | ||||
|     JNIEnv* env = javavm_to_jnienv(mVM); | ||||
|     jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact, code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags); | ||||
|     return res!=JNI_FALSE?NO_ERROE:UNKNOWN_TRANSACTION; | ||||
| } | ||||
| private boolean execTransact(int code, long dataObj, long replyObj, int flags){ | ||||
|     Parcel data = Parcel.obtain(dataObj); | ||||
|     Parcel reply = Parcel.obtain(replyObj); | ||||
|     boolean res = onTransact(code, data, reply, flags); | ||||
|     reply.recycle(); | ||||
|     data.recycle(); | ||||
|     return res; | ||||
| } | ||||
| public static abstract class Stub extends android.os.Binder implements IRemoteCaller{ | ||||
|     boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags){ | ||||
|         switch(code){ | ||||
|             data.enforceInterface(descriptor); | ||||
|                 ICallback _arg0 = ICallback.Stub.asInterface(data.readStrongBinder()); | ||||
|                 this.publishBinder(_arg0); | ||||
|                 reply.writeNoException(); | ||||
|                 return true; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
|  | ||||
| After Width: | Height: | Size: 222 KiB | 
					Loading…
					
					
				
		Reference in new issue