Binder作为Android系统中重要的进程间通信方式,了解其基本的原理,对于分析问题具有重要的作用。由于Binder架构涉及的内容比较多,后面将会从应用层、框架层、Native层、内核层四个层次来说明Binder的原理。首先将从应用层的AIDL开始逐渐深入到内核层。整个系列的文章如下:

深入理解Binder机制1-AIDL原理
深入理解Binder机制2-注册服务addService
深入理解Binder机制3-获取服务getService
深入理解Binder机制4-bindService过程分析
深入理解Binder机制5-binder驱动分析
深入理解Binder机制6-总结篇

一、AIDL

在进行进程间通信时,需要将接口定义好,定义好之后创建aidl文件,将接口方法放在文件中。客户端和服务端,aidl文件要保持一致,包括包名。在build之后,会在客户端和服务端生成接口类。

1.aidl文件

[->IRemoteService.aidl]

// IRemoteService.aidl
package com.skytoby.server;interface IRemoteService {void addPhone(String name);boolean getPhone(String name);int getPid();
}

2.服务端

[->PhoneService.java]

package com.skytoby.server;import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;public class PhoneService extends Service {List<String> phones = new ArrayList<>();//实现binder接口private IRemoteService.Stub mBinder = new IRemoteService.Stub() {@Overridepublic void addPhone(String name) throws RemoteException {Log.d("phone binder","server add phone:"+name);phones.add(name);}@Overridepublic boolean getPhone(String name) throws RemoteException {Log.d("phone binder","server get phone:"+name);if(phones.contains(name)){return true;}return false;}@Overridepublic int getPid() throws RemoteException {Log.d("phone binder","server getPid "+android.os.Process.myPid());return android.os.Process.myPid();}@Overridepublic void linkToDeath(IBinder.DeathRecipient recipient, int flags) {super.linkToDeath(recipient, flags);Log.d("phone binder","server getPid linkToDeath");}};@Overridepublic void onCreate() {Log.d("phone binder","server onCreate");super.onCreate();}@Overridepublic IBinder onBind(Intent intent) {Log.d("phone binder","server onBind");return mBinder;}@Overridepublic boolean onUnbind(Intent intent) {Log.d("phone binder","server onUnbind");return super.onUnbind(intent);}@Overridepublic void onDestroy() {Log.d("phone binder","server onDestroy");super.onDestroy();}
}

3.客户端

[->MainActivity.java]

