热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

AndroidFramework:Binder全解析(三,阿里面试100%会问到的JVM

mVMStartmmap(0,BINDER_VM_SIZE,PROT_READ,MAP_PRIVATE|MAP_NORESERVE,mDriverFD,0);if(mVMStart



mVMStart = mmap(0, 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();
}
}
LOG_ALWAYS_FATAL_IF(mDriverFD <0, “Binder driver could not be opened. Terminating.”);
}

注释1处,ProcessState的构造方法首先调用了open_driver()方法,这个方法一看名字就知道,是打开驱动嘛,它的参数不就是我们刚才看到的传进去的/dev/binder,也就是说ProcessState在构造方法处打开了Binder驱动。看看它是怎么打开驱动的吧


open_driver

//frameworks/native/libs/binder/ProcessState.cpp
static int open_driver(const char *driver)
{
int fd = open(driver, O_RDWR | O_CLOEXEC);//1
if (fd >= 0) {

size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);//2
if (result == -1) {
ALOGE(“Binder ioctl to set max threads failed: %s”, strerror(errno));
}
} else {
ALOGW(“Opening ‘%s’ failed: %s\n”, driver, strerror(errno));
}
return fd;
}

注释1处用于打开/dev/binder设备并返回文件操作符fd,这样就可以操作内核的Binder驱动了。


Linux 系统中,把一切都看做是文件,当进程打开现有文件或创建新文件时,内核向进程返回一个文件描述符,文件描述符就是内核为了高效管理已被打开的文件所创建的索引,用来指向被打开的文件,所有执行I/O操作的系统调用都会通过文件描述符。


注释2处的ioctl函数的作用就是和Binder设备进行参数的传递,这里的ioctl函数用于设定binder支持的最大线程数为15(maxThreads的值为15)。


在用户空间,使用ioctl方法系统调用来控制设备。这是方法原型:



