前面一节学习了ServiceManager这个特殊service的工作过程,这一节来看看普通service的工作过程。

就用media.extractor这个service来当例子!

1、服务的注册及启动

media.extractor这个service的注册及启动在 frameworks/av/services/mediaextractor/main_extractorservice.cpp

int main(int argc __unused, char** argv)
{ #if __has_feature(hwaddress_sanitizer)
ALOGI("disable media.extractor memory limits (hwasan enabled)");
#else
ALOGI("enable media.extractor memory limits");
limitProcessMemory(
"ro.media.maxmem", /* property that defines limit */
SIZE_MAX, /* upper limit in bytes */
20 /* upper limit as percentage of physical RAM */);
#endif signal(SIGPIPE, SIG_IGN); //b/62255959: this forces libutis.so to dlopen vendor version of libutils.so
//before minijail is on. This is dirty but required since some syscalls such
//as pread64 are used by linker but aren't allowed in the minijail. By
//calling the function before entering minijail, we can force dlopen.
android::report_sysprop_change(); SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath); strcpy(argv[0], "media.extractor");
// 1、打开binder driver
sp<ProcessState> proc(ProcessState::self());
// 2、获取ServiceManager
sp<IServiceManager> sm = defaultServiceManager();
// 3、实例化MediaExtractorService,并注册到ServiceManager当中
MediaExtractorService::instantiate();
// 4、
ProcessState::self()->startThreadPool();
// 5、
IPCThreadState::self()->joinThreadPool();
}

前面两个步骤已经很熟悉了,就直接来看看后面三步在干什么:

a.  实例化MediaExtractorService,并注册到ServiceManager当中

MediaExtractorService继承与BinderService,instantiate声明在 frameworks/native/libs/binder/include/binder/BinderService.h 中,同样被包含在libbinder中

template<typename SERVICE>
class BinderService
{
public:
static status_t publish(bool allowIsolated = false,
int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) {
sp<IServiceManager> sm(defaultServiceManager());
return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated,
dumpFlags);
} static void publishAndJoinThreadPool(
bool allowIsolated = false,
int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) {
publish(allowIsolated, dumpFlags);
joinThreadPool();
} static void instantiate() { publish(); } static status_t shutdown() { return NO_ERROR; } private:
static void joinThreadPool() {
sp<ProcessState> ps(ProcessState::self());
ps->startThreadPool();
ps->giveThreadPoolName();
IPCThreadState::self()->joinThreadPool();
}
};

服务的注册过程前面一节已经看过了,ServiceManager中的map会记录下传进来的这个BBinder对象。

b.  ProcessState::self()->startThreadPool()

void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
if (!mThreadPoolStarted) {
mThreadPoolStarted = true;
spawnPooledThread(true);
}
} void ProcessState::spawnPooledThread(bool isMain)
{
if (mThreadPoolStarted) {
String8 name = makeBinderThreadName();
ALOGV("Spawning new pooled thread, name=%s\n", name.string());
sp<Thread> t = sp<PoolThread>::make(isMain);
t->run(name.string());
}
} class PoolThread : public Thread
{
public:
explicit PoolThread(bool isMain)
: mIsMain(isMain)
{
} protected:
virtual bool threadLoop()
{
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
} const bool mIsMain;
};

在ProcessState中开了一个PoolThread线程来执行 IPCThreadState::self()->joinThreadPool,但是看看main函数执行的最后一句代码也是 IPCThreadState::self()->joinThreadPool,做了同样的事情,接下来看看:

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); mIsLooper = true;
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) {
LOG_ALWAYS_FATAL("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
mProcess->mDriverFD, result);
} // 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);
mIsLooper = false;
talkWithDriver(false);
}

这里有个do while循环用来检查是否client端有信息发过来并且处理信息,同时不让server进程结束。至于为什么调用了两次 IPCThreadState::joinThreadPool,这可能是和server端的多线程处理有关,这边后续再研究。


2、服务的获取

注册并启动服务之后我们要使用服务,首先要用ServiceManager来获取服务

这里摘一段MediaExtractorFactory中的代码:

sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor"));
sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder));
sp<IMediaExtractor> ex;
mediaExService->makeExtractor(
CreateIDataSourceFromDataSource(source),
mime ? std::optional<std::string>(mime) : std::nullopt,
&ex);

先来看看getService

