沃梦达 / IT编程 / 移动开发 / 正文

Android显示系统SurfaceFlinger详解

本文详细讲解了Android显示系统SurfaceFlinger,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

WindowManagerImpl.java:


public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    mGlobal.addView(view, params, mDisplay, mParentWindow);
}

WindowManagerGlobal.java:


public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) {
    ...
    final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
    //创建 ViewRootImpl
    ViewRootImpl root = new ViewRootImpl(view.getContext(), display);
    view.setLayoutParams(wparams);
    mViews.add(view);
    mRoots.add(root);
    mParams.add(wparams);
    //设置 View
    root.setView(view, wparams, panelParentView);
    ...
}

创建 ViewRootImpl:


    public ViewRootImpl(Context context, Display display) {
       //获取 IWindowSession的代理类
        this(context, display, WindowManagerGlobal.getWindowSession(),
                false /* useSfChoreographer */);
    }

WindowManagerGlobal.java:


@UnsupportedAppUsage
    public static IWindowSession getWindowSession() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowSession == null) {
                try {
                    // Emulate the legacy behavior.  The global instance of InputMethodManager
                    // was instantiated here.
                    // TODO(b/116157766): Remove this hack after cleaning up @UnsupportedAppUsage
                    //获取 IMS 的代理类
                    InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
                    IWindowManager windowManager = getWindowManagerService();
                    //经过 Binder 调用,最终调用 WMS
                    sWindowSession = windowManager.openSession(
                            new IWindowSessionCallback.Stub() {
                                @Override
                                public void onAnimatorScaleChanged(float scale) {
                                    ValueAnimator.setDurationScale(scale);
                                }
                            });
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowSession;
        }
    }

WindowManagerService.openSession:


// -------------------------------------------------------------
    // IWindowManager API
    // -------------------------------------------------------------

    @Override
    public IWindowSession openSession(IWindowSessionCallback callback) {
        //创建session对象
        return new Session(this, callback);
    }

再次经过 Binder 将数据写回 app 进程,则获取的便是 Session 的代理对象 IWindowSession。

创建完 ViewRootImpl 对象后,接下来调用该对象的 setView() 方法:

ViewRootImpl:


public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
  synchronized (this) {
 
    requestLayout(); //详见下面分析
    ...
    //通过 Binder调用,进入 system 进程的 Session
     res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,                                    getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame,                                    mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,                                    mAttachInfo.mDisplayCutout, inputChannel,                                    mTempInsets, mTempControls);
    ...
  }
}

Session.java


@Override
    public int addToDisplayAsUser(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, int userId, Rect outFrame,
            Rect outContentInsets, Rect outStableInsets,
            DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
            InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) {
        //调用WMS的addWindow方法    
        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
                outContentInsets, outStableInsets, outDisplayCutout, outInputChannel,
                outInsetsState, outActiveControls, userId);
    }

WindowManagerService.java:


