android native service

本文详细介绍了如何将一个C++编写的Native Service注册到Android的ServiceManager,使其成为全局服务。主要内容包括TestService的注册过程,涉及到的关键步骤如ProcessState::self()->startThreadPool()、IPCThreadState::self()->joinThreadPool()以及binder服务端如何处理客户端请求。通过BBinder::transact()和onTransact()实现服务间的交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前面讲了如何定义个native(C++)层的service,TestService,接下里我们继续完善,讲一下如何将它注册到servicemanager,成为全局的service。


TestService.h

#ifndef ANDROID_HXIONFG_TEST_H  
#define ANDROID_HXIONFG_TEST_H  
  
#include <ITestService.h>  
#include <binder/BinderService.h>  
namespace android {  
  
  
class TestService : public BnTestService, public BinderService<TestService> {  
public:  
    
    TestService();  
    virtual ~TestService();  
    
    // Implementation of BinderService<T>
    static char const* getServiceName() { return "hxiong.test"; }

    virtual status_t test(int api);  
};  
}  
#endif

然后再写一个可执行程序,将它编译成可执行程序文件

main_testserver.cpp

#include "TestService.h"
using namespace android;

int main(int argc __unused, char** argv __unused)
{
    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager> sm = defaultServiceManager();
    ALOGI("ServiceManager: %p", sm.get());
    TestService::instantiate();
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
}

1、ProcessState::self() 

创建ProcessState 实例,注意这是一个单例,也就是一个进程中只有一个ProcessState 实例,ProcessState在构造函数中做了一件十分重要的事,那就是打开binder driver。返回fd,后面就可以通过这个fd和binder driver打交道了,跟driver打交道,基本上用的都是ioctl。

static int open_driver()
{
    int fd = open("/dev/binder", 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 does not match user space protocol!");
            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));
        }
    } else {
        ALOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
    }
    return fd;
}

2、TestService::instantiate()

这个会调用BinderService 的instantiate()函数,主要作用就是将TestService注册到ServiceManager里面,成为一个全局的service,service的名字如上面定义的"hxiong.test"。

rameworks/native/include/binder/BinderService.h

 

template<typename SERVICE>

class BinderService{

//在这里模版中的SERVICE 就是TestService类,所以publish里面创建了TestService的实例
  static status_t publish(bool allowIsolated = false) {
        sp<IServiceManager> sm(defaultServiceManager());
        return sm->addService(
                String16(SERVICE::getServiceName()),
                new SERVICE(), allowIsolated);
    }

   static void instantiate() { publish(); }
}

3、ProcessState::self()->startThreadPool()

创建启动线程池


4、IPCThreadState::self()->joinThreadPool();

IPCThreadState也是单例模式,一个进程中只有一个IPCThreadState实例,joinThreadPool ()的作用就是通过ioctl从binder driver读是数据,然后处理数据。

void IPCThreadState::joinThreadPool(bool isMain)
{
   
    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
    set_sched_policy(mMyThreadId, SP_FOREGROUND);
        
    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) {
            ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
                  mProcess->mDriverFD, result);
            abort();
        }
     
        if(result == TIMED_OUT && !isMain) {
            break;
        }
    } while (result != -ECONNREFUSED && result != -EBADF);
    
    mOut.writeInt32(BC_EXIT_LOOPER);
    talkWithDriver(false);
}

5、binder的server 端如何处理请求

调用IPCThreadState::joinThreadPool()后,就是让当前的线程(也就是我们常说的binder线程)等待client端发起的通信。


 1)IPCThreadState::takeWithDriver()

  这个可以当作是binder线程在调用revc,接收来自binderdriver返回的数据,binder线程会阻塞在这里。可以通过打印线程的调用栈就知道,连接adb 后,输入如下命令

C:\Users\hxiong>adb root

C:\Users\hxiong>adb shell
generic_x86_64:/ # ps | grep cameraserver
cameraserver 1292  1     21240  5788  binder_thr 00ffffe430 S /system/bin/camera
server
generic_x86_64:/ # debuggerd -b 1292
Sending request to dump task 1292.

----- pid 1292 at 2017-06-16 14:14:44 -----
Cmd line: /system/bin/cameraserver
ABI: 'x86'

