博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android Binder机制(二) ------- 服务的实现
阅读量:4677 次
发布时间:2019-06-09

本文共 9698 字,大约阅读时间需要 32 分钟。

服务分析

所谓服务,简单点就是不断的监听客户端的请求,然后处理并向客户端返回处理的结果。要实现这一功能,至少需要以下几点:

  • 循环,我们的服务就是一个大循环,不断的监听客户发来的请求。(线程循环)
  • 通讯,要与客户端通讯(Binder机制)

我们以SurfaceFlinger服务为例来介绍一下Binder服务的实现流程。

SurfaceFlinger介绍

  • SurfaceFlinger是显示系统中一个重要的服务,它管理底层的显示设备以及上层的图层。应用画先的图层交由SurfaceFlinger合成,最终提交给显示设备显示。
  • SurfaceFlinger源码在frameworks/native/services/surfaceflinger目录中
  • SurfaceFlinger在init.rc中启动,其入口在main_surfaceflinger.cpp文件的main函数中

服务的具体代码分析

从main_surfaceflinger.cpp的main函数入手,来看看这个过程

int main(int, char**) {    // When SF is launched in its own process, limit the number of    // binder threads to 4.    ProcessState::self()->setThreadPoolMaxThreadCount(4);    // start the thread pool    sp
ps(ProcessState::self()); ps->startThreadPool(); // instantiate surfaceflinger sp
flinger = new SurfaceFlinger(); setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY); set_sched_policy(0, SP_FOREGROUND); // initialize before clients can connect flinger->init(); // publish surface flinger sp
sm(defaultServiceManager()); sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false); // run in this thread flinger->run(); return 0;}

此函数即包含了服务的实现,也包含了服务的注册。我们先说实现,注册放在后面。与实现有关的两句代码如下

sp
ps(ProcessState::self()); ps->startThreadPool();

ProcessState为单例类,看看它的构造函数

