Android Binder 之 ServiceManager (基于android 12.0/S)
Binder 原理整理:
因为Linux中的进程的用户空间是不共享的,内核空间是共享的,所以IPC通信是两个用户空间(APP 进程)通过共享的内核空间(Binder驱动)进行数据交互。
Binder 整体框架:
Binder 通信框架:
ServiceManager :
ServiceManager 可执行文件的生成:
ServiceManager 在android系统中是一个可执行文件,位于/system/bin/servicemanager下面
Servicemanager 是在init.rc中启动的
在android 10.0.0.R47 及以前 servicemanager是由以下目录结构编译生成的,
在android 10.0.0.R47 及以前 控制编译的相关bp文件:
在android 11.0.0_r21后面原先的service_manager.c变成了ServiceManager.cpp,binder.c变成了main.cpp,同时添加了Access.cpp和Access.h,bctest 变成了 test_sm。
Android 11.0.0_r21 以后的bp如图,先是将ServiceManager.cpp和Access.cpp一起生成了servicemanager_defaults,然后通过servicemanager_defaults编译生成可运行的servicemanager。
再简单看下目前android 12中的代码目录结构和 android 13的代码结构:
Android T(13.0)中添加了servicemanager.microdroid.rc 和servicemanager.recovery.rc 两个rc文件。
ServiceManager的代码分析:
总入口:
Android S 中将android 10.0.0.R47 及以前 在service_manager.c中的 main 方法提取到了main.cpp中。main.cpp中除了main 方法外还额外有ClientCallbackCallback和BinderCallback两个callback.
int main(int argc, char** argv) { if (argc > 2) {LOG(FATAL) << "usage: " << argv[0] << " [binder driver]";}const char* driver = argc == 2 ? argv[1] : "/dev/binder";//第二个参数可以缺省sp<ProcessState> ps = ProcessState::initWithDriver(driver);//打开binder驱动ps->setThreadPoolMaxThreadCount(0);ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);// 实例化ServiceManagersp<ServiceManager> manager = sp<ServiceManager>::make(std::make_unique<Access>());// 将自身注册到ServiceManager当中if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {LOG(ERROR) << "Could not self register servicemanager";}// 将ServiceManager设置给IPCThreadState的全局变量IPCThreadState::self()->setTheContextObject(manager);ps->becomeContextManager();//注册成为binder服务的大管家// 准备Loopersp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);//给Looper设置callback BinderCallback::setupTo(looper);ClientCallbackCallback::setupTo(looper, manager);//进入无限循环,处理client端发来的请求while(true) {looper->pollAll(-1);}// should not be reachedreturn EXIT_FAILURE;
}
下图为android 10.0.0.R47 及以前 在service_manager.c中的 main 方法(因为页面截图空间限制没有截全 可以自行查看 http://aospxref.com/android-10.0.0_r47/xref/frameworks/native/cmds/servicemanager/service_manager.c#382),相关代码讲解可以参考http://gityuan.com/2015/11/07/binder-start-sm/
其中main方法中主要干了四件事:
1)初始化binder驱动
2)将自身以“manager” 注册到servicemanager中
3)注册成为binder服务的大管家
4) 给Looper设置callback,进入无限循环,处理client端发来的请求
这里面着重讲后三个代码块
1)第一个代码块中,android 10.0.0.R47 之前是通过binder_open 直接操作binder驱动,没有借助libbinder,Android 11.0.0_r21 以后是通过initWithDriver 对于binder进行操作的,在编译servicemanager的时候,添加了libbinder的库依赖进去。
2)第二个代码块,将自身以“manager” 注册到servicemanager中:
Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) { auto ctx = mAccess->getCallingContext();//获取到调用的Context// apps cannot add services (AID_APP =10000)if (multiuser_get_app_id(ctx.uid) >= AID_APP) {return Status::fromExceptionCode(Status::EX_SECURITY);}if (!mAccess->canAdd(ctx, name)) {return Status::fromExceptionCode(Status::EX_SECURITY);}if (binder == nullptr) {return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);}if (!isValidServiceName(name)) {LOG(ERROR) << "Invalid service name: " << name;return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);}#ifndef VENDORSERVICEMANAGERif (!meetsDeclarationRequirements(binder, name)) {// already loggedreturn Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);}
#endif // !VENDORSERVICEMANAGER// implicitly unlinked when the binder is removed if (binder->remoteBinder() != nullptr &&binder->linkToDeath(sp<ServiceManager>::fromExisting(this)) != OK) {LOG(ERROR) << "Could not linkToDeath when adding " << name;return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);}//以上代码多是异常情况处理 // Overwrite the old service if it exists//将service的相关信息写入到 servicemanager的 map中mNameToService[name] = Service {.binder = binder,.allowIsolated = allowIsolated,.dumpPriority = dumpPriority,.debugPid = ctx.debugPid,};auto it = mNameToRegistrationCallback.find(name);if (it != mNameToRegistrationCallback.end()) {for (const sp<IServiceCallback>& cb : it->second) {mNameToService[name].guaranteeClient = true;// permission checked in registerForNotificationscb->onRegistration(name, binder);}}return Status::ok();
}
上面的addService 涉及到 Binder的报错类型枚举类:
servicemanager中维护注册服务的map:
分解看service类和ServiceMap:
这里可以看到servicemanager是用map维护注册的服务的,android 10.0.0.R47 及以前是通过链表进行维护的。这里面猜测数据结构的变化是随着手机代码的内存增大和性能指标的增强,链表省空间但是查询较慢的特性已经不能满足需求,于是改用了查询更快的 map进行存储。下图是 android 10.0.0.R47 的注册方法:
3)第三个代码块,servicemanager 成为binder服务的大管家。此处通过ioctl往binder驱动发了#define BINDER_SET_CONTEXT_MGR_EXT _IOW('b', 13, struct flat_binder_object) 的命令,如果不好用则按照android 10.0.0.R47的方式发 #define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32)。后续流程的拆解欢迎大家帮忙补充下。
4)第四个代码块,给Looper设置callback,进入无限循环,处理client端发来的请求
给Looper 设置了BinderCallback 和 ClientCallbackCallback,两个callback 都是Loopercallback的子类。
class BinderCallback : public LooperCallback {
public:static sp<BinderCallback> setupTo(const sp<Looper>& looper) { // 实例化BinderCallback sp<BinderCallback> cb = sp<BinderCallback>::make();int binder_fd = -1;//通过IPCThreadState获取binder_fd,这里面的IPCThreadState待补充IPCThreadState::self()->setupPolling(&binder_fd);LOG_ALWAYS_FATAL_IF(binder_fd < 0, "Failed to setupPolling: %d", binder_fd);//添加监听目标int ret = looper->addFd(binder_fd,Looper::POLL_CALLBACK,Looper::EVENT_INPUT,cb,nullptr /*data*/);LOG_ALWAYS_FATAL_IF(ret != 1, "Failed to add binder FD to Looper");return cb;}int handleEvent(int /* fd */, int /* events */, void* /* data */) override { //处理回调IPCThreadState::self()->handlePolledCommands();return 1; // Continue receiving callbacks.}
};
Looper会监听ServiceManager 进程中打开的binder_fd,有消息上来了会调用handlePolledCommands处理。
核心是getAndExecuteCommand方法:
status_t IPCThreadState::getAndExecuteCommand(){status_t result;int32_t cmd;//从binder driver获取mIn数据result = talkWithDriver();if (result >= NO_ERROR) {size_t IN = mIn.dataAvail();if (IN < sizeof(int32_t)) return result;cmd = mIn.readInt32();IF_LOG_COMMANDS() {alog << "Processing top-level Command: "<< getReturnString(cmd) << endl;}pthread_mutex_lock(&mProcess->mThreadCountLock);mProcess->mExecutingThreadsCount++;if (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads &&mProcess->mStarvationStartTimeMs == 0) {mProcess->mStarvationStartTimeMs = uptimeMillis();}pthread_mutex_unlock(&mProcess->mThreadCountLock);// 解析出对应的cmd,执行cmdresult = executeCommand(cmd);pthread_mutex_lock(&mProcess->mThreadCountLock);mProcess->mExecutingThreadsCount--;if (mProcess->mExecutingThreadsCount < mProcess->mMaxThreads &&mProcess->mStarvationStartTimeMs != 0) {int64_t starvationTimeMs = uptimeMillis() - mProcess->mStarvationStartTimeMs;if (starvationTimeMs > 100) {ALOGE("binder thread pool (%zu threads) starved for %" PRId64 " ms",mProcess->mMaxThreads, starvationTimeMs);}mProcess->mStarvationStartTimeMs = 0;}// Cond broadcast can be expensive, so don't send it every time a binder// call is processed. b/168806193if (mProcess->mWaitingForThreads > 0) {pthread_cond_broadcast(&mProcess->mThreadCountDecrement);}pthread_mutex_unlock(&mProcess->mThreadCountLock);}return result;
}
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:result = mIn.readInt32();break;case BR_OK:break;case BR_ACQUIRE:refs = (RefBase::weakref_type*)mIn.readPointer();obj = (BBinder*)mIn.readPointer();ALOG_ASSERT(refs->refBase() == obj,"BR_ACQUIRE: object %p does not match cookie %p (expected %p)",refs, obj, refs->refBase());obj->incStrong(mProcess.get());IF_LOG_REMOTEREFS() {LOG_REMOTEREFS("BR_ACQUIRE from driver on %p", obj);obj->printRefs();}mOut.writeInt32(BC_ACQUIRE_DONE);mOut.writePointer((uintptr_t)refs);mOut.writePointer((uintptr_t)obj);break;case BR_RELEASE:refs = (RefBase::weakref_type*)mIn.readPointer();obj = (BBinder*)mIn.readPointer();ALOG_ASSERT(refs->refBase() == obj,"BR_RELEASE: object %p does not match cookie %p (expected %p)",refs, obj, refs->refBase());IF_LOG_REMOTEREFS() {LOG_REMOTEREFS("BR_RELEASE from driver on %p", obj);obj->printRefs();}mPendingStrongDerefs.push(obj);break;case BR_INCREFS:refs = (RefBase::weakref_type*)mIn.readPointer();obj = (BBinder*)mIn.readPointer();refs->incWeak(mProcess.get());mOut.writeInt32(BC_INCREFS_DONE);mOut.writePointer((uintptr_t)refs);mOut.writePointer((uintptr_t)obj);break;case BR_DECREFS:refs = (RefBase::weakref_type*)mIn.readPointer();obj = (BBinder*)mIn.readPointer();// NOTE: This assertion is not valid, because the object may no// longer exist (thus the (BBinder*)cast above resulting in a different// memory address).//ALOG_ASSERT(refs->refBase() == obj,// "BR_DECREFS: object %p does not match cookie %p (expected %p)",// refs, obj, refs->refBase());mPendingWeakDerefs.push(refs);break;case BR_ATTEMPT_ACQUIRE:refs = (RefBase::weakref_type*)mIn.readPointer();obj = (BBinder*)mIn.readPointer();{const bool success = refs->attemptIncStrong(mProcess.get());ALOG_ASSERT(success && refs->refBase() == obj,"BR_ATTEMPT_ACQUIRE: object %p does not match cookie %p (expected %p)",refs, obj, refs->refBase());mOut.writeInt32(BC_ACQUIRE_RESULT);mOut.writeInt32((int32_t)success);}break;case BR_TRANSACTION_SEC_CTX:case BR_TRANSACTION:{//读取mIn中的数据到一个binder_transaction_data中binder_transaction_data_secctx tr_secctx;binder_transaction_data& tr = tr_secctx.transaction_data;if (cmd == (int) BR_TRANSACTION_SEC_CTX) {result = mIn.read(&tr_secctx, sizeof(tr_secctx));} else {result = mIn.read(&tr, sizeof(tr));tr_secctx.secctx = 0;}ALOG_ASSERT(result == NO_ERROR,"Not enough command data for brTRANSACTION");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);const void* origServingStackPointer = mServingStackPointer;mServingStackPointer = &origServingStackPointer; // anything on the stackconst pid_t origPid = mCallingPid;const char* origSid = mCallingSid;const uid_t origUid = mCallingUid;const int32_t origStrictModePolicy = mStrictModePolicy;const int32_t origTransactionBinderFlags = mLastTransactionBinderFlags;const int32_t origWorkSource = mWorkSource;const bool origPropagateWorkSet = mPropagateWorkSource;// Calling work source will be set by Parcel#enforceInterface. Parcel#enforceInterface// is only guaranteed to be called for AIDL-generated stubs so we reset the work source// here to never propagate it.clearCallingWorkSource();clearPropagateWorkSource();mCallingPid = tr.sender_pid;mCallingSid = reinterpret_cast<const char*>(tr_secctx.secctx);mCallingUid = tr.sender_euid;mLastTransactionBinderFlags = tr.flags;// ALOGI(">>>> TRANSACT from pid %d sid %s uid %d\n", mCallingPid,// (mCallingSid ? mCallingSid : "<N/A>"), mCallingUid);Parcel reply;status_t error;IF_LOG_TRANSACTIONS() {TextOutput::Bundle _b(alog);alog << "BR_TRANSACTION thr " << (void*)pthread_self()<< " / obj " << tr.target.ptr << " / code "<< TypeCode(tr.code) << ": " << indent << buffer<< dedent << endl<< "Data addr = "<< reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer)<< ", offsets addr="<< reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl;}if (tr.target.ptr) {// We only have a weak reference on the target object, so we must first try to// safely acquire a strong reference before doing anything else with it.if (reinterpret_cast<RefBase::weakref_type*>(tr.target.ptr)->attemptIncStrong(this)) {error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,&reply, tr.flags);reinterpret_cast<BBinder*>(tr.cookie)->decStrong(this);} else {error = UNKNOWN_TRANSACTION;}} else {//调用BBinder的transact方法error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);}//打开该处log可以用来调试//ALOGI("<<<< TRANSACT from pid %d restore pid %d sid %s uid %d\n",// mCallingPid, origPid, (origSid ? origSid : "<N/A>"), origUid);if ((tr.flags & TF_ONE_WAY) == 0) {LOG_ONEWAY("Sending reply to %d!", mCallingPid);if (error < NO_ERROR) reply.setError(error);constexpr uint32_t kForwardReplyFlags = TF_CLEAR_BUF;//将返回的结果重新发给bindersendReply(reply, (tr.flags & kForwardReplyFlags));} else {if (error != OK) {alog << "oneway function results for code " << tr.code<< " on binder at "<< reinterpret_cast<void*>(tr.target.ptr)<< " will be dropped but finished with status "<< statusToString(error);// ideally we could log this even when error == OK, but it// causes too much logspam because some manually-written// interfaces have clients that call methods which always// write results, sometimes as oneway methods.if (reply.dataSize() != 0) {alog << " and reply parcel size " << reply.dataSize();}alog << endl;}LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);}mServingStackPointer = origServingStackPointer;mCallingPid = origPid;mCallingSid = origSid;mCallingUid = origUid;mStrictModePolicy = origStrictModePolicy;mLastTransactionBinderFlags = origTransactionBinderFlags;mWorkSource = origWorkSource;mPropagateWorkSource = origPropagateWorkSet;IF_LOG_TRANSACTIONS() {TextOutput::Bundle _b(alog);alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "<< tr.target.ptr << ": " << indent << reply << dedent << endl;}}break;case BR_DEAD_BINDER:{BpBinder *proxy = (BpBinder*)mIn.readPointer();proxy->sendObituary();mOut.writeInt32(BC_DEAD_BINDER_DONE);mOut.writePointer((uintptr_t)proxy);} break;case BR_CLEAR_DEATH_NOTIFICATION_DONE:{BpBinder *proxy = (BpBinder*)mIn.readPointer();proxy->getWeakRefs()->decWeak(proxy);} break;case BR_FINISHED:result = TIMED_OUT;break;case BR_NOOP:break;case BR_SPAWN_LOOPER:mProcess->spawnPooledThread(false);break;default:ALOGE("*** BAD COMMAND %d received from Binder driver\n", cmd);result = UNKNOWN_ERROR;break;}if (result != NO_ERROR) {mLastError = result;}return result;
}
ClientCallbackCallback:
// LooperCallback for IClientCallbackclass ClientCallbackCallback : public LooperCallback {
public:static sp<ClientCallbackCallback> setupTo(const sp<Looper>& looper, const sp<ServiceManager>& manager) { sp<ClientCallbackCallback> cb = sp<ClientCallbackCallback>::make(manager);//创建一个定时器描述符timerfdint fdTimer = timerfd_create(CLOCK_MONOTONIC, 0 /*flags*/);LOG_ALWAYS_FATAL_IF(fdTimer < 0, "Failed to timerfd_create: fd: %d err: %d", fdTimer, errno);itimerspec timespec {.it_interval = {.tv_sec = 5,.tv_nsec = 0,},.it_value = {.tv_sec = 5,.tv_nsec = 0,},};//启动所有的定时器int timeRes = timerfd_settime(fdTimer, 0 /*flags*/, ×pec, nullptr);LOG_ALWAYS_FATAL_IF(timeRes < 0, "Failed to timerfd_settime: res: %d err: %d", timeRes, errno);//以时间为描述符注册到Looper中int addRes = looper->addFd(fdTimer,Looper::POLL_CALLBACK,Looper::EVENT_INPUT,cb,nullptr);LOG_ALWAYS_FATAL_IF(addRes != 1, "Failed to add client callback FD to Looper");return cb;}int handleEvent(int fd, int /*events*/, void* /*data*/) override { uint64_t expirations;int ret = read(fd, &expirations, sizeof(expirations));if (ret != sizeof(expirations)) {ALOGE("Read failed to callback FD: ret: %d err: %d", ret, errno);}mManager->handleClientCallbacks();return 1; // Continue receiving callbacks.}
private:friend sp<ClientCallbackCallback>;ClientCallbackCallback(const sp<ServiceManager>& manager) : mManager(manager) {}sp<ServiceManager> mManager;
};
当looper接收到消息时候,调用servicemanager的 handleClientCallbacks进行处理。
主要调用handleServiceClientCallback进行处理:
ssize_t ServiceManager::handleServiceClientCallback(const std::string& serviceName, bool isCalledOnInterval) {auto serviceIt = mNameToService.find(serviceName);if (serviceIt == mNameToService.end() || mNameToClientCallback.count(serviceName) < 1) {return -1;}Service& service = serviceIt->second;ssize_t count = service.getNodeStrongRefCount();// binder driver doesn't support this featureif (count == -1) return count;bool hasClients = count > 1; // this process holds a strong countif (service.guaranteeClient) {// we have no record of this clientif (!service.hasClients && !hasClients) {sendClientCallbackNotifications(serviceName, true);}// guarantee is temporaryservice.guaranteeClient = false;}// only send notifications if this was called via the interval checking workflowif (isCalledOnInterval) {if (hasClients && !service.hasClients) {// client was retrieved in some other waysendClientCallbackNotifications(serviceName, true);}// there are no more clients, but the callback has not been called yetif (!hasClients && service.hasClients) {sendClientCallbackNotifications(serviceName, false);}}return count;
}
最后通过Looper.pollAll进入无限循环,如果Looper收到消息则触发callback。
servicemanager的主要功能:
1)注册服务
其中注册服务主要是通过addService 方法实现的,在讲解总入口第二个代码块的时候已经做过拆解,不再赘余。
2)查询服务
sp<IBinder> ServiceManager::tryGetService(const std::string& name, bool startIfNotFound) { auto ctx = mAccess->getCallingContext();sp<IBinder> out;Service* service = nullptr;if (auto it = mNameToService.find(name); it != mNameToService.end()) {service = &(it->second);if (!service->allowIsolated) {uid_t appid = multiuser_get_app_id(ctx.uid);bool isIsolated = appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END;if (isIsolated) {return nullptr;}}//将map中的信息赋值out = service->binder;}if (!mAccess->canFind(ctx, name)) {return nullptr;}//如果找不到对应的service,则尝试以AIDL的方式启动该serviceif (!out && startIfNotFound) {tryStartService(name);}if (out) {// Setting this guarantee each time we hand out a binder ensures that the client-checking// loop knows about the event even if the client immediately drops the serviceservice->guaranteeClient = true;}return out;
}
3)获取servicemanager
不论是注册服务或者查询服务,都需要先获得servicemanager的实例,servicemanager是通过defaultServiceManager 获取的,
[[clang::no_destroy]] static std::once_flag gSmOnce;
sp<IServiceManager> defaultServiceManager(){std::call_once(gSmOnce, []() {//AidlServiceManager 就是IServiceManagersp<AidlServiceManager> sm = nullptr;while (sm == nullptr) {sm = interface_cast<AidlServiceManager>(ProcessState::self()->getContextObject(nullptr));if (sm == nullptr) {ALOGE("Waiting 1s on context object on %s.", ProcessState::self()->getDriverName().c_str());sleep(1);}}gDefaultServiceManager = sp<ServiceManagerShim>::make(sm);});return gDefaultServiceManager;
}
这里面的gSmOnce和call_once 从名字看是只调用一次的意思,这里先不求甚解。类比android 10.0之前是使用的单例模式,此处的功能应该是类似的。
如图,AidlServiceManager 就是IServiceManager。
这里与一般的单例模式不太一样,里面多了一层while循环,这是google在2013年1月Todd Poynor提交的修改。当尝试创建或获取ServiceManager时,ServiceManager可能尚未准备就绪,这时通过sleep 1秒后,循环尝试获取直到成功。gDefaultServiceManager的创建过程,可分解为以下3个步骤:
ProcessState::self()
:用于获取ProcessState对象(也是单例模式),每个进程有且只有一个ProcessState对象,存在则直接返回,不存在则创建;
getContextObject()
: 用于获取BpBinder对象,对于handle=0的BpBinder对象,存在则直接返回,不存在才创建;
interface_cast<
AidlServiceManager
>()
:用于获取BpServiceManager对象;
分开讲三个流程:
1)ProcessState::self()
获取ProcessState对象
sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault){[[clang::no_destroy]] static sp<ProcessState> gProcess;[[clang::no_destroy]] static std::mutex gProcessMutex;if (driver == nullptr) {std::lock_guard<std::mutex> l(gProcessMutex);return gProcess;}[[clang::no_destroy]] static std::once_flag gProcessOnce;std::call_once(gProcessOnce, [&](){if (access(driver, R_OK) == -1) {ALOGE("Binder driver %s is unavailable. Using /dev/binder instead.", driver);driver = "/dev/binder";}std::lock_guard<std::mutex> l(gProcessMutex);//ProcessState调用构造方法进行初始化gProcess = sp<ProcessState>::make(driver);});if (requireDefault) {// Detect if we are trying to initialize with a different driver, and// consider that an error. ProcessState will only be initialized once above.LOG_ALWAYS_FATAL_IF(gProcess->getDriverName() != driver,"ProcessState was already initialized with %s,"" can't initialize with %s.",gProcess->getDriverName().c_str(), driver);}return gProcess;
}
ProcessState::ProcessState(const char *driver) : mDriverName(String8(driver)), mDriverFD(open_driver(driver))//打开Binder驱动, mVMStart(MAP_FAILED), mThreadCountLock(PTHREAD_MUTEX_INITIALIZER), mThreadCountDecrement(PTHREAD_COND_INITIALIZER), mExecutingThreadsCount(0), mWaitingForThreads(0), mMaxThreads(DEFAULT_MAX_BINDER_THREADS), mStarvationStartTimeMs(0), mThreadPoolStarted(false), mThreadPoolSeq(1), mCallRestriction(CallRestriction::NONE)
{if (mDriverFD >= 0) {// mmap the binder, providing a chunk of virtual address space to receive transactions. //mmap binder驱动,提供一个虚拟内存空间地址用于收到事务//#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);if (mVMStart == MAP_FAILED) {// *sigh*ALOGE("Using %s failed: unable to mmap transaction memory.\n", mDriverName.c_str());close(mDriverFD);mDriverFD = -1;mDriverName.clear();}}#ifdef __ANDROID__LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver '%s' could not be opened. Terminating.", driver);
#endif
}
打开binder驱动代码块:
static int open_driver(const char *driver){// 打开/dev/binder设备,建立与内核的Binder驱动的交互通道int fd = open(driver, O_RDWR | O_CLOEXEC);if (fd >= 0) {int vers = 0;status_t result = ioctl(fd, BINDER_VERSION, &vers);if (result == -1) {ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));close(fd);fd = -1;}if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {ALOGE("Binder driver protocol(%d) does not match user space protocol(%d)! ioctl() return value: %d",vers, BINDER_CURRENT_PROTOCOL_VERSION, result);close(fd);fd = -1;}size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;// 通过ioctl设置binder驱动,能支持的最大线程数//#define DEFAULT_MAX_BINDER_THREADS 15 默认是15个线程result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);if (result == -1) {ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));}uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);if (result == -1) {ALOGD("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));}} else {ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));}return fd;
}
2)getContextObject()
: 获取BpBinder对象
获取handle=0的IBinder
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle){sp<IBinder> result;AutoMutex _l(mLock);//查找handle对应的资源项handle_entry* e = lookupHandleLocked(handle);if (e != nullptr) {// We need to create a new BpBinder if there isn't currently one, OR we// are unable to acquire a weak reference on this current one. The// attemptIncWeak() is safe because we know the BpBinder destructor will always// call expungeHandle(), which acquires the same lock we are holding now.// We need to do this because there is a race condition between someone// releasing a reference on this BpBinder, and a new reference on its handle// arriving from the driver.IBinder* b = e->binder;if (b == nullptr || !e->refs->attemptIncWeak(this)) {if (handle == 0) {// Special case for context manager...// The context manager is the only object for which we create// a BpBinder proxy without already holding a reference.// Perform a dummy transaction to ensure the context manager// is registered before we create the first local reference// to it (which will occur when creating the BpBinder).// If a local reference is created for the BpBinder when the// context manager is not present, the driver will fail to// provide a reference to the context manager, but the// driver API does not return status. Note that this is not race-free if the context manager// dies while this code runs. TODO: add a driver API to wait for context manager, or// stop special casing handle 0 for context manager and add// a driver API to get a handle to the context manager with// proper reference counting.IPCThreadState* ipc = IPCThreadState::self();CallRestriction originalCallRestriction = ipc->getCallRestriction();ipc->setCallRestriction(CallRestriction::NONE);Parcel data;status_t status = ipc->transact(0, IBinder::PING_TRANSACTION, data, nullptr, 0);//通过ping操作测试binder是否准备就绪ipc->setCallRestriction(originalCallRestriction);if (status == DEAD_OBJECT)return nullptr;}//当handle值所对应的IBinder不存在或弱引用无效时,则创建BpBinder对象sp<BpBinder> b = BpBinder::create(handle);e->binder = b.get();if (b) e->refs = b->getWeakRefs();result = b;} else {// This little bit of nastyness is to allow us to add a primary// reference to the remote proxy when this team doesn't have one// but another team is sending the handle to us.result.force_set(b);e->refs->decWeak(this);}}return result;
}
如果handle 为0的Ibinder存在且通过Ping 测试已经准备好了,则返回该Ibinder,当handle值所对应的IBinder不存在或弱引用无效时,则创建BpBinder对象。
ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle){const size_t N=mHandleToObject.size();//当handle大于mHandleToObject的长度时,进入该分支if (N <= (size_t)handle) {handle_entry e;e.binder = nullptr;e.refs = nullptr;//从mHandleToObject的第N个位置开始,插入(handle+1-N)个e到队列中status_t err = mHandleToObject.insertAt(e, N, handle+1-N);if (err < NO_ERROR) return nullptr;}return &mHandleToObject.editItemAt(handle);
}
(下面模板函数部分文案出自GitYuan,非原创)根据handle值来查找对应的handle_entry
,handle_entry
是一个结构体,里面记录IBinder和weakref_type两个指针。当handle大于mHandleToObject的Vector长度时,则向该Vector中添加(handle+1-N)个handle_entry结构体,然后再返回handle向对应位置的handle_entry结构体指针。
当handle值所对应的IBinder不存在或弱引用无效时,创建BpBinder并延长对象的生命时间,创建BpBinder对象中会将handle相对应Binder的弱引用增加1:
3)interface_cast<
AidlServiceManager
>()
:获取BpServiceManager对象
AidlServiceManager就是IServiceManager,所以主要拆解 interface_cast:
(interface_cast<IServiceManager>() 等价于 IServiceManager::asInterface(),asInterface是通过模板函数来定义的,
主要由以下两个部分构成:
① DECLARE_META_INTERFACE(IServiceManager)
② IMPLEMENT_META_INTERFACE(IServiceManager,"android.os.IServiceManager")
对于IServiceManager来说只需要换INTERFACE=IServiceManager即可,
DECLARE_META_INTERFACE 过程主要是声明asInterface()
,getInterfaceDescriptor()
方法。
IMPLEMENT_META_INTERFACE 过程:
对于IServiceManager来说 INTERFACE=IServiceManager, NAME=”android.os.IServiceManager”,可以看到DECLARE_META_INTERFACE 中的IServiceManager::asInterface() 等价于 BpIServiceManager()::make(obj)。在这里,更确切地说应该是BpIServiceManager::make(BpBinder)。
BpIServiceManager/BpServiceManager 的构造暂时未找到,能力有限,模板函数并不是很熟悉,此处文大家可以参考GitYuan的博客http://gityuan.com/2015/11/08/binder-get-sm/ 先看下android 11.0之前的讲解。后续会补上android 12部分的拆解
总结来看,defaultServiceManager 几近 等于BpIServiceManager::make(BpBinder),这样就获得到了serviceManager的proxy,类似systemServer 中调用PackageManagerService的方法要拿到PackageManager 一样,后续就可以调用serviceManager中的addService和getService方法了。
从网上找到的 Android 11 之前的 启动流程图,可以先借助理解下,后面会更新最新的图示:
权限控制模块:
Access 主要是通过Selinux来进行权限控制的
1)注册服务的时候的校验:
由于manager在service_contexts中注册了,所以这块Selinux可以顺利通过。
2)在查询服务的时候通过canFind对于权限进行校验。
最后和 addService一样也会通过actionAllowedFromLookup 进行校验。
对外接口:
在android 11之前对外接口只有四个:
在android 12中扩充为14个: (这里将binderDied和handleClientCallbacks计算在内了)
相关面试题:
servicemanager映射的虚拟内存有多大?现在的答案是和普通应用一样大:1M-2页。
frameworks/native/libs/binder/ProcessState.cpp
#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
参考资料:
Android 12 系统源码分析 | Native Binder 代码变迁 - 秋城 - 博客园
Android 12(S) Binder(一) - 青山渺渺 - 博客园
www.jb51.net
Binder系列-开篇 - Gityuan博客 | 袁辉辉的技术博客
Binder系列3-启动ServiceManager - Gityuan博客 | 袁辉辉的技术博客
Android Binder 之 ServiceManager (基于android 12.0/S)相关推荐
- android sse 人脸识别,基于Android Camera2之openCamera 流程
简介 frameworks\base\core\java\android\hardware\camera2 Camera2在Android 5.0上首次出现,主要重新定义了一套Camera 的使用接口 ...
- Android开发介绍(基于Android Studio软件)
Android开发介绍(基于Android Studio软件) 关于Android开发,笔者走过一些弯路,因此今天总计了有关Android开发的一些内容和心得,希望对大家有所帮助.首先来一张安卓开发者 ...
- Android开发自学笔记(基于Android Studio1.3.1)—1.环境搭建(转)
一.引言 本套学习笔记的开发环境是Windows 10 专业版和Android Studio 的最新版1.3.1. Android Studio 是一个Android开发环境,基于Intelli ...
- Android开发自学笔记(基于Android Studio1.3.1)—1.环境搭建
一.引言 本套学习笔记的开发环境是Windows 10 专业版和Android Studio 的最新版1.3.1. Android Studio 是一个Android开发环境,基于IntelliJ I ...
- 三星android应用程序更新,基于Android 11:三星OneUI 3.0详细升级计划公布
基于Android 11:三星OneUI 3.0详细升级计划公布 2020-12-02 22:06:14 14点赞 18收藏 47评论 本周,三星方面公布了基于Android 11的OneUI 3.0 ...
- 三星android的one ui,基于Android 11!三星OneUI 3.0详细升级计划公布
本周,三星方面公布了基于Android 11的OneUI 3.0具体升级安排,其最早出现了埃及地区手机用户的三星会员APP中. 2020年12月: Galaxy S20 Ultra.Galaxy S2 ...
- 魅族android os是什么,基于安卓5.0:新版魅族Flyme OS初体验
上月底开始,魅族开启了Flyme Powered by Android 5.0版本的测试工作,首先适配的是MX4 Pro,经过几个版本的极小范围内测之后,近日终于进入A轮内测阶段.我们有幸拿到了系统包 ...
- nubia ui 5.0 android,国内首家 基于安卓5.0开发nubia UI公测
[PConline 资讯]3月9日最新消息,受安卓5.0的吸引和Moto在国内使用Android 5.0原生系统的影响,国内手机厂商也纷纷推出基于Android 5.0的系统升级,其中nubia手机的 ...
- 基于Android的备忘录软件,基于Android的手机备忘录软件设计
<基于Android的手机备忘录软件设计>由会员分享,可在线阅读,更多相关<基于Android的手机备忘录软件设计(25页珍藏版)>请在皮匠网上搜索. 1.课程设计报告(本科) ...
最新文章
- 构建自主操作系统,阿里为何失败了?
- 【学术相关】现阶段硕士的困境:读博没信心,不读还闹心
- BGP重分布进IGP-EIGRP
- VC++动态链接库(DLL)编程深入浅出(zz)
- 数据可视化,带给你的惊艳并不止这一点!
- Android官方开发文档Training系列课程中文版:高效显示位图之加载大位图
- 剖析 Apache 顶级项目 SkyWalking 的源码 ,看看它有什么好?
- (转)VC 字节对齐
- 游戏开发设计模式(一):单例模式
- 2020年中国天线行业发展现状及细分市场结构分析[图]
- 关于在Onenote online导出笔记的笔记
- Vue实现excel文件下载
- 通讯录总结-JAVA GUI- “婉君被通讯录吓晕”-第一版
- aardio - 利用bitLock快速读写图片颜色值
- vchart 坐标轴标题_ECharts xAxis配置 x坐标轴名称的文本样式
- JS XML在线格式化、压缩、校验、XML转JSON工具-toolfk程序员工具网
- Web前端基础笔记:第十章 CSS-背景
- anaconda利用pip安装module
- css超链接中的下划线设置
- c语言中 float delta,比较float和double值与delta吗?
热门文章
- iPad上用code-server运行VS Code
- 简单梳理下git的使用感受,思考git中最重要的是什么
- Can‘t read file : End of file found 文件:txn_current、current svn无法正常读取文件
- 硬件基础:嵌入式软件可靠性设计要注意的问题
- 伯禹公益AI《动手学深度学习PyTorch版》Task 03 学习笔记
- 指纹登录 TouchID FaceID
- 很棒的图片浏览器代码,源码研究
- yum 源没有php7.0,yum安装最新版php7的操作方法
- 《嵌入式 – GD32开发实战指南》第3章 GPIO流水灯的前世今生
- 【C语言】输出由各种符号打印出的三角形