"cameraserver" sysTid=1292
  #00 pc ffffe430  [vdso:ffffe000] (__kernel_vsyscall+16)
  #01 pc 0008a07c  /system/lib/libc.so (__ioctl+28)
  #02 pc 000251f1  /system/lib/libc.so (ioctl+42)
  #03 pc 000477e7  /system/lib/libbinder.so (_ZN7android14IPCThreadState14talkWithDriverEb+343)
  #04 pc 0004799a  /system/lib/libbinder.so (_ZN7android14IPCThreadState20getAndExecuteCommandEv+42)
  #05 pc 0004826f  /system/lib/libbinder.so (_ZN7android14IPCThreadState14joinThreadPoolEb+95)
  #06 pc 00000950  /system/bin/cameraserver
  #07 pc 00016bd6  /system/lib/libc.so (__libc_init+100)
  #08 pc 000007c2  /system/bin/cameraserver

"EmulatedCameraH" sysTid=1311
  #00 pc ffffe430  [vdso:ffffe000] (__kernel_vsyscall+16)
  #01 pc 0008b9ac  /system/lib/libc.so (read+28)
  #02 pc 00099880  /system/lib/libc.so (__read_chk+74)
  #03 pc 00019bb1  /system/lib/hw/camera.ranchu.so (_ZN7android27EmulatedCameraHotplugThread10threadLoopEv+625)
  #04 pc 00012095  /system/lib/libutils.so (_ZN7android6Thread11_threadLoopEPv+309)
  #05 pc 00011883  /system/lib/libutils.so (_ZN13thread_data_t10trampolineEPKS_+259)
  #06 pc 00086cdf  /system/lib/libc.so (_ZL15__pthread_startPv+190)
  #07 pc 00022f00  /system/lib/libc.so (__start_thread+25)
  #08 pc 00020766  /system/lib/libc.so (__bionic_clone+70)

"Binder:1292_1" sysTid=1574
  #00 pc ffffe430  [vdso:ffffe000] (__kernel_vsyscall+16)
  #01 pc 0008a07c  /system/lib/libc.so (__ioctl+28)
  #02 pc 000251f1  /system/lib/libc.so (ioctl+42)
  #03 pc 000477e7  /system/lib/libbinder.so (_ZN7android14IPCThreadState14talkWithDriverEb+343)
  #04 pc 0004799a  /system/lib/libbinder.so (_ZN7android14IPCThreadState20getAndExecuteCommandEv+42)
  #05 pc 0004826f  /system/lib/libbinder.so (_ZN7android14IPCThreadState14joinThreadPoolEb+95)
  #06 pc 0006edbe  /system/lib/libbinder.so (_ZN7android10PoolThread10threadLoopEv+46)
  #07 pc 00012095  /system/lib/libutils.so (_ZN7android6Thread11_threadLoopEPv+309)
  #08 pc 00011883  /system/lib/libutils.so (_ZN13thread_data_t10trampolineEPKS_+259)
  #09 pc 00086cdf  /system/lib/libc.so (_ZL15__pthread_startPv+190)
  #10 pc 00022f00  /system/lib/libc.so (__start_thread+25)
  #11 pc 00020766  /system/lib/libc.so (__bionic_clone+70)

"Binder:1292_2" sysTid=2167
  #00 pc ffffe430  [vdso:ffffe000] (__kernel_vsyscall+16)
  #01 pc 0008a07c  /system/lib/libc.so (__ioctl+28)
  #02 pc 000251f1  /system/lib/libc.so (ioctl+42)
  #03 pc 000477e7  /system/lib/libbinder.so (_ZN7android14IPCThreadState14talkWithDriverEb+343)
  #04 pc 0004799a  /system/lib/libbinder.so (_ZN7android14IPCThreadState20getAndExecuteCommandEv+42)
  #05 pc 0004826f  /system/lib/libbinder.so (_ZN7android14IPCThreadState14joinThreadPoolEb+95)
  #06 pc 0006edbe  /system/lib/libbinder.so (_ZN7android10PoolThread10threadLoopEv+46)
  #07 pc 00012095  /system/lib/libutils.so (_ZN7android6Thread11_threadLoopEPv+309)
  #08 pc 00011883  /system/lib/libutils.so (_ZN13thread_data_t10trampolineEPKS_+259)
  #09 pc 00086cdf  /system/lib/libc.so (_ZL15__pthread_startPv+190)
  #10 pc 00022f00  /system/lib/libc.so (__start_thread+25)
  #11 pc 00020766  /system/lib/libc.so (__bionic_clone+70)

----- end 1292 -----
generic_x86_64:/ #

通过上面的打印也看到了,binder线程会一直“阻塞”在takeWithDriver


2)IPCThreadState::executeCommand()

