首页 > 系统相关 >Android开发 - IInterface 接口 Binder 机制跨进程通信 (IPC)解析

Android开发 - IInterface 接口 Binder 机制跨进程通信 (IPC)解析

时间:2024-08-27 21:14:28浏览次数:9  
标签:IPC AIDL IMyService 接口 Binder IInterface import android os

什么是 IInterface

  • IInterface 一个接口,用于跨进程通信 (IPC)。有时需要让一个应用程序与另一个应用程序服务进行通信。这些应用程序可能运行在不同的进程中,使用 Binder 机制来实现这种通信,而 IInterface 就是 Binder 机制一部分

  • 简单来说,IInterface 是一个基础接口,它为跨进程通信提供了一个通用的接口

为什么需要 IInterface

  • 每个应用程序通常运行在自己的进程中。由于进程的隔离特性,一个进程中的代码无法直接访问另一个进程中的对象。为了让不同进程之间能够安全地互相通信,由此使用了 Binder 机制
    • 跨进程通信 (IPC)IInterface 是一个基础接口,允许不同进程之间进行方法调用(即所谓的远程过程调用,RPC)
    • AIDL (Android Interface Definition Language):当使用 AIDL 创建跨进程接口时,系统会自动生成一个接口,该接口继承IInterface。这个接口用来定义客户端如何与服务端进行通信

IInterface 的主要方法

  • asBinder():这个方法返回一个 IBinder 对象IBinderBinder 通信核心对象,它允许客户端获取一个用于与服务端通信Binder 对象。每当实现一个 AIDL 接口自定义的 Binder 类时,你都需要实现 asBinder() 方法,返回一个能够处理远程请求IBinder 对象

IInterface 的使用场景

  • IInterface 通常不会直接使用,而是通过 AIDL 或者其他 Binder 类间接使用。以下是几个常见使用场景
    • AIDL 文件生成的接口:当开发者使用 AIDL 定义接口时,会自动生成一个 Java 接口,这个接口会继承自 IInterface。这个接口提供了客户端与服务端通信方法
    • 自定义 Binder 类:如果开发者需要更灵活跨进程通信控制,也可以手动实现一个 Binder 类,该也会间接实现 IInterface,并提供 asBinder() 方法

