Binder 服务获取与使用过程情景分析之C++篇

7/29/2023

本文基于 Android10 源码环境

先看一下客户端主函数:

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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

主要的流程:

  • 调用 ProcessState::self() 完成 Binder 的初始化
  • 调用 defaultServiceManager() 获取到 BpServiceManger 对象
  • getService 获取到 hello 服务
  • 发起远程调用

前两个阶段流程和 Binder 服务注册过程情景分析之C++篇 (opens new window) 相同,这里不在重复

# 1. 获取服务

sp<IBinder> binder = sm->getService(String16("hello"));
1

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();
    }   
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

通过 remote 发起远程调用,remote 的调用细节和 Binder 服务注册过程情景分析之C++篇 (opens new window) 相同,这里不在重复。

ServiceManager checkService 返回的是一个整型 handle,通过 reply.readStrongBinder() 将 handle 包装为一个 IBinder 对象(实际是一个 BpBinder 对象)。转换过程会在后面 Parcel 解析的文章分析。这里知道其功能即可。

接着通过 interface_cast 将其转换为 BpHelloService 对象,流程和Binder 服务注册过程情景分析之C++篇 (opens new window)defaultServiceManager 中的分析相同。最终就是 new 一个 BpHelloService 对象,通过构造函数参数传入 BpBinder。

sp<IHelloService> service =
		    interface_cast<IHelloService>(binder);
1
2

# 2. 发起远程调用

有了 HpHelloService 对象就可以发起远程调用了,这里分析 sayHello 的实现,sayHelloto 就留给读者了

service->sayHello();
1

实现如下:

void BpHelloService::sayHello() {
    Parcel data, reply;
    data.writeInt32(0);
    data.writeString16(String16("IHelloService"));
    remote()->transact(HELLO_SVR_CMD_SAYHELLO, data, &reply);
}
1
2
3
4
5
6

通过 remote 发起远程调用,客户端阻塞,服务端被唤醒。我们的服务端开启了两个线程等待远程调用,内核会选择一个线程唤醒:

服务端通过 joinThreadPool 函数读数据同时陷入阻塞:

void IPCThreadState::joinThreadPool(bool isMain)
{
    //......
    
    do { //进入循环
        //......
        // now get the next command to be processed, waiting if necessary
        //读数据,处理数据
        result = getAndExecuteCommand();
    } while (result != -ECONNREFUSED && result != -EBADF);

  //......
}

joinThreadPool 内部执行 getAndExecuteCommand 来读数据和处理数据:

status_t IPCThreadState::getAndExecuteCommand()
{
    status_t result;
    int32_t cmd;

    //读数据
    result = talkWithDriver();
    if (result >= NO_ERROR) {
        //......
         cmd = mIn.readInt32();
        //......
        //处理数据
        result = executeCommand(cmd);

       //......
    }

    return result;
}

talkWithDriver 进行数据的读取工作,executeCommand 进行数据的处理工作:

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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114

talkWithDriver 通过 ioctl 读到数据 binder_write_read bwr,并把 bwr 中的数据存放到 Parcel mIn 中。

接着从 mIn 中读出 cmd,并执行 executeCommand 来处理我们收到的数据:

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;
            //读到的数据存入到 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 函数
                    // tr.cookie 是我们注册服务时传入的 BnHelloService 对象指针
                    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;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136

从 ioctl 唤醒,解析出数据,通过 transact 方法调用到我们自定义的 onTransact 函数,从而执行到 sayHello:

status_t BnHelloService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {

    switch(code) {
        case HELLO_SVR_CMD_SAYHELLO:  {
            sayHello();
            reply->writeInt32(0);
            return NO_ERROR;
        } break;
           
        case HELLO_SVR_CMD_SAYHELLO_TO: {
            int32_t policy =  data.readInt32();
			String16 name16_tmp = data.readString16(); 
			
			String16 name16 = data.readString16();
			String8 name8(name16);

			int cnt = sayHelloTo(name8.string());

			reply->writeInt32(0); 
			reply->writeInt32(cnt);

            return NO_ERROR;
        } break;
            
        default:
            return BBinder::onTransact(code, data, reply, flags);
        
    }
}

void BnHelloService::sayHello() {
    static int count = 0;
    ALOGI("server say hello :%d\n ", ++count);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34