sp<IBinder> ServiceManagerShim::getService(const String16& name) const
{
static bool gSystemBootCompleted = false; sp<IBinder> svc = checkService(name);
if (svc != nullptr) return svc; const bool isVendorService =
strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0;
constexpr int64_t timeout = 5000;
int64_t startTime = uptimeMillis();
// Vendor code can't access system properties
if (!gSystemBootCompleted && !isVendorService) {
#ifdef __ANDROID__
char bootCompleted[PROPERTY_VALUE_MAX];
property_get("sys.boot_completed", bootCompleted, "0");
gSystemBootCompleted = strcmp(bootCompleted, "1") == 0 ? true : false;
#else
gSystemBootCompleted = true;
#endif
}
// retry interval in millisecond; note that vendor services stay at 100ms
const useconds_t sleepTime = gSystemBootCompleted ? 1000 : 100; ALOGI("Waiting for service '%s' on '%s'...", String8(name).string(),
ProcessState::self()->getDriverName().c_str()); int n = 0;
while (uptimeMillis() - startTime < timeout) {
n++;
usleep(1000*sleepTime); sp<IBinder> svc = checkService(name);
if (svc != nullptr) {
ALOGI("Waiting for service '%s' on '%s' successful after waiting %" PRIi64 "ms",
String8(name).string(), ProcessState::self()->getDriverName().c_str(),
uptimeMillis() - startTime);
return svc;
}
}
ALOGW("Service %s didn't start. Returning NULL", String8(name).string());
return nullptr;
}

核心方法就是checkService

sp<IBinder> ServiceManagerShim::checkService(const String16& name) const
{
sp<IBinder> ret;
if (!mTheRealServiceManager->checkService(String8(name).c_str(), &ret).isOk()) {
return nullptr;
}
return ret;
}

调用的就是BpServiceManager的checkService方法,对外的接口参数是String16,而BpServiceManager接口参数为String8。经过Binder驱动的处理最终调用到server端的checkService

Status ServiceManager::checkService(const std::string& name, sp<IBinder>* outBinder) {
*outBinder = tryGetService(name, false);
// returns ok regardless of result for legacy reasons
return Status::ok();
}
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;
}
}
out = service->binder;
} if (!mAccess->canFind(ctx, name)) {
return nullptr;
} if (!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 service
service->guaranteeClient = true;
} return out;
}

注意到在addService时,保存到map中的IBinder实际是一个BnBinder对象,那Server端getSevice获得的也是一个BnBinder对象,返回给调用进程的就是这个BnBinder对象吗?其实不是的。

来看看BpServiceManager的checkService代码:

::android::binder::Status BpServiceManager::checkService(const ::std::string& name, ::android::sp<::android::IBinder>* _aidl_return) {
::android::Parcel _aidl_data;
_aidl_data.markForBinder(remoteStrong());
::android::Parcel _aidl_reply;
::android::status_t _aidl_ret_status = ::android::OK;
::android::binder::Status _aidl_status;
_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
_aidl_ret_status = _aidl_data.writeUtf8AsUtf16(name);
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
_aidl_ret_status = remote()->transact(BnServiceManager::TRANSACTION_checkService, _aidl_data, &_aidl_reply, 0);
if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IServiceManager::getDefaultImpl())) {
return IServiceManager::getDefaultImpl()->checkService(name, _aidl_return);
}
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
if (!_aidl_status.isOk()) {
return _aidl_status;
}
// 获取代理对象
_aidl_ret_status = _aidl_reply.readNullableStrongBinder(_aidl_return);
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
_aidl_error:
_aidl_status.setFromStatusT(_aidl_ret_status);
return _aidl_status;
}

获得RPC调用结果aidl_reply之后,最后面还有一句Parcel.readNullableStrongBinder,目的就是获取代理

