当前位置:   article > 正文

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

android 冻屏分析

    在Android系统开发过程中,偶尔会遇到显示异常的问题,如画面不再刷新,也就是冻屏,或者屏幕变黑,如果对图形显示系统不熟悉,遇到此类问题还是比较棘手的。如果在工作中遇到类似的问题,或者对图形显示系统感兴趣,可参考清华大学出版社出版的《Android图形显示系统》。 图形显示系统是Android系统中最为核心、复杂的子系统,掌握它对于理解Android系统会有一个很大的提升,是一门进阶课题。

    下面主要结合《Android图形显示系统》来分析工作过程中碰到的图形显示异常的问题。该书主要基于Android9,而本文主要基于Android12,其实思路是一样的,只不过在代码上有差异。

    假设遇到了一个屏幕突然变黑的问题,首先得确认黑屏的可能原因,比如是否灭屏,如果不是灭屏,那就是应用的图形内容没有正常地传递到屏幕,可以在SurfaceFlinger确定大体原因。

   通过《Android图形显示系统》可以指导,应用的图形内容要经过SurfaceFlinger才能传递到显示设备,SurfaceFlinger每隔一定时间(间隔由帧率决定)会向屏幕传递图形数据,但是并不是每个应用的图形都会显示,只有最前面应用的画面才能显示,应用的图形数据一般保存在图层中,因此每次刷新都会收集可见的图层。核心流程如下。

  1. void SurfaceFlinger::onMessageRefresh() {
  2. mCompositionEngine->present(refreshArgs);
  3. }
  4. void CompositionEngine::present(CompositionRefreshArgs& args) {
  5. for (const auto& output : args.outputs) {
  6. output->prepare(args, latchedLayers);
  7. }
  8. }
  9. void Output::prepare(const compositionengine::CompositionRefreshArgs& refreshArgs,
  10. LayerFESet& geomSnapshots) {
  11. rebuildLayerStacks(refreshArgs, geomSnapshots);
  12. }
  13. void Output::collectVisibleLayers(const compositionengine::CompositionRefreshArgs& refreshArgs,
  14. compositionengine::Output::CoverageState& coverage) {
  15. for (auto layer : reversed(refreshArgs.layers)) {
  16. ensureOutputLayerIfVisible(layer, coverage);
  17. }
  18. }
  19. void Output::ensureOutputLayerIfVisible(sp<compositionengine::LayerFE>& layerFE,
  20. compositionengine::Output::CoverageState& coverage) {
  21. auto result = ensureOutputLayer(prevOutputLayerIndex, layerFE);
  22. layerFE->dumpLayer();
  23. }

    流程解析如下:

1)SurfaceFlinger在处理onMessageRefresh时正是要刷新屏幕,调用CompositionEngine的present进行下一步处理。

2)CompositionEngine在处理present时,针对每个显示设备调用prepare先准备好要处理的图层,每个Output对象代表一个显示设备。

3)Output在处理prepare主要重建图层栈,也就是找到可见的图层,如果上面的流程走到ensureOutputLayerIfVisible的ensureOutputLayer,可以确定该图层是可见的,这里可以把该图层及其父图层打印出来,这里layerFE->dumpLayer();是新加的方法,需要在Layer也加上相应的实现,如下。

  1. class LayerFE : public virtual RefBase {
  2. virtual void dumpLayer() = 0;
  3. };
  4. class Layer : public virtual RefBase, compositionengine::LayerFE {
  5. void dumpLayer() override {
  6. sp<Layer> parent = getParent();
  7. if(parent != nullptr){
  8. parent->dumpLayer();
  9. }
  10. ALOGI("dumpLayer LayerName: %s", mName.c_str());
  11. }
  12. }

这里会把图层及其父图层的名称打印出来,结果如下。

  1. 04-12 14:37:57.714 720 720 I BufferLayer: dumpLayer LayerName: WindowToken{7c850a1 android.os.BinderProxy@bd7a6ab}#0
  2. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: f541552 ScreenDecorOverlayBottom#0
  3. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: ScreenDecorOverlayBottom#0
  4. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: WindowToken{6e71384 android.os.BinderProxy@26cb1d8}#0
  5. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: fdb4f1c ScreenDecorOverlay#0
  6. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: ScreenDecorOverlay#0
  7. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: Root#0
  8. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: WindowedMagnification:0:31#0
  9. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: Leaf:24:25#0
  10. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: WindowToken{4b66858 android.os.BinderProxy@23dd335}#0
  11. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: Surface(name=521d296 NavigationBar0)/@0x8baf6da - animation-leash of insets_animation#0
  12. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: 521d296 NavigationBar0#0
  13. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: NavigationBar0#0
  14. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: Root#0
  15. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: WindowedMagnification:0:31#0
  16. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: OneHanded:17:17#0
  17. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: FullscreenMagnification:17:17#0
  18. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: Leaf:17:17#0
  19. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: WindowToken{4beb8e7 android.os.BinderProxy@afe79e8}#0
  20. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: Surface(name=17ee33d StatusBar)/@0xbfb7639 - animation-leash of insets_animation#0
  21. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: 17ee33d StatusBar#0
  22. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: StatusBar#0
  23. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: Root#0
  24. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: WindowedMagnification:0:31#0
  25. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: HideDisplayCutout:0:16#0
  26. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: OneHanded:2:16#0
  27. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: FullscreenMagnification:2:14#0
  28. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: DefaultTaskDisplayArea#0
  29. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: Task=14#0
  30. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: ActivityRecord{73e3548 u0 com.sino.compose/.MainActivity t14}#0
  31. 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
  32. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: b001cb7 Splash Screen com.sino.compose#0
  33. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: Splash Screen com.sino.compose#0
  34. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: Root#0
  35. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: WindowedMagnification:0:31#0
  36. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: HideDisplayCutout:0:16#0
  37. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: OneHanded:2:16#0
  38. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: FullscreenMagnification:2:14#0
  39. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: DefaultTaskDisplayArea#0
  40. 04-12 14:37:57.715 720 720 I BufferLayer: dumpLayer LayerName: Task=14#0
  41. 04-12 14:37:57.716 720 720 I BufferLayer: dumpLayer LayerName: ActivityRecord{73e3548 u0 com.sino.compose/.MainActivity t14}#0
  42. 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,

  1. bool Layer::setFlags(uint32_t flags, uint32_t mask) {
  2. const uint32_t newFlags = (mDrawingState.flags & ~mask) | (flags & mask);
  3. if (mDrawingState.flags == newFlags) return false;
  4. mDrawingState.sequence++;
  5. mDrawingState.flags = newFlags;
  6. mDrawingState.modified = true;
  7. setTransactionFlags(eTransactionNeeded);
  8. return true;
  9. }

一旦确认是该接口被调用导致图层的状态发生了变化,就到SurfaceControl找到相应的接口,并加日志进一步确认。

  1. public final class SurfaceControl implements Parcelable {
  2. public @Nullable String getName(){
  3. return mName;
  4. }
  5. public static class Transaction implements Closeable, Parcelable {
  6. public Transaction hide(SurfaceControl sc) {
  7. checkPreconditions(sc);
  8. Log.i("SurfaceControl::Transaction", "hide "+sc.getName());
  9. Thread.dumpStack();
  10. nativeSetFlags(mNativeObject, sc.mNativeObject, SURFACE_HIDDEN, SURFACE_HIDDEN);
  11. return this;
  12. }
  13. }
  14. }

在上面的代码中,通过Thread.dumpStack();可以把调用hide方法的调用堆栈打印出来,

  1. 04-12 19:32:57.502 1744 1892 I SurfaceControl::Transaction: hide com.sino.compose/com.sino.compose.MainActivity
  2. 04-12 19:32:57.502 1744 1892 W System.err: java.lang.Exception: Stack trace
  3. 04-12 19:32:57.502 1744 1892 W System.err: at java.lang.Thread.dumpStack(Thread.java:1517)
  4. 04-12 19:32:57.502 1744 1892 W System.err: at android.view.SurfaceControl$Transaction.hide(SurfaceControl.java:2760)
  5. 04-12 19:32:57.502 1744 1892 W System.err: at com.android.server.wm.WindowSurfaceController.hideSurface(WindowSurfaceController.java:128)
  6. 04-12 19:32:57.502 1744 1892 W System.err: at com.android.server.wm.WindowSurfaceController.hide(WindowSurfaceController.java:118)
  7. 04-12 19:32:57.502 1744 1892 W System.err: at com.android.server.wm.WindowStateAnimator.hide(WindowStateAnimator.java:228)
  8. 04-12 19:32:57.502 1744 1892 W System.err: at com.android.server.wm.WindowStateAnimator.prepareSurfaceLocked(WindowStateAnimator.java:531)
  9. 04-12 19:32:57.502 1744 1892 W System.err: at com.android.server.wm.WindowState.prepareSurfaces(WindowState.java:5494)
  10. 04-12 19:32:57.502 1744 1892 W System.err: at com.android.server.wm.WindowContainer.prepareSurfaces(WindowContainer.java:2432)
  11. 04-12 19:32:57.502 1744 1892 W System.err: at com.android.server.wm.ActivityRecord.prepareSurfaces(ActivityRecord.java:6682)
  12. 04-12 19:32:57.502 1744 1892 W System.err: at com.android.server.wm.WindowContainer.prepareSurfaces(WindowContainer.java:2432)
  13. 04-12 19:32:57.502 1744 1892 W System.err: at com.android.server.wm.Task.prepareSurfaces(Task.java:3973)
  14. 04-12 19:32:57.502 1744 1892 W System.err: at com.android.server.wm.WindowContainer.prepareSurfaces(WindowContainer.java:2432)
  15. 04-12 19:32:57.502 1744 1892 W System.err: at com.android.server.wm.WindowContainer.prepareSurfaces(WindowContainer.java:2432)
  16. 04-12 19:32:57.503 1744 1892 W System.err: at com.android.server.wm.WindowContainer.prepareSurfaces(WindowContainer.java:2432)
  17. 04-12 19:32:57.503 1744 1892 W System.err: at com.android.server.wm.WindowContainer.prepareSurfaces(WindowContainer.java:2432)
  18. 04-12 19:32:57.503 1744 1892 W System.err: at com.android.server.wm.WindowContainer.prepareSurfaces(WindowContainer.java:2432)
  19. 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

  1. //frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
  2. void SurfaceFlinger::onMessageRefresh() {
  3. mCompositionEngine->present(refreshArgs);
  4. }
  5. //frameworks/native/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
  6. void CompositionEngine::present(CompositionRefreshArgs& args) {
  7. for (const auto& output : args.outputs) {
  8. output->prepare(args, latchedLayers);
  9. }
  10. }
  11. //frameworks/native/services/surfaceflinger/CompositionEngine/src/Output.cpp
  12. void Output::prepare(const compositionengine::CompositionRefreshArgs& refreshArgs,
  13. LayerFESet& geomSnapshots) {
  14. rebuildLayerStacks(refreshArgs, geomSnapshots);
  15. }
  16. void Output::rebuildLayerStacks(const compositionengine::CompositionRefreshArgs& refreshArgs,
  17. LayerFESet& layerFESet) {
  18. collectVisibleLayers(refreshArgs, coverage);
  19. }
  20. void Output::collectVisibleLayers(const compositionengine::CompositionRefreshArgs& refreshArgs,
  21. compositionengine::Output::CoverageState& coverage) {
  22. for (auto layer : reversed(refreshArgs.layers)) {
  23. // Incrementally process the coverage for each layer
  24. ensureOutputLayerIfVisible(layer, coverage);
  25. }
  26. }
  27. void Output::ensureOutputLayerIfVisible(sp<compositionengine::LayerFE>& layerFE,
  28. compositionengine::Output::CoverageState& coverage) {
  29. auto result = ensureOutputLayer(prevOutputLayerIndex, layerFE);
  30. }
  31. //frameworks/native/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
  32. class Output : public virtual compositionengine::Output {
  33. OutputLayer* ensureOutputLayer(std::optional<size_t> prevIndex,
  34. const sp<LayerFE>& layerFE) {
  35. auto outputLayer = (prevIndex && *prevIndex <= mCurrentOutputLayersOrderedByZ.size())
  36. ? std::move(mCurrentOutputLayersOrderedByZ[*prevIndex])
  37. : BaseOutput::createOutputLayer(layerFE); //here
  38. }
  39. }
  40. //frameworks/native/services/surfaceflinger/CompositionEngine/src/Display.cpp
  41. std::unique_ptr<compositionengine::OutputLayer> Display::createOutputLayer(
  42. const sp<compositionengine::LayerFE>& layerFE) const {
  43. auto hwcLayer = hwc.createLayer(*halDisplayId);
  44. }
  45. //frameworks/native/services/surfaceflinger/DisplayHardware/HWComposer.cpp
  46. std::shared_ptr<HWC2::Layer> HWComposer::createLayer(HalDisplayId displayId) {
  47. auto expected = mDisplayData[displayId].hwcDisplay->createLayer();
  48. }
  49. //frameworks/native/services/surfaceflinger/DisplayHardware/HWC2.cpp
  50. base::expected<std::shared_ptr<HWC2::Layer>, hal::Error> Display::createLayer() {
  51. HWLayerId layerId = 0;
  52. auto intError = mComposer.createLayer(mId, &layerId);
  53. }
  54. //frameworks/native/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
  55. Error Composer::createLayer(Display display, Layer* outLayer)
  56. {
  57. mClient->createLayer(display, kMaxLayerBufferCount,
  58. [&](const auto& tmpError, const auto& tmpLayer) {
  59. error = tmpError;
  60. if (error != Error::NONE) {
  61. return;
  62. }
  63. *outLayer = tmpLayer;
  64. });
  65. return error;
  66. }

    createLayer请求HAL创建硬件图层保存图形缓冲。

2) setBuffer

  1. void CompositionEngine::present(CompositionRefreshArgs& args) {
  2. for (const auto& output : args.outputs) {
  3. output->present(args);
  4. }
  5. }
  6. void Output::present(const compositionengine::CompositionRefreshArgs& refreshArgs) {
  7. writeCompositionState(refreshArgs);
  8. }
  9. void Output::writeCompositionState(const compositionengine::CompositionRefreshArgs& refreshArgs) {
  10. layer->writeStateToHWC(includeGeometry, skipLayer, z++, overrideZ, isPeekingThrough);
  11. }
  12. void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t z,
  13. bool zIsOverridden, bool isPeekingThrough) {
  14. if (auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence); error != hal::Error::NONE) {}
  15. }
  16. //HWC2.cpp
  17. Error Layer::setBuffer(uint32_t slot, const sp<GraphicBuffer>& buffer,
  18. const sp<Fence>& acquireFence)
  19. {
  20. auto intError = mComposer.setLayerBuffer(mDisplay->getId(), mId, slot, buffer, fenceFd);
  21. return static_cast<Error>(intError);
  22. }
  23. Error Composer::setLayerBuffer(Display display, Layer layer,
  24. uint32_t slot, const sp<GraphicBuffer>& buffer, int acquireFence)
  25. {
  26. mWriter.selectDisplay(display);
  27. mWriter.selectLayer(layer);
  28. const native_handle_t* handle = nullptr;
  29. if (buffer.get()) {
  30. handle = buffer->getNativeBuffer()->handle;
  31. }
  32. mWriter.setLayerBuffer(slot, handle, acquireFence);
  33. return Error::NONE;
  34. }

      setBuffer把要显示的图形缓冲从SurfaceFlinger传递到HAL

3) present

  1. void Output::present(const compositionengine::CompositionRefreshArgs& refreshArgs) {
  2. prepareFrame();
  3. }
  4. void Output::prepareFrame() {
  5. chooseCompositionStrategy();
  6. }
  7. void Display::chooseCompositionStrategy() {
  8. if (status_t result =
  9. hwc.getDeviceCompositionChanges(*halDisplayId, anyLayersRequireClientComposition(),
  10. getState().earliestPresentTime,
  11. getState().previousPresentFence, &changes);
  12. }
  13. status_t HWComposer::getDeviceCompositionChanges(
  14. HalDisplayId displayId, bool frameUsesClientComposition,
  15. std::chrono::steady_clock::time_point earliestPresentTime,
  16. const std::shared_ptr<FenceTime>& previousPresentFence,
  17. std::optional<android::HWComposer::DeviceRequestedChanges>* outChanges) {
  18. error = hwcDisplay->presentOrValidate(&numTypes, &numRequests, &outPresentFence , &state);
  19. }
  20. HWC2.cpp
  21. Error Display::presentOrValidate(uint32_t* outNumTypes, uint32_t* outNumRequests,
  22. sp<android::Fence>* outPresentFence, uint32_t* state) {
  23. auto intError = mComposer.presentOrValidateDisplay(
  24. mId, &numTypes, &numRequests, &presentFenceFd, state);
  25. }
  26. Error Composer::presentOrValidateDisplay(Display display, uint32_t* outNumTypes,
  27. uint32_t* outNumRequests, int* outPresentFence, uint32_t* state) {
  28. mWriter.selectDisplay(display);
  29. mWriter.presentOrvalidateDisplay();
  30. }

    present通知HAL把图形数据传递到底层驱动,开始对图形进行合成并显示。

    如果上面3步流程也没有问题,那么可以认为是底层显示驱动的问题,需要在显示驱动模块继续分析原因。

    小结:

    通过上面的分析可以指定,分析图形显示异常的关键主要在SurfaceFlinger,因此要对SurfaceFlinger的关键流程要比较熟悉,同时WindowManagerSurface的内容也很重要,这两部分内容可参考《Android图形显示系统》。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/535836
推荐阅读
相关标签
  

闽ICP备14008679号