Android系统冻屏、黑屏问题的分析思路

    在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& 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 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& 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 prevIndex,
                                       const sp& 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 Display::createOutputLayer(
        const sp& layerFE) const {
        auto hwcLayer = hwc.createLayer(*halDisplayId);
}

//frameworks/native/services/surfaceflinger/DisplayHardware/HWComposer.cpp
std::shared_ptr HWComposer::createLayer(HalDisplayId displayId) {
    auto expected = mDisplayData[displayId].hwcDisplay->createLayer();
} 
    
//frameworks/native/services/surfaceflinger/DisplayHardware/HWC2.cpp
base::expected, 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& buffer,
        const sp& acquireFence)
{
    auto intError = mComposer.setLayerBuffer(mDisplay->getId(), mId, slot, buffer, fenceFd);
    return static_cast(intError);
}

Error Composer::setLayerBuffer(Display display, Layer layer,
        uint32_t slot, const sp& 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& previousPresentFence,
        std::optional* outChanges) {
        error = hwcDisplay->presentOrValidate(&numTypes, &numRequests, &outPresentFence , &state);
}

HWC2.cpp
Error Display::presentOrValidate(uint32_t* outNumTypes, uint32_t* outNumRequests,
                                 sp* 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图形显示系统》。

你可能感兴趣的:(图形显示系统,黑屏,冻屏,图层,SurfaceFlinger)