Physical Address:
ChongQing,China.
WebSite:
在Android系统中,Java Framework层的诸多服务都通过Binder与Native层的服务进行通信;基于此再对外提供接口给各个Java应用。在这种通信模式下,两端遵守的是C-S架构。一般而言Native服务会作为Server端而存在。
Native服务作为Server端,是需要注册到serviceManager成为服务之后才能被系统中的各个Client进行获取、连接与使用的。本篇博客将以Android12的源码为基础,简单分析一下Android Native服务的注册流程。
这里我们先以CameraService为例做一个分析讲解。
CameraService在Native层主要分为两个部分:一个是以binary形式而存在的cameraserver;另外一个则是以共享库形式而存在的libcameraservice。前者作为CamearService的程序入口,而后者则是具体的逻辑主体实现,且后者是前者的依赖项之一,由前者负责调用。其服务注册的主体部分,位于cameraserver内,总体涉及的到源码路径如下:
//cameraserver
frameworks/av/camera/cameraserver
//libcameraservice
frameworks/av/services/camera/libcameraservice
我们找到cameraserver启动的源码文件:main_cameraserver.cpp,其源码内容非常精简,具体内容如下所示:
#define LOG_TAG "cameraserver"
//#define LOG_NDEBUG 0
#include "CameraService.h"
#include <hidl/HidlTransportSupport.h>
using namespace android;
int main(int argc __unused, char** argv __unused)
{
signal(SIGPIPE, SIG_IGN);
// Set 5 threads for HIDL calls. Now cameraserver will serve HIDL calls in
// addition to consuming them from the Camera HAL as well.
hardware::configureRpcThreadpool(5, /*willjoin*/ false);
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
ALOGI("ServiceManager: %p", sm.get());
CameraService::instantiate();
ALOGI("ServiceManager: %p done instantiate", sm.get());
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
在cameraserver的服务启动过程中,就包含了服务注册的部分,主要包含以下几个步骤:
1.获取ProcessState对象,用于连接底层binder驱动;
2.获取ServiceManager实例,通过父类instantiate接口发布到Android系统中;
3.启动binder线程池,该线程池用于处理Binder IPC通信;
4.线程执行,此时可以处理Binder IPC请求;
这一步的目的其实是为了通过libbinder连接底层binder驱动(/dev/binder),涉及到的源码文件如下:
frameworks/native/libs/binder/include/binder/ProcessState.h //头文件
frameworks/native/libs/binder/ProcessState.cpp //源码文件
ProcessState类在源码中是一个单例实现,部分关键源码如下:
//frameworks/native/libs/binder/ProcessState.cpp
#ifdef __ANDROID_VNDK__
const char* kDefaultDriver = "/dev/vndbinder";
#else
const char* kDefaultDriver = "/dev/binder";
#endif
//native 服务使用该接口进行binder初始化,如
sp<ProcessState> ProcessState::self()
{
return init(kDefaultDriver, false /*requireDefault*/);
}
//init 函数作为主入口
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);
//use sp<CLASS>::make to construct an sp object
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 constructor
ProcessState::ProcessState(const char *driver)
: mDriverName(String8(driver))
, mDriverFD(open_driver(driver))
, 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.
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
}
//构造函数列表初始化中通过open_driver连接驱动
static int open_driver(const char *driver)
{
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;
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;
}
在Native Service启动时,我们通过ProcessState::self()获取到单例对象,再通过 ProcessState 的拷贝构造函数赋值给proc,从而得到名为proc指向 ProcessState 的智能指针。
获取IServiceManager实例是为了后续将服务添加到ServiceManager中,这一步涉及到的源码文件如下:
/frameworks/native/libs/binder/include/binder/IServiceManager.h //头文件
/frameworks/native/libs/binder/IServiceManager.cpp //源文件
IServiceManager自身也是单例实现,其实现部分的代码如下:
using AidlServiceManager = android::os::IServiceManager;
sp<IServiceManager> defaultServiceManager()
{
//通过std::call_once确保在多线程并行调用情况下也只会执行一次
std::call_once(gSmOnce, []() {
sp<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;
}
在defaultServiceManager函数实现中,首先通过std::call_once来确保多线程并发调用的情况下函数主体只会调用一次,并且通过while循环来确保在serviceManager进程启动慢时通过sleep休眠来暂缓获取的过程,其中最为关键的接口在于getContextObject函数,其具体内容如下:
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
sp<IBinder> context = getStrongProxyForHandle(0);
if (context) {
// The root object is special since we get it directly from the driver, it is never
// written by Parcell::writeStrongBinder.
internal::Stability::markCompilationUnit(context.get());
} else {
ALOGW("Not able to get context object on %s.", mDriverName.c_str());
}
return context;
}
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
handle_entry* e = lookupHandleLocked(handle);
if (e != nullptr) {
IBinder* b = e->binder;
if (b == nullptr || !e->refs->attemptIncWeak(this)) {
if (handle == 0) {
.....
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);
ipc->setCallRestriction(originalCallRestriction);
if (status == DEAD_OBJECT)
return nullptr;
}
sp<BpBinder> b = BpBinder::create(handle);
e->binder = b.get();
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}
getContextObject中通过getStrongProxyForHandle函数来获取IBinder的sp对象,而其实际上是通过BpBinder::create(handle)来进行获取的,不过在这一步得到的对象是指向BpBinder的sp,我们将上面的代码进行简化,可以得到如下的内容:
//原始内容
sp<AidlServiceManager> sm = interface_cast<AidlServiceManager>(ProcessState::self()->getContextObject(nullptr))
//简化内容
sp<android::os::IServiceManager> sm = interface_cast<android::os::IServiceManager>(BpBinder::create(0))
这里通过interface_cast将BpBinder::create(0)转换为了android::os::IServiceManager,具体的转换过程可以看看interface_cast的源码实现,其本身属于类模板函数,源码位于frameworks/native/libs/binder/include/binder/IInterface.h内,具体内容如下:
/**
* If this is a local object and the descriptor matches, this will return the
* actual local object which is implementing the interface. Otherwise, this will
* return a proxy to the interface without checking the interface descriptor.
* This means that subsequent calls may fail with BAD_TYPE.
*/
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
return INTERFACE::asInterface(obj);
}
我们将其中的INTERFACE模板做相应替换后,可以得到如下内容:
sp<android::os::IServiceManager> sm = android::os::IServiceManager::asInterface(BpBinder::create(0))
我们再关注一下IServiceManager类的内部,可以看到如下方法:
/**
* Retrieve an existing service, blocking for a few seconds
* if it doesn't yet exist.
*/
virtual sp<IBinder> getService( const String16& name) const = 0;
/**
* Retrieve an existing service, non-blocking.
*/
virtual sp<IBinder> checkService( const String16& name) const = 0;
/**
* Register a service.
*/
// NOLINTNEXTLINE(google-default-arguments)
virtual status_t addService(const String16& name, const sp<IBinder>& service,
bool allowIsolated = false,
int dumpsysFlags = DUMP_FLAG_PRIORITY_DEFAULT) = 0;
/**
* Return list of all existing services.
*/
// NOLINTNEXTLINE(google-default-arguments)
virtual Vector<String16> listServices(int dumpsysFlags = DUMP_FLAG_PRIORITY_ALL) = 0;
/**
* Efficiently wait for a service.
*
* Returns nullptr only for permission problem or fatal error.
*/
virtual sp<IBinder> waitForService(const String16& name) = 0;
这部分方法都是与服务获取、使用相关的,且都属于纯虚函数,具体的实现逻辑在其子类ServiceManagerShim内。
接下来就是服务注册了,这部分可能也是最让人困惑的。从整个代码调用上来看,服务注册最直观的调用应该属于CameraService::instantiate();这一句,但即使我们翻遍CameraService的源码也是无法找到 instantiate的具体实现的,原因就在于 instantiate 方法其实是来自于父类的public方法,我们在相应的头文件内可以看到:
//
class CameraService :
public BinderService<CameraService>,
public virtual ::android::hardware::BnCameraService,
public virtual IBinder::DeathRecipient,
public virtual CameraProviderManager::StatusListener
{
......
}
事实上instantiate方法就是类模板BinderService的公有方法 ,其代码实现如下:
//frameworks/native/libs/binder/include/binder/BinderService.h
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();
}
};
这里 instantiate方法其实就是封装了一下publish方法,在publish方法内,通过IServiceManager的addService方法添加服务,这里有两个小细节是需要注意的:一个是我们实现的服务必须要实现getServiceName方法,且该方法必须为public static方法;另一个是我们实现的服务必须要显式实现默认构造函数,且必须为public可见,新手一般会在这两个地方踩坑。具体原因,我们只需要看sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated,dumpFlags);这一行就知道为什么了。
在将服务注册到ServiceManager之后,我们需要启动服务侧的binder线程池,由于是多Client并发请求的,线程池是必须的,
// 启动binder线程池
ProcessState::self()->startThreadPool();
// 加入到Binder线程池
IPCThreadState::self()->joinThreadPool();
首先看看startThreadPool内的实现:
//frameworks/native/libs/binder/ProcessState.cpp
void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
if (!mThreadPoolStarted) {
mThreadPoolStarted = true;
//通过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());
}
}
//PoolThread为内部类,继承自Android自行封装的Thread类
class PoolThread : public Thread
{
public:
explicit PoolThread(bool isMain)
: mIsMain(isMain)
{
}
protected:
virtual bool threadLoop()
{
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
}
const bool mIsMain;
};
从其实现我们可以看到,startThreadPool调用就会开启线程执行,并且是作为主线程执行;接着我们看看joinThreadPool的实现:
//frameworks/native/libs/binder/IPCThreadState.cpp
void IPCThreadState::joinThreadPool(bool isMain)
{
LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
//设定线程状态,mOut属于Parcel对象
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);
}
//从binder中获取command并执行
status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
int32_t cmd;
result = talkWithDriver();
if (result >= NO_ERROR) {
//mIn属于Parcel对象,从中获取binder driver传递的command
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);
result = 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/168806193
if (mProcess->mWaitingForThreads > 0) {
pthread_cond_broadcast(&mProcess->mThreadCountDecrement);
}
pthread_mutex_unlock(&mProcess->mThreadCountLock);
}
return result;
}
整个实现过程中最为关键的函数为executeCommand,其内部实现简单来讲就是根据mIn传递的binder驱动指令(BR_XXX)执行相关动作,再将执行结果(BC_XXX)通过mOut返回至binder驱动。
这里我们再简单总结一下如何实现一个安卓Native Service:
1.在头文件中include以下头文件:
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/BinderService.h>
声明MyOwnService类,并使其继承public BinderService<MyOwnService>,并将BinderService<MyOwnService>设置为友元类;并实现如下函数:
MyOwnService();//默认构造函数
static char const* getServiceName(); //用于定义service名称
如果我们需要在MyOwnService中实现AIDL接口,如IMyOwnService.aidl,需要继承BnMyOwnService类,并覆写 IMyOwnService.aidl中所定义的接口。
如果需要处理BinderDied这种异常情况,则需要继承IBinder::DeathRecipient,覆写binderDied接口。如下所示:
//for service register
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/BinderService.h>
class MyOwnService :public BinderService<MyOwnService>,public BnMyOwnService,public
virtual IBinder::DeathRecipient{
public:
MyOwnService();
static char const* getServiceName();
.....
private:
void binderDied(const wp<IBinder>& who) override;
.....
}
2.Main函数编写:
void main(int argc,char * argv[])
{
configureRpcThreadpool(3, false /* callerWillJoin */);
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
myOwnService::instantiate();
//这两句一定放在服务准备工作完成之后,否则后续的语句不会执行
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
至此服务就能注册到ServiceManager中,并可进行binder通信了。
如果我们要在远端获取service,在Java层可以采用如下方式:
import android.os.IBinder;
import android.os.ServiceManager;
//字符串必须与service实现的getServiceName接口所返回的一致
IBinder binder = ServiceManager.getService("myOwnService");
//将IBinder通过asInterface转换为具体的service远端对象
mMyOwnService = IMyOwnService.Stub.asInterface(binder);
关于IMyOwnService.Stub.asInterface接口的由来,可以参考我的另一篇文章。