首页 > 其他分享 >大厂 Framework 面试必备 Handler&Binder&AMS 面试题

大厂 Framework 面试必备 Handler&Binder&AMS 面试题

时间:2023-08-19 18:35:23浏览次数:44  
标签:面试题 映射 Framework Binder 实例 线程 Looper 进程

前言

大家都知道现在 Android Framework 成为头部公司必不缺少的技术栈之一,尤其是熟悉 Franmework 源码的 Android 开发者,在面试中往往会占到很大的优势

那我今天就带来Android Framework 比较高刷的面试题分享,总共包含以下四大类:

系统启动流程面试题解析 Binder 面试题解析Handler面试题解析AMS面试题解析

话不多说,直接接上面试题!!!!

一、你了解 Android 系统启动流程吗?

当按电源键触发开机,首先会从ROM中预定义的地方加载引导程序BootLoader 到 RAM中,并执行BootLoader程序启动Linux Kernel,然后启动用户级别的第一个进程: init 进程。init 进程会解析init.rc脚本做一些初始化工作,包括挂载文件系统创建工作目录以及启动系统服务进程等,其中系统服务进程包括 Zygote、service manager、media 等。在 Zygote中会进一步去启动 system_ server进程,然后在 system_server 进程中会启动AMS、WMS、PMS等服务,等这些服务启动之后,AMS中就会打开Launcher应用的home Activity,最终就看到了手机的“桌面”。

二、system_server 为什么要在 Zygote 中启动,而不是由 init 直接启动呢?

Zygote 作为一个孵化器,可以提前加载一些资源,这样 fork()时基于 Copy-On-Write 机制创建的其他进程就能直接使用这些资源,而不用重新加载。 比如 system_server 就可以直接使用 Zygote 中的 JNI 函数、共享库、常用的类、以及主题资源。

三、为什么要专门使用 Zygote 进程去孵化应用进程,而不是让system_server去孵化呢?

首先 system_server 相比 Zygote 多运行了 AMS、 WMS 等服务,这些对一个应用程序来说是不需要的。另外进程的fork()对多线程不友好,仅会将发起调用的线程拷贝到子进程,这可能会导致死锁,而system_server 中肯定是有很多线程的。

四、能具体说说是怎么导致的死锁的吗?

在POSIX 标准中,fork的行为是这样的:复制整个用户空间的数据(通常使用 copy-on-write 的策略,所以可以实现的速度快)以及所有系统对象,然后仅复制当前线程到子进程。这里:所有父进程中别的线程,到了子进程中都是突然蒸发掉的对于锁来说,从 OS 看,每个锁有一个所有者,即最后一次 lock 它的线程。假设这么一个环境,在 fork 之前,有一个子线程 lock 了某个锁,获得了对锁的所有权。fork 以后,在子进程中,所有的额外线程都人间蒸发了。而锁却被正常复制了,在子进程看来,这个锁没有主人,所以没有任何人可以对它解锁。 当子进程想 lock 这个锁时,不再有任何手段可以解开了。

五、Zygote 为什么不采用 Binder 机制进行 IPC 通信?

Binder机制中存在Binder线程池,是多线程的,如果Zygote采用Binder的话就存在上面说的fork()与多线程的问题了。其实严格来说,Binder机制不一定要多线程,所谓的Binder线程只不过是在循环读取Binder驱动的消息而已,只注册一个Binder线程也是可以工作的,比如service manager 就是这样的。实际上Zygote尽管没有采取Binder机制,它也不是单线程的,但它在fork()前主动停止了其他线程,fork()后重新启动了。

六、Binder有什么优势

性能方面

  • 共享内存 0次数据拷贝
  • Binder 1次数据拷贝
  • Socket/管道/消息队列 2次数据拷贝

稳定性方面

  • Binder:基于C/S架构,客户端 (Client) 有什么需求就丢给服务端 (Server) 去完成,架构清晰、职责明确又相互独立,自然稳定性更好
  • 共享内存:虽然无需拷贝,但是控制复杂,难以使用
  • 从稳定性的角度讲,Binder机制是优于内存共享的。

安全性方面

  • 传统的IPC没有任何安全措施,安全依赖上层协议来确保。
  • 传统的IPC方法无法获得对方可靠的进程用户ID/进程UI (UID/PID) ,从而无法鉴别对方身份。
  • 传统的IPC只能由用户在数据包中填入UID/PID,容易被恶意程序利用。
  • 传统的IPC访问接入点是开放的,无法阻止恶意程序通过猜测接收方地址获得连接。
  • Binder既支持实名Binder,又支持匿名Binder,安全性高。