代码示例(一)

  • 接下来定义一个简单的服务 MyService,它提供一个方法 getMessage(),返回一条字符串消息。客户端可以通过绑定到这个服务调用该方法获取消息

    1. 定义一个 AIDL 文件:创建一个 AIDL 文件 IMyService.aidl,定义服务接口

      // IMyService.aidl
      package com.example.myservice;
      
      // AIDL接口定义,继承自IInterface
      interface IMyService {
          // 定义一个远程方法,用于获取消息
          String getMessage();
      }
      
    2. 系统生成接口:编译 AIDL 文件后,系统会生成一个 Java 接口 IMyService,该接口继承自 IInterface(以下并非创建的类,只做讲解,理解即可)

      // IMyService.java
      package com.example.myservice;
      
      // IMyService 接口继承自 IInterface,表示它是一个用于跨进程通信的接口
      public interface IMyService extends android.os.IInterface {
          // Stub 类,负责实现 Binder 相关的逻辑
          // Stub 是 IMyService 的抽象类,它继承自 Binder 并实现 IMyService 接口。它用于处理 IPC 相关的细节
          public static abstract class Stub extends android.os.Binder implements IMyService {
              // Stub 的构造方法
              public Stub() {
                  // 调用 attachInterface 方法将自己附加到接口上
                  this.attachInterface(this, DESCRIPTOR);
              }
      
              // 静态方法 asInterface 用于将 IBinder 对象转换为 IMyService 接口,方便客户端使用
              public static IMyService asInterface(android.os.IBinder obj) {
                  if ((obj == null)) {
                      return null;
                  }
                  IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
                  if (((iin != null) && (iin instanceof IMyService))) {
                      return ((IMyService) iin);
                  }
                  return new Proxy(obj);
              }
      
              // 重写 asBinder 方法,返回当前的 Binder 对象,以便客户端和服务端通信
              @Override
              public android.os.IBinder asBinder() {
                  return this;
              }
      
              // 代理类,用于客户端的IPC调用
              // Proxy 类用于实现客户端的代理。它持有一个 IBinder 对象,并通过它与服务端通信
              private static class Proxy implements IMyService {
                  private android.os.IBinder mRemote;
      
                  // Proxy 类的构造方法,接收一个 IBinder 对象,并将其保存为 mRemote
                  Proxy(android.os.IBinder remote) {
                      mRemote = remote;
                  }
      
                  @Override
                  public android.os.IBinder asBinder() {
                      return mRemote;
                  }
      
                  // 在 Proxy 类中实现 getMessage 方法,通过 IBinder 进行远程调用
                  @Override
                  public String getMessage() throws android.os.RemoteException {
                      // 创建一个 Parcel 对象 _data,用于封装数据
                      android.os.Parcel _data = android.os.Parcel.obtain();
                      android.os.Parcel _reply = android.os.Parcel.obtain();
                      String _result;
                      try {
                          _data.writeInterfaceToken(DESCRIPTOR);
                          // 通过 transact 方法向服务端发送请求
                          mRemote.transact(Stub.TRANSACTION_getMessage, _data, _reply, 0);
                          // 读取服务端的返回结果
                          _reply.readException();
                          // 并将其转换为字符串
                          _result = _reply.readString();
                      } finally {
                          _reply.recycle();
                          _data.recycle();
                      }
                      return _result;
                  }
              }
      
              // 方法标识符
              static final int TRANSACTION_getMessage = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
      
              // 在 Stub 类中实现 getMessage 方法,处理客户端的请求并返回消息
              @Override
              public android.os.ParcelFileDescriptor getMessage(android.os.ParcelFileDescriptor data) throws android.os.RemoteException {
                  // 服务端实际实现 getMessage 方法
                  data.enforceInterface(DESCRIPTOR);
                  String _result = this.getMessage();
                  data.writeNoException();
                  // 将返回的消息写入到 Parcel 中,发送回客户端
                  data.writeString(_result);
                  return data;
              }
          }
      
          // 服务端需要实现的实际方法
          public String getMessage() throws android.os.RemoteException;
      }
      
    3. 服务端实现:服务端将实现这个生成的接口,并提供具体业务逻辑

      // MyService.java
      package com.example.myservice;
      
      import android.app.Service;
      import android.content.Intent;
      import android.os.IBinder;
      import android.os.RemoteException;
      
      // 实现IMyService接口的服务类
      public class MyService extends Service {
      
          // 实现AIDL接口的Stub类
          private final IMyService.Stub mBinder = new IMyService.Stub() {
              @Override
              public String getMessage() throws RemoteException {
                  // 服务端实现的具体逻辑,返回一条消息
                  return "Hello from MyService!";
              }
          };
      
          @Override
          public IBinder onBind(Intent intent) {
              // 返回Stub实例,以便客户端绑定
              return mBinder;
          }
      }
      
    4. 客户端调用:客户端可以绑定到 MyService 并调用远程方法

      // MainActivity.java
      package com.example.myservice;
      
      import android.content.ComponentName;
      import android.content.Context;
      import android.content.Intent;
      import android.content.ServiceConnection;
      import android.os.IBinder;
      import android.os.RemoteException;
      import android.widget.TextView;
      import androidx.appcompat.app.AppCompatActivity;
      import android.os.Bundle;
      
      public class MainActivity extends AppCompatActivity {
      
          // 声明一个 IMyService 对象,用于保存绑定的服务
          private IMyService mService;
          // 一个布尔变量 mBound,用于跟踪服务是否绑定
          private boolean mBound = false;
      
          // 定义 ServiceConnection,用于管理服务连接的回调
          private ServiceConnection mConnection = new ServiceConnection() {
              // 当服务连接时被调用,传递 IBinder 对象
              @Override
              public void onServiceConnected(ComponentName className, IBinder service) {
                  // 获取绑定的服务
                  mService = IMyService.Stub.asInterface(service);
                  mBound = true;
                  try {
                      // 调用远程方法并显示结果
                      String message = mService.getMessage();
                      ((TextView) findViewById(R.id.textView)).setText(message);
                  } catch (RemoteException e) {
                      e.printStackTrace();
                  }
              }
      
              // // 当服务断开时被调用
              @Override
              public void onServiceDisconnected(ComponentName arg0) {
                  mService = null;
                  mBound = false;
              }
          };
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
          }
      
          @Override
          protected void onStart() {
              super.onStart();
              // 绑定服务
              Intent intent = new Intent(this, MyService.class);
              bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
          }
      
          @Override
          protected void onStop() {
              super.onStop();
              // 解除绑定服务
              if (mBound) {
                  unbindService(mConnection);
                  mBound = false;
              }
          }
      }
      
      

总结(一)

  • 以上示例,IInterface 用于实现跨进程通信的一个基础接口,它提供了远程过程调用基础框架。虽然你可能不会直接使用 IInterface,但它是所有 AIDL自定义 Binder 通信核心概念

