Surface的管理

Surface是窗口能真正显示到物理屏幕上的基础,由surfaceflinger管理,可以通过WindowStateAnimator.java中的变量mDrawState来查看每个窗口相关的surface的状态。

surface有5中状态:

WindowStateAnimator.java

//Surface还没有创建。

staticfinal int NO_SURFACE = 0;

//Surface已经创建,但是窗口还没绘制,这时surface是隐藏的。

staticfinal int DRAW_PENDING = 1;

//窗口已经完成了第一次绘制,但是surface还没有显示,Surface将会在下次layout时显示出来。

staticfinal int COMMIT_DRAW_PENDING = 2;

//窗口的绘制请求已经提交,surface还没真正的显示,这通常用于延迟显示surface直到这个token中的所有窗口都已准备显示。

staticfinal int READY_TO_SHOW = 3;

//窗口已经第一次在屏幕上显示出来。

staticfinal int HAS_DRAWN = 4;

  1. String drawStateToString() @WindowStateAnimator.java{
  2. switch (mDrawState) {
  3. case NO_SURFACE: return "NO_SURFACE";
  4. case DRAW_PENDING: return "DRAW_PENDING";
  5. case COMMIT_DRAW_PENDING: return "COMMIT_DRAW_PENDING";
  6. case READY_TO_SHOW: return "READY_TO_SHOW";
  7. case HAS_DRAWN: return "HAS_DRAWN";
  8. default: return Integer.toString(mDrawState);
  9. }
  10. }
  11. int mDrawState;

1),Surface的申请

WMS只负责窗口的层级和属性,surfaceflinger负责真正的将数据合成并显示到屏幕上。UI数据的绘制需要有画板,就是BufferQueue的支持,不管是那类窗口都要向surfaceflinger申请相应的layer,进一步得到缓冲区的使用权。这一切的启动是在viewroot中执行viewtree遍历时,会想WMS申请一个surface。

具体是从relayoutWindow开始,重新布局窗口,应用进程通过mWindowSession.relayout让WMS向surfaceflinger申请画板,然后通过最后一个参数mSurface将结果返回。

  1. final Surface mSurface = new Surface();
  2. private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
  3. boolean insetsPending) throws RemoteException@ViewRootImpl.java {
  4. int relayoutResult = mWindowSession.relayout(
  5. mWindow, mSeq, params,
  6. (int) (mView.getMeasuredWidth() * appScale + 0.5f),
  7. (int) (mView.getMeasuredHeight() * appScale + 0.5f),
  8. viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
  9. mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
  10. mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingConfiguration,
  11. mSurface);
  12. }

接着看surface是怎么申请的,先看IwindowSession中的处理。

  1. public int relayout(android.view.IWindow window, int seq, android.view.WindowManager.LayoutParams attrs, int requestedWidth, int requestedHeight, int viewVisibility, int flags, android.graphics.Rect outFrame, android.graphics.Rect outOverscanInsets, android.graphics.Rect outContentInsets, android.graphics.Rect outVisibleInsets, android.graphics.Rect outStableInsets, android.graphics.Rect outOutsets, android.graphics.Rect outBackdropFrame, android.content.res.Configuration outConfig, android.view.Surface outSurface) throws android.os.RemoteException
  2. @IwindowSession.java$IWindowSession$Stub$Proxy{
  3. //通过Binder向服务端发送请求TRANSACTION_relayout,
  4. mRemote.transact(Stub.TRANSACTION_relayout, _data, _reply, 0);
  5. //收到恢复后,从reply中取出结果,这是客户端的实现,具体取出的是什么,就要看服务端写入的什么了。
  6. outSurface.readFromParcel(_reply);
  7. }

