Android 显示系统 - View体系、WMS

文章目录

一、WMS、View体系与SurfaceFlinger的关系

这里的框图重点体现WMS、View和SF这几个主体,不会糅杂太多细节和分支,框架应该如此!

1)WMS是管理者;

2)View是生成者;

3)SF是消费者,也是硬件资源管理者;

WMS、View都属于上层使用者,在Android显示子系统 原理探索中 可以简单了解框架(逻辑的堆砌过于庞大),SF另起篇幅重点介绍。

二、View体系

几乎所有的APK应用程序的UI界面都是由view来描述,

1)View整体框架

1、可以看出View系统主要在JAVA层实现,绘图工具依赖natvie层的图形库;

2)Activity、window、view的关系

1)一个APP有多个Activity(Activity是一个粗略的UI界面显示和处理容器,占整个界面);

2)一个Activity界面有多个大大小小的Window窗口;

3)精细的窗口内容则是view,view才是UI内容真正的生产者,Activity和Window都是布局;

4)View是基本单元,派生出各式各样的图形效果Buttom/Menu/ImageView

复制代码
/android/frameworks/base/core/java/android/view
/android/frameworks/base/core/java/android/widget/Button.java
/android/frameworks/base/core/java/android/widget/Toolbar.java
/android/frameworks/base/core/java/android/widget/ImageView.java

5)可以看到,Activity/WMS/view主要是JAVA实现,需要用到硬件资源才会进入到natvie;

3)View Tree

1、Android View System最终会构建出这样一个View Tree,记录在DisplayList (HWUI);

2、每一个View内容都应该是单独绘制,当界面需要更新时,只需更新变化的view;

4)view数据结构

复制代码
View的结构非常庞大,抽取部分UI相关的举例说明

1.View
public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {
    //args
    String VIEW_LOG_TAG = "View";
    //function
    setScrollBarSize(int scrollBarSize);
}

2、Bitmap : 用于存放像素数据(GPU/CPU生产的像素数据),比如Drawable以及它的众多子集


3.Drawable概念
Bitmap文件就可以说是Drawable,也是最简单的Drawable,只有图像数据本身,不带任何附加信息
一般而言,Drawable除了图形数据外,还封装了相关的操作函数-创建、销毁、简单的图形处理、绘制等

4.Drawable
public abstract class Drawable {
    public interface Callback {
        void invalidateDrawable(@NonNull Drawable who);
        void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when);
        void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what);
    }
}

1、View中的UI属性

2、View的回调接口

3、View.invalidate

使当前UI界面判定无效,从而引起重绘动作,使新绘制的界面生效;

5)UI显示的三要素

UI三要素指的是UI尺寸大小、位置和内容

1、UI三要素对应的方法

复制代码
1.UI尺寸大小、位置和内容对应的处理方法
/android/frameworks/base/core/java/android/view/ViewRootImpl.java
performMeasure() //计算View对象在UI界面上的绘图区域大小
performLayout()  //计算View对象在UI界面上的绘图位置
performDraw()    //绘制UI

2.performDraw()
/android/frameworks/base/core/java/android/view/ViewRootImpl.java
--draw(fullRedrawNeeded, usingAsyncReport && mSyncBuffer);
----Surface surface = mSurface; //画板
----mAttachInfo.mThreadedRenderer.invalidateRoot(); //硬件绘制(OpenGLRenderer 即使用GPU绘制)
/android/frameworks/base/core/java/android/view/ThreadedRenderer.java
------draw()
/android/frameworks/base/core/java/android/view/ViewRootImpl.java
----drawSoftware(surface, mAttachInfo, xOffset, yOffset) //软件绘制

