Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(355)

Side by Side Diff: content/browser/renderer_host/render_process_host_impl_unittest.cc

Issue 16267002: Re-fix http://crbug.com/87176, and add a test. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase on top of https://codereview.chromium.org/16490003/ Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 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 "content/browser/renderer_host/render_process_host_impl.h"
6
7 #include "base/command_line.h"
8 #include "base/process_util.h"
9 #include "base/run_loop.h"
10 #include "content/browser/child_process_launcher.h"
11 #include "content/browser/loader/resource_dispatcher_host_impl.h"
12 #include "content/browser/site_instance_impl.h"
13 #include "content/browser/storage_partition_impl.h"
14 #include "content/browser/webui/web_ui_controller_factory_registry.h"
15 #include "content/common/child_process_messages.h"
16 #include "content/common/view_messages.h"
17 #include "content/public/browser/render_process_host_factory.h"
18 #include "content/public/common/sandboxed_process_launcher_delegate.h"
19 #include "content/public/test/test_browser_context.h"
20 #include "content/public/test/test_browser_thread.h"
21 #include "content/test/test_content_browser_client.h"
22 #include "content/test/test_render_view_host_factory.h"
23 #include "content/test/test_web_contents.h"
24 #include "ipc/ipc_switches.h"
25 #include "ipc/ipc_test_sink.h"
26 #include "net/url_request/url_request_test_util.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28
29 namespace content {
30 namespace {
31
32 class FakeChildProcessLauncher;
33
34 struct LaunchedChildProcess {
35 // Becomes NULL after the FakeChildProcessLauncher is destroyed.
36 FakeChildProcessLauncher* launcher_;
37 // Collects messages sent to the child process.
38 IPC::TestSink messages_;
39 };
40
41 class FakeChildProcessLauncher : public ChildProcessLauncher {
42 public:
43 FakeChildProcessLauncher(LaunchedChildProcess* info,
44 const IPC::ChannelHandle& channel,
45 Client* client)
46 : info_(info),
47 client_(client),
48 starting_(true),
49 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION),
50 channel_(new IPC::ChannelProxy(
51 channel,
52 IPC::Channel::MODE_CLIENT,
53 &info->messages_,
54 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO))),
55 weak_this_factory_(this) {
56 info_->launcher_ = this;
57
58 // Automatically start the child process so the RenderProcessHostImpl sends
59 // messages to it. To mimic real child processes, don't start instantly.
60 base::MessageLoopProxy::current()->PostTask(
61 FROM_HERE,
62 base::Bind(&FakeChildProcessLauncher::Start,
63 weak_this_factory_.GetWeakPtr()));
64 }
65
66 virtual ~FakeChildProcessLauncher() { info_->launcher_ = NULL; }
67
68 void Send(IPC::Message* msg) {
69 EXPECT_TRUE(channel_->Send(msg));
70 }
71
72 Client* client() const { return client_; }
73
74 // Implementation of ChildProcessLauncher.
75 virtual bool IsStarting() OVERRIDE { return starting_; }
76 virtual base::ProcessHandle GetHandle() OVERRIDE {
77 return base::Process::Current().handle();
78 }
79 virtual base::TerminationStatus GetChildTerminationStatus(bool known_dead,
80 int* exit_code)
81 OVERRIDE {
82 return termination_status_;
83 }
84 virtual void SetProcessBackgrounded(bool background) OVERRIDE {}
85 virtual void SetTerminateChildOnShutdown(bool terminate_on_shutdown)
86 OVERRIDE {}
87
88 private:
89 void Start() {
90 starting_ = false;
91 client_->OnProcessLaunched();
92 }
93
94 LaunchedChildProcess* info_;
95 Client* client_;
96 bool starting_;
97 base::TerminationStatus termination_status_;
98 scoped_ptr<IPC::ChannelProxy> channel_;
99 base::WeakPtrFactory<FakeChildProcessLauncher> weak_this_factory_;
100 };
101
102 scoped_ptr<ChildProcessLauncher> NewFakeChildProcessLauncher(
103 ScopedVector<LaunchedChildProcess>* child_processes,
104 #if defined(OS_WIN)
105 SandboxedProcessLauncherDelegate* delegate,
106 #elif defined(OS_POSIX)
107 bool use_zygote,
108 const base::EnvironmentVector& environ,
109 int ipcfd,
110 #endif
111 CommandLine* cmd_line,
112 int child_process_id,
113 ChildProcessLauncher::Client* client) {
114 #if defined(OS_WIN)
115 delete delegate;
116 #endif
117 scoped_ptr<CommandLine> cmd_line_deleter(cmd_line);
118 child_processes->push_back(new LaunchedChildProcess());
119 std::string channel_id =
120 cmd_line->GetSwitchValueASCII(switches::kProcessChannelID);
121 return scoped_ptr<ChildProcessLauncher>(new FakeChildProcessLauncher(
122 child_processes->back(),
123 IPC::ChannelHandle(channel_id
124 #if defined(OS_POSIX)
125 ,
126 base::FileDescriptor(ipcfd, false)
127 #endif
128 ),
129 client));
130 }
131
132 class RPHIBrowserContext : public TestBrowserContext {
133 private:
134 virtual net::URLRequestContextGetter* GetRequestContextForRenderProcess(
135 int renderer_child_id) OVERRIDE {
136 return GetRequestContext();
137 }
138 };
139
140 class RPHIBrowserClient : public TestContentBrowserClient {
141 public:
142 RPHIBrowserClient()
143 : request_context_getter_(new net::TestURLRequestContextGetter(
144 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO))) {}
145
146 virtual net::URLRequestContextGetter* CreateRequestContext(
147 BrowserContext* browser_context,
148 ProtocolHandlerMap* protocol_handlers) OVERRIDE {
149 return request_context_getter_.get();
150 }
151
152 private:
153 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
154 };
155
156 class FakeChildProcessRPHFactory : public RenderProcessHostFactory {
157 public:
158 FakeChildProcessRPHFactory(
159 ScopedVector<LaunchedChildProcess>* child_processes)
160 : child_processes_(child_processes) {
161 SiteInstanceImpl::set_render_process_host_factory(this);
162 }
163 virtual ~FakeChildProcessRPHFactory() {
164 SiteInstanceImpl::set_render_process_host_factory(NULL);
165 }
166
167 virtual RenderProcessHost* CreateRenderProcessHost(
168 BrowserContext* browser_context,
169 SiteInstance* site_instance) const OVERRIDE {
170 RenderProcessHostImpl* host =
171 new RenderProcessHostImpl(browser_context,
172 static_cast<StoragePartitionImpl*>(
173 TestBrowserContext::GetStoragePartition(
174 browser_context, site_instance)),
175 false,
176 false);
177 host->SetChildProcessLauncherFactory(
178 base::Bind(&NewFakeChildProcessLauncher, child_processes_));
179 return host;
180 }
181
182 private:
183 ScopedVector<LaunchedChildProcess>* child_processes_;
184 };
185
186 class RenderProcessHostImplTest : public testing::Test {
187 public:
188 RenderProcessHostImplTest()
189 : ui_thread_(BrowserThread::UI, &message_loop_),
190 webkit_thread_(BrowserThread::WEBKIT_DEPRECATED, &message_loop_),
191 file_user_blocking_thread_(BrowserThread::FILE_USER_BLOCKING,
192 &message_loop_),
193 io_thread_(BrowserThread::IO, &message_loop_),
194 old_browser_client_(SetBrowserClientForTesting(&test_browser_client_)) {
195 }
196
197 virtual ~RenderProcessHostImplTest() {
198 base::RunLoop().RunUntilIdle();
199 SetBrowserClientForTesting(old_browser_client_);
200 }
201
202 protected:
203 ScopedVector<LaunchedChildProcess> child_processes_;
204 base::MessageLoopForIO message_loop_;
205 TestBrowserThread ui_thread_;
206 TestBrowserThread webkit_thread_;
207 TestBrowserThread file_user_blocking_thread_;
208 TestBrowserThread io_thread_;
209
210 RPHIBrowserContext browser_context_;
211 RPHIBrowserClient test_browser_client_;
212 ContentBrowserClient* old_browser_client_;
213 ResourceDispatcherHostImpl resource_dispatcher_host_;
214
215 DISALLOW_COPY_AND_ASSIGN(RenderProcessHostImplTest);
216 };
217
218 // http://crbug.com/87176
219 TEST_F(RenderProcessHostImplTest,
220 RejectShutdownFromChildProcessWithOneActiveView) {
221 const GURL kUrl("http://example.com");
222
223 scoped_refptr<SiteInstance> site(
224 SiteInstance::CreateForURL(&browser_context_, kUrl));
225 FakeChildProcessRPHFactory rph_factory(&child_processes_);
226
227 WebContents::CreateParams params(&browser_context_, site.get());
228 scoped_ptr<WebContentsImpl> tab(
229 WebContentsImpl::CreateWithOpener(params, NULL));
230 tab->GetController().LoadURL(kUrl, Referrer(), PAGE_TRANSITION_TYPED, "");
231 base::RunLoop().RunUntilIdle();
232 ASSERT_EQ(1U, child_processes_.size());
233
234 child_processes_[0]->messages_.ClearMessages();
235
236 RenderProcessHostImpl* tab_process =
237 static_cast<RenderProcessHostImpl*>(tab->GetSiteInstance()->GetProcess());
238 EXPECT_EQ(1, tab_process->GetActiveViewCount());
239 EXPECT_EQ(child_processes_[0]->launcher_->client(), tab_process);
240
241 // Sometimes the renderer process's ShutdownRequest (corresponding to the
242 // ViewMsg_WasSwappedOut from a previous navigation) doesn't arrive until
243 // after the browser process decides to re-use the renderer for a new purpose.
244 // This test makes sure the browser doesn't let the renderer die in that case.
245 child_processes_[0]->launcher_->
246 Send(new ChildProcessHostMsg_ShutdownRequest());
247 base::RunLoop().RunUntilIdle();
248 EXPECT_FALSE(child_processes_[0]->messages_.GetFirstMessageMatching(
249 ChildProcessMsg_Shutdown::ID))
250 << "Host sent a message confirming that the renderer process should shut "
251 << "down even though it was still being used.";
252 }
253
254 } // namespace
255 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698