问题现象

Untitled

问题分析

首先说明问题出现的是 Android 12,即开始使用 BLASTBufferQueue 的版本。以下内容基于 Android 12 代码。

SurfaceView 的释放 中说明过,SurfaceView.tryReleaseSurfaces() 中会调用 Transaction.remove(),其中 Transaction.reparent() 会把 SurfaceControl 的 sp 指针添加到 transaction 的字段里。然后调用 ViewRootImpl.applyTransactionOnDraw() 把 transaction 注册到下一帧绘制中,下一帧到来时会调用 Transaction::apply() 清除 SurfaceControl 的 sp 指针,这时就释放了 SurfaceControl。

private void tryReleaseSurfaces() {
    mSurfaceAlpha = 1f;

    synchronized (mSurfaceControlLock) {
        mSurface.destroy();
        if (mBlastBufferQueue != null) {
            mBlastBufferQueue.destroy();
            mBlastBufferQueue = null;
        }

        ViewRootImpl viewRoot = getViewRootImpl();
        Transaction transaction = new Transaction();
        releaseSurfaces(transaction);
        if (viewRoot != null) {
            viewRoot.applyTransactionOnDraw(transaction);
        } else {
            transaction.apply();
        }
    }
}

然而,我们的用例是 finish activity,所以就不会有下一帧绘制。这导致了永远不会调用 Transaction::apply(),所以 SurfaceControl 无法被释放。

但是 transaction 是一个局部变量,所以当 GC 执行后会释放该 transaction,同时 Transaction 的构造器中利用虚引用监听了该对象的生命周期,当 Transaction 对象回收时会调用 releaseTransaction() 删除 Transaction native 对象。因此,当 GC 执行后 SurfaceView layer 销毁了。

public static class Transaction implements Closeable, Parcelable {
    public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
            Transaction.class.getClassLoader(),
            nativeGetNativeTransactionFinalizer(), 512);

    public Transaction() {
        mNativeObject = nativeCreateTransaction();
        mFreeNativeResources
            = sRegistry.registerNativeAllocation(this, mNativeObject);
    }
}