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
相关推荐
·云扬·12 分钟前
MySQL四大系统库详解:作用、核心表与实用SQL查询
android·sql·mysql
普马萨特12 分钟前
移动网络信号指标与单位整理(2G/3G/4G/5G Android vs IoT)
android·网络·物联网
de之梦-御风21 分钟前
【电视投屏】针对“局域网投屏开源项目(Android 手机 ↔ Android TV)
android·智能手机·开源
threelab36 分钟前
Merge3D 三维引擎中 GeoJSON 数据加载的整体设计
android·3d
优选资源分享1 小时前
Escrcpy 便携版 v2.0.0:安卓手机电脑同屏软件
android·智能手机·电脑
2501_915918412 小时前
介绍如何在电脑上查看 iPhone 和 iPad 的完整设备信息
android·ios·小程序·uni-app·电脑·iphone·ipad
TheNextByte12 小时前
如何通过蓝牙将照片从 iPhone 分享到Android ?
android·gitee·iphone
2501_916008892 小时前
没有 Mac 如何在 Windows 上创建 iOS 应用描述文件
android·macos·ios·小程序·uni-app·iphone·webview
Android系统攻城狮4 小时前
Android ALSA进阶之处理PCM的ioctl命令snd_pcm_lib_ioctl:用法实例(一百)
android·pcm·alsa·音频进阶
诸神黄昏EX12 小时前
Android Build系列专题【篇六:VINTF机制】
android