android Binder
来源:互联网 发布:linux dhcp 作用 编辑:程序博客网 时间:2024/06/17 07:33
Binder 是什么? 顾名思义 Binder 英文意思 别针,回形针,在android中 主要用于进程间通信。android 中Binder 工作于Linux层面,属于一个驱动,只是该驱动不需要硬件,或者说其操作的硬件是基于一小段内存。从线程角度来讲,Binder 驱动代码运行在内核端,客户端程序调用Binder是通过系统调用完成的。
Binder 跨进程通信是如何完成的?
在Binder 主要提供了三个模块,即 服务端接口,Binder驱动,客户端接口 三者的关系可以看下图
下面我们来详细介绍Binder中 这三个模块的主要功能:
1:服务端:一个Binder 服务端其实就是一个Binder类对象,服务端内该Binder对象一旦创建,就会启动一个隐藏线程,而该线程的作用是和Binder驱动 进行消息的交互。当该隐藏线程收到消息之后就会执行Binder对象中的onTransact() 方法,根据该方法的传入参数执行不同的服务代码。
2:Binder驱动 : Binder驱动是客户端雨服务端进行通信的桥 ,Binder驱动中的mRemote对象实质上也是一个Binder对象,该对象是在服务端创建Binder对象时,同时创建的。而客户端要访问远程服务端时,都是通过Binder驱动中的mRemote对象进行访问的。而在Binder驱动中同样重载类transact() 方法
重载transact() 方法内容主要包括:
2.1:向服务端隐藏线程发送调用消息
2.2:挂起当前线程,等待服务端执行完成之后通知
2.3:接到服务端通知后,继续执行客户端线程,并返回执行结果
3:客户端:客户端想要访问远程服务,必须获取远程服务在Binder 对象中对应的mRemote对象。
注:对于应用程序开发来说,客户端似乎是直接调用了服务端Binder对象,而实质上是客户端调用了Binder驱动中的Binder对象,然后通过Binder驱动中的Binder对象与服务端的Binder进行通信,所以应用程序中是存在两个Binder对象,一个服务端Binder,一个Binder驱动中的Binder。
下面我们从两个方面对Binder 进行详细的分析,分别是客户端通过Binder调用系统服、自定义一个远程服务客户端通过Binder进行调用
1:客户端通过Binder调用系统服务;
在调用系统服务时我们通常使用 getSystemService(String str);方法去获取系统服务;
InputManager inputManager = (InputManager) getSystemService(Context.INPUT_SERVICE); inputManager.getInputDeviceIds();
下面我们从这段代码开始分析看客户端是如何获取到服务端Binder对象,以及通过该Binder对象客户端如何与服务端进行通信的。
public class Activity extends ContextThemeWrapper implements LayoutInflater.Factory2, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, ComponentCallbacks2, Window.OnWindowDismissedCallback, WindowControllerCallback{ @Override public Object getSystemService(@ServiceName @NonNull String name) { ... return super.getSystemService(name); } }
通过上述代码我们可以看到实质上是调用了ContextThemeWrapper.getSystemService(name);方法;
public class ContextThemeWrapper extends ContextWrapper { @Override public Object getSystemService(String name) { ... return getBaseContext().getSystemService(name); }}
而在ContextThemeWrapper中我们可以看出实际上是调用了ContextImpl中的getSystemService(name);方法
@Override public Object getSystemService(String name) { return SystemServiceRegistry.getSystemService(this, name); }
在该段代码中可以看出实质上是调用到了SystemServiceRegistry 类中的getSystemService(…)方法,
private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS = new HashMap<String, ServiceFetcher<?>>(); static abstract interface ServiceFetcher<T> { T getService(ContextImpl ctx); } public static Object getSystemService(ContextImpl ctx, String name) { ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name); return fetcher != null ? fetcher.getService(ctx) : null; }
可以看出在SystemServiceRegistry 类内部通过Map将name与 ServiceFetcher 一一对应进行存放,然后通过Map的key - value 值先获取ServiceFetcher 然后通过getService()获取Object对象,而getService()方法实质上是 ServiceFetcher 抽象类中的一个抽象方法。
而ServiceFetcher抽象方法的具体实现是:
/** * Override this class when the system service constructor needs a * ContextImpl and should be cached and retained by that context. */ static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> { ... }/** * Override this class when the system service does not need a ContextImpl * and should be cached and retained process-wide. */static abstract class StaticServiceFetcher<T> implements ServiceFetcher<T> {...}/** * Like StaticServiceFetcher, creates only one instance of the service per application, but when * creating the service for the first time, passes it the application context of the creating * application. * * TODO: Delete this once its only user (ConnectivityManager) is known to work well in the * case where multiple application components each have their own ConnectivityManager object. */static abstract class StaticApplicationContextServiceFetcher<T> implements ServiceFetcher<T> {...}
通过上述源码可以看出 getService(…)方法实质上是 执行了
CachedServiceFetcher 中的getService方法。
private T mCachedInstance; @Override public final T getService(ContextImpl unused) { synchronized (StaticServiceFetcher.this) { if (mCachedInstance == null) { mCachedInstance = createService(); } return mCachedInstance; } } public abstract T createService();
可以看出在改方法中Object 对象是通过数组获取的,如果数组中没有该对象,则会创建一个Object对象,然后将该对象存放到数组中。
而在SystemServiceRegistry 类中我们可以看到内部有一个static 代码块在这段代码块中我们可以看到;
static{ ... registerService(Context.INPUT_SERVICE, InputManager.class, new StaticServiceFetcher<InputManager>() { @Override public InputManager createService() { return InputManager.getInstance(); }}); .... registerService(Context.LOCATION_SERVICE, LocationManager.class, new CachedServiceFetcher<LocationManager>() { @Override public LocationManager createService(ContextImpl ctx) { IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE); return new LocationManager(ctx, ILocationManager.Stub.asInterface(b)); }});}
内部执行了一些列的注册活动,
private static final HashMap<Class<?>, String> SYSTEM_SERVICE_NAMES = new HashMap<Class<?>, String>(); private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS = new HashMap<String, ServiceFetcher<?>>(); private static <T> void registerService(String serviceName, Class<T> serviceClass, ServiceFetcher<T> serviceFetcher) { SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName); SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher); }
在注册方法中实质上是将’ key-value’ 数据存储到Map容器中;
下面我们单独看 INPUT_SERVICE 是如何存储到,在 registerService 过程中我们只需要关注
new StaticServiceFetcher<InputManager>() { @Override public InputManager createService() { return InputManager.getInstance(); }}
而上述代码实质上是返回了一个InputManager对象,而在InputManager类中
public static InputManager getInstance() { synchronized (InputManager.class) { if (sInstance == null) { IBinder b = ServiceManager.getService(Context.INPUT_SERVICE); sInstance = new InputManager(IInputManager.Stub.asInterface(b)); } return sInstance; } }
我们可以看到 内部首先 通过ServiceManager.getService(…)方法获取一个IBinder对象,而改IBinder对象实质上是其他系统Service的Binder引用,
public static IBinder getService(String name) { try { IBinder service = sCache.get(name); if (service != null) { return service; } else { return getIServiceManager().getService(name); } } catch (RemoteException e) { Log.e(TAG, "error in getService", e); } return null; }
然后通过 new 出一个InputManager 出入到参数为 IInputManager.Stub.asInterface(b),该参数实质上是一个IInputMethodManager的统一接口。
private final IInputManager mIm; private InputManager(IInputManager im) { mIm = im; }
在我们调用InputManager内部方法是可以看到实质上是调用了IInputManager中的方法
public InputDevice getInputDevice(int id) { synchronized (mInputDevicesLock) { ... InputDevice inputDevice = mInputDevices.valueAt(index); ... return inputDevice; } }
通过上述代码的调用我们可以看到实质上是 通过InputManager中的IBinder对象 获取了远程的IInputManager接口对象,调用了远程的方法。
至此 我们可以看出系统服务中是如何通过Binder进行远程调用的。
总结:系统的各种服务的获取实质上 是先通过ServiceManager对象获取到不同Manager对应的IBinder对想,然后通过IBinder对象去获取远程接口,然后通过该远程接口调用远程方法去实现客户端的需求。
下面我们以图示的方式说明系统内部是如何跨进程调用的:
----------------------------
2:下面我们来看一下如何通过Binder来自定义跨进程通信:
关于自定义跨进程通信 android提供了统一的方法--aidl,下面我们就以aidl方式来讲解通过Binder 如何实现的跨进程通信。
先来看一段aidl如何实现跨进程通信的实例:
1:定义aidl
interface IKernelInterface { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString); //自定义远程服务中的方法 void test();}
2:实现一个Service 并在该Service中实现aidl中自定义的方法,并将Binder对象通过 onBind 方法返回;
public class KernelService extends Service { private IBinder iBinder = new IKernelInterface.Stub() { @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } @Override public void test() throws RemoteException { Log.d("TAG","aidl"); } }.asBinder(); @Override public void onCreate() { super.onCreate(); } @Nullable @Override public IBinder onBind(Intent intent) { return iBinder; }}
3:客户端 通bindService启动Service 并实现ServiceConnection接口,在该接口中获取其它进程中的接口,然后通过该接口调用内部方法。
Intent intent = new Intent(this,KernelService.class); bindService(intent,new KernelConnection(), Context.BIND_AUTO_CREATE); class KernelConnection implements ServiceConnection{ //IBinder 获取Binder驱动中的Remoter对象。 @Override public void onServiceConnected(ComponentName name, IBinder service) { IKernelInterface iKernelInterface = IKernelInterface.Stub.asInterface(service); try { iKernelInterface.test(); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }
以上就是aidl的实现步骤,通过以上步骤我们可以实现跨进程通信。
下面我们通过源码来分析上述代码是如何实现跨进程通信的。
在文章的开始我们提到跨进程通信实质上是客户端获取到Binder驱动中的Binder对象,然后调用 transact(…)方法实现跨进程通信的。
在aidl生成的文件中我们可以看到 Binder驱动中transact(…) 方法实质上系统已经帮我们实现了。在我们调用test() 方法是内部实质上已经调用到了该方法
@Override public void test() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_test, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } }
所以我们并不需要在aidl中关注如何 获取到mRemote对象,并调用了transact 方法,因为这些系统已经帮我们实现了,我们现在所关注的是 客户端如何去调用test方法。
按照我们的编程思想,我们只需要在某个类中实现这个接口,并在客户端调用该接口中的方法即可。
实际上aidl中的实现也是这样实现的,首先在Service中 定义一个IBinder对象,而该对象实质上实现是
public static abstract class Stub extends android.os.Binder implements IKernelInterface
并在Service中实现 IKernelInterface接口中的方法。
到这里很多读者认为在Service中已经实现了该接口方法,客户端只需要获取到Service对象的实例,然后调用 IKernelInterface 中的方法不就可以了吗?
针对这个问题 我们可能忽略了一个问题,就是 Service很可能不在我们当前这个进程,既然不在我们当前的进程,我们又如何去获取该对象的实例呢。
针对这个问题 android 系统为我们提供了很好的方法。
因为我们接口的实现是通过Service实现的,android系统为我们提供了 bindService方法来获取到远程到Binder对象,然后通过该Binder对象,我们可以得到 我们需要的接口
在aidl文件中我们可以看到该方法
public static com.liuluchao.kernelaidl.IKernelInterface asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.liuluchao.kernelaidl.IKernelInterface))) { return ((com.liuluchao.kernelaidl.IKernelInterface) iin); } return new com.liuluchao.kernelaidl.IKernelInterface.Stub.Proxy(obj); }
通过asInterface 方法我们可以得到 IKernelInterface 接口,得到该接口之后,我们就可以在客户端调用接口中的方法,这样就实现了跨进程通信。
在上述过程中还存在一个问题就是,我们如何在客户端获取到 远程服务为我们提供的Binde对象?
针对这个问题我们可以通过bindService方法的源码进行分析:
bindService在执行过程中实质上是执行了ContextImpl.bindService(…)方法
@Override public boolean bindService(Intent service, ServiceConnection conn, int flags) { warnIfCallingFromSystemProcess(); return bindServiceCommon(service, conn, flags, mMainThread.getHandler(), Process.myUserHandle()); }
可以看出内部直接调用了bindServiceCommon方法 ,
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler handler, UserHandle user) { .... if (mPackageInfo != null) { sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags); } else { throw new RuntimeException("Not supported in system context"); }...int res = ActivityManagerNative.getDefault().bindService( mMainThread.getApplicationThread(), getActivityToken(), service, service.resolveTypeIfNeeded(getContentResolver()), sd, flags, getOpPackageName(), user.getIdentifier());}
在该方法中我们只需要关注上述代码即可, 通过上述代码 我们看到实质上是去执行了 ActivityManagerService中的bindService方法
public int bindService(IApplicationThread caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, int flags, String callingPackage, int userId) throws TransactionTooLargeException { ... synchronized(this) { return mServices.bindServiceLocked(caller, token, service, resolvedType, connection, flags, callingPackage, userId); } }
其内部实质上是调用了ActiveServices.bindServiceLocked(…) 方法
final IServiceConnection conn; int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service, String resolvedType, final IServiceConnection connection, int flags, String callingPackage, final int userId) throws TransactionTooLargeException{ .... AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp); ConnectionRecord c = new ConnectionRecord(b, activity, connection, flags, clientLabel, clientIntent); ... c.conn.connected(s.name, b.intent.binder); ...}
这段代码很长我们只看我们需要关注的点。
1:通过外部传入的Service 获取到AppBindRecord 对象。
通过AppBindRecord.intent 获取IntentBindRecord 对象;在IntentBindRecord 对象中获取IBinder对象
final class IntentBindRecord { ... IBinder binder; }
这样就获取到了外部Service中的IBinder对象;
2:c.conn 该对象为 IServiceConnection 而IServiceConnection接口中有几个抽象方法
private static class InnerConnection extends IServiceConnection.Stub { .... public void connected(ComponentName name, IBinder service) throws RemoteException { ... } }
通过上述代码我们可以看出 在 ActiveServices的 bindServiceLocked 方法中将IBinder对象回调到了外部。
而Service的onBind方法在Service启动时会执行该方法,并将改方法 得到的IBinder对象保存到 IntentBindRecord 中,具体到详细执行过程 读者可以看
http://blog.csdn.net/liuluchao0543/article/details/52434095
该文章就可以了解。
至此我们 通过aidl实现进程间通信,读者应该有了更深一步的了解。
下面是视图对aidl进程间进一步说明:
ok 至此进程间的通信已经讲解完了,内容中如存在不正确的地方,还请各位看官指出来。
- Android Binder -什么是binder
- Android Binder
- Android Binder
- android Binder
- Android-binder
- android Binder
- Android--Binder
- android binder
- Android Binder
- android binder
- android: binder
- 【Android】Binder
- Android BInder
- android binder
- android Binder
- Android Binder
- android binder
- Android Binder
- 排序算法题
- Oracle10g自定义聚合函数(字符串拼接)
- http请求
- Harris角点检测(Python-OpenCV)
- STL -- 关于一些字符串处理用到的函数和数据结构
- android Binder
- 巧用ViewPager 打造不一样的广告轮播切换效果
- 互联网协议
- 最小生成树—Prim算法和Kruskal算法
- 编程面试过程中常见的10大算法概念汇总
- 利用Windows API实现精确计时器
- CCF认证 201604-3 路径解析
- 信号量的原理总结
- HelloAction extends ActionSupport 数据验证