http://gityuan.com/2015/10/31/binder-prepare/
1. 注冊服務##
- 從cpp開始分析(main_mediaserver.cpp)
int main(int argc __unused, char** argv)
{
...
InitializeIcuOrDie();
//獲得ProcessState實例對象
sp<ProcessState> proc(ProcessState::self());
//獲取ServiceManager實例對象
sp<IServiceManager> sm = defaultServiceManager();
AudioFlinger::instantiate();
//多媒體服務
MediaPlayerService::instantiate();
ResourceManagerService::instantiate();
CameraService::instantiate();
AudioPolicyService::instantiate();
SoundTriggerHwService::instantiate();
RadioService::instantiate();
registerExtensions();
//創建Binder線程,并加入線程池
ProcessState::self()->startThreadPool();
//當前線程加入到線程池
IPCThreadState::self()->joinThreadPool();
}
可見主多媒體服務,在main方法中初始化了很多多媒體的服務,我們就挑一個去分析
void MediaPlayerService::instantiate() {
defaultServiceManager()->addService( String16("media.player"), new MediaPlayerService());
}
virtual status_t addService(const String16& name, const sp<IBinder>& service,
bool allowIsolated)
{
Parcel data, reply; //Parcel是數據通信包
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); //寫入RPC頭信息
data.writeString16(name); // name為 "media.player"
data.writeStrongBinder(service); // MediaPlayerService對象
data.writeInt32(allowIsolated ? 1 : 0); // allowIsolated= false
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
很明先的ServiceManager的addService的方法是公用的,最主要的就是調用的
remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply)
remote方法返回的是BpBinder對象(IBinder的子類,和BBinder一樣)
client端:BpBinder.transact()來發送事務請求;
server端:BBinder.onTransact()會接收到相應事務。
然后我們去看BpBinder的transact的方法
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的transact方法,每一個線程都有一個IPCThreadState,而每一個IPCThreadState都會有mIn和mOut,這兩個東西就是把相應的數據寫入的Binder中和從Binder中讀取。
然后可以在IPCThreadState的transact方法中
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);
}
if ((flags & TF_ONE_WAY) == 0) {
//需要等待reply的場景
if (reply) {
//等待響應
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
} else {
//oneway,則不需要等待reply的場景
err = waitForResponse(NULL, NULL);
}
return err;
}
主要方法就是writeTransactionData和waitForResponse這兩個方法
前面的是將數據寫到binder設備中去,而waitForResponse方法就是等待binder設備的數據回調。
而主要的和binder之間的交互就是定義在waitForResponse方法中的
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
int32_t cmd;
int32_t err;
while (1) {
if ((err=talkWithDriver()) < NO_ERROR) break; // 【見流程10】
err = mIn.errorCheck();
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:
{
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));
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); //【見流程11】
if (err != NO_ERROR) goto finish;
break;
}
}
finish:
if (err != NO_ERROR) {
if (acquireResult) *acquireResult = err;
if (reply) reply->setError(err);
mLastError = err;
}
return err;
}
主要的就是BR_REPLY
我們看到while(1)就是一個死循環,不斷的從mIn中去讀response的反饋,,讀到BR_REPLY之后,用binder_transaction_data類型去把反饋讀出來,我們可以看while(1)里面err=talkWithDriver()這個方法是將數據寫到mIn里面去的,也就是真正看到最后,重中之重就是這個跟老司機交流的方法。
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
if (mProcess->mDriverFD <= 0) {
return -EBADF;
}
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) {
//接收數據緩沖區信息的填充。如果以后收到數據,就直接填在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 Driver進行通信
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
if (mProcess->mDriverFD <= 0) {
err = -EBADF;
}
} 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;
}
最主要的方法就是如下這個循環:
do {
//通過ioctl不停的讀寫操作,跟Binder Driver進行通信
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
if (mProcess->mDriverFD <= 0) {
err = -EBADF;
}
} while (err == -EINTR);
ioctl方法會不斷的去跟binder driver通信,然后將數據寫入到binder_write_read中。
再回去看waitforResponse的default選項:
err = executeCommand(cmd);
也就是說除了
case BR_TRANSACTION_COMPLETE:
case BR_DEAD_REPLY:
case BR_FAILED_REPLY:
case BR_ACQUIRE_RESULT:
case BR_REPLY:
這幾個類型之外的所有類型都走的是executeCommand方法
主要看BR_TRANSACTION方法
binder_transaction_data tr;
result = mIn.read(&tr, sizeof(tr));
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) {
setpriority(PRIO_PROCESS, mMyThreadId, ANDROID_PRIORITY_NORMAL);
}
} else {
if (curPrio >= ANDROID_PRIORITY_BACKGROUND) {
set_sched_policy(mMyThreadId, SP_BACKGROUND);
}
}
Parcel reply;
status_t error;
// tr.cookie里存放的是BBinder,此處b是BBinder的實現子類
if (tr.target.ptr) {
sp<BBinder> b((BBinder*)tr.cookie);
error = b->transact(tr.code, buffer, &reply, tr.flags); //
} else {
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
}
if ((tr.flags & TF_ONE_WAY) == 0) {
if (error < NO_ERROR) reply.setError(error);
sendReply(reply, 0);
}
mCallingPid = origPid;
mCallingUid = origUid;
mStrictModePolicy = origStrictModePolicy;
mLastTransactionBinderFlags = origTransactionBinderFlags;
主要的方法就是
sp<BBinder> b((BBinder*)tr.cookie);
error = b->transact(tr.code, buffer, &reply, tr.flags);
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);
break;
}
if (reply != NULL) {
reply->setDataPosition(0);
}
return err;
}
status_t BBinder::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t /*flags*/)
{
switch (code) {
case INTERFACE_TRANSACTION:
reply->writeString16(getInterfaceDescriptor());
return NO_ERROR;
case DUMP_TRANSACTION: {
int fd = data.readFileDescriptor();
int argc = data.readInt32();
Vector<String16> args;
for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
args.add(data.readString16());
}
return dump(fd, args);
}
case SYSPROPS_TRANSACTION: {
report_sysprop_change();
return NO_ERROR;
}
default:
return UNKNOWN_TRANSACTION;
}
}
MediaPlayeService發送注冊請求給Binder設備(BC_TRANSACTION),Binder收到請求之后,回復BR_TRANSACTION_COMPLETE,然后Binder發送給ServiceManger,BR_TRANSACTION命令告訴他需要注冊,然后SericeManager進行注冊服務注冊,之后返回BC_REPLY給Binder,Binder成功喚醒MediaPlayerService,然后告訴ServiceManger已經成功完成任務了,后者進入睡眠,然后告訴MediaPlayerServiceBR_REPLY,走完整個請求流程。
然后我們來看main方法的最后兩行
//創建Binder線程,并加入線程池 ProcessState::self()->startThreadPool();
當前線程創建binder線程,并且加入到binder線程池
//當前線程加入到線程池 IPCThreadState::self()->joinThreadPool();
當前線程自己也加入binder線程池
2. 獲取服務##
獲取servicemanager之后就不斷的循環的去獲取名為media.service的binder服務
sp<IServiceManager> sm = defaultServiceManager(); //獲取ServiceManager
sp<IBinder> binder;
do {
//獲取名為"media.player"的服務 【見流程2】
binder = sm->getService(String16("media.player"));
if (binder != 0) {
break;
}
usleep(500000); // 0.5 s
} while (true);
而getservice方法則是做5次請求,每次間隔1秒,取不到就返回null
virtual sp<IBinder> getService(const String16& name) const
{
unsigned n;
for (n = 0; n < 5; n++){
sp<IBinder> svc = checkService(name); //【見流程3】
if (svc != NULL) return svc;
sleep(1);
}
return NULL;
}
checkservice會去驗證服務是否存在
virtual sp<IBinder> checkService( const String16& name) const
{
Parcel data, reply;
//寫入RPC頭
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
//寫入服務名
data.writeString16(name);
remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply); //【見流程4】
return reply.readStrongBinder();
}
主要就是transact方法,和之前的注冊服務一樣的了。
然后我們來看看死亡通知
if (sDeathNotifier == NULL) {
sDeathNotifier = new DeathNotifier(); //創建死亡通知對象
}
//將死亡通知連接到binder 【見流程14】
binder->linkToDeath(sDeathNotifier);
sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
將死亡通知和binder連接起來,死亡通知主要負責的東西就是Bp端(跟遠程端打交道)需要去監聽B端(跟本地端打交道)的相關服務的生死情況,在B端的服務線程退出之后,就會發出死亡通知,然后Bp端就會做出服務的清理工作。
如何去獲取serviceManager
我們在注冊和獲取服務的過程中都調用了defaultServiceManager,那么到底是怎么去獲得到的呢?
sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
{
AutoMutex _l(gDefaultServiceManagerLock); //加鎖
while (gDefaultServiceManager == NULL) {
//【見下文小節二,三,四】
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(NULL));
if (gDefaultServiceManager == NULL)
sleep(1);
}
}
return gDefaultServiceManager;
}
很顯然,使用了單例模式去管理serviceManager,對單例進行加鎖,然后去獲取serviceManger,如果拿不到就停止1秒鐘,因為可能存在serviceManager還沒有準備好的情況。
然后我們一個一個看,ProcessState::self()方法,之前就看過,直接去獲取到ProcessState的單例,每個線程只有一個,那到底做了什么呢?首先是一個很簡單的單例
sp<ProcessState> ProcessState::self()
{
Mutex::Autolock _l(gProcessMutex);
if (gProcess != NULL) {
return gProcess;
}
//實例化ProcessState 【見小節2.2】
gProcess = new ProcessState;
return gProcess;
}
然后我們看一下,new方法到底new出來的是什么東西
ProcessState::ProcessState()
: mDriverFD(open_driver()) // 打開Binder驅動【見小節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) {
//采用內存映射函數mmap,給binder分配一塊虛擬地址空間,用來接收事務
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
if (mVMStart == MAP_FAILED) {
close(mDriverFD); //沒有足夠空間分配給/dev/binder,則關閉驅動
mDriverFD = -1;
}
}
}
打開binder驅動,我們看到由于是單例模式,每一次只會打開binder驅動一次,還有其中有兩個參數,我們需要知道一下:
BINDER_VM_SIZE = (110241024) - (4096 *2), binder分配的默認內存大小為1M-8k。
DEFAULT_MAX_BINDER_THREADS = 15,binder默認的最大可并發訪問的線程數為16
然后來看getContextObject方法,
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
return getStrongProxyForHandle(0); //【見小節3.2】
}
去獲取handle為0的IBinder
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
//查找handle對應的資源項【見小節3.3】
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL) {
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
if (handle == 0) {
Parcel data;
//通過ping操作測試binder是否準備就緒
status_t status = IPCThreadState::self()->transact(
0, IBinder::PING_TRANSACTION, data, NULL, 0);
if (status == DEAD_OBJECT)
return NULL;
}
//當handle值所對應的IBinder不存在或弱引用無效時,則創建BpBinder對象【見小節3.4】
b = new BpBinder(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}
我們看到先去獲得handle對應的資源項,然后如果拿不到它的binder的話,就去創建BpBinder,對handle為0的情況還需要去判斷binder是否已經準備就緒了,因為handle為0的情況,是要首次去打開binder,首次去初始化serviceManager。然后我們看一下new BpBinder方法是怎么實現的:
BpBinder::BpBinder(int32_t handle)
: mHandle(handle)
, mAlive(1)
, mObitsSent(0)
, mObituaries(NULL)
{
extendObjectLifetime(OBJECT_LIFETIME_WEAK); //延長對象的生命時間
IPCThreadState::self()->incWeakHandle(handle); //handle所對應的binder弱引用 + 1
}
然后interface_cast方法傳入的參數其實就是最后的最后,new出來的BpBinder對象。
而interface_cast方法最后主要就是去創建BpServiceManager
其實說的最通俗一點就是首次去獲取ServiceManger的時候系統會幫我們打開binder開關,位binder創建內存控件,并為我們新建BpBinder對象,然后將BpBinder包裹起來,生成新的BpServiceManager單例。
ServiceManager使如何啟動的
上面我們看到已經獲得到了ServiceManager了,那么我們來到main方法中去看啟動的時候做了什么
int main(int argc, char **argv)
{
struct binder_state *bs;
//打開binder驅動,申請128k大小的內存空間 【見流程1】
bs = binder_open(128*1024);
if (!bs) {
return -1;
}
//成為上下文管理者 【見流程2】
if (binder_become_context_manager(bs)) {
return -1;
}
selinux_enabled = is_selinux_enabled(); //判斷selinux權限問題
sehandle = selinux_android_service_context_handle();
selinux_status_open(true);
if (selinux_enabled > 0) {
if (sehandle == NULL) { //無法獲取sehandle
abort();
}
if (getcon(&service_manager_context) != 0) { //無法獲取service_manager上下文
abort();
}
}
union selinux_callback cb;
cb.func_audit = audit_callback;
selinux_set_callback(SELINUX_CB_AUDIT, cb);
cb.func_log = selinux_log_callback;
selinux_set_callback(SELINUX_CB_LOG, cb);
//進入無限循環,處理client端發來的請求 【見流程5】
binder_loop(bs, svcmgr_handler);
return 0;
}
具體的時序圖如下
先是打開binder驅動的相關操作,binder_open()
struct binder_state *binder_open(size_t mapsize)
{
struct binder_state *bs;
struct binder_version vers;
//請求了相應size的內存空間
bs = malloc(sizeof(*bs));
if (!bs) {
errno = ENOMEM;
return NULL;
}
//通過系統調用陷入內核,打開Binder設備驅動
bs->fd = open("/dev/binder", O_RDWR);
if (bs->fd < 0) {
goto fail_open; // 無法打開binder設備
}
//通過系統調用,ioctl獲取binder版本信息
if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
(vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
goto fail_open; //內核空間與用戶空間的binder不是同一版本
}
bs->mapsize = mapsize;
//通過系統調用,mmap內存映射
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
if (bs->mapped == MAP_FAILED) {
goto fail_map; // binder設備內存無法映射
}
return bs;
fail_map:
close(bs->fd);
fail_open:
free(bs);
return NULL;
}
分別是位binder請求內存空間,然后打開binder設備,再然后去獲取binder 的版本信息,并且與binder建立起內存映射聯系。
然后去成為上下文的管理者,然后通過binder_loop(),去不斷的循環讀寫。
小結
ServiceManager啟動流程:
打開binder驅動,并調用mmap()方法分配128k的內存映射空間:binder_open();
通知binder驅動使其成為守護進程:binder_become_context_manager();
驗證selinux權限,判斷進程是否有權注冊或查看指定服務;
進入循環狀態,等待Client端的請求:binder_loop()。
ServiceManger意義:
ServiceManger集中管理系統內的所有服務,通過權限控制進程是否有權注冊服務;
ServiceManager能通過字符串名稱來查找對應的Service,操作方便;
當Server進程異常退出,只需告知ServiceManager,每個Client通過查詢ServiceManager可獲取Server進程的情況,降低所有Client進程直接檢測會導致負載過重。
Binder的核心方法
我們來一一看一下binder有哪些核心的方法
1.首先是binder的init方法:
主要任務是負責注冊misc設備(理解為一種特殊的設備驅動),并且打開binder設備
2.binder的mmap方法:
主要負責在內存虛擬地址空間申請一塊和用戶虛擬地址一樣大小的內存,再申請一個page大小的物理內存,分別映射到內核虛擬空間和用戶虛擬空間。說白了就是實現了內核和用戶的同步操作,感覺就好像是通過了binder訪問了內核服務的樣子。
3.binder的ioctl方法:
主要負責在兩個進程之間收發IPC的數據和IPC reply的數據
4.binder的ioctl_write_read方法:
首先把用戶空間數據拷貝到內核空間bwr;
當bwr寫緩存中有數據,則執行binder寫操作;當寫失敗,再將bwr數據寫回用戶空間,并退出;
當bwr讀緩存中有數據,則執行binder讀操作;當讀失敗,再將bwr數據寫回用戶空間,并退出;
最后把內核數據bwr拷貝到用戶空間。
這個很直白,其實最后binder的進程通信很好的被詮釋,就是先將用戶空間數據拷貝到內核空間,然后進行讀寫,如果失敗則將緩存中的內容寫回到用戶空間,并且退出。如果成功則將內核中的數據拷貝到用戶空間。