Android 进阶——Framework核心 之Binder Java成员类详解(三)

news2024/11/17 4:52:30

文章大纲

  • 引言
  • 一、Binder Java家族核心成员关系图
  • 二、Binder Java家族核心成员源码概述
    • 1、android.os.IBinder
      • 1.1、boolean transact(int code, Parcel data, Parcel reply, int flags) send a call to an IBinder object
      • 1.2、String getInterfaceDescriptor()
      • 1.3、boolean pingBinder() 检测Binder是否存活
      • 1.4、boolean isBinderAlive()检测托管进程是否存在
      • 1.5、 IInterface queryLocalInterface(String descriptor) 获取Binder对应的本地实现对象
      • 1.6、android.os.IBinder.DeathRecipient
      • 1.7、android.os.IBinder 小结
    • 2、android.os.Binder 和 android.os.BinderProxy
      • 2.1、Binder 构造方法
      • 2.2、attachInterface(IInterface owner, String descriptor) 初始化
      • 2.3、boolean onTransact(int code, Parcel data, Parcel reply,
      • 2.4、android.os.BinderProxy
    • 3、android.os.IInterface
    • 4、Stub和Stub.Proxy角色

引言

上一篇文章解读了Binder native家族成员的关系和功能,不过呢,和这篇文章关系也不是很大,不存在先后的顺序,因为这篇文章是主要解读Binder 代码层面主要Java家族成员类功能和部分代码的,目的是从代码和逻辑设计对Binder 有更深的理解。不过呢,Android中Java 、Native层使用同一套架构实现Binder服务,而且Java层最终是通过JNI调用Native 层的实现的,因此可以对照native层学习Java层将更容易掌握,所以建议先看native层的。

一、Binder Java家族核心成员关系图

主要有IBinder、IInterface、 Binder、BinderProxy类和Stub、Stub.Proxy角色。
在这里插入图片描述

  • IBinder接口——代表一种跨进程传输的能力,实现这个接口就能将这个对象进行跨进程传递。
  • Binder类——Binder本地对象。
  • BinderProxy类——代表服务进程的Binder对象的本地代理。
  • Parcel类——主要用于存储序列化数据,然后可以通过Binder在进程间传递这些数据。
  • IInterface接口——Client端与Server端的调用契约(提供什么样的能力),实现这个接口就代表远程Server对象具有什么能力,其asBinder方法可以将Binder本地对象或代理对象返回。
  • Stub角色(Local-side IPC implementation stub class)——是AIDL接口的静态内部抽象类,继承Binder并实现了具体的IInterface派生接口,负责把Binder转为Stup.Proxy角色。
  • Stub.Proxy角色——Binder代理对象,Stub的静态内部类同样实现了AIDL接口派生类,真正去实现Binder#transact方法去实现AIDL接口方法的跨进程通信逻辑。

asInterface方法——当客户端bindService的onServiceConnecttion的回调里面,通过asInterface方法获取远程的service的。其函数的参数IBinder类型的obj,这个对象是驱动给我们的,如果是Binder本地对象,那么它就是Binder类型,如果是Binder代理对象,那就是BinderProxy类型。asInterface方法中会调用queryLocalInterface,查找Binder本地对象,如果找到,说明Client和Server都在同一个进程,这个参数直接就是本地对象,直接强制类型转换然后返回,如果找不到,说明是远程对象那么就需要创建Binder代理对象,让这个Binder代理对象实现对于远程对象的访问首先用Parcel把数据序列化,然后调用mRemote.transact方法,mRemote就是new Stub.Proxy(obj)传进来的,即BinderProxy对象

二、Binder Java家族核心成员源码概述

Framework层的Binder通过JNI来调用(C/C++)层的Binder框架,从而为上层应用程序提供服务。而Java层在命名与架构上和Native也非常相近,基本上是无缝衔接,同样也实现了一套类似的IPC通信架构供应用开发使用,当然最后都是通过Native层的Binder框架实现的。

1、android.os.IBinder

IBinder是远程对象的Base接口,不仅可以在跨进程可以调用,也可以在进程内部调用。IBinder接口代表一种跨进程传输的能力,实现这个接口(不过通常都是去继承其子类android.os.Binder)就能将这个对象进行跨进程传递,IBinder用于定义了与远程对象进行交互的抽象协议。

1.1、boolean transact(int code, Parcel data, Parcel reply, int flags) send a call to an IBinder object

public boolean transact(int code, Parcel data, Parcel reply, int flags)

transact方法是Binder IPC机制中真正去执行跨进程的方法,通过把序列化后的对象封装为Parcel 数据进行传递。换言之,所有跨进程的方法的调用最终都是会经过transact。通过**transact方法可以向一个IBinder对象发送调用请求**,而在**Binder.onTransact方法接收到一个Binder对象的调用**。transact()方法是同步调用,通常调用发出后会阻塞直到对方的Binder.onTransact()方法调用完成后才会返回。

参数说明
code“协议”代码,取值为android.os.IBinder#FIRST_CALL_TRANSACTION+N,用AIDL时与定义接口方法的顺序有关
data传输给服务端的数据,如果你没有传输任何数据,你必须创建一个空的Parcel实例。
reply从服务端接收的数据,如果不需要处理返回的值,传入null
flagsIPC逻辑控制,如传入0表示是普通调用,而当且仅当调用者和响应者在不同进程时,传入android.os.IBinder#FLAG_ONEWAY时表示单向RPC,调用者会马上返回,而不必等结果从响应者响应之后再返回。

Parcel(一个通用缓冲区具体实现在Native层)除了有数据外还带有一些描述它内容的元数据(保存着IBinder对象的引用)。这样就能在缓冲区从一个进程移动到另一个进程时,保存这些引用。这确保了当一个 IBinder 在A进程内被写入到一个 Parcel 并发送到B进程后,B进程能将同一个 IBinder 的引用发送回A进程且确保A进程将收到相同的 IBinder 对象。因此可以将 IBinder/Binder 对象用作可以跨进程管理的唯一TOKEN。此外,系统为每一个进程维持一个Binder线程池,用于派发所有从其他进程发来的IPC调用。当进程A向进程B发起一个IPC 调用,A发出后,调用的线程就阻塞在transact()方法中了,进程B中Binder线程池的接收并调用Binder.onTransact(),完成后返回一个Parcel,然后A中的之前等待的线程在收到返回的Parcel才能继续执行,让你感觉像是在一个进程内线程之间的通信一样,实际上却是进程间的通信。

Binder机制还支持进程间的递归调用,transact()方法将在IBinder所在的进程不存在时抛出RemoteException异常

1.2、String getInterfaceDescriptor()

获取Binder 对应的标识,后续传入到queryLocalInterface中得到相应的IInterface对象。

1.3、boolean pingBinder() 检测Binder是否存活

如果目标进程不存在,那么调用pingBinder()时返回false,否则返回另一端的 pingBinder() 实现返回的结果(默认始终为 true)。

1.4、boolean isBinderAlive()检测托管进程是否存在

检查Binder所在的进程是否还活着,返回false则表示已经死亡,返回true有可能是正在返回结果或者活跃状态。

1.5、 IInterface queryLocalInterface(String descriptor) 获取Binder对应的本地实现对象

获取 Binder 对象的对应的本地实现对象, 返回null,则需要实例化一个代理类。

1.6、android.os.IBinder.DeathRecipient

监听当前进程所托管的Binder对象死亡的接口(只有一个方法android.os.IBinder.DeathRecipient#binderDied),可以通过linkToDeath(DeathRecipient recipient, int flags)方法注册监听IBinder生命周期,当Binder对象死亡时会被触发,而在不需要监听时调用unlinkToDeath(DeathRecipient recipient, int flags)。

1.7、android.os.IBinder 小结

总之,Binder 机制就是让我们感觉到跨进程的调用与进程内的调用没有什么区别。

  • IBindre是远程对象的基接口,不仅可以在跨进程可以调用,也可以在进程内部调用
  • 在远程调用的时候,一端用IBinder.transact()发送(封装为Parcel同步调用),另一端用Binder的Binder.onTransact()接受。
  • 系统为每个进程维护一个进行跨进程调用的Binder线程池。

2、android.os.Binder 和 android.os.BinderProxy

android.os.Binder 和android.os.BinderProxy实现了android.os.IBinder接口,因而都可以被跨进程传输,在跨越进程的时候,Binder驱动会自动完成这两个对象的转换。Binder 是IBinder的标准实现,IPC 执行时直接继承的基类,但只是一个basic IPC primitive,它对应用程序的生命周期没有影响且只有在创建它的进程继续运行时才有效,因此要正确使用它必须在android.app.Service、android.app.Activity 或 android.content. ContentProvider里让创建它的进程一致存活。

2.1、Binder 构造方法

只有一个构造方法,由Native 进行,会在Stub 自动被调用。Binder实现了IBinder接口,但是一般不需要直接实现此类,而是跟据你的需要由开发包中的工具根据AIDL语法自动生成Binder的派生类。

2.2、attachInterface(IInterface owner, String descriptor) 初始化

初始化Binder和对应的标识,在Stub 构造函数中被调用并传入Stub自身对象和对应的全类名。

public static abstract class Stub extends android.os.Binder implements com.xxx.netservice.ICallback{
private static final java.lang.String DESCRIPTOR = "com.xxx.netservice.ICallback";
/** Construct the stub at attach it to the interface. */
public Stub(){
    this.attachInterface(this, DESCRIPTOR);
}

2.3、boolean onTransact(int code, Parcel data, Parcel reply,

        int flags)

Binder中对应IBinder transact的实现,本质上就是调用Parcel 进行类“IO"操作。

2.4、android.os.BinderProxy

BinderProxy类也实现IBinder接口且是final类型的,主要API 的实现都是通过JNI调用Native 层的Binder,代表远程进程的Binder对象的本地代理,它的transact方法通过JNI去借助Binder驱动完成数据的传输,当完成数据传输后,会唤醒Server端,调用了Server端本地对象的onTransact函数,在Server进程里面,onTransact根据调用code会调用相关函数,接着将结果写入reply并通过super.onTransact返回给驱动,驱动唤醒挂起的Client进程里面的线程并将结果返回。

3、android.os.IInterface

Binder 的基类接口(定义的AIDL 实现时直接继承这个IInterface),主要是用于把IInterface 转为IBinder,以便确保代理对象可以返回正确的结果。

public interface IInterface{
    /**
     * Retrieve the Binder object associated with this interface.You must use this instead of a plain cast, so that proxy objects can return the correct result.
     */
    public IBinder asBinder();
}

4、Stub和Stub.Proxy角色

Stub(抽象类)和Stub.Proxy(实体类) 是AIDL提供的标准实现定义的静态内部类,Stub.Proxy类和Stub类,都实现了AIDL接口,分别对应于本地进程和远程进程的Binder实例。其中Stub类在Server进程中实例化并通过 Service.onBind 方法传递给 Client 进程;而Client 进程接收到 IBinder 以后,通过 Stub.asInterface 方法转换成 AIDL接口之后使用Stub.asInterface 在本地进程工作时直接返回 Stub 实例,否则创建一个 Proxy 实例来代理通讯。

Stub#onTransact方法该方法运行在服务端中的Binder线程池中,服务端通过code确定客户端所请求的目标方法是什么,从data中取出目标方法所需的参数,然后执行目标方法,并将目标方法的返回值写入reply。如果该方法的返回false,则表示客户端的请求回失败,可以利用这个特性来做权限验证。

Stub.Proxy实现aidl接口并将方法的标识,参数和返回值对象传入方法mRemote.transact中,发起远程调用请求,同时挂起当前线程,然后服务端的Stub#onTransact被调用,当onTransact返回true,调用成功,从reply对象中取出返回值,返回给客户端调用方,当Client 进程使用时通过 Stub.asInterface 创建,同时会将方法调用的数据,都通过mRemote 转发给Server端的 Binder 实例。

package com.xx.netservice;

public interface IBaseIPC extends android.os.IInterface {

    public static abstract class Stub extends android.os.Binder implements com.xx.netservice.IBaseIPC {
        private static final java.lang.String DESCRIPTOR = "com.xx.netservice.IBaseIPC";

        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }
        /**
         * 无论是哪个进程,拿到反序列化的 IBinder 对象以后,通过这个静态方法来获取ICallback接口。
         * 如果是 Server 进程(local),可以从 binder 中直接取出之前 attach的IInterface 实例,那么调用ICallback的方法,就相当于直接调用Stub 实例的方法了。
         * 如果是 Client 进程,IBinder 只是系统在远程创建的一个 Proxy 类并无实现,因此iin 将变成 null,此时 asInterface 会创建一个Stub.Proxy 代理类,来实现 IBaseIPC 接口。
         */
        public static com.xx.netservice.IBaseIPC asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.xx.netservice.IBaseIPC))) {
                return ((com.xx.netservice.IBaseIPC) iin);
            }
            return new com.xx.netservice.IBaseIPC.Stub.Proxy(obj);
        }

        @Override
        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 {
            java.lang.String descriptor = DESCRIPTOR;
            switch (code) {
                // Server 进程的 Binder,在这里接收 transaction,并将数据反序列化以后,调用 IBaseIPC 抽象方法。
                case TRANSACTION_baseIPC: {
                    data.enforceInterface(descriptor);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    int _arg1;
                    _arg1 = data.readInt();
                    boolean _arg2;
                    _arg2 = (0 != data.readInt());
                    this.IBaseIPC(_arg0, _arg1, _arg2);
                    reply.writeNoException();
                    return true;
                }
                default: {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }

        /**
        * Client 进程持有的代理类,通过 Stub.asInterface 创建,Proxy 也实现了 IBaseIPC,会将方法调用的数据,都通过 mRemote 转发给远程的 Binder 实体。
        */
        private static class Proxy implements com.xx.netservice.IBaseIPC {
            private android.os.IBinder mRemote;

            Proxy(android.os.IBinder remote) {
                mRemote = remote;
            }

            @Override
            public android.os.IBinder asBinder() {
                return mRemote;
            }

            public java.lang.String getInterfaceDescriptor() {
                return DESCRIPTOR;
            }

            @Override
            public void baseIPC(java.lang.String type, int deviceType, boolean status) 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(type);
                    _data.writeInt(deviceType);
                    _data.writeInt(((status) ? (1) : (0)));
                    mRemote.transact(Stub.TRANSACTION_baseIPC, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }

        static final int TRANSACTION_baseIPC = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    }

    public void baseIPC(java.lang.String type, int deviceType, boolean status) throws android.os.RemoteException;
}

未完待续…

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/339601.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【宝塔部署SpringBoot前后端不分离项目】含域名访问部署、数据库、反向代理、Nginx等配置

一定要弄懂项目部署的方方面面。当服务器上部署的项目过多时,端口号什么时候该放行、什么时候才会发生冲突?多个项目使用redis怎么防止覆盖?Nginx的配置会不会产生站点冲突?二级域名如何合理配置?空闲的时候要自己用服…

【生成式AI】谁拥有生成式 AI 平台?

文章目录市场的价值将增长点技术栈:基础架构、模型和应用程序生成式 AI 应用程序留存率和差异化方面举步维艰生成式 AI 应用程序公司面临的一些问题模型提供商尚未达到大规模商业规模基础设施供应商是目前的最大赢家系统性的护城河技术栈早期阶段出现在生成人工智能…

[个人笔记] Zabbix实现自定义脚本监控Agent端

系统工程 - 运维篇 第三章 Zabbix实现自定义脚本监控Agent端系统工程 - 运维篇系列文章回顾前言实施步骤前置条件Zabbix实现自定义脚本监控Agent端Zabbix实现ssh免密登录OpenWrt服务器编写自定义sh脚本监控OpenWrt,zabbix测试监控功能Windows及Linux安装Zabbix-Agen…

IDEA自定义自动导包设置

JetBrains公司的intellij Idea堪称JAVA编程界的苹果,用户体验非常好 下面介绍一下IDEA的一个能显著提升写代码效率的非常好用的功能设置—— Auto Import 在使用IDEA编程时,我们会经常使用到下面两个快捷键 CTRLALTO(Windows) 自动导包快捷键CTRLALTL(W…

安全渗透测试中的一款免费开源的超级关键词URL采集工具

安全渗透测试中的一款免费开源的超级关键词URL采集工具。 #################### 免责声明:工具本身并无好坏,希望大家以遵守《网络安全法》相关法律为前提来使用该工具,支持研究学习,切勿用于非法犯罪活动,对于恶意使…

flutter 升级到 3.7.3 报错 Unable to find bundled Java version

大家好,我是 17。 Android studio 是2020 年的版本,有点老,昨天突发想法,升级到了 Android Studio Electric Eel 2022.1。 计划今天和明天写那个 Flutter WebView 优化的文章,这篇是 在 Flutter 中使用 webview_flut…

Android-Service详解

前言 Service 是长期运行在后台的应用程序组件 。 Service 是和应用程序在同一个进程中,所以应用程序关掉了,Service也会关掉。可以理解为 Service是不能直接处理耗时操作的,如果直接把耗时操作放在 Service 的 onStartCommand() 中&#xff…

健康码互通方案优化

背景 解决不同场景一码通–全国互认互扫 技术方案设计目标:安全、高可用、可拓展、高性能、易用性。 健康码二维码优化 要设计一个能互通的二维码,二维码需要放入的信息会更多,因为需要塞进去更多的内容。而二维码会因为字符串的长度而导致…

Redis实例绑定CPU物理核优化Redis性能

进入本次Redis性能调优之前,首先要知道CPU结构也会影响Redis的性能。接下来,具体了解一下!为什么CPU结构也会影响Redis的性能?主流的 CPU 架构一个 CPU 处理器中一般有多个物理核,每个物理核都可以运行应用程序。每个物…

docker-微服务篇

docker学习笔记1.docker简介1.1为什么会出现docker?1.2docker理念1.3虚拟机(virtual machine)1.4容器虚拟化技术1.5一次构建到处运行2.docker安装2.1前提条件2.2docker基本构成2.3docker安装步骤*2.4测试镜像3.docker常用命令3.1 启动docker3…

微信小程序 java ssm Springboot学生作业提交管理系统

系统具有良好的集成性,提供标准接口,以实现与其他相关系统的功能和数据集成。开放性好,便于系统的升级维护、以及与各种信息系统进行集成。功能定位充分考虑平台服务对象的需求。 一个微信小程序由.js、.json、.wxml、.wxss四种文件构成&…

zookeeper和kafka集群从0到1搭建(保姆教程)

一、环境准备 1、准备3台机器 主机名称 主机IP zookeeper版本 kafka版本 主机名称主机IPzookeeper版本kafka版本worker01192.168.179.128zookeeper-3.4.14.tar.gzkafka_2.12-2.2.1.tgzworker02192.168.179.129zookeeper-3.4.14.tar.gzkafka_2.12-2.2.1.tgzworker03192.168.1…

Arduino IDE 2.0.6中 ESP32开发环境搭建笔记

Arduino IDE 2.0.6中 ESP32开发环境搭建 Arduino IDE2.0 已上线一段时间,以后ESP32的学习转至新的IDE中 ,需对开发环境进行。 Arduino IDE2.0与1.0有很大差异。原来环境搭建方法已完全不同。下文主要记录环…

Docker进阶 - 13. Docker 容器监控之 CAdvisor+InfluxDB+Granfana (CIG) 简介

目录 1. CIG 产生原因 2. CIG 是什么 3. CIG 详细介绍 1. CIG 产生原因 使用docker stats命令可以看到当前宿主机上所有容器的CPU,内存以及网络流量等数据,简单的监控够用。但是docker stats统计结果只能是当前宿主机的全部容器,数据资料是实时的&am…

外包干了5年,寄了

前两天有读者想我资讯: 我是一名软件测试工程师,工作已经四年多快五年了。现在正在找工作,由于一直做的都是外包的项目。技术方面都不是很深入,现在找工作都是会问一些,测试框架,自动化测试,感…

微信公众号(二)每日推送详细教程(ChatGPT对话机器人)

微信公众号(二)每日推送详细教程(ChatGPT对话机器人)1.准备阶段1.1 基础性配置1.2 申请ChatGPT账号2. 配置阶段2.1 配置application.yml文件2.2 EnableChatGPT注解3. 部署效果图如下 1.准备阶段 1.1 基础性配置 首先下载源码…

Vue3+SpringBoot实现【登录】【毛玻璃】【渐变色】

首先创建Login.vue&#xff0c;编写界面和样式 这个是渐变色背景&#xff0c;登陆框背景为白色 <template><div class"wrapper"><div style"margin: 200px auto; background-color: #fff; width: 350px; height: 300px;padding: 20px;border-r…

hadoop高可用+mapreduce on yarn集群搭建

虚拟机安装 本次安装了四台虚拟机&#xff1a;hadoop001、hadoop002、hadoop003、hadoop004&#xff0c;安装过程略过 移除虚拟机自带jdk rpm -qa | grep -i java | xargs -n1 rpm -e --nodeps关闭防火墙 systemctl stop firewalld systemctl disable firewalld.service给普…

MyBatis-Plus基本CRUD

MyBatis-Plus基本CRUD三、基本CRUD1、BaseMapper2、插入3、删除a>通过id删除记录b>通过id批量删除记录c>通过map条件删除记录4、通过id修改一条记录5、查询a>根据id查询用户信息b>根据多个id查询多个用户信息c>通过map条件查询用户信息d>查询所有数据6、通…

微软ATP智汇十二道场 · 探索AI 驱动转型(北京专场)

为了推动微软与苏州人工智能产业创新中心共同构建企业级AI创新生态圈&#xff0c;微软ATP定于2023年3月3日在微软亚太研发集团总部&#xff08;北京&#xff09;举办“微软ATP智汇十二道场 探索AI 驱动转型”线下活动。 ▍微软探索AI商用&#xff0c;避免“创新陷阱”ChatGPT …