简介

Window简介

Android中,Window是一个重要部分,用户看到的界面、触摸显示界面进行一系列操作都涉及到Window。但实际上,Window本身并不具备绘制功能。
该篇简单介绍下Window的一点内容,同时总结下WMS的启动过程。在下篇会逐步介绍一个Activity是如何创建出窗口 并 添加到WMS中的。
该篇基于Andorid10的代码。

窗口涉及到一下几个功能:

  1. 窗口管理-WMS
    WMS管理窗口的创建、添加、删除、大小、层级等等。

  2. 输入中转-IMS(InputManagerService)
    触摸窗口产生触摸事件,IMS对触摸事件进行处理,最后寻找一个最合适窗口进行反馈处理。

  3. 窗口动画 —WindowAnimator
    窗口间进行切换时,使用窗口动画可以实现更好的效果,窗口动画主要由WindowAnimator管理。可以在开发者模式菜单找到相应设置。

  4. Surface管理 —SurfaceFlinger
    窗口不具备有绘制的功能,因此每个窗口都需要有一块Surface来供自己绘制。为每个窗口分配Surface是由WMS来完成的。
    Surface就像画布,然后通过Canvas或OpenGL绘制。
    SurfaceFlinger的作用主要是merge Surface,它接受多个来源的Surface图形显示数据(所有Surface:所有Window的Surface,特殊情况 有些Surface跟Window无关,如StrictMode),然后将他们合并(根据特定顺序Z-order),然后发送到显示设备。如最常见的界面是3层,顶部的statusbar,底部的导航栏,应用界面。

WMS简介

WMS同之前总结过的AMS、PMS一样(链接:AMS的启动AMS之应用的第一次启动过程PMS的启动及应用的安装过程),是系统服务,作为Binder的服务端。 下表简单对比列出下:

系统服务 binder服务端 binder客户端 服务名
AMS ActivityManagerService(extends IActivityManager.Stub) ActivityManager activity(Context.ACTIVITY_SERVICE)
PMS PackageManagerService(extends IPackageManager.Stub) PackageManager package
WMS WindowManagerService(extends IWindowManager.Stub) WindowManager window(Context.WINDOW_SERVICE)

一般获取方法:
获取binder客户端,与服务通信,类似:
ActivityManager am = (ActivityManager) context.getSystemService(“activity”);
ActivityManager am = context.getSystemService(ActivityManager.class);
从ServiceManager获取服务的Binder,类似:
IBinder binder = ServiceManager.getService(Context.ACTIVITY_SERVICE);
下面两个也是用的ServiceManager.getService():
IActivityManager mgr = ActivityManager.getService();
PackageManagerService pm = (PackageManagerService) ServiceManager.getService(“package”);

WMS的启动过程

之前总结了 AMS的启动AMS之应用的第一次启动过程PMS的启动及应用的安装过程。 这里WMS的启动类似,下面会简单介绍下。

WMS是在system server启动后的startOtherServices()中启动。下面截取了其中关于WMS相关的代码。

//SystemServer.java
private void startOtherServices() {
    final Context context = mSystemContext;
    WindowManagerService wm = null;
   
    try {
        // WMS 依赖 sensor service
        ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);
        //标记1:StartWindowManagerService
        //创建WMS实例
        wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
                new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
        //注册WINDOW_SERVICE 服务到 ServiceManager。 
        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);

        //标记2:SetWindowManagerService
        //WMS设置到AMS/ATMS中。     
        mActivityManagerService.setWindowManager(wm);
        
        //标记3:WindowManagerServiceOnInitReady
        //WMS初始化完成。 
        wm.onInitReady();

        inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
        inputManager.start();

        mDisplayManagerService.windowManagerAndInputReady();
    }

    // Before things start rolling, be sure we have decided whether
    // we are in safe mode.
    final boolean safeMode = wm.detectSafeMode();
    try {
        //标记4:MakeDisplayReady
        //初始化显示信息
        wm.displayReady();
    } 

    if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
        if (!isWatch) {
            try {
                statusBar = new StatusBarManagerService(context, wm);
                ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
            } 
        }
    }

    try {
        //标记5:MakeWindowManagerServiceReady
        //通知WMS系统准备好了,初始化完成了。    
        wm.systemReady();
    } 

    final Configuration config = wm.computeNewConfiguration(DEFAULT_DISPLAY);
    DisplayMetrics metrics = new DisplayMetrics();
    WindowManager w = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    w.getDefaultDisplay().getMetrics(metrics);
    context.getResources().updateConfiguration(config, metrics);

    final WindowManagerService windowManagerF = wm;

    mActivityManagerService.systemReady(() -> {      
        try {
            startSystemUi(context, windowManagerF);
        } 
    }, BOOT_TIMINGS_TRACE_LOG);
}