七、Binder是如何做到一次拷贝的

主要是因为Linux是使用的虚拟内存寻址方式,它有如下特性:

  • 用户空间的虚拟内存地址是映射到物理内存中的。
  • 对虚拟内存的读写实际上是对物理内存的读写,这个过程就是内存映射。
  • 这个内存映射过程是通过系统调用mmap()来实现的。
  • Binder借助了内存映射的方法,在内核空间的接收方用户控件的数据缓存区之间做了一层内存映射,就相当于直接拷贝到了接收方用户空间的数据缓存区,从而减少了一次数据拷贝。

八、MMAP的内存映射原理了解吗?

MMAP内存映射的实现过程,总的来说可以分为三个阶段: (一)进程启动映射过程,并在虚拟地址空间中为映射创建虚拟映射区域

  1. 进程在用户空间调用库函数mmap,原型:void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
  2. 在当前进程的虚拟地址空间中,寻找一段空闲的满足要求的连续的虚拟地址
  3. 为此虚拟区分配一个vm_area_struct结构,接着对这个结构的各个域进行了初始化
  4. 将新建的虚拟区结构 (vm_area_struct) 插入进程的虚拟地址区域链表或树中

(二)调用内核空间的系统调用函数mmap(不同于用户空间函数),实现文件物理地址和进程虚拟地址的一一映射关系

  1. 为映射分配了新的虚拟地址区域后,通过待映射的文件指针,在文件描述符表中找到对应的文件描 述 符,通过文件描述符,链接到内核“已打开文件集”中该文件的文件结构体 (struct file) , 每个 文件结构体维护着和这个已打开文件相关各项信息。
  2. 通过该文件的文件结构体,链接到file_operations模块,调用内核函数mmap,其原型为: int mmap(struct file *filp, struct vm_area_struct *vma),不同于用户空间库 函数。
  3. 内核mmap函数通过虚拟文件系统inode模块定位到文件磁盘物理地址。
  4. 通过remap_pfn_range函数建立页表,即实现了文件地址和虚拟地址区域的映射关系。此时,这 片 虚拟地址并没有任何数据关联到主存中。 注:前两个阶段仅在于创建虚拟区间并完成地址映射,但是并没有将任何文件数据的拷贝至主存。 真正的文件读取是当进程发起读或写操作时。进程的读或写操作访问虚拟地址空间这一段映射地址,通过查询页表,发现这一段地址并不在物 理页面上。因为目前只建立了地址映射,真正的硬盘数据还没有拷贝到内存中,因此引发缺页异常。

(三)进程发起对这片映射空间的访问,引发缺页异常,实现文件内容到物理内存(主存)的拷贝 注:前两个阶段仅在于创建虚拟区间并完成地址映射,但是并没有将任何文件数据的拷贝至主存。真正的文件读取是当进程发起读或写操作时。进程的读或写操作访问虚拟地址空间这一段映射地址,通过查询页表,发现这一段地址并不物理页面上。因为目前只建立了地址映射,真正的硬盘数据还没有拷贝到内存中,因此引发缺页异常。

  1. 缺页异常进行一系列判断,确定无非法操作后,内核发起请求调页过程。
  2. 调页过程先在交换缓存空间 (swap cache) 中寻找需要访问的内存页,如果没有则调用nopage 函 数把所缺的页从磁盘装入到主存中。
  3. 之后进程即可对这片主存进行读或者写的操作,如果写操作改变了其内容,一定时间后系统会自动回写脏页面到对应磁盘地址,也即完成了写入到文件的过程。

注 :修改过的脏页面并不会立即更新回文件中,而是有一段时间的延迟,可以调用msync()来强制同步,这样所写的内容就能立即保存到文件里了

九、Binder机制是如何跨进程的

  1. Binder驱动
  • 在内核空间创建一块接收缓存区,
  • 实现地址映射:将内核缓存区、接收进程用户空间映射到同一接收缓存区
  1. 发送进程通过系统调用 (copy_from_user) 将数据发送到内核缓存区。由于内核缓存区和 接收进程用户空间存在映射关系,故相当于也发送了接收进程的用户空间,实现了跨进程通信

