原文鏈接:Binder系列5—注冊(cè)服務(wù)(addService) - CSDN博客
framework/native/libs/binder/
? - Binder.cpp
? - BpBinder.cpp
? - IPCThreadState.cpp
? - ProcessState.cpp
? - IServiceManager.cpp
? - IInterface.cpp
? - Parcel.cpp
frameworks/native/include/binder/
? - IInterface.h (包括BnInterface, BpInterface)
一.概述
1.1 media服務(wù)注冊(cè)
media入口函數(shù)是main_mediaserver.cpp中的main()方法,代碼如下:
int main(int argc __unused, char** argv)
{
? ? ...
? ? InitializeIcuOrDie();
? ? //獲得ProcessState實(shí)例對(duì)象【見(jiàn)小節(jié)2.1】
? ? sp<ProcessState> proc(ProcessState::self());
? ? //獲取BpServiceManager對(duì)象
? ? sp<IServiceManager> sm = defaultServiceManager();
? ? AudioFlinger::instantiate();
? ? //注冊(cè)多媒體服務(wù)? 【見(jiàn)小節(jié)3.1】
? ? MediaPlayerService::instantiate();
? ? ResourceManagerService::instantiate();
? ? CameraService::instantiate();
? ? AudioPolicyService::instantiate();
? ? SoundTriggerHwService::instantiate();
? ? RadioService::instantiate();
? ? registerExtensions();
? ? //啟動(dòng)Binder線程池
? ? ProcessState::self()->startThreadPool();
? ? //當(dāng)前線程加入到線程池
? ? IPCThreadState::self()->joinThreadPool();
}
過(guò)程說(shuō)明:
獲取ServiceManager: 講解了defaultServiceManager()返回的是BpServiceManager對(duì)象, 用于跟servicemanager進(jìn)程通信;
理解Binder線程池的管理, 講解了startThreadPool和joinThreadPool過(guò)程.
本文的重點(diǎn)就是講解Native層服務(wù)注冊(cè)的過(guò)程。
1.2 類圖
在Native層的服務(wù)以media服務(wù)為例,來(lái)說(shuō)一說(shuō)服務(wù)注冊(cè)過(guò)程,先來(lái)看看media的整個(gè)的類關(guān)系圖。?
圖解:
藍(lán)色代表的是注冊(cè)MediaPlayerService服務(wù)所涉及的類;
綠色代表的是Binder架構(gòu)中與Binder驅(qū)動(dòng)通信過(guò)程中的最為核心的兩個(gè)類;
紫色代表的是注冊(cè)服務(wù)和獲取服務(wù)的公共接口/父類;
1.3 時(shí)序圖
先通過(guò)一幅圖來(lái)說(shuō)說(shuō),media服務(wù)啟動(dòng)過(guò)程是如何向servicemanager注冊(cè)服務(wù)的。
二. ProcessState
2.1 ProcessState::self
[-> ProcessState.cpp]
sp<ProcessState> ProcessState::self()
{
? ? Mutex::Autolock _l(gProcessMutex);
? ? if (gProcess != NULL) {
? ? ? ? return gProcess;
? ? }
? ? //實(shí)例化ProcessState 【見(jiàn)小節(jié)2.2】
? ? gProcess = new ProcessState;
? ? return gProcess;
}
獲得ProcessState對(duì)象: 這也是單例模式,從而保證每一個(gè)進(jìn)程只有一個(gè)ProcessState對(duì)象。其中g(shù)Process和gProcessMutex是保存在Static.cpp類的全局變量。
2.2 ProcessState初始化
[-> ProcessState.cpp]
ProcessState::ProcessState()
? ? : mDriverFD(open_driver()) // 打開(kāi)Binder驅(qū)動(dòng)【見(jiàn)小節(jié)2.3】
? ? , mVMStart(MAP_FAILED)
? ? , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
? ? , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
? ? , mExecutingThreadsCount(0)
? ? , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
? ? , mManagesContexts(false)
? ? , mBinderContextCheckFunc(NULL)
? ? , mBinderContextUserData(NULL)
? ? , mThreadPoolStarted(false)
? ? , mThreadPoolSeq(1)
{
? ? if (mDriverFD >= 0) {
? ? ? ? //采用內(nèi)存映射函數(shù)mmap,給binder分配一塊虛擬地址空間【見(jiàn)小節(jié)2.4】
? ? ? ? mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
? ? ? ? if (mVMStart == MAP_FAILED) {
? ? ? ? ? ? close(mDriverFD); //沒(méi)有足夠空間分配給/dev/binder,則關(guān)閉驅(qū)動(dòng)
? ? ? ? ? ? mDriverFD = -1;
? ? ? ? }
? ? }
}
1. ProcessState的單例模式的惟一性,因此一個(gè)進(jìn)程只打開(kāi)binder設(shè)備一次,其中ProcessState的成員變量mDriverFD記錄binder驅(qū)動(dòng)的fd,用于訪問(wèn)binder設(shè)備。
2. BINDER_VM_SIZE = (1*1024*1024) - (4096 *2), binder分配的默認(rèn)內(nèi)存大小為1M-8k。
3. DEFAULT_MAX_BINDER_THREADS = 15,binder默認(rèn)的最大可并發(fā)訪問(wèn)的線程數(shù)為16。
2.3 open_driver
[-> ProcessState.cpp]
static int open_driver()
{
? ? // 打開(kāi)/dev/binder設(shè)備,建立與內(nèi)核的Binder驅(qū)動(dòng)的交互通道
? ? int fd = open("/dev/binder", O_RDWR);
? ? if (fd >= 0) {
? ? ? ? fcntl(fd, F_SETFD, FD_CLOEXEC);
? ? ? ? int vers = 0;
? ? ? ? status_t result = ioctl(fd, BINDER_VERSION, &vers);
? ? ? ? if (result == -1) {
? ? ? ? ? ? close(fd);
? ? ? ? ? ? fd = -1;
? ? ? ? }
? ? ? ? if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
? ? ? ? ? ? close(fd);
? ? ? ? ? ? fd = -1;
? ? ? ? }
? ? ? ? size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
? ? ? ? // 通過(guò)ioctl設(shè)置binder驅(qū)動(dòng),能支持的最大線程數(shù)
? ? ? ? result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
? ? ? ? if (result == -1) {
? ? ? ? ? ? ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
? ? ? ? }
? ? } else {
? ? ? ? ALOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
? ? }
? ? return fd;
}
open_driver作用是打開(kāi)/dev/binder設(shè)備,設(shè)定binder支持的最大線程數(shù)。關(guān)于binder驅(qū)動(dòng)的相應(yīng)方法,見(jiàn)文章Binder Driver初探。
ProcessState采用單例模式,保證每一個(gè)進(jìn)程都只打開(kāi)一次Binder Driver。
2.4 mmap
//原型
void*?mmap(void* addr, size_t size,?int?prot,?int?flags,?int?fd, off_t offset)?//此處?mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD,?0);
參數(shù)說(shuō)明:
addr: 代表映射到進(jìn)程地址空間的起始地址,當(dāng)值等于0則由內(nèi)核選擇合適地址,此處為0;
size: 代表需要映射的內(nèi)存地址空間的大小,此處為1M-8K;
prot: 代表內(nèi)存映射區(qū)的讀寫等屬性值,此處為PROT_READ(可讀取);
flags: 標(biāo)志位,此處為MAP_PRIVATE(私有映射,多進(jìn)程間不共享內(nèi)容的改變)和 MAP_NORESERVE(不保留交換空間)
fd: 代表mmap所關(guān)聯(lián)的文件描述符,此處為mDriverFD;
offset:偏移量,此處為0。
mmap()經(jīng)過(guò)系統(tǒng)調(diào)用,執(zhí)行binder_mmap過(guò)程。
三. 服務(wù)注冊(cè)
3.1 instantiate
[-> MediaPlayerService.cpp]
void MediaPlayerService::instantiate() {
? ? //注冊(cè)服務(wù)【見(jiàn)小節(jié)3.2】
? ? defaultServiceManager()->addService(String16("media.player"), new MediaPlayerService());
}
注冊(cè)服務(wù)MediaPlayerService:由defaultServiceManager()返回的是BpServiceManager,同時(shí)會(huì)創(chuàng)建ProcessState對(duì)象和BpBinder對(duì)象。 故此處等價(jià)于調(diào)用BpServiceManager->addService。其中MediaPlayerService位于libmediaplayerservice庫(kù)。
3.2 BpSM.addService
[-> IServiceManager.cpp ::BpServiceManager]
virtual?status_t?addService(const?String16& name,?const?sp<IBinder>& service,?bool?allowIsolated)?{
? ? Parcel data, reply; //Parcel是數(shù)據(jù)通信包
? ? //寫入頭信息"android.os.IServiceManager"
? ? data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());?
? ? data.writeString16(name);? ? ? ? // name為 "media.player"
? ? data.writeStrongBinder(service); // MediaPlayerService對(duì)象【見(jiàn)小節(jié)3.2.1】
? ? data.writeInt32(allowIsolated ? 1 : 0); // allowIsolated= false
? ? //remote()指向的是BpBinder對(duì)象【見(jiàn)小節(jié)3.3】
? ? status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
? ? return err == NO_ERROR ? reply.readExceptionCode() : err;
}
服務(wù)注冊(cè)過(guò)程:向ServiceManager注冊(cè)服務(wù)MediaPlayerService,服務(wù)名為”media.player”;
3.2.1 writeStrongBinder
[-> parcel.cpp]
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
? ? return flatten_binder(ProcessState::self(), val, this);
}
3.2.2 flatten_binder
[-> parcel.cpp]
status_t flatten_binder(const sp<ProcessState>& /*proc*/,
? ? const sp<IBinder>& binder, Parcel* out)
{
? ? flat_binder_object obj;
? ? obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
? ? if (binder != NULL) {
? ? ? ? IBinder *local = binder->localBinder(); //本地Binder不為空
? ? ? ? if (!local) {
? ? ? ? ? ? BpBinder *proxy = binder->remoteBinder();
? ? ? ? ? ? const int32_t handle = proxy ? proxy->handle() : 0;
? ? ? ? ? ? obj.type = BINDER_TYPE_HANDLE;
? ? ? ? ? ? obj.binder = 0;
? ? ? ? ? ? obj.handle = handle;
? ? ? ? ? ? obj.cookie = 0;
? ? ? ? } else { //進(jìn)入該分支
? ? ? ? ? ? obj.type = BINDER_TYPE_BINDER;
? ? ? ? ? ? obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
? ? ? ? ? ? obj.cookie = reinterpret_cast<uintptr_t>(local);
? ? ? ? }
? ? } else {
? ? ? ? ...
? ? }
? ? //【見(jiàn)小節(jié)3.2.3】
? ? return finish_flatten_binder(binder, obj, out);
}
將Binder對(duì)象扁平化,轉(zhuǎn)換成flat_binder_object對(duì)象。
? ? 1.?對(duì)于Binder實(shí)體,則cookie記錄Binder實(shí)體的指針;
? ? 2.?對(duì)于Binder代理,則用handle記錄Binder代理的句柄;
關(guān)于localBinder,代碼見(jiàn)Binder.cpp。
BBinder* BBinder::localBinder()
{
? ? return this;
}
BBinder* IBinder::localBinder()
{
? ? return NULL;
}
3.2.3 finish_flatten_binder
inline static status_t finish_flatten_binder(
? ? const sp<IBinder>& , const flat_binder_object& flat, Parcel* out)
{
? ? return out->writeObject(flat, false);
}
將flat_binder_object寫入out。
3.3 BpBinder::transact
[-> BpBinder.cpp]
status_t BpBinder::transact(
? ? uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
? ? if (mAlive) {
? ? ? ? // code=ADD_SERVICE_TRANSACTION【見(jiàn)小節(jié)3.4】
? ? ? ? status_t status = IPCThreadState::self()->transact(
? ? ? ? ? ? mHandle, code, data, reply, flags);
? ? ? ? if (status == DEAD_OBJECT) mAlive = 0;
? ? ? ? return status;
? ? }
? ? return DEAD_OBJECT;
}
Binder代理類調(diào)用transact()方法,真正工作還是交給IPCThreadState來(lái)進(jìn)行transact工作。先來(lái)看看IPCThreadState::self的過(guò)程。
3.3.1 IPCThreadState::self
[-> IPCThreadState.cpp]
IPCThreadState* IPCThreadState::self()
{
? ? if (gHaveTLS) {
restart:
? ? ? ? const pthread_key_t k = gTLS;
? ? ? ? IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
? ? ? ? if (st) return st;
? ? ? ? return new IPCThreadState;? //初始IPCThreadState 【見(jiàn)小節(jié)3.3.2】
? ? }
? ? if (gShutdown) return NULL;
? ? pthread_mutex_lock(&gTLSMutex);
? ? if (!gHaveTLS) { //首次進(jìn)入gHaveTLS為false
? ? ? ? if (pthread_key_create(&gTLS, threadDestructor) != 0) { //創(chuàng)建線程的TLS
? ? ? ? ? ? pthread_mutex_unlock(&gTLSMutex);
? ? ? ? ? ? return NULL;
? ? ? ? }
? ? ? ? gHaveTLS = true;
? ? }
? ? pthread_mutex_unlock(&gTLSMutex);
? ? goto restart;
}
TLS是指Thread local storage(線程本地儲(chǔ)存空間),每個(gè)線程都擁有自己的TLS,并且是私有空間,線程之間不會(huì)共享。通過(guò)pthread_getspecific/pthread_setspecific函數(shù)可以獲取/設(shè)置這些空間中的內(nèi)容。從線程本地存儲(chǔ)空間中獲得保存在其中的IPCThreadState對(duì)象。
3.3.2 IPCThreadState初始化
[-> IPCThreadState.cpp]
IPCThreadState::IPCThreadState()
? ? : mProcess(ProcessState::self()),
? ? ? mMyThreadId(gettid()),
? ? ? mStrictModePolicy(0),
? ? ? mLastTransactionBinderFlags(0)
{
? ? pthread_setspecific(gTLS, this);
? ? clearCaller();
? ? mIn.setDataCapacity(256);
? ? mOut.setDataCapacity(256);
}
每個(gè)線程都有一個(gè)IPCThreadState,每個(gè)IPCThreadState中都有一個(gè)mIn、一個(gè)mOut。成員變量mProcess保存了ProcessState變量(每個(gè)進(jìn)程只有一個(gè))。
????mIn 用來(lái)接收來(lái)自Binder設(shè)備的數(shù)據(jù),默認(rèn)大小為256字節(jié);
????mOut用來(lái)存儲(chǔ)發(fā)往Binder設(shè)備的數(shù)據(jù),默認(rèn)大小為256字節(jié)。
3.4 IPC::transact
[-> IPCThreadState.cpp]
status_t IPCThreadState::transact(int32_t handle,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? uint32_t code, const Parcel& data,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Parcel* reply, uint32_t flags)
{
? ? status_t err = data.errorCheck(); //數(shù)據(jù)錯(cuò)誤檢查
? ? flags |= TF_ACCEPT_FDS;
? ? ....
? ? if (err == NO_ERROR) { // 傳輸數(shù)據(jù) 【見(jiàn)小節(jié)3.5】
? ? ? ? err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
? ? }
? ? ...
? ? if ((flags & TF_ONE_WAY) == 0) {
? ? ? ? if (reply) {
? ? ? ? ? ? //等待響應(yīng) 【見(jiàn)小節(jié)3.6】
? ? ? ? ? ? err = waitForResponse(reply);
? ? ? ? } else {
? ? ? ? ? ? Parcel fakeReply;
? ? ? ? ? ? err = waitForResponse(&fakeReply);
? ? ? ? }
? ? } else {
? ? ? ? //oneway,則不需要等待reply的場(chǎng)景
? ? ? ? err = waitForResponse(NULL, NULL);
? ? }
? ? return err;
}
IPCThreadState進(jìn)行transact事務(wù)處理分3部分:
????errorCheck() //數(shù)據(jù)錯(cuò)誤檢查
????writeTransactionData() // 傳輸數(shù)據(jù)
????waitForResponse() //f等待響應(yīng)
3.5 IPC.writeTransactionData
[-> IPCThreadState.cpp]
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 = 0
? ? tr.code = code;? ? ? ? ? ? // code = ADD_SERVICE_TRANSACTION
? ? tr.flags = binderFlags;? ? // binderFlags = 0
? ? tr.cookie = 0;
? ? tr.sender_pid = 0;
? ? tr.sender_euid = 0;
? ? // data為記錄Media服務(wù)信息的Parcel對(duì)象
? ? const status_t err = data.errorCheck();
? ? if (err == NO_ERROR) {
? ? ? ? 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
? ? } else if (statusBuffer) {
? ? ? ? ...
? ? } else {
? ? ? ? return (mLastError = err);
? ? }
? ? mOut.writeInt32(cmd);? ? ? ? //cmd = BC_TRANSACTION
? ? mOut.write(&tr, sizeof(tr));? //寫入binder_transaction_data數(shù)據(jù)
? ? return NO_ERROR;
}
其中handle的值用來(lái)標(biāo)識(shí)目的端,注冊(cè)服務(wù)過(guò)程的目的端為service manager,此處handle=0所對(duì)應(yīng)的是binder_context_mgr_node對(duì)象,正是service manager所對(duì)應(yīng)的binder實(shí)體對(duì)象。binder_transaction_data結(jié)構(gòu)體是binder驅(qū)動(dòng)通信的數(shù)據(jù)結(jié)構(gòu),該過(guò)程最終是把Binder請(qǐng)求碼BC_TRANSACTION和binder_transaction_data結(jié)構(gòu)體寫入到mOut。
transact過(guò)程,先寫完binder_transaction_data數(shù)據(jù),其中Parcel data的重要成員變量:
????mDataSize:保存再data_size,binder_transaction的數(shù)據(jù)大小;
????mData: 保存在ptr.buffer, binder_transaction的數(shù)據(jù)的起始地址;
????mObjectsSize:保存在ptr.offsets_size,記錄著flat_binder_object結(jié)構(gòu)體的個(gè)數(shù);
????mObjects: 保存在offsets, 記錄著flat_binder_object結(jié)構(gòu)體在數(shù)據(jù)偏移量;
接下來(lái)執(zhí)行waitForResponse()方法。
3.6 IPC.waitForResponse
[-> IPCThreadState.cpp]
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
? ? int32_t cmd;
? ? int32_t err;
? ? while (1) {
? ? ? ? if ((err=talkWithDriver()) < NO_ERROR) break; // 【見(jiàn)小節(jié)3.7】
? ? ? ? ...
? ? ? ? if (mIn.dataAvail() == 0) continue;
? ? ? ? cmd = mIn.readInt32();
? ? ? ? switch (cmd) {
? ? ? ? ? ? case BR_TRANSACTION_COMPLETE: ...
? ? ? ? ? ? case BR_DEAD_REPLY: ...
? ? ? ? ? ? case BR_FAILED_REPLY: ...
? ? ? ? ? ? case BR_ACQUIRE_RESULT: ...
? ? ? ? ? ? case BR_REPLY: ...
? ? ? ? ? ? ? ? goto finish;
? ? ? ? ? ? default:
? ? ? ? ? ? ? ? err = executeCommand(cmd);? //【見(jiàn)小節(jié)3.x】
? ? ? ? ? ? ? ? if (err != NO_ERROR) goto finish;
? ? ? ? ? ? ? ? break;
? ? ? ? }
? ? }
? ? ...
? ? return err;
}
在waitForResponse過(guò)程, 首先執(zhí)行BR_TRANSACTION_COMPLETE;另外,目標(biāo)進(jìn)程收到事務(wù)后,處理BR_TRANSACTION事務(wù)。 然后發(fā)送給當(dāng)前進(jìn)程,再執(zhí)行BR_REPLY命令。
3.7 IPC.talkWithDriver
[-> IPCThreadState.cpp]
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
? ? ...
? ? 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) {
? ? ? ? //接收數(shù)據(jù)緩沖區(qū)信息的填充。如果以后收到數(shù)據(jù),就直接填在mIn中了。
? ? ? ? bwr.read_size = mIn.dataCapacity();
? ? ? ? bwr.read_buffer = (uintptr_t)mIn.data();
? ? } else {
? ? ? ? bwr.read_size = 0;
? ? ? ? bwr.read_buffer = 0;
? ? }
? ? //當(dāng)讀緩沖和寫緩沖都為空,則直接返回
? ? if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
? ? bwr.write_consumed = 0;
? ? bwr.read_consumed = 0;
? ? status_t err;
? ? do {
? ? ? ? //通過(guò)ioctl不停的讀寫操作,跟Binder Driver進(jìn)行通信
? ? ? ? if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
? ? ? ? ? ? err = NO_ERROR;
? ? ? ? ...
? ? } while (err == -EINTR); //當(dāng)被中斷,則繼續(xù)執(zhí)行
? ? ...
? ? return err;
}
binder_write_read結(jié)構(gòu)體用來(lái)與Binder設(shè)備交換數(shù)據(jù)的結(jié)構(gòu), 通過(guò)ioctl與mDriverFD通信,是真正與Binder驅(qū)動(dòng)進(jìn)行數(shù)據(jù)讀寫交互的過(guò)程。 主要是操作mOut和mIn變量。
ioctl()經(jīng)過(guò)系統(tǒng)調(diào)用后進(jìn)入Binder Driver。
四. Binder Driver
ioctl -> binder_ioctl -> binder_ioctl_write_read
4.1 binder_ioctl_write_read
[-> binder.c]
static int binder_ioctl_write_read(struct file *filp,
? ? ? ? ? ? ? ? unsigned int cmd, unsigned long arg,
? ? ? ? ? ? ? ? struct binder_thread *thread)
{
? ? struct binder_proc *proc = filp->private_data;
? ? void __user *ubuf = (void __user *)arg;
? ? struct binder_write_read bwr;
? ? //將用戶空間bwr結(jié)構(gòu)體拷貝到內(nèi)核空間
? ? copy_from_user(&bwr, ubuf, sizeof(bwr));
? ? ...
? ? if (bwr.write_size > 0) {
? ? ? ? //將數(shù)據(jù)放入目標(biāo)進(jìn)程【見(jiàn)小節(jié)4.2】
? ? ? ? ret = binder_thread_write(proc, thread,
? ? ? ? ? ? ? ? ? ? ? bwr.write_buffer,
? ? ? ? ? ? ? ? ? ? ? bwr.write_size,
? ? ? ? ? ? ? ? ? ? ? &bwr.write_consumed);
? ? ? ? ...
? ? }
? ? if (bwr.read_size > 0) {
? ? ? ? //讀取自己隊(duì)列的數(shù)據(jù) 【見(jiàn)小節(jié)】
? ? ? ? ret = binder_thread_read(proc, thread, bwr.read_buffer,
? ? ? ? ? ? bwr.read_size,
? ? ? ? ? ? &bwr.read_consumed,
? ? ? ? ? ? filp->f_flags & O_NONBLOCK);
? ? ? ? if (!list_empty(&proc->todo))
? ? ? ? ? ? wake_up_interruptible(&proc->wait);
? ? ? ? ...
? ? }
? ? //將內(nèi)核空間bwr結(jié)構(gòu)體拷貝到用戶空間
? ? copy_to_user(ubuf, &bwr, sizeof(bwr));
? ? ...
}?
4.2 binder_thread_write
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命令,此時(shí)為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);
? ? ? ? ? ? // 見(jiàn)小節(jié)4.3】
? ? ? ? ? ? binder_transaction(proc, thread, &tr, cmd == BC_REPLY);
? ? ? ? ? ? break;
? ? ? ? }
? ? ? ? ...
? ? }
? ? *consumed = ptr - buffer;
? }
? return 0;
}
4.3 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;
? ? ...
? ? if (reply) {
? ? ? ? ...
? ? }else {
? ? ? ? if (tr->target.handle) {
? ? ? ? ? ? ...
? ? ? ? } else {
? ? ? ? ? ? // handle=0則找到servicemanager實(shí)體
? ? ? ? ? ? target_node = binder_context_mgr_node;
? ? ? ? }
? ? ? ? //target_proc為servicemanager進(jìn)程
? ? ? ? target_proc = target_node->proc;
? ? }
? ? if (target_thread) {
? ? ? ? ...
? ? } else {
? ? ? ? //找到servicemanager進(jìn)程的todo隊(duì)列
? ? ? ? target_list = &target_proc->todo;
? ? ? ? target_wait = &target_proc->wait;
? ? }
? ? t = kzalloc(sizeof(*t), GFP_KERNEL);
? ? tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
? ? //非oneway的通信方式,把當(dāng)前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; //此次通信目標(biāo)進(jìn)程為servicemanager進(jìn)程
? ? t->to_thread = target_thread;
? ? t->code = tr->code;? //此次通信code = ADD_SERVICE_TRANSACTION
? ? t->flags = tr->flags;? // 此次通信flags = 0
? ? t->priority = task_nice(current);
? ? //從servicemanager進(jìn)程中分配buffer
? ? 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); //引用計(jì)數(shù)加1
? ? offp = (binder_size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));
? ? //分別拷貝用戶空間的binder_transaction_data中ptr.buffer和ptr.offsets到內(nèi)核
? ? 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_BINDER:
? ? ? ? ? ? case BINDER_TYPE_WEAK_BINDER: {
? ? ? ? ? ? ? struct binder_ref *ref;
? ? ? ? ? ? ? //【見(jiàn)4.3.1】
? ? ? ? ? ? ? struct binder_node *node = binder_get_node(proc, fp->binder);
? ? ? ? ? ? ? if (node == NULL) {
? ? ? ? ? ? ? ? //服務(wù)所在進(jìn)程 創(chuàng)建binder_node實(shí)體【見(jiàn)4.3.2】
? ? ? ? ? ? ? ? node = binder_new_node(proc, fp->binder, fp->cookie);
? ? ? ? ? ? ? ? ...
? ? ? ? ? ? ? }
? ? ? ? ? ? ? //servicemanager進(jìn)程binder_ref【見(jiàn)4.3.3】
? ? ? ? ? ? ? ref = binder_get_ref_for_node(target_proc, node);
? ? ? ? ? ? ? ...
? ? ? ? ? ? ? //調(diào)整type為HANDLE類型
? ? ? ? ? ? ? if (fp->type == BINDER_TYPE_BINDER)
? ? ? ? ? ? ? ? fp->type = BINDER_TYPE_HANDLE;
? ? ? ? ? ? ? else
? ? ? ? ? ? ? ? fp->type = BINDER_TYPE_WEAK_HANDLE;
? ? ? ? ? ? ? fp->binder = 0;
? ? ? ? ? ? ? fp->handle = ref->desc; //設(shè)置handle值
? ? ? ? ? ? ? fp->cookie = 0;
? ? ? ? ? ? ? binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
? ? ? ? ? ? ? ? ? ? ? &thread->todo);
? ? ? ? ? ? } break;
? ? ? ? ? ? case :...
? ? }
? ? if (reply) {
? ? ? ? ..
? ? } else if (!(t->flags & TF_ONE_WAY)) {
? ? ? ? //BC_TRANSACTION 且 非oneway,則設(shè)置事務(wù)棧信息
? ? ? ? t->need_reply = 1;
? ? ? ? t->from_parent = thread->transaction_stack;
? ? ? ? thread->transaction_stack = t;
? ? } else {
? ? ? ? ...
? ? }
? ? //將BINDER_WORK_TRANSACTION添加到目標(biāo)隊(duì)列,本次通信的目標(biāo)隊(duì)列為target_proc->todo
? ? t->work.type = BINDER_WORK_TRANSACTION;
? ? list_add_tail(&t->work.entry, target_list);
? ? //將BINDER_WORK_TRANSACTION_COMPLETE添加到當(dāng)前線程的todo隊(duì)列
? ? tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
? ? list_add_tail(&tcomplete->entry, &thread->todo);
? ? //喚醒等待隊(duì)列,本次通信的目標(biāo)隊(duì)列為target_proc->wait
? ? if (target_wait)
? ? ? ? wake_up_interruptible(target_wait);
? ? return;
}
注冊(cè)服務(wù)的過(guò)程,傳遞的是BBinder對(duì)象,故[小節(jié)3.2.1]的writeStrongBinder()過(guò)程中l(wèi)ocalBinder不為空, 從而flat_binder_object.type等于BINDER_TYPE_BINDER。
服務(wù)注冊(cè)過(guò)程是在服務(wù)所在進(jìn)程創(chuàng)建binder_node,在servicemanager進(jìn)程創(chuàng)建binder_ref。 對(duì)于同一個(gè)binder_node,每個(gè)進(jìn)程只會(huì)創(chuàng)建一個(gè)binder_ref對(duì)象。
向servicemanager的binder_proc->todo添加BINDER_WORK_TRANSACTION事務(wù),接下來(lái)進(jìn)入ServiceManager進(jìn)程。
4.3.1 binder_get_node
static struct binder_node *binder_get_node(struct binder_proc *proc,
? ? ? ? ? ? binder_uintptr_t ptr)
{
? struct rb_node *n = proc->nodes.rb_node;
? struct binder_node *node;
? while (n) {
? ? node = rb_entry(n, struct binder_node, rb_node);
? ? if (ptr < node->ptr)
? ? ? n = n->rb_left;
? ? else if (ptr > node->ptr)
? ? ? n = n->rb_right;
? ? else
? ? ? return node;
? }
? return NULL;
}
從binder_proc來(lái)根據(jù)binder指針ptr值,查詢相應(yīng)的binder_node。
4.3.2 binder_new_node
static struct binder_node *binder_new_node(struct binder_proc *proc,
? ? ? ? ? ? ? ? ? ? ? binder_uintptr_t ptr,
? ? ? ? ? ? ? ? ? ? ? binder_uintptr_t cookie)
{
? ? struct rb_node **p = &proc->nodes.rb_node;
? ? struct rb_node *parent = NULL;
? ? struct binder_node *node;
? ? ... //紅黑樹(shù)位置查找
? ? //給新創(chuàng)建的binder_node 分配內(nèi)核空間
? ? node = kzalloc(sizeof(*node), GFP_KERNEL);
? ? // 將新創(chuàng)建的node添加到proc紅黑樹(shù);
? ? rb_link_node(&node->rb_node, parent, p);
? ? rb_insert_color(&node->rb_node, &proc->nodes);
? ? node->debug_id = ++binder_last_id;
? ? node->proc = proc;
? ? node->ptr = ptr;
? ? node->cookie = cookie;
? ? node->work.type = BINDER_WORK_NODE; //設(shè)置binder_work的type
? ? INIT_LIST_HEAD(&node->work.entry);
? ? INIT_LIST_HEAD(&node->async_todo);
? ? return node;
}
4.3.3 binder_get_ref_for_node
static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc,
? ? ? ? ? ? ? struct binder_node *node)
{
? struct rb_node *n;
? struct rb_node **p = &proc->refs_by_node.rb_node;
? struct rb_node *parent = NULL;
? struct binder_ref *ref, *new_ref;
? //從refs_by_node紅黑樹(shù),找到binder_ref則直接返回。
? while (*p) {
? ? parent = *p;
? ? ref = rb_entry(parent, struct binder_ref, rb_node_node);
? ? if (node < ref->node)
? ? ? p = &(*p)->rb_left;
? ? else if (node > ref->node)
? ? ? p = &(*p)->rb_right;
? ? else
? ? ? return ref;
? }
? //創(chuàng)建binder_ref
? new_ref = kzalloc_preempt_disabled(sizeof(*ref));
? new_ref->debug_id = ++binder_last_id;
? new_ref->proc = proc; //記錄進(jìn)程信息
? new_ref->node = node; //記錄binder節(jié)點(diǎn)
? rb_link_node(&new_ref->rb_node_node, parent, p);
? rb_insert_color(&new_ref->rb_node_node, &proc->refs_by_node);
? //計(jì)算binder引用的handle值,該值返回給target_proc進(jìn)程
? new_ref->desc = (node == binder_context_mgr_node) ? 0 : 1;
? //從紅黑樹(shù)最最左邊的handle對(duì)比,依次遞增,直到紅黑樹(shù)遍歷結(jié)束或者找到更大的handle則結(jié)束。
? for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) {
? ? //根據(jù)binder_ref的成員變量rb_node_desc的地址指針n,來(lái)獲取binder_ref的首地址
? ? ref = rb_entry(n, struct binder_ref, rb_node_desc);
? ? if (ref->desc > new_ref->desc)
? ? ? break;
? ? new_ref->desc = ref->desc + 1;
? }
? // 將新創(chuàng)建的new_ref 插入proc->refs_by_desc紅黑樹(shù)
? p = &proc->refs_by_desc.rb_node;
? while (*p) {
? ? parent = *p;
? ? ref = rb_entry(parent, struct binder_ref, rb_node_desc);
? ? if (new_ref->desc < ref->desc)
? ? ? p = &(*p)->rb_left;
? ? else if (new_ref->desc > ref->desc)
? ? ? p = &(*p)->rb_right;
? ? else
? ? ? BUG();
? }
? rb_link_node(&new_ref->rb_node_desc, parent, p);
? rb_insert_color(&new_ref->rb_node_desc, &proc->refs_by_desc);
? if (node) {
? ? hlist_add_head(&new_ref->node_entry, &node->refs);
? }
? return new_ref;
}
handle值計(jì)算方法規(guī)律:
? ??每個(gè)進(jìn)程binder_proc所記錄的binder_ref的handle值是從1開(kāi)始遞增的;
? ??所有進(jìn)程binder_proc所記錄的handle=0的binder_ref都指向service manager;
? ??同一個(gè)服務(wù)的binder_node在不同進(jìn)程的binder_ref的handle值可以不同;
五. ServiceManager
由Binder系列3—啟動(dòng)ServiceManager已介紹其原理,循環(huán)在binder_loop()過(guò)程, 會(huì)調(diào)用binder_parse()方法。
5.1 binder_parse
[-> servicemanager/binder.c]
int?binder_parse(struct?binder_state *bs,?struct?binder_io *bio, uintptr_t ptr, size_t size, binder_handler func)?{
? ? int r = 1;
? ? uintptr_t end = ptr + (uintptr_t) size;
? ? while (ptr < end) {
? ? ? ? uint32_t cmd = *(uint32_t *) ptr;
? ? ? ? ptr += sizeof(uint32_t);
? ? ? ? switch(cmd) {
? ? ? ? case BR_TRANSACTION: {
? ? ? ? ? ? struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
? ? ? ? ? ? ...
? ? ? ? ? ? binder_dump_txn(txn);
? ? ? ? ? ? if (func) {
? ? ? ? ? ? ? ? unsigned rdata[256/4];
? ? ? ? ? ? ? ? struct binder_io msg;
? ? ? ? ? ? ? ? struct binder_io reply;
? ? ? ? ? ? ? ? int res;
? ? ? ? ? ? ? ? bio_init(&reply, rdata, sizeof(rdata), 4);
? ? ? ? ? ? ? ? bio_init_from_txn(&msg, txn); //從txn解析出binder_io信息
? ? ? ? ? ? ? ? // 收到Binder事務(wù) 【見(jiàn)小節(jié)5.2】
? ? ? ? ? ? ? ? res = func(bs, txn, &msg, &reply);
? ? ? ? ? ? ? ? // 發(fā)送reply事件【見(jiàn)小節(jié)5.4】
? ? ? ? ? ? ? ? binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
? ? ? ? ? ? }
? ? ? ? ? ? ptr += sizeof(*txn);
? ? ? ? ? ? break;
? ? ? ? }
? ? ? ? case : ...
? ? }
? ? return r;
}
5.2 svcmgr_handler
[-> service_manager.c]
int?svcmgr_handler(struct?binder_state *bs,?struct?binder_transaction_data *txn,?struct?binder_io *msg,?struct?binder_io *reply)?{
? ? struct svcinfo *si;
? ? uint16_t *s;
? ? size_t len;
? ? uint32_t handle;
? ? uint32_t strict_policy;
? ? int allow_isolated;
? ? ...
? ? strict_policy = bio_get_uint32(msg);
? ? s = bio_get_string16(msg, &len);
? ? ...
? ? switch(txn->code) {
? ? ? case SVC_MGR_ADD_SERVICE:
? ? ? ? ? s = bio_get_string16(msg, &len);
? ? ? ? ? ...
? ? ? ? ? handle = bio_get_ref(msg); //獲取handle
? ? ? ? ? allow_isolated = bio_get_uint32(msg) ? 1 : 0;
? ? ? ? ? //注冊(cè)指定服務(wù) 【見(jiàn)小節(jié)5.3】
? ? ? ? ? if (do_add_service(bs, s, len, handle, txn->sender_euid,
? ? ? ? ? ? ? allow_isolated, txn->sender_pid))
? ? ? ? ? ? ? return -1;
? ? ? ? ? break;
? ? ? case :...
? ? }
? ? bio_put_uint32(reply, 0);
? ? return 0;
}
5.3 do_add_service
[-> service_manager.c]
int do_add_service(struct binder_state *bs,
? ? ? ? ? ? ? ? ? const uint16_t *s, size_t len,
? ? ? ? ? ? ? ? ? uint32_t handle, uid_t uid, int allow_isolated,
? ? ? ? ? ? ? ? ? pid_t spid)
{
? ? struct svcinfo *si;
? ? if (!handle || (len == 0) || (len > 127))
? ? ? ? return -1;
? ? //權(quán)限檢查
? ? if (!svc_can_register(s, len, spid)) {
? ? ? ? return -1;
? ? }
? ? //服務(wù)檢索
? ? si = find_svc(s, len);
? ? if (si) {
? ? ? ? if (si->handle) {
? ? ? ? ? ? svcinfo_death(bs, si); //服務(wù)已注冊(cè)時(shí),釋放相應(yīng)的服務(wù)
? ? ? ? }
? ? ? ? si->handle = handle;
? ? } else {
? ? ? ? si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
? ? ? ? if (!si) {? //內(nèi)存不足,無(wú)法分配足夠內(nèi)存
? ? ? ? ? ? return -1;
? ? ? ? }
? ? ? ? si->handle = handle;
? ? ? ? si->len = len;
? ? ? ? memcpy(si->name, s, (len + 1) * sizeof(uint16_t)); //內(nèi)存拷貝服務(wù)信息
? ? ? ? si->name[len] = '\0';
? ? ? ? si->death.func = (void*) svcinfo_death;
? ? ? ? si->death.ptr = si;
? ? ? ? si->allow_isolated = allow_isolated;
? ? ? ? si->next = svclist; // svclist保存所有已注冊(cè)的服務(wù)
? ? ? ? svclist = si;
? ? }
? ? //以BC_ACQUIRE命令,handle為目標(biāo)的信息,通過(guò)ioctl發(fā)送給binder驅(qū)動(dòng)
? ? binder_acquire(bs, handle);
? ? //以BC_REQUEST_DEATH_NOTIFICATION命令的信息,通過(guò)ioctl發(fā)送給binder驅(qū)動(dòng),主要用于清理內(nèi)存等收尾工作。
? ? binder_link_to_death(bs, handle, &si->death);
? ? return 0;
}
svcinfo記錄著服務(wù)名和handle信息,保存到svclist列表。
5.4 binder_send_reply
[-> servicemanager/binder.c]
void?binder_send_reply(struct?binder_state *bs,?struct?binder_io *reply, binder_uintptr_t buffer_to_free,?int?status)?{
? ? struct {
? ? ? ? uint32_t cmd_free;
? ? ? ? binder_uintptr_t buffer;
? ? ? ? uint32_t cmd_reply;
? ? ? ? struct binder_transaction_data txn;
? ? } __attribute__((packed)) data;
? ? data.cmd_free = BC_FREE_BUFFER; //free buffer命令
? ? data.buffer = buffer_to_free;
? ? data.cmd_reply = BC_REPLY; // reply命令
? ? data.txn.target.ptr = 0;
? ? data.txn.cookie = 0;
? ? data.txn.code = 0;
? ? if (status) {
? ? ? ? ...
? ? } else {
? ? ? ? data.txn.flags = 0;
? ? ? ? data.txn.data_size = reply->data - reply->data0;
? ? ? ? data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0);
? ? ? ? data.txn.data.ptr.buffer = (uintptr_t)reply->data0;
? ? ? ? data.txn.data.ptr.offsets = (uintptr_t)reply->offs0;
? ? }
? ? //向Binder驅(qū)動(dòng)通信
? ? binder_write(bs, &data, sizeof(data));
}
binder_write進(jìn)入binder驅(qū)動(dòng)后,將BC_FREE_BUFFER和BC_REPLY命令協(xié)議發(fā)送給Binder驅(qū)動(dòng), 向client端發(fā)送reply。
六. 總結(jié)
服務(wù)注冊(cè)過(guò)程(addService)核心功能:在服務(wù)所在進(jìn)程創(chuàng)建binder_node,在servicemanager進(jìn)程創(chuàng)建binder_ref。 其中binder_ref的desc再同一個(gè)進(jìn)程內(nèi)是唯一的:
????每個(gè)進(jìn)程binder_proc所記錄的binder_ref的handle值是從1開(kāi)始遞增的;
????所有進(jìn)程binder_proc所記錄的handle=0的binder_ref都指向service manager;
????同一個(gè)服務(wù)的binder_node在不同進(jìn)程的binder_ref的handle值可以不同;????
Media服務(wù)注冊(cè)的過(guò)程涉及到MediaPlayerService(作為Client進(jìn)程)和Service Manager(作為Service進(jìn)程),通信流程圖如下所示:
過(guò)程分析:
1. MediaPlayerService進(jìn)程調(diào)用ioctl()向Binder驅(qū)動(dòng)發(fā)送IPC數(shù)據(jù),該過(guò)程可以理解成一個(gè)事務(wù)binder_transaction(記為T1),執(zhí)行當(dāng)前操作的線程binder_thread(記為thread1),則T1->from_parent=NULL,T1->from =thread1,thread1->transaction_stack=T1。其中IPC數(shù)據(jù)內(nèi)容包含:
????Binder協(xié)議為BC_TRANSACTION;
????Handle等于0;
????RPC代碼為ADD_SERVICE;
????RPC數(shù)據(jù)為”media.player”。
2.?Binder驅(qū)動(dòng)收到該Binder請(qǐng)求,生成BR_TRANSACTION命令,選擇目標(biāo)處理該請(qǐng)求的線程,即ServiceManager的binder線程(記為thread2),則 T1->to_parent = NULL,T1->to_thread =thread2。并將整個(gè)binder_transaction數(shù)據(jù)(記為T2)插入到目標(biāo)線程的todo隊(duì)列;
3.?Service Manager的線程thread2收到T2后,調(diào)用服務(wù)注冊(cè)函數(shù)將服務(wù)”media.player”注冊(cè)到服務(wù)目錄中。當(dāng)服務(wù)注冊(cè)完成后,生成IPC應(yīng)答數(shù)據(jù)(BC_REPLY),T2->form_parent = T1,T2->from = thread2, thread2->transaction_stack = T2。
4.?Binder驅(qū)動(dòng)收到該Binder應(yīng)答請(qǐng)求,生成BR_REPLY命令,T2->to_parent = T1,T2->to_thread = thread1, thread1->transaction_stack = T2。 在MediaPlayerService收到該命令后,知道服務(wù)注冊(cè)完成便可以正常使用。
整個(gè)過(guò)程中,BC_TRANSACTION和BR_TRANSACTION過(guò)程是一個(gè)完整的事務(wù)過(guò)程;BC_REPLY和BR_REPLY是一個(gè)完整的事務(wù)過(guò)程。 到此,其他進(jìn)行便可以獲取該服務(wù),使用服務(wù)提供的方法,下一篇文章將會(huì)講述如何獲取服務(wù)。