//看服务端的处理。

  1. public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
  2. @IwindowSession.java$IWindowSession$Stub{
  3. switch (code){
  4. //跟客户端相同的业务码TRANSACTION_relayout
  5. case TRANSACTION_relayout:
  6. {
  7. //服务器端,首先创建了一个surface对象,然后调用WMS的relayoutWindow函数为这个对象赋值,最后通过_arg15.writeToParcel把结果写入回复的parcel中。如果一个类想在aidl机制中,客户度与服务端之间传递,就要继承Parcelable接口,并实现writeToParcel方法。
  8. android.view.Surface _arg15;
  9. _arg15 = new android.view.Surface();
  10. //这里会调用服务端Session.java中的实现,进一步调用WMS中的relayoutWindow。
  11. int _result = this.relayout(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11,
  12. _arg12, _arg13, _arg14, _arg15);
  13. _arg15.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
  14. }
  15. }
  16. }
  1. public int relayoutWindow(Session session, IWindow client, int seq,
  2. WindowManager.LayoutParams attrs, int requestedWidth,
  3. int requestedHeight, int viewVisibility, int flags,
  4. Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
  5. Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame,
  6. Configuration outConfig, Surface outSurface) @WindowManagerService.java{
  7. //每个windowState都有一个mWinAnimator来处理窗口的退出和进入动画。
  8. WindowStateAnimator winAnimator = win.mWinAnimator;
  9. //设置用户请求的宽、高,这值也会影响到surface的属性。
  10. win.setRequestedSize(requestedWidth, requestedHeight);
  11. //生成surface对象,通过outSurface.copyFrom返回客户端。
  12. result = createSurfaceControl(outSurface, result, win, winAnimator);
  13.  
  14. updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
  15. false /*updateInputWindows*/)
  16.  
  17. mWindowPlacerLocked.performSurfacePlacement();
  18. }

WMS并没有直接生成surface的操作,继续跟踪createSurfaceControl。

  1. private int createSurfaceControl(Surface outSurface, int result, WindowState win,
  2. WindowStateAnimator winAnimator) @WindowManagerService.java{
  3. // createSurfaceLocked将会生成一个真正的surface,并有SurfaceControl来管理。
  4. WindowSurfaceController surfaceController = winAnimator.createSurfaceLocked();
  5. if (surfaceController != null) {
  6. surfaceController.getSurface(outSurface);
  7. }
  8. }

//管理Surface的mSurfaceControl变量是在WindowSurfaceController的构造函数中生成的。

  1. WindowSurfaceController createSurfaceLocked() @WindowStateAnimator.java{
  2. mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession,
  3. attrs.getTitle().toString(),
  4. width, height, format, flags, this);
  5. }

接着看SurfaceControl的构造函数。

  1. long mNativeObject;
  2. public SurfaceControl(SurfaceSession session,
  3. String name, int w, int h, int format, int flags){
  4. //调用的nativeCreate函数,将会建立跟SurfaceFlinger的联系。
  5. mNativeObject = nativeCreate(session, name, w, h, format, flags);
  6. }
  1. static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
  2. jstring nameStr, jint w, jint h, jint format, jint flags) @android_view_SurfaceControl.cpp{
  3. // SurfaceComposerClient是surfaceflinger的代表,opengl es和surface都是在这个类的协助下申请和访问buffer缓冲区。这里是通过 android_view_SurfaceSession_getClient来获取client对象,那么是什么地方创建的呢?
  4. sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
  5. sp<SurfaceControl> surface = client->createSurface( String8(name.c_str()), w, h, format, flags);
  6. surface->incStrong((void *)nativeCreate);
  7. return reinterpret_cast<jlong>(surface.get());
  8. }

继续看哪里创建了client(SurfaceComposerClient)对象。从这个函数的实现,可以知道,这是从jni层获取java层的属性,所以创建相关类实例的地方应该在native层创建了对象,然后通过jni保存在了java层。

  1. sp<SurfaceComposerClient> android_view_SurfaceSession_getClient(
  2. JNIEnv* env, jobject surfaceSessionObj) @android_view_SurfaceSession.cpp{
  3. return reinterpret_cast<SurfaceComposerClient*>(
  4. env->GetLongField(surfaceSessionObj, gSurfaceSessionClassInfo.mNativeClient));
  5. }

具体过程,还要从addWindow看起。

  1. public int addWindow(…...)@WindowManagerService.java{
  2. //创建WindowState时,将session变量保存在WindowState 的变量mSession中。
  3. WindowState win = new WindowState(this, session, client, token…);
  4. //attach()的实现中,调用mSession的windowAddedLocked()方法。进一步生成了SurfaceSession实例mSurfaceSession(属于Session.java的变量)。
  5. win.attach();
  6. }

//在SurfaceSession的构造函数中,通过native方法创建一个到SurfaceFlinger的连接,就是SurfaceComposerClient实例,这是native的SurfaceComposerClient.cpp对象,这个对象保存在了SurfaceSession.java中的变量mNativeClient中。

  1. private long mNativeClient; // SurfaceComposerClient*
  2. public SurfaceSession() @SurfaceSession.java{
  3. mNativeClient = nativeCreate();
  4. }

在创建WindowState对象时,其构造函数中,同时创建了WindowStateAnimator对象,而且WindowStateAnimator.java的构造函数中也保存了Session对象到其变量mSession中。

  1. WindowStateAnimator(final WindowState win) @WindowStateAnimator.java{
  2. mSession = win.mSession;
  3. }