十、简述下Handler机制的总体原理

  1. Looper 准备和开启轮循: Looper#prepare()初始化线程独有的 Looper 以及 MessageQueue Looper#loop()开启死循环读取 MessageQueue 中下一个满足执行时间的 Message 尚无 Message 的话,调用 Native 侧的 pollOnce()进入无限等待存在 Message,但执行时间 when 尚未满足的话,调用 pollOnce()时传入剩余时长参数进入有限等待
  2. Message 发送、入队和出队: Native 侧如果处于无限等待的话:任意线程向 Handler 发送 Message 或 Runnable 后,Message 将按照 when 条件的先后,被插 入 Handler 持有的 Looper 实例所对应的 MessageQueue 中适当的位置。 MessageQueue 发现有合适的 Message 插入后将调用 Native 侧的 wake() 唤醒无限等待的线程。这将促使 MessageQueue 的读取继续进入下一次循环,此刻 Queue 中已有满足条件的 Message 则 出队返回给 Looper Native 侧如果处于有限等待的话:在等待指定时长后 epoll_wait 将返回。线程继续读取 MessageQueue, 此 刻因为时长条件将满足将其出队 Looper 处理Message 的实现:
  3. Looper 得到 Message 后回调 Message 的 callback 属性即 Runnable,或依据 target 属性即 Handler,去执行 Handler 的回调。存在 mCallback属性的话回调 Handler$Callback 反之,回调 handleMessage()

十一、 Looper 存在哪?如何可以保证线程独有?

Looper实例被管理在静态属性sThreadLocal中ThreadLocal内部通过ThreadLocalMap持有Looper,key为ThreadLocal实例本身,value即为Looper实例每个Thread都有一个自己的ThreadLocalMap,这样可以保证每个线程对应一个独立的 Looper实例,进而保证 myLooper()可以获得线程独有的 Looper 彩蛋:一个 App 拥有几个 Looper 实例?几个 ThreadLocal 实例?几个 MessageQueue 实例?几个Message 实例?几个Handler实例一个线程只有一个 Looper实例一个 Looper 实例只对应着一个 MessageQueue实例一个MessageQueue 实例可对应多个 Message 实例,其从 Message 静态池里获取,存在50的上限一个线程可以拥有多个 Handler 实例,其Handler 只是发送和执行任务逻辑的入口和出口 ThreadLocal 实例是静态的,整个进程共用一个实例。每个 Looper 存放的 ThreadLocalMap 均弱引用它作为 key

十二、如何理解 ThreadLocal 的作用?(六)

首先要明确并非不是用来切换线程的,只是为了让每个线程方便程获取自己的 Looper 实例,见 Looper#myLooper()后续可供 Handler 初始化时指定其所属的 Looper 线程也可用来线程判断自己是否是主线程

十三、ActivityManagerService是什么?什么时候初始化的?有什么作用?九

ActivityManagerService 主要负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作,其职责与操作系统中的进程管理和调度模块类似。ActivityManagerService进行初始化的时机很明确,就是在 SystemServer进程开启的时候,就会初始化ActivityManagerService。(系统启动流程)如果打开一个App的话,需要AMS去通知zygote进程,所有的Activity的生命周期AMS来控制

十四、ActivityThread是什么?ApplicationThread是什么?他们的区别

1、ActivityThread 在 Android中它就代表了 Android的主线程,它是创建完新进程之后,main函数被加载,然后执行一个loop的循环使当前线程进入消息循环,并且作为主线程。 2、ApplicationThread ApplicationThread是 ActivityThread的内部类,是一个Binder对象。在此处它是作为IApplicationThread对象的server端等待client端的请求然后进行处理,最大的client就是AMS。

十五、 Instrumentation是什么?和ActivityThread是什么关系?

AMS与 ActivityThread之间诸如Activity的创建、暂停等的交互工作实际上是由Instrumentation具体操作的。每个 Activity都持有一个Instrumentation对象的一个引用,整个进程中是只有一个Instrumentation。mInstrumentation的初始化在ActivityThread::handleBindApplication函数。可以用来独立地控制某个组件的生命周期。ActivitystartActivity方法。startActivity会调用mInstrumentation .execStartActivity(); mInstrumentation 掉用 AMS, AMS 通过 socket 通信告知 Zygote 进程 fork 子进程。

最后

此外我整理了一套Android面试题合集,除了以上面试题,还包含【Java 基础、集合、多线程、虚拟机、反射、泛型、并发编程、Android四大组件、异步任务和消息机制、UI绘制、性能调优、SDN、第三方框架、设计模式、Kotlin、计算机网络、系统启动流程、Dart、Flutter、算法和数据结构、NDK、H.264、H.265.音频编解码、FFmpeg、OpenMax、OpenCV、OpenGL ES

大厂 Framework 面试必备 Handler&Binder&AMS 面试题_用户空间

