diff options
| -rw-r--r-- | services/surfaceflinger/Layer.cpp | 22 |
1 files changed, 21 insertions, 1 deletions
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index d5498edf35..c21f0c26a1 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2543,7 +2543,25 @@ bool Layer::reparentChildren(const sp<IBinder>& newParentHandle) { } for (const sp<Layer>& child : mCurrentChildren) { - newParent->addChild(child); + // We don't call addChild as we need to delay updating the child's parent pointer until + // a transaction occurs. Remember a refresh could occur in between now and the next + // transaction, in which case the Layer's parent pointer would be updated, but changes + // made to the parent in the same transaction would not have applied. + // This means that the following kind of scenario wont work: + // + // 1. Existing and visible child and parent surface exist + // 2. Create new surface hidden + // 3. Open transaction + // 4. Show the new surface, and reparent the old surface's children to it. + // 5. Close transaction. + // + // If we were to update the parent pointer immediately, then the child surface + // could disappear for one frame as it pointed at the new parent which + // hasn't yet become visible as the transaction hasn't yet occurred. + // + // Instead we defer the reparenting to commitChildList which happens as part + // of the global transaction. + newParent->mCurrentChildren.add(child); sp<Client> client(child->mClientRef.promote()); if (client != nullptr) { @@ -2713,6 +2731,8 @@ uint8_t Layer::getAlpha() const { void Layer::commitChildList() { for (size_t i = 0; i < mCurrentChildren.size(); i++) { const auto& child = mCurrentChildren[i]; + child->setParent(this); + child->commitChildList(); } mDrawingChildren = mCurrentChildren; |