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