这个函数用于处理binder driver返回的数据,如果只考虑service端的处理,我们只需要看如下代码就可以了。

IPCThreadState::executeCommand()
case BR_TRANSACTION:
        {
            binder_transaction_data tr;
            result = mIn.read(&tr, sizeof(tr));
            ALOG_ASSERT(result == NO_ERROR,
                "Not enough command data for brTRANSACTION");
            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, this);
            
            const pid_t origPid = mCallingPid;
            const uid_t origUid = mCallingUid;
            const int32_t origStrictModePolicy = mStrictModePolicy;
            const int32_t origTransactionBinderFlags = mLastTransactionBinderFlags;

            mCallingPid = tr.sender_pid;
            mCallingUid = tr.sender_euid;
            mLastTransactionBinderFlags = tr.flags;

            int curPrio = getpriority(PRIO_PROCESS, mMyThreadId);
            if (gDisableBackgroundScheduling) {
                if (curPrio > ANDROID_PRIORITY_NORMAL) {
                    // We have inherited a reduced priority from the caller, but do not
                    // want to run in that state in this process.  The driver set our
                    // priority already (though not our scheduling class), so bounce
                    // it back to the default before invoking the transaction.
                    setpriority(PRIO_PROCESS, mMyThreadId, ANDROID_PRIORITY_NORMAL);
                }
            } else {
                if (curPrio >= ANDROID_PRIORITY_BACKGROUND) {
                    // We want to use the inherited priority from the caller.
                    // Ensure this thread is in the background scheduling class,
                    // since the driver won't modify scheduling classes for us.
                    // The scheduling group is reset to default by the caller
                    // once this method returns after the transaction is complete.
                    set_sched_policy(mMyThreadId, SP_BACKGROUND);
                }
            }

            //ALOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid);

            Parcel reply;
            status_t error;
            IF_LOG_TRANSACTIONS() {
                TextOutput::Bundle _b(alog);
                alog << "BR_TRANSACTION thr " << (void*)pthread_self()
                    << " / obj " << tr.target.ptr << " / code "
                    << TypeCode(tr.code) << ": " << indent << buffer
                    << dedent << endl
                    << "Data addr = "
                    << reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer)
                    << ", offsets addr="
                    << reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl;
            }
            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);
            }

            //ALOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n",
            //     mCallingPid, origPid, origUid);
            
            if ((tr.flags & TF_ONE_WAY) == 0) {
                LOG_ONEWAY("Sending reply to %d!", mCallingPid);
                if (error < NO_ERROR) reply.setError(error);
                sendReply(reply, 0);
            } else {
                LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
            }
            
            mCallingPid = origPid;
            mCallingUid = origUid;
            mStrictModePolicy = origStrictModePolicy;
            mLastTransactionBinderFlags = origTransactionBinderFlags;

            IF_LOG_TRANSACTIONS() {
                TextOutput::Bundle _b(alog);
                alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
                    << tr.target.ptr << ": " << indent << reply << dedent << endl;
            }
            
        }
        break;


其实我们只要关心下面这段代码就够了

  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);  
            }

error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,  &reply, tr.flags); 

这一行是怎么调到TestService 里面去的呢,注意(tr.cookie)其实就指向了TestService,我们在publish 注册这个service的时候,创建了这个实例。



不好意思,我又把这个图贴出来了,因为这个继承关键很重要,一定要看懂才行,不然会被绕晕的。

 error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer, &reply, tr.flags);

这段代码会调到 BBinder::transact(),然后调用onTransact()

status_t BBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    data.setDataPosition(0);

    status_t err = NO_ERROR;
    switch (code) {
        case PING_TRANSACTION:
            reply->writeInt32(pingBinder());
            break;
        default:
            err = onTransact(code, data, reply, flags);
            break;
    }

    if (reply != NULL) {
        reply->setDataPosition(0);
    }

    return err;
}

因为子类有重写onTransact(),所以会调用到BnTestService::onTransact()

status_t BnTestService::onTransact(  
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)  
{  
    switch(code) {  
        case TEST: {  
            CHECK_INTERFACE(ITestService, data, reply);  
            int api = data.readInt32();  
            int result=test(api);    //这里会调用到TestService 的test函数  
            reply->writeInt32(result);  
            return NO_ERROR;  
        }  
    }  
    return BBinder::onTransact(code, data, reply, flags);  
}  

最后通过switch   case 确定调用TestService 对应的函数。

---------------------------------------------------------------------------------------------------------------------------------------------------

分析完毕,欢迎评论...




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值