一、IPC 描述
ipc 就是跨进程通信。不同进程间为了安全 不能直接互相访问数据。需要通过IPC技术来实现,这里借用底层binder驱动来实现。
android frameword 层哪些地方需要Binder 机制 呢?
四大组件的创建,运行, 交互,生命周期的管理, 都是通过IPC 来进行的。使用系统服务也是IPC通信的过程。
图片
二、aidl 描述
aidl是进程间通信 定义的语言 。每一个进程当中 都有一个aidl,例如A进程访问B进程,那么A,B两个进程都有相同AIDL对象。
每一个aidl 都包含两个部分:proxy stub.说白了 ,就是一个统一约定的接口。
其结构图如下。
Stub:
Proxy
在进程A访问进程B中,访问者 我们这里理解为客户端,被访问者 理解为服务端。
proxy 就是用来向服务端 发送请求的组件。
Stub 就是服务端 用来接收客户端的请求并处理的组件。
三、IPC通信流程
这里我以绑定一个Service远程服务来 分析。假如有进程A(activity) 和 B(Service),对应工程A 和 工程B.
假如如下aidl 接口是 工程A 和 工程B 共有的。
package com.braincol.aidl.service;
public interface RemoteWebPage extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.braincol.aidl.service.RemoteWebPage
{
private static final java.lang.String DESCRIPTOR = "com.braincol.aidl.service.RemoteWebPage";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.braincol.aidl.service.RemoteWebPage interface,
* generating a proxy if needed.
*/
public static com.braincol.aidl.service.RemoteWebPage asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.braincol.aidl.service.RemoteWebPage))) {
return ((com.braincol.aidl.service.RemoteWebPage)iin);
}
return new com.braincol.aidl.service.RemoteWebPage.Stub.Proxy(obj);
}
public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getCurrentPageUrl:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _result = this.getCurrentPageUrl();
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.braincol.aidl.service.RemoteWebPage
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
public java.lang.String getCurrentPageUrl() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getCurrentPageUrl, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_getCurrentPageUrl = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public java.lang.String getCurrentPageUrl() throws android.os.RemoteException;
}
工程A:
import com.ryg.sayhi.aidl.IMyService;
import com.ryg.sayhi.aidl.Student;
public class MainActivity extends Activity implements OnClickListener {
private static final String ACTION_BIND_SERVICE = "com.ryg.sayhi.MyService";
private IMyService mIMyService;
private ServiceConnection mServiceConnection = new ServiceConnection()
{
@Override
public void onServiceDisconnected(ComponentName name)
{
mIMyService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
//通过服务端onBind方法返回的binder对象得到IMyService的实例,得到实例就可以调用它的方法了
mIMyService = IMyService.Stub.asInterface(service);
try {
Student student = mIMyService.getStudent().get(0);
showDialog(student.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
if (view.getId() == R.id.button1) {
Intent intentService = new Intent(ACTION_BIND_SERVICE);
intentService.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainActivity.this.bindService(intentService, mServiceConnection, BIND_AUTO_CREATE);
}
}
public void showDialog(String message)
{
new AlertDialog.Builder(MainActivity.this)
.setTitle("scott")
.setMessage(message)
.setPositiveButton("确定", null)
.show();
}
@Override
protected void onDestroy() {
if (mIMyService != null) {
unbindService(mServiceConnection);
}
super.onDestroy();
}
}
工程B:
public class MyService extends Service
{
private final static String TAG = "MyService";
private static final String PACKAGE_SAYHI = "com.example.test";
private NotificationManager mNotificationManager;
private boolean mCanRun = true;
private List<Student> mStudents = new ArrayList<Student>();
//这里实现了aidl中的抽象函数
private final IMyService.Stub mBinder = new IMyService.Stub() {
@Override
public List<Student> getStudent() throws RemoteException {
synchronized (mStudents) {
return mStudents;
}
}
@Override
public void addStudent(Student student) throws RemoteException {
synchronized (mStudents) {
if (!mStudents.contains(student)) {
mStudents.add(student);
}
}
}
//在这里可以做权限认证,return false意味着客户端的调用就会失败,比如下面,只允许包名为com.example.test的客户端通过,
//其他apk将无法完成调用过程
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
String packageName = null;
String[] packages = MyService.this.getPackageManager().
getPackagesForUid(getCallingUid());
if (packages != null && packages.length > 0) {
packageName = packages[0];
}
Log.d(TAG, "onTransact: " + packageName);
if (!PACKAGE_SAYHI.equals(packageName)) {
return false;
}
return super.onTransact(code, data, reply, flags);
}
};
@Override
public void onCreate()
{
Thread thr = new Thread(null, new ServiceWorker(), "BackgroundService");
thr.start();
synchronized (mStudents) {
for (int i = 1; i < 6; i++) {
Student student = new Student();
student.name = "student#" + i;
student.age = i * 5;
mStudents.add(student);
}
}
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
super.onCreate();
}
@Override
public IBinder onBind(Intent intent)
{
Log.d(TAG, String.format("on bind,intent = %s", intent.toString()));
displayNotificationMessage("服务已启动");
return mBinder;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy()
{
mCanRun = false;
super.onDestroy();
}
private void displayNotificationMessage(String message)
{
Notification notification = new Notification(R.drawable.icon, message,
System.currentTimeMillis());
notification.flags = Notification.FLAG_AUTO_CANCEL;
notification.defaults |= Notification.DEFAULT_ALL;
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, MyActivity.class), 0);
notification.setLatestEventInfo(this, "我的通知", message,
contentIntent);
mNotificationManager.notify(R.id.app_notification_id + 1, notification);
}
class ServiceWorker implements Runnable
{
long counter = 0;
@Override
public void run()
{
// do background processing here.....
while (mCanRun)
{
Log.d("scott", "" + counter);
counter++;
try
{
Thread.sleep(2000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
}
通过以上两个工程 来理解 跨进程 通信,流程理解如下 。
1:创建 A 进程 和 B进程 的 aidl 对象。
通过IPC 绑定 (bind)B进程服务时(Service), Service 被创建出来,同时B 进程(Service)的aidl 对象也创建出来。
B 进程创建aidl 对象:
注意这是个普通的成员变量,当Service对象被创建出来后,这个mBinder 也会被创建出来。
或者 在 onCreate 生命周期方法中 实例化 这个aidl对象。
private final IMyService.Stub mBinder = new IMyService.Stub() {
@Override
public List<Student> getStudent() throws RemoteException {
synchronized (mStudents) {
return mStudents;
}
}
@Override
public void addStudent(Student student) throws RemoteException {
synchronized (mStudents) {
if (!mStudents.contains(student)) {
mStudents.add(student);
}
}
}
绑定完远程服务后,(A进程)activity 中的onServiceConnected () 方法被回调, 这里返回一个远程 服务的IBinder 引用。
我们用这个ibinder 引用来初始化本进程的aidl 对象。
(也就是 初始化 A进程的 aidl对象)如下:
mIMyService = IMyService.Stub.asInterface(service);
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
//通过服务端onBind方法返回的binder对象得到IMyService的实例,得到实例就可以调用它的方法了
mIMyService = IMyService.Stub.asInterface(service);
try {
Student student = mIMyService.getStudent().get(0);
showDialog(student.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
2: 在activity 中(A 进程) 调用aidl对象的 方法 和 远程服务通信。
mIMyService.getStudent()。
这里的mIMyService 就是 Proxy 对象,当调用getStudent 方法时, 如下:
public java.lang.String getStudent() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getCurrentPageUrl, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
注意这里 有个
_result = _reply.readString();
用来 读取 远程服务端 的 数据。而不是等待return 回来。
3: 远程服务(B进程) 会被底层驱动 调用,并执行其aidl 中 Stub 的 onTransact 方法 。
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws RemoteException
{
switch (code)
case TRANSACTION_getCurrentPageUrl:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _result = this.getCurrentPageUrl();
reply.writeNoException();
reply.writeString(_result);
return true;
}
在onTransact 方法中根据A进程 中传来的方法ID 来匹配到 相应 的 方法,并调用本进程的实现,
java.lang.String _result = this.getCurrentPageUrl();
调用完毕后将结果 写入 底层。
reply.writeNoException();
reply.writeString(_result);
A 进程 会接收到。
通信 到此完毕.