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.
5 #include "chrome/common/service_process_util.h"
7 #include "base/basictypes.h"
9 #include "base/command_line.h"
10 #include "base/files/file_path.h"
11 #include "base/location.h"
12 #include "base/process/kill.h"
13 #include "base/process/launch.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/strings/string_split.h"
17 #if !defined(OS_MACOSX)
18 #include "base/at_exit.h"
19 #include "base/memory/scoped_ptr.h"
20 #include "base/strings/string_util.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "base/test/multiprocess_test.h"
23 #include "base/test/test_timeouts.h"
24 #include "base/threading/thread.h"
25 #include "chrome/common/chrome_switches.h"
26 #include "chrome/common/chrome_version_info.h"
27 #include "testing/multiprocess_func_list.h"
30 #include "base/win/win_util.h"
34 #include "chrome/common/auto_start_linux.h"
38 // This test fails http://crbug.com/84854, and is very flaky on CrOS and
39 // somewhat flaky on other Linux.
40 #define MAYBE_ForceShutdown DISABLED_ForceShutdown
42 #if defined(OS_LINUX) || defined(OS_WIN)
43 #define MAYBE_ForceShutdown DISABLED_ForceShutdown
45 #define MAYBE_ForceShutdown ForceShutdown
51 bool g_good_shutdown
= false;
53 void ShutdownTask(base::MessageLoop
* loop
) {
54 // Quit the main message loop.
55 ASSERT_FALSE(g_good_shutdown
);
56 g_good_shutdown
= true;
57 loop
->task_runner()->PostTask(FROM_HERE
, base::MessageLoop::QuitClosure());
62 TEST(ServiceProcessUtilTest
, ScopedVersionedName
) {
63 std::string test_str
= "test";
64 std::string scoped_name
= GetServiceProcessScopedVersionedName(test_str
);
65 chrome::VersionInfo version_info
;
66 EXPECT_TRUE(EndsWith(scoped_name
, test_str
, true));
67 EXPECT_NE(std::string::npos
, scoped_name
.find(version_info
.Version()));
70 class ServiceProcessStateTest
: public base::MultiProcessTest
{
72 ServiceProcessStateTest();
73 ~ServiceProcessStateTest() override
;
74 void SetUp() override
;
75 base::SingleThreadTaskRunner
* IOMessageLoopProxy() {
76 return io_thread_
.task_runner().get();
78 void LaunchAndWait(const std::string
& name
);
81 // This is used to release the ServiceProcessState singleton after each test.
82 base::ShadowingAtExitManager at_exit_manager_
;
83 base::Thread io_thread_
;
86 ServiceProcessStateTest::ServiceProcessStateTest()
87 : io_thread_("ServiceProcessStateTestThread") {
90 ServiceProcessStateTest::~ServiceProcessStateTest() {
93 void ServiceProcessStateTest::SetUp() {
94 base::Thread::Options
options(base::MessageLoop::TYPE_IO
, 0);
95 ASSERT_TRUE(io_thread_
.StartWithOptions(options
));
98 void ServiceProcessStateTest::LaunchAndWait(const std::string
& name
) {
99 base::Process process
= SpawnChild(name
);
100 ASSERT_TRUE(process
.IsValid());
102 ASSERT_TRUE(process
.WaitForExit(&exit_code
));
103 ASSERT_EQ(exit_code
, 0);
106 TEST_F(ServiceProcessStateTest
, Singleton
) {
107 ServiceProcessState state
;
108 ASSERT_TRUE(state
.Initialize());
109 LaunchAndWait("ServiceProcessStateTestSingleton");
112 // http://crbug.com/396390
113 TEST_F(ServiceProcessStateTest
, DISABLED_ReadyState
) {
114 ASSERT_FALSE(CheckServiceProcessReady());
115 ServiceProcessState state
;
116 ASSERT_TRUE(state
.Initialize());
117 ASSERT_TRUE(state
.SignalReady(IOMessageLoopProxy(), base::Closure()));
118 LaunchAndWait("ServiceProcessStateTestReadyTrue");
119 state
.SignalStopped();
120 LaunchAndWait("ServiceProcessStateTestReadyFalse");
123 TEST_F(ServiceProcessStateTest
, AutoRun
) {
124 ServiceProcessState state
;
125 ASSERT_TRUE(state
.AddToAutoRun());
126 scoped_ptr
<base::CommandLine
> autorun_command_line
;
128 std::string value_name
= GetServiceProcessScopedName("_service_run");
129 base::string16 value
;
130 EXPECT_TRUE(base::win::ReadCommandFromAutoRun(HKEY_CURRENT_USER
,
131 base::UTF8ToWide(value_name
),
133 autorun_command_line
.reset(
134 new base::CommandLine(base::CommandLine::FromString(value
)));
135 #elif defined(OS_POSIX) && !defined(OS_MACOSX)
136 #if defined(GOOGLE_CHROME_BUILD)
137 std::string base_desktop_name
= "google-chrome-service.desktop";
138 #else // CHROMIUM_BUILD
139 std::string base_desktop_name
= "chromium-service.desktop";
141 std::string exec_value
;
142 EXPECT_TRUE(AutoStart::GetAutostartFileValue(
143 GetServiceProcessScopedName(base_desktop_name
), "Exec", &exec_value
));
145 // Make sure |exec_value| doesn't contain strings a shell would
147 ASSERT_EQ(std::string::npos
, exec_value
.find('#'));
148 ASSERT_EQ(std::string::npos
, exec_value
.find('\n'));
149 ASSERT_EQ(std::string::npos
, exec_value
.find('"'));
150 ASSERT_EQ(std::string::npos
, exec_value
.find('\''));
152 base::CommandLine::StringVector argv
;
153 base::SplitString(exec_value
, ' ', &argv
);
154 ASSERT_GE(argv
.size(), 2U)
155 << "Expected at least one command-line option in: " << exec_value
;
156 autorun_command_line
.reset(new base::CommandLine(argv
));
157 #endif // defined(OS_WIN)
158 if (autorun_command_line
.get()) {
159 EXPECT_EQ(autorun_command_line
->GetSwitchValueASCII(switches::kProcessType
),
160 std::string(switches::kServiceProcess
));
162 ASSERT_TRUE(state
.RemoveFromAutoRun());
164 EXPECT_FALSE(base::win::ReadCommandFromAutoRun(HKEY_CURRENT_USER
,
165 base::UTF8ToWide(value_name
),
167 #elif defined(OS_POSIX) && !defined(OS_MACOSX)
168 EXPECT_FALSE(AutoStart::GetAutostartFileValue(
169 GetServiceProcessScopedName(base_desktop_name
), "Exec", &exec_value
));
170 #endif // defined(OS_WIN)
173 // http://crbug.com/396390
174 TEST_F(ServiceProcessStateTest
, DISABLED_SharedMem
) {
178 // On Posix, named shared memory uses a file on disk. This file
179 // could be lying around from previous crashes which could cause
180 // GetServiceProcessPid to lie. On Windows, we use a named event so we
181 // don't have this issue. Until we have a more stable shared memory
182 // implementation on Posix, this check will only execute on Windows.
183 ASSERT_FALSE(GetServiceProcessData(&version
, &pid
));
184 #endif // defined(OS_WIN)
185 ServiceProcessState state
;
186 ASSERT_TRUE(state
.Initialize());
187 ASSERT_TRUE(GetServiceProcessData(&version
, &pid
));
188 ASSERT_EQ(base::GetCurrentProcId(), pid
);
191 TEST_F(ServiceProcessStateTest
, MAYBE_ForceShutdown
) {
192 base::Process process
= SpawnChild("ServiceProcessStateTestShutdown");
193 ASSERT_TRUE(process
.IsValid());
194 for (int i
= 0; !CheckServiceProcessReady() && i
< 10; ++i
) {
195 base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
197 ASSERT_TRUE(CheckServiceProcessReady());
200 ASSERT_TRUE(GetServiceProcessData(&version
, &pid
));
201 ASSERT_TRUE(ForceServiceProcessShutdown(version
, pid
));
203 ASSERT_TRUE(process
.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(),
205 ASSERT_EQ(exit_code
, 0);
208 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestSingleton
) {
209 ServiceProcessState state
;
210 EXPECT_FALSE(state
.Initialize());
214 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestReadyTrue
) {
215 EXPECT_TRUE(CheckServiceProcessReady());
219 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestReadyFalse
) {
220 EXPECT_FALSE(CheckServiceProcessReady());
224 MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestShutdown
) {
225 base::MessageLoop message_loop
;
226 message_loop
.set_thread_name("ServiceProcessStateTestShutdownMainThread");
227 base::Thread
io_thread_("ServiceProcessStateTestShutdownIOThread");
228 base::Thread::Options
options(base::MessageLoop::TYPE_IO
, 0);
229 EXPECT_TRUE(io_thread_
.StartWithOptions(options
));
230 ServiceProcessState state
;
231 EXPECT_TRUE(state
.Initialize());
232 EXPECT_TRUE(state
.SignalReady(
233 io_thread_
.task_runner().get(),
234 base::Bind(&ShutdownTask
, base::MessageLoop::current())));
235 message_loop
.task_runner()->PostDelayedTask(
236 FROM_HERE
, base::MessageLoop::QuitClosure(),
237 TestTimeouts::action_max_timeout());
238 EXPECT_FALSE(g_good_shutdown
);
240 EXPECT_TRUE(g_good_shutdown
);
246 #include <CoreFoundation/CoreFoundation.h>
248 #include "base/files/file_path.h"
249 #include "base/files/file_util.h"
250 #include "base/files/scoped_temp_dir.h"
251 #include "base/mac/mac_util.h"
252 #include "base/test/test_timeouts.h"
253 #include "base/threading/thread.h"
254 #include "chrome/common/mac/launchd.h"
255 #include "chrome/common/mac/mock_launchd.h"
256 #include "testing/gtest/include/gtest/gtest.h"
258 class ServiceProcessStateFileManipulationTest
: public ::testing::Test
{
260 ServiceProcessStateFileManipulationTest()
261 : io_thread_("ServiceProcessStateFileManipulationTest_IO") {
264 void SetUp() override
{
265 base::Thread::Options options
;
266 options
.message_loop_type
= base::MessageLoop::TYPE_IO
;
267 ASSERT_TRUE(io_thread_
.StartWithOptions(options
));
268 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
269 ASSERT_TRUE(MockLaunchd::MakeABundle(GetTempDirPath(),
273 mock_launchd_
.reset(new MockLaunchd(executable_path_
, &loop_
,
275 scoped_launchd_instance_
.reset(
276 new Launchd::ScopedInstance(mock_launchd_
.get()));
277 ASSERT_TRUE(service_process_state_
.Initialize());
278 ASSERT_TRUE(service_process_state_
.SignalReady(
279 io_thread_
.task_runner().get(), base::Closure()));
280 loop_
.PostDelayedTask(FROM_HERE
,
281 base::MessageLoop::QuitClosure(),
282 TestTimeouts::action_max_timeout());
285 const MockLaunchd
* mock_launchd() const { return mock_launchd_
.get(); }
286 const base::FilePath
& executable_path() const { return executable_path_
; }
287 const base::FilePath
& bundle_path() const { return bundle_path_
; }
288 const base::FilePath
& GetTempDirPath() const { return temp_dir_
.path(); }
290 base::SingleThreadTaskRunner
* GetIOMessageLoopProxy() {
291 return io_thread_
.task_runner().get();
293 void Run() { loop_
.Run(); }
296 base::ScopedTempDir temp_dir_
;
297 base::MessageLoopForUI loop_
;
298 base::Thread io_thread_
;
299 base::FilePath executable_path_
, bundle_path_
;
300 scoped_ptr
<MockLaunchd
> mock_launchd_
;
301 scoped_ptr
<Launchd::ScopedInstance
> scoped_launchd_instance_
;
302 ServiceProcessState service_process_state_
;
305 void DeleteFunc(const base::FilePath
& file
) {
306 EXPECT_TRUE(base::DeleteFile(file
, true));
309 void MoveFunc(const base::FilePath
& from
, const base::FilePath
& to
) {
310 EXPECT_TRUE(base::Move(from
, to
));
313 void ChangeAttr(const base::FilePath
& from
, int mode
) {
314 EXPECT_EQ(chmod(from
.value().c_str(), mode
), 0);
317 class ScopedAttributesRestorer
{
319 ScopedAttributesRestorer(const base::FilePath
& path
, int mode
)
320 : path_(path
), mode_(mode
) {
322 ~ScopedAttributesRestorer() {
323 ChangeAttr(path_
, mode_
);
326 base::FilePath path_
;
330 void TrashFunc(const base::FilePath
& src
) {
333 EXPECT_TRUE(base::mac::FSRefFromPath(src
.value(), &path_ref
));
334 OSStatus status
= FSMoveObjectToTrashSync(&path_ref
,
336 kFSFileOperationDefaultOptions
);
337 EXPECT_EQ(status
, noErr
) << "FSMoveObjectToTrashSync " << status
;
340 TEST_F(ServiceProcessStateFileManipulationTest
, VerifyLaunchD
) {
341 // There have been problems where launchd has gotten into a bad state, usually
342 // because something had deleted all the files in /tmp. launchd depends on
343 // a Unix Domain Socket that it creates at /tmp/launchd*/sock.
344 // The symptom of this problem is that the service process connect fails
345 // on Mac and "launch_msg(): Socket is not connected" appears.
346 // This test is designed to make sure that launchd is working.
347 // http://crbug/75518
348 // Note: This particular problem no longer affects launchd in 10.10+, since
349 // there is no user owned launchd process and sockets are no longer made at
350 // /tmp/launchd*/sock. This test is still useful as a sanity check to make
351 // sure that launchd appears to be working.
353 base::CommandLine
cl(base::FilePath("/bin/launchctl"));
354 cl
.AppendArg("limit");
358 ASSERT_TRUE(base::GetAppOutputWithExitCode(cl
, &output
, &exit_code
)
360 << " exit_code:" << exit_code
<< " " << output
;
363 TEST_F(ServiceProcessStateFileManipulationTest
, DeleteFile
) {
364 GetIOMessageLoopProxy()->PostTask(
366 base::Bind(&DeleteFunc
, executable_path()));
368 ASSERT_TRUE(mock_launchd()->remove_called());
369 ASSERT_TRUE(mock_launchd()->delete_called());
372 TEST_F(ServiceProcessStateFileManipulationTest
, DeleteBundle
) {
373 GetIOMessageLoopProxy()->PostTask(
375 base::Bind(&DeleteFunc
, bundle_path()));
377 ASSERT_TRUE(mock_launchd()->remove_called());
378 ASSERT_TRUE(mock_launchd()->delete_called());
381 TEST_F(ServiceProcessStateFileManipulationTest
, MoveBundle
) {
382 base::FilePath new_loc
= GetTempDirPath().AppendASCII("MoveBundle");
383 GetIOMessageLoopProxy()->PostTask(
385 base::Bind(&MoveFunc
, bundle_path(), new_loc
));
387 ASSERT_TRUE(mock_launchd()->restart_called());
388 ASSERT_TRUE(mock_launchd()->write_called());
391 TEST_F(ServiceProcessStateFileManipulationTest
, MoveFile
) {
392 base::FilePath new_loc
= GetTempDirPath().AppendASCII("MoveFile");
393 GetIOMessageLoopProxy()->PostTask(
395 base::Bind(&MoveFunc
, executable_path(), new_loc
));
397 ASSERT_TRUE(mock_launchd()->remove_called());
398 ASSERT_TRUE(mock_launchd()->delete_called());
401 TEST_F(ServiceProcessStateFileManipulationTest
, TrashBundle
) {
403 ASSERT_TRUE(base::mac::FSRefFromPath(bundle_path().value(), &bundle_ref
));
404 GetIOMessageLoopProxy()->PostTask(
406 base::Bind(&TrashFunc
, bundle_path()));
408 ASSERT_TRUE(mock_launchd()->remove_called());
409 ASSERT_TRUE(mock_launchd()->delete_called());
410 std::string
path(base::mac::PathFromFSRef(bundle_ref
));
411 base::FilePath
file_path(path
);
412 ASSERT_TRUE(base::DeleteFile(file_path
, true));
415 TEST_F(ServiceProcessStateFileManipulationTest
, ChangeAttr
) {
416 ScopedAttributesRestorer
restorer(bundle_path(), 0777);
417 GetIOMessageLoopProxy()->PostTask(
419 base::Bind(&ChangeAttr
, bundle_path(), 0222));
421 ASSERT_TRUE(mock_launchd()->remove_called());
422 ASSERT_TRUE(mock_launchd()->delete_called());