在调用WindowStateAnimator的createSurfaceLocked函数,创建WindowSurfaceController对象时,把mSession.mSurfaceSession传给了WindowSurfaceController的构造函数,在WindowSurfaceController的构造函数中,这个SurfaceSession对象传给了SurfaceControl。

现在我们直到SurfaceControl.java调用native函数nativeCreate时,获取的SurfaceComposerClient实例client是怎么来的了。

前面说了Surface是有SurfaceControl来管理的,SurfaceControl.java构造函数的nativeCreate就是建立跟surfaceflinger的连接,最终的surface的创建还要有SurfaceFlinger来完成。

  1. sp<SurfaceControl> SurfaceComposerClient::createSurface(
  2. const String8& name,
  3. uint32_t w,
  4. uint32_t h,
  5. PixelFormat format,
  6. uint32_t flags)@SurfaceComposerClient.cpp{
  7. sp<IGraphicBufferProducer> gbp;
  8. //调用Client.cpp的实现,创建IGraphicBufferProducer实例。
  9. status_t err = mClient->createSurface(name, w, h, format, flags,
  10. &handle, &gbp);
  11. //生成native层的 SurfaceControl对象,同时传入IGraphicBufferProducer对象。
  12. sur = new SurfaceControl(this, handle, gbp);
  13. }

回头看前面createSurfaceControl函数中获取surface的方式是surfaceController(WindowSurfaceController.java)的getSurface(outSurface);这个java层方法最终会调用SurfaceControl.cpp中的getSurface方法。

  1. sp<Surface> SurfaceControl::getSurface() const @SurfaceControl.cpp{
  2. mSurfaceData = new Surface(mGraphicBufferProducer, false);
  3. return mSurfaceData;
  4. }

可以看到这里创建了真正的Surface对象,当然这里的对象还是在server端,然后会通过writeToParcel写入reply。这样ViewRootImpl.java这边,也即是客户端就可以利用readFromParcel把它还原出来,实现了对ViewRootImpl.java中mSurface变量的填充。

  1. public int relayout(android.view.IWindow window, int seq, android.view.WindowManager.LayoutParams attrs, int requestedWidth, int requestedHeight, int viewVisibility, int flags, android.graphics.Rect outFrame, android.graphics.Rect outOverscanInsets, android.graphics.Rect outContentInsets, android.graphics.Rect outVisibleInsets, android.graphics.Rect outStableInsets, android.graphics.Rect outOutsets, android.graphics.Rect outBackdropFrame, android.content.res.Configuration outConfig, android.view.Surface outSurface) throws android.os.RemoteException@IWindowSession.java{
  2. //这里就是读取server端的返回值。Surface.java中的 readFromParcel调用了native层的实现nativeReadFromParcel。
  3. outSurface.readFromParcel(_reply);
  4. }

//可以看到客户端新创建了native层的Surface对象,所以和服务端的surface(native层)对象并不是同一个,但是跟surface关联的IGraphicBufferProducer是同一个,实际上Surface的主要职责就是管理用于存储UI数据的内存块。

  1. static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz,
  2. jlong nativeObject, jobject parcelObj) @android_view_Surface.cpp{
  3. Parcel* parcel = parcelForJavaObject(env, parcelObj);
  4. android::view::Surface surfaceShim;
  5. surfaceShim.readFromParcel(parcel, /*nameAlreadyRead*/true);
  6. sp<Surface> sur;
  7. sur = new Surface(surfaceShim.graphicBufferProducer, true);
  8. sur->incStrong(&sRefBaseOwner);
  9. return jlong(sur.get());
  10. }

2),relayoutWindow中还有一个比较重要的调用performSurfacePlacement,功能包括两部分,一是performLayout,计算窗口大小,二是performSurface,对Surface属性的设置,如:setSize,setLayer,setPostion,然后这些变更会告知Surfaceflinger。

  1. public int relayoutWindow(Session session, IWindow client, int seq,
  2. WindowManager.LayoutParams attrs, int requestedWidth,
  3. int requestedHeight, int viewVisibility, int flags,
  4. Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
  5. Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame,
  6. Configuration outConfig, Surface outSurface)@WindowManagerService.java {
  7. mWindowPlacerLocked.performSurfacePlacement();
  8. }

performSurfacePlacement间接调用了performSurfacePlacementInner。

