Android 面试必备:高工必问Binder机制~

news2024/12/25 9:29:45

面试可能会问到的问题

  1. 从IPC的方式问到Binder的优势
  2. 为什么zygote跟其他服务进程的通讯不使用Binder
  3. Binder线程池和Binder机制

等等这些问题都是基于你对Binder的理解还有对其他IPC通讯的理解

IPC方式有多少种

  • 传统的IPC方式有Socket、共享内存、管道、信号量等
  • 安卓特有的是Binder,其他系统也有自己定义的比如window的wfc(Windows Communication Foundation)

Binder机制的优势

传统的ipc管道跟信号量都是比较轻的,基本不能用于复杂的IPC通讯,Socket有个缺点就是数据要复制两遍,第一遍是进程A复制到Socket通道,第二遍是Socket通道复制到进程B。共享内存的缺点就是不方便管理,如果频繁的对共享内存进行操作很可能会导致死锁、饥饿等问题。

img

为了解决这个痛点,安卓设计了Binder的通讯机制,提供更高效、安全、可靠的方式。下图是Binder机制图。只需要在内核里面复制一遍,这里可以简单的理解为单例模式,大家都只需要对Binder内存区域做操作,内存只有一份。 img

还有一些概念,比如我们应该都听说Binder是内核里面的,Binder是怎么用到安卓系统里面的,再看一个图 img 这里面有四个角色,其实很好理解,两个进程、一个Binder内核空间、一个ServiceManager服务。两个进程时采用的C/S结构一个客户端一个服务端。

  1. Binder内核空间就是一块存在于内核区的内存理解为一个通道
  2. ServiceManager是安卓的核心服务之一,AMS、PMS、WMS这些是一样的。它里面提供了很多线程池。Binder线程池只是其中的一种。在这里可以理解为是管理Binder给外部用的提供了一个注册机制用于识别不同的进程。下面是其他的几个线程池
    • Activity Manager线程池:用于处理Activity启动、停止等操作,保证UI界面的流畅性。
    • JobScheduler线程池:用于调度执行后台任务。
    • MediaServer线程池:用于处理音视频等媒体数据。
    • SurfaceFlinger线程池:用于处理UI界面绘制等操作。

有没有想过为什么要搞那么线程池,还要搞那么多个。其实也比较好理解,因为ServiceManager这个类的有很多地方用到,不可能是单线程处理的,这样就堵塞了。为什么搞那么多线程池是因为不同的功能不同比如有些调用比较频繁有些需要比较多的cpu。只有一个线程池的话很容易会导致占用时间过长等问题。

  1. server进程需要提供方法被别人调用,需要先在ServiceManager里面注册。
  2. server注册完以后会提供接口给client进程调用

来到这里应该可以回答剩下的那两个问题了。

Binder线程池和Binder机制

  • Binder线程池是ServiceManager提供的,利用的是Binder内核机制。
  • Binder机制是安卓为了提供更高效、稳定、可靠的方式实现的一套基于内核的IPC机制。

为什么zygote进程跟其他进程通讯使用socket而不是binder

  1. Binder虽然在内核,但是提供服务的是ServiceManager,这个时候如果要给AMS提供Binder IPC就需要等ServiceManager先初始化好,这个是没办法保证的,如果要保证这个先后顺序又要搞多一套进程通讯就更麻烦了。
  2. 另外,由于Zygote进程只与少数几个进程进行通讯,使用Socket通讯的开销相对较小,因此选择Socket通讯更加合适。而且这里面是优化过的LocalSocket效率会更高。

上面一直说内核空间,那内核空间跟用户空间有什么区别呢?

  1. 内核程序运行在操作系统的内核空间,具有更高的权限和更快的执行速度,能够实现更底层的操作,如硬件驱动、文件系统等,因此通常用于操作系统的核心功能的实现。
  2. 用户程序运行在操作系统的用户空间,具有更多的自由度和可移植性,能够实现更丰富的功能,如应用程序、服务进程等,因此通常用于操作系统的外围功能和应用程序的实现。

简单的说就是内核空间有操作内存的方法,但是这一块对用户空间是封闭的,用户空间里面操作的都是内核提供的服务。比如操作文件用到的文件系统模块和操作内存用到的内存管理模块。拿内存管理模块里面用到的kmallockfree来说。这两个方法在用户空间就调用不到,这是内核封装的方法。

`kmalloc()` 和 `kfree()`: 内核内存分配器,用于在内核空间中动态分配和释放内存。
 // 这个还并不是c/c++的原生方法,是内核自己封装的

再看一下比如使用Binder的时候我们传的是一个序列化的文件,那他是怎么映射到内存中的?

在内核中有vm_map_ramvm_insert_page这些方法可以把文件插入到内存地址中。而如果在用户空间需要跟这些打交道用到的还是内存管理模块的mmap这些。 mmap 的实现在内核中使用了 vm_area_struct。意思是内存管理模块提供给外面的一层封装。所以与其这么麻烦还不如直接放到内核里面更合适。

