frameworks 之BInder启动
- 调用 AppRuntime
- 打开驱动 内存映射 ProcessState
- PoolThread 开启 Binder 消息
进程在fork 的时候会初始化并启动对应的 Binder。
涉及到的类如下
- frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
- frameworks/base/core/jni/include/android_runtime/AndroidRuntime.h
- frameworks/base/core/jni/AndroidRuntime.cpp
- frameworks/base/cmds/app_process/app_main.cpp
- frameworks/native/libs/binder/ProcessState.cpp
- frameworks/native/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
- frameworks/native/libs/binder/IPCThreadState.cpp
调用 AppRuntime
创建进程时候会执行 zygoteInit 方法,该方法会调用对应的 nativeZygoteInit
public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,String[] argv, ClassLoader classLoader) {if (RuntimeInit.DEBUG) {Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");}Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");RuntimeInit.redirectLogStreams();RuntimeInit.commonInit();// 这里启动BinderZygoteInit.nativeZygoteInit();return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,classLoader);}// c++ 方法private static native void nativeZygoteInit();
查看 nativeZygoteInit 实现(位于 AndroidRuntime.cpp ),通过变量调用 onZygoteInit。该方法和gCurRuntime 变量为 静态方法和静态变量, 其中 变量初始化为
AppRuntime 的 main 方法初始化,AppRuntime 继承 AndroidRuntime, 初始化时候会将 this 赋值给 gCurRuntime。
// frameworks/base/core/jni/AndroidRuntime.cpp
static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{gCurRuntime->onZygoteInit();
}
// 初始化变量 gCurRuntime
AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :mExitWithoutCleanup(false),mArgBlockStart(argBlockStart),mArgBlockLength(argBlockLength)
{init_android_graphics();// Pre-allocate enough space to hold a fair number of options.mOptions.setCapacity(20);assert(gCurRuntime == NULL); // one per processgCurRuntime = this;
}
// frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])
{if (!LOG_NDEBUG) {String8 argv_String;for (int i = 0; i < argc; ++i) {argv_String.append("\"");argv_String.append(argv[i]);argv_String.append("\" ");}ALOGV("app_process main with argv: %s", argv_String.string());}// 初始化 AppRuntime ,该方法会初始化 gCurRuntimeAppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));// Process command line arguments// ignore argv[0]argc--;argv++;
}
打开驱动 内存映射 ProcessState
因为变量其实是子类 AppRuntime, 所以 onZygoteInit 方法实际就是由 AppRuntime 实现,查看对应的代码。 该代码调用对应的 ProcessState::self 静态方法。
// frameworks/base/cmds/app_process/app_main.cppvirtual void onZygoteInit(){sp<ProcessState> proc = ProcessState::self();ALOGV("App process: starting thread pool.\n");proc->startThreadPool();}
查看 self 方法, 该方法调用 Init 方法, 而 init 方法主要通过 make 方法初始化 ProcessState 变量。第一参数为 BInder 驱动,
// frameworks/native/libs/binder/ProcessState.cpp
// 驱动名称
#ifdef __ANDROID_VNDK__
const char* kDefaultDriver = "/dev/vndbinder";
#else
const char* kDefaultDriver = "/dev/binder";
#endifsp<ProcessState> ProcessState::self()
{return init(kDefaultDriver, false /*requireDefault*/);
}sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault)
{[[clang::no_destroy]] static sp<ProcessState> gProcess;[[clang::no_destroy]] static std::mutex gProcessMutex;if (driver == nullptr) {std::lock_guard<std::mutex> l(gProcessMutex);return gProcess;}[[clang::no_destroy]] static std::once_flag gProcessOnce;std::call_once(gProcessOnce, [&](){if (access(driver, R_OK) == -1) {ALOGE("Binder driver %s is unavailable. Using /dev/binder instead.", driver);driver = "/dev/binder";}std::lock_guard<std::mutex> l(gProcessMutex);// 生成 processState,传入驱动 该方法来自 gProcess = sp<ProcessState>::make(driver);});if (requireDefault) {// Detect if we are trying to initialize with a different driver, and// consider that an error. ProcessState will only be initialized once above.LOG_ALWAYS_FATAL_IF(gProcess->getDriverName() != driver,"ProcessState was already initialized with %s,"" can't initialize with %s.",gProcess->getDriverName().c_str(), driver);}return gProcess;
}
make 为 binder_interface_utils.h 的泛型 方法。
// frameworks/native/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
static std::shared_ptr<T> make(Args&&... args) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"// 创建变量T* t = new T(std::forward<Args>(args)...);
#pragma clang diagnostic pop// warning: Potential leak of memory pointed to by 't' [clang-analyzer-unix.Malloc]return t->template ref<T>(); // NOLINT(clang-analyzer-unix.Malloc)}
查看对应的ProcessState 构造方法,在构造方法内 打开 Binder 驱动,在通过 mmap 映射内存。通过上面的传进来的驱动参数 通过 open_driver 打开驱动,里面调用 open方法打开驱动, 并返回文件描述符, 里面还会设置最大线程数,后续通过 ioctl 跟驱动交互。
BINDER_VM_SIZE 定义了内存大小,_SC_PAGE_SIZE 为内存片大小一般为1024 这就是 1M - 4k 的由来。mmap 传入大小参数 进行映射对应的内存。
// frameworks/native/libs/binder/ProcessState.cpp
// 内存大小
#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
// 最大线程数
#define DEFAULT_MAX_BINDER_THREADS 15
// 打开驱动
static int open_driver(const char *driver)
{// 打开驱动int fd = open(driver, O_RDWR | O_CLOEXEC);if (fd >= 0) {int vers = 0;// 告诉binder驱动版本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(%d) does not match user space protocol(%d)! ioctl() return value: %d",vers, BINDER_CURRENT_PROTOCOL_VERSION, result);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));}uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);if (result == -1) {ALOGD("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));}} else {ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));}// 返回文件描述符return fd;
}ProcessState::ProcessState(const char *driver): mDriverName(String8(driver))// 打开驱动, mDriverFD(open_driver(driver)), mVMStart(MAP_FAILED), mThreadCountLock(PTHREAD_MUTEX_INITIALIZER), mThreadCountDecrement(PTHREAD_COND_INITIALIZER), mExecutingThreadsCount(0), mWaitingForThreads(0), mMaxThreads(DEFAULT_MAX_BINDER_THREADS), mStarvationStartTimeMs(0), mThreadPoolStarted(false), mThreadPoolSeq(1), mCallRestriction(CallRestriction::NONE)
{if (mDriverFD >= 0) {// mmap the binder, providing a chunk of virtual address space to receive transactions.// 映射对应的内存mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);if (mVMStart == MAP_FAILED) {// *sigh*ALOGE("Using %s failed: unable to mmap transaction memory.\n", mDriverName.c_str());close(mDriverFD);mDriverFD = -1;mDriverName.clear();}}#ifdef __ANDROID__LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver '%s' could not be opened. Terminating.", driver);
#endif
}
创建完 ProcessState 后,调用 startThreadPool 方法,里面又继续调用 spawnPooledThread 方法。
void ProcessState::startThreadPool()
{AutoMutex _l(mLock);if (!mThreadPoolStarted) {mThreadPoolStarted = true;spawnPooledThread(true);}
}
spawnPooledThread 方法又生成了 PoolThread 对象
void ProcessState::spawnPooledThread(bool isMain)
{if (mThreadPoolStarted) {// 生成 binder线程名称。String8 name = makeBinderThreadName();ALOGV("Spawning new pooled thread, name=%s\n", name.string());// 将 isMain 构造参数传入地址,为truesp<Thread> t = sp<PoolThread>::make(isMain);t->run(name.string());}
}
PoolThread 开启 Binder 消息
PoolThread 继承于 Thread 。不了解 Thread 可以查看该文章 ,从上面知道 make 生成对应的 PoolThread 对象。所以调用 run 方法 则会执行 threadLoop 方法。
class PoolThread : public Thread
{
public:explicit PoolThread(bool isMain): mIsMain(isMain){}protected:// 调用 run 会执行virtual bool threadLoop(){IPCThreadState::self()->joinThreadPool(mIsMain);return false;}const bool mIsMain;
};
首先则会执行 self 静态方法, 该方法会从一个 pthread_getspecific 类似 key value 的结构获取,如果获取到 则立即返回。 否则构造一个新的变量。第一次为 false 不会进入先进入下面 在通过 goto restart 重新获取 pthread_key_create 创建对应的key。可以看出每个binder线程只有一个 IPCThreadState 。
IPCThreadState* IPCThreadState::self()
{// 第一次为 false 不会进入先进入下面 在通过 goto restart 重新获取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)) {ALOGW("Calling IPCThreadState::self() during shutdown is dangerous, expect a crash.\n");return nullptr;}pthread_mutex_lock(&gTLSMutex);if (!gHaveTLS.load(std::memory_order_relaxed)) {// threadDestructor 方法生成对应的对象。// 创建一个 Keyint key_create_value = pthread_key_create(&gTLS, threadDestructor);if (key_create_value != 0) {pthread_mutex_unlock(&gTLSMutex);ALOGW("IPCThreadState::self() unable to create TLS key, expect a crash: %s\n",strerror(key_create_value));return nullptr;}gHaveTLS.store(true, std::memory_order_release);}pthread_mutex_unlock(&gTLSMutex);goto restart;
}
查看 IPCThreadState 的构造方法,可以看到初始化一些变量,并放进去对应的缓存中 pthread_setspecific
IPCThreadState::IPCThreadState(): mProcess(ProcessState::self()),mServingStackPointer(nullptr),mWorkSource(kUnsetWorkSource),mPropagateWorkSource(false),mIsLooper(false),mIsFlushing(false),mStrictModePolicy(0),mLastTransactionBinderFlags(0),mCallRestriction(mProcess->mCallRestriction) {// 放进对应的 缓存中pthread_setspecific(gTLS, this);clearCaller();mIn.setDataCapacity(256);mOut.setDataCapacity(256);
}
通过 self 创建完 IPCThreadState 后则调用 joinThreadPool 方法。该方法开启了while 循环,让线程进入到循环中,等待命令,解析命令,给出响应。
void IPCThreadState::joinThreadPool(bool isMain)
{LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());// // isMain为true 所以会给驱动发送一个BC_ENTER_LOOPER 进入循环命令mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);mIsLooper = true;status_t result;do {processPendingDerefs();// now get the next command to be processed, waiting if necessaryresult = 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);mIsLooper = false;talkWithDriver(false);
}
这样就完成了 Binder 启动。