代码示例(二)

  • 接下来将实现一个简单的服务 MyService,它运行在一个独立的进程中,并提供一个接口 IMyService 供客户端调用。客户端可以通过这个接口调用服务端方法

    1. 创建 AIDL 文件:需要定义一个 AIDL 文件 IMyService.aidl,它定义了服务接口

      // IMyService.aidl
      package com.example.myservice;
      
      // 定义一个 AIDL 接口,所有方法都将是远程调用的
      interface IMyService {
          // 一个简单的计算两个整数和的方法
          int add(int a, int b);
      }
      
    2. AIDL 文件生成的接口编译 IMyService.aidl 文件后,系统会生成一个 Java 接口 IMyService。这个接口继承自 android.os.IInterface,并提供了所有定义在 AIDL 文件中方法非创建的类这里就不复述

    3. 实现服务端的 Binder 类:服务端实现 AIDL 生成的接口,并通过一个 Binder 类提供具体方法逻辑

      // MyService.java
      package com.example.myservice;
      
      import android.app.Service;
      import android.content.Intent;
      import android.os.IBinder;
      import android.os.RemoteException;
      
      // 继承自 Service 类,提供一个 AIDL 接口实现
      // 定义一个服务 MyService,它继承自 Service 类。服务是一个运行在后台的组件,可以执行长时间运行的操作
      public class MyService extends Service {
      
          // 实现 AIDL 生成的接口 IMyService.Stub
          // 创建一个 IMyService.Stub 类型的对象 binder。IMyService.Stub 是 AIDL 编译器生成的一个抽象类,它实现了 IInterface 接口
          private final IMyService.Stub binder = new IMyService.Stub() {
              // 实现 IMyService 接口中的 add 方法。该方法接收两个整数并返回它们的和
              @Override
              public int add(int a, int b) throws RemoteException {
                  // 实现接口中的 add 方法:计算两个整数的和
                  return a + b;
              }
          };
      
          // 重写 onBind 方法。当客户端绑定到服务时,系统调用这个方法
          @Override
          public IBinder onBind(Intent intent) {
              // 当客户端绑定到服务时,返回 binder 对象,以便客户端能够与服务进行通信
              return binder;
          }
      }
      
    4. 客户端代码示例:客户端代码绑定到服务调用远程方法

      // MainActivity.java
      package com.example.myserviceclient;
      
      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.widget.TextView;
      import androidx.appcompat.app.AppCompatActivity;
      import com.example.myservice.IMyService;
      
      public class MainActivity extends AppCompatActivity {
      
          // 定义一个 IMyService 类型的变量,用于存储服务接口的引用
          private IMyService myService; // 定义 AIDL 接口类型的变量
          private boolean isBound = false; // 用于跟踪服务绑定状态
      
          // 创建一个 ServiceConnection 对象,用于处理服务连接和断开
          private ServiceConnection serviceConnection = new ServiceConnection() {
      
              // 当客户端成功绑定到服务时调用此方法
              @Override
              public void onServiceConnected(ComponentName name, IBinder service) {
                  // 服务连接时调用,将 IBinder 对象转换为 AIDL 接口
                  // 使用 IMyService.Stub.asInterface 方法将传递的 IBinder 对象转换为 IMyService 接口。这一步使客户端能够调用远程服务的方法
                  myService = IMyService.Stub.asInterface(service);
                  isBound = true;
                  // 调用远程服务方法
                  try {
                      // 调用远程服务方法 add,并传递两个整数。这个调用实际上是一个跨进程调用
                      int result = myService.add(5, 3);
                      TextView textView = findViewById(R.id.result_text);
                      // 显示服务返回的结果
                      textView.setText("Result from service: " + result);
                  } catch (RemoteException e) {
                      e.printStackTrace();
                  }
              }
      
              // 当服务意外断开时调用此方法
              @Override
              public void onServiceDisconnected(ComponentName name) {
                  // 服务断开时调用,清空接口实例并更新绑定状态
                  myService = null;
                  isBound = false;
              }
          };
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
      
              // 启动并绑定远程服务:创建一个新的 Intent,用于绑定服务
              Intent intent = new Intent();
              // 设置 ComponentName,指定服务的包名和类名
              intent.setComponent(new ComponentName("com.example.myservice", "com.example.myservice.MyService"));
              // 绑定服务。BIND_AUTO_CREATE 标志表示如果服务尚未启动,则自动启动它
              bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
          }
      
          // 当活动销毁时调用,确保解绑服务以防止内存泄漏
          @Override
          protected void onDestroy() {
              super.onDestroy();
              // 解绑服务以防止内存泄漏
              if (isBound) {
                  unbindService(serviceConnection);
                  isBound = false;
              }
          }
      }
      