ProcessState::ProcessState()    : mDriverFD(open_driver())    , mVMStart(MAP_FAILED)    , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)    , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)    , mExecutingThreadsCount(0)    , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)    , mManagesContexts(false)    , mBinderContextCheckFunc(NULL)    , mBinderContextUserData(NULL)    , mThreadPoolStarted(false)    , mThreadPoolSeq(1){               if (mDriverFD >= 0) {        // XXX Ideally, there should be a specific define for whether we        // have mmap (or whether we could possibly have the kernel module        // availabla).#if !defined(HAVE_WIN32_IPC)        // mmap the binder, providing a chunk of virtual address space to receive transactions.        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);        if (mVMStart == MAP_FAILED) {            // *sigh*            ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");            close(mDriverFD);            mDriverFD = -1;        }#else        mDriverFD = -1;#endif    }    LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened.  Terminating.");}
  • 通过open_driver函数打开Binder驱动,并把文件句柄返回给成员变量mDriverFD
  • 初始化其它成员变量
static int open_driver(){    int fd = open("/dev/binder", O_RDWR);    if (fd >= 0) {        fcntl(fd, F_SETFD, FD_CLOEXEC);        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;}
  • 通过open函数打开Binder设备文件
  • 通过ioctl函数操作设备文件,查询Binder驱动版本、协议版本、设置最大线程数

ProcessState的构造函数就大致分析完了。回到前面startThreadPool函数

void ProcessState::startThreadPool(){    AutoMutex _l(mLock);    if (!mThreadPoolStarted) {        mThreadPoolStarted = true;        spawnPooledThread(true);    }}
  • 这个函数主要调用spawnPooledThread方法
  • 由于mThreadPoolStarted 变量的控制,spawnPooledThread方法只会在初始调用时执行
void ProcessState::spawnPooledThread(bool isMain){    if (mThreadPoolStarted) {        String8 name = makeBinderThreadName();        ALOGV("Spawning new pooled thread, name=%s\n", name.string());        sp
t = new PoolThread(isMain); t->run(name.string()); }}

创建一个PoolThread的线程对象,并启动线程。看看PoolThread的类定义

class PoolThread : public Thread{public:    PoolThread(bool isMain)        : mIsMain(isMain)    {    }protected:    virtual bool threadLoop()    {        IPCThreadState::self()->joinThreadPool(mIsMain);        return false;    }    const bool mIsMain;};
  • PoolThread 继承于Thread类
  • 线程执行函数主要是创建一个IPCThreadState的线程对象,并把本线程加入到线程池。
void IPCThreadState::joinThreadPool(bool isMain){    LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);            // This thread may have been spawned by a thread that was in the background    // scheduling group, so first we will make sure it is in the foreground    // one to avoid performing an initial transaction in the background.    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();        }                                                // 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=%p\n",        (void*)pthread_self(), getpid(), (void*)result);        mOut.writeInt32(BC_EXIT_LOOPER);    talkWithDriver(false);}
  • 这个函数里面就有一个循环,这就是我们前面提到的线程循环,在该循环里不断读取客户端发来的请求,并将请求派发给对应的服务类去处理
  • 循环里的关键函数为getAndExecuteCommand,该函数读取Binder驱动里的数据并处理相应请求
status_t IPCThreadState::getAndExecuteCommand(){    status_t result;    int32_t cmd;    result = talkWithDriver();    if (result >= NO_ERROR) {        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++;        pthread_mutex_unlock(&mProcess->mThreadCountLock);        result = executeCommand(cmd);        pthread_mutex_lock(&mProcess->mThreadCountLock);        mProcess->mExecutingThreadsCount--;        pthread_cond_broadcast(&mProcess->mThreadCountDecrement);        pthread_mutex_unlock(&mProcess->mThreadCountLock);        // After executing the command, ensure that the thread is returned to the        // foreground cgroup before rejoining the pool.  The driver takes care of        // restoring the priority, but doesn't do anything with cgroups so we        // need to take care of that here in userspace.  Note that we do make        // sure to go in the foreground after executing a transaction, but        // there are other callbacks into user code that could have changed        // our group so we want to make absolutely sure it is put back.        set_sched_policy(mMyThreadId, SP_FOREGROUND);    }    return result;}
  • talkWithDriver获取Binder设备文件句柄mDriverFD,并调用ioctl的BINDER_WRITE_READ命令读取驱动中客户端发来的请求
  • executeCommand处理请求,并将结果写入成员变量mOut中,等待返回给驱动
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:        {            ......            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
( tr.target.ptr)->attemptIncStrong(this)) { error = reinterpret_cast
(tr.cookie)->transact(tr.code, buffer, &reply, tr.flags); reinterpret_cast
(tr.cookie)->decStrong(this); } else { error = UNKNOWN_TRANSACTION; } } else { error = the_context_object->transact(tr.code, buffer, &reply, tr.flags); } ...... } break; ...... default: printf("*** BAD COMMAND %d received from Binder driver\n", cmd); result = UNKNOWN_ERROR; break; } if (result != NO_ERROR) { mLastError = result; } return result;}

这个函数有点多,我们看下BR_TRANSACTION,从binder_transaction_data变量tr中获取Binder实体对象指针BBinder*,然后调用其transact函数。BBinder的transact函数实现如下:

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函数
  • onTransact为虚函数,所以最终会调用子类的onTransact数据,即对应的服务实体对象的onTransact。并且onTransact会根据传入的code在去调用具体的服务成员函数去处理请求,并把请求封装返到reply变量中,通过talkWithDriver函数最终返回给Binder驱动。

这样服务从启动,监听客户端的请求,返回处理结果整个过程大致走完了。

转载于:https://www.cnblogs.com/qzhang1535/p/8639824.html

你可能感兴趣的文章
用分布式缓存提升ASP.NET Core性能
查看>>
Spring+EhCache缓存实例(具体解说+源代码下载)
查看>>
JavaScript 中的所有数据都是以 64 位浮点型数据(float) 来存储。浮点型数据使用注意事项。全局变量特殊之处...
查看>>
170427、centos6.5配置duboo
查看>>
在花旗的几点体会
查看>>
backbone showcase
查看>>
【js基础修炼之路】— 浅谈this关键字
查看>>
[MySQL FAQ]系列 -- mysql如何计算打开文件数
查看>>
《数据结构》相关题目
查看>>
Codeforces Round #431 (Div. 2) A 水 B 暴力模拟 C 思维
查看>>
php-fpm 进程管理
查看>>
nginx相关知识
查看>>
[linux-内核][转]内核日志及printk结构浅析
查看>>
实变函数基本理论及其应用
查看>>
JAVA操作properties文件
查看>>
JavaScript读书笔记
查看>>
值传递和引用传递
查看>>
NLTK中文语料库sinica_treebank
查看>>
LightGBM 调参方法(具体操作)
查看>>
通过sqlalchemy操作mysql
查看>>