赞
踩
在Android系统开发过程中,偶尔会遇到显示异常的问题,如画面不再刷新,也就是冻屏,或者屏幕变黑,如果对图形显示系统不熟悉,遇到此类问题还是比较棘手的。如果在工作中遇到类似的问题,或者对图形显示系统感兴趣,可参考清华大学出版社出版的《Android图形显示系统》。 图形显示系统是Android系统中最为核心、复杂的子系统,掌握它对于理解Android系统会有一个很大的提升,是一门进阶课题。
下面主要结合《Android图形显示系统》来分析工作过程中碰到的图形显示异常的问题。该书主要基于Android9,而本文主要基于Android12,其实思路是一样的,只不过在代码上有差异。
假设遇到了一个屏幕突然变黑的问题,首先得确认黑屏的可能原因,比如是否灭屏,如果不是灭屏,那就是应用的图形内容没有正常地传递到屏幕,可以在SurfaceFlinger确定大体原因。
通过《Android图形显示系统》可以指导,应用的图形内容要经过SurfaceFlinger才能传递到显示设备,SurfaceFlinger每隔一定时间(间隔由帧率决定)会向屏幕传递图形数据,但是并不是每个应用的图形都会显示,只有最前面应用的画面才能显示,应用的图形数据一般保存在图层中,因此每次刷新都会收集可见的图层。核心流程如下。
-
- void SurfaceFlinger::onMessageRefresh() {
- mCompositionEngine->present(refreshArgs);
- }
-
- void CompositionEngine::present(CompositionRefreshArgs& args) {
- for (const auto& output : args.outputs) {
- output->prepare(args, latchedLayers);
- }
- }
-
- void Output::prepare(const compositionengine::CompositionRefreshArgs& refreshArgs,
- LayerFESet& geomSnapshots) {
- rebuildLayerStacks(refreshArgs, geomSnapshots);
- }
-
- void Output::collectVisibleLayers(const compositionengine::CompositionRefreshArgs& refreshArgs,
- compositionengine::Output::CoverageState& coverage) {
- for (auto layer : reversed(refreshArgs.layers)) {
- ensureOutputLayerIfVisible(layer, coverage);
- }
- }
-
- void Output::ensureOutputLayerIfVisible(sp<compositionengine::LayerFE>& layerFE,
- compositionengine::Output::CoverageState& coverage) {
- auto result = ensureOutputLayer(prevOutputLayerIndex, layerFE);
- layerFE->dumpLayer();
- }
流程解析如下:
1)SurfaceFlinger在处理onMessageRefresh时正是要刷新屏幕,调用CompositionEngine的present进行下一步处理。
2)CompositionEngine在处理present时,针对每个显示设备调用prepare先准备好要处理的图层,每个Output对象代表一个显示设备。
3)Output在处理prepare主要重建图层栈,也就是找到可见的图层,如果上面的流程走到ensureOutputLayerIfVisible的ensureOutputLayer,可以确定该图层是可见的,这里可以把该图层及其父图层打印出来,这里layerFE->dumpLayer();是新加的方法,需要在Layer也加上相应的实现,如下。
- class LayerFE : public virtual RefBase {
- virtual void dumpLayer() = 0;
- };
-
- class Layer : public virtual RefBase, compositionengine::LayerFE {
- void dumpLayer() override {
- sp<Layer> parent = getParent();
- if(parent != nullptr){
- parent->dumpLayer();
- }
- ALOGI("dumpLayer LayerName: %s", mName.c_str());
- }
- }
这里会把图层及其父图层的名称打印出来,结果如下。
- 04-12 14:37:57.714 720 720 I BufferLayer: dumpLayer LayerName: WindowToken{7c850a1 android.os.BinderProxy@bd7a6ab}#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: f541552 ScreenDecorOverlayBottom#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: ScreenDecorOverlayBottom#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: WindowToken{6e71384 android.os.BinderProxy@26cb1d8}#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: fdb4f1c ScreenDecorOverlay#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: ScreenDecorOverlay#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: Root#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: WindowedMagnification:0:31#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: Leaf:24:25#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: WindowToken{4b66858 android.os.BinderProxy@23dd335}#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: Surface(name=521d296 NavigationBar0)/@0x8baf6da - animation-leash of insets_animation#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: 521d296 NavigationBar0#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: NavigationBar0#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: Root#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: WindowedMagnification:0:31#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: OneHanded:17:17#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: FullscreenMagnification:17:17#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: Leaf:17:17#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: WindowToken{4beb8e7 android.os.BinderProxy@afe79e8}#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: Surface(name=17ee33d StatusBar)/@0xbfb7639 - animation-leash of insets_animation#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: 17ee33d StatusBar#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: StatusBar#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: Root#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: WindowedMagnification:0:31#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: HideDisplayCutout:0:16#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: OneHanded:2:16#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: FullscreenMagnification:2:14#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: DefaultTaskDisplayArea#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: Task=14#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: ActivityRecord{73e3548 u0 com.sino.compose/.MainActivity t14}#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: Surface(name=b001cb7 Splash Screen com.sino.compose)/@0xf9b3d26 - animation-leash of window_animation#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: b001cb7 Splash Screen com.sino.compose#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: Splash Screen com.sino.compose#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: Root#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: WindowedMagnification:0:31#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: HideDisplayCutout:0:16#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: OneHanded:2:16#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: FullscreenMagnification:2:14#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: DefaultTaskDisplayArea#0
- 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: Task=14#0
- 04-12 14:37:57.716 720 720 I BufferLayer: dumpLayer LayerName: ActivityRecord{73e3548 u0 com.sino.compose/.MainActivity t14}#0
- 04-12 14:37:57.716 720 720 I BufferLayer: dumpLayer LayerName: 1c021fa com.sino.compose/com.sino.compose.MainActivity#0
在上面的日志中Root#0是第0个屏幕的根图层,com.sino.compose/com.sino.compose.MainActivity才是应用显示内容的图层。从内容图层到根图层有9层。
这里需要根据打印的图层确定异常的位置,如果某个图层突然不显示了,那么就不会打印出来,找到发送变换的位置,找到是哪个图层发生了变化。如果一个图层发生变化,基本上是向它设置了状态,可以把在相关方法加日志,比如设置隐藏状态对于的接口为setFlags,
- bool Layer::setFlags(uint32_t flags, uint32_t mask) {
- const uint32_t newFlags = (mDrawingState.flags & ~mask) | (flags & mask);
- if (mDrawingState.flags == newFlags) return false;
- mDrawingState.sequence++;
- mDrawingState.flags = newFlags;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
- }
一旦确认是该接口被调用导致图层的状态发生了变化,就到SurfaceControl找到相应的接口,并加日志进一步确认。
- public final class SurfaceControl implements Parcelable {
- public @Nullable String getName(){
- return mName;
- }
- public static class Transaction implements Closeable, Parcelable {
- public Transaction hide(SurfaceControl sc) {
- checkPreconditions(sc);
-
- Log.i("SurfaceControl::Transaction", "hide "+sc.getName());
- Thread.dumpStack();
-
- nativeSetFlags(mNativeObject, sc.mNativeObject, SURFACE_HIDDEN, SURFACE_HIDDEN);
- return this;
- }
- }
- }
在上面的代码中,通过Thread.dumpStack();可以把调用hide方法的调用堆栈打印出来,
- 04-12 19:32:57.502 1744 1892 I SurfaceControl::Transaction: hide com.sino.compose/com.sino.compose.MainActivity
- 04-12 19:32:57.502 1744 1892 W System.err: java.lang.Exception: Stack trace
- 04-12 19:32:57.502 1744 1892 W System.err: at java.lang.Thread.dumpStack(Thread.java:1517)
- 04-12 19:32:57.502 1744 1892 W System.err: at android.view.SurfaceControl$Transaction.hide(SurfaceControl.java:2760)
- 04-12 19:32:57.502 1744 1892 W System.err: at com.android.server.wm.WindowSurfaceController.hideSurface(WindowSurfaceController.java:128)
- 04-12 19:32:57.502 1744 1892 W System.err: at com.android.server.wm.WindowSurfaceController.hide(WindowSurfaceController.java:118)
- 04-12 19:32:57.502 1744 1892 W System.err: at com.android.server.wm.WindowStateAnimator.hide(WindowStateAnimator.java:228)
- 04-12 19:32:57.502 1744 1892 W System.err: at com.android.server.wm.WindowStateAnimator.prepareSurfaceLocked(WindowStateAnimator.java:531)
- 04-12 19:32:57.502 1744 1892 W System.err: at com.android.server.wm.WindowState.prepareSurfaces(WindowState.java:5494)
- 04-12 19:32:57.502 1744 1892 W System.err: at com.android.server.wm.WindowContainer.prepareSurfaces(WindowContainer.java:2432)
- 04-12 19:32:57.502 1744 1892 W System.err: at com.android.server.wm.ActivityRecord.prepareSurfaces(ActivityRecord.java:6682)
- 04-12 19:32:57.502 1744 1892 W System.err: at com.android.server.wm.WindowContainer.prepareSurfaces(WindowContainer.java:2432)
- 04-12 19:32:57.502 1744 1892 W System.err: at com.android.server.wm.Task.prepareSurfaces(Task.java:3973)
- 04-12 19:32:57.502 1744 1892 W System.err: at com.android.server.wm.WindowContainer.prepareSurfaces(WindowContainer.java:2432)
- 04-12 19:32:57.502 1744 1892 W System.err: at com.android.server.wm.WindowContainer.prepareSurfaces(WindowContainer.java:2432)
- 04-12 19:32:57.503 1744 1892 W System.err: at com.android.server.wm.WindowContainer.prepareSurfaces(WindowContainer.java:2432)
- 04-12 19:32:57.503 1744 1892 W System.err: at com.android.server.wm.WindowContainer.prepareSurfaces(WindowContainer.java:2432)
- 04-12 19:32:57.503 1744 1892 W System.err: at com.android.server.wm.WindowContainer.prepareSurfaces(WindowContainer.java:2432)
- 04-12 19:32:57.503 1744 1892 W System.err: at com.android.server.wm.DisplayArea$Dimmable.prepareSurfaces(DisplayArea.java:644)
通过堆栈可以分析到调用该接口的地方,这里主要是WindowManagerService的内容,需要根据实际情况分析具体原因。
假设图层没有异常,就需要分析图形数据有没有传递到HAL层,在《Android图形显示系统》介绍过,通过硬件混合渲染器合成的方式主要分为以下3步。
1)createLayer
- //frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
- void SurfaceFlinger::onMessageRefresh() {
- mCompositionEngine->present(refreshArgs);
- }
-
- //frameworks/native/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
- void CompositionEngine::present(CompositionRefreshArgs& args) {
- for (const auto& output : args.outputs) {
- output->prepare(args, latchedLayers);
- }
- }
-
- //frameworks/native/services/surfaceflinger/CompositionEngine/src/Output.cpp
- void Output::prepare(const compositionengine::CompositionRefreshArgs& refreshArgs,
- LayerFESet& geomSnapshots) {
- rebuildLayerStacks(refreshArgs, geomSnapshots);
- }
-
- void Output::rebuildLayerStacks(const compositionengine::CompositionRefreshArgs& refreshArgs,
- LayerFESet& layerFESet) {
- collectVisibleLayers(refreshArgs, coverage);
- }
-
- void Output::collectVisibleLayers(const compositionengine::CompositionRefreshArgs& refreshArgs,
- compositionengine::Output::CoverageState& coverage) {
- for (auto layer : reversed(refreshArgs.layers)) {
- // Incrementally process the coverage for each layer
- ensureOutputLayerIfVisible(layer, coverage);
- }
- }
-
- void Output::ensureOutputLayerIfVisible(sp<compositionengine::LayerFE>& layerFE,
- compositionengine::Output::CoverageState& coverage) {
-
- auto result = ensureOutputLayer(prevOutputLayerIndex, layerFE);
- }
- //frameworks/native/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
- class Output : public virtual compositionengine::Output {
- OutputLayer* ensureOutputLayer(std::optional<size_t> prevIndex,
- const sp<LayerFE>& layerFE) {
- auto outputLayer = (prevIndex && *prevIndex <= mCurrentOutputLayersOrderedByZ.size())
- ? std::move(mCurrentOutputLayersOrderedByZ[*prevIndex])
- : BaseOutput::createOutputLayer(layerFE); //here
- }
- }
-
- //frameworks/native/services/surfaceflinger/CompositionEngine/src/Display.cpp
- std::unique_ptr<compositionengine::OutputLayer> Display::createOutputLayer(
- const sp<compositionengine::LayerFE>& layerFE) const {
- auto hwcLayer = hwc.createLayer(*halDisplayId);
- }
-
- //frameworks/native/services/surfaceflinger/DisplayHardware/HWComposer.cpp
- std::shared_ptr<HWC2::Layer> HWComposer::createLayer(HalDisplayId displayId) {
- auto expected = mDisplayData[displayId].hwcDisplay->createLayer();
- }
-
- //frameworks/native/services/surfaceflinger/DisplayHardware/HWC2.cpp
- base::expected<std::shared_ptr<HWC2::Layer>, hal::Error> Display::createLayer() {
- HWLayerId layerId = 0;
- auto intError = mComposer.createLayer(mId, &layerId);
- }
-
- //frameworks/native/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
- Error Composer::createLayer(Display display, Layer* outLayer)
- {
- mClient->createLayer(display, kMaxLayerBufferCount,
- [&](const auto& tmpError, const auto& tmpLayer) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
- *outLayer = tmpLayer;
- });
-
- return error;
- }
createLayer请求HAL创建硬件图层保存图形缓冲。
2) setBuffer
- void CompositionEngine::present(CompositionRefreshArgs& args) {
-
- for (const auto& output : args.outputs) {
- output->present(args);
- }
- }
-
- void Output::present(const compositionengine::CompositionRefreshArgs& refreshArgs) {
- writeCompositionState(refreshArgs);
- }
- void Output::writeCompositionState(const compositionengine::CompositionRefreshArgs& refreshArgs) {
- layer->writeStateToHWC(includeGeometry, skipLayer, z++, overrideZ, isPeekingThrough);
- }
-
- void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t z,
- bool zIsOverridden, bool isPeekingThrough) {
- if (auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence); error != hal::Error::NONE) {}
- }
- //HWC2.cpp
- Error Layer::setBuffer(uint32_t slot, const sp<GraphicBuffer>& buffer,
- const sp<Fence>& acquireFence)
- {
- auto intError = mComposer.setLayerBuffer(mDisplay->getId(), mId, slot, buffer, fenceFd);
- return static_cast<Error>(intError);
- }
-
- Error Composer::setLayerBuffer(Display display, Layer layer,
- uint32_t slot, const sp<GraphicBuffer>& buffer, int acquireFence)
- {
- mWriter.selectDisplay(display);
- mWriter.selectLayer(layer);
-
- const native_handle_t* handle = nullptr;
- if (buffer.get()) {
- handle = buffer->getNativeBuffer()->handle;
- }
-
- mWriter.setLayerBuffer(slot, handle, acquireFence);
- return Error::NONE;
- }
setBuffer把要显示的图形缓冲从SurfaceFlinger传递到HAL
3) present
- void Output::present(const compositionengine::CompositionRefreshArgs& refreshArgs) {
- prepareFrame();
- }
-
- void Output::prepareFrame() {
- chooseCompositionStrategy();
- }
-
- void Display::chooseCompositionStrategy() {
- if (status_t result =
- hwc.getDeviceCompositionChanges(*halDisplayId, anyLayersRequireClientComposition(),
- getState().earliestPresentTime,
- getState().previousPresentFence, &changes);
- }
- status_t HWComposer::getDeviceCompositionChanges(
- HalDisplayId displayId, bool frameUsesClientComposition,
- std::chrono::steady_clock::time_point earliestPresentTime,
- const std::shared_ptr<FenceTime>& previousPresentFence,
- std::optional<android::HWComposer::DeviceRequestedChanges>* outChanges) {
- error = hwcDisplay->presentOrValidate(&numTypes, &numRequests, &outPresentFence , &state);
- }
-
- HWC2.cpp
- Error Display::presentOrValidate(uint32_t* outNumTypes, uint32_t* outNumRequests,
- sp<android::Fence>* outPresentFence, uint32_t* state) {
-
- auto intError = mComposer.presentOrValidateDisplay(
- mId, &numTypes, &numRequests, &presentFenceFd, state);
- }
-
- Error Composer::presentOrValidateDisplay(Display display, uint32_t* outNumTypes,
- uint32_t* outNumRequests, int* outPresentFence, uint32_t* state) {
- mWriter.selectDisplay(display);
- mWriter.presentOrvalidateDisplay();
- }
present通知HAL把图形数据传递到底层驱动,开始对图形进行合成并显示。
如果上面3步流程也没有问题,那么可以认为是底层显示驱动的问题,需要在显示驱动模块继续分析原因。
小结:
通过上面的分析可以指定,分析图形显示异常的关键主要在SurfaceFlinger,因此要对SurfaceFlinger的关键流程要比较熟悉,同时WindowManagerSurface的内容也很重要,这两部分内容可参考《Android图形显示系统》。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。