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/browser/service_process/service_process_control.h"
8 #include "base/bind_helpers.h"
9 #include "base/command_line.h"
10 #include "base/path_service.h"
11 #include "base/process/kill.h"
12 #include "base/process/process_handle.h"
13 #include "base/process/process_iterator.h"
14 #include "base/test/test_timeouts.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/common/chrome_constants.h"
17 #include "chrome/common/chrome_version_info.h"
18 #include "chrome/common/service_process_util.h"
19 #include "chrome/test/base/in_process_browser_test.h"
20 #include "chrome/test/base/ui_test_utils.h"
21 #include "content/public/common/content_paths.h"
22 #include "content/public/common/content_switches.h"
23 #include "testing/gmock/include/gmock/gmock.h"
25 class ServiceProcessControlBrowserTest
26 : public InProcessBrowserTest
{
28 ServiceProcessControlBrowserTest()
29 : service_process_handle_(base::kNullProcessHandle
) {
31 virtual ~ServiceProcessControlBrowserTest() {
32 base::CloseProcessHandle(service_process_handle_
);
33 service_process_handle_
= base::kNullProcessHandle
;
36 void HistogramsCallback() {
37 MockHistogramsCallback();
41 MOCK_METHOD0(MockHistogramsCallback
, void());
44 void LaunchServiceProcessControl() {
45 // Launch the process asynchronously.
46 ServiceProcessControl::GetInstance()->Launch(
47 base::Bind(&ServiceProcessControlBrowserTest::ProcessControlLaunched
,
50 &ServiceProcessControlBrowserTest::ProcessControlLaunchFailed
,
53 // Then run the message loop to keep things running.
54 content::RunMessageLoop();
57 static void QuitMessageLoop() {
58 base::MessageLoop::current()->Quit();
61 static void CloudPrintInfoCallback(
62 const cloud_print::CloudPrintProxyInfo
& proxy_info
) {
67 // This will close the IPC connection.
68 ServiceProcessControl::GetInstance()->Disconnect();
71 virtual void SetUp() OVERRIDE
{
72 service_process_handle_
= base::kNullProcessHandle
;
75 virtual void TearDown() OVERRIDE
{
76 if (ServiceProcessControl::GetInstance()->IsConnected())
77 EXPECT_TRUE(ServiceProcessControl::GetInstance()->Shutdown());
78 #if defined(OS_MACOSX)
79 // ForceServiceProcessShutdown removes the process from launched on Mac.
80 ForceServiceProcessShutdown("", 0);
82 if (service_process_handle_
!= base::kNullProcessHandle
) {
83 EXPECT_TRUE(base::WaitForSingleProcess(
84 service_process_handle_
,
85 TestTimeouts::action_max_timeout()));
86 service_process_handle_
= base::kNullProcessHandle
;
90 void ProcessControlLaunched() {
91 base::ProcessId service_pid
;
92 EXPECT_TRUE(GetServiceProcessData(NULL
, &service_pid
));
93 EXPECT_NE(static_cast<base::ProcessId
>(0), service_pid
);
94 EXPECT_TRUE(base::OpenProcessHandleWithAccess(
96 base::kProcessAccessWaitForTermination
|
97 // we need query permission to get exit code
98 base::kProcessAccessQueryInformation
,
99 &service_process_handle_
));
100 // Quit the current message. Post a QuitTask instead of just calling Quit()
101 // because this can get invoked in the context of a Launch() call and we
102 // may not be in Run() yet.
103 base::MessageLoop::current()->PostTask(FROM_HERE
,
104 base::MessageLoop::QuitClosure());
107 void ProcessControlLaunchFailed() {
109 // Quit the current message.
110 base::MessageLoop::current()->PostTask(FROM_HERE
,
111 base::MessageLoop::QuitClosure());
115 base::ProcessHandle service_process_handle_
;
118 class RealServiceProcessControlBrowserTest
119 : public ServiceProcessControlBrowserTest
{
121 virtual void SetUpCommandLine(CommandLine
* command_line
) OVERRIDE
{
122 ServiceProcessControlBrowserTest::SetUpCommandLine(command_line
);
124 PathService::Get(base::DIR_EXE
, &exe
);
125 #if defined(OS_MACOSX)
126 exe
= exe
.DirName().DirName().DirName();
128 exe
= exe
.Append(chrome::kHelperProcessExecutablePath
);
129 // Run chrome instead of browser_tests.exe.
130 EXPECT_TRUE(base::PathExists(exe
));
131 command_line
->AppendSwitchPath(switches::kBrowserSubprocessPath
, exe
);
135 // TODO(vitalybuka): Fix crbug.com/340563
136 IN_PROC_BROWSER_TEST_F(RealServiceProcessControlBrowserTest
,
137 DISABLED_LaunchAndIPC
) {
138 LaunchServiceProcessControl();
140 // Make sure we are connected to the service process.
141 ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
142 ServiceProcessControl::GetInstance()->GetCloudPrintProxyInfo(
143 base::Bind(&ServiceProcessControlBrowserTest::CloudPrintInfoCallback
));
144 content::RunMessageLoop();
146 // And then shutdown the service process.
147 EXPECT_TRUE(ServiceProcessControl::GetInstance()->Shutdown());
150 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest
, LaunchAndIPC
) {
151 LaunchServiceProcessControl();
153 // Make sure we are connected to the service process.
154 ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
155 ServiceProcessControl::GetInstance()->GetCloudPrintProxyInfo(
156 base::Bind(&ServiceProcessControlBrowserTest::CloudPrintInfoCallback
));
157 content::RunMessageLoop();
159 // And then shutdown the service process.
160 EXPECT_TRUE(ServiceProcessControl::GetInstance()->Shutdown());
163 // This tests the case when a service process is launched when the browser
164 // starts but we try to launch it again while setting up Cloud Print.
165 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest
, LaunchTwice
) {
166 // Launch the service process the first time.
167 LaunchServiceProcessControl();
169 // Make sure we are connected to the service process.
170 ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
171 EXPECT_TRUE(ServiceProcessControl::GetInstance()->GetCloudPrintProxyInfo(
172 base::Bind(&ServiceProcessControlBrowserTest::CloudPrintInfoCallback
)));
173 content::RunMessageLoop();
175 // Launch the service process again.
176 LaunchServiceProcessControl();
177 ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
178 EXPECT_TRUE(ServiceProcessControl::GetInstance()->GetCloudPrintProxyInfo(
179 base::Bind(&ServiceProcessControlBrowserTest::CloudPrintInfoCallback
)));
180 content::RunMessageLoop();
183 static void DecrementUntilZero(int* count
) {
186 base::MessageLoop::current()->PostTask(FROM_HERE
,
187 base::MessageLoop::QuitClosure());
190 // Invoke multiple Launch calls in succession and ensure that all the tasks
192 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest
,
193 MultipleLaunchTasks
) {
194 ServiceProcessControl
* process
= ServiceProcessControl::GetInstance();
195 int launch_count
= 5;
196 for (int i
= 0; i
< launch_count
; i
++) {
197 // Launch the process asynchronously.
198 process
->Launch(base::Bind(&DecrementUntilZero
, &launch_count
),
199 base::MessageLoop::QuitClosure());
201 // Then run the message loop to keep things running.
202 content::RunMessageLoop();
203 EXPECT_EQ(0, launch_count
);
206 // Make sure using the same task for success and failure tasks works.
207 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest
, SameLaunchTask
) {
208 ServiceProcessControl
* process
= ServiceProcessControl::GetInstance();
209 int launch_count
= 5;
210 for (int i
= 0; i
< launch_count
; i
++) {
211 // Launch the process asynchronously.
212 base::Closure task
= base::Bind(&DecrementUntilZero
, &launch_count
);
213 process
->Launch(task
, task
);
215 // Then run the message loop to keep things running.
216 content::RunMessageLoop();
217 EXPECT_EQ(0, launch_count
);
220 // Tests whether disconnecting from the service IPC causes the service process
222 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest
, DieOnDisconnect
) {
223 // Launch the service process.
224 LaunchServiceProcessControl();
225 // Make sure we are connected to the service process.
226 ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
230 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest
, ForceShutdown
) {
231 // Launch the service process.
232 LaunchServiceProcessControl();
233 // Make sure we are connected to the service process.
234 ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
235 base::ProcessId service_pid
;
236 EXPECT_TRUE(GetServiceProcessData(NULL
, &service_pid
));
237 EXPECT_NE(static_cast<base::ProcessId
>(0), service_pid
);
238 chrome::VersionInfo version_info
;
239 ForceServiceProcessShutdown(version_info
.Version(), service_pid
);
242 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest
, CheckPid
) {
243 base::ProcessId service_pid
;
244 EXPECT_FALSE(GetServiceProcessData(NULL
, &service_pid
));
245 // Launch the service process.
246 LaunchServiceProcessControl();
247 EXPECT_TRUE(GetServiceProcessData(NULL
, &service_pid
));
248 EXPECT_NE(static_cast<base::ProcessId
>(0), service_pid
);
249 // Disconnect from service process.
253 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest
, HistogramsNoService
) {
254 ASSERT_FALSE(ServiceProcessControl::GetInstance()->IsConnected());
255 EXPECT_CALL(*this, MockHistogramsCallback()).Times(0);
256 EXPECT_FALSE(ServiceProcessControl::GetInstance()->GetHistograms(
257 base::Bind(&ServiceProcessControlBrowserTest::HistogramsCallback
,
258 base::Unretained(this)),
262 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest
, HistogramsTimeout
) {
263 LaunchServiceProcessControl();
264 ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
265 // Callback should not be called during GetHistograms call.
266 EXPECT_CALL(*this, MockHistogramsCallback()).Times(0);
267 EXPECT_TRUE(ServiceProcessControl::GetInstance()->GetHistograms(
268 base::Bind(&ServiceProcessControlBrowserTest::HistogramsCallback
,
269 base::Unretained(this)),
270 base::TimeDelta::FromMilliseconds(100)));
271 EXPECT_CALL(*this, MockHistogramsCallback()).Times(1);
272 EXPECT_TRUE(ServiceProcessControl::GetInstance()->Shutdown());
273 content::RunMessageLoop();
276 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest
, Histograms
) {
277 LaunchServiceProcessControl();
278 ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
279 // Callback should not be called during GetHistograms call.
280 EXPECT_CALL(*this, MockHistogramsCallback()).Times(0);
281 // Wait for real callback by providing large timeout value.
282 EXPECT_TRUE(ServiceProcessControl::GetInstance()->GetHistograms(
283 base::Bind(&ServiceProcessControlBrowserTest::HistogramsCallback
,
284 base::Unretained(this)),
285 base::TimeDelta::FromHours(1)));
286 EXPECT_CALL(*this, MockHistogramsCallback()).Times(1);
287 content::RunMessageLoop();