來點(diǎn)前奏說明
當(dāng)你打開這個(gè)文檔的時(shí)候侣监,你已經(jīng)做好準(zhǔn)備了鸭轮,話不多說開搞。
本文以Android 9.0 版本進(jìn)行分析橄霉,當(dāng)然你也可以在線看源碼
在線源碼查看
kernel_3.18 在線源碼
Android源碼下載編譯
9.0源碼下載鏈接 提取碼:d0ks
在此特別說明窃爷,這篇文檔參考了很多文章和視頻,主要自己記錄一下,有些我也不明白按厘。
產(chǎn)生Binder原因:
- 為了多進(jìn)程間的通信
進(jìn)程間通訊為什么選擇使用Binder:
- 性能上:Binder相對(duì)出傳統(tǒng)的Socket方式医吊,更加高效。Binder數(shù)據(jù)拷貝只需要一次逮京,而管道卿堂、消息隊(duì)列、Socket都需要2次
- 安全方面:Binder機(jī)制從協(xié)議本身就支持對(duì)通信雙方做身份校檢懒棉,因而大大提升了安全性草描。
Binder是什么:
- 從IPC角度說:它是Android中一種跨進(jìn)程通信方式,是Android獨(dú)有的
- App層:它是客戶端和服務(wù)端進(jìn)行通信的媒介策严,當(dāng)bindService時(shí)候穗慕,服務(wù)端返回一個(gè)包含了服務(wù)器端業(yè)務(wù)調(diào)用的Binder對(duì)象,通過這個(gè)對(duì)象妻导,客戶端可以獲取服務(wù)端提供的服務(wù)或者數(shù)據(jù)揍诽,這里的服務(wù)包括普通服務(wù)和基于AIDL的服務(wù)。
- Framework層:它是各種Manager(ActivityManager/WindowManager等)和XxxManagerService(ActivityManagerService/WindowManagerService等)的橋梁栗竖。
- Native層:它是創(chuàng)建Service Manager以及BpBinder/BBinder模型,搭建和Kernel層的橋梁渠啤。
- Kernel層:它提供了最底層的數(shù)據(jù)傳遞狐肢、對(duì)象標(biāo)識(shí)、線程管理沥曹、調(diào)用過程控制等功能份名。驅(qū)動(dòng)層是整個(gè)Binder機(jī)制的核心。它還可以理解為一種虛擬的數(shù)據(jù)設(shè)備妓美,它的設(shè)備驅(qū)動(dòng)是別dev/binder
核心類圖
核心類圖
Binder架構(gòu)
Binder架構(gòu)圖
源碼分析
Framework層
frameworks/base/core/jni/AndroidRuntime.cpp的start方法開始
/*
* Start the Android runtime. This involves starting the virtual machine
* and calling the "static void main(String[] args)" method in the class
* named by "className".
*
* Passes the main function two arguments, the class name and the specified
* options string.
*/
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
ALOGD(">>>>>> START %s uid %d <<<<<<\n",
className != NULL ? className : "(unknown)", getuid());
static const String8 startSystemServer("start-system-server");
/*
* 'startSystemServer == true' means runtime is obsolete and not run from
* init.rc anymore, so we print out the boot start event here.
*/
for (size_t i = 0; i < options.size(); ++i) {
if (options[i] == startSystemServer) {
/* track our progress through the boot sequence */
const int LOG_BOOT_PROGRESS_START = 3000;
LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
}
}
const char* rootDir = getenv("ANDROID_ROOT");
if (rootDir == NULL) {
rootDir = "/system";
if (!hasDir("/system")) {
LOG_FATAL("No root directory specified, and /android does not exist.");
return;
}
setenv("ANDROID_ROOT", rootDir, 1);
}
//const char* kernelHack = getenv("LD_ASSUME_KERNEL");
//ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
onVmCreated(env);
/*
* Register android functions.
*/
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
/*
* We want to call main() with a String array with arguments in it.
* At present we have two arguments, the class name and an option string.
* Create an array to hold them.
*/
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;
stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);
strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
assert(strArray != NULL);
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr);
for (size_t i = 0; i < options.size(); ++i) {
jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
assert(optionsStr != NULL);
env->SetObjectArrayElement(strArray, i + 1, optionsStr);
}
/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
char* slashClassName = toSlashClassName(className != NULL ? className : "");
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
free(slashClassName);
ALOGD("Shutting down VM\n");
if (mJavaVM->DetachCurrentThread() != JNI_OK)
ALOGW("Warning: unable to detach main thread\n");
if (mJavaVM->DestroyJavaVM() != 0)
ALOGW("Warning: VM did not shut down cleanly\n");
}
startReg 在Android系統(tǒng)開機(jī)過程中僵腺,Zygote啟動(dòng)會(huì)有一個(gè)虛擬機(jī)注冊(cè)過程,該過程調(diào)用了該方法完成了jni的注冊(cè)
/*
* Register android native functions with the VM.
*/
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
ATRACE_NAME("RegisterAndroidNatives");
/*
* This hook causes all future threads created in this process to be
* attached to the JavaVM. (This needs to go away in favor of JNI
* Attach calls.)
*/
androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
ALOGV("--- registering native functions ---\n");
/*
* Every "register" function calls one or more things that return
* a local reference (e.g. FindClass). Because we haven't really
* started the VM yet, they're all getting stored in the base frame
* and never released. Use Push/Pop to manage the storage.
*/
env->PushLocalFrame(200);
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
env->PopLocalFrame(NULL);
return -1;
}
env->PopLocalFrame(NULL);
//createJavaThread("fubar", quickTest, (void*) "hello");
return 0;
}
Native層(System Manager)
1 壶栋、啟動(dòng)Service Manager時(shí)序圖
啟動(dòng)Service Manager時(shí)序圖
- 啟動(dòng)大致從 frameworks/native/cmds/service_manager.c這個(gè)文件開始
- main方法開始
- binder_open 打開binder驅(qū)動(dòng)
- binder_become_context_manager 注冊(cè)成為binder服務(wù)
- binder_loop 進(jìn)入無限循環(huán)辰如,處理客戶client端發(fā)來的請(qǐng)求
int main(int argc, char** argv)
{
struct binder_state *bs;
union selinux_callback cb;
char *driver;
if (argc > 1) {
driver = argv[1];
} else {
driver = "/dev/binder";
}
bs = binder_open(driver, 128*1024);
if (!bs) {
#ifdef VENDORSERVICEMANAGER
ALOGW("failed to open binder driver %s\n", driver);
while (true) {
sleep(UINT_MAX);
}
#else
ALOGE("failed to open binder driver %s\n", driver);
#endif
return -1;
}
if (binder_become_context_manager(bs)) {
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
cb.func_audit = audit_callback;
selinux_set_callback(SELINUX_CB_AUDIT, cb);
cb.func_log = selinux_log_callback;
selinux_set_callback(SELINUX_CB_LOG, cb);
#ifdef VENDORSERVICEMANAGER
sehandle = selinux_android_vendor_service_context_handle();
#else
sehandle = selinux_android_service_context_handle();
#endif
selinux_status_open(true);
if (sehandle == NULL) {
ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n");
abort();
}
if (getcon(&service_manager_context) != 0) {
ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");
abort();
}
binder_loop(bs, svcmgr_handler);
return 0;
}
2、獲取Service Manager時(shí)序圖
獲取Service Manager時(shí)序圖
- 獲取Service Manager大致從 frameworks/native/libs/binder/IServiceManager.cpp 這個(gè)文件開始
sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
{
AutoMutex _l(gDefaultServiceManagerLock);
while (gDefaultServiceManager == NULL) {
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(NULL));
if (gDefaultServiceManager == NULL)
sleep(1);
}
}
return gDefaultServiceManager;
}
- frameworks/native/libs/binder/ProcessState.cpp
ProcessState::self()獲取ProcessState單例對(duì)象贵试,每個(gè)進(jìn)程有且只有一個(gè)ProcessState對(duì)象琉兜,存在則返回,否則就創(chuàng)建毙玻。
sp<ProcessState> ProcessState::self()
{
Mutex::Autolock _l(gProcessMutex);
if (gProcess != NULL) {
return gProcess;
}
gProcess = new ProcessState("/dev/binder");
return gProcess;
}
getContextObject() 用于獲取BpBinder對(duì)象豌蟋,對(duì)于handle=0的BpBinder對(duì)象,存在就返回否則創(chuàng)建
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
return getStrongProxyForHandle(0);
}
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL) {
// We need to create a new BpBinder if there isn't currently one, OR we
// are unable to acquire a weak reference on this current one. See comment
// in getWeakProxyForHandle() for more info about this.
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
if (handle == 0) {
// Special case for context manager...
// The context manager is the only object for which we create
// a BpBinder proxy without already holding a reference.
// Perform a dummy transaction to ensure the context manager
// is registered before we create the first local reference
// to it (which will occur when creating the BpBinder).
// If a local reference is created for the BpBinder when the
// context manager is not present, the driver will fail to
// provide a reference to the context manager, but the
// driver API does not return status.
//
// Note that this is not race-free if the context manager
// dies while this code runs.
//
// TODO: add a driver API to wait for context manager, or
// stop special casing handle 0 for context manager and add
// a driver API to get a handle to the context manager with
// proper reference counting.
Parcel data;
status_t status = IPCThreadState::self()->transact(
0, IBinder::PING_TRANSACTION, data, NULL, 0);
if (status == DEAD_OBJECT)
return NULL;
}
b = BpBinder::create(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
// This little bit of nastyness is to allow us to add a primary
// reference to the remote proxy when this team doesn't have one
// but another team is sending the handle to us.
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}
3桑滩、注冊(cè)服務(wù)(對(duì)照架構(gòu)圖1.注冊(cè)服務(wù))
注冊(cè)服務(wù).jpg
- 注冊(cè)服務(wù)大致從 frameworks/native/libs/binder/IServiceManager.cpp 這個(gè)文件開始分析
virtual status_t addService(const String16& name, const sp<IBinder>& service,
bool allowIsolated, int dumpsysPriority) {
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
data.writeStrongBinder(service);
data.writeInt32(allowIsolated ? 1 : 0);
data.writeInt32(dumpsysPriority);
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
Kernel層:
- 大致從 kernel3.18/driver/staging/android/binder.c 這個(gè)文件分析
- binder_init 驅(qū)動(dòng)設(shè)備初始化方法
- binder_open 打開binder驅(qū)動(dòng)設(shè)備
- binder_mmap 實(shí)現(xiàn)用戶空間Buffer和內(nèi)存空間的Buffer 同步操作梧疲。在內(nèi)存虛擬地址空間,申請(qǐng)一塊與用戶虛擬內(nèi)存相同大小的內(nèi)存;再申請(qǐng)一個(gè)page大小的物理內(nèi)存幌氮,將同一塊物理內(nèi)存分別映射到內(nèi)存虛擬地址空間和用戶虛擬空間去實(shí)現(xiàn)的缭受。
- binder_ioctl 數(shù)據(jù)操作