[animation-worket] Ensure each worklet receives only its own input
Previously we would allow worklet to access and act on all of worklet inputs.
This is bad since it can leak information between different animation
worklet global scopes.
Summary of the fix:
- Introduce WorkletAnimationId which can uniquely identify both the worklet and animation.
- Give each worklet animation its own Id generated using its underlying worklet's scope.
- Plumb this new Id to cc.
- AnimationHost produces input state which is bucketed per scope.
- CompositorMutatorImpl only passes to each compositor animator the input.
bucket that matches that compositor animator's scope Id.
- For additional safety added DCHECK to verify that each scope is receiving only its
own input.
TEST: compositor_mutator_impl_test.cc
Bug: 857479
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_layout_tests_slimming_paint_v2;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: Ib4b8f610ef661bdbf09c4c0252a2b9c4ba04db16
Reviewed-on: https://chromium-review.googlesource.com/1120436
Reviewed-by: Kentaro Hara <[email protected]>
Reviewed-by: Robert Flack <[email protected]>
Commit-Queue: Majid Valipour <[email protected]>
Cr-Commit-Position: refs/heads/master@{#572572}
diff --git a/cc/trees/layer_tree_mutator.cc b/cc/trees/layer_tree_mutator.cc
index 801e3ad..addb471 100644
--- a/cc/trees/layer_tree_mutator.cc
+++ b/cc/trees/layer_tree_mutator.cc
@@ -4,25 +4,88 @@
#include "cc/trees/layer_tree_mutator.h"
+#include <algorithm>
+
namespace cc {
-MutatorInputState::AddAndUpdateState::AddAndUpdateState(
- int animation_id,
+AnimationWorkletInput::AddAndUpdateState::AddAndUpdateState(
+ WorkletAnimationId worklet_animation_id,
std::string name,
double current_time,
std::unique_ptr<AnimationOptions> options)
- : animation_id(animation_id),
+ : worklet_animation_id(worklet_animation_id),
name(name),
current_time(current_time),
options(std::move(options)) {}
-MutatorInputState::AddAndUpdateState::AddAndUpdateState(AddAndUpdateState&&) =
- default;
-MutatorInputState::AddAndUpdateState::~AddAndUpdateState() = default;
+AnimationWorkletInput::AddAndUpdateState::AddAndUpdateState(
+ AddAndUpdateState&&) = default;
+AnimationWorkletInput::AddAndUpdateState::~AddAndUpdateState() = default;
+
+#if DCHECK_IS_ON()
+bool AnimationWorkletInput::ValidateScope(int scope_id) const {
+ return std::all_of(added_and_updated_animations.cbegin(),
+ added_and_updated_animations.cend(),
+ [scope_id](auto& it) {
+ return it.worklet_animation_id.scope_id == scope_id;
+ }) &&
+ std::all_of(updated_animations.cbegin(), updated_animations.cend(),
+ [scope_id](auto& it) {
+ return it.worklet_animation_id.scope_id == scope_id;
+ }) &&
+ std::all_of(removed_animations.cbegin(), removed_animations.cend(),
+ [scope_id](auto& it) { return it.scope_id == scope_id; });
+}
+#endif
+
+AnimationWorkletInput::AnimationWorkletInput() = default;
+AnimationWorkletInput::~AnimationWorkletInput() = default;
MutatorInputState::MutatorInputState() = default;
MutatorInputState::~MutatorInputState() = default;
-MutatorOutputState::MutatorOutputState() = default;
-MutatorOutputState::~MutatorOutputState() = default;
+bool MutatorInputState::IsEmpty() const {
+ // If there is an AnimationWorkletInput entry in the map then that entry is
+ // guranteed to be non-empty. So checking |inputs_| map emptiness is
+ // sufficient.
+ return inputs_.empty();
+}
+
+AnimationWorkletInput& MutatorInputState::EnsureWorkletEntry(int id) {
+ auto it = inputs_.find(id);
+ if (it == inputs_.end())
+ it = inputs_.emplace_hint(it, id, new AnimationWorkletInput);
+
+ return *it->second;
+}
+
+void MutatorInputState::Add(AnimationWorkletInput::AddAndUpdateState&& state) {
+ AnimationWorkletInput& worklet_input =
+ EnsureWorkletEntry(state.worklet_animation_id.scope_id);
+ worklet_input.added_and_updated_animations.push_back(std::move(state));
+}
+void MutatorInputState::Update(AnimationWorkletInput::UpdateState&& state) {
+ AnimationWorkletInput& worklet_input =
+ EnsureWorkletEntry(state.worklet_animation_id.scope_id);
+ worklet_input.updated_animations.push_back(std::move(state));
+}
+void MutatorInputState::Remove(WorkletAnimationId worklet_animation_id) {
+ AnimationWorkletInput& worklet_input =
+ EnsureWorkletEntry(worklet_animation_id.scope_id);
+ worklet_input.removed_animations.push_back(worklet_animation_id);
+}
+
+std::unique_ptr<AnimationWorkletInput> MutatorInputState::TakeWorkletState(
+ int scope_id) {
+ auto it = inputs_.find(scope_id);
+ if (it == inputs_.end())
+ return nullptr;
+
+ std::unique_ptr<AnimationWorkletInput> result = std::move(it->second);
+ inputs_.erase(it);
+ return result;
+}
+
+AnimationWorkletOutput::AnimationWorkletOutput() = default;
+AnimationWorkletOutput::~AnimationWorkletOutput() = default;
} // namespace cc