package com.skytoby.client;import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.design.widget.BottomNavigationView;
import android.support.v7.app.AppCompatActivity;
import android.support.annotation.NonNull;
import android.util.Log;
import android.view.MenuItem;
import android.widget.TextView;
import com.skytoby.server.IRemoteService;public class MainActivity extends AppCompatActivity {private TextView mTextMessage;private IRemoteService mService;private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener= new BottomNavigationView.OnNavigationItemSelectedListener() {@Overridepublic boolean onNavigationItemSelected(@NonNull MenuItem item) {switch (item.getItemId()) {case R.id.navigation_home:mTextMessage.setText(R.string.title_home);bindService();return true;case R.id.navigation_dashboard:mTextMessage.setText(R.string.title_dashboard);unbindService();return true;case R.id.navigation_notifications:mTextMessage.setText(R.string.title_notifications);killService();return true;}return false;}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);BottomNavigationView navView = findViewById(R.id.nav_view);mTextMessage = findViewById(R.id.message);navView.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);Log.d("phone binder","onCreate");}void bindService(){Intent intent = new Intent();intent.setComponent(new ComponentName("com.skytoby.server","com.skytoby.server.PhoneService"));bindService(intent, connection, Context.BIND_AUTO_CREATE);}void unbindService(){if(mService!=null){unbindService(connection);}}void killService(){try {if(mService!=null){android.os.Process.killProcess(mService.getPid());}} catch (RemoteException e) {e.printStackTrace();}}ServiceConnection connection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {Log.d("phone binder","onServiceConnected");try {//获取代理mService = IRemoteService.Stub.asInterface(service);Log.d("phone binder","client getphone:"+mService.getPhone("apple"));mService.addPhone("apple");Log.d("phone binder","client getphone:"+mService.getPhone("apple"));} catch (RemoteException e) {e.printStackTrace();}}@Overridepublic void onServiceDisconnected(ComponentName name) {Log.d("binder","onServiceDisconnected");mService =  null;}};}

4.运行结果

点击客户端相应的控件,完成绑定服务,解绑服务,杀死service进程,日志如下:

16:09:10.394 27006-27006/com.skytoby.server D/phone binder: server onCreate
16:09:10.395 27006-27006/com.skytoby.server D/phone binder: server onBind
16:09:10.405 27006-27018/com.skytoby.server D/phone binder: server get phone:apple
16:09:10.407 27006-27018/com.skytoby.server D/phone binder: server add phone:apple
16:09:10.409 27006-27018/com.skytoby.server D/phone binder: server get phone:apple
16:16:55.497 27006-27006/com.skytoby.server D/phone binder: server onUnbind
16:16:55.502 27006-27006/com.skytoby.server D/phone binder: server onDestroy
16:16:57.955 27006-27020/com.skytoby.server D/phone binder: server getPid 27006

二、AIDL原理分析

1. IRemoteService类

aidl生成一个对应的IRemoteService.java,其原理还是利用了framework binder的架构,具体的内部原理后面介绍,先分析下这个生成类,其流程如下:

  • AIDL接口:继承IInterface。

  • Stub类:Binder的实现类,服务端通过这个类来提供服务。

  • Proxy类:服务器的本地代理,客户端通过这个类调用服务器的方法。

  • asInterface():客户端调用,将服务端的返回的Binder对象,转换成客户端所需要的AIDL接口类型对象。返回对象:

​ 1.若客户端和服务端位于同一进程,则直接返回Stub对象本身;

​ 2.否则,返回的是系统封装后的Stub.proxy对象。

  • asBinder():根据当前调用情况返回代理Proxy的Binder对象。

  • onTransact():运行服务端的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法来处理。

  • transact():运行在客户端,当客户端发起远程请求的同时将当前线程挂起。之后调用服务端的onTransact()直到远程请求返回,当前线程才继续执行。

/** This file is auto-generated.  DO NOT MODIFY.* Original file: G:\\Android studio\\Aidl\\client\\src\\main\\aidl\\com\\skytoby\\server\\IRemoteService.aidl*/
package com.skytoby.server;public interface IRemoteService extends android.os.IInterface {/*** Local-side IPC implementation stub class.*/public static abstract class Stub extends android.os.Binder implements com.skytoby.server.IRemoteService {private static final java.lang.String DESCRIPTOR = "com.skytoby.server.IRemoteService";/*** Construct the stub at attach it to the interface.*/public Stub() {this.attachInterface(this, DESCRIPTOR);}/*** Cast an IBinder object into an com.skytoby.server.IRemoteService interface,* generating a proxy if needed.*/public static com.skytoby.server.IRemoteService asInterface(android.os.IBinder obj) {if ((obj == null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin != null) && (iin instanceof com.skytoby.server.IRemoteService))) {return ((com.skytoby.server.IRemoteService) iin);}return new com.skytoby.server.IRemoteService.Stub.Proxy(obj);}@Overridepublic android.os.IBinder asBinder() {return this;}@Overridepublic boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {java.lang.String descriptor = DESCRIPTOR;switch (code) {case INTERFACE_TRANSACTION: {reply.writeString(descriptor);return true;}case TRANSACTION_addPhone: {data.enforceInterface(descriptor);java.lang.String _arg0;_arg0 = data.readString();this.addPhone(_arg0);reply.writeNoException();return true;}case TRANSACTION_getPhone: {data.enforceInterface(descriptor);java.lang.String _arg0;_arg0 = data.readString();boolean _result = this.getPhone(_arg0);reply.writeNoException();reply.writeInt(((_result) ? (1) : (0)));return true;}case TRANSACTION_getPid: {data.enforceInterface(descriptor);int _result = this.getPid();reply.writeNoException();reply.writeInt(_result);return true;}default: {return super.onTransact(code, data, reply, flags);}}}private static class Proxy implements com.skytoby.server.IRemoteService {private android.os.IBinder mRemote;Proxy(android.os.IBinder remote) {mRemote = remote;}@Overridepublic android.os.IBinder asBinder() {return mRemote;}public java.lang.String getInterfaceDescriptor() {return DESCRIPTOR;}@Overridepublic void addPhone(java.lang.String name) throws android.os.RemoteException {android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();try {_data.writeInterfaceToken(DESCRIPTOR);_data.writeString(name);mRemote.transact(Stub.TRANSACTION_addPhone, _data, _reply, 0);_reply.readException();} finally {_reply.recycle();_data.recycle();}}@Overridepublic boolean getPhone(java.lang.String name) throws android.os.RemoteException {android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();boolean _result;try {_data.writeInterfaceToken(DESCRIPTOR);_data.writeString(name);mRemote.transact(Stub.TRANSACTION_getPhone, _data, _reply, 0);_reply.readException();_result = (0 != _reply.readInt());} finally {_reply.recycle();_data.recycle();}return _result;}@Overridepublic int getPid() throws android.os.RemoteException {android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();int _result;try {_data.writeInterfaceToken(DESCRIPTOR);mRemote.transact(Stub.TRANSACTION_getPid, _data, _reply, 0);_reply.readException();_result = _reply.readInt();} finally {_reply.recycle();_data.recycle();}return _result;}}static final int TRANSACTION_addPhone = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);static final int TRANSACTION_getPhone = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);static final int TRANSACTION_getPid = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);}public void addPhone(java.lang.String name) throws android.os.RemoteException;public boolean getPhone(java.lang.String name) throws android.os.RemoteException;public int getPid() throws android.os.RemoteException;
}

2. 原理

对于应用层来说bindService之后就可以和服务端进行交互了,可以不用里面具体的操作如何,这样的设计大大降低了使用了难度,对于binderService的具体的过程将在后面分析,下面是其分层次的调用图。

