安卓系统面经_Android面经(6/20)WMS深入浅出

牛客高级系列专栏:

安卓(安卓系统开发也要掌握)

嵌入式

  • 本人是2020年毕业于广东工业大学研究生:许乔丹,有国内大厂CVTE和世界500强企业安卓开发经验,该专栏整理本人从嵌入式Linux转Android系统开发过程中对常见安卓系统开发面试题的理解;
  • 1份外卖价格助您提高安卓面试准备效率,为您面试保驾护航!!

正文开始⬇

面试题预览

  1. WMS是什么?有什么功能?⭐⭐⭐⭐⭐
  2. WMS、AMS与Activity间的联系是什么?⭐⭐⭐
  3. 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的职责可以简单总结为如图所示:
alt

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

alt

3 WMS、AMS与Activity间的联系

一个 Activity 在启动过程中,需要多个系统服务的支持——而其中最主要的就是 AMS 和WMS。可以参见下图: alt

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进程的一直运行了。

alt

其中上报走的是ActivityThread.attach接口,该接口通过ActivityManager拿到AMS的本地代理类,进而通过Binder调用AMS的attachApplication方法来通知AMS创建成功并上报APP的PID,那么AMS就可以通过PID来管理APP,保证APP的安全性。 alt

下面我们从两个方面来详细介绍WMS、AMS与Activity这三者的关系。

3.1 IPC通信

Activity 运行在应用程序进程中,而 AMS和WMS则运行在系统相关进程中,它们之间的通信需要Binder的支持。从这个角度来看,它们之间的关系如下图所示。

alt

应用程序访问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来表示。所以从服务内部组织方式的角度来讲,三者的关系如下图所示:

alt

如图所示,WMS 除了利用 WindowState 来保存一个"窗口"相关的信息外,还使用AppWindowToken来对应AMS中的一个ActivityRecord。这样三者间就形成非常紧密的联系,为窗口的显示与管理打下了坚实的基础。

4 窗口属性

alt

4.1 窗口类型与层级

Android 支持的窗口类型很多,不过我们可以将它们统一划分为三大类,即 Application Window,System Window 和 Sub Window。另外各个种类下还细分为若干子类型,且都在WindowManagerjava中定义。如下所示:

4.1.1 Application Window

普通的应用程序都属于这一类。 alt

4.1.2 Sub Window

从“Sub Window”的字面意思可以了解到,这类窗口将附着在其他Window中,因而被称为“子窗口”。具体包括如下子类型,如下表所示。

alt

4.1.3 System Window

系统程序所采用的窗口类型。如下表所示:

alt alt

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%内容,订阅专栏后可继续查看/也可单篇购买

Android系统面试题全解析 文章被收录于专栏

2020年研究生毕业后,工作重心由嵌入式Linux转为安卓系统,Android发展已经很多年,网上面向中初级Android系统开发的面经还比较少,也不够集中,因此梳理出本专栏,本专栏收集了本人工作中持续积累的众多安卓系统知识,持续更新中。

全部评论
付费内容全崩。。。。。。
点赞 回复 分享
发布于 04-01 16:15 山西
图片都崩了
点赞 回复 分享
发布于 03-01 23:59 广东
大佬,很多图片都崩了
点赞 回复 分享
发布于 2024-07-13 13:18 广东
梳理的好到位
点赞 回复 分享
发布于 2024-05-02 15:38 上海

相关推荐

白火同学:能。我当初应届沟通了1200,收简历50,面试10左右吧,加油投吧
点赞 评论 收藏
分享
评论
2
6
分享

创作者周榜

更多
牛客网
牛客企业服务