status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
{
return unflattenBinder(val);
} status_t Parcel::unflattenBinder(sp<IBinder>* out) const
{
if (isForRpc()) {
LOG_ALWAYS_FATAL_IF(mSession == nullptr, "RpcSession required to read from remote parcel"); int32_t isNull;
status_t status = readInt32(&isNull);
if (status != OK) return status; sp<IBinder> binder; if (isNull & 1) {
auto addr = RpcAddress::zero();
status_t status = addr.readFromParcel(*this);
if (status != OK) return status;
binder = mSession->state()->onBinderEntering(mSession, addr);
} return finishUnflattenBinder(binder, out);
} // 这里可以拿到一个Handle
const flat_binder_object* flat = readObject(false); if (flat) {
switch (flat->hdr.type) {
case BINDER_TYPE_BINDER: {
sp<IBinder> binder =
sp<IBinder>::fromExisting(reinterpret_cast<IBinder*>(flat->cookie));
return finishUnflattenBinder(binder, out);
}
case BINDER_TYPE_HANDLE: {
// 创建一个BpBinder(handle)
sp<IBinder> binder =
ProcessState::self()->getStrongProxyForHandle(flat->handle);
return finishUnflattenBinder(binder, out);
}
}
}
return BAD_TYPE;
}

后面调用interface_cast 获取一个 BpMediaExtractorService,这和之前SeviceManager是相同的。

template<typename INTERFACE>
inline sp<IMediaExtractorService> interface_cast(const sp<IBinder>& obj)
{
return IMediaExtractorService::asInterface(obj);
} ::android::sp<IMediaExtractorService> IMediaExtractorService::asInterface(
const ::android::sp<::android::IBinder>& obj)
{
::android::sp<IMediaExtractorService> intr;
if (obj != nullptr) {
intr = ::android::sp<IMediaExtractorService>::cast(
obj->queryLocalInterface(IMediaExtractorService::descriptor));
if (intr == nullptr) {
intr = ::android::sp<BpMediaExtractorService>::make(obj);
}
}
return intr;
} template<typename INTERFACE>
inline sp<IInterface> BnInterface<IMediaExtractorService>::queryLocalInterface(
const String16& _descriptor)
{
if (_descriptor == IMediaExtractorService::descriptor) return sp<IInterface>::fromExisting(this);
return nullptr;
}

3、服务的使用

client使用就不再看了,看到server端时想到一个问题,IPCThreadState监听消息,但是没有指定由谁来执行。之前ServiceManager调用了setTheContextObject指定执行对象,但是media.extractor没有执行这一句,但是仔细看代码,似乎是从client发送的数据中可以找到target

            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;
}
// ......
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 {
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
}

到这里binder service框架大致就了解了,之后看到相关内容也更加从容,binder驱动之后有空再学习。

Android 12(S) Binder(二)的更多相关文章

  1. Android 12(S) 图形显示系统 - 示例应用(二)

    1 前言 为了更深刻的理解Android图形系统抽象的概念和BufferQueue的工作机制,这篇文章我们将从Native Level入手,基于Android图形系统API写作一个简单的图形处理小程序 ...

  2. Android 12(S) 图形显示系统 - Surface 一点补充知识(十二)

    必读: Android 12(S) 图形显示系统 - 开篇 一.前言 因为个人工作主要是Android多媒体播放的内容,在工作中查看源码或设计程序经常会遇到调用API: static inline i ...

  3. ZT android -- 蓝牙 bluetooth (二) 打开蓝牙

    android -- 蓝牙 bluetooth (二) 打开蓝牙 分类: Android的原生应用分析 2013-05-23 23:57 4773人阅读 评论(20) 收藏 举报 androidblu ...

  4. Android 12(S) 图形显示系统 - createSurface的流程(五)

    题外话 刚刚开始着笔写作这篇文章时,正好看电视在采访一位92岁的考古学家,在他的日记中有这样一句话,写在这里与君共勉"不要等待幸运的降临,要去努力的掌握知识".如此朴实的一句话,此 ...

  5. Android 12(S) 图形显示系统 - BufferQueue/BLASTBufferQueue之初识(六)

    题外话 你有没有听见,心里有一声咆哮,那一声咆哮,它好像在说:我就是要从后面追上去! 写文章真的好痛苦,特别是自己对这方面的知识也一知半解就更加痛苦了.这已经是这个系列的第六篇了,很多次都想放弃了,但 ...

  6. Android 12(S) 图形显示系统 - 初识ANativeWindow/Surface/SurfaceControl(七)

    题外话 "行百里者半九十",是说步行一百里路,走过九十里,只能算是走了一半.因为步行越接近目的地,走起来越困难.借指凡事到了接近成功,往往是最吃力.最艰难的时段.劝人做事贵在坚持, ...

  7. Android 12(S) 图形显示系统 - BufferQueue的工作流程(八)

    题外话 最近总有一个感觉:在不断学习中,越发的感觉自己的无知,自己是不是要从"愚昧之巅"掉到"绝望之谷"了,哈哈哈 邓宁-克鲁格效应 一.前言 前面的文章中已经 ...

  8. Android 12(S) 图形显示系统 - BufferQueue的工作流程(九)

    题外话 Covid-19疫情的强烈反弹,小区里检测出了无症状感染者.小区封闭管理,我也不得不居家办公了.既然这么大把的时间可以光明正大的宅家里,自然要好好利用,八个字 == 努力工作,好好学习 一.前 ...

  9. Android 12(S) 图形显示系统 - 解读Gralloc架构及GraphicBuffer创建/传递/释放(十四)

    必读: Android 12(S) 图形显示系统 - 开篇 一.前言 在前面的文章中,已经出现过 GraphicBuffer 的身影,GraphicBuffer 是Android图形显示系统中的一个重 ...

  10. Android 12(S) 图像显示系统 - SurfaceFlinger 之 VSync - 中篇(十七)

    必读: Android 12(S) 图像显示系统 - 开篇 1 前言 这一篇文章,将继续讲解有关VSync的知识,前一篇文章 Android 12(S) 图像显示系统 - SurfaceFlinger ...

