SurfaceFlinger07-Layer销毁流程

前言

在上一篇文章中,对Layer的创建流程进行了分析。Layer创建完成后,根节点或Parent Layer是保存在SurfaceFlinger类中的mCurrentState.layersSortedByZmDrawingState.layersSortedByZ列表中,而子Layer则是保存在对应Parent Layer的mCurrentChildrenmDrawingChildren列表中。

同时,在客户端SurfaceControl对象中持有sp引用,LayerHandle中持有sp引用,因此客户端通过操作LayerHandle就能找到与之对应的Layer。

当SurfaceControl销毁时,对应sp在引用数清零后开始析构,从而触发sp 的引用计数减一。当sp 引用数清零后,便会对Layer进行析构,完成Layer的销毁。

在这个过程中,如果sp持有数太多,则会出现SurfaceControl销毁但Layer没有销毁的场景,此时将导致Layer的泄漏。

surfaceflinger中规定最多只能创建4096个Layer,一旦存留过多,会导致性能变差,带来内存不足、卡顿、发热等问题。所以当业务进程不再使用Layer时,要即时释放销毁,避免出现Layer泄漏问题而影响性能、稳定性。

本篇文章中,将对Layer的整个销毁流程进行说明总结。

Layer的整个销毁流程分为三步:SurfaceControl销毁 -> LayerHandle销毁 -> Layer销毁。

一、SurfaceControl销毁

SurfaceControl销毁有两种方式:

  1. 调用SurfaceControl.release()方法

该方法可以销毁客户端SurfaceControl对象,并将其内部的LayerHandle引用计数减一,但并不一定会保证surfaceflinger进程内的LayerHandle、Layer对象也同步销毁,还要取决于该LayerHandle是否被其他SurfaceControl引用,以及Layer是否存在Parent Layer。

如果对应Layer存在Parent,当客户端对应SurfaceControl销毁时,并不会将Layer同步进行析构,这是因为在Parent Layer中还持有子Layer的强指针引用(sp)。在当其Parent释放时,才会进行析构和销毁。

如果希望对应Layer立即销毁,需要先调用SurfaceControl.Transaction.reparent(null)方法将其Parent置空后,再执行release();

  1. 调用SurfaceControl.Transaction.remove(SurfaceControl sc)方法。

该方法会对客户端和服务端资源同时进行释放,其内部结合了以上提到的两方法:

java 复制代码
public Transaction remove(@NonNull SurfaceControl sc) {
    // 先将Parent设置为null
    reparent(sc, null);
    // 再进行release操作
    sc.release();
    return this;
}

因此,当释放SurfaceControl后,为确保Layer能正常销毁,必须至少满足:

所有引用该Layer对应LayerHandle的SurfaceControl对象全部通过SurfaceControl.release()释放、且通过SurfaceControl.reparent(null)将其父Layer置空。

理想情况下,如果一个Parent为空的SurfaceControl执行其release()方法后,surfaceflinger中对应的LayerHandle、Layer会依次释放和析构,反之,如果Parent不为空,则仅释放析构LayerHandle,Layer不会析构。

1.1、SurfaceControl.release()方法释放SurfaceControl

SurfaceControl.release()方法如下:

java 复制代码
// frameworks/base/core/java/android/view/SurfaceControl.java
   
    public void release() {
        if (mNativeObject != 0) {
            // 执行Runnable
            mFreeNativeResources.run();
            // 重置native SurfaceControl指针强转类型值
            mNativeObject = 0;
            // 重置native LayerHandler指针强转类型值
            mNativeHandle = 0;
            .....
            mCloseGuard.close();
            // mChoreographer置空
            synchronized (mChoreographerLock) {
                if (mChoreographer != null) {
                    mChoreographer.invalidate();
                    mChoreographer = null;
                }
            }
            // 从SurfaceControlRegistry中移除,用于Debug
            removeFromRegistry();
        }
    }

以上方法中:

  1. 执行mFreeNativeResources.run(),触发Native层对象内存的释放;
  2. 将Native层对象句柄置为0;

mFreeNativeResources是一个Runnable类型对象,这是释放Native层资源的关键组件。mNativeObject和mNativeHandle分别是Native层SurfaceControl指针和LayerHandle指针地址。

1.2、NativeAllocationRegistry释放Native资源

我们知道,Java对象可以通过JVM垃圾回收器自动进行回收,但Native层对象必须显式进行释放才能回收,因此需要在JVM对象回收前,对引用的Native层资源也需要进行释放,这时就可以通过NativeAllocationRegistry来实现。

