首先说明问题出现的是 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);
}
}