IPC

作者: 简安理思 | 来源:发表于2022-02-28 21:26 被阅读0次

参考《Android开发艺术探索》
Binder学习指南
Android跨进程通信:图文详解 Binder机制 原理
gityuan的Binder系列

关于Binder咱也看不明白罗老师写的那个源代码分析,就先看看上面博客入个门吧。。。

概念
多进程开启
序列化
内存映射
进程内存空间划分
Android IPC通信方式
Binder原理 注册服务、获取服务、使用服务、线程池
AIDL/Messenger

IPC:进程间通信,两个进程之间进行数据交换的过程。因为进程有自己的用户内存空间和内核空间,进程之间相互隔离,互相不能访问对方的user space属于独有不可共享空间, 并且user space访问kernel space是需要系统调用 copy_from_user()和copy_to_user()进行数据传递的。

Android有通过以下几种方式进行进程间通信

  1. Intent Bundle可以在两个APP进程中进行传值

  2. 通过ContentProvider(基于Binder)以表格的形式组织数据,对其他应用的数据进行写改删查

  3. 通过文件传递数据,比如传递对象,可以把对象序列化写入文件,另一个APP再通过读取文件反序列化获取对象。序列化对象
    3.1 序列化对象,实现Serializable或者Parcelable接口
    3.2 写入文件 val oos = ObjectOutputStream(FileOutputStream(file)) oos.write(user)
    3.3 读取文件val ois = ObjectInputStream(FileInputStream(file)) ois.readObject()
    3.4 写入多个对象,读取时与写入顺序一致,依次读取

  4. 使用Messenger(基于Binder)

  5. 使用AIDL(基于Binder)

  6. 使用Socket

Android应用开启多进程

在manifest文件中对四大组件指定android:process属性

<service android:name=".service.MyService"
       android:process="com.app.id:remote"/>  // : 代表私有进程,可以省略前面的包名。其他应用组件不允许在这个进程中运行。
 <service android:name=".service.MyService" 
      android:process="com.app.id.remote"/> // . 代表全局进程,其他进程组件如果拥有相同shareUID和相同签名可以进入该进程,可以互相访问data及组件信息

开启多进程的影响

  1. application会创建多次
  2. 内存互相之间不可访问,互相线程无法同步,无法访问对方进程中的数据。
  3. 一个应用的多个进程访问同一个SharedPreference,导致可靠性下降,因为不支持并发访问

Messenger

在不同进程中传递Message对象,轻量级IPC方案,底层是AIDL方式,只能传递Bundle支持的数据类型的数据。支持发送多个消息,串行执行。
两个角色: Server/Client 发送消息,如果想要接收回信,要给Message对象设置replyTo(Messenger)

Server

class ServiceUseMessenger : Service() {

    companion object {
        const val MSG_SAY_HELLO = 0X001;
        const val MSG_SEND_TO_ACTIVITY = 0X002;
        const val MSG_START = 0X003;

    }
//1-9是客户端(activity)发给服务端(service)的消息处理
    //使用messenger进行通讯
    private val TAG: String = "ServiceUseMessenger"

    //    1.创建一个消息处理器
    class IncomingHandler(
        context: Context,
        private val applicationContext: Context = context.applicationContext,
        private val service: ServiceUseMessenger = context as ServiceUseMessenger
    ) : Handler() {
        override fun handleMessage(msg: Message) {
            when (msg.what) {
                MSG_SAY_HELLO -> {
                    Toast.makeText(applicationContext, "hello", Toast.LENGTH_SHORT).show()
                    service.sendBack( msg.replyTo)
                }
                else -> {
                    super.handleMessage(msg)
                }
            }
        }
    }

    //    2. 声明一个用来通信的messenger
    private lateinit var mMessenger: Messenger

    //    3. 在onbind时activity使用messenger给service发消息
    override fun onBind(intent: Intent?): IBinder? {
        Log.d(TAG, "onBind: ================")
        mMessenger = Messenger(IncomingHandler(this))
        return mMessenger.binder
    }

//    4.对应操作在mainActivity里


Client

public class MainActivity : BaseActivity() {
    //  新增使用Messenger和service通信
    //    4.messenger声明,用来和service通信
    private var mService: Messenger? = null

    //    5.service是否绑定的flag
    private var bound = false

    //    6.bindservie的参数,用来监听是否连接
    private val mConnection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            mService = Messenger(service)
            bound = true
        }

        override fun onServiceDisconnected(name: ComponentName?) {
            mService = null
            bound = false
        }

    }

    //    7.加个按钮用来给service发送消息
    fun sendMessage(view: View) {

        if (!bound) return
        val msg = Message.obtain(null, MSG_SAY_HELLO, 0, 0)
        selfMessenger = Messenger(ServerMsgHandler(this) )
        //比较难设置,所以就在发消息的时候给service传过去这个messenger
        msg.replyTo = selfMessenger
        try {
            mService?.send(msg)
        } catch (e: RemoteException) {
            e.printStackTrace()
        }
    }

    //    8.加个按钮给他绑定service
    fun bindToService(view: View) {
        Intent(this, ServiceUseMessenger::class.java).also { intent ->
            bindService(intent, mConnection, Context.BIND_AUTO_CREATE)
        }
    }

    //    9.onstop的时候给他解绑service
    private fun terminalService() {
        if (bound) {
            unbindService(mConnection)
            bound = false
        }

    }

    //在服务端(service)要发给客户端(activity)处理就需要在activity里也要有个消息处理器messageHandler
    private class ServerMsgHandler(
        context: Context,
        private val applicationContext: Context = context.applicationContext
    ) : Handler() {
        override fun handleMessage(msg: Message) {
            when (msg.what) {
                MSG_SEND_TO_ACTIVITY -> {
                    showToast("service sent to activity");
                }
                else -> {
                    super.handleMessage(msg)
                }
            }
        }

        fun showToast(s: String) {
            Toast.makeText(applicationContext, s, Toast.LENGTH_SHORT).show()
        }
    }

    //初始化一个用来处理service发来消息的处理器
    private lateinit var selfMessenger: Messenger


}

