-
打開binder設備:
service_manager.c 源碼中:if (argc > 1) { driver = argv[1]; } else { driver = "/dev/binder"; //打開binder設備文件,返回文件描述符 } bs = binder_open(driver, 128*1024); // binder 的 buffer緩衝區創建,用於進程間數據的傳輸
-
打開一個binder設備文件,並且開啓一個128k的內存映射。
binder.c 有內存映射mmap()
函數調用bs->fd = open(driver, O_RDWR | O_CLOEXEC); // 打開binder設備 // ... bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0); // 開啓內存映射
mmap 函數是在系統啓動的時候就開啓了binder映射,查看源碼System.map
-
ServiceManager啓動
init.rc中啓動ServiceManager服務
-
打包Parcel中,數據寫入binder設備,copy_from_user
- IServiceManager.cpp源碼中,搜索
addService
parcel對象,將Service相關的信息打包到parcel對象,並且通過virtual status_t addService(const String16& name, const sp<IBinder>& service, bool allowIsolated, int dumpsysPriority) { Parcel data, reply; //parcel對象,將Service相關的信息打包 data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); data.writeString16(name); data.writeStrongBinder(service); data.writeInt32(allowIsolated ? 1 : 0); data.writeInt32(dumpsysPriority); status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply); return err == NO_ERROR ? reply.readExceptionCode() : err; }
remote()->transact
方法傳輸到下一步,
- 如何將數據寫入binder設備,查看IIPCThreadState.cpp源碼,IPCThreadState.h
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
- IServiceManager.cpp源碼中,搜索
-
服務註冊,添加到鏈表svclist中
int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle, uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid) { struct svcinfo *si; //ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle, // allow_isolated ? "allow_isolated" : "!allow_isolated", uid); if (!handle || (len == 0) || (len > 127)) return -1; if (!svc_can_register(s, len, spid, uid)) {//檢查服務權限, ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n", str8(s, len), handle, uid); return -1; } si = find_svc(s, len);//檢查服務是否已經在svclist鏈表上註冊過 if (si) { if (si->handle) { ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n", str8(s, len), handle, uid); svcinfo_death(bs, si); } si->handle = handle; } else { si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t)); //沒有註冊過,分配服務管理結構svcinfo,並將其添加到鏈表的list當中。 if (!si) { ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n", str8(s, len), handle, uid); return -1; } si->handle = handle; si->len = len; memcpy(si->name, s, (len + 1) * sizeof(uint16_t)); si->name[len] = '\0'; si->death.func = (void*) svcinfo_death; si->death.ptr = si; si->allow_isolated = allow_isolated; si->dumpsys_priority = dumpsys_priority; si->next = svclist; //將代表該服務的結構添加到鏈表中 svclist = si; } binder_acquire(bs, handle); // 增加binder的應用 計數 binder_link_to_death(bs, handle, &si->death);//如果服務退出之後,就需要通知ServiceManager return 0; }
以上整個過程,就是Server如何向ServerManager添加服務的註冊過程。
-
定義主線程的線程池,不停地讀寫
查看IIPCThreadState.cpp源碼void IPCThreadState::joinThreadPool(bool isMain) { LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid()); mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER); 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) { ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting", mProcess->mDriverFD, result); abort(); } // 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); LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%d\n", (void*)pthread_self(), getpid(), result); mOut.writeInt32(BC_EXIT_LOOPER); talkWithDriver(false); }
-
循環從
mIn mOut
中取出讀寫請求,發送的binder的設備中pthread_setspecific(gTLS, this); //將對象設置爲當前線程的私有 clearCaller(); mIn.setDataCapacity(256); //輸入分配256字節的空間 mOut.setDataCapacity(256);//輸出分配256字節的空間
輸入/出 預分配256字節的空間,主要工作循環從
mIn mOut
中進行IO的讀寫工作,然後發送的binder的設備中來。繼續往下,是如何檢查是否有數據要讀?
binder_write_read bwr; // 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; // //檢查是否有寫數據的請求 // 省略代碼.... if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0) //將讀寫的請求 發送到binder中來 err = NO_ERROR; else err = -errno;
平時項目中,碰到的第三方登錄,分享。實際就是跨進行。