NativeAllocationRegistry用于对本地内存(Native Allocations)和Java对象进行关联,并将它们注册到运行时中。

在以上流程中,当执行release()方法时,便通过mFreeNativeResources.run()触发Native层对象资源的释放;

对于某个代码块内的SurfaceControl局部对象而言,会当Java对象由于GC释放内存时,Native层对象也将同步通过注册函数完成Native层内存的释放。

下面来看下NativeAllocationRegistry的具体使用。

1.2.1、获取NativeAllocationRegistry实例

在SurfaceControl创建过程中,会创建并获取一个NativeAllocationRegistry对象:

java 复制代码
// frameworks/base/core/java/android/view/SurfaceControl.java

// 创建NativeAllocationRegistry实例
private static final NativeAllocationRegistry sRegistry =
        NativeAllocationRegistry.createMalloced(SurfaceControl.class.getClassLoader(),
                nativeGetNativeSurfaceControlFinalizer());

其中第二个参数是一个函数接口,用于释放Native层关联对象的函数。因此,当Java层SurfaceControl释放时,会执行nativeGetNativeSurfaceControlFinalizer()方法对Native层对象进行释放。

1.2.2、关联Java Objects和Native Allocations

也是在SurfaceControl创建过程中,会通过NativeAllocationRegistry.registerNativeAllocation()方法对Java层对象和Native层对象进行关联,并返回一个Runnable对象:

java 复制代码
// frameworks/base/core/java/android/view/SurfaceControl.java

private void assignNativeObject(long nativeObject, String callsite) {
    ......
    if (nativeObject != 0) {
        // 注册待回收Native Allocation(nativeObject)对象并返回Runnable
        mFreeNativeResources =
                sRegistry.registerNativeAllocation(this, nativeObject);
    }
    .....
}

1.2.3、执行nativeGetNativeSurfaceControlFinalizer()释放Native资源

因此,在执行mFreeNativeResources.run()后,将触发nativeGetNativeSurfaceControlFinalizer()方法的执行:

cpp 复制代码
// frameworks/base/core/jni/android_view_SurfaceControl.cpp

static jlong nativeGetNativeSurfaceControlFinalizer(JNIEnv* env, jclass clazz) {
    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&release));
}

static void release(SurfaceControl* ctrl) {
    // 引用计数减1, 无引用后将析构
    ctrl->decStrong((void *)nativeCreate);
}

当Native层sp指针引用计数为0后,将通过delete操作释放该指针,SurfaceControl将被析构。

1.3、执行SurfaceControl::~SurfaceControl()

Native层SurfaceControl析构方法如下:

cpp 复制代码
// frameworks/native/libs/gui/SurfaceControl.cpp

SurfaceControl::~SurfaceControl()
{
    // 清除sp<SurfaceComposerClient>引用计数
    mClient.clear();
    // 清除sp<LayerHandle>引用计数
    mHandle.clear();
    // 清除sp<BLASTBufferQueue>引用计数
    mBbq.clear();
    // 刷新Binder命令队列,同步服务端
    IPCThreadState::self()->flushCommands();
}

以上方法中,对各类对象sp指针进行了引用计数清零,其中包括sp,之后surfaceflinger进程中将执行LayerHandler的析构。

在Binder IPC中,引用计数管理自动进行,不需要直接调用 IPCThreadState::processPendingDerefs() 方法。这个方法是 Binder IPC 机制内部的实现细节,由系统在适当的时机调用以确保资源正确管理。

此时,客户端进程SurfaceControl等对象内存完成释放。

二、LayerHandle销毁

进入surfaceflinger进程,LayerHandle析构方法如下:

cpp 复制代码
// frameworks/native/services/surfaceflinger/FrontEnd/LayerHandle.cpp

LayerHandle::~LayerHandle() {
    if (mFlinger) {
        // 执行SurfaceFlinger::onHandleDestroyed()
        mFlinger->onHandleDestroyed(this, mLayer, mLayerId);
    }
}

以上方法中,直接执行SurfaceFlinger::onHandleDestroyed()方法。

2.1、SurfaceFlinger::onHandleDestroyed()

cpp 复制代码
// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