public int addWindow(Session session, IWindow client, int seq,
            LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
            Rect outContentInsets, Rect outStableInsets,
            DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
            InsetsState outInsetsState, InsetsSourceControl[] outActiveControls,
            int requestUserId) {
        Arrays.fill(outActiveControls, null);
        int[] appOp = new int[1];
        final boolean isRoundedCornerOverlay = (attrs.privateFlags
                & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0;
        int res = mPolicy.checkAddPermission(attrs.type, isRoundedCornerOverlay, attrs.packageName,
                appOp);
        if (res != WindowManagerGlobal.ADD_OKAY) {
            return res;
        }

        WindowState parentWindow = null;
        final int callingUid = Binder.getCallingUid();
        final int callingPid = Binder.getCallingPid();
        final long origId = Binder.clearCallingIdentity();
        final int type = attrs.type;

        synchronized (mGlobalLock) {
            if (!mDisplayReady) {
                throw new IllegalStateException("Display has not been initialialized");
            }
...
            //创建 WindowState
            final WindowState win = new WindowState(this, session, client, token, parentWindow,
                    appOp[0], seq, attrs, viewVisibility, session.mUid, userId,
                    session.mCanAddInternalSystemWindow);
            if (win.mDeathRecipient == null) {
                // Client has apparently died, so there is no reason to
                // continue.
                ProtoLog.w(WM_ERROR, "Adding window client %s"
                        + " that is dead, aborting.", client.asBinder());
                return WindowManagerGlobal.ADD_APP_EXITING;
            }

            if (win.getDisplayContent() == null) {
                ProtoLog.w(WM_ERROR, "Adding window to Display that has been removed.");
                return WindowManagerGlobal.ADD_INVALID_DISPLAY;
            }

            // 调整 WindowManager的LayoutParams 参数
            final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
            displayPolicy.adjustWindowParamsLw(win, win.mAttrs, callingPid, callingUid);

            res = displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid);
            if (res != WindowManagerGlobal.ADD_OKAY) {
                return res;
            }

            // 打开输入通道
            final boolean openInputChannels = (outInputChannel != null
                    && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
            if  (openInputChannels) {
                win.openInputChannel(outInputChannel);
            }

...
            displayContent.getInputMonitor().setUpdateInputWindowsNeededLw();

            boolean focusChanged = false;
            //当该窗口能接收按键事件,则更新聚焦窗口
            if (win.canReceiveKeys()) {
                focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
                        false /*updateInputWindows*/);
                if (focusChanged) {
                    imMayMove = false;
                }
            }

            if (imMayMove) {
                displayContent.computeImeTarget(true /* updateImeTarget */);
            }
...
        }

        Binder.restoreCallingIdentity(origId);

        return res;
    }

创建 SurfaceSession 对象,并将当前 Session 添加到 WMS.mSessions 成员变量。

Session.java:


void windowAddedLocked(String packageName) {
        mPackageName = packageName;
        mRelayoutTag = "relayoutWindow: " + mPackageName;
        if (mSurfaceSession == null) {
            if (DEBUG) {
                Slog.v(TAG_WM, "First window added to " + this + ", creating SurfaceSession");
            }
            mSurfaceSession = new SurfaceSession();
            ProtoLog.i(WM_SHOW_TRANSACTIONS, "  NEW SURFACE SESSION %s", mSurfaceSession);
            mService.mSessions.add(this);
            if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {
                mService.dispatchNewAnimatorScaleLocked(this);
            }
        }
        mNumWindow++;
    }

SurfaceSession 的创建会调用 JNI,在 JNI 调用 nativeCreate()。

android_view_SurfaceSession.cpp:


static jlong nativeCreate(JNIEnv* env, jclass clazz) {
    SurfaceComposerClient* client = new SurfaceComposerClient();
    client->incStrong((void*)nativeCreate);
    return reinterpret_cast<jlong>(client);
}

static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
        jstring nameStr, jint w, jint h, jint format, jint flags, jlong parentObject,
        jobject metadataParcel) {
    ScopedUtfChars name(env, nameStr);
    sp<SurfaceComposerClient> client;
    if (sessionObj != NULL) {
        client = android_view_SurfaceSession_getClient(env, sessionObj);
    } else {
        client = SurfaceComposerClient::getDefault();
    }
    SurfaceControl *parent = reinterpret_cast<SurfaceControl*>(parentObject);
    sp<SurfaceControl> surface;
    LayerMetadata metadata;
    Parcel* parcel = parcelForJavaObject(env, metadataParcel);
    if (parcel && !parcel->objectsCount()) {
        status_t err = metadata.readFromParcel(parcel);
        if (err != NO_ERROR) {
          jniThrowException(env, "java/lang/IllegalArgumentException",
                            "Metadata parcel has wrong format");
        }
    }

    status_t err = client->createSurfaceChecked(
            String8(name.c_str()), w, h, format, &surface, flags, parent, std::move(metadata));
    if (err == NAME_NOT_FOUND) {
        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
        return 0;
    } else if (err != NO_ERROR) {
        jniThrowException(env, OutOfResourcesException, NULL);
        return 0;
    }

    surface->incStrong((void *)nativeCreate);
    return reinterpret_cast<jlong>(surface.get());
}