这些方法其实都不重要,只需要知道一点,这些方法在用户进程空间是拿不到的


基于Binder的IPC

这里是一些基础,可以不看了。因为这些用的少,方便自己以后看

AIDL

服务端

// IMyService.aidl
interface IMyService {
    int add(int a, int b);
}

// MyService.java
public class MyService extends Service {
    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }

    private class MyBinder extends IMyService.Stub {
        @Override
        public int add(int a, int b) throws RemoteException {
            return a + b;
        }
    }
}

客户端

// MainActivity.java
public class MainActivity extends AppCompatActivity {
    private IMyService mService;

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mService = IMyService.Stub.asInterface(service);
            try {
                int result = mService.add(1, 2);
                Toast.makeText(MainActivity.this, "Result: " + result, Toast.LENGTH_SHORT).show();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mService = null;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent = new Intent(this, MyService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(mConnection);
    }
}

Messager

轻量级的AIDL只能单线程 服务端 MessengerService.java:

public class MessengerService extends Service {
    private static class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 1:
                    String clientMessage = (String) msg.obj;
                    Log.i("MessengerService", "Received message from client: " + clientMessage);

                    // Send a response back to the client
                    Messenger clientMessenger = msg.replyTo;
                    Message replyMessage = Message.obtain(null, 2);
                    Bundle bundle = new Bundle();
                    bundle.putString("serverResponse", "Hello from server!");
                    replyMessage.setData(bundle);
                    try {
                        clientMessenger.send(replyMessage);
                    } catch (RemoteException e) {
                        Log.e("MessengerService", "Failed to send message to client", e);
                    }
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    private final Messenger mMessenger = new Messenger(new IncomingHandler());

    @Override
    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();
    }
}

客户端 MessengerClient.java:

public class MessengerClient extends AppCompatActivity {
    private Messenger mMessenger;

    private static class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 2:
                    String serverMessage = msg.getData().getString("serverResponse");
                    Log.i("MessengerClient", "Received message from server: " + serverMessage);
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    private final Messenger mClientMessenger = new Messenger(new IncomingHandler());

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent = new Intent(this, MessengerService.class);
        bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(mServiceConnection);
    }

    private final ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mMessenger = new Messenger(service);
            sendMessageToServer();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mMessenger = null;
        }
    };

    private void sendMessageToServer() {
        if (mMessenger == null) {
            return;
        }

        Message message = Message.obtain(null, 1);
        message.obj = "Hello from client!";
        message.replyTo = mClientMessenger;
        try {
            mMessenger.send(message);
        } catch (RemoteException e) {
            Log.e("MessengerClient", "Failed to send message to server", e);
        }
    }
}

广播、内容提供者

……

其实每次的面试你永远不知道,面试官下面会问到什么问题,所以在面试前我们需要全方位的做好提前预习的准备,面试造火箭,工作拧螺丝这个道理,想必大家都是懂的,所以我为完后的面试准备了一些面试习题进行复习,并整理成为了《Android 面试题集》的集合,如需要参考可以访问:https://qr18.cn/CKV8OZ

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

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

相关文章

Spring AOP —— 详解、实现原理、简单demo

目录 一、Spring AOP 是什么? 二、学习AOP 有什么作用? 三、AOP 的组成 3.1、切面(Aspect) 3.2、切点(Pointcut) 3.3、通知(Advice) 3.4、连接点 四、实现 Spring AOP 一个简…

linux系统安装学习

文章目录一、系统安装二、命令格式和帮助三、文件目录操作命令创建目录四、cat查看文件内容、合并文件sudo获得root权限总结一、系统安装 二、命令格式和帮助 三、文件目录操作命令 ls查看目录文件 -a 显示隐藏的文件 -l 以列表的形式显示 -h 以人性化的方式显示文件内容大小 …

【java】Java 集合框架

文章目录集合框架体系如图所示集合接口集合实现类(集合类)集合算法如何使用迭代器遍历 ArrayList遍历 Map如何使用比较器总结早在 Java 2 中之前,Java 就提供了特设类。比如:Dictionary, Vector, Stack, 和 Properties 这些类用来…

【Maven】P4 生命周期与插件

Maven 生命周期与插件项目构建生命周期clean 生命周期default 构建生命周期site 构建生命周期插件项目构建生命周期 Maven 生命周期描述的是一次构建过程经历了多少个事件。 Maven 对构建生命周期划分为3套: clean:清理工作;default&#…

1.4 条件概率与乘法公式