void SurfaceFlinger::onHandleDestroyed(BBinder* handle, sp<Layer>& layer, uint32_t layerId) {
    {
        std::scoped_lock<std::mutex> lock(mCreatedLayersLock);
        // 将LayerId添加到mDestroyedHandles列表中
        mDestroyedHandles.emplace_back(layerId);
    }
    Mutex::Autolock lock(mStateLock);
    // 将Layer对象添加到待移除列表中
    markLayerPendingRemovalLocked(layer);
    // 将mHandleAlive属性设置为false
    layer->onHandleDestroyed();
    mBufferCountTracker.remove(handle);
    // 清除sp<Layer>引用计数
    layer.clear();
    // 设置eTransactionNeeded标记,发起surfaceflinger提交操作
    setTransactionFlags(eTransactionFlushNeeded);
}

以上方法中:

  1. 将Layer ID添加到mDestroyedHandles列表中,mDestroyedHandles列表中保存的是销毁LayerHandle对应的Layer ID,在收到VSYNC信号执行事务提交和更新时,会填充给frontend::Update。(这个列表在LifeCycleManager方案中使用,Android U版本没有使用);

  2. 执行markLayerPendingRemovalLocked()将方法Layer对象添加到待移除列表中;

  3. 执行layer->onHandleDestroyed()方法将mHandleAlive属性设置为false,表示LayerHandle已经被销毁;

  4. 清除LayerHandler中的sp引用计数,之后LayerHandle::mLayer将被置为nullptr,但由于其他位置依然存在对Layer的引用,因此此次clear不会触发Layer析构方法的执行;

  5. 执行setTransactionFlags()方法触发SurfaceFlinger中VSYNC的调度。

2.1.1、加入mLayersPendingRemoval列表

markLayerPendingRemovalLocked()方法中,将Layer添加到mLayersPendingRemoval列表中:

cpp 复制代码
// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

void SurfaceFlinger::markLayerPendingRemovalLocked(const sp<Layer>& layer) {
    // 将Layer添加到mLayersPendingRemoval列表中
    mLayersPendingRemoval.add(layer);
    // 一个标记值,用于在合成过程遍历mLayersPendingRemoval列表
    mLayersRemoved = true;
    // 设置eTransactionNeeded标记
    setTransactionFlags(eTransactionNeeded);
}

mLayersPendingRemoval中保存待销毁的Layer,在之后执行Layer更新时,将会从该列表中取出Layer,并执行相应的LayerTree移除操作。

LayerHandle析构执行完毕后,意味着LayerHandle完成销毁。接下来,在SurfaceFlinger中收到VSYNC信号进行事务提交和Layer状态更新时,会对mLayersPendingRemoval列表中的Layer进行更新和移除,同时在这个过程中,当Layer指针引用计数清零后,开始析构Layer。

三、Layer销毁

Layer的析构必须在surfaceflinger主线程进行,否则将直接中止程序的执行。因此,在SurfaceFlinger中收到VSYNC信号后,在主线程进行下一次提交和合成过程中,会对待释放的Layer进行析构,同时更新合成输出内容。

在这个过程中,正常情况下,Layer的析构发生在以下两个操作中的任意一处:

  1. 在LayerHandle发生析构后,如果该Layer在上一帧还处于可见状态,该Layer以及其已经释放LayerHandle的子Layer会在SurfaceFligner::composite()方法中清空mPreviouslyComposedLayers列表后开始析构;
  2. 在LayerHandle发生析构后,如果该Layer在上一帧前就不处于可见状态,且不存在Parent Layer,则该Layer会在SurfaceFlinger::doCommitTransactions()方法中清空mLayersPendingRemoval列表后开始析构。

下面看下在commit和composite过程中跟Layer销毁相关的逻辑。

3.1、commit过程中更新赃区域和OffscreenLayer列表

commit过程中,经过commit() -> updateLayerSnapshotsLegacy() -> commitTransactions()调用,在commitTransactionsLocked()方法中会首先针对mLayersPendingRemoval中的元素进行dirty区域更新:

cpp 复制代码
// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
    
void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) {
    // Commit display transactions.
    const bool displayTransactionNeeded = transactionFlags & eDisplayTransactionNeeded;
    mFrontEndDisplayInfosChanged = displayTransactionNeeded;
    ....

    // Layer销毁相关
    if (mLayersRemoved) {
        mLayersRemoved = false;
        mVisibleRegionsDirty = true;
        mUpdateInputInfo = true;
        // 遍历mDrawingState.layersSortedByZ列表,更新脏区域
        mDrawingState.traverseInZOrder([&](Layer* layer) {
            if (mLayersPendingRemoval.indexOf(sp<Layer>::fromExisting(layer)) >= 0) {
                Region visibleReg;
                visibleReg.set(layer->getScreenBounds());
                invalidateLayerStack(layer->getOutputFilter(), visibleReg);
            }
        });
    }
    ......
    
    doCommitTransactions();
}