通过以上JNI接口获取SurfaceComposerClient 对象,作为跟 SurfaceFlinger 通信的代理对象。


void SurfaceComposerClient::onFirstRef() {
    //getComposerService() 将返回 SF 的 Binder 代理端的 BpSurfaceFlinger 对象
    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
    if (sf != nullptr && mStatus == NO_INIT) {
        sp<ISurfaceComposerClient> conn;
        //调用 SF 的 createConnection()
        conn = sf->createConnection();
        if (conn != nullptr) {
            mClient = conn;
            mStatus = NO_ERROR;
        }
    }
}

比如截屏接口就会通过SurfaceControl调用到其中的capture 接口:


status_t ScreenshotClient::capture(const sp<IBinder>& display, ui::Dataspace reqDataSpace,
                                   ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
                                   uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
                                   ui::Rotation rotation, bool captureSecureLayers,
                                   sp<GraphicBuffer>* outBuffer, bool& outCapturedSecureLayers) {
    sp<ISurfaceComposer> s(ComposerService::getComposerService());
    if (s == nullptr) return NO_INIT;
    status_t ret = s->captureScreen(display, outBuffer, outCapturedSecureLayers, reqDataSpace,
                                    reqPixelFormat, sourceCrop, reqWidth, reqHeight,
                                    useIdentityTransform, rotation, captureSecureLayers);
    if (ret != NO_ERROR) {
        return ret;
    }
    return ret;
}

然后具体看下核心的SurfaceFlinger实现:

SurfaceFlinger.cpp:


sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() {
    //创建一个Client
    const sp<Client> client = new Client(this);
    return client->initCheck() == NO_ERROR ? client : nullptr;
}

回到之前,创建完 ViewRootImpl 对象后,接下来调用该对象的 setView() 方法。在 setView() 中调用了 requestLayout() 方法,现在具体来看下这个方法调用流程:


@Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }

@UnsupportedAppUsage
    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();       //启动TraversalRunnable
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }

    final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }

void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

            if (mProfile) {
                Debug.startMethodTracing("ViewAncestor");
            }
        //调用performTraversals             performTraversals();
if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false;
            }
        }
    }

private void performTraversals() {
        // cache mView since it is used so much below...
        final View host = mView; //它就是 DecorView
...
        if (mFirst || windowShouldResize || viewVisibilityChanged || cutoutChanged || params != null
                || mForceNextWindowRelayout) {
            mForceNextWindowRelayout = false;

            if (isViewVisible) {
                // If this window is giving internal insets to the window
                // manager, and it is being added or changing its visibility,
                // then we want to first give the window manager "fake"
                // insets to cause it to effectively ignore the content of
                // the window during layout.  This avoids it briefly causing
                // other windows to resize/move based on the raw frame of the
                // window, waiting until we can finish laying out this window
                // and get back to the window manager with the ultimately
                // computed insets.
                insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
            }
...
            try {
                if (DEBUG_LAYOUT) {
                    Log.i(mTag, "host=w:" + host.getMeasuredWidth() + ", h:" +
                            host.getMeasuredHeight() + ", params=" + params);
                }

                if (mAttachInfo.mThreadedRenderer != null) {
                    // relayoutWindow may decide to destroy mSurface. As that decision
                    // happens in WindowManager service, we need to be defensive here
                    // and stop using the surface in case it gets destroyed.
                    if (mAttachInfo.mThreadedRenderer.pause()) {
                        // Animations were running so we need to push a frame
                        // to resume them
                        mDirty.set(0, 0, mWidth, mHeight);
                    }
                    mChoreographer.mFrameInfo.addFlags(FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED);
                }
                // 关键函数relayoutWindow
                relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);

                if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString()
                        + " cutout=" + mPendingDisplayCutout.get().toString()
                        + " surface=" + mSurface);

                // If the pending {@link MergedConfiguration} handed back from
                // {@link #relayoutWindow} does not match the one last reported,
                // WindowManagerService has reported back a frame from a configuration not yet
                // handled by the client. In this case, we need to accept the configuration so we
                // do not lay out and draw with the wrong configuration.
                if (!mPendingMergedConfiguration.equals(mLastReportedMergedConfiguration)) {
                    if (DEBUG_CONFIGURATION) Log.v(mTag, "Visible with new config: "
                            + mPendingMergedConfiguration.getMergedConfiguration());
                    performConfigurationChange(mPendingMergedConfiguration, !mFirst,
                            INVALID_DISPLAY /* same display */);
                    updatedConfiguration = true;
                }

            } catch (RemoteException e) {
            }
