1 // Copyright (c) 2012 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 "chrome/common/service_process_util.h"
6
7 #include <memory>
8
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/files/file_path.h"
12 #include "base/location.h"
13 #include "base/process/kill.h"
14 #include "base/process/launch.h"
15 #include "base/run_loop.h"
16 #include "base/single_thread_task_runner.h"
17 #include "base/strings/string_split.h"
18 #include "base/test/task_environment.h"
19 #include "base/threading/platform_thread.h"
20 #include "base/threading/thread_task_runner_handle.h"
21 #include "build/branding_buildflags.h"
22 #include "build/build_config.h"
23
24 #if !defined(OS_MAC)
25 #include "base/at_exit.h"
26 #include "base/message_loop/message_pump_type.h"
27 #include "base/strings/string_util.h"
28 #include "base/strings/utf_string_conversions.h"
29 #include "base/test/multiprocess_test.h"
30 #include "base/test/test_timeouts.h"
31 #include "base/threading/thread.h"
32 #include "chrome/common/chrome_switches.h"
33 #include "components/version_info/version_info.h"
34 #include "content/public/common/content_switches.h"
35 #include "testing/multiprocess_func_list.h"
36
37 #if defined(OS_WIN)
38 #include "base/win/win_util.h"
39 #endif
40
41 #if defined(OS_POSIX)
42 #include "chrome/common/auto_start_linux.h"
43 #endif
44
45 #if defined(USE_AURA)
46 // This test fails http://crbug.com/84854, and is very flaky on CrOS and
47 // somewhat flaky on other Linux.
48 #define MAYBE_ForceShutdown DISABLED_ForceShutdown
49 #else
50 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_WIN)
51 #define MAYBE_ForceShutdown DISABLED_ForceShutdown
52 #else
53 #define MAYBE_ForceShutdown ForceShutdown
54 #endif
55 #endif
56
57 namespace {
58
59 bool g_good_shutdown = false;
60
ShutdownTask(base::RunLoop * loop)61 void ShutdownTask(base::RunLoop* loop) {
62 // Quit the main message loop.
63 ASSERT_FALSE(g_good_shutdown);
64 g_good_shutdown = true;
65 loop->QuitWhenIdle();
66 }
67
68 } // namespace
69
TEST(ServiceProcessUtilTest,ScopedVersionedName)70 TEST(ServiceProcessUtilTest, ScopedVersionedName) {
71 std::string test_str = "test";
72 std::string scoped_name = GetServiceProcessScopedVersionedName(test_str);
73 EXPECT_TRUE(base::EndsWith(scoped_name, test_str,
74 base::CompareCase::SENSITIVE));
75 EXPECT_NE(std::string::npos,
76 scoped_name.find(version_info::GetVersionNumber()));
77 }
78
79 class ServiceProcessStateTest : public base::MultiProcessTest {
80 public:
81 ServiceProcessStateTest();
82 ~ServiceProcessStateTest() override;
83 void SetUp() override;
IOTaskRunner()84 base::SingleThreadTaskRunner* IOTaskRunner() {
85 return io_thread_.task_runner().get();
86 }
87 void LaunchAndWait(const std::string& name);
88
89 private:
90 // This is used to release the ServiceProcessState singleton after each test.
91 base::ShadowingAtExitManager at_exit_manager_;
92 base::Thread io_thread_;
93 };
94
ServiceProcessStateTest()95 ServiceProcessStateTest::ServiceProcessStateTest()
96 : io_thread_("ServiceProcessStateTestThread") {
97 }
98
~ServiceProcessStateTest()99 ServiceProcessStateTest::~ServiceProcessStateTest() {
100 }
101
SetUp()102 void ServiceProcessStateTest::SetUp() {
103 base::Thread::Options options(base::MessagePumpType::IO, 0);
104 ASSERT_TRUE(io_thread_.StartWithOptions(options));
105 }
106
LaunchAndWait(const std::string & name)107 void ServiceProcessStateTest::LaunchAndWait(const std::string& name) {
108 base::Process process = SpawnChild(name);
109 ASSERT_TRUE(process.IsValid());
110 int exit_code = 0;
111 ASSERT_TRUE(process.WaitForExit(&exit_code));
112 ASSERT_EQ(exit_code, 0);
113 }
114
TEST_F(ServiceProcessStateTest,Singleton)115 TEST_F(ServiceProcessStateTest, Singleton) {
116 ServiceProcessState state;
117 ASSERT_TRUE(state.Initialize());
118 LaunchAndWait("ServiceProcessStateTestSingleton");
119 }
120
121 // http://crbug.com/396390
TEST_F(ServiceProcessStateTest,DISABLED_ReadyState)122 TEST_F(ServiceProcessStateTest, DISABLED_ReadyState) {
123 ASSERT_FALSE(CheckServiceProcessReady());
124 ServiceProcessState state;
125 ASSERT_TRUE(state.Initialize());
126 ASSERT_TRUE(state.SignalReady(IOTaskRunner(), base::OnceClosure()));
127 LaunchAndWait("ServiceProcessStateTestReadyTrue");
128 state.SignalStopped();
129 LaunchAndWait("ServiceProcessStateTestReadyFalse");
130 }
131
TEST_F(ServiceProcessStateTest,AutoRun)132 TEST_F(ServiceProcessStateTest, AutoRun) {
133 ServiceProcessState state;
134 ASSERT_TRUE(state.AddToAutoRun());
135 std::unique_ptr<base::CommandLine> autorun_command_line;
136 #if defined(OS_WIN)
137 std::string value_name = GetServiceProcessScopedName("_service_run");
138 base::string16 value;
139 EXPECT_TRUE(base::win::ReadCommandFromAutoRun(HKEY_CURRENT_USER,
140 base::UTF8ToWide(value_name),
141 &value));
142 autorun_command_line.reset(
143 new base::CommandLine(base::CommandLine::FromString(value)));
144 #elif defined(OS_POSIX) && !defined(OS_MAC)
145 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
146 std::string base_desktop_name = "google-chrome-service.desktop";
147 #else // BUILDFLAG(CHROMIUM_BRANDING)
148 std::string base_desktop_name = "chromium-service.desktop";
149 #endif
150 std::string exec_value;
151 EXPECT_TRUE(AutoStart::GetAutostartFileValue(
152 GetServiceProcessScopedName(base_desktop_name), "Exec", &exec_value));
153
154 // Make sure |exec_value| doesn't contain strings a shell would
155 // treat specially.
156 ASSERT_EQ(std::string::npos, exec_value.find('#'));
157 ASSERT_EQ(std::string::npos, exec_value.find('\n'));
158 ASSERT_EQ(std::string::npos, exec_value.find('"'));
159 ASSERT_EQ(std::string::npos, exec_value.find('\''));
160
161 base::CommandLine::StringVector argv = base::SplitString(
162 exec_value, base::CommandLine::StringType(1, ' '),
163 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
164 ASSERT_GE(argv.size(), 2U)
165 << "Expected at least one command-line option in: " << exec_value;
166 autorun_command_line.reset(new base::CommandLine(argv));
167 #endif // defined(OS_WIN)
168 if (autorun_command_line.get()) {
169 EXPECT_EQ(autorun_command_line->GetSwitchValueASCII(switches::kProcessType),
170 std::string(switches::kCloudPrintServiceProcess));
171 }
172 ASSERT_TRUE(state.RemoveFromAutoRun());
173 #if defined(OS_WIN)
174 EXPECT_FALSE(base::win::ReadCommandFromAutoRun(HKEY_CURRENT_USER,
175 base::UTF8ToWide(value_name),
176 &value));
177 #elif defined(OS_POSIX) && !defined(OS_MAC)
178 EXPECT_FALSE(AutoStart::GetAutostartFileValue(
179 GetServiceProcessScopedName(base_desktop_name), "Exec", &exec_value));
180 #endif // defined(OS_WIN)
181 }
182
TEST_F(ServiceProcessStateTest,SharedMem)183 TEST_F(ServiceProcessStateTest, SharedMem) {
184 std::string version;
185 base::ProcessId pid;
186 #if defined(OS_POSIX)
187 // On Posix, named shared memory uses a file on disk. This file could be lying
188 // around from previous crashes which could cause GetServiceProcessPid to lie,
189 // so we aggressively delete it before testing. On Windows, we use a named
190 // event so we don't have this issue.
191 ServiceProcessState::DeleteServiceProcessDataRegion();
192 #endif // defined(OS_POSIX)
193 ASSERT_FALSE(ServiceProcessState::GetServiceProcessData(&version, &pid));
194 ServiceProcessState state;
195 ASSERT_TRUE(state.Initialize());
196 ASSERT_TRUE(ServiceProcessState::GetServiceProcessData(&version, &pid));
197 ASSERT_EQ(base::GetCurrentProcId(), pid);
198 }
199
TEST_F(ServiceProcessStateTest,MAYBE_ForceShutdown)200 TEST_F(ServiceProcessStateTest, MAYBE_ForceShutdown) {
201 base::Process process = SpawnChild("ServiceProcessStateTestShutdown");
202 ASSERT_TRUE(process.IsValid());
203 for (int i = 0; !CheckServiceProcessReady() && i < 10; ++i) {
204 base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
205 }
206 ASSERT_TRUE(CheckServiceProcessReady());
207 std::string version;
208 base::ProcessId pid;
209 ASSERT_TRUE(ServiceProcessState::GetServiceProcessData(&version, &pid));
210 ASSERT_TRUE(ForceServiceProcessShutdown(version, pid));
211 int exit_code = 0;
212 ASSERT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(),
213 &exit_code));
214 ASSERT_EQ(exit_code, 0);
215 }
216
MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestSingleton)217 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestSingleton) {
218 ServiceProcessState state;
219 EXPECT_FALSE(state.Initialize());
220 return 0;
221 }
222
MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestReadyTrue)223 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestReadyTrue) {
224 EXPECT_TRUE(CheckServiceProcessReady());
225 return 0;
226 }
227
MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestReadyFalse)228 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestReadyFalse) {
229 EXPECT_FALSE(CheckServiceProcessReady());
230 return 0;
231 }
232
MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestShutdown)233 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestShutdown) {
234 base::PlatformThread::SetName("ServiceProcessStateTestShutdownMainThread");
235 base::test::SingleThreadTaskEnvironment task_environment;
236 base::RunLoop run_loop;
237 base::Thread io_thread_("ServiceProcessStateTestShutdownIOThread");
238 base::Thread::Options options(base::MessagePumpType::IO, 0);
239 EXPECT_TRUE(io_thread_.StartWithOptions(options));
240 ServiceProcessState state;
241 EXPECT_TRUE(state.Initialize());
242 EXPECT_TRUE(state.SignalReady(io_thread_.task_runner().get(),
243 base::BindOnce(&ShutdownTask, &run_loop)));
244 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
245 FROM_HERE, run_loop.QuitWhenIdleClosure(),
246 TestTimeouts::action_max_timeout());
247 EXPECT_FALSE(g_good_shutdown);
248 run_loop.Run();
249 EXPECT_TRUE(g_good_shutdown);
250 return 0;
251 }
252
253 #endif // !OS_MAC
254