Android IPC、Binder和AIDL
1、前言 IPC
PC(Inter-Process Communication)进程间通信,提供了各种进程间通信的方法。不仅是Android,其他语言也大很多情况下需要进程间通信的。Android本质上属于Linux,它的跨进程通信也基于Linux进程通信的原理。在Linux C编程中有几种方法
(1) 半双工Unix管道
(2) FIFOs(命名管道)
(3) 消息队列
(4) 信号量
(5) 共享内存
(6) 网络Socket
以上方法都可以实现进程间的通讯,但Android并没有使用以上6种现成的通信方法,而是自己开发Binder驱动,至于为什么重新开发Binder,可参考知乎上的回答:
https://www.zhihu.com/question/39440766?sort=created
大致原因:安全,性能,稳定。
本篇大致围绕下面几个问题,大致做出回答
- 什么是IPC,大致适应场景
- Binder机制
- Binder与AIDL
- 如何使用AIDL
1、为什么会有IPC?
因为在很多情况下,我们需要共享进程或者进程间通信,场景
1、下载的音乐文件在文件管理器中,当前我正在播放因为,我在文件管理器删除音乐(文件不存在了),当前音乐播放器是不是该停止呢?
2、第三方APP集成支付宝付款时,第三方应用怎么样调起支付宝用于支付呢
其实使用的场景很多,要实现上面的功能就得使用IPC。
内存共享
在用户空间中没有办法共享,因此进程间不能通信,但在内核空间中可以共享,不同的APP要进行通信,可以通过使用内核空间来做到,这样就产生IPC机制,IPC是用于解决这些问题的。为了做到IPC,Android 中提供了Binder机制,来解决进程通信问题
2、Binder机制
服务端:Binder服务端其实就是一个Binder对象,对象建立后,启动一个线程,这个线程接收Binder驱动发送的消息,并执行onTransact()方法,执行服务代码。
Binder驱动:当服务端对象创建时,同时会在Binder驱动中创建一个mRemote对象,该对象类型也是Binder类,客户端要过程访问时,都是通过mRemote对象。
客户端:客户端想要访问远程服务时,必须获取远程服务在B inder中对应的mRemote 对象,获取方法就是通过AIDL
3、Binder与AIDL
AIDL(Android Interface Define Language),是android的一种接口定义语言。借助它,你可以定义接口,使得客户端和服务端之间实现进程间通信。
Binder是Android的一个类,它实现了IBinder接口。从IPC角度来说,Binder是android中的一种跨进程通信方式。通过这个Binder对象,客户端就可以获取服务端提供的服务或数据,这里的服务包括普通服务和基于AIDL的服务。
也就是说Binder是用来实现远程服务访问的,AIDL则主要负责远程访问的主要内容,这些内容则用AIDL中的接口来描述。
4、AIDL使用示例
示例做一个进程间通信的Demo,在AIDLServer中新建一个方法,返回一个字符串,在另一个Client的APP中调用。
1、服务端代码
1.创建一个AIDL文件:
// IMyAidlInterface.aidlpackage com.example.aidlservice;// Declare any non-default types here with import statementsinterface IMyAidlInterface { /** * 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); String getString();}
2、新建服务,这个服务就是远程访问的服务,用于客户端调用
package com.example.aidlservice;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;import android.support.annotation.Nullable;/** * Created by yuxiaogang on 2017/8/5. */public class RemoteService extends Service { @Nullable @Override public IBinder onBind(Intent intent) { return iMyAidlInterface; } private IMyAidlInterface.Stub iMyAidlInterface = new IMyAidlInterface.Stub() { @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } @Override public String getString() throws RemoteException { return "im from server"; } };}
3、启动服务:
public class MainActivity extends AppCompatActivity implements View.OnClickListener { private Button btn_bind; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn_bind = (Button) findViewById(R.id.btn_bind); btn_bind.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_bind: Intent intent = new Intent(this, RemoteService.class); bindService(intent, new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Toast.makeText(MainActivity.this, "success", Toast.LENGTH_SHORT).show(); } @Override public void onServiceDisconnected(ComponentName name) { Toast.makeText(MainActivity.this, "failed", Toast.LENGTH_SHORT).show(); } }, BIND_AUTO_CREATE); break; } }}
2、客户端
客户端就是实际上需要调用远程服务,首先引进AIDL文件,注意AIDL文件的位置和包名。可以直接从Service中复制过来。编译后,客户端就可以调用到服务端的方法了
public class MainActivity extends AppCompatActivity implements View.OnClickListener { private Button btn_msg; private TextView text; private IMyAidlInterface iMyAidlInterface; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn_msg = (Button) findViewById(R.id.btn_msg); text = (TextView) findViewById(R.id.text); btn_msg.setOnClickListener(this); } @Override protected void onResume() { super.onResume(); Intent intent = new Intent(); intent.setAction("com.example.aidlservice.RemoteService"); // intent.setPackage("com.example.aidlservice"); bindService(intent, new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { iMyAidlInterface=IMyAidlInterface.Stub.asInterface(service); Log.i("MainActivity", "onServiceConnected"); } @Override public void onServiceDisconnected(ComponentName name) { Log.i("MainActivity", "onServiceDisconnected"); } }, BIND_AUTO_CREATE); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_msg: try { text.setText(iMyAidlInterface.getString()); } catch (RemoteException e) { e.printStackTrace(); } break; } }}