host_frame_sink_manager_unittest.cc 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/viz/host/host_frame_sink_manager.h"
  5. #include <memory>
  6. #include <utility>
  7. #include "base/run_loop.h"
  8. #include "components/viz/common/display/renderer_settings.h"
  9. #include "components/viz/common/surfaces/frame_sink_id.h"
  10. #include "components/viz/common/surfaces/surface_id.h"
  11. #include "components/viz/common/surfaces/surface_info.h"
  12. #include "components/viz/test/compositor_frame_helpers.h"
  13. #include "components/viz/test/fake_host_frame_sink_client.h"
  14. #include "components/viz/test/fake_surface_observer.h"
  15. #include "components/viz/test/mock_compositor_frame_sink_client.h"
  16. #include "components/viz/test/mock_display_client.h"
  17. #include "components/viz/test/test_frame_sink_manager.h"
  18. #include "mojo/public/cpp/bindings/associated_remote.h"
  19. #include "mojo/public/cpp/bindings/pending_receiver.h"
  20. #include "mojo/public/cpp/bindings/pending_remote.h"
  21. #include "mojo/public/cpp/bindings/remote.h"
  22. #include "services/viz/privileged/mojom/compositing/frame_sink_manager.mojom.h"
  23. #include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom.h"
  24. #include "testing/gmock/include/gmock/gmock.h"
  25. #include "testing/gtest/include/gtest/gtest.h"
  26. using testing::_;
  27. namespace viz {
  28. namespace {
  29. constexpr FrameSinkId kFrameSinkParent1(1, 1);
  30. constexpr FrameSinkId kFrameSinkParent2(2, 1);
  31. constexpr FrameSinkId kFrameSinkChild1(3, 1);
  32. // Holds the four interface objects needed to create a RootCompositorFrameSink.
  33. struct RootCompositorFrameSinkData {
  34. mojom::RootCompositorFrameSinkParamsPtr BuildParams(
  35. const FrameSinkId& frame_sink_id) {
  36. auto params = mojom::RootCompositorFrameSinkParams::New();
  37. params->gpu_compositing = false;
  38. params->frame_sink_id = frame_sink_id;
  39. params->widget = gpu::kNullSurfaceHandle;
  40. params->compositor_frame_sink =
  41. compositor_frame_sink.BindNewEndpointAndPassReceiver();
  42. params->compositor_frame_sink_client =
  43. compositor_frame_sink_client.BindInterfaceRemote();
  44. params->display_private = display_private.BindNewEndpointAndPassReceiver();
  45. params->display_client = display_client.BindRemote();
  46. return params;
  47. }
  48. mojo::AssociatedRemote<mojom::CompositorFrameSink> compositor_frame_sink;
  49. MockCompositorFrameSinkClient compositor_frame_sink_client;
  50. mojo::AssociatedRemote<mojom::DisplayPrivate> display_private;
  51. MockDisplayClient display_client;
  52. };
  53. // A mock implementation of mojom::FrameSinkManager.
  54. class MockFrameSinkManagerImpl : public TestFrameSinkManagerImpl {
  55. public:
  56. MockFrameSinkManagerImpl() = default;
  57. ~MockFrameSinkManagerImpl() override = default;
  58. // mojom::FrameSinkManager:
  59. MOCK_METHOD2(RegisterFrameSinkId,
  60. void(const FrameSinkId& frame_sink_id, bool report_activation));
  61. MOCK_METHOD1(InvalidateFrameSinkId, void(const FrameSinkId& frame_sink_id));
  62. MOCK_METHOD2(SetFrameSinkDebugLabel,
  63. void(const FrameSinkId& frame_sink_id,
  64. const std::string& debug_label));
  65. MOCK_METHOD4(CreateCompositorFrameSink,
  66. void(const FrameSinkId&,
  67. const absl::optional<FrameSinkBundleId>&,
  68. mojo::PendingReceiver<mojom::CompositorFrameSink>,
  69. mojo::PendingRemote<mojom::CompositorFrameSinkClient>));
  70. void CreateRootCompositorFrameSink(
  71. mojom::RootCompositorFrameSinkParamsPtr params) override {
  72. MockCreateRootCompositorFrameSink(params->frame_sink_id);
  73. }
  74. MOCK_METHOD1(MockCreateRootCompositorFrameSink,
  75. void(const FrameSinkId& frame_sink_id));
  76. void DestroyCompositorFrameSink(
  77. const FrameSinkId& frame_sink_id,
  78. DestroyCompositorFrameSinkCallback callback) override {
  79. MockDestroyCompositorFrameSink(frame_sink_id);
  80. std::move(callback).Run();
  81. }
  82. MOCK_METHOD1(MockDestroyCompositorFrameSink,
  83. void(const FrameSinkId& frame_sink_id));
  84. MOCK_METHOD2(RegisterFrameSinkHierarchy,
  85. void(const FrameSinkId& parent, const FrameSinkId& child));
  86. MOCK_METHOD2(UnregisterFrameSinkHierarchy,
  87. void(const FrameSinkId& parent, const FrameSinkId& child));
  88. MOCK_METHOD(void,
  89. Throttle,
  90. (const std::vector<FrameSinkId>& ids, base::TimeDelta interval),
  91. (override));
  92. };
  93. } // namespace
  94. class HostFrameSinkManagerTest : public testing::Test {
  95. public:
  96. HostFrameSinkManagerTest() { ConnectToGpu(); }
  97. HostFrameSinkManagerTest(const HostFrameSinkManagerTest&) = delete;
  98. HostFrameSinkManagerTest& operator=(const HostFrameSinkManagerTest&) = delete;
  99. ~HostFrameSinkManagerTest() override = default;
  100. HostFrameSinkManager& host() { return host_manager_; }
  101. MockFrameSinkManagerImpl& impl() { return *manager_impl_; }
  102. mojom::FrameSinkManagerClient* GetFrameSinkManagerClient() {
  103. return static_cast<mojom::FrameSinkManagerClient*>(&host_manager_);
  104. }
  105. bool FrameSinkDataExists(const FrameSinkId& frame_sink_id) const {
  106. return host_manager_.frame_sink_data_map_.count(frame_sink_id) > 0;
  107. }
  108. bool IsBoundToFrameSinkManager() {
  109. return host_manager_.frame_sink_manager_remote_.is_bound() ||
  110. host_manager_.receiver_.is_bound();
  111. }
  112. bool DisplayHitTestQueryExists(const FrameSinkId& frame_sink_id) {
  113. return host_manager_.display_hit_test_query_.count(frame_sink_id) > 0;
  114. }
  115. void FlushHostAndVerifyExpectations() {
  116. host_manager_.frame_sink_manager_remote_.FlushForTesting();
  117. testing::Mock::VerifyAndClearExpectations(&impl());
  118. }
  119. // Destroys FrameSinkManagerImpl which kills the message pipes.
  120. void KillGpu() { manager_impl_.reset(); }
  121. // Connects HostFrameSinkManager to FrameSinkManagerImpl using Mojo.
  122. void ConnectToGpu() {
  123. DCHECK(!manager_impl_);
  124. manager_impl_ =
  125. std::make_unique<testing::NiceMock<MockFrameSinkManagerImpl>>();
  126. mojo::PendingRemote<mojom::FrameSinkManager> frame_sink_manager;
  127. mojo::PendingReceiver<mojom::FrameSinkManager> frame_sink_manager_receiver =
  128. frame_sink_manager.InitWithNewPipeAndPassReceiver();
  129. mojo::PendingRemote<mojom::FrameSinkManagerClient>
  130. frame_sink_manager_client;
  131. mojo::PendingReceiver<mojom::FrameSinkManagerClient>
  132. frame_sink_manager_client_receiver =
  133. frame_sink_manager_client.InitWithNewPipeAndPassReceiver();
  134. host_manager_.BindAndSetManager(
  135. std::move(frame_sink_manager_client_receiver), nullptr,
  136. std::move(frame_sink_manager));
  137. manager_impl_->BindReceiver(std::move(frame_sink_manager_receiver),
  138. std::move(frame_sink_manager_client));
  139. }
  140. protected:
  141. HostFrameSinkManager host_manager_;
  142. std::unique_ptr<testing::NiceMock<MockFrameSinkManagerImpl>> manager_impl_;
  143. };
  144. // Verify that registering and destroying multiple CompositorFrameSinks works
  145. // correctly when one of the CompositorFrameSinks hasn't been created.
  146. TEST_F(HostFrameSinkManagerTest, CreateCompositorFrameSinks) {
  147. FakeHostFrameSinkClient host_client;
  148. // Register then create CompositorFrameSink for child.
  149. EXPECT_CALL(impl(), RegisterFrameSinkId(kFrameSinkChild1,
  150. true /* report_activation */));
  151. host().RegisterFrameSinkId(kFrameSinkChild1, &host_client,
  152. ReportFirstSurfaceActivation::kYes);
  153. EXPECT_TRUE(FrameSinkDataExists(kFrameSinkChild1));
  154. MockCompositorFrameSinkClient compositor_frame_sink_client;
  155. mojo::Remote<mojom::CompositorFrameSink> compositor_frame_sink;
  156. EXPECT_CALL(impl(), CreateCompositorFrameSink(kFrameSinkChild1, _, _, _));
  157. host().CreateCompositorFrameSink(
  158. kFrameSinkChild1, compositor_frame_sink.BindNewPipeAndPassReceiver(),
  159. compositor_frame_sink_client.BindInterfaceRemote());
  160. FlushHostAndVerifyExpectations();
  161. // Register but don't actually create CompositorFrameSink for parent.
  162. host().RegisterFrameSinkId(kFrameSinkParent1, &host_client,
  163. ReportFirstSurfaceActivation::kYes);
  164. // Register should call through to FrameSinkManagerImpl and should work even
  165. // though |kFrameSinkParent1| was not created yet.
  166. EXPECT_CALL(impl(),
  167. RegisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1));
  168. host().RegisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1);
  169. // Destroy the CompositorFrameSink.
  170. EXPECT_CALL(impl(), InvalidateFrameSinkId(kFrameSinkChild1));
  171. host().InvalidateFrameSinkId(kFrameSinkChild1);
  172. FlushHostAndVerifyExpectations();
  173. // Unregister should work after the CompositorFrameSink is destroyed.
  174. EXPECT_CALL(impl(), UnregisterFrameSinkHierarchy(kFrameSinkParent1,
  175. kFrameSinkChild1));
  176. host().UnregisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1);
  177. FlushHostAndVerifyExpectations();
  178. // Data for |kFrameSinkChild1| should be deleted now.
  179. EXPECT_FALSE(FrameSinkDataExists(kFrameSinkChild1));
  180. }
  181. // Verify that that creating two RootCompositorFrameSinks works.
  182. TEST_F(HostFrameSinkManagerTest, CreateRootCompositorFrameSinks) {
  183. FakeHostFrameSinkClient host_client;
  184. host().RegisterFrameSinkId(kFrameSinkChild1, &host_client,
  185. ReportFirstSurfaceActivation::kYes);
  186. RootCompositorFrameSinkData root_data1;
  187. host().CreateRootCompositorFrameSink(
  188. root_data1.BuildParams(kFrameSinkChild1));
  189. EXPECT_TRUE(FrameSinkDataExists(kFrameSinkChild1));
  190. host().RegisterFrameSinkId(kFrameSinkParent1, &host_client,
  191. ReportFirstSurfaceActivation::kYes);
  192. RootCompositorFrameSinkData root_data2;
  193. host().CreateRootCompositorFrameSink(
  194. root_data2.BuildParams(kFrameSinkParent1));
  195. EXPECT_TRUE(FrameSinkDataExists(kFrameSinkParent1));
  196. // Verify that registering and unregistering frame sink hierarchy works.
  197. EXPECT_CALL(impl(),
  198. RegisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1));
  199. host().RegisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1);
  200. EXPECT_CALL(impl(), UnregisterFrameSinkHierarchy(kFrameSinkParent1,
  201. kFrameSinkChild1));
  202. host().UnregisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1);
  203. FlushHostAndVerifyExpectations();
  204. // We should still have the CompositorFrameSink data for |kFrameSinkChild1|.
  205. EXPECT_TRUE(FrameSinkDataExists(kFrameSinkChild1));
  206. // Data for |kFrameSinkChild1| should be deleted when everything is destroyed.
  207. EXPECT_CALL(impl(), InvalidateFrameSinkId(kFrameSinkChild1));
  208. host().InvalidateFrameSinkId(kFrameSinkChild1);
  209. EXPECT_FALSE(FrameSinkDataExists(kFrameSinkChild1));
  210. // Data for |kFrameSinkParent1| should be deleted when everything is
  211. // destroyed.
  212. EXPECT_CALL(impl(), InvalidateFrameSinkId(kFrameSinkParent1));
  213. host().InvalidateFrameSinkId(kFrameSinkParent1);
  214. EXPECT_FALSE(FrameSinkDataExists(kFrameSinkParent1));
  215. FlushHostAndVerifyExpectations();
  216. }
  217. // Verify that multiple parents in the frame sink hierarchy works.
  218. TEST_F(HostFrameSinkManagerTest, HierarchyMultipleParents) {
  219. FakeHostFrameSinkClient host_client;
  220. // Register two parent and child CompositorFrameSink.
  221. const FrameSinkId& id_parent1 = kFrameSinkParent1;
  222. host().RegisterFrameSinkId(id_parent1, &host_client,
  223. ReportFirstSurfaceActivation::kYes);
  224. RootCompositorFrameSinkData root_data1;
  225. host().CreateRootCompositorFrameSink(root_data1.BuildParams(id_parent1));
  226. const FrameSinkId& id_parent2 = kFrameSinkChild1;
  227. host().RegisterFrameSinkId(id_parent2, &host_client,
  228. ReportFirstSurfaceActivation::kYes);
  229. RootCompositorFrameSinkData root_data2;
  230. host().CreateRootCompositorFrameSink(root_data2.BuildParams(id_parent2));
  231. const FrameSinkId& id_child = kFrameSinkParent2;
  232. host().RegisterFrameSinkId(id_child, &host_client,
  233. ReportFirstSurfaceActivation::kYes);
  234. MockCompositorFrameSinkClient compositor_frame_sink_client;
  235. mojo::Remote<mojom::CompositorFrameSink> compositor_frame_sink;
  236. host().CreateCompositorFrameSink(
  237. id_child, compositor_frame_sink.BindNewPipeAndPassReceiver(),
  238. compositor_frame_sink_client.BindInterfaceRemote());
  239. // Register |id_parent1| in hierarchy first, this is the original window
  240. // embedding.
  241. EXPECT_CALL(impl(), RegisterFrameSinkHierarchy(id_parent1, id_child));
  242. host().RegisterFrameSinkHierarchy(id_parent1, id_child);
  243. // Register |id_parent2| in hierarchy second, this is a second embedding for
  244. // something like alt-tab on a different monitor.
  245. EXPECT_CALL(impl(), RegisterFrameSinkHierarchy(id_parent2, id_child));
  246. host().RegisterFrameSinkHierarchy(id_parent2, id_child);
  247. FlushHostAndVerifyExpectations();
  248. // Unregistering hierarchy with multiple parents should also work.
  249. EXPECT_CALL(impl(), UnregisterFrameSinkHierarchy(id_parent2, id_child));
  250. host().UnregisterFrameSinkHierarchy(id_parent2, id_child);
  251. EXPECT_CALL(impl(), UnregisterFrameSinkHierarchy(id_parent1, id_child));
  252. host().UnregisterFrameSinkHierarchy(id_parent1, id_child);
  253. FlushHostAndVerifyExpectations();
  254. }
  255. // Verify that HostFrameSinkManager can handle restarting after a GPU crash.
  256. TEST_F(HostFrameSinkManagerTest, RestartOnGpuCrash) {
  257. FakeHostFrameSinkClient host_client;
  258. // Register two FrameSinkIds, hierarchy between them and create a
  259. // CompositorFrameSink for one.
  260. EXPECT_CALL(impl(), RegisterFrameSinkId(kFrameSinkParent1,
  261. true /* report_activation */));
  262. host().RegisterFrameSinkId(kFrameSinkParent1, &host_client,
  263. ReportFirstSurfaceActivation::kYes);
  264. EXPECT_CALL(impl(), RegisterFrameSinkId(kFrameSinkChild1,
  265. true /* report_activation */));
  266. host().RegisterFrameSinkId(kFrameSinkChild1, &host_client,
  267. ReportFirstSurfaceActivation::kYes);
  268. EXPECT_CALL(impl(),
  269. RegisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1));
  270. host().RegisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1);
  271. RootCompositorFrameSinkData root_data;
  272. EXPECT_CALL(impl(), MockCreateRootCompositorFrameSink(kFrameSinkParent1));
  273. host().CreateRootCompositorFrameSink(
  274. root_data.BuildParams(kFrameSinkParent1));
  275. MockCompositorFrameSinkClient compositor_frame_sink_client;
  276. mojo::Remote<mojom::CompositorFrameSink> compositor_frame_sink;
  277. EXPECT_CALL(impl(), CreateCompositorFrameSink(kFrameSinkChild1, _, _, _));
  278. host().CreateCompositorFrameSink(
  279. kFrameSinkChild1, compositor_frame_sink.BindNewPipeAndPassReceiver(),
  280. compositor_frame_sink_client.BindInterfaceRemote());
  281. EXPECT_TRUE(IsBoundToFrameSinkManager());
  282. // Verify registration and CompositorFrameSink creation happened.
  283. FlushHostAndVerifyExpectations();
  284. // Kill the GPU. HostFrameSinkManager will have a connection error on the
  285. // message pipe and should clear state appropriately.
  286. KillGpu();
  287. {
  288. base::RunLoop run_loop;
  289. host().SetConnectionLostCallback(run_loop.QuitClosure());
  290. run_loop.Run();
  291. }
  292. EXPECT_FALSE(IsBoundToFrameSinkManager());
  293. // Verify that when HostFrameSinkManager is connected to the GPU again it
  294. // reregisters FrameSinkIds and FrameSink hierarchy.
  295. ConnectToGpu();
  296. EXPECT_CALL(impl(), RegisterFrameSinkId(kFrameSinkParent1,
  297. true /* report_activation */));
  298. EXPECT_CALL(impl(), RegisterFrameSinkId(kFrameSinkChild1,
  299. true /* report_activation */));
  300. EXPECT_CALL(impl(),
  301. RegisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1));
  302. FlushHostAndVerifyExpectations();
  303. EXPECT_TRUE(IsBoundToFrameSinkManager());
  304. }
  305. // Verify that HostFrameSinkManager does early return when trying to send
  306. // hit-test data after HitTestQuery was deleted.
  307. TEST_F(HostFrameSinkManagerTest, DeletedHitTestQuery) {
  308. FakeHostFrameSinkClient host_client;
  309. // Register a FrameSinkId, and create a RootCompositorFrameSink, which should
  310. // create a HitTestQuery.
  311. host().RegisterFrameSinkId(kFrameSinkParent1, &host_client,
  312. ReportFirstSurfaceActivation::kYes);
  313. RootCompositorFrameSinkData root_data;
  314. EXPECT_CALL(impl(), MockCreateRootCompositorFrameSink(kFrameSinkParent1));
  315. host().CreateRootCompositorFrameSink(
  316. root_data.BuildParams(kFrameSinkParent1));
  317. EXPECT_TRUE(DisplayHitTestQueryExists(kFrameSinkParent1));
  318. // Verify RootCompositorFrameSink was created on other end of message pipe.
  319. FlushHostAndVerifyExpectations();
  320. GetFrameSinkManagerClient()->OnAggregatedHitTestRegionListUpdated(
  321. kFrameSinkParent1, {});
  322. // Continue to send hit-test data to HitTestQuery associated with
  323. // kFrameSinkChild1.
  324. host().InvalidateFrameSinkId(kFrameSinkParent1);
  325. // Invalidating kFrameSinkChild1 would delete the corresponding HitTestQuery,
  326. // so further msgs to that HitTestQuery should be dropped.
  327. EXPECT_FALSE(DisplayHitTestQueryExists(kFrameSinkParent1));
  328. GetFrameSinkManagerClient()->OnAggregatedHitTestRegionListUpdated(
  329. kFrameSinkParent1, {});
  330. }
  331. // Verify that on lost context a RootCompositorFrameSink can be recreated.
  332. TEST_F(HostFrameSinkManagerTest, ContextLossRecreateRoot) {
  333. FakeHostFrameSinkClient host_client;
  334. // Register a FrameSinkId, and create a RootCompositorFrameSink.
  335. host().RegisterFrameSinkId(kFrameSinkParent1, &host_client,
  336. ReportFirstSurfaceActivation::kYes);
  337. RootCompositorFrameSinkData root_data1;
  338. host().CreateRootCompositorFrameSink(
  339. root_data1.BuildParams(kFrameSinkParent1));
  340. // Verify RootCompositorFrameSink was created on other end of message pipe.
  341. EXPECT_CALL(impl(), MockCreateRootCompositorFrameSink(kFrameSinkParent1));
  342. FlushHostAndVerifyExpectations();
  343. // Create a new RootCompositorFrameSink and try to connect it with the same
  344. // FrameSinkId. This will happen if the browser GL context is lost.
  345. RootCompositorFrameSinkData root_data2;
  346. host().CreateRootCompositorFrameSink(
  347. root_data2.BuildParams(kFrameSinkParent1));
  348. // Verify RootCompositorFrameSink is destroyed and then recreated.
  349. EXPECT_CALL(impl(), MockDestroyCompositorFrameSink(kFrameSinkParent1));
  350. EXPECT_CALL(impl(), MockCreateRootCompositorFrameSink(kFrameSinkParent1));
  351. FlushHostAndVerifyExpectations();
  352. }
  353. // Verify that on lost context a CompositorFrameSink can be recreated.
  354. TEST_F(HostFrameSinkManagerTest, ContextLossRecreateNonRoot) {
  355. FakeHostFrameSinkClient host_client;
  356. // Register a FrameSinkId and create a CompositorFrameSink.
  357. host().RegisterFrameSinkId(kFrameSinkChild1, &host_client,
  358. ReportFirstSurfaceActivation::kYes);
  359. MockCompositorFrameSinkClient compositor_frame_sink_client1;
  360. mojo::Remote<mojom::CompositorFrameSink> compositor_frame_sink1;
  361. host().CreateCompositorFrameSink(
  362. kFrameSinkChild1, compositor_frame_sink1.BindNewPipeAndPassReceiver(),
  363. compositor_frame_sink_client1.BindInterfaceRemote());
  364. // Verify CompositorFrameSink was created on other end of message pipe.
  365. EXPECT_CALL(impl(), CreateCompositorFrameSink(kFrameSinkChild1, _, _, _));
  366. FlushHostAndVerifyExpectations();
  367. // Create a new CompositorFrameSink and try to connect it with the same
  368. // FrameSinkId. This will happen if the client GL context is lost.
  369. MockCompositorFrameSinkClient compositor_frame_sink_client2;
  370. mojo::Remote<mojom::CompositorFrameSink> compositor_frame_sink2;
  371. host().CreateCompositorFrameSink(
  372. kFrameSinkChild1, compositor_frame_sink2.BindNewPipeAndPassReceiver(),
  373. compositor_frame_sink_client2.BindInterfaceRemote());
  374. // Verify CompositorFrameSink is destroyed and then recreated.
  375. EXPECT_CALL(impl(), MockDestroyCompositorFrameSink(kFrameSinkChild1));
  376. EXPECT_CALL(impl(), CreateCompositorFrameSink(kFrameSinkChild1, _, _, _));
  377. FlushHostAndVerifyExpectations();
  378. }
  379. TEST_F(HostFrameSinkManagerTest, ThrottleFramePainting) {
  380. const std::vector<FrameSinkId> frame_sink_ids{
  381. FrameSinkId(1, 1), FrameSinkId(2, 2), FrameSinkId(3, 3)};
  382. constexpr base::TimeDelta interval = base::Hertz(10);
  383. EXPECT_CALL(impl(), Throttle(frame_sink_ids, interval));
  384. host().Throttle(frame_sink_ids, interval);
  385. FlushHostAndVerifyExpectations();
  386. }
  387. } // namespace viz