深入理解Binder机制1-AIDL原理相关推荐

  1. 一文分析Binder机制和AIDL的理解

    为什么要去理解Android的进程间通信机制 对于Android开发工程师来说,如果不去理解进程间通信机制也可以使用系统提供的API完成应用开发,但如果想要达到更高的层级,那么就不能简单只会调用API ...

  2. 不得不说的Android Binder机制与AIDL

    说起Android的进程间通信,想必大家都会不约而同的想起Android中的Binder机制.而提起Binder,想必也有不少同学会想起初学Android时被Binder和AIDL支配的恐惧感.但是作 ...

  3. 【Binder 机制】AIDL 分析 ( 分析 AIDL 文件生成的 Java 源文件 | Binder | IBinder | Stub | Proxy )

    文章目录 前言 一.分析 AIDL 文件生成的 Java 源文件 1.IMyAidlInterface.java 中的类结构 2.DESCRIPTOR 描述符 3.Stub 构造方法 4.Stub.a ...

  4. Binder机制之AIDL

    ** 简单说一下,第一次写文章,有点不习惯,从下定决心看一看Android的系统源码开始,看过了简单的系统源码如何修改编译,简单了解了点Linux内核驱动的一点点知识,随后跟着老罗的Android系统 ...

  5. Android跨进程通信Binder机制与AIDL实例

    文章目录 进程通信 1.1 进程空间划分 1.2 跨进程通信IPC 1.3 Linux跨进程通信 1.4 Android进程通信 Binder跨进程通信 2.1 Binder简介 2.2 Binder ...

  6. 深入理解Binder机制4-bindService过程分析

    一.概述 1.1 Binder架构 Android内核基于Linux系统,而Linux系统进程间通信方式有很多,如管道,共g享内存,信号,信号量,消息队列,套接字.而Android为什么要用binde ...

  7. 从mediaserver入手快速理解binder机制(最简单理解binder)

    (一) 概述    Android的binder机制提供一种进程间通信的方法,使一个进程可以以类似远程过程调用的形式调用另一个进程所提供的功能.binder机制在Java环境和C/C++环境都有提供. ...

  8. 【Binder 机制】AIDL 分析 ( AIDL 通信完整流程梳理 )

    文章目录 AIDL 跨进程通信完整流程梳理 1.AIDL 文件编译 2.注册服务 3.IMyAidlInterface.Stub.asInterface 方法获取远程服务 4.IMyAidlInter ...

  9. 【Binder 机制】AIDL 分析 ( 创建 AIDL 文件 | 创建 Parcelable 类 | AIDL 中使用 Parcelable 类 | 编译工程生成 AIDL 对应的Java源文件 )

    文章目录 一.创建 AIDL 文件 1.创建 AIDL 目录 2.创建 AIDL 文件 3.创建 Parcelable 类 4.AIDL 目录下声明 Parcelable 类 5.AIDL 中使用 P ...

  10. 【Binder 机制】AIDL 分析 ( 创建 Service 服务 | 绑定 Service 远程服务 )

    文章目录 一.创建 Service 远程服务 1.创建 Service 2.AndroidManifest.xml 清单文件中配置 Service 二.绑定 Service 远程服务 1.核心代码 2 ...

最新文章

  1. Gurobi Optimizer的安装教程
  2. 通过css类/选择器选取元素 文档结构和遍历 元素树的文档
  3. Python 标准库 —— uuid(生成唯一 ID)
  4. 学习:java设计模式—工厂模式
  5. 开源 CI/CD 构建框架 TekTon 的深入剖析
  6. android 双线程等待,在Java/Android中启动另一个线程之前如何等待线程完成?
  7. 程序员进阶之算法练习(一)
  8. LeetCode(832)——翻转图像(JavaScript)
  9. python函数名的作用_Python:函数名称空间与作用域:
  10. LINUX也有C#?
  11. 【数据库系统概论】数据库系统概述
  12. cisp证书考试费用_cisp考试费多少钱
  13. 超详细讲解OSPF中如何选举DR和BDR
  14. java实现树形菜单_Java构建树形菜单的实例代码(支持多级菜单)
  15. JSD-2204-连接查询-JDBC-Day10
  16. mysql超链接_PHP MYSQL超链接和表单
  17. 关于Java中Scanner获取Char字符类型的方法
  18. 刚子扯谈:标题木有啊
  19. 带有默认值的参数一定位于参数列表的末尾
  20. PHP代码来模拟双色球,大乐透机选

热门文章

  1. xjoi 1524 枚举集合
  2. 如何用CSDN-markdown编辑器写博客
  3. sqlserver格式化-年月日
  4. 最新Mac安装/卸载pip教程
  5. 项目管理之项目章程和三个重要说明书
  6. 铁道交通运营管理专业对计算机要求高吗,铁道交通运营管理就业前景怎么样
  7. 第七章 yaml格式
  8. 2022年防爆电气考试题及答案
  9. Java设计模式之观察者模式应用与实战
  10. 无线网路中的虚拟AP技术