android之AIDL跨进程通信详解 (五) Android IBinder机制简单介绍

原理简介

我们都知道android 是通过IBinder来实现IPC(Inter Process Communication)进程间通信的。。。

参考:Android进程间通信(IPC)机制Binder简要介绍和学习计划


借用一下:


1. Client、Server和Service Manager实现在用户空间中,Binder驱动程序实现在内核空间中
2. Binder驱动程序和Service Manager在Android平台中已经实现,开发者只需要在用户空间实现自己的Client和Server
3. Binder驱动程序提供设备文件/dev/binder与用户空间交互,Client、Server和Service Manager通过open和ioctl文件操作函数与Binder驱动程序进行通信
4. Client和Server之间的进程间通信通过Binder驱动程序间接实现

5. Service Manager是一个守护进程,用来管理Server,并向Client提供查询Server接口的能力


AIDL的使用

aidl是 Android Interface definition language的缩写,它是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口


ITestService.aidl文件

  1. package test.aidl;
  2. interface ITestService {
  3. void start();
  4. }
注意在client端和server端中的aidl文件的的包名必须是一样的,此处必须是test.aidl
自动生成ITestService类,其中有Stub子类
  1. public static test.aidl. ITestService asInterface(android.os.IBinder obj) {
  2. ......
  3. }
Stub的asInterface方法返回了ITestService对象


lbb.demo.first进程中的服务,充当Server角色

  1. package lbb.demo.first;
  2. public class RemoteService extends Service {
  3. private TestService mITestService;
  4. public class TestService extends ITestService.Stub {
  5. public void start() {
  6. Log.d( "LiaBin", "RemoteService start");
  7. }
  8. }
  9. @Override
  10. public void onCreate() {
  11. super.onCreate();
  12. //实例化Binder
  13. mITestService = new TestService();
  14. }
  15. @Override
  16. public IBinder onBind(Intent intent) {
  17. return mITestService;
  18. }
  19. }

  1. <service android:name= ".RemoteService">
  2. <intent-filter>
  3. <action android:name= "android.intent.action.MyFirstService"/>
  4. <category android:name= "android.intent.category.default"/>
  5. </intent-filter>
  6. </service>

lbb.demo.two进程充当Client角色
  1. package lbb.demo.two;
  2. public class MainActivity extends AppCompatActivity {
  3. private static final String REMOT_SERVICE_ACTION = "android.intent.action.MyFirstService";
  4. private ITestService testService;
  5. private ServiceConnection connection = new ServiceConnection() {
  6. @Override
  7. public void onServiceConnected(ComponentName name, IBinder service) {
  8. testService = ITestService.Stub.asInterface(service);
  9. }
  10. @Override
  11. public void onServiceDisconnected(ComponentName name) {
  12. }
  13. };
  14. @Override
  15. protected void onCreate(Bundle savedInstanceState) {
  16. super.onCreate(savedInstanceState);
  17. setContentView(R.layout.activity_main);
  18. ButterKnife.bind( this);
  19. bindService( new Intent(REMOT_SERVICE_ACTION), connection, BIND_AUTO_CREATE);
  20. }
  21. @OnClick(R.id.but)
  22. void onClick() {
  23. try {
  24. testService.start();
  25. } catch (Exception e) {
  26. e.printStackTrace();
  27. }
  28. }
  29. @Override
  30. protected void onDestroy() {
  31. super.onDestroy();
  32. unbindService(connection);
  33. }
  34. }
此时lbb.demo.two进程点击button最终会执行start方法,activity通过bindService获得了远程服务的IBinder引用。。
怎么获得的,现在也不是很清楚,但是肯定跟上面说的Binder驱动程序和Service Manager守护进程了脱不了关系的。。

另一方面:有没有发现,同一个进程中的activity和service的通信,其实也差不多。。。。只是不需要定义aidl文件而已,因为如果在service中定义一个IBinder实现类,那么
在activity中就能访问得到该IBindler对象了。。所以不需要aidl文件。。 如果硬要使用aidl文件定义的接口,此时也是没有任何问题的。。。
但是如果service和activity在不同的进程,是没法访问到service中定义的IBindler,那么只能通过共享使用一个aidl文件了
,来达到共享IBinder进行通信。。
  1. private MyBinder myBinder = new MyBinder();
  2. @Override
  3. public IBinder onBind(Intent intent) {
  4. // TODO Auto-generated method stub
  5. return myBinder;
  6. }
  7. public class MyBinder extends Binder{
  8. public void start(){
  9. Log.d( "LiaBin", "MyBinder start");
  10. }
  11. }
  12. MyBinder binder;
  13. private ServiceConnection conn = new ServiceConnection() {
  14. @Override
  15. public void onServiceDisconnected(ComponentName name) {
  16. }
  17. @Override
  18. public void onServiceConnected(ComponentName name, IBinder service) {
  19. binder = (MyBinder)service;
  20. }
  21. };
  22. binder.start();
