安卓系统面经_Android面经(6/20)WMS深入浅出
牛客高级系列专栏:
安卓(安卓系统开发也要掌握)
- 想通关安卓面试,请看:《150道安卓高频面试题目录及答案链接》
- 想通关安卓系统面试,请看:《140道安卓系统Framework面试题目录及答案链接》
- 想进阶安卓开发,请看:《Android进阶知识体系解析_15大安卓进阶必备知识点》
- 想了解安卓APP完整开发流程,请看:《安卓APP完整开发流程》
- 想掌握安卓App性能优化,请看:《安卓性能优化讲解和实战专栏》
- 想掌握Gradle语法,制作Gradle插件,请看:《安卓Gradle语法解析和实践大全》
嵌入式
- 想通关嵌入式面试,请看: 《111道嵌入式面试题目录及答案链接》
- 想多掌握几个嵌入式项目,请看:《6个嵌入式项目交流分享(附源码)》
- 本人是2020年毕业于广东工业大学研究生:许乔丹,有国内大厂CVTE和世界500强企业安卓开发经验,该专栏整理本人从嵌入式Linux转Android系统开发过程中对常见安卓系统开发面试题的理解;
- 1份外卖价格助您提高安卓面试准备效率,为您面试保驾护航!!
正文开始⬇
面试题预览
- WMS是什么?有什么功能?⭐⭐⭐⭐⭐
- WMS、AMS与Activity间的联系是什么?⭐⭐⭐
- Activity应用进程在什么时候会调用addView,进而由WMS来处理addWindow 呢?⭐⭐⭐
1 概述
WMS(WindowManagerService)是一个重要的系统服务,由SystemServer进程启动,发生异常时会自动重启,直到系统关机时才能退出。在WMS没有运行之前,开机动画由BootAnimation直接通过OpenGL ES与SurfaceFlinger的配合来完成。
1.1 WMS的职责
- 1.窗口管理 WMS是窗口的管理者,它负责窗口的启动、添加和删除,另外窗口的大小和层级也是由WMS进行管理的。窗口管理的核心成员有DisplayContent、WindowToken和WindowState。
- 2.窗口动画 窗口间进行切换时,使用窗口动画可以显得更炫一些,窗口动画由WMS 的动画子系统来负责,动画子系统的管理者为WindowAnimator。
- 3.输入系统的中转站 通过对窗口的触摸从而产生触摸事件,InputManagerService(IMS)会对触摸事件进行处理,它会寻找一个最合适的窗口来处理触摸反馈信息,WMS是窗口的管理者,它作为输入系统的中转站再合适不过了。
- 4.Surface管理 窗口并不具备绘制的功能,因此每个窗口都需要有一块Surface来供自己绘制,为每个窗口分配Surface是由WMS来完成的。
WMS的职责可以简单总结为如图所示:
WMS承载着和“界面”有关的数据和属性,管理和“界面”有关的状态。就像N个演员参演的话剧:WMS是导演、SurfaceFlinger是摄像机、ViewRoot是演员个体。
2 WMS的启动流程
SystemServer进程启动后,会去启动一系列服务,其中就包括WMS。
/**
* 进程的入口点
*/
public static void main(String[] args) {
new SystemServer().run();
}
private void run() {
...
// 启动 AMS PowerManagerService PackageManagerService 等服务
startBootstrapServices(t);
// 启动了BatteryService UsageStatsService WebViewUpdateService
startCoreServices(t);
// CameraService AlarmManagerService VrManagerService
startOtherServices(t);
...
}
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
...
t.traceBegin("StartWindowManagerService");
// WMS needs sensor service ready
ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);
mSensorServiceStart = null;
// 创建WMS对象,与AMS关联
wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
// 将WMS加入SM,使用的时候去里面拿就行
ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
/* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
t.traceEnd();
t.traceBegin("SetWindowManagerService");
// WMS与AMS关联
mActivityManagerService.setWindowManager(wm);
t.traceEnd();
t.traceBegin("WindowManagerServiceOnInitReady");
// 初始化监视器等等
wm.onInitReady();
t.traceEnd();
...
}
2.1 关键代码解析
2.1.1 WindowManagerService.main函数
WindowManagerService提供了一个静态的main函数,WMS真正的创建工作是在这里面实现的。
我们看看 WMS 的 main 方法:
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm) {
return main(context, im, showBootMsgs, onlyCore, policy, atm,
SurfaceControl.Transaction::new, Surface::new, SurfaceControl.Builder::new);
}
public static WindowManagerService main(final Context context, final InputManagerService im,final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,ActivityTaskManagerService atm, Supplier<SurfaceControl.Transaction> transactionFactory,Supplier<Surface> surfaceFactory,
Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {
DisplayThread.getHandler().runWithScissors(() ->
sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
atm, transactionFactory, surfaceFactory, surfaceControlFactory), 0);
return sInstance;
}
上面通过 DisplayThread 的 getHandler 方法获取到了 DisplayThread 的 Handler 实例。DisplayThread 是一个单例的前台线程,用来处理需要低延时显示的相关操作,并且只能由 WindowManager,DisplayManager 和 INputManager 试试执行快速操作。runWithScissors 表达式中创建了 WMS 对象。
2.1.2 WMS构造方法
private WindowManagerService(Context context, InputManagerService inputManager,
boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm, TransactionFactory transactionFactory) {
...
//保存 IMS ,这样就持有了 IMS 的引用。
mInputManager = inputManager; // Must be before createDisplayContentLocked.
//初始化 WindowManagerPolicy ,它用来定义一个窗口测量所需要遵循的规范。
mPolicy = policy;
//创建了 WindowAnimator,它用于管理所有的窗口动画。
mAnimator = new WindowAnimator(this);
//创建 RootWindowContainer 对象,根窗口容器
mRoot = new RootWindowContainer(this);
//获取 DisplayManager 服务
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
//获取 AMS,并持有他的引用
mActivityManager = ActivityManager.getService();
//将 LocalService 添加到 LocalServices 中
LocalServices.addService(WindowManagerInternal.class, new LocalService());
...
}
在上面 WMS的启动中 WMS 创建完成后会调用 wm.onInitReady 方法,下面我们来看一下这个方法:
2.1.3 onInitReady
public void onInitReady() {
initPolicy();
//将 WMS 添加到 Watchdog 中,Watchdog 用来监控一下系统关键服务的运行情况。
//这些被监控的服务都会实现 Watchdog.Monitor 接口,Watchdog 每分钟都会对
//被监控的服务进行检测,如果被监控的服务出现了死锁,则会杀死 Watchdog 所在的进程
Watchdog.getInstance().addMonitor(this);
......
}
private void initPolicy() {
UiThread.getHandler().runWithScissors(new Runnable() {
@Override
public void run() {
WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());
mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);
}
}, 0);
}
和 WMS 的 main 方法类似,WindowManagerPolicy (简称 WMP) 是一个接口,init 的具体实现在 PhoneWindowManager(PWM) 中,并且通过上面代码我们知道,init 方法运行在 android.ui线程中。因此他的线程优先级要高于 android.display 线程,必须等 init 方法执行完成后,android.display线程才会被唤醒从而继续执行下面的代码。
WindowManagerPolicy 用来定义一个窗口策略所要遵循的通用规范,并提供了 WindowManager 所有的特定 UI 行为 他的具体实现类为 PhoneWindowManager
3 WMS、AMS与Activity间的联系
一个 Activity 在启动过程中,需要多个系统服务的支持——而其中最主要的就是 AMS 和WMS。可以参见下图:
APP不能直接调用AMS和WMS的接口,因为不在同一个进程里。 AMS和WMS是在SystemServer的进程里,APP也是独立的进程,那么就需要用Binder来做进程间通讯。ServiceManager保存了SystemServer启动每个系统Service时候的Binder接口,那么APP就可以通过SystemServer来获取AMS和WMS的接口。
问1:每个APP是独立的进程,有自己的虚拟机,那么这个虚拟机是怎么来的呢?答:从Zygote fork出APP进程时候,复制的Zygote的虚拟机。
ActivityThread.main函数里会做一个非常重要的事情,就是上报。然后就会进入Looper.loop(),在这里loop里保证APP进程的一直运行了。
其中上报走的是ActivityThread.attach接口,该接口通过ActivityManager拿到AMS的本地代理类,进而通过Binder调用AMS的attachApplication方法来通知AMS创建成功并上报APP的PID,那么AMS就可以通过PID来管理APP,保证APP的安全性。
下面我们从两个方面来详细介绍WMS、AMS与Activity这三者的关系。
3.1 IPC通信
Activity 运行在应用程序进程中,而 AMS和WMS则运行在系统相关进程中,它们之间的通信需要Binder的支持。从这个角度来看,它们之间的关系如下图所示。
应用程序访问WMS服务首先得通过ServiceManager,因为WMS是实名Binder Service;除此之外,WMS还需要针对每个Activity提供另一种匿名的实现,即IWindowSession——这有点类似于SurfaceFlinger中的Client。WMS和SurfaceFlinger是面向系统中所有应用程序服务的,如果客户的任何"小请求"都需要直接通过它们来处理,那么无疑会加重两者的负担,进而影响到系统的整体响应速度。所以WMS通过IWindowManager:openSession()向外界开放一个打开Session 的接口,然后客户端的一些"琐碎"杂事就可以找Session解决了。
3.2 内部组织形式
当一个新的Activity被启动时(startActivity),它首先需要在AMS中注册——此时AMS会在内部生成一个 ActivityRecord来记录这个 Activity;另外因为 Activity 是四大组件中专门用于 UI 显示的,所以WMS也会对它进行记录——以WindowState来表示。所以从服务内部组织方式的角度来讲,三者的关系如下图所示:
如图所示,WMS 除了利用 WindowState 来保存一个"窗口"相关的信息外,还使用AppWindowToken来对应AMS中的一个ActivityRecord。这样三者间就形成非常紧密的联系,为窗口的显示与管理打下了坚实的基础。
4 窗口属性
4.1 窗口类型与层级
Android 支持的窗口类型很多,不过我们可以将它们统一划分为三大类,即 Application Window,System Window 和 Sub Window。另外各个种类下还细分为若干子类型,且都在WindowManagerjava中定义。如下所示:
4.1.1 Application Window
普通的应用程序都属于这一类。
4.1.2 Sub Window
从“Sub Window”的字面意思可以了解到,这类窗口将附着在其他Window中,因而被称为“子窗口”。具体包括如下子类型,如下表所示。
4.1.3 System Window
系统程序所采用的窗口类型。如下表所示:
4.2 窗口策略
4.3 窗口属性
这两节都是些概念性的东西,有兴趣的可以找相关资料学习。推荐《深入理解Android内核设计思想》这本书。
5 窗口的添加过程
前面介绍过窗口分为系统窗口和应用程序的窗口,下面分别介绍这两种窗口的添加过程。
5.1 系统窗口添加
这里以StatusBar添加过程为案例进行描述。
/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
private void addStatusBarWindow() {
makeStatusBarView();
mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
mRemoteInputManager.setUpWithPresenter(this, mEntryManager, this,
new RemoteInputController.Delegate() {
public void setRemoteInputActive(NotificationData.Entry entry,
boolean remoteInputActive) {
mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive);
entry.row.notifyHeightChanged(true /* needsAnimation */);
updateFooter();
}
public void lockScrollTo(NotificationData.Entry entry) {
mStackScroller.lockScrollTo(entry.row);
}
public void requestDisallowLongPressAndDismiss() {
mStackScroller.requestDisallowLongPress();
mStackScroller.requestDisallowDismiss();
}
});
mRemoteInputManager.getController().addCallback(mStatusBarWindowManager);
mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
}
这里先调用了makeStatusBarView方法来创建状态栏的控件树,然后通过StatusBarWindowManager来add到WMS中。
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
public void add(View statusBarView, int barHeight) {
// Now that the status bar window encompasses the sliding panel and its
// translucent backdrop, the entire thing is made TRANSLUCENT and is
// hardware-accelerated.
mLp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, //宽度填满
barHeight,
WindowManager.LayoutParams.TYPE_STATUS_BAR, //类型为statusbar
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE //不接受按键事件
| WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
PixelFormat.TRANSLUCENT);
mLp.token = new Binder();
mLp.gravity = Gravity.TOP;
mLp.softInputMode
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
2020年研究生毕业后,工作重心由嵌入式Linux转为安卓系统,Android发展已经很多年,网上面向中初级Android系统开发的面经还比较少,也不够集中,因此梳理出本专栏,本专栏收集了本人工作中持续积累的众多安卓系统知识,持续更新中。