Android-Binder

Posted 鲁迅认识的那只猹

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android-Binder相关的知识,希望对你有一定的参考价值。

android-Binder(一)

学习自

《Android开发艺术探索》
https://www.jianshu.com/p/bdef9e3178c9
https://blog.csdn.net/u011240877/article/details/72765136

Binder漫谈

Binder是IBinder接口的一个实现类,inder是连接系统的各种Manager和其对应的Service的桥梁,Binder主要用于Service中。

Android系统的分层

对Android系统的分层了解了之后,我们会对IPC有一个更清晰的认知,所以我们来看一看系统的分层

技术分享图片

我们来依次看一下各层的职责:

  • Linux Kernel(Linux内核层), 这一层中主要是各种硬件的驱动,Binder IPC的驱动也是在此层的
  • HAL(硬件抽象层),对内核层的封装,为系统服务层提提供可调用的接口,以JNI的方式。
  • Android System Service(Android 系统服务层), Android系统的核心服务,为应用层提供调用的接口
  • Binder IPC Proxys(Binder IPC的代理层),是应用层和系统服务层之间的桥梁,实现跨进程通信
  • Application Freamwork(应用程序框架层), 这一程就是我们的SDK,提供我们日常开发所用到的类库

其中Linux内核层好硬件抽象层,都是以C/C++来实现,硬件抽象层会编译为so文件,已JNI的方式提供给系统服务层调用,系统服务层通过Java实现,该层中的服务随着手机的开机而启动(不关机就会一直运行),这些服务负责Activity的管理,Window的管理等等。因为系统服务层是通过Java实现的所以,他们肯定是运行与一个独立的 Dalvik 中。

因为我们程序员自己开发的程序和系统的服务都分别运行在不同的虚拟机中,之间的通信就只能靠 IPC技术来完成了,为了方便Coder调用系统服务接口Google提供了一系统服务相对应的Manager。其调用关系如下:

技术分享图片

从AIDL开始

AIDL(Android Interface Definition Language) Androd 接口定义语言,通过AIDL可以实现IPC,通过AIDL定义的接口我们可以完成客户端和服务的跨进程通信,使用了AIDL的话在编译的时候系统会自动帮我们生成 Binder .

建立AIDL相关的文件

建立需要的实体类 Book 实现Parcelable接口

package top.littledavid.studyipc.beans

import android.os.Parcel
import android.os.Parcelable

/**
 * Created by IT on 7/30/2018.
 */
class Book(val bookId: Int, val bookName: String, val author: String) : Parcelable {
    constructor(parcel: Parcel) : this(
            parcel.readInt(),
            parcel.readString(),
            parcel.readString()) {
    }

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeInt(bookId)
        parcel.writeString(bookName)
        parcel.writeString(author)
    }

    override fun describeContents(): Int {
        return 0
    }
    
    override fun toString(): String {
        return "Book(bookId=$bookId, bookName='$bookName', author='$author')"
    }

    companion object CREATOR : Parcelable.Creator<Book> {
        override fun createFromParcel(parcel: Parcel): Book {
            return Book(parcel)
        }

        override fun newArray(size: Int): Array<Book?> {
            return arrayOfNulls(size)
        }
    }
}

建立AIDL目录,随便输入一名称,建立起目录解构即可,然后把文件删掉,我们自家定义我们自己的文件

技术分享图片

建立实体类映射文件 Book.aidl 要在aidl 下与Book 实体类相同的包下才行,否则会报错,无法通过编译,实体类的包接口是 top.littledavid.studyipc.beans->beans 所以aidl下的 Book.aidl包也要一样才行

//实体映射包名一定要和实体定义的包名相同
package top.littledavid.studyipc.beans;
//定义映射
parcelable Book;

定义 IBookManager.aidl 其中定义了IPC操作的方法

// IBookManager.aidl
package top.littledavid.studyipc;

// Declare any non-default types here with import statements
import top.littledavid.studyipc.beans.Book;

interface IBookManager {
    List<top.littledavid.studyipc.beans.Book> getBookList();
    //这是如果不是使用的基础数据类型,一定要使用方向类型标识 : in ,out ,inout
    void addBook(in Book book);
}

整体目录解构如下

技术分享图片

编译成功后会在 项目路径appuildgeneratedsourceaidldebug oplittledavidstudyipc (包名可能不同)下生成一个 IBookManager.java ,其中实现了IPC相关的代码。

建立Service

class BookService : Service() {
    private lateinit var mBookList: MutableList<Book>

    override fun onBind(intent: Intent?): IBinder {
        mBookList = mutableListOf()
        Log.e("TAG", "OnBind")
        return mIBinder
    }

    //实现AIDL定义的接口
    private val mIBinder = object : IBookManager.Stub() {
        override fun getBookList(): List<Book> {
            return [email protected]()
        }

        override fun addBook(book: Book) {
            [email protected](book)
        }
    }
}

在Minefast文件中配置服务

<service
    android:name=".BookService"
    android:enabled="true"
    android:exported="true"
    android:process=":remote" />

进行IPC

在Activity中进行IPC

class MainActivity : AppCompatActivity() {
    private var mIBookManager: IBookManager? = null

    private val mConn = object : ServiceConnection {
        override fun onServiceDisconnected(name: ComponentName?) {
            mIBookManager = null
        }

        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            //将IBinder转换为AIDL接口
            mIBookManager = IBookManager.Stub.asInterface(service)
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        //开启服务
        val serviceBindIntent = android.content.Intent(this, BookService::class.java)
        this.bindService(serviceBindIntent, mConn, Context.BIND_AUTO_CREATE)
    }

    //添加书籍信息
    fun addBook(view: View) {
        val book = Book(1, "Android开发艺术探索", "任玉刚老师")
        this.mIBookManager!!.addBook(book)

        loadBookInfo()
    }

    private fun loadBookInfo() {
        val bookList = mIBookManager!!.bookList
        val stringBuilder = StringBuilder()
        bookList.forEach {
            stringBuilder.append(it.toString() + "
")
        }
        this.bookInfoTV.text = stringBuilder.toString()
    }

    override fun onDestroy() {
        super.onDestroy()
        this.unbindService(mConn)
    }
}

总结

磕磕绊绊的总算完成了AIDL的IPC,非常感谢参考文档中国的博主的无私奉献。下一章我们来看一看Binder的原理。

以上是关于Android-Binder的主要内容,如果未能解决你的问题,请参考以下文章

Android-Binder进程间通讯机制-多图详解

Android-binder通信详解

微信小程序代码片段

VSCode自定义代码片段——CSS选择器

谷歌浏览器调试jsp 引入代码片段,如何调试代码片段中的js

片段和活动之间的核心区别是啥?哪些代码可以写成片段?