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