1.4.1 条件概率在实际问题中,除了直接考虑某事件 B 发生的概率P(B)外,有时还会碰到这样的问题,就是“在事件A 已经发生的条件下,事件B 发生的概率”。一般情况下,后概率与前一概率不同,为了区别,我们常把后者称为条件概率,记为P(B…

一文带你入门angular(中)

一、angular中的dom操作原生和ViewChild两种方式以及css3动画 1.原生操作 import { Component } from angular/core;Component({selector: app-footer,templateUrl: ./footer.component.html,styleUrls: [./footer.component.scss] }) export class FooterComponent {flag: b…

tftp、nfs 服务器环境搭建

目录 一、认识 tftp、nfs 1、什么是 tftp? 2、什么是 nfs? 3、tftp 和 nfs 的区别 二、tftp的安装 1、安装 tftp 服务端 2、配置 tftp 3、启动 tftp 服务 三、nfs 的安装 1、安装 nfs 服务端 2、配置 nfs 3、启动 nfs 服务 一、认识 tftp、…

3D目标检测(毕业设计+代码)

概述 3d Objectron是一种适用于日常物品的移动实时3D物体检测解决方案。它可以检测2D图像中的物体,并通过在Objectron数据集上训练的机器学习(ML)模型估计它们的姿态. 下图为模型训练后推理的结果! ​ 算法 我们建立了两个机器…

web项目的初始化

Tomcat 安装配置 Tomcat 官方站点:Apache Tomcat - Welcome! 。 安装 得到下载的安装包(一般是 zip 文件),并解压到你指定的目录(建议不要解压在 c 盘);(这里以 windows10 系统为例…

网上电子商城的设计与实现

技术:Java、JSP等摘要:21 世纪以来,人类经济高速发展,人们的生活发生了日新月异的变化,特别是计算机的应用及普及到经济和社会生活的各个领域。在消费领域,网上购物已经成为大众所接受的一种新型的消费方式…

javaEE初阶 — 如何用 HTML 编写一个简易代码

文章目录html1. 建立一个文本文档的方式编写2. 标签的方式编写3. 补充:更改后缀的方式4. 如何使用 VS Code 来编写一个 html 代码4.1 VS Code 的下载4.2 VS Code 的使用html html 用来描述网页的骨架,这是一个非常有特点的 标签化 的语言。 下面来写一个…

分布式对象存储——Apache Hadoop Ozone

前言 本文隶属于专栏《大数据技术体系》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢! 本专栏目录结构和参考文献请见大数据技术体系 1. 概述 Ozone是Apache Hadoop项目的子项目&#xf…

MySQL下载安装以及环境配置教程

目录MySQL 下载MySQL 安装配置环境变量MySQL 下载 进入官方网站 https://www.mysql.com/ 点击 DOWNLOADS 进入下载页面 免费版本点击下方的 MySQL Community (GPL) Downloads 点击 MySQL Community Server 点击 Go to Download Page 进入下载页面 点击 Download 点击 No thank…

【逐步剖C】-第九章-字符串函数和内存函数

前言:第一部分先简单介绍一下常用字符串函数和内存函数,第二部分再重点介绍重要函数的的模拟实现。若日后再发现某些好用或者有意思的库函数,都会在本文中进行更新。 一、常用库函数介绍 1. strlen (1)函数声明&…

C语言-基础了解-11-C作用域规则

C作用域规则 一、C作用域规则 任何一种编程中,作用域是程序中定义的变量所存在的区域,超过该区域变量就不能被访问。C 语言中有三个地方可以声明变量: 1、在函数或块内部的局部变量 2、在所有函数外部的全局变量 3、在形式参数的函数参数定…

Oracle Primavera P6 学习地图(Updating)

目录P6介绍及使用P6异常处理P6部署配置维护P6集成及开发P6集成及开发为了方便大家更好的针对查询我博客中的内容,特针对P6不同方面进行简要分类,如在使用P6过程中有碰到任何问题,欢迎通过如下方式与我取得联系(查询联系方式) P6介绍及使用 P…

什么是EventLoop?怎么测试Node或页面的性能

Event Loop 机制大家应该都有了解。本文利用 EventLoop 去做一个有趣的检测node或页面性能的代码,顺便介绍了一下EventLoop,希望对大家有所帮助! Event Loop Event Loop 机制大家应该都有了解。我先重复总结一下。 Node.js 和 Javascript 的…

1.6 独立性

1.6.1 事件的独立性1.两个事件的独立性中任意两个事件都相互独立、則称 A,.A.,,A.两两独立,显然•若,个事件相互独立,則一定两两独立,反之,不一定成立【例 1.251 将一个均匀的正四面体的第一面染上红、黄、蓝三色,将其他三百多别染…

C语言实现扫雷【详细讲解+全部源码】

扫雷的实现1. 配置运行环境2. 扫雷游戏的初步实现2.1 建立扫雷分布模块2.2 创建名为board的二维数组并进行棋盘初始化2.3 打印棋盘3. 接下来该讨论的事情3.1 布置雷3.2 排查雷3.3 统计坐标周围有几个雷4. 完整扫雷游戏的实现4.1 game.h4.2 game.c4.3 扫雷.c1. 配置运行环境 本游…

你相信吗?用ChatGPT写井字棋游戏仅需几分钟

井字棋 我们先实现一个最基本的使用控制台交互的井字棋游戏。 为了保持代码整洁,方便后续扩展,我们使用类Board来实现棋盘。除了常规的初始化方法__init__和字符串方法__str__,我们还要判断游戏的胜负、棋子位置的合理性。 在main中&…