binder的jni方法注册
1.zygote启动
1-1.启动zygote进程
zygote是由init进程通过解析 init.zygote.rc 文件而创建的,zygote所对应的可执行程序 app_process,所对应的源文件是 app_main.cpp ,进程名为zygote
// system/core/rootdir/init.zygote32.rc
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --startsystem-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
writepid /dev/cpuset/foreground/tasks
1-2.执行app_main.cpp 中的main方法
int main(int argc, char* const argv[])
{
...
if (!className.isEmpty()) {
runtime.setClassNameAndArgs(className, argc - i, argv + i);
} else {
// We're in zygote mode.
maybeCreateDalvikCache();
//启动
if (startSystemServer) {
args.add(String8("start-system-server"));
}
...
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string());
set_process_name(niceName.string());
}
...
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
}
1-3.AndroidRuntime::start
发现AppRuntime类继承于AndroidRuntime,而AppRuntime类中是没有start()函数的,因此回到上方的main()函数中,实际上当执行AppRuntime#start()时实际上是执行了AndroidRuntime#start()
void AndroidRuntime::start(const char* className, ..., bool zygote)
{
startVm(&mJavaVM, &env,
/*
* Register android functions.注册jni
*/
startReg(env);
/*
* We want to call main() with a String array with arguments in it.
*/
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;
stringClass = env->FindClass("java/lang/String");
strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr);
/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
char* slashClassName = toSlashClassName(className);
jclass startClass = env->FindClass(slashClassName);
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
env->CallStaticVoidMethod(startClass, startMeth, strArray);
...
}
根据AndroidRuntime名称和上述代码可以分析得出,该函数启动了 Android 系统运行时库,其中它主要做了三件事:
调用startVmVM()函数启动虚拟机 调用startReg()函数注册 Android 的 Java 方法,其实在这里就是 JNI 方法 反射调用 Java 类com.android.internal.os.ZygoteInit#main()方法,并把 fork zygote进程时的参数传入用来辅助初始化zygote进程
/*
* Register android native functions with the VM.
*/
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
...
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
env->PopLocalFrame(NULL);
return -1;
}
...
return 0;
}
static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
{
for (size_t i = 0; i < count; i++) {
if (array[i].mProc(env) < 0) {
#ifndef NDEBUG
ALOGD("----------!!! %s failed to load\n", array[i].mName);
#endif
return -1;
}
}
return 0;
}
static const RegJNIRec gRegJNI[] = {
...
REG_JNI(register_android_os_Binder),
...
};
binder驱动
1.binder_init
kernel/drivers/staging/android/binder.c //设备驱动入口函数 device_initcall(binder_init);
static int __init binder_init(void)
{
int ret;
char *device_name, *device_names;
struct binder_device *device;
struct hlist_node *tmp;
//创建名为binder的单线程的工作队列
binder_deferred_workqueue = create_singlethread_workqueue("binder");
while ((device_name = strsep(&device_names, ","))) {
ret = init_binder_device(device_name);
if (ret)
goto err_init_binder_device_failed;
}
return ret;
}
static int __init init_binder_device(const char *name)
{
int ret;
struct binder_device *binder_device;
//为binder设备分配内存
binder_device = kzalloc(sizeof(*binder_device), GFP_KERNEL);
if (!binder_device)
return -ENOMEM;
//初始化设备
binder_device->miscdev.fops = &binder_fops;
binder_device->miscdev.minor = MISC_DYNAMIC_MINOR;
binder_device->miscdev.name = name;
binder_device->context.binder_context_mgr_uid = INVALID_UID;
binder_device->context.name = name;
ret = misc_register(&binder_device->miscdev);
if (ret < 0) {
kfree(binder_device);
return ret;
}
hlist_add_head(&binder_device->hlist, &binder_devices);
return ret;
}
2.binder_open
kernel/drivers/staging/android/binder.c
static int binder_open(struct inode *nodp, struct file *filp)
//为binder_proc结构体在kernel分配内存空间
proc = kzalloc(sizeof(*proc), GFP_KERNEL);
INIT_LIST_HEAD(&proc->todo); // 初始化todo列表
init_waitqueue_head(&proc->wait); // 初始化wait队列
3.binder_mmap
1. 通过用户空间的虚拟内存大小 --- 分配一块内核的虚拟内存
2. 分配了一块物理内存 --- 4KB
3. 把这块物理内存分别映射到 用户空间的虚拟内存和内核的虚拟内存
kernel/drivers/staging/android/binder.c
static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
//保证映射内存大小不超过4M
if ((vma->vm_end - vma->vm_start) > SZ_4M)
vma->vm_end = vma->vm_start + SZ_4M;
//同步锁,保证一次只有一个进程分配内存,保证多进程间的并发访问
mutex_lock(&binder_mmap_lock);
// 采用 VM_IOREMAP方式,分配一个连续的内核虚拟内存,与进程虚拟内存大小一致
area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP);
//将proc中的buffer指针指向这块内核的虚拟内存
proc->buffer = area->addr;
// 计算出用户空间和内核空间的地址偏移量。地址偏移量 = 用户虚拟内存地址 - 内核虚拟内存地址
proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer;
mutex_unlock(&binder_mmap_lock); // 释放锁
//物理空间映射到虚拟内核空间
ret = map_kernel_range_noflush((unsigned long)page_addr,
PAGE_SIZE, PAGE_KERNEL, page);
//物理空间映射到虚拟进程空间
ret = vm_insert_page(vma, user_page_addr, page[0])
4.binder_ioctl
4-1.binder_ioctl_write_read
|