1 // Copyright 2019 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
5 #include <string.h>
6
7 #include "base/memory/shared_memory_mapping.h"
8 #include "base/memory/unsafe_shared_memory_region.h"
9 #include "base/optional.h"
10 #include "base/run_loop.h"
11 #include "base/stl_util.h"
12 #include "base/test/bind.h"
13 #include "base/time/time.h"
14 #include "base/timer/elapsed_timer.h"
15 #include "content/public/browser/service_process_host.h"
16 #include "content/public/test/browser_test.h"
17 #include "content/public/test/content_browser_test.h"
18 #include "services/test/echo/public/mojom/echo.mojom.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 namespace content {
22
23 using ServiceProcessHostBrowserTest = ContentBrowserTest;
24
25 class EchoServiceProcessObserver : public ServiceProcessHost::Observer {
26 public:
EchoServiceProcessObserver()27 EchoServiceProcessObserver() { ServiceProcessHost::AddObserver(this); }
28
~EchoServiceProcessObserver()29 ~EchoServiceProcessObserver() override {
30 ServiceProcessHost::RemoveObserver(this);
31 }
32
WaitForLaunch()33 void WaitForLaunch() { launch_loop_.Run(); }
WaitForDeath()34 void WaitForDeath() { death_loop_.Run(); }
WaitForCrash()35 void WaitForCrash() { crash_loop_.Run(); }
36
37 private:
38 // ServiceProcessHost::Observer:
OnServiceProcessLaunched(const ServiceProcessInfo & info)39 void OnServiceProcessLaunched(const ServiceProcessInfo& info) override {
40 if (info.IsService<echo::mojom::EchoService>())
41 launch_loop_.Quit();
42 }
43
OnServiceProcessTerminatedNormally(const ServiceProcessInfo & info)44 void OnServiceProcessTerminatedNormally(
45 const ServiceProcessInfo& info) override {
46 if (info.IsService<echo::mojom::EchoService>())
47 death_loop_.Quit();
48 }
49
OnServiceProcessCrashed(const ServiceProcessInfo & info)50 void OnServiceProcessCrashed(const ServiceProcessInfo& info) override {
51 if (info.IsService<echo::mojom::EchoService>())
52 crash_loop_.Quit();
53 }
54
55 base::RunLoop launch_loop_;
56 base::RunLoop death_loop_;
57 base::RunLoop crash_loop_;
58
59 DISALLOW_COPY_AND_ASSIGN(EchoServiceProcessObserver);
60 };
61
IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest,Launch)62 IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, Launch) {
63 EchoServiceProcessObserver observer;
64 auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>();
65 observer.WaitForLaunch();
66
67 const std::string kTestString =
68 "Aurora borealis! At this time of year? At this time of day? "
69 "In this part of the country? Localized entirely within your kitchen?";
70 base::RunLoop loop;
71 echo_service->EchoString(
72 kTestString,
73 base::BindLambdaForTesting([&](const std::string& echoed_input) {
74 EXPECT_EQ(kTestString, echoed_input);
75 loop.Quit();
76 }));
77 loop.Run();
78 }
79
IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest,LocalDisconnectQuits)80 IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, LocalDisconnectQuits) {
81 EchoServiceProcessObserver observer;
82 auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>();
83 observer.WaitForLaunch();
84 echo_service.reset();
85 observer.WaitForDeath();
86 }
87
IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest,RemoteDisconnectQuits)88 IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, RemoteDisconnectQuits) {
89 EchoServiceProcessObserver observer;
90 auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>();
91 observer.WaitForLaunch();
92 echo_service->Quit();
93 observer.WaitForDeath();
94 }
95
IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest,AllMessagesReceived)96 IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, AllMessagesReceived) {
97 // Verifies that messages sent right before disconnection are always received
98 // and dispatched by the service before it self-terminates.
99 EchoServiceProcessObserver observer;
100 auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>();
101
102 const size_t kBufferSize = 256;
103 const std::string kMessages[] = {
104 "I thought we were having steamed clams.",
105 "D'oh, no! I said steamed hams. That's what I call hamburgers.",
106 "You call hamburgers, \"steamed hams?\"",
107 "Yes. It's a regional dialect."};
108 auto region = base::UnsafeSharedMemoryRegion::Create(kBufferSize);
109 base::WritableSharedMemoryMapping mapping = region.Map();
110 memset(mapping.memory(), 0, kBufferSize);
111
112 // Send several messages, since it helps to verify a lack of raciness between
113 // service-side message dispatch and service termination.
114 for (const auto& message : kMessages) {
115 ASSERT_LE(message.size(), kBufferSize);
116 echo_service->EchoStringToSharedMemory(message, region.Duplicate());
117 }
118 echo_service.reset();
119 observer.WaitForDeath();
120
121 const std::string& kLastMessage = kMessages[base::size(kMessages) - 1];
122 EXPECT_EQ(0,
123 memcmp(mapping.memory(), kLastMessage.data(), kLastMessage.size()));
124 }
125
IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest,ObserveCrash)126 IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, ObserveCrash) {
127 EchoServiceProcessObserver observer;
128 auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>();
129 observer.WaitForLaunch();
130 echo_service->Crash();
131 observer.WaitForCrash();
132 }
133
IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest,IdleTimeout)134 IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, IdleTimeout) {
135 EchoServiceProcessObserver observer;
136 auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>();
137
138 base::RunLoop wait_for_idle_loop;
139 constexpr auto kTimeout = base::TimeDelta::FromSeconds(1);
140 echo_service.set_idle_handler(kTimeout, base::BindLambdaForTesting([&] {
141 wait_for_idle_loop.Quit();
142 echo_service.reset();
143 }));
144
145 // Send a message and wait for the reply. Once the message is sent we should
146 // observe at least |kTimeout| time elapsing before the RunLoop quits, because
147 // the service process must wait at least that long to report itself as idle.
148 base::ElapsedTimer timer;
149 const std::string kTestString =
150 "Yes, and you call them steamed hams despite the fact that they are "
151 "obviously grilled.";
152 echo_service->EchoString(
153 kTestString,
154 base::BindLambdaForTesting([&](const std::string& echoed_input) {
155 EXPECT_EQ(kTestString, echoed_input);
156 }));
157 wait_for_idle_loop.Run();
158 EXPECT_GE(timer.Elapsed(), kTimeout);
159
160 // And since the idle handler resets |echo_service|, we should imminently see
161 // normal service process termination.
162 observer.WaitForDeath();
163 }
164
165 } // namespace content
166