//有些属性发生了变化,要在这里对变更做计算。

  1. private void performSurfacePlacementInner(boolean recoveringMemory) @WindowSurfacePlacer.java{
  2. //在处理surface属性前,先调用 openTransaction,然后对surface属性做处理,但是处理不是立即生效,而是要等到 closeTransaction业务关闭后,统一告知surfaceflinger才会生效。
  3. SurfaceControl.openTransaction();
  4. try {
  5. applySurfaceChangesTransaction(recoveringMemory, numDisplays, defaultDw, defaultDh);
  6. }finally {
  7. SurfaceControl.closeTransaction();
  8. }
  9. //获取默认显示屏的窗口列表。
  10. final WindowList defaultWindows = defaultDisplay.getWindowList();
  11.  
  12. //处理应用切换mService.mAppTransition相关的操作。
  13. defaultDisplay.pendingLayoutChanges |= handleAppTransitionReadyLocked(defaultWindows);
  14. defaultDisplay.pendingLayoutChanges |=mService.handleAnimatingStoppedAndTransitionLocked();
  15. //如果窗口不可见了,销毁他的surface。
  16. boolean wallpaperDestroyed = false;
  17. i = mService.mDestroySurface.size();
  18. if (i > 0) {
  19. //这里有while循环,处理mDestroySurface列表中的每个 WindowState。
  20. WindowState win = mService.mDestroySurface.get(i);
  21. win.destroyOrSaveSurface();
  22. mService.mDestroySurface.clear();
  23. }
  24.  
  25. //移除不在具有可见窗口的token。
  26. for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
  27. final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx);
  28. ArrayList<WindowToken> exitingTokens = displayContent.mExitingTokens;
  29. for (i = exitingTokens.size() - 1; i >= 0; i--) {
  30. WindowToken token = exitingTokens.get(i);
  31. exitingTokens.remove(i);
  32. mWallpaperControllerLocked.removeWallpaperToken(token);
  33. }
  34. }
  35.  
  36. //从task中移除退出的应用程序。
  37. for (int stackNdx = mService.mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
  38. final AppTokenList exitingAppTokens =
  39. mService.mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
  40. AppWindowToken token = exitingAppTokens.get(i);
  41. token.mAppAnimator.clearAnimation();
  42. token.removeAppFromTaskLocked();
  43. }
  44.  
  45. //更新窗口信息到Inputdispatch,因为现在窗口更改已经稳定了。
  46. mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
  47.  
  48. //安排动画的执行。
  49. mService.scheduleAnimationLocked();
  50. }
    1. private void applySurfaceChangesTransaction(boolean recoveringMemory, int numDisplays,
    2. int defaultDw, int defaultDh) @WindowSurfacePlacer.java{
    3. //循环处理每个显示设备,我们只关注主显示屏,
    4. final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx);
    5. WindowList windows = displayContent.getWindowList();
    6. DisplayInfo displayInfo = displayContent.getDisplayInfo();
    7. int repeats = 0;
    8. do {
    9. //while循环,6次后跳出,为什么是6次不知道?
    10. repeats++;
    11. if (repeats > 6) {
    12. displayContent.layoutNeeded = false;
    13. break;
    14. }
    15. //需要的化,计算窗口大小,这个 LAYOUT_REPEAT_THRESHOLD是4,定义在WindowManagerService.java中。
    16. if (repeats < LAYOUT_REPEAT_THRESHOLD) {
    17. performLayoutLockedInner(displayContent, repeats == 1,false /* updateInputWindows */);
    18. }
    19.  
    20. if (isDefaultDisplay) {
    21. //对每一个窗口,调用窗口策略policy(PhoneWindowManager.java)中的方法,应用policy。
    22. mService.mPolicy.beginPostLayoutPolicyLw(dw, dh);
    23. for (int i = windows.size() - 1; i >= 0; i--) {
    24. WindowState w = windows.get(i);
    25. if (w.mHasSurface) {
    26. mService.mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs,
    27. w.mAttachedWindow);
    28. }
    29. }
    30. displayContent.pendingLayoutChanges |=mService.mPolicy.finishPostLayoutPolicyLw();
    31. }
    32. }while (displayContent.pendingLayoutChanges != 0);
    33.  
    34. //针对每个窗口,根据需要应用特效,动画相关等。
    35. for (int i = windows.size() - 1; i >= 0; i--) {
    36. WindowState w = windows.get(i);
    37. w.applyDimLayerIfNeeded();
    38. }
    39. }