3.使用软件绘制drawSoftware
/android/frameworks/base/core/java/android/view/ViewRootImpl.java
----drawSoftware()
------canvas = mSurface.lockCanvas(dirty); //先取得一个Canvas对象,在此基础上作图
------canvas.translate(-xoff, -yoff); //坐标转换
------mView.draw(canvas);  //由顶层元素开始遍历绘制
/android/frameworks/base/core/java/android/view/Surface.java
------surface.unlockCanvasAndPost(canvas); //绘制完毕,释放Canvas并"提交结果"
--------unlockSwCanvasAndPost(canvas);
----------nativeUnlockCanvasAndPost(mLockedObject, canvas);
/android/frameworks/base/core/jni/android_view_Surface.cpp
------------canvas.setBuffer(nullptr, ADATASPACE_UNKNOWN);
------------surface->unlockAndPost();
/android/frameworks/native/libs/gui/Surface.cpp
--------------mLockedBuffer->unlockAsync(&fd);
--------------queueBuffer(mLockedBuffer.get(), fd);

1)注意软件绘制由于是CPU处理,因此是同步操作;
2)Canvas是一个绘图工具,应用程序只需要调用它的接口即可完成图形的绘制,绘制的原理涉及到图形库,这里不展开


4.使用硬件绘制流程(简单了解)
cursor - 如何调用到 GL 库
/android/frameworks/base/core/java/android/view/ThreadedRenderer.java
ThreadedRenderer.draw() (Java)
    ↓
/android/frameworks/base/graphics/java/android/graphics/HardwareRenderer.java
syncAndDrawFrame() (继承自 HardwareRenderer)
    ↓ [JNI 调用]
/android/frameworks/base/libs/hwui/renderthread/RenderProxy.cpp
RenderProxy.syncAndDrawFrame() (Native)
    ↓
CanvasContext.draw() (在 RenderThread 中)
    ↓
OpenGLRenderer.draw()
    ↓
glDrawArrays() / glDrawElements() (OpenGL ES API)
    ↓
Mesa3D
    ↓
Panfrost 驱动
    ↓
GPU 硬件 (通过 DRM/KMS)

1)注意硬件绘制由于是GPU处理,CPU不会等待GPU处理完成,因此是异步操作;
2)各个view的绘图任务交由ThreadedRenderer线程统一处理,它会收集绘图任务,最终发给GPU统一处理;
3)既然是异步,CPU如何得知GPU渲染完成?通过Fence驱动机制 同步


在现代设备上,几乎都能支持硬件绘制,我们重点看硬件绘制和硬件GPU渲染!

2、View的draw方法

复制代码
/android/frameworks/base/core/java/android/view/View.java
draw(Canvas canvas)  //没有fading的情况
--drawBackground(canvas);  //绘制背景
--onDraw(canvas); //绘制内容,调用派生类的重载方法
/android/frameworks/base/core/java/android/widget/ImageView.java
----canvas.clipRect(); //没有占满整个父view,则需要裁剪
----canvas.translate(mPaddingLeft, mPaddingTop);  //裁剪后进行坐标转换 确定相对位置
----mDrawable.draw(canvas);
--dispatchDraw(canvas); //绘制子对象
--onDrawForeground(canvas);
--drawDefaultFocusHighlight(canvas);

3、View的画板Surface

1)Surface的数据来源有哪些?
复制代码
Surface是一块空白内存,谁来填充?可以是OpenGL 、Skia等等图形引擎

1.Window Type
/android/frameworks/native/libs/nativewindow/include/system/window.h
enum {
    /* Buffers will be queued by EGL via eglSwapBuffers after being filled using
     * OpenGL ES.
     */
    NATIVE_WINDOW_API_EGL = 1,  //表示Surface数据由GL库填充

    /* Buffers will be queued after being filled using the CPU */
    NATIVE_WINDOW_API_CPU = 2, //表示Surface数据由CPU构造填充

    /* Buffers will be queued by Stagefright after being filled by a video
     * decoder.  The video decoder can either be a software or hardware decoder.
     */
    NATIVE_WINDOW_API_MEDIA = 3, //表示Surface数据由video decoder硬件构造填充

    /* Buffers will be queued by the the camera HAL.*/
    NATIVE_WINDOW_API_CAMERA = 4, //表示Surface数据由camera构造填充
};
2)Canva与Surface
3)View向SF索要画板过程

4、Android原生硬件绘制JAVA示例