以上方法代码片段中:

  1. 会将待移除Layer对应区域标记为"赃区域",在之后的合成阶段对赃区域进行处理;
  2. 执行doCommitTransactions()方法,更新mCurrentState.layersSortedByZ列表、OffScreenLayers列表等 ;

3.1.1、更新dirtyRegion

进入mLayersPendingRemoval列表的Layer,表示是待移除的Layer,Layer对应的区域也需要在合成时进行刷新,因此把这部分跟Layer面积相同的区域标记为赃区域,通过invalidateLayerStack()方法标记:

cpp 复制代码
// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
void SurfaceFlinger::invalidateLayerStack(const ui::LayerFilter& layerFilter, const Region& dirty) {
    // 遍历DisplayDevice列表
    for (const auto& [token, displayDevice] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
        auto display = displayDevice->getCompositionDisplay();
        // 根据layerFilter找到对应的DisplayDevice,
        // 并对对应OutputCompositionState.dirtyRegion进行区域标记
        if (display->includesLayer(layerFilter)) {
            display->editState().dirtyRegion.orSelf(dirty);
        }
    }
}

最终对CompostionDisplay的OutputCompositionState.dirtyRegion属性进行了更新,OutputCompositionState属性是合成过程中用于记录状态的属性,如屏幕的合成方式、内容投射区域、色彩空间、色彩矩阵等等.....

3.1.2、更新DrawingState和OffScreenLayers列表

接下来执行doCommitTransactions()方法,开始更新SurfaceFlinger.mDrawingState和OffScreenLayer列表:

cpp 复制代码
// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

void SurfaceFlinger::doCommitTransactions() {

    if (!mLayersPendingRemoval.isEmpty()) {
        // Notify removed layers now that they can't be drawn from
        for (const auto& l : mLayersPendingRemoval) {
            // 释放Buffer
            if (l->isRemovedFromCurrentState()) {
                l->latchAndReleaseBuffer();
            }

            // 对于Root节点Layer, 从RootLayer列表中移除
            if (l->isAtRoot()) {
                l->setIsAtRoot(false);
                mCurrentState.layersSortedByZ.remove(l);
            }

            // 对于不存在Parent的Layer,将其添加到mOffscreenLayers中
            if (!l->getParent()) {
                mOffscreenLayers.emplace(l.get());
            }
        }
        // 清空mLayersPendingRemoval列表
        mLayersPendingRemoval.clear();
    }

    // 更新mDrawingState
    mDrawingState = mCurrentState;
    // clear the "changed" flags in current state
    mCurrentState.colorMatrixChanged = false;
    // 更新Layer内部DrawingState
    if (mVisibleRegionsDirty) {
        for (const auto& rootLayer : mDrawingState.layersSortedByZ) {
            rootLayer->commitChildList();
        }
    }
    // 更新OffScreenLayer内部状态
    commitOffscreenLayers();
    ......
}

以上方法中:

  1. 对于没有Parent的根节点Layer,会将其从根节点Layer列表mCurrentState.layersSortedByZ中直接移除;

  2. 对于不存在Parent的Layer,会将其添加到mOffscreenLayers列表中;

  3. 清空mLayersPendingRemoval列表;

  4. 将mCurrentState更新给mDrawingState;

  5. 执行commitOffscreenLayers()更新OffScreenLayer状态。

以上逻辑执行完毕后,mLayersPendingRemoval列表被清空,因此如果此时sp计数也恰好为0,就开始执行Layer析构方法。

OffscreenLayer表示不再参与合成但未析构的Layer。另外,需要注意的是,mOffscreenLayers列表中是直接将Layer*进行保存,其不会影响sp引用计数。

3.2、composite过程中更新mPreviouslyComposedLayers列表

mPreviouslyComposedLayers列表中保存的是上一帧合成时参与合成的Layer。每次合成时,如果存在赃区域,会在moveSnapshotsToCompositionArgs()方法中对其进行更新:

cpp 复制代码
// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