startOtherServices()中,创建了WindowManagerService对象 并 注册了服务Context.WINDOW_SERVICE。然后进行了各种初始化等操作。
注意上面的注释,下面主要看下其中的5行代码(标记1-标记5)。

标记1:wm = WindowManagerService.main(…)

//public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
//WindowManagerService.java
private static WindowManagerService sInstance;
static WindowManagerService getInstance() {
    return sInstance;
}

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);
}

@VisibleForTesting
public static WindowManagerService main(final Context context, final InputManagerService im,
        final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
        ActivityTaskManagerService atm, TransactionFactory transactionFactory) {
    //android.display线程中执行
    DisplayThread.getHandler().runWithScissors(() ->
            sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
                    atm, transactionFactory), 0);
    return sInstance;
}


private WindowManagerService(Context context, InputManagerService inputManager,
        boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
        ActivityTaskManagerService atm, TransactionFactory transactionFactory) {
    ......
    //ActivityTaskManagerService
    mAtmService = atm;
    //context是mSystemContext   system server进程上下文
    mContext = context;
    mOnlyCore = onlyCore;
    mInTouchMode = context.getResources().getBoolean(
            com.android.internal.R.bool.config_defaultInTouchMode);
    mMaxUiWidth = context.getResources().getInteger(
            com.android.internal.R.integer.config_maxUiWidth);
    mLowRamTaskSnapshotsAndRecents = context.getResources().getBoolean(
            com.android.internal.R.bool.config_lowRamTaskSnapshotsAndRecents);
    //输入法管理
    mInputManager = inputManager; // Must be before createDisplayContentLocked.
    mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
    mDisplayWindowSettings = new DisplayWindowSettings(this);
    mPolicy = policy;
    //管理窗口动画
    mAnimator = new WindowAnimator(this);
    mRoot = new RootWindowContainer(this);
    mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
    mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
    mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
    mActivityManager = ActivityManager.getService();
    mActivityTaskManager = ActivityTaskManager.getService();
    mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
    mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
    mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
    ......
}

WindowManagerService.main()主要就是创建了WindowManagerService对象。
WindowManagerService的构造方法没有完整附上了,没什么特别的,基本是初始化并保存 WMS中需要用到的各种对象等数据。上面列出了几个常见的。
DisplayThread.getHandler().runWithScissors(),注意这里是DisplayThread(继承ServiceThread),是在android.display线程上执行。

题外话DisplayThread.getHandler().runWithScissors(() -> sInstance = new WindowManagerService(...),0);lambda表达式 ,这里相当于:

DisplayThread.getHandler().runWithScissors(
    new Runnable() {
        @Override
        public void run() {
            sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
                    atm, transactionFactory)
        }
    }, 0);

标记2:mActivityManagerService.setWindowManager(wm)

这个很简单,wm被设置的到AMS和ATMS中。

//ActivityManagerService.java
public void setWindowManager(WindowManagerService wm) {
    synchronized (this) {
        mWindowManager = wm;
        mActivityTaskManager.setWindowManager(wm);
    }
}

