当前位置:网站首页>Tencent Interviewer: How did binder get its system services?
Tencent Interviewer: How did binder get its system services?
2022-06-26 04:02:00 【Liuwangshu】
This article was first published on WeChat public 「 Post Factory Technical Officer 」
Related series
Android AOSP Foundation Series
Android System startup series
Application process startup series
Android Go deep into the four major component series
Android In depth understanding of Context series
Android In depth understanding of JNI series
Android analysis WindowManager
Android analysis WMS series
Android analysis AMS series
Android Package management mechanism series
Android Input system series
Preface
In previous articles in this series , With MediaPlayerService For example , Explains how system services are registered (addService), Since there is registration, there must be acquisition , This article still uses MediaPlayerService For example , To explain the acquisition process of system services (getService). The article will be divided into two parts to explain , They are clients MediaPlayerService Request to get service and server ServiceManager Processing requests , Let's learn the first part .
For previous articles, see :https://liuwangshu.cn/tags/Binder%E5%8E%9F%E7%90%86/
1. client MediaPlayerService Request for service
To get MediaPlayerService, You need to call getMediaPlayerService function , As shown below .
frameworks/av/media/libmedia/IMediaDeathNotifier.cpp
IMediaDeathNotifier::getMediaPlayerService()
{
ALOGV("getMediaPlayerService");
Mutex::Autolock _l(sServiceLock);
if (sMediaPlayerService == 0) {
sp<IServiceManager> sm = defaultServiceManager();//1
sp<IBinder> binder;
do {
binder = sm->getService(String16("media.player"));//2
if (binder != 0) {
//3
break;
}
ALOGW("Media player service not published, waiting...");
usleep(500000); //4
} while (true);
if (sDeathNotifier == NULL) {
sDeathNotifier = new DeathNotifier();
}
binder->linkToDeath(sDeathNotifier);
sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);//5
}
ALOGE_IF(sMediaPlayerService == 0, "no media player service!?");
return sMediaPlayerService;
}
notes 1 Situated defaultServiceManager The return is BpServiceManager, notes 2 It was named ”media.player” System services (MediaPlayerService), The returned value is BpBinder. Because of this time MediaPlayerService Maybe not to ServiceManager register , Then it can't satisfy the comment 3 Conditions , In the comments 4 Sleep at 0.5s Then continue to call getService function , Until the corresponding service is obtained .
notes 5 Situated interface_cast The function is used to BpBinder convert to BpMediaPlayerService, The principle is through BpBinder Of handle To find the corresponding service , namely BpMediaPlayerService.
notes 2 The key point of this paper is to obtain services at ,BpServiceManager Of getService The function is shown below .
frameworks/native/libs/binder/IServiceManager.cpp::BpServiceManager
virtual sp<IBinder> getService(const String16& name) const
{
...
int n = 0;
while (uptimeMillis() < timeout) {
n++;
if (isVendorService) {
ALOGI("Waiting for vendor service %s...", String8(name).string());
CallStack stack(LOG_TAG);
} else if (n%10 == 0) {
ALOGI("Waiting for service %s...", String8(name).string());
}
usleep(1000*sleepTime);
sp<IBinder> svc = checkService(name);//1
if (svc != NULL) return svc;
}
ALOGW("Service %s didn't start. Returning NULL", String8(name).string());
return NULL;
}
getService The main thing to do in the function is to query whether the circular query service exists , If it doesn't exist, continue to query , The query service uses comments 1 Situated checkService function , The code is as follows .
frameworks/native/libs/binder/IServiceManager.cpp::BpServiceManager
virtual sp<IBinder> checkService( const String16& name) const
{
Parcel data, reply;//1
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);//2
remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);//3
return reply.readStrongBinder();
}
notes 1 Situated data, The students who read the last article should be familiar with , It appears in BpServiceManager Of addService Function ,data It's a packet , The data will be written to data in . notes 2 Place string "media.player" Write to data in .
notes 3 Situated remote() refer to mRemote, That is to say BpBinder,BpBinder Of transact The function is shown below .
frameworks/native/libs/binder/BpBinder.cpp
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
if (mAlive) {
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
BpBinder Give logic to IPCThreadState, The subsequent call chain is =Android Binder principle ( 3、 ... and ) Registration process of system services In the said , Let's go through it again ,IPCThreadState::self() Will create create IPCThreadState,IPCThreadState Of transact The function is shown below .
frameworks/native/libs/binder/IPCThreadState.cpp
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
status_t err;
flags |= TF_ACCEPT_FDS;
...
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);//1
if (err != NO_ERROR) {
if (reply) reply->setError(err);
return (mLastError = err);
}
if ((flags & TF_ONE_WAY) == 0) {
...
if (reply) {
err = waitForResponse(reply);//2
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
...
} else {
// No need to wait reply The branch of
err = waitForResponse(NULL, NULL);
}
return err;
}
call BpBinder Of transact A function is actually a call to IPCThreadState Of transact function . notes 1 Situated writeTransactionData Function to transfer data , The first parameter BC_TRANSACTION Represents to Binder Drive send command protocol .
notes 1 Situated writeTransactionData Data to be sent , Inside it will be BC_TRANSACTION and binder_transaction_data Structure write to mOut in .
Then check waitForResponse What does the function do , The code is as follows .
frameworks/native/libs/binder/IPCThreadState.cpp
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
uint32_t cmd;
int32_t err;
while (1) {
if ((err=talkWithDriver()) < NO_ERROR) break;//1
err = mIn.errorCheck();
if (err < NO_ERROR) break;
if (mIn.dataAvail() == 0) continue;
cmd = (uint32_t)mIn.readInt32();
IF_LOG_COMMANDS() {
alog << "Processing waitForResponse Command: "
<< getReturnString(cmd) << endl;
}
switch (cmd) {
case BR_TRANSACTION_COMPLETE:
if (!reply && !acquireResult) goto finish;
break;
...
default:
// Deal with all kinds of command protocols
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
break;
}
}
finish:
...
return err;
}
notes 1 Situated talkWithDriver The function passes through ioctl And Binder Drive to communicate , The code is as follows .
frameworks/native/libs/binder/IPCThreadState.cpp
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
if (mProcess->mDriverFD <= 0) {
return -EBADF;
}
// and Binder The structure that drives communication
binder_write_read bwr; //1
//mIn Is there any readable data , The received data is stored in mIn
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data();//2
// At this time doReceive The value of is true
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();//3
} else {
bwr.read_size = 0;
bwr.read_buffer = 0;
}
...
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_LOG_COMMANDS() {
alog << "About to read/write, write size = " << mOut.dataSize() << endl;
}
#if defined(__ANDROID__)
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)//4
err = NO_ERROR;
else
err = -errno;
#else
err = INVALID_OPERATION;
#endif
...
} while (err == -EINTR);
...
return err;
}
notes 1 Situated binder_write_read Is and Binder The structure that drives communication , In the comments 2 and 3 General mOut、mIn Assign a value to binder_write_read The corresponding fields of , Finally, through notes 4 Situated ioctl Functions and Binder Drive to communicate . The sequence diagram of this process is as follows .
Now we need to check again Android Binder principle ( 3、 ... and ) Registration process of system services This article is No 2 The graph given in Section .
As can be seen from this simplified flow chart , We are currently analyzing the process of the client process , When MediaPlayerService towards Binder Drive send BC_TRANSACTION After the command ,Binder The drive will go to ServiceManager send out BR_TRANSACTION command , Next let's look at the server ServiceManager How to deal with the request of getting service .
2. Server side ServiceManager Processing requests
When it comes to servers ServiceManager Processing requests , I have to say ServiceManager Start up process of , For details, please see Android Binder principle ( Four )ServiceManager Start up process of This article .
Here is a brief review servicemanager The entry function of , As shown below .
frameworks/native/cmds/servicemanager/service_manager.c
int main(int argc, char** argv)
{
...
bs = binder_open(driver, 128*1024);
...
if (binder_become_context_manager(bs)) {
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
...
if (getcon(&service_manager_context) != 0) {
ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");
abort();
}
binder_loop(bs, svcmgr_handler);//1
return 0;
}
main Function does three main things , The last thing is to call binder_loop function , Here we need to pay attention to , Its second parameter is svcmgr_handler, It will be mentioned again later svcmgr_handler.
binder_loop The function is shown below .
frameworks/native/cmds/servicemanager/binder.c
void binder_loop(struct binder_state *bs, binder_handler func)
{
...
for (;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (uintptr_t) readbuf;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
if (res < 0) {
ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
break;
}
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
if (res == 0) {
ALOGE("binder_loop: unexpected reply?!\n");
break;
}
if (res < 0) {
ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));
break;
}
}
}
Call continuously in infinite loop ioctl function , It's constantly used BINDER_WRITE_READ Command query Binder Is there a new request in the driver , If there is one, give it to binder_parse Function processing . without , The current thread will be in Binder Driving sleep , Waiting for new interprocess communication requests .
binder_parse The function is shown below .
frameworks/native/cmds/servicemanager/binder.c
int binder_parse(struct binder_state *bs, struct binder_io *bio,
uintptr_t ptr, size_t size, binder_handler func)
{
int r = 1;
uintptr_t end = ptr + (uintptr_t) size;
while (ptr < end) {
uint32_t cmd = *(uint32_t *) ptr;
ptr += sizeof(uint32_t);
#if TRACE
fprintf(stderr,"%s:\n", cmd_name(cmd));
#endif
switch(cmd) {
...
case BR_TRANSACTION: {
struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
if ((end - ptr) < sizeof(*txn)) {
ALOGE("parse: txn too small!\n");
return -1;
}
binder_dump_txn(txn);
if (func) {
unsigned rdata[256/4];
struct binder_io msg;
struct binder_io reply;
int res;
bio_init(&reply, rdata, sizeof(rdata), 4);
bio_init_from_txn(&msg, txn);
res = func(bs, txn, &msg, &reply);//1
if (txn->flags & TF_ONE_WAY) {
binder_free_buffer(bs, txn->data.ptr.buffer);
} else {
binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
}
}
ptr += sizeof(*txn);
break;
}
...
}
return r;
}
Here we intercept BR_TRANSACTION The processing part of the order , notes 1 Out of func All the way to the point is svcmgr_handler,svcmgr_handler The function is shown below .
frameworks/native/cmds/servicemanager/service_manager.c
int svcmgr_handler(struct binder_state *bs,
struct binder_transaction_data *txn,
struct binder_io *msg,
struct binder_io *reply)
{
...
switch(txn->code) {
case SVC_MGR_GET_SERVICE:
case SVC_MGR_CHECK_SERVICE:
s = bio_get_string16(msg, &len);
if (s == NULL) {
return -1;
}
handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
if (!handle)
break;
bio_put_ref(reply, handle);
return 0;
...
default:
ALOGE("unknown code %d\n", txn->code);
return -1;
}
bio_put_uint32(reply, 0);
return 0;
}
When it comes to getting Services , Would call do_find_service function , The code is as follows .
frameworks/native/cmds/servicemanager/service_manager.c
uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid)
{
struct svcinfo *si = find_svc(s, len);//1
if (!si || !si->handle) {
return 0;
}
if (!si->allow_isolated) {
uid_t appid = uid % AID_USER;
if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
return 0;
}
}
if (!svc_can_find(s, len, spid, uid)) {
return 0;
}
return si->handle;
}
notes 1 Situated find_svc Function to query services , Back to svcinfo It's a structure , It contains the handle value , It will eventually return to the service handle value . Then look find_svc function :
frameworks/native/cmds/servicemanager/service_manager.c
struct svcinfo *find_svc(const uint16_t *s16, size_t len)
{
struct svcinfo *si;
for (si = svclist; si; si = si->next) {
if ((len == si->len) &&
!memcmp(s16, si->name, len * sizeof(uint16_t))) {
return si;
}
}
return NULL;
}
In the registration process of system services , stay Kernel Binder Will call do_add_service function , It will contain the service name and handle It's worth it svcinfo Save to svclist In the list . alike , In the process of getting Services ,find_svc Function will traverse svclist list , Find whether the corresponding service has been registered according to the service name , If you have already registered, you will return the corresponding svcinfo, If you don't register, return NULL.
summary
This article divides the acquisition process of system services into two parts , The code involves Native Binder and Kernel Binder. I will continue to learn in the next article Java Binder Related content .
For more information, please pay attention to the knowledge system of my independent blog :
http://liuwangshu.cn/system/