复制代码
/android/frameworks/base/tests/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasSurfaceViewActivity.java

案例是用的SurfaceView.java的流程。这个流程和实际上从ViewRootImpl.java中通过performDraw的流程类似

6)View Animation

Android的三种动画(帧动画、View动画、属性动画):https://juejin.cn/post/7556911205157748746

动画的本质是时间和图像的关系

复制代码
Transformation :交互
Interpolator : 内插程序

/android/frameworks/base/core/java/android/view/animation

/android/frameworks/base/core/java/android/view/animation/Animation.java

View与Animation的交互

三、WMS

1、WMS总体设计

1)WMS是显示框架中唯一不依赖硬件,纯软件实现的模块,重点是管理窗口的层级和属性 - 简单理解操控窗口的XYZ轴,既然是管理,必然和其它GUI显示相关的组件 密切相关;

2)WMS并不是必须的,比如开机动画是不依赖WMS的,只依赖SurfaceFlinger和OpenGL-ES;

3)WMS的逻辑十分庞大和复杂,要完全掌握几乎不现实,先把握住框架才是首要任务;

1)WMS的设计思想

1)可以看到WMS是统筹各个GUI组件的作用,打个比方:

SurfaceFlinger是摄像机、View系统是演员、InputManagerService是用户给系统传达命令的通讯设备、AMS是剧本、而WMS则是导演,根据用户的意图和既定的剧本来演绎 "舞台剧";

2)WMS不需要实际干活(操作硬件),而是根据各种信息 指导 各个组件干活,因此它的逻辑是相当复杂;

3)从计算机I/O系统的角度来看,WMS至少要完成以下两个功能

1、全局的窗口管理 - 窗口的添加和删除

1)设置启动窗口、设置窗口动画、窗口大小计算、窗口层级

2、全局的事件管理派发(input),事件来自于IMS;

4)窗口类型

1、Application Window - 应用程序自身的Activity

2、System Window - 系统状态栏、壁纸等

3、Sub Window - 点击Menu出现的应用程序菜单

2)WMS的对外接口

复制代码
/android/frameworks/base/core/java/android/view/IWindowManager.aidl
AIDL工具会将aidl转化为IWindowManager.java
1)接口功能 - 获取屏幕尺寸、锁定屏幕、截取屏幕等
IWindowSession openSession(in IWindowSessionCallback callback); //与WMS建立一个Session连接
void getInitialDisplaySize(int displayId, out Point size);
void addWindowToken(IBinder token, int type, int displayId, in Bundle options);
void setForcedDisplayDensityForUser(int displayId, int density, int userId);

3)WMS的启动与初始化

复制代码
1、WMS与其它服务一样,由SystemServer启动
/android/frameworks/base/services/java/com/android/server/SystemServer.java
import com.android.server.wm.WindowManagerService;
public void run {
    wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
    ServiceManager.addService(Context.WINDOW_SERVICE, wm, DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
}

2. WindowManagerService
/android/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public class WindowMangerService extends IWindowManager.Stub implements WindowManagerPolicy.WindowManagerFuncs {

}


3.WindowManagerService构造函数 - 极其庞大
private WindowManagerService(Context context, InputManagerService inputManager,
            boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
            ActivityTaskManagerService atm, DisplayWindowSettingsProvider
            displayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,
            Supplier<Surface> surfaceFactory,
            Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {
    1.与众多服务关联起来
    mInputManager = inputManager;
    mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
    mSurfaceControlFactory = surfaceControlFactory;
    mPolicy = policy; //窗口策略
    LocalServices.addService(WindowManagerPolicy.class, mPolicy);
    mAnimator = new WindowAnimator(this); //窗口动画
    mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
    mKeyguardDisableHandler = KeyguardDisableHandler.create(mContext, mPolicy, mH); //键盘-SystemUi
    mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
    mActivityManager = ActivityManager.getService();
}

4)WMS的工作方式

1、给WMS服务发送消息

复制代码
1.消息发送
mH.sendMessage()
2.WMS处理消息
/android/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public void handleMessage(Message msg) {
}

2、WMS、AMS和Activity的aidl通信

复制代码
/android/frameworks/base/core/java/android/app/IActivityManager.aidl
/android/frameworks/base/core/java/android/view/IWindowSession.aidl
/android/frameworks/base/core/java/android/view/IWindow.aidl
/android/frameworks/base/core/java/android/view/IWindowManager.aidl

5)Window Policy