Android 7.1 GUI系统-窗口管理WMS-Surface管理(四)的更多相关文章

  1. 图解Android - Android GUI 系统 (2) - 窗口管理 (View, Canvas, Window Manager)

    Android 的窗口管理系统 (View, Canvas, WindowManager) 在图解Android - Zygote 和 System Server 启动分析一 文里,我们已经知道And ...

  2. android Gui系统之WMS(2)----窗口的添加

    Android系统很多,但是最常用的就两类,一类是有系统进场管理的,系统窗口.还有一类就是由应用程序产生的,应用窗口. 1.系统窗口的添加流程 1.1 addStatusBarWindow Phone ...

  3. android Gui系统之WMS(1)----window flags & view flags

    SurfaceFlinger 前面说的,就是一个surface的合成.SurfaceFlinger就是一个默默的记录着,它不会对surface的内容有什么改动. WMS(WindowsManagerS ...

  4. android Gui系统之SurfaceFlinger(1)---SurfaceFlinger概论

    GUI 是任何系统都很重要的一块. android GUI大体分为4大块. 1)SurfaceFlinger 2)WMS 3)View机制 4)InputMethod 这块内容非常之多,但是理解后,可 ...

  5. 图解Android - Android GUI 系统 (5) - Android的Event Input System

    Android的用户输入处理 Android的用户输入系统获取用户按键(或模拟按键)输入,分发给特定的模块(Framework或应用程序)进行处理,它涉及到以下一些模块: Input Reader: ...

  6. android Gui系统之SurfaceFlinger(1)---SurfaceFlinger概论【转】

    转自:https://www.cnblogs.com/deman/p/5584198.html 阅读目录 1.OpenGL & OpenGL ES 2.Android的硬件接口HAL 3.An ...

  7. 图解Android - Android GUI 系统 (1) - 概论

    Android的GUI系统是Android最重要也最复杂的系统之一.它包括以下部分: 窗口和图形系统 - Window and View Manager System. 显示合成系统 - Surfac ...

  8. Android GUI系统

    图解Android - Android GUI 系统 (1) - 概论 图解Android - Android GUI 系统 (2) - 窗口管理系统 图解Android - Android GUI ...

  9. 图解Android - System Service 概论 和 Android GUI 系统

    通过 图解Android - Binder 和 Service 一文中,我们已经分析了Binder 和 Service的工作原理.接下来,我们来简要分析Android 系统里面都有哪些重要的Servi ...

随机推荐

  1. JavaScript实现网页元素的拖拽效果

    以下的页面中放了两个div,能够通过鼠标拖拽这两个元素到任何位置. watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamFja2ZydWVk/font/5a6 ...

  2. Solidworks如何开启自动求解

    1 我打开了一个DWG格式的文件,提示草图太大,关闭的自动求解(就是没法撤销了)   2 工具-草图设定-自动求解   3 随便做一个标注,然后发现撤销按钮可以使用了,点击之后也的确可以撤销刚才的操作 ...

  3. UVA - 10895 Matrix Transpose

    UVA - 10895 Matrix Transpose Time Limit:3000MS   Memory Limit:Unknown   64bit IO Format:%lld & % ...

  4. suid sgid sbit chattr lsattr find

    suid 一般用于二进制可执行文件不可用于shell脚本和目录,suid代表当用户执行此二进制文件时,暂时具有此文件所有者的权限 chmod 4xxx binfile sgid 一般用于目录,sgid ...

  5. hibernate 过滤

    1.可以使用@Where的过滤,不过这种过滤式全局的,支持延迟加载. 2.可以使用@Filters,这种过滤不支持延迟加载. @Entity@Table(name = "qc315_tous ...

  6. vue2.0 仿手机新闻站(二)项目结构搭建 及 路由配置

    1.项目结构 $ vue init webpack-simple news $ npm install vuex vue-router axios style-loader css-loader -D ...

  7. Oracle中没有 if exists(...)的解决方法

    http://blog.csdn.net/hollboy/article/details/7550171对于Oracle中没有 if exists(...) 的语法,目前有许多种解决方法,这里先分析常 ...

  8. jquery垂直滚动插件一个参数用于设置速度,兼容ie6

    利用外层的块级元素负外边距来滚动 1.使用 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://ww ...

  9. ant 可自动替换友盟渠道、版本号、包名

    可自动替换友盟渠道.版本号.包名 如何集成到我的项目里 前提:了解android官方文档,在项目目录中执行ant debug能打包,比如常见的打包步骤: android update project ...

  10. eclipse tomcat maven

    jdk jre eclipse 略过 下载maven和tomcat 上apache官网下载maven:http://maven.apache.org/download.cgi. 上apache官网下载 ...