标记3:wm.onInitReady()

//WindowManagerService.java
public void onInitReady() {
    //初始化PhoneWindowManager (PhoneWindowManager implements WindowManagerPolicy)
    initPolicy();

    // Add ourself to the Watchdog monitors.
    Watchdog.getInstance().addMonitor(this);
    //SurfaceControl.openTransaction();
    openSurfaceTransaction();
    try {
        //水印,这里了解了下
        createWatermarkInTransaction();
    } finally {
        closeSurfaceTransaction("createWatermarkInTransaction");
    }

    showEmulatorDisplayOverlayIfNeeded();
}

private void initPolicy() {
    //android.ui线程上执行
    UiThread.getHandler().runWithScissors(new Runnable() {
        @Override
        public void run() {
            WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());
            mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);
        }
    }, 0);
}

void createWatermarkInTransaction() {
    ...
    File file = new File("/system/etc/setup.conf");
    ...
    try {
        ...
        if (line != null) {
            String[] toks = line.split("%");
            if (toks != null && toks.length > 0) {
                // TODO(multi-display): Show watermarks on secondary displays.
                final DisplayContent displayContent = getDefaultDisplayContentLocked();
                mWatermark = new Watermark(displayContent, displayContent.mRealDisplayMetrics,
                        toks);
            }
        }
    }
    ...
}

onInitReady()这里几个地方记录下,个人觉得比较值得注意的:

  1. initPolicy()中,mPolicy即PhoneWindowManager对象,从开始处startOtherServices()中可以看到。startOtherServices()创建了PhoneWindowManager,这里完成了PhoneWindowManager的init()操作。

  2. initPolicy()中,是运行在UiThread,也是继承的ServiceThread。执行mPolicy.init()。

  3. createWatermarkInTransaction():这个可以看一下。这是在window manager的窗口上添加水印。这个功能几乎没有用过,尝试了下,效果如下图。

往后跟踪,可以看到:显示的字符配置到/system/etc/setup.conf里的,Watermark有个解析过程(类似解密),详细的可以自己看下Watermark的构造方法。如下图中显示的字符串“WMS”,我在setup.conf配置的是“A8B2A<%30”,%后面是字体大小。“A8B2A<”即“WMS”。

wms_watermark

标记4:wm.displayReady()

//WindowManagerService.java
public void displayReady() {
    synchronized (mGlobalLock) {
        if (mMaxUiWidth > 0) {
            mRoot.forAllDisplays(displayContent -> displayContent.setMaxUiWidth(mMaxUiWidth));
        }
        //全局设置仅适用于默认显示。设置Display size、Display density、Display scaling mode。
        //getDefaultDisplayContentLocked()。
        final boolean changed = applyForcedPropertiesForDefaultDisplay();
        mAnimator.ready();
        mDisplayReady = true;
        if (changed) {
            reconfigureDisplayLocked(getDefaultDisplayContentLocked());
        }
        mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
                PackageManager.FEATURE_TOUCHSCREEN);
    }

    try {
        //初始化配置完成,ATMS完成第一次Configuration更新
        mActivityTaskManager.updateConfiguration(null);
    } catch (RemoteException e) {
    }

    updateCircularDisplayMaskIfNeeded();
}

看下注释。这里主要是初始化显示信息。初始化配置完成,ATMS完成第一次Configuration更新。

标记5:wm.systemReady()

//WindowManagerService.java
public void systemReady() {
    mSystemReady = true;
    mPolicy.systemReady();
    ...
}

系统初始化完成,通知WMS系统准备好了。这里主要完成:mPolicy.systemReady()

在标记3 时,有在android.ui线程执行的mPolicy.init(),这里有mPolicy.systemReady()
mPolicy是PhoneWindowManager,关于这两个方法这里不关注,在后续类似事件传递时应该会再触及。

版权声明:本文为fanglongxiang原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/fanglongxiang/p/13951212.html