总结(二)

  • 以上示例,展示了如何使用 IInterface 及其衍生类(如通过 AIDL 定义的接口)实现应用程序中的跨进程通信。服务端实现了 AIDL 接口并提供了一个 Binder 对象。客户端通过 ServiceConnection 连接服务,并使用接口调用远程方法

标签:IPC,AIDL,IMyService,接口,Binder,IInterface,import,android,os
From: https://www.cnblogs.com/ajunjava/p/18383574

相关文章

  • 互联工厂数据交换标准:IPC-CFX
    大家好,我是Edison。全球电子制造主要集中在中国,面向未来工业4.0、中国制造2025的战略转型升级,互联互通是基础、数据是核心,如何从用户角度来定义设备加工数据的内容完整性、有效性、可扩展性将是工厂通讯连接交换的工作重点。IPC-CFX是什么?首先,解释下这两个缩写的意思:IPC是国际......
  • Android开发 - IBinder 类与 Binder 类的关系解析
    IBinder类IBinder类说明:IBinder是一个接口,它是AndroidIPC机制的基础。它定义了一组用于进程间通信的基本操作,但不提供实际的实现。IBinder主要用于描述一个可以被远程调用的对象主要特点:接口定义:IBinder是一个接口,定义了如何进行进程间通信的基本方法,如trans......
  • Android开发 - Binder 类进程间通信(IPC)的机制解析
    什么是BinderBinder是一种用于进程间通信(IPC)的机制,允许不同的进程(或者不同的组件)相互交互,提供了跨进程通信(IPC)的基础。它允许一个进程中的对象(如服务)被另一个进程中的代码(如应用组件)调用。Binder是一种特殊的对象,它能够在不同进程之间传递数据和调用方法Binder的作用进......
  • Android开发 - IBinder 类实现跨进程通信(IPC)解析
    什么是IBinderIBinder类是一个重要的接口,常用于实现跨进程通信(IPC);IBinder允许不同的进程或组件之间相互传递数据和调用方法。主要用于实现进程间通信。它是Android中的一个底层机制,允许不同的应用或组件(即使它们在不同的进程中)通过IBinder对象进行数据交换和方法调用IB......
  • 重头开始嵌入式第二十六天(Linux系统编程 进程间通信 IPC)
    目录IPC进程间通信1.管道通信管道的特性使用流程无名管道1.创建并打开管道:2.无名管道的读写:3.关闭管道: close();4.使用例子:有名管道1、创建:mkfifo2、打开有名管道 open3、管道的读写: 文件IO4、关闭管道:5、卸载管道:remove();IPC进程间通信进程间通信(In......
  • IPC对象通信方式---共享内存 | 网络通信 -编程
    共享内存共享内存机制其允许两个或多个进程共享一个给定的存储区,这一段存储区可以被两个或两个以上的进程映射至自身的地址空间中,一个进程写入共享内存的信息,可以被其他使用这个共享内存的进程,通过一个简单的内存读取错做读出,从而实现了进程间的通信。是内核预留的内存空间,最......
  • VisualStudio 产生的.sdf和.ipch文件删除、不生成
    前言全局说明VisualStudio产生的.sdf和.ipch文件删除、不生成一、说明环境:Windows7旗舰版VisualStudio2013二、原因某天,打算给vs2013的一个工程,打包备份,打包后,发现压缩包有90MB,看到数字确实很惊讶。因为这个工程就是画了几个按钮的小功能,怎么会这么大。......
  • 安卓笔记—binder
    binder的c实现代码我没有读,下面的笔记都是从文章中学习的https://elinux.org/Android_Binderbinder有哪些功能?跨进程传输数据,跨进程传递时机。进程是分配内存的最小单位,因此进程间不共享内存。但是内核与进程之间是一对多的关系,也就是一个内核对应多个进程,因此binder......
  • 进程间通信IPC
    前言        进程是操作系统中独立运行的程序单元,每个进程拥有自己的内存空间。由于进程之间的内存空间是隔离的,不能直接访问彼此的内存,因此需要借助IPC来实现进程间的数据交换一.管道进程间通信的本质是让不同的进程看到同一份资源, 我们先来看管道是如何做到的......
  • 【IO】IPC通信机制函数(消息队列,共享内存,信号量集函数整理汇总)
            整理了一下IPC通信的函数,包括消息队列,共享内存,信号量集;信号量集的使用是在共享内存的基础上使用,函数太多啦,慢慢学吧cc,争取全部记住        其中在使用有关信号量集的函数的时候,进行简单的封装函数功能之后,再进行使用,会更加方便,在文章最后对信号量集的......