随机推荐

  1. Spring框架之IOC和AOP底层原理

    ​1.1简介 Spring:春天-->软件行业的春天 2002,首次推出了Spring框架的雏:interface21框架! Spring框架即以interface21框架为基础,经过重新设计, ...

  2. 实战指南:使用 xUnit.DependencyInjection 在单元测试中实现依赖注入【完整教程】

    引言 上一篇我们创建了一个Sample.Api项目和Sample.Repository,并且带大家熟悉了一下Moq的概念,这一章我们来实战一下在xUnit项目使用依赖注入. Xunit.Depende ...

  3. 图像验证码识别,字母数字汉子均可cnn+lstm+ctc

    图形验证码如下: 训练两轮时的准确率:上边显示的是未识别的  config_demo.yaml System: GpuMemoryFraction: 0.7 TrainSetPath: 'train/ ...

  4. MD5前端vue加密

    Vue 前端md5加密用户注册时将加密后的密码发送给后端存储当登陆的时候,再将加密后的密码和数据库中加密的密码相匹配.npm: https://www.npmjs.com/package/crypto ...

  5. 力扣1768(java&python)-交替合并字符串(简单)

    题目: 给你两个字符串 word1 和 word2 .请你从 word1 开始,通过交替添加字母来合并字符串.如果一个字符串比另一个字符串长,就将多出来的字母追加到合并后字符串的末尾. 返回 合并后的 ...

  6. 力扣306(java)-累加数(中等)

    题目: 累加数 是一个字符串,组成它的数字可以形成累加序列. 一个有效的 累加序列 必须 至少 包含 3 个数.除了最开始的两个数以外,序列中的每个后续数字必须是它之前两个数字之和. 给你一个只包含数 ...

  7. Dataphin产品核心功能大图(六)发布中心:生产和开发隔离模式下的保护伞

    ​简介:Dataphin,用中台方法论打造企业级好数据.Dataphin是阿里巴巴集团OneData数据治理方法论内部实践的云化输出,一站式提供数据采.建.管.用全生命周期的大数据能力,以助力企业显著 ...

  8. dotnet 读 WPF 源代码笔记 聊聊 HwndWrapper.GetGCMemMessage 调试消息

    我在阅读 WPF 源代码,在 HwndWrapper 的静态构造函数看到了申请了 HwndWrapper.GetGCMemMessage 这个 Windows 消息,好奇这个消息是什么功能的.通过阅读 ...

  9. dotnet 使用 CsWin32 库简化 Win32 函数调用逻辑

    很多开发者,包括开发老司机们,在碰到需要调用 Win32 函数时,都有一个困扰,那就是我应该如何去调用.有两个主要的选项,第一就是自己写 PInvoke 代码,第二就是使用其他大佬给许多 Win32 ...

  10. 一个在线下载地图XYZ瓦片的网站实现

    1. 什么是XYZ瓦片 XYZ瓦片是一种在线地图数据格式,常见的地图底图如Google.OpenStreetMap 等互联网的瓦片地图服务,都是XYZ瓦片,严格来说是ZXY规范的地图瓦片 ZXY规范的 ...