写给应用开发的 Android Framework 教程是一个系列教程,目前已更新以下内容:
-
系统开发基础
-
AOSP 上手指南
-
学穿 Binder 系列
- Binder 基本原理
- Binder 程序示例之 C 语言篇
- Binder 服务注册过程情景分析之C语言篇
- Binder 服务获取与使用过程情景分析之C语言篇
- Binder C++ 程序示例
- Binder C++ 程序分析之主要类解析
- Binder 服务注册过程情景分析之 C++ 篇
- Binder 服务获取与使用过程情景分析之 C++ 篇(本文)
-
HAL 与硬件服务
本文基于 AOSP Android10 r41
源码环境
先看一下客户端主函数:
int main(int argc, char const *argv[])
{
//Binder 驱动初始化
sp<ProcessState> proc(ProcessState::self());
//获取 BpServiceManger 对象
sp<IServiceManager> sm = defaultServiceManager();
//获取服务
sp<IBinder> binder = sm->getService(String16("hello"));
//转成 BpHelloService
sp<IHelloService> service =
interface_cast<IHelloService>(binder);
if (binder == 0)
{
ALOGI("can't get hello service\n");
return -1;
}
//发起远程调用
service->sayHello();
int cnt = service->sayHelloTo("nihao");
ALOGI("client call sayhello_to, cnt = %d", cnt);
return 0;
}
主要的流程:
- 调用
ProcessState::self()
完成 Binder 的初始化 - 调用
defaultServiceManager()
获取到 BpServiceManger 对象 getService
获取到 hello 服务- 发起远程调用
前两个阶段流程和 Binder 服务注册过程情景分析之C++篇 相同,这里不在重复
1. 获取服务
sp<IBinder> binder = sm->getService(String16("hello"));
getService
具体实现在 frameworks/native/libs/binder/IServiceManager.cpp
virtual sp<IBinder> getService(const String16& name) const
{
sp<IBinder> svc = checkService(name);
if (svc != nullptr) return svc;
//......
}
virtual sp<IBinder> checkService( const String16& name) const
{
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
return reply.readStrongBinder();
}
通过 remote 发起远程调用,remote 的调用细节和 Binder 服务注册过程情景分析之C++篇 相同,这里不在重复。
ServiceManager getService 返回的是一个整型 handle,通过 reply.readStrongBinder()
将 handle 包装为一个 IBinder 对象(实际是一个 BpBinder 对象)。转换过程会在后面 Parcel 解析的文章分析。这里知道其功能即可。
接着通过 interface_cast
将其转换为 BpHelloService 对象,流程和Binder 服务注册过程情景分析之C++篇 中 defaultServiceManager
中的分析相同。最终就是 new 一个 BpHelloService 对象,通过构造函数参数传入 BpBinder。
sp<IHelloService> service =
interface_cast<IHelloService>(binder);
2. 发起远程调用
有了 HpHelloService 对象就可以发起远程调用了,这里分析 sayHello 的实现,sayHelloto 就留给读者了
service->sayHello();
实现如下:
void BpHelloService::sayHello() {
Parcel data, reply;
data.writeInt32(0);
data.writeString16(String16("IHelloService"));
remote()->transact(HELLO_SVR_CMD_SAYHELLO, data, &reply);
}
通过 remote 发起远程调用,客户端阻塞,服务端被唤醒。我们的服务端开启了两个线程等待远程调用,内核会选择一个线程唤醒(具体选哪个会在驱动分析中说明):
void IPCThreadState::joinThreadPool(bool isMain)
{
//......
do { //进入循环
//......
// now get the next command to be processed, waiting if necessary
//读数据,处理数据
result = getAndExecuteCommand();
} while (result != -ECONNREFUSED && result != -EBADF);
//......
}
status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
int32_t cmd;
//读数据
result = talkWithDriver();
if (result >= NO_ERROR) {
//......
//处理数据
result = executeCommand(cmd);
//......
}
return result;
}
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
if (mProcess->mDriverFD < 0) {
return -EBADF;
}
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;
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data();
// This is what we'll read.
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
bwr.read_size = 0;
bwr.read_buffer = 0;
}
// Return immediately if there is nothing to do.
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
#if defined(__ANDROID__)
//从这里唤醒
//读到数据 bwr
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
#else
err = INVALID_OPERATION;
#endif
if (mProcess->mDriverFD < 0) {
err = -EBADF;
}
} while (err == -EINTR);
if (err >= NO_ERROR) {
if (bwr.write_consumed > 0) {
if (bwr.write_consumed < mOut.dataSize())
LOG_ALWAYS_FATAL("Driver did not consume write buffer. "
"err: %s consumed: %zu of %zu",
statusToString(err).c_str(),
(size_t)bwr.write_consumed,
mOut.dataSize());
else {
mOut.setDataSize(0);
processPostWriteDerefs();
}
}
//将收到的数据写到 mIn 中
if (bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);
}
return NO_ERROR;
}
return err;
}
//
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR;
switch ((uint32_t)cmd) {
case BR_TRANSACTION_SEC_CTX:
case BR_TRANSACTION:
{
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 {
//读出刚才写入到 mIn 中的数据
result = mIn.read(&tr, sizeof(tr));
tr_secctx.secctx = 0;
}
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 = __builtin_frame_address(0);
const pid_t origPid = mCallingPid;
const char* origSid = mCallingSid;
const uid_t origUid = mCallingUid;
const bool origHasExplicitIdentity = mHasExplicitIdentity;
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;
mHasExplicitIdentity = false;
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 (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)) {
//tranact 执行到 onTranact,从而执行到 sayHello 函数
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);
}
//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);
// b/238777741: clear buffer before we send the reply.
// Otherwise, there is a race where the client may
// receive the reply and send another transaction
// here and the space used by this transaction won't
// be freed for the client.
buffer.setDataSize(0);
constexpr uint32_t kForwardReplyFlags = TF_CLEAR_BUF;
sendReply(reply, (tr.flags & kForwardReplyFlags));
} else {
if (error != OK) {
std::ostringstream logStream;
logStream << "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);
if (reply.dataSize() != 0) {
logStream << " and reply parcel size " << reply.dataSize();
}
std::string message = logStream.str();
ALOGI("%s", message.c_str());
}
}
mServingStackPointer = origServingStackPointer;
mCallingPid = origPid;
mCallingSid = origSid;
mCallingUid = origUid;
mHasExplicitIdentity = origHasExplicitIdentity;
mStrictModePolicy = origStrictModePolicy;
mLastTransactionBinderFlags = origTransactionBinderFlags;
mWorkSource = origWorkSource;
mPropagateWorkSource = origPropagateWorkSet;
}
break;
//......
default:
ALOGE("*** BAD COMMAND %d received from Binder driver\n", cmd);
result = UNKNOWN_ERROR;
break;
}
if (result != NO_ERROR) {
mLastError = result;
}
return result;
}
从 ioctl 唤醒,解析出数据,通过 transact 方法调用到我们自定义的 onTransact 函数,从而执行到 sayHello。