1 // Copyright 2016 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 "base/bind.h"
6 #include "base/run_loop.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "build/build_config.h"
9 #include "content/browser/utility_process_host.h"
10 #include "content/public/browser/browser_child_process_observer.h"
11 #include "content/public/browser/browser_task_traits.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/child_process_data.h"
14 #include "content/public/browser/child_process_termination_info.h"
15 #include "content/public/test/browser_test.h"
16 #include "content/public/test/content_browser_test.h"
17 #include "content/public/test/content_browser_test_utils.h"
18 #include "content/public/test/test_service.mojom.h"
19 #include "mojo/public/cpp/bindings/remote.h"
20
21 #if defined(OS_MAC) || defined(OS_LINUX) || defined(OS_CHROMEOS)
22 #include <sys/wait.h>
23 #endif
24
25 #if defined(OS_WIN)
26 #include <windows.h>
27 #endif // OS_WIN
28
29 namespace content {
30
31 namespace {
32
33 const char kTestProcessName[] = "test_process";
34
35 } // namespace
36
37 class UtilityProcessHostBrowserTest : public BrowserChildProcessObserver,
38 public ContentBrowserTest {
39 public:
RunUtilityProcess(bool elevated,bool crash)40 void RunUtilityProcess(bool elevated, bool crash) {
41 DCHECK_CURRENTLY_ON(BrowserThread::UI);
42 BrowserChildProcessObserver::Add(this);
43 has_crashed = false;
44 base::RunLoop run_loop;
45 done_closure_ =
46 base::BindOnce(&UtilityProcessHostBrowserTest::DoneRunning,
47 base::Unretained(this), run_loop.QuitClosure(), crash);
48 GetIOThreadTaskRunner({})->PostTask(
49 FROM_HERE,
50 base::BindOnce(
51 &UtilityProcessHostBrowserTest::RunUtilityProcessOnIOThread,
52 base::Unretained(this), elevated, crash));
53 run_loop.Run();
54 }
55
56 protected:
DoneRunning(base::OnceClosure quit_closure,bool expect_crashed)57 void DoneRunning(base::OnceClosure quit_closure, bool expect_crashed) {
58 DCHECK_CURRENTLY_ON(BrowserThread::UI);
59 BrowserChildProcessObserver::Remove(this);
60 EXPECT_EQ(expect_crashed, has_crashed);
61 std::move(quit_closure).Run();
62 }
63
RunUtilityProcessOnIOThread(bool elevated,bool crash)64 void RunUtilityProcessOnIOThread(bool elevated, bool crash) {
65 DCHECK_CURRENTLY_ON(BrowserThread::IO);
66 UtilityProcessHost* host = new UtilityProcessHost();
67 host->SetName(base::ASCIIToUTF16("TestProcess"));
68 host->SetMetricsName(kTestProcessName);
69 #if defined(OS_WIN)
70 if (elevated)
71 host->SetSandboxType(
72 sandbox::policy::SandboxType::kNoSandboxAndElevatedPrivileges);
73 #endif
74 EXPECT_TRUE(host->Start());
75
76 host->GetChildProcess()->BindReceiver(
77 service_.BindNewPipeAndPassReceiver());
78 if (crash) {
79 service_->DoCrashImmediately(
80 base::BindOnce(&UtilityProcessHostBrowserTest::OnSomethingOnIOThread,
81 base::Unretained(this), crash));
82 } else {
83 service_->DoSomething(
84 base::BindOnce(&UtilityProcessHostBrowserTest::OnSomethingOnIOThread,
85 base::Unretained(this), crash));
86 }
87 }
88
ResetServiceOnIOThread()89 void ResetServiceOnIOThread() {
90 DCHECK_CURRENTLY_ON(BrowserThread::IO);
91 service_.reset();
92 }
93
OnSomethingOnIOThread(bool expect_crash)94 void OnSomethingOnIOThread(bool expect_crash) {
95 DCHECK_CURRENTLY_ON(BrowserThread::IO);
96 // If service crashes then this never gets called.
97 ASSERT_EQ(false, expect_crash);
98 ResetServiceOnIOThread();
99 GetUIThreadTaskRunner({})->PostTask(FROM_HERE, std::move(done_closure_));
100 }
101
102 mojo::Remote<mojom::TestService> service_;
103 base::OnceClosure done_closure_;
104
105 // Access on UI thread.
106 bool has_crashed;
107
108 private:
109 // content::BrowserChildProcessObserver implementation:
BrowserChildProcessKilled(const ChildProcessData & data,const ChildProcessTerminationInfo & info)110 void BrowserChildProcessKilled(
111 const ChildProcessData& data,
112 const ChildProcessTerminationInfo& info) override {
113 DCHECK_CURRENTLY_ON(BrowserThread::UI);
114 #if defined(OS_ANDROID)
115 // Android does not send crash notifications but sends kills. See comment in
116 // browser_child_process_observer.h.
117 BrowserChildProcessCrashed(data, info);
118 #else
119 FAIL() << "Killed notifications should only happen on Android.";
120 #endif
121 }
122
BrowserChildProcessCrashed(const ChildProcessData & data,const ChildProcessTerminationInfo & info)123 void BrowserChildProcessCrashed(
124 const ChildProcessData& data,
125 const ChildProcessTerminationInfo& info) override {
126 DCHECK_CURRENTLY_ON(BrowserThread::UI);
127 #if defined(OS_WIN)
128 EXPECT_EQ(EXCEPTION_BREAKPOINT, DWORD{info.exit_code});
129 #elif defined(OS_MAC) || defined(OS_LINUX) || defined(OS_CHROMEOS)
130 EXPECT_TRUE(WIFSIGNALED(info.exit_code));
131 EXPECT_EQ(SIGTRAP, WTERMSIG(info.exit_code));
132 #endif
133 EXPECT_EQ(kTestProcessName, data.metrics_name);
134 EXPECT_EQ(false, has_crashed);
135 has_crashed = true;
136 GetIOThreadTaskRunner({})->PostTask(
137 FROM_HERE,
138 base::BindOnce(&UtilityProcessHostBrowserTest::ResetServiceOnIOThread,
139 base::Unretained(this)));
140 std::move(done_closure_).Run();
141 }
142 };
143
IN_PROC_BROWSER_TEST_F(UtilityProcessHostBrowserTest,LaunchProcess)144 IN_PROC_BROWSER_TEST_F(UtilityProcessHostBrowserTest, LaunchProcess) {
145 RunUtilityProcess(false, false);
146 }
147
IN_PROC_BROWSER_TEST_F(UtilityProcessHostBrowserTest,LaunchProcessAndCrash)148 IN_PROC_BROWSER_TEST_F(UtilityProcessHostBrowserTest, LaunchProcessAndCrash) {
149 RunUtilityProcess(false, true);
150 }
151
152 #if defined(OS_WIN)
153 // Times out. crbug.com/927298.
IN_PROC_BROWSER_TEST_F(UtilityProcessHostBrowserTest,DISABLED_LaunchElevatedProcess)154 IN_PROC_BROWSER_TEST_F(UtilityProcessHostBrowserTest,
155 DISABLED_LaunchElevatedProcess) {
156 RunUtilityProcess(true, false);
157 }
158
159 // Disabled because currently this causes a WER dialog to appear.
IN_PROC_BROWSER_TEST_F(UtilityProcessHostBrowserTest,DISABLED_LaunchElevatedProcessAndCrash)160 IN_PROC_BROWSER_TEST_F(UtilityProcessHostBrowserTest,
161 DISABLED_LaunchElevatedProcessAndCrash) {
162 RunUtilityProcess(true, true);
163 }
164 #endif
165
166 } // namespace content
167