Android之进程通信--Binder
- Cilent从ServiceManger哪里获得BnMediaService的BnBinder引用就可以调用BnMediaPlayerService的方法了,BnMediaPlayerService是怎样响应客户端的请求的哪?
BnMediaService并不是直接接受Cilent发送过来的请求,而是使用IPCThreadState接受Cilent发送过来的请求,然后调用BBinder的transact函数,传入客户端发送过来的相关参数,由transact函数来调用BnMediaPlayerService类的onTransact函数来真正的处理Cilent请求的。也就是说Cilent的请求是经过了IPCThreadState的中转才调用BnMediaService的onTransact服务的。为什么要中转哪?因为这是跨进程的对象访问,并不是在进程内的直接访问,要让跨进程的对象访问像自己内部对象访问一样,必须经过底层驱动的一个转换过程,也就是说在IPCTheadState线程里完成了和底层Binder的通信。
3.通常客户端如何和服务器端通信的流程?
LayoutInflater layoutInflater=(LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//1.通常情况下是客户端要和服务器端通信就是调用ServieManager远程接口提供的getService接口来实现的。这样就获得了服务器端的跨进程引用
View view =layoutInflater.inflate(R.layout.activity_second, null);
//2.客户端直接调用服务引用的方法
//3.服务器端的IPCTHreadState线程接受到客户端的请求后会调用BBinder的transat函数,传入客户端的请求,然后由transact函数自动调用服务器端的onTransact函数(为什么这里调用IPCThreadState而不是直接在Service里调用,因为Service端是多线程的,也就是服务器端可以有几个至几十个客户端,而用线程正好可以给每个客户端请求开启一个IPCTheadState线程)
//4.服务器端在onTransate函数里执行对外开发的服务方法,返回执行结果。
4.通常的C/S的通信流程是从客户端有ServiceManger的远程接口开始的,正式因为客户端一开始就有ServiceManger的远程接口,所以才能调用getService 接口,才有后面的流程,那么客户端如何获得ServiceManger的远程接口的哪?
//1.客户端直接调用defaultServiceManager就可以获得ServiceManger的引用
ServiceManager
5.ServiceManager有很多父类和实现了很多接口,最终ServiceManger有一个很重要的成员变量mRemote他的类型是IBinder*,实现类就是BpBinder。ServiceManger服务的对外监听客户端请求的线程IPCThreadState有一个成员变量mProcess,这个mProcess的类型就是ProcessState。一个进程里只有一个PoocessState,当客户端调用defaultServiceManger的时候就是在请求BpBinder。
/****
过程如下:
1.客户端(可能是MediaServiceManager也可能是一个自定义普通的Service,无论这个对象是Service Cilent 还是ServiceManger在这个时候相对于ServiceManger这个Linux init函数最先加载的进程都是客户端)调用defaultServiceManger,那么ServiceMnager就会启动一个IPCThreadState线程,然后会同过ProcessState打开/dev/binder设备
2.返回一个句柄值为0的binder引用 ****/
6.Android和Binder驱动通信都是在ProcessState里完成的,因为只有ProcessState打开了/dev/binder文件,分析ProcessState的构造函数
ProcessState::ProcessState()
: mDriverFD(open_driver())//打开/dev/binder文件,并把设备文件描述符保存在mDriverFD成员变量中
//打开文件设备的时候会使用BINDER_VERSION和BINDER_SET_MAX_THREADS命令和Binder驱动程序交互,前者用来获得驱动程序的版本号,后者告诉驱动Server端最多可以打开的线程的数量。和驱动交互本身就是和内核态的程序交互,发送命令获得返回值。
, mVMStart(MAP_FAILED)
, mManagesContexts(false)
, mBinderContextCheckFunc(NULL)
, mBinderContextUserData(NULL)
, mThreadPoolStarted(false)
, mThreadPoolSeq(1)
{
if (mDriverFD >= 0) {
// XXX Ideally, there should be a specific define for whether we
// have mmap (or whether we could possibly have the kernel module
// availabla).
#if !defined(HAVE_WIN32_IPC)
// mmap the binder, providing a chunk of virtual address space to receive transactions.
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
if (mVMStart == MAP_FAILED) {
// *sigh*
LOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
close(mDriverFD);
mDriverFD = -1;
}
#else
mDriverFD = -1;
#endif
}
if (mDriverFD < 0) {
// Need to run without the driver, starting our own thread pool.
}
}
7.Sever创建一个Binder实体,为其取一个字符形式可读易记的名字,将这个Binder连同名字以数据包的形式通过Binder驱动发送给SMGr,通知SMgr注册一个叫张三的Binder,它位于某个Server中,驱动为这个穿过进程边界的Binder创建位于内核中的实体节点以及SMgr对实体的引用,将名字及新建的引用传递给Smgr。SMgr接收到数据包后,从中取出名字和引用填写到一张查找表中。Server创建一个BInder实体后,就会通过AddService向ServiceManger注册,注册的时候因为是在进程间的通讯,所以必然要通过内核,内核就根据BInder实体的Parcel信息在内核中创建了一个实体,和引用,发送给ServerManger,这样当客户端向服务器发送请求的时候直接把数据发送到内核,内核经过ServerManger的唯一确定后,直接在内核中完成对Service方法的调用,因为无论是IPCThreadState还是ProcessState都是C++实现的在内核中完成的功能。java端只是实现了Binder会拥有哪些功能,而这个用java写成的功能会是被C++的代码接收请求和管理的。
package com.example.servicedemo3; import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log; public class ServiceDemo extends Service { @Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Log.d("Start COmmand","Startcommad 调用");
return super.onStartCommand(intent, flags, startId);
} @Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return new MyBlinder(); } class MyBlinder extends Binder{ public void checkWifi(){ System.out.println("----------------------------");
System.out.println("------------CheckWIfi----------------");
Log.d("CHeckWIFT","Service------------------"); } } }
8.当一个进程使用BINDER_SET_CONTEXT_MGR命令将自己注册成Servermanger的时候,BInder驱动就会自动的在驱动中创建一个ServerManger的实体(而一般的服务是在addServer的时候才会在驱动中创建实体),也就是说系统启动后,那些角色为ServerManager的进程当调用BINDER_SET_CONTEXT_MGR命令后,驱动就自动在BInder驱动里创建BpBinder,系统有多少ServiceManger,驱动就一一对应有多少BpBInder。他们的关系是平等。而当有Service向某个ServerManger注册BInder的时候其实注册的就是BBinder。驱动在自己的内存空间里维护着BpBinder和BBinder的一对多关系,这样当客户端需要调用某个服务的时候就会先取得BpBInder,当调用getService的时候就是由驱动在自己的内存中从BpBinder这个节点开始搜索对象名字的BBinder,如果查到就直接执行BBinder里的方法。因为客户端事实上是只有BpBinder的引用,所以就是这个过程中,首先把客户端的数据拷贝到内核中,当查询到指定的BBinder后,就可以直接执行了,而不必拷贝到别的地方。BInder驱动内部的结构如图所示:
参考阅读:Android深入浅出之Binder机制
Android进程间通信(IPC)机制Binder简要介绍和学习计划
Android之进程通信--Binder的更多相关文章
- 【朝花夕拾】Android性能篇之(七)Android跨进程通信篇
前言 只要是面试高级工程师岗位,Android跨进程通信就是最受面试官青睐的知识点之一.Android系统的运行由大量相互独立的进程相互协助来完成的,所以Android进程间通信问题,是做好Andro ...
- android跨进程通信(IPC)——AIDL
转载请标明出处: http://blog.csdn.net/sinat_15877283/article/details/51026711: 本文出自: [温利东的博客] 近期在看 @任玉刚 大神编写 ...
- Android跨进程通信:图文详解 Binder机制 原理
binder原理讲的很详细 https://blog.csdn.net/carson_ho/article/details/73560642
- Android跨进程通信Messenger
一.概述 我们可以在客户端发送一个Message给服务端,在服务端的handler中会接收到客户端的消息,然后进行对应的处理,处理完成后,再将结果等数据封装成Message,发送给客户端,客户端的ha ...
- Android跨进程通信的四种方式
由于android系统中应用程序之间不能共享内存.因此,在不同应用程序之间交互数据(跨进程通讯)就稍微麻烦一些.在android SDK中提供了4种用于跨进程通讯的方式.这4种方式正好对应于andro ...
- android 跨进程通信
转自:http://www.androidsdn.com/article/show/137 由于android系统中应用程序之间不能共享内存.因此,在不同应用程序之间交互数据(跨进程通讯)就稍微麻烦一 ...
- Android跨进程通信AIDL服务
服务(Service)是android系统中非常重要的组件.Service可以脱离应用程序运行.也就是说,应用程序只起到一个启动Service的作用.一但Service被启动,就算应用程序关闭,Ser ...
- Android跨进程通信广播(Broadcast)
广播是一种被动跨进程通讯的方式.当某个程序向系统发送广播时,其他的应用程序只能被动地接收广播数据.这就象电台进行广播一样,听众只能被动地收听,而不能主动与电台进行沟通,在应用程序中发送广播比较简单.只 ...
- Android跨进程通信访问其他应用程序的Activity
访问其他应用程序的ActivityActivity既可以在进程内(同一个应用程序)访问,也可以跨进程访问.如果想在同一个应用程序中访问Activity,需要指定Context对象和Activity的C ...
随机推荐
- 使用github同步网站
今天刚刚完成了自己的一个小项目,想把他上传到服务器上,想到到我使用的Visual Stdio Code具有git功能,于是想到使用github作为代码仓库来同步代码. 大体步骤分为这几步:创建远程代码 ...
- import方法引入模块详解
在python用import或者from...import或者from...import...as...来导入相应的模块,作用和使用方法与C语言的include头文件类似.其实就是引入某些成熟的函数库 ...
- Asp.Net生命周期系列一
Asp.Net生命周期对于初级甚至中级程序员来说,一直都是一个难题,很多程序员不了解生命周期,导致使用Asp.Net做开发感觉很不灵活,感觉太多东西被微软封装好了,我们不能改变,其实只要你稍微了解一下 ...
- javascript获取和判断浏览器窗口、屏幕、网页的高度、宽度等
主要介绍了javascript获取和判断浏览器窗口.屏幕.网页的高度.宽度等 scrollHeight: 获取对象的滚动高度.scrollLeft:设置或获取位于对象左边界和窗口中目前可见内容的最左端 ...
- 关于php网络爬虫phpspider
前几天,被老板拉去说要我去抓取大众点评某家店的数据,当然被我义正言辞的拒绝了,理由是我不会...但我的反抗并没有什么卵用,所以还是乖乖去查资料,因为我是从事php工作的,首先找的就是php的网络爬虫源 ...
- Windows下的Memcache安装与Java部署
Windows下的Memcache安装: 1. 下载memcached的windows稳定版,解压放某个盘下面,比如在c:\memcached 2. 在终端(也即cmd命令界面)下输入 ‘c:\mem ...
- Jira & filter & subscribe & issues
Jira & filter & subscribe & issues https://confluence.atlassian.com/search/?query=subscr ...
- express框架 中间件
- ElasticSearch1.7.1拼音插件elasticsearch-analysis-pinyin-1.3.3使用介绍
ElasticSearch拼音插件elasticsearch-analysis-pinyin使用介绍 https://my.oschina.net/xiaohui249/blog/214505 摘要: ...
- Lua学习笔记:面向对象
Lua学习笔记:面向对象 https://blog.csdn.net/liutianshx2012/article/details/41921077 Lua 中只存在表(Table)这么唯一一种数据结 ...