音视频学习阶段(二)Binder native 源码学习(二)

70 阅读4分钟

上一篇文章 音视频学习阶段(二)Binder native 源码学习(一)

关于 Binder 的学习过程中有一些概念需要重点介绍一下

1:ProcessState 单例对象,每个进程仅有一个

2:handle_entry 记录了所有binder 的指针,非常重要的代理类的核心

3: IPCThreadState 在Android中,每个参与Binder通信的线程都会有一个 IPCThreadState 实例与之关联。

并且在上一篇文章中也提到过 IPCThreadState 的这么一方法

status_t status = IPCThreadState::self()->transact( 0, IBinder::PING_TRANSACTION, data, nullptr, 0);

,用来验证Context Manager 的状态 ,从这里将 IPCThreadState::self 与 IPCThreadState 的创建联系起来就非常清楚了,

IPCThreadState* IPCThreadState::self()
{
   if (gHaveTLS.load(std::memory_order_acquire)) {
restart:
       const pthread_key_t k = gTLS;
       IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
       if (st) return st;
       return new IPCThreadState;
   }

   // Racey, heuristic test for simultaneous shutdown.
   if (gShutdown.load(std::memory_order_relaxed)) {
       return nullptr;
   }

   pthread_mutex_lock(&gTLSMutex);
   if (!gHaveTLS.load(std::memory_order_relaxed)) {
       int key_create_value = pthread_key_create(&gTLS, threadDestructor);
       if (key_create_value != 0) {
           pthread_mutex_unlock(&gTLSMutex);
           return nullptr;
       }
       gHaveTLS.store(true, std::memory_order_release);
   }
   pthread_mutex_unlock(&gTLSMutex);
   goto restart;
}

调用 IPCThreadState 的self 先价差 gHaveTLS.load(std::memory_order_acquire) 是否存在,如果当前线程没有与binder 建立过链接,那么肯定是不存在的,走到下面会在 pthread 中写入 &gTLS, threadDestructor,并提交store 并尝试重新 gHaveTLS.load(std::memory_order_acquire),如果可以就从线程中获取 IPCThreadState ,获取到了就返回,获取不到就创建

上一篇文章将 分析了前面2段的代码

sp<ProcessState> proc(ProcessState::self()); // 获取一个 ServiceManager 0 这个级别就代表的是 
ServiceManager sp<IServiceManager> sm(defaultServiceManager());

接下来我们继续分析

int main(int argc __unused, char **argv __unused)
{
    signal(SIGPIPE, SIG_IGN);
    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager> sm(defaultServiceManager());
    ALOGI("ServiceManager: %p", sm.get());
    AIcu_initializeIcuOrDie();
    MediaPlayerService::instantiate();
    ResourceManagerService::instantiate();
    registerExtensions();
    ::android::hardware::configureRpcThreadpool(16, false);
    // 重要方法  创建线程池 ,上面的应该是和服务有关,在分析binder 的过程中暂不分析
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
    ::android::hardware::joinRpcThreadpool();
}

接下来要分析的方法是 ProcessState::self()->startThreadPool(); 这个方法是创建与 Binder 链接的线程池的方法,下面来具体分析一下

void ProcessState::startThreadPool()
{
    AutoMutex _l(mLock);
    if (!mThreadPoolStarted) {
        mThreadPoolStarted = true;
        spawnPooledThread(true);
    }
}

同步调用了 spawnPooledThread 这个方法

void ProcessState::spawnPooledThread(bool isMain)
{
    if (mThreadPoolStarted) {
        String8 name = makeBinderThreadName();
        ALOGV("Spawning new pooled thread, name=%s\n", name.string());
        sp<Thread> t = new PoolThread(isMain);
        t->run(name.string());
    }
}

在这个里面创建了 PoolThread 线程池 ,再来分析一下 PoolThread 的构造方法

class PoolThread : public Thread
{
public:
    explicit PoolThread(bool isMain)
        : mIsMain(isMain)
    {
    }

protected:
    virtual bool threadLoop()
    {
        IPCThreadState::self()->joinThreadPool(mIsMain);
        return false;
    }

    const bool mIsMain;
};

整个 PoolThread 句非常的简单

回到main_mediaserver.cpp 中继续分析

int main(int argc __unused, char **argv __unused)
{
    signal(SIGPIPE, SIG_IGN);

    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager> sm(defaultServiceManager());
    ALOGI("ServiceManager: %p", sm.get());
    AIcu_initializeIcuOrDie();
    MediaPlayerService::instantiate();
    ResourceManagerService::instantiate();
    registerExtensions();
    ::android::hardware::configureRpcThreadpool(16, false);
    ProcessState::self()->startThreadPool();
    // 接下来就是这里了
    IPCThreadState::self()->joinThreadPool();
    ::android::hardware::joinRpcThreadpool();
}

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

//isMain=true。代表是主线程。
void IPCThreadState::joinThreadPool(bool isMain)
{
  //isMain=true。代表是主线程。
  //BC_ENTER_LOOPER发送给binderDriver后,binderDriver确认能否启动线程,如果不能会报error?   
  //isMain=false。代表是普通的binder线程。
  // BC_REGISTER_LOOPER发送给binderDriver后,binderDriver会确认能否启动线程,如果不能会报error
   mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
   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) {
           LOG_ALWAYS_FATAL("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
                 mProcess->mDriverFD, result);
       }

       // 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=%d\n",
       (void*)pthread_self(), getpid(), result);

   mOut.writeInt32(BC_EXIT_LOOPER);
   talkWithDriver(false);
}

到了这里就是向 binder 写指令了 ,而且还是一个dowhile 循环向里面写的,到了这里才是 binder 的所有准备才算完成,

关于代码逻辑我已经整理了,但是这个里面还涉及到非常多的 IPC 的知识,并不是这一点点代码能提供的, 网上有非常多的博客 写的都非常的好 传送门,大家可以阅读一下,将这个体系连贯起来,

在FrameWork Binder 相关的内容中,分析了他的流程,是在 SystemServer 的启动过程中,启动的各个服务,然后各个服务在启动后,将自身添加到了SystemServiceManager 来管理的,依照这个流程,我们现在已经打开了了binder驱动,并且已经创建好了 BpBinder ,下一步的流程大概就是向管理器中注册自己,这段代码就在

    MediaPlayerService::instantiate();

看一下他的具体的逻辑 ServiceManager

void MediaPlayerService::instantiate() {
    defaultServiceManager()->addService(
            String16("media.player"), new MediaPlayerService());
}

在 ServiceManagerShim 但是创建 ServiceManagerShim 又传了一个 impl ,没找到 真是崩溃

status_t ServiceManagerShim::addService(const String16& name, const sp<IBinder>& service,
                                        bool allowIsolated, int dumpsysPriority)
{
    Status status = mTheRealServiceManager->addService(
        String8(name).c_str(), service, allowIsolated, dumpsysPriority);
    return status.exceptionCode();
}