边栏推荐
- Webrtc series - 7-ice supplement of network transmission preference and priority
- Camera-memory内存泄漏分析(二)
- ABP framework Practice Series (I) - Introduction to persistence layer
- (15) Blender source code analysis flash window display menu function
- Analysis of updatechild principle of widget update mechanism of fluent
- I/O 虚拟化技术 — UIO Framework
- Three level menu applet
- IEDA 突然找不到了compact middle packages
- Force buckle 515 Find the maximum value in each tree row
- 力扣 515. 在每个树行中找最大值
猜你喜欢
随机推荐
ABP framework Practice Series (I) - Introduction to persistence layer
Ipvs0 network card of IPVS
EF core Basics
Uni app, the text implementation expands and retracts the full text
Analysis of camera memory memory leakage (II)
Detailed explanation of globalkey of flutter
软件调试测试的十大重要基本准则
Camera-CreateCaptureSession
高性能算力中心 — RoCE — Overview
【MySQL】 MySQL 导出数据库
Open Camera异常分析(一)
[QT] dialog box
[Nuggets' operation routine disclosure] the routine of being truly Nuggets
Alibaba cloud function computing service one click to build Z-blog personal blog
[从零开始学习FPGA编程-45]:视野篇 - 集成电路助力数字化时代高质量发展-2-市场预测
Go time package: second, millisecond, nanosecond timestamp output
What preparation should I make before learning SCM?
(15)Blender源码分析之闪屏窗口显示菜单功能
XML parsing bean tool class
High performance computing center roce overview