...
        }

        boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;

        if (!cancelDraw) {
            if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
                for (int i = 0; i < mPendingTransitions.size(); ++i) {
                    mPendingTransitions.get(i).startChangingAnimations();
                }
                mPendingTransitions.clear();
            }

            //开始绘制,其中调用了draw(fullRedrawNeeded);
            performDraw();
        } else {
            if (isViewVisible) {
                // Try again
                scheduleTraversals();
            } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
                for (int i = 0; i < mPendingTransitions.size(); ++i) {
                    mPendingTransitions.get(i).endChangingAnimations();
                }
                mPendingTransitions.clear();
            }
        }

        if (mAttachInfo.mContentCaptureEvents != null) {
            notifyContentCatpureEvents();
        }

        mIsInTraversal = false;
    }

再看下relayoutWindow的实现:


...        if (mSurfaceControl.isValid()) {
            if (!useBLAST()) {
                //先创建一个本地Surface,然后调用copyFrom   将SurfaceControl信息拷贝到Surface中
                mSurface.copyFrom(mSurfaceControl);
            } else {
                final Surface blastSurface = getOrCreateBLASTSurface(mSurfaceSize.x,
                    mSurfaceSize.y);
                // If blastSurface == null that means it hasn't changed since the last time we
                // called. In this situation, avoid calling transferFrom as we would then
                // inc the generation ID and cause EGL resources to be recreated.
                if (blastSurface != null) {
                    mSurface.transferFrom(blastSurface);
                }
            }
        } else {
            destroySurface();
        }....

SurfaceControl 类可以看作是一个 wrapper 类,最后会执行 copyFrom() 将其返回给 App 客户端:


@UnsupportedAppUsage
    public void copyFrom(SurfaceControl other) {
        if (other == null) {
            throw new IllegalArgumentException("other must not be null");
        }

        long surfaceControlPtr = other.mNativeObject;
        if (surfaceControlPtr == 0) {
            throw new NullPointerException(
                    "null SurfaceControl native object. Are you using a released SurfaceControl?");
        }

        //通过JNI获取源SurfaceControl
        long newNativeObject = nativeGetFromSurfaceControl(mNativeObject, surfaceControlPtr);

        synchronized (mLock) {
            if (newNativeObject == mNativeObject) {
                return;
            }
            if (mNativeObject != 0) {
                nativeRelease(mNativeObject);
            }
            //保存到全局mNativeObject用于外部调用
            setNativeObjectLocked(newNativeObject);
        }
    }

Surface 显示过程总结:

在 App 进程中创建 PhoneWindow 后会创建 ViewRoot。ViewRoot 的创建会创建一个 Surface,这个 Surface 其实是空的,通过与 WindowManagerService 通信 copyFrom() 一个NativeSurface 与 SurfaceFlinger 通信时。

关于Native Window:

Native Window是OpenGL与本地窗口系统之间搭建了桥梁。整个GUI系统至少需要两种本地窗口:

  • (1)面向管理者(SurfaceFlinger)

SurfaceFlinger是系统中所有UI界面的管理者,需要直接或间接的持有“本地窗口”,此本地窗口是FramebufferNativeWindow。

  • (2)面向应用程序

这类本地窗口是Surface。

正常情况按照SDK向导生成APK应用程序,是采用Skia等第三方图形库,而对于希望使用OpenGL ES来完成复杂界面渲染的应用开发者来说,Android也提供封装的GLSurfaceView(或其他方式)来实现图形显示。

