1. 怎么跨进程传递大图片
考察点
- 了解各种跨进程传输数据的方式及各自优缺点
- 了解TransactionTooLargeException的触发原因和底层机制
- 了解Bitmap传输底层原理
跨进程传大图有哪些方案
- 给图片保存到固定的地方,传key值(路径)给对方
- 问题:性能差,把图片写到文件需要耗时,对方读取文件也需要耗时
- 通过IPC的方式转发图片数据
- 不经过文件系统,但是需要多次拷贝
IPC方式传图
- Binder:性能好,使用方便,但是大小有限制
- Socket、管道:两次拷贝,也有大小限制
- 共享内存:性能不错
- 主要注意点
- 1.性能,减少拷贝次数
- 2.内存泄漏,资源及时关闭
TransactionTooLargeException
- 发出去的或者返回的数据量太大
- Binder缓存用于该进程所有正在进行中的Binder事务
- 进程弃用binder机制会映射一块内存,大小是1M
- 跨进程通信申请的缓冲区大小是不能超过1M的
- 所有binder事务共享这1M内存空间,应该尽量避免同时跑多个事务,尤其是数据量很大的事务
- 大数据量打碎分批发,或按需发(官方建议)
总结 跨进程传递大图片的方式
- 图片写到文件,路径传到另一个进程,再读出来
- intent传图,但是容易抛异常,原因是什么
- binder调用传图,底层ashmem机制
- 图115
- 图115
2. ThreadLocal原理
考察点
- ThreadLocal的适用于什么场景?
- ThreadLocal的使用方式是怎样的?
- ThreadLocal的实现原理是怎样的?
ThreadLocal在FrameWork中的使用
- Looper
- 图116
- 图116
- Choreorgapher
- 图117
- 图117
原理
- 每一个线程都有一张表,其实就是一个数组,key和value都存储在数组中
- key存储在weakReference中,value对应对象如Looper、Choreorgapher等
- 一个应用里可以定义多个ThreadLocal,ThreadLocal都有自己的哈希值,哈希值根据hashCounter计算
- 算出hash值之后,对表的size取余数,就能算出key:value在表中的index值
- 如果发生了hash冲突,就会从当前index开始向下遍历数组,放在空闲的位置上
- 代码如下:
- 图119
- 图119
总结
- 同一个ThreadLocal对象,在不同线程get返回不同value
- Thread对象里有张表,保存ThreadLocal到value的映射关系
- 这张表是怎么实现的?(见上面的原理分析)
- 是如何解决hash冲突的?(见上面的原理分析)
3. 说说Looper的副业(待完善)
- Looper里可以监听其它描述符
- 创建管道,跨进程传数据,用looper监听描述符事件
4. 怎么检查线程有耗时任务
两种情况
- 正常的,轻微阻塞
- 不正常的,严重阻塞
检测机制
- WatchDog:
- Framework自带,检查system_server中系统服务是否正常
- 用于检查死锁或者线程异常
- BlockCanary
- 开源框架,用于检查线程是否有耗时任务
WatchDog WatchDog的作用上面说过:一是检查是否发生了死锁,二是检查线程是否被任务blocked
- WatchDog是一个线程
- 看下WatchDog的关键变量:
- mHandlerCheckers是核心列表,添加了多个HandlerChecker
- 每一个Checker都对应了一个线程,比如主线程、前台线程、IO线程等,这几个线程都是system_server中非常重要的工作线程
- 每一个HandlerChecker下都有一个Monitor列表
- addMonitor实质上是向mMonitorChecker加了一个BinderThreadMonitor,用于检测binder线程是否正常
- 图121
看下下图
- 第一个MonitorChecker用户检查系统服务是否发生了死锁,在单独的线程中检查,
- 原理就是在另外的线程中去尝试拿到锁,拿到了就正常返回
- 如果一直拿不到,就可能是产生了死锁问题
- 如图AMS中代码细节
- 图122
- 图122
- 同时服务还会把自己的工作线程new一个HandlerChecker,也注册到watchDog,每一个handlerChecker都会对应一个线程,在线程中派发handlerChecker
BlockCanary 原理就是通过messageLogging在消息分发前后的时间戳打印,利用时间戳的差算出消息执行耗时
5. 怎么同步处理消息
「同步处理消息」:我们发了一个消息到另外一个线程去处理,并没有直接返回,而是挂在那里等待消息处理完毕,有些时候还需要拿到消息处理结果,这就是同步处理消息
适用场景如图124
应用要访问另一个进程的服务,请求会调到服务进程的binder线程池中,binder线程切换到工作线程处理请求,工作线程工作的时候binder线程会一直等待,应用端也会一直等着,等到处理完成后返回结果给给应用
6. 你去了解framework是为了解决一个什么样的问题,怎么解决的?
考察点
- 你有没有解决复杂问题的经验
- 你有没有深入研究底层原理的习惯
- 你的知识体系是否有一定深度
7. 应用组件相关题目
- 为什么Activity在onResume之后才会显示出来
- ActivityThread handleResumeActivity时WindowManager才会addView并makeVisible
- bindService的时候Rebind总是调不到,研究原理
- TODO
- 广播onReceive的context可否启动Activity, 显示Dialog?
- TODO
- 发现provider的onCreate比Application还早,研究一下
- Application 构造方法 –> Application.attachBaseContext –> ContentProvider.onCreate –> Application.onCreate –> Activity.onCreate
- 看下 ActivityThread.java 的 handleBindApplication方法:
- 图130
8. 消息通信相关题目
- intent带的数据量大了会异常,研究原因
- binder机制 1m限制
- 需要跨进程传大图,研究Bitmap传输原理,Ashmem机制
- 想知道Handler消息延时的精度怎么样,去了解原理
- 延迟处理不是延迟发送,精度不太准确
- 为什么有时候IdleHandler调不到,去了解原理
- 主线程繁忙,一直在处理消息
- 比如:
- 在View的onDraw方法里面无限制的直接或者间接调用View的invalidate方法。
- 做一个无限轮询的View动画。
9.性能优化相关题目
- ANR了,看主线程是否有耗时任务
- 卡顿掉帧,了解屏幕刷新机制,研究Choregrapher
- 启动速度优化,了解应用启动原理
- 内存优化,清理不必要的资源
10. Android FrameWork用到了哪些设计模式?请举例说明
单例模式
- Framework中:SingleTon类,应用IAM
- 图126
- 图126
- 线程内:
- 线程间/进程内:Choreographer,ThreadLocal线程私有,不同线程获取不同的实例,同一线程获取同一实例
- 图125
- 图125
- 进程间:
- 进程间的内存是相互隔离的,如何保证在进程间的单例呢,这个时候就需要一个中间人,所谓的中间人,就是他可以和所有进程进行通信,由其确保这个对象是单例的
- 下面的例子中,单例是ServiceManager,中间人是binder驱动
- 对所有的进程来说,ServiceManager对应的binder句柄都是一个即0,这样binder驱动在转发请求的时候都会送往同一个目标,即ServiceManager所在的进程,这样就能保证ServiceManager是跨进程单例的
- 图127
观察者模式
- 分为进程内和跨进程两种
- 应用:
- 广播(同时支持进程内和进程间)
- 推送(基于网络)
- 应用层
- Rxjava
- RecyclerView:Adapter的notifyChanged、notifyItemChanged等
代理模式
- 静态代理
- ActivityManagerProxy
- IActivityManager的接口调用都会转交给mRemote
- 128
- ActivityManagerProxy
- 动态代理
11.Framework中有什么你觉得设计很巧妙的地方,请举例说明
- Binder调用,模糊进程边界,让IPC调用像在一个进程中一样简单,使开发者不必过分关注跨进程通信的事,将重点放在业务上
- 请求的转发:请求由应用端发起,通过binder驱动转发给目标进程去处理,目标进程处理完毕之后,会把返回结果通过binder驱动传回Client端
- binder对象的传递:包含实体对象和引用对象,这两种实体在经过binder驱动层的时候会自动转换,比如binder实体对象跨进程之后就变成了代理对象,代理对象回到实体对象所在的进程之后又会还原为实体对象;不论实体对象还是代理对象,应用层拿到的都是统一的接口对象,方便调用
- Bitmap大图传输,高性能
- 传递匿名共享内存的句柄,到了目标进程之后映射内存,这样目标进程就能获取bitmap的像素数据
- Zygote预加载资源创建应用进程,共享资源,这样应用进程就不必重复加载资源
- init进程启动后,会启动一些系统服务和Zygote进程zygote预加载资源(系统主题资源,常用的类等 )并启动system_server,并开启循环等待socket请求,孵化应用进程
- 图129
- Intent解耦,模糊进程边界,把调用者和组件之间进行解耦
- 应用只需要表达自己的意图,由AMS选择处理意图的组件
- 调用者和组件之间可能是同一进程的,也可能不是同一进程的
- 比如广播,发广播的时候带intent,由AMS解析intent,匹配接收的receiver,receiver可能是同一进程的,也可能是不同进程的,只要用intent表达意图就可以了
1. Android设备开机之后发生了什么
- 1.Bootloader引导开机
- 长按开机键后,主板通电,引导芯片开始执行预设代码,加载引导程序到内存中,主要做内存检查和硬件初始化工作
- 2.Linux kernel
- 加载硬件驱动 如硬件驱动/显示驱动/输入驱动/媒体驱动
- 硬件抽象层解决并适配不同驱动标准,为上层应用提供统一的api
- 3.C++ framework
- 创建linux中的第一个用户进程,init(pid=1)
- 孵化adbd进程(断点调试)和logd进程(日志打印)
- 孵化第一个java进程->zygote进程(连接java世界和native c++世界)
- 4.Android framework
- zygote进程
- ZygoteInit.java会启动systemserver系统服务进程
- 所有app进程都由zygote进程孵化而来
- app进程创建完成之后,都会由ZygoteInit反射调用ActivityThread.java(main函数),使得app得以启动
- ZygoteInit.java是由C++代码通过类加载机制加载的,最终调用到了ZygoteInit.java的实例方法
- ZygoteInit.java中main方法会启动SystemServer系统服务进程
- SystemServer进程创建之后会执行入口类SystemServer.java,创建ActivityManagerService/WindowManagerService/PowerManagerService/InputManagerService
- zygote进程
- 5.Apps
- 所有的系统服务都创建成功之后,会执行Launcher启动流程
2. ZygoteInit.java做了那些事情
- 预加载资源
- 启动SystemServer进程,三类,当所有系统服务都启动完成之后,会通知AMS调用systemReady启动Launcher应用
- 引导服务 17个
- AMS 四大组建调度服务(安卓10之后Activity调度交给ATMS)
- Activity Task Manager Service 安卓10之后Activity调度服务
- PKMS 安装,卸载,扫描管理等
- PowerManagerService 电源管理服务
- Dex字节码优化服务等
- 启动核心服务 9个
- BatteryService 电池状态管理
- WebviewUpdateService Webview升级服务
- GpuService Gpu驱动加载服务
- 启动其他服务 90+
- AlarmManagerService 时钟服务
- NetworkStatsService 网络状态服务
- WindowManagerService 窗口管理服务
- AudioService 音频服务
- 引导服务 17个
- 创建Socket服务
- 进入阻塞状态,等待连接,用以来处理来自AMS申请进程创建的请求
3. Launcher相关
- 如何定制一款Launcher
- 启动Activity添加category.HOME和category.DEFAULT
- 系统如何识别已安装应用那个是Launher应用
- Intent.category_home属性
4. ActivityThread
- main方法
- ①初始化主线程looper ③主线程开始轮训
- ②attach()向AMS注册自己,以便AMS调度自己
- attachApplication:应用进程向AMS注册本地应用进程,方便AMS调度四大组件及生命周期,从此应用与Framework建立关联,有了生命力
- bindApplication:ActivityThread反射创建Application对象,调用onCreate函数
- 通过AMS(ATMS)再次启动Activity,进程创建时未启动的那个Activity会恢复继续创建
- 在ActivityThread中以反射形式创建Activity实例对象,接着会调度Activity的核心方法`
activity.attach()
activity.onCreate()
- 在ActivityThread中以反射形式创建Activity实例对象,接着会调度Activity的核心方法`
5. View树相关
- 如何在Activity的onCreate和onResume获取view宽高?
- 由于setContentView之后view的测绘工作还没有开始,正确获取view宽高的方式是使用view.post或者view.viewTreeObserver.addOnGlobalLayoutListener监听器获取
- viewTree绘制流程是从哪里开始的?
- 在Activity的onCreate、onStart、onResume都没有view绘制相关的代码,说明view绘制在onResume之后
- 查看ActivityThread源码可以发现,handleResumeActivity()函数调用performResumeActivity之后会调用WindowManager.addView(…)函数,windowManager的具体实现在WindowManagerGlobal中,这里创建了ViewRootImpl,ViewRootImpl关联了decorView,然后便开始了测量、布局、绘制的流程
- ViewRootImpl
- 特点
- WindowSession将Window添加到WindowManagerService
- 页面View树的顶层节点,关联Window和View
- Choreographer接收Vsync同步信号触发View的三大流程
- WindowInputEventReceiver接收屏幕输入事件,分发手势
- 接收Vsync同步信号,触发View的动画重绘
- viewRootImpl中对UI测量布局绘制的消息是一条异步消息
- 页面上所有view的测量Measure工作都由ViewRootImpl的performMeasure()来实现,同理layout->performLayout()和draw->performDraw()
- 特点
- 小结:View三大流程
- ①ActivityThread的handleResumeActivity()函数调用了WindowManagerGlobal的addView函数
- ②在WindowManagerGlobal的addView函数中,实例化了ViewRootImpl,并且将传入的decorView绑定
- ③在ViewRootImpl的setView函数中,调用了requestLayout,requesetLayout会先对线程进行检查(checkThread),检查通过之后,就会通过Cherographer注册一个垂直同步信号监听,屏幕上每一帧刷新都会执行PerformTraversals函数,PerformTraversals函数中会调用performMeasure、performLayout、performDraw,进而调用到了viewGroup中,viewGroup会遍历所有子view,调用子view的measure、layout、draw函数
6. Activity之手势分发
- 手势的接收在ViewRootImpl内部类WindowInputEventReceiver中接收的
- doProcessInputEvents分发了手势(输入)事件,从队列头部开始派发
- 事件的分发采用了责任链设计模式,依次为ViewpostImeInputStage->NativePostImeInputStage->EarlyPostImeInputStage->ImeInputStage->ViewPreImeInputStage->NativePreImeInputStage
- 点击事件在ViewpostImeInputStage的onProcess中处理
- 小结:如上图
- 在ViewRootImpl中,使用WindowInputEventReceiver接收手势事件,向系统注册了一个输入事件的监听,一旦有输入事件就会派发给Receiver,在一个输入事件被派发给应用之前,会经过几个阶段的预处理
- 对于一个屏幕点击事件而言,最终会调用ViewRootImpl的processPointerEvents方法,进而调用decorView的dispatchTouchEvent方法,这个方法又通过window.callback接口转发到Activity中
- 为什么不转发到viewGroup中呢,这样做是为了使开发者能够在Activity中监听或者自定义手势的拦截,多了一次机会
- 在Activity的dispatchTouchEvent中,又把手势分发给了phoneWindow,在phonewindow中兜兜转转又把手势转给了DecorView,最后就到达了view或者view
文章来源于互联网:Android FrameWork面试点集合
阅读全文
下载说明:
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.dandroid.cn/archives/21146,转载请注明出处。
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.dandroid.cn/archives/21146,转载请注明出处。
评论0