有需要的朋友详细Vx关注公众号:岛上码农编程!!!


标签:面试题,映射,Framework,Binder,实例,线程,Looper,进程
From: https://blog.51cto.com/u_16175630/7150895

相关文章

  • “金九银十”的秋招季,请收下这套互联网中大厂Android面试题大全(含答案解析)
    金九银十,每年9、10月份各大互联网公司都会周期性地发生人事变动,无论是刚进入社会的职场菜鸟,还是准备跳槽的老手,都想在这个时候获得新的工作,或迎来晋升涨薪的最佳机会。不同于往年的是今年的互联网寒冬好像更冷一点,形式更严峻了一些,不少公司都在裁员,可能在求职中有一大部分人经历了......
  • elasticSearch常见的面试题
    常见的面试问题描述使用场景es集群架构3个节点,根据不同的服务创建不同的索引,根据日期和环境,平均每天递增60*2,大约60Gb的数据。调优技巧设计阶段的调优根据业务增长的需求,采取日期模版创建索引,通过rolloverAPI实现滚动索引定义条件,生成新的索引,但都指向一个别名根据别名对索引进行......
  • KubeSphere 社区双周报 | Java functions framework 支持 SkyWalking | 2023.8.4-8.17
    KubeSphere社区双周报主要整理展示新增的贡献者名单和证书、新增的讲师证书以及两周内提交过commit的贡献者,并对近期重要的PR进行解析,同时还包含了线上/线下活动和布道推广等一系列社区动态。本次双周报涵盖时间为:2023.08.04-2023.08.17。贡献者名单新晋KubeSphereCon......
  • python 面试题第一弹
    1.如何理解Python中的深浅拷贝浅拷贝(ShallowCopy)创建一个新的对象,该对象的内容是原始对象的引用。这意味着新对象与原始对象共享相同的内存地址,因此对于可变对象来说,如果修改了其中一个对象,另一个对象也会受到影响。浅拷贝通常使用copy模块的copy()函数或者对象的copy()方法来......
  • Python game engine framework All In One
    PythongameengineframeworkAllInOneRen'PyRen'Py视觉小说引擎是一款开放源代码的自由软件引擎,用来创作透过电脑叙述故事的视觉小说。Ren'Py之名是Ren'ai与Python两词混合而成。Ren'ai为日文,意指“恋爱”,而Python是Ren'Py所使用的语言环境。和其他流行的视觉小说......
  • 2023年Android中高级最全面试题(含大厂原题+解析)
    前言又快要到了一年一度的金九银十黄金跳槽时节,也是互联网大厂疯狂招人的时期,现在应该有很多Android程序员已经按耐不住了。但是现在网上的面试题资料太多了,而且有些面试题已经过时甚至是漏洞百出。今天结合自己前段时间的面试经历和几位大厂大佬交流讨论总结出这份2023年Android中......
  • 使用.NET Framework进行Windows桌面应用程序开发
    当编写涉及使用.NETFramework进行Windows桌面应用程序开发的博客时,您可以涵盖从界面设计到用户交互和数据处理的各个方面。以下是一个简要的指南,您可以在博客中展开介绍,同时结合示例代码来说明。1.创建项目和界面设计项目创建:使用VisualStudio创建新的WindowsForms应用程序项......
  • AQS和JUC面试题
    【讲义】第2讲:AQS和JUC⼀、ReentrantLock重⼊锁1.1>概述1.2>中断响应lockInterruptibly()1.3>锁申请等待限时tryLock(longtime,TimeUnitunit)1.4>公平锁和⾮公平锁1.5>AQS源码解析⼆、Condition重⼊锁的搭配类三、Semaphore信号量四、ReadWriteLock读写锁五、C......
  • Robot Framework安装以及RIDE界面介绍
    RobotFramework安装以及RIDE界面介绍1.RobotFramework框架的底层是基于python,所以在安装RobotFramework之前,我先介绍一下python的一些注意点,因为后续RobotFramework的安装都将基于pip来安装。不管在windows系统下,还是在linux系统下,很经常就会遇到一个关于python版本的问题,那么......
  • vue面试题1
    VUE11.那你能讲一讲MVVM吗?MVVM是Model-View-ViewModel缩写,也就是把MVC中的Controller演变成ViewModel。Model层代表数据模型,View代表UI组件,ViewModel是View和Model层的桥梁,数据会绑定到viewModel层并自动将数据渲染到页面中,视图变化的时候会通知viewModel层更新数据。2.简单......