复制代码
1.作用是根据不同的产品形态(Phone/Tablet/TV/车载)来 选用不同的窗口组合
2.Window Policy有四个相关的类:WindowManagerPolicy、PhoneWindowManager、PolicyManager、Policy
3.
/android/frameworks/base/services/core/java/com/android/server/policy/WindowManagerPolicy.java
/android/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
/android/frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java

2、窗口的添加过程

复制代码
1.以SystemUI的Notification窗口为例
/android/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
public class NotificationShadeWindowControllerImpl {
    attach() //Adds the notification shade view to the window manager.
    /android/frameworks/base/core/java/android/view/WindowManagerImpl.java
    --mWindowManager.addView(mNotificationShadeView, LayoutParams);
    /android/frameworks/base/core/java/android/view/WindowManagerGlobal.java
    ----mGlobal.addView()
    /android/frameworks/base/core/java/android/view/ViewRootImpl.java
    ------root = new ViewRootImpl(view.getContext(), display);
    ------root.setView(view, wparams, panelParentView, userId);
    --------requestLayout(); //发起layout请求
     /android/frameworks/base/core/java/android/view/WindowlessWindowManager.java
    --------mWindowSession.addToDisplayAsUser()
    /android/frameworks/base/services/core/java/com/android/server/wm/Session.java
    ----------mService.addWindow()
    /android/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
    ------------parentWindow = windowForClientLocked(null, attrs.token, false);//寻找父窗口
    ------------WindowState win = new WindowState();  //生成一个WindowState来管理窗口
    ------------displayPolicy.adjustWindowParamsLw(win, win.mAttrs); //调整window属性
    ------------win.mToken.addWindow(win);
    ------------displayPolicy.addWindowLw(win, attrs);
}

3、Surface管理

WMS需要向SF申请Surface,并交由应用程序进行绘制

1)Surface实现重点

2)Surface关系图

3)Surface的创建

复制代码
1.Surface的创建
/android/frameworks/base/core/java/android/view/ViewRootImpl.java
public final Surface mSurface = new Surface();
private final SurfaceControl mSurfaceControl = new SurfaceControl();

/android/frameworks/base/core/java/android/view/ViewRootImpl.java
performTraversals()
--relayoutWindow(params, viewVisibility, insetsPending);
/android/frameworks/base/services/core/java/com/android/server/wm/Session.java
----mWindowSession.relayout(mWindow, params, mSurfaceControl, ...)
/android/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
-----mService.relayoutWindow()
-------createSurfaceControl(outSurfaceControl, result, win, winAnimator);
/android/frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java
---------surfaceController = winAnimator.createSurfaceLocked();


/android/frameworks/base/core/jni/android_view_SurfaceControl.cpp
nativeCreate()
--client->createSurface()

2.Surface的业务操作
nativeCreateTransaction()
nativeApplyTransaction()

4、启动窗口和窗口动画

复制代码
为了更好的体验,用户程序的窗口切换 可以添加在它们之间增加 启动窗口和窗口动画,让其过渡效果更加顺滑

1.启动窗口的添加与销毁
/android/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
addWindow()
/android/frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java
--activity.attachStartingWindow(win);

2.窗口动画
/android/frameworks/base/core/java/android/view/View.java
public void startAnimation(Animation animation) {
        animation.setStartTime(Animation.START_ON_FIRST_FRAME);
        setAnimation(animation);
        invalidateParentCaches();
        invalidate(true);
}

/android/frameworks/base/services/core/java/com/android/server/wm/WindowAnimator.java
相关推荐
阿巴斯甜6 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker6 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95277 小时前
Andorid Google 登录接入文档
android
黄林晴9 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab21 小时前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_1 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android