AIDL

进程间通信方式之一,涉及不同APP中server端里处理多线程问题的需求用AIDL Android interface description language官网介绍

  1. 准备数据类main/java/com.app.aidl/Data implements Parcelable

  2. 定义数据类同名main/aidl/com.app.aidl/Data.aidl

  3. 创建接口aidl文件main/aidl/com.app.aidl/DataManager.aidl,里面定义要提供的方法

  4. make project

  5. 定义Service组件, onBind()方法返回IBinder实现类: ManagerBinder

     ManagerBinder  extends  DataManager.Stub{} //里面具体实现定义的方法
    
  6. bindService(service,serviceConn,CREATE),在回调里获取对象,然后调用具体方法
    serviceConn: ServiceConnection--> onServiceConnect(IBinder service) {dataManager = DataManager.Stub.asInterface(service)}

1-6涉及文件
// Book.kt
@Parcelize
class Book(var name: String, var author: String,var publishYear: Int) : Parcelable
// Book.aidl
package com.wx.kotlinapp.aidl;

// Declare any non-default types here with import statements
import com.wx.kotlinapp.aidl.Book;

parcelable Book;
//BookDealer.aidl
import com.wx.kotlinapp.aidl.Book;
import com.wx.kotlinapp.aidl.DelayCallback;


interface BookDealer {
    /**
     * 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);


   void showBookName(in Book book);
   void purchasingBooks(in List<Book> book);
   void delayPurchasing();
   List<Book> showBooks(DelayCallback callback);

}
// BookDealerService 

class BookDealerService : Service()  {


    override fun onBind(intent: Intent?): IBinder? {
        return BookDealerBinder()
    }
    class BookDealerBinder : BookDealer.Stub(){
        override fun basicTypes(anInt: Int, aLong: Long, aBoolean: Boolean, aFloat: Float, aDouble: Double, aString: String?
        ) {}
        override fun showBookName(book: Book?) {}
        override fun purchasingBooks(book: MutableList<Book>?) {}
        override fun delayPurchasing() {}
        override fun showBooks(callback: DelayCallback?): MutableList<Book> {return ArrayList<Book>()}
    }
}
//activity里使用
class AIDLSampleActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_aidlsample)
    }


    private fun bindAIDLService() {
        Intent(this,BookDealerService::class.java).also {
            bindService(it,ConnectionCallback(), BIND_AUTO_CREATE)
        }
    }
    private fun useAIDLFunction() {
        bookDealer.showBookName(Book("little prince","some guy",2000))
        bookDealer.purchasingBooks(
            listOf(
                Book("A","wx",2022),
                Book("B","wx",2022),
                Book("C","wx",2022),
            )
        )
    }

    private lateinit var bookDealer: BookDealer

    inner class ConnectionCallback : ServiceConnection {
        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            bookDealer = BookDealer.Stub.asInterface(service)
        }

        override fun onServiceDisconnected(name: ComponentName?) {
            TODO("Not yet implemented")
        }

    }
}

Binder的设计

这个设计我没有看过源码,就是看了最开头列举的博客,这里只记录下我记住了哪些东西。

Binder是Android提供的IPC方式,基于Client-Server通信模式,作用是在Client和Server中间建立一个通信管道,通过内存映射的方式共享数据,只需copy一次(从内核空间复制到client进程的用户控件)数据就可以达到传递数据的效果

内存映射就是把进程的虚拟内存地址和磁盘上的对象产生对应关系,多个进程的虚拟内存都可以指向同一个对象,其中一个进程操作了对象,其他进程也是可见的。

进程内存空间划分一个进程有用户空间(进程私有不可共享)和内核空间(进程共享),从线程的user space访问kernel space是要通过系统才能访问的

进程内存空间划分

角色:
Server进程: 提供服务,支持多个Client进程向Server请求服务。
Client进程: 提供参数,通过Binder的代理对象调用Server服务。
Binder:就是用来创建虚拟内存区域,实现地址映射关系,Binder属于进程的内核空间,是虚拟的设备驱动,连接Server,Client和ServiceManager三个进程数据传输的桥梁。
ServiceManager: 管理Server的binder对象注册,用Binder类名的形式转化成Client中对该Binder的引用

Binder的使用流程

  1. 注册服务
    Server通过Binder把自己注册到ServiceManager中,让ServiceManager拥有了server的进程信息。Server提供Binder实体
  2. 客户端获取服务
    Client传递参数通过Binder给ServiceManager查找对应的server,再通过Binder把信息分发给Client, Server和Client建立连接。Client使用的Binder是serverBinder的一个代理对象。
  3. 使用服务
    3.1 Binder实现内存映射:把内核空间缓存区域和server用户空间,通过Binder创建的接收缓存区建立映射关系
    3.2 client发送参数给server: client把用户控件的参数复制到内核空间,又因为存在映射关系,写到内核空间相当于发送到server的用户空间,当前client请求服务的线程被挂起,Binder通知Server调用
    3.3 server调用client请求的方法:收到binder通知后,server进程从线程池中取出线程,处理传入的参数包后调用方法,把结果卸载自己的用户空间
    3.4 server进程返回结果给client:Biinder通知client取结果,client被挂起的线程被唤醒,client通过系统调用copy_to_user,把结果从内核空间拿到用户空间使用。

相关文章

网友评论

      本文标题:IPC

      本文链接:https://www.haomeiwen.com/subject/xqolrrtx.html