Binder类默认实现了IBinder接口


activity和service通信能不能用handler,当然不能。因为service没法获取activity中的handler引用,msg跟handler是一一对应的。就是说使用service中的handler发送消息,
只能service中的handler接收得到。。handler只是用来线程间的通信,因为其它一个线程时候,可以把main线程中的handler传递过去。所以实现了通信。。但是启动service,是没法把handler传过去的。。

本质上不管是startactivity,startservice,bindservice其实都是通过AMS服务来调度的。。AMS(ActivityManagerService)属于系统进程,
应用进程跟AMS其实是通过IBinder通信的
,以后会分析下AMS,这里简单提一下。。


IBinder机制在framework层的使用

  1. TelephonyManager telManager = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
  2. telManager.dial( "110"); //实际这是错的,因为dial方法在TelephonyManager类中被隐藏了,你是看不到滴,为了演示,调用dial方法。。

可以看到其实context.getSystemService获取的并不是系统服务。。只是一个简单的对象而已。。

ContextImpl.java

  1. @Override
  2. public Object getSystemService(String name) {
  3. ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
  4. return fetcher == null ? null : fetcher.getService( this);
  5. }
  6. registerService(TELEPHONY_SERVICE, new ServiceFetcher() {
  7. public Object createService(ContextImpl ctx) {
  8. return new TelephonyManager(ctx.getOuterContext());
  9. }});

所以this.getSystemService(Context.TELEPHONY_SERVICE);返回的是TelephonyManager对象。


TelephonyManager.java

  1. /** @hide */
  2. @SystemApi
  3. public void dial(String number) {
  4. try {
  5. getITelephony().dial(number);
  6. } catch (RemoteException e) {
  7. Log.e(TAG, "Error calling ITelephony#dial", e);
  8. }
  9. }
  10. private ITelephony getITelephony() {
  11. return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
  12. }
  13. public static final String TELEPHONY_SERVICE = "phone";

可以看到此时真正执行的是ITelephony的dial方法。。可以看到“phone”类型的服务返回的一个IBinder

ServiceManager.getService获取的才是真正的系统服务

  1. public class PhoneInterfaceManager extends ITelephony.Stub {
  2. private PhoneInterfaceManager(PhoneGlobals app, Phone phone) {
  3. .......
  4. publish();
  5. }
  6. private void publish() {
  7. if (DBG) log( "publish: " + this);
  8. ServiceManager.addService( "phone", this);
  9. }
  10. public void dial(String number) {
  11. dialForSubscriber(getPreferredVoiceSubscription(), number);
  12. }
  13. public void dialForSubscriber(int subId, String number) {
  14. if (DBG) log( "dial: " + number);
  15. String url = createTelUrl(number);
  16. if (url == null) {
  17. return;
  18. }
  19. // PENDING: should we just silently fail if phone is offhook or ringing?
  20. PhoneConstants.State state = mCM.getState(subId);
  21. if (state != PhoneConstants.State.OFFHOOK && state != PhoneConstants.State.RINGING) {
  22. Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(url));
  23. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  24. mApp.startActivity(intent);
  25. }
  26. }
  27. }
可以看到,构造函数调用publish,然后注册了“phone"这个服务。。ServiceManager.addService("phone", this);

然后dial方法,实际上走的是PhoneInterfaceManager类的dial方法 Intent  intent = new Intent(Intent.ACTION_DIAL, Uri.parse(url));  此时调用拨号界面进行拨号

PhoneInterfaceManager实现了ITelephony.Stub,所有最后来看看ITelephony.aidl文件


ITelephony.aidl文件

  1. interface ITelephony {
  2. /**
  3. * Dial a number. This doesn't place the call. It displays
  4. * the Dialer screen.
  5. * @param number the number to be dialed. If null, this
  6. * would display the Dialer screen with no number pre-filled.
  7. */
  8. void dial(String number);
  9. .......
  10.  }

最后:此时可以看到PhoneInterfaceManager可以当作是Server角色,TelephonyManager充当是Client角色。。。
TelephonyManager是公开的,我们代码中可以访问得到,其实只是一个门面,系统暴露给我们的接口(TelephonyManager更多的用到使用它来查询当前通话状态啊等功能),真正还是通过IBinder机制去调用系统服务PhoneInterfaceManager去具体的实现。。PhoneInterfaceManager是隐藏的,我们看不到。。。



总结一下:

不管是AIDL还是在framework中通过ServiceManager进行跨进程调用其实,都是先把IBinder拿到,只有拿到这个两个进程才能够通信

ServiceManager.getService(Context.TELEPHONY_SERVICE)得到的是IBinder

bindservice中的ServiceConnection得到的也是IBinder


原文链接:https://blog.youkuaiyun.com/Mr_LiaBill/article/details/49837851

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值