/*
fd:文件描述符
cmd:控制命令
…:可选参数:插入argp,具体内容依赖于cmd/
int ioctl(int fd,unsigned long cmd,…);



用户程序所作的只是通过命令码告诉驱动程序它想做什么,至于怎么解释这些命令和怎么实现这些命令,这都是驱动程序要做的事情。所以在用户空间我们想做什么事情都是通过这个方法以命令的形式告诉Binder驱动,Binder驱动收到命令执行相应的操作。



mmap

在刚才的注释2处就是大名鼎鼎的内存映射。内存映射函数mmap,给binder分配一块虚拟地址空间。它会在内核虚拟地址空间中申请一块与用户虚拟内存相同大小的内存,然后再申请物理内存,将
同一块物理内存分别映射到内核虚拟地址空间和用户虚拟内存空间,实现了内核虚拟地址空间和用户虚拟内存空间的数据同步操作。

这是函数原型:

//原型
/*
addr: 代表映射到进程地址空间的起始地址,当值等于0则由内核选择合适地址,此处为0;
size: 代表需要映射的内存地址空间的大小,此处为1M-8K;
prot: 代表内存映射区的读写等属性值,此处为PROT_READ(可读取);
flags: 标志位,此处为MAP_PRIVATE(私有映射,多进程间不共享内容的改变)和 MAP_NORESERVE(不保留交换空间)
fd: 代表mmap所关联的文件描述符,此处为mDriverFD;
offset:偏移量,此处为0。

此处 mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
/
void
mmap(void* addr, size_t size, int prot, int flags, int fd, off_t offset)

总的来说,ProcessState做了两件事情,一是打开Binder驱动并返回文件操作符fd,二是通过mmap为Binder分配了一块虚拟内存空间,以达到内存映射的目的。

得到ProcessState对象后,调用它的getContextObject方法得到BpBinder对象。


ProcessState.getContextObject

//frameworks/native/libs/binder/ProcessState.cpp
sp ProcessState::getContextObject(const sp& /caller/)
{
return getStrongProxyForHandle(0); //
}

在之前的篇幅中讲了,当请求服务的进程的handler是0的时候就是获取ServiceManager的BpBinder对象。这里的话就是获取获取handle=0的IBinder。


ProcessState.getStrongProxyForHandle

//frameworks/native/libs/binder/ProcessState.cpp
sp ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp result;

AutoMutex _l(mLock);
//查找handle对应的资源项
handle_entry* e = lookupHandleLocked(handle);

if (e != NULL) {
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
if (handle == 0) {
Parcel data;
//通过ping操作测试binder是否准备就绪
status_t status = IPCThreadState::self()->transact(
0, IBinder::PING_TRANSACTION, data, NULL, 0);
if (status == DEAD_OBJECT)
return NULL;
}
//当handle值所对应的IBinder不存在或弱引用无效时,则创建BpBinder对象
b = new BpBinder(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}

首先查找handler所对应的资源,当handle值所对应的IBinder不存在或弱引用无效时会创建BpBinder,否则直接获取。handle==0的特殊情况,即获取的是ServiceManager,需要通过PING_TRANSACTION来判断是否准备就绪。


创建BpBinder

//frameworks/native/libs/binder/BpBinder.cpp
BpBinder::BpBinder(int32_t handle)
: mHandle(handle)
, mAlive(1)
, mObitsSent(0)
, mObituaries(NULL)
{
extendObjectLifetime(OBJECT_LIFETIME_WEAK); //延长对象的生命时间
IPCThreadState::self()->incWeakHandle(handle); //handle所对应的bindle弱引用 + 1
}

创建BpBinder对象中会将handle相对应Binder的弱引用增加1.

创建完成以后我们就重新回到了getContextObject()方法中

static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
sp b = ProcessState::self()->getContextObject(NULL);
return javaObjectForIBinder(env, b);
}

可以看到,使用了javaObjectForIBinder方法将本地IBinder指针转为javaobject。然后返回给了Java层。


javaObjectForIBinder

//frameworks/base/core/jni/android_util_Binder.cpp
jobject javaObjectForIBinder(JNIEnv* env, const sp& val) {
if (val == NULL) return NULL;

if (val->checkSubclass(&gBinderOffsets)) { //返回false
jobject object = static_cast(val.get())->object();
return object;
}

AutoMutex _l(mProxyLock);

jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
if (object != NULL) { //第一次object为null
jobject res = jniGetReferent(env, object);
if (res != NULL) {
return res;
}
android_atomic_dec(&gNumProxyRefs);
val->detachObject(&gBinderProxyOffsets);
env->DeleteGlobalRef(object);
}

//创建BinderProxy对象
object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
if (object != NULL) {
//BinderProxy.mObject成员变量记录BpBinder对象
env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());
val->incStrong((void*)javaObjectForIBinder);

jobject refObject = env->NewGlobalRef(
env->GetObjectField(object, gBinderProxyOffsets.mSelf));
//将BinderProxy对象信息附加到BpBinder的成员变量mObjects中
val->attachObject(&gBinderProxyOffsets, refObject,
jnienv_to_javavm(env), proxy_cleanup);

sp drl = new DeathRecipientList;
lf));
//将BinderProxy对象信息附加到BpBinder的成员变量mObjects中
val->attachObject(&gBinderProxyOffsets, refObject,
jnienv_to_javavm(env), proxy_cleanup);

sp drl = new DeathRecipientList;



推荐阅读
  • 本文探讨了如何利用 Android 的 Movie 类来展示 GIF 动画,并详细介绍了调整 GIF 尺寸以适应不同布局的方法。同时,提供了相关的代码示例和注意事项。 ... [详细]
  • 一、使用Microsoft.Office.Interop.Excel.DLL需要安装Office代码如下:2publicstaticboolExportExcel(S ... [详细]
  • 本文探讨了如何使用Scrapy框架构建高效的数据采集系统,以及如何通过异步处理技术提升数据存储的效率。同时,文章还介绍了针对不同网站采用的不同采集策略。 ... [详细]
  • 本文介绍了如何使用 Python 的 Pyglet 库加载并显示图像。Pyglet 是一个用于开发图形用户界面应用的强大工具,特别适用于游戏和多媒体项目。 ... [详细]
  • Gradle 是 Android Studio 中默认的构建工具,了解其基本配置对于开发效率的提升至关重要。本文将详细介绍如何在 Gradle 中定义和使用共享变量,以确保项目的一致性和可维护性。 ... [详细]
  • 基于SSM框架的在线考试系统:随机组卷功能详解
    本文深入探讨了基于SSM(Spring, Spring MVC, MyBatis)框架构建的在线考试系统中,随机组卷功能的设计与实现方法。 ... [详细]
  • 在Android中实现黑客帝国风格的数字雨效果
    本文将详细介绍如何在Android平台上利用自定义View实现类似《黑客帝国》中的数字雨效果。通过实例代码,我们将探讨如何设置文字颜色、大小,以及如何控制数字下落的速度和间隔。 ... [详细]
  • 本文深入探讨了WPF框架下的数据验证机制,包括内置验证规则的使用、自定义验证规则的实现方法、错误信息的有效展示策略以及验证时机的选择,旨在帮助开发者构建更加健壮和用户友好的应用程序。 ... [详细]
  • 本文总结了 #define 在 C/C++ 编程中的多种用途和技巧,包括定义常量、函数、宏以及条件编译等,并提供了详细的示例和注意事项。 ... [详细]
  • 本文分享了作者在使用LaTeX过程中的几点心得,涵盖了从文档编辑、代码高亮、图形绘制到3D模型展示等多个方面的内容。适合希望深入了解LaTeX高级功能的用户。 ... [详细]
  • Java多线程售票案例分析
    本文通过一个售票系统的实例,深入探讨了Java中的多线程技术及其在资源共享和并发控制中的应用。售票过程涉及查询、收款、找零和出票等多个步骤,其中对总票数的管理尤为关键。 ... [详细]
  • 本文详细介绍了如何使用C#实现不同类型的系统服务账户(如Windows服务、计划任务和IIS应用池)的密码重置方法。 ... [详细]
  • 深入解析 C++ 中的 String 和 Vector
    本文详细介绍了 C++ 编程语言中 String 和 Vector 的使用方法及特性,旨在帮助开发者更好地理解和应用这两个重要的容器。 ... [详细]
  • 使用Matlab创建动态GIF动画
    动态GIF图可以有效增强数据表达的直观性和吸引力。本文将详细介绍如何利用Matlab软件生成动态GIF图,涵盖基本代码实现与高级应用技巧。 ... [详细]
  • 深入解析C语言中的关键字及其分类
    本文将全面介绍C语言中的关键字,并按照功能将其分为数据类型关键字、控制结构关键字、存储类别关键字和其他关键字四大类,旨在帮助读者更好地理解和运用这些基本元素。C语言中共有32个关键字。 ... [详细]
author-avatar
无名有名我无名_593
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有