①FramebufferNativeWindow

EGL需要通过本地窗口来为OpenGL/OpenGL ES创建环境。由于OpenGL/ES对多平台支持,考虑到兼容性和移植性。不同平台的本地窗口EGLNativeWindowType数据类型不同。

Android平台的数据类型是ANativeWindow,像是一份“协议”,规定了一个本地窗口的形态和功能。ANativeWindow是FramebufferNativeWindow的父类。

Android中,由于多缓冲技术,EGLNativeWindowType所管理的缓冲区最少2个,最大3个。

FramebufferNativeWindow初始化需要Golloc支持,步骤如下:

  • 加载GRALLOC_HARDWARE_MODULE_ID模块,参见上节。
  • 分别打开fb和gralloc设备,打开后的设备由全局变量fbDev和grDev管理。
  • 根据设备的属性来给FramebufferNativeWindow赋初值。
  • 根据FramebufferNativeWindow的实现来填充ANativeWindow中的“协议”
  • 其他一些必要的初始化

②应用程序的本地窗口 - Surface

Surface也继承了ANativeWindow


 class Surface : public ANativeObjectBase<ANativeWindow, Surface, RefBase>

Surface是面向Android系统中所有UI应用程序的,即它承担着应用进程中的UI显示需求。

需要面向上层实现(主要是Java层)提供绘制图像的画板。SurfaceFlinger需要收集系统中所有应用程序绘制的图像数据,然后集中显示到物理屏幕上。Surface需要扮演相应角色,本质上还是由SurfaceFlinger服务统一管理的,涉及到很多跨进程的通信细节。

③Surface的创建

Surface将通过mGraphicBufferProducer来获取buffer,这些缓冲区会被记录在mSlots中数据中。mGraphicBufferProducer这一核心成员的初始化流程如下:

ViewRootImpl持有一个Java层的Surface对象(mSurface)。

ViewRootImpl向WindowManagerService发起relayout请求,此时mSurface被赋予真正的有效值,将辗转生成的SurfaceControl通过Surface.copyFrom()函数复制到mSurface中。

由此,Surface由SurfaceControl管理,SurfaceControl由SurfaceComposerClient创建。SurfaceComposerClient获得的匿名Binder是ISurfaceComposer,其服务端实现是SurfaceFlinger。而Surface依赖的IGraphicBufferProducer对象在Service端的实现是BufferQueue。


class SurfaceFlinger : 
  public BinderService<SurfaceFlinger>, //在ServiceManager中注册为SurfaceFlinger
  public BnSurfaceComposer,//实现的接口却叫ISurfaceComposer

④SurfaceFlinger服务框架:

Buffer,Consumer,Producer是“生产者-消费者”模型中的3个参与对象,如何协调好它们的工作是应用程序能否正常显示UI的关键。

Buffer是BufferQueue,Producer是应用程序,Consumer是SurfaceFlinger。

Surface内部提供一个BufferQueue,与上层和SurfaceFlinger形成一个生产者消费者模型,上层对应Producer,SurfaceFlinger对应Consumer。三者通过Buffer产生联系,每个Buffer都有四种状态:

  • Free:可被上层使用;
  • Dequeued:出列,正在被上层使用;
  • Queued:入列,已完成上层绘制,等待SurfaceFlinger合成;
  • Acquired:被获取,SurfaceFlinger正持有该Buffer进行合成;

如此循环,形成一个Buffer被循环使用的过程(FREE-> DEQUEUED->QUEUED->ACQUIRED->FREE)。

BufferQueue中的mSlots数组用于管理期内的缓冲区,最大容器是32。数据缓冲区的空间是动态分配的,应用程序与SurfaceFlinger都是使用OpenGL ES来完成UI显示。Layer类在SurfaceFlinger中表示“层”,通俗地讲就是代表了一个“画面”,最终物理屏幕上的显示结果就是通过对系统中同时存在的所有“画面”进行处理叠加而成。

到此这篇关于Android显示系统SurfaceFlinger详解的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持编程学习网。

本文标题为:Android显示系统SurfaceFlinger详解