std::vector<std::pair<Layer*, LayerFE*>> SurfaceFlinger::moveSnapshotsToCompositionArgs(
        compositionengine::CompositionRefreshArgs& refreshArgs, bool cursorOnly, int64_t vsyncId) {
    std::vector<std::pair<Layer*, LayerFE*>> layers;
    if (mLayerLifecycleManagerEnabled) {
        ......
    }
    if (mLegacyFrontEndEnabled && !mLayerLifecycleManagerEnabled) {
        // 定义函数moveSnapshots,接收一个Layer指针类型参数
        auto moveSnapshots = [&layers, &refreshArgs, cursorOnly](Layer* layer) {
            if (const auto& layerFE = layer->getCompositionEngineLayerFE()) {
                if (cursorOnly &&
                    layer->getLayerSnapshot()->compositionType !=
                            aidl::android::hardware::graphics::composer3::Composition::CURSOR)
                    return;
                // 更新LayerSnapshot
                layer->updateSnapshot(refreshArgs.updatingGeometryThisFrame);
                // 将LayerSnapshot转移给LayerFE
                layerFE->mSnapshot = layer->stealLayerSnapshot();
                refreshArgs.layers.push_back(layerFE);
                layers.emplace_back(layer, layerFE.get());
            }
        };

        if (cursorOnly || !mVisibleRegionsDirty) {
            ......
        } else {
            // 清空mPreviouslyComposedLayers列表
            mPreviouslyComposedLayers.clear();
            // 遍历Layer列表
            mDrawingState.traverseInZOrder(
                    [&moveSnapshots](Layer* layer) { moveSnapshots(layer); });
            mPreviouslyComposedLayers.reserve(layers.size());
            // 将参与合成的Layer重新添加到列表mPreviouslyComposedLayers
            for (auto [layer, _] : layers) {
                mPreviouslyComposedLayers.push_back(sp<Layer>::fromExisting(layer));
            }
        }
    }

    return layers;
}

以上方法中,会将该帧参与合成的Layer添加到列表mPreviouslyComposedLayers,而不参与合成的将移除掉。

正常情况下,从mPreviouslyComposedLayers中移除后,sp对象引用计数将清零,后续将开始执行Layer的析构。

3.2、执行Layer::~Layer()

Layer析构方法如下:

cpp 复制代码
// frameworks/native/services/surfaceflinger/Layer.cpp

Layer::~Layer() {
    // 必须在主线程执行
    LOG_ALWAYS_FATAL_IF(std::this_thread::get_id() != mFlinger->mMainThreadId,
                        "Layer destructor called off the main thread.");

    // 执行onReleaseBuffer方法回调,通知BBQ释放Buffer
    if (mBufferInfo.mBuffer != nullptr) {
        callReleaseBufferCallback(mDrawingState.releaseBufferListener,
                                  mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFrameNumber,
                                  mBufferInfo.mFence);
    }
    // 移除该Layer的Texture
    // Clone Layer和Original Layer共享一个Texture
    if (!isClone()) {
        mFlinger->deleteTextureAsync(mTextureName);
    }
    
    ......
    // Layer销毁后的回调
    mFlinger->onLayerDestroyed(this);
    ......
}

在以上方法中,分别对Layer相关资源也进行了释放,然后执行mFlinger->onLayerDestroyed()方法:

cpp 复制代码
// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

void SurfaceFlinger::onLayerDestroyed(Layer* layer) {
    // Layer数 -1
    mNumLayers--;
    // 从offscreenLayer列表中移除
    removeHierarchyFromOffscreenLayers(layer);
    // 从调度器中移除Layer,用于刷新率管控
    if (!layer->isRemovedFromCurrentState()) {
        mScheduler->deregisterLayer(layer);
    }
    .......
}

以上方法中:

  1. 执行removeHierarchyFromOffscreenLayers()方法,将Layer从offscreenLayer列表中移除;

  2. 执行mScheduler->deregisterLayer()方法,将Layer从Scheduler中移除,用于刷新率管控。

removeHierarchyFromOffscreenLayers()方法移除OffscreenLayer如下:

cpp 复制代码
// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

void SurfaceFlinger::removeHierarchyFromOffscreenLayers(Layer* layer) {
    // 如果析构Layer存在子Layer, 则会将子Layer添加到offScreenLayer列表中
    for (auto& child : layer->getCurrentChildren()) {
        mOffscreenLayers.emplace(child.get());
    }
    // 从OffScreenLayer列表中移除
    mOffscreenLayers.erase(layer);
}

因此,当Layer完成析构,便从OffscreenLayer列表中移除。

以上就是整个Layer的销毁过程。

下面对OffscreenLayer和Layer泄漏场景做下补充说明。

四、关于OffscreenLayer

OffscreenLayer表示从Layer树结构不可达(不再参与合成)但未析构的Layer。这里再说明下关于OffScreenLayer的三个问题:

  1. OffscreenLayer的作用是什么?

  2. 什么情况下会将Layer添加到OffscreenLayer列表?

  3. 什么情况下会将Layer从OffscreenLayer列表中移除?

4.1、OffscreenLayer的作用

OffscreenLayer的特点是:不可达、不参与合成、Layer未析构、但依然可以接收GraphicBuffer的更新。

因此,当需要持续更新图层显示数据但又不希望图层显示时,可以将它作为"离屏图层"放入OffscreenLayer列表中,等再需要它显示时,重新从OffscreenLayer列表中移出来,继续参与合成过程。

如此一来,可以避免频繁地创建和销毁Layer对象,从而提高系统的性能和进行资源的复用。

4.2、添加到OffscreenLayer列表的场景

以下三种场景可以将Layer添加到offscreenLayer中:

  1. 当一个LayerHandle发生析构,且对应Layer没有Parent Layer时,会将对应Layer加入OffscreenLayer列表中(并在Layer析构时从Offscreen列表中移除);

  2. 当一个Layer发生析构后,会将其所有子Layer加入OffscreenLayer列表;

  3. 当一个Layer进行reparent,且将其Parent置为空时,会将该Layer加入OffscreenLayer列表;

前两种场景已在上面进行过说明,这里补充下第三种场景。第三种场景跟Layer的reparent操作有关,因此这里对reparent过程做个完成的说明。

4.2.1、Layer的reparent过程

Layer::reparent()方法看起:

cpp 复制代码
// frameworks/native/services/surfaceflinger/Layer.cpp

bool Layer::reparent(const sp<IBinder>& newParentHandle) {
    ......
    sp<Layer> parent = getParent();
    // 当前Parent Layer中移除该Layer
    if (parent != nullptr) {
        parent->removeChild(sp<Layer>::fromExisting(this));
    }

    if (newParentHandle != nullptr) {
        // 如果新Parent Layer不为空,添加到新Parent Layer中
        newParent->addChild(sp<Layer>::fromExisting(this));
        // 如果新Parent Layer参与合成过程,则该Layer也将参与到合成过程
        // 否则,将该Layer添加到待移除列表中
        if (!newParent->isRemovedFromCurrentState()) {
            addToCurrentState();
        } else {
            onRemovedFromCurrentState();
        }
    } else {
        // 否则,将该Layer添加到待移除列表中
        onRemovedFromCurrentState();
    }

    return true;
}

以上方法中:

  1. 如果新Parent Layer不为空,则将该Layer添加到新Parent Layer的Child列表中;

    • 如果新Parent Layer参与合成过程,则该Layer也将参与;
    • 如果新Parent Layer不参与合成过程,则将该Layer及它的子Layer添加到待移除列表中;
  2. 如果新Parent Layer为空,则将该LayerLayer及它的子Layer添加到待移除列表中,并在随后添加到OffscreenLayer中;

Layer::mRemovedFromDrawingState属性表示该Layer是否参与合成过程,默认为false,当不需要参与合成过程时,会通过Layer::onRemovedFromCurrentState()方法将该Layer及它的子Layer的该属性值设置为true,随后加入到mLayersPendingRemoval列表中:

cpp 复制代码
//  frameworks/native/services/surfaceflinger/Layer.cpp

void Layer::onRemovedFromCurrentState() {
    // 获取当前Layer所在的整个LayerTree
    auto layersInTree = getRootLayer()->getLayersInTree(LayerVector::StateSet::Current);
    std::sort(layersInTree.begin(), layersInTree.end());

    REQUIRE_MUTEX(mFlinger->mStateLock);
    // 遍历当前Layer的子Layer,并执行自身及子Layer的removeFromCurrentState()方法
    traverse(LayerVector::StateSet::Current,
             [&](Layer* layer) REQUIRES(layer->mFlinger->mStateLock) {
                 layer->removeFromCurrentState();
                 layer->removeRelativeZ(layersInTree);
             });
}

最终调用Layer::removeFromCurrentState()方法,更新了mRemovedFromDrawingState值,并添加到了mLayersPendingRemoval中:

cpp 复制代码
//  frameworks/native/services/surfaceflinger/Layer.cpp
void Layer::removeFromCurrentState() {
    // 将mRemovedFromDrawingState值修改为true
    if (!mRemovedFromDrawingState) {
        mRemovedFromDrawingState = true;
        mFlinger->mScheduler->deregisterLayer(this);
    }
    updateTrustedPresentationState(nullptr, nullptr, -1 /* time_in_ms */, true /* leaveState*/);
    // 添加到待移除列表中
    mFlinger->markLayerPendingRemovalLocked(sp<Layer>::fromExisting(this));
}

之后,便根据3.1.2小节中的内容,将mLayersPendingRemoval中不存在Parent Layer的Layer添加到mOffscreenLayers中。

4.3、移出OffscreenLayer列表的场景

以下两种场景下,会将Layer从OffscreenLayer列表中移除:

  1. 当一个Layer发生析构后,会将其从OffscreenLayer列表中移除,这时该Layer已经彻底销毁,见SurfaceFlinger::onLayerDestroyed()方法;
  2. 当一个Layer进行reparent,对其设置一个参与合成过程的Parent Layer时,会将其从OffscreenLayer列表中移除,这时该Layer及其子Layer将重新参与合成过程。

第二种场景在Layer::addToCurrentState()方法中:

cpp 复制代码
// frameworks/native/services/surfaceflinger/Layer.cpp
void Layer::addToCurrentState() {
    if (mRemovedFromDrawingState) {
        mRemovedFromDrawingState = false;
        // 向调度器注册Layer
        mFlinger->mScheduler->registerLayer(this);
        // 从Offscreen中移除
        mFlinger->removeFromOffscreenLayers(this);
    }
    // 对子Layer进行同样操作
    for (const auto& child : mCurrentChildren) {
        child->addToCurrentState();
    }
}

void SurfaceFlinger::removeFromOffscreenLayers(Layer* layer) {
    mOffscreenLayers.erase(layer);
}

如果一直位于OffsreenLayer中且一直没有进行移除,则可能发生了OffscreenLayer泄漏。

五、Layer泄漏场景

通过对Layer创建和销毁流程的分析,可以看到SurfaceControl、LayerHandle、Layer三者关联性非常强,任意一个出现问题,都可能导致Layer发生泄漏,进而影响整个系统。

导致Layer泄漏的常见原因主要有:

  1. SurfaceControl操作不合理。

    • 业务侧在使用完毕SurfaceControl后,没有执行SurfaceControl.release()进行释放;
    • 业务侧在释放时,如果存在父SurfaceControl,没有执行SurfaceControl.reparent(null)
    • 业务侧创建了多份SurfaceControl副本,且没有对所有副本都执行以上操作。
  2. LayerHandle操作不合理。

    • SurfaceControl未析构,持有LayerHandle引用;
    • ComposerState未析构,持有LayerHandle引用。
  3. Layer操作不合理。

    • 释放时没有将Parent Layer置空;
    • 仅对Parent Layer进行释放,未释放子Layer;

因此,在使用SurfaceControl时,需要规范使用。当出现Layer泄漏问题时,也可以从这几个方向出发排查具体原因。

相关推荐
sz_denny11 分钟前
jlatexmath-android如何实现自定义渲染字符
android
lichong9512 小时前
【Flutter&Dart】MVVM(Model-View-ViewModel)架构模式例子-dio版本(31 /100)
android·flutter·架构·api·postman·win·smartapi
cheese-liang3 小时前
如何使用Python将长图片分隔为若干张小图片
android·java·python
我命由我123454 小时前
11-3.Android 项目结构 - 认识 .idea 目录
android·xml·java·java-ee·gitee·android jetpack·android runtime
JJIAYin7 小时前
RN|系统组件之触摸组件及区别 📝
android·前端·react native
谁把我睡的觉偷了xhxh8 小时前
MySQL查询相关内容
android·adb
尘云逸10 小时前
react native学习【6.1】——列表视图
android·学习·react native
2401_8979138611 小时前
android EditText光标位置,光标样式,EditText限制输入内容,软键盘遮挡的EditText,搜索框,限制输入表情
android
氤氲息12 小时前
Android 防止每次打开APP都显示启动页
android
m0_7482451719 小时前
万字详解 MySQL MGR 高可用集群搭建
android·mysql·adb