OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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 "chrome/browser/renderer_host/render_process_host.h" | |
6 | |
7 #include "base/rand_util.h" | |
8 #include "base/sys_info.h" | |
9 #include "chrome/browser/child_process_security_policy.h" | |
10 #include "chrome/common/child_process_info.h" | |
11 #include "chrome/common/chrome_constants.h" | |
12 #include "chrome/common/notification_service.h" | |
13 | |
14 namespace { | |
15 | |
16 size_t max_renderer_count_override = 0; | |
17 | |
18 size_t GetMaxRendererProcessCount() { | |
19 if (max_renderer_count_override) | |
20 return max_renderer_count_override; | |
21 | |
22 // Defines the maximum number of renderer processes according to the | |
23 // amount of installed memory as reported by the OS. The table | |
24 // values are calculated by assuming that you want the renderers to | |
25 // use half of the installed ram and assuming that each tab uses | |
26 // ~40MB, however the curve is not linear but piecewise linear with | |
27 // interleaved slopes of 3 and 2. | |
28 // If you modify this table you need to adjust browser\browser_uitest.cc | |
29 // to match the expected number of processes. | |
30 | |
31 static const size_t kMaxRenderersByRamTier[] = { | |
32 3, // less than 256MB | |
33 6, // 256MB | |
34 9, // 512MB | |
35 12, // 768MB | |
36 14, // 1024MB | |
37 18, // 1280MB | |
38 20, // 1536MB | |
39 22, // 1792MB | |
40 24, // 2048MB | |
41 26, // 2304MB | |
42 29, // 2560MB | |
43 32, // 2816MB | |
44 35, // 3072MB | |
45 38, // 3328MB | |
46 40 // 3584MB | |
47 }; | |
48 | |
49 static size_t max_count = 0; | |
50 if (!max_count) { | |
51 size_t memory_tier = base::SysInfo::AmountOfPhysicalMemoryMB() / 256; | |
52 if (memory_tier >= arraysize(kMaxRenderersByRamTier)) | |
53 max_count = chrome::kMaxRendererProcessCount; | |
54 else | |
55 max_count = kMaxRenderersByRamTier[memory_tier]; | |
56 } | |
57 return max_count; | |
58 } | |
59 | |
60 // Returns true if the given host is suitable for launching a new view | |
61 // associated with the given profile. | |
62 static bool IsSuitableHost(RenderProcessHost* host, Profile* profile, | |
63 RenderProcessHost::Type type) { | |
64 if (host->profile() != profile) | |
65 return false; | |
66 | |
67 RenderProcessHost::Type host_type = RenderProcessHost::TYPE_NORMAL; | |
68 if (ChildProcessSecurityPolicy::GetInstance()->HasWebUIBindings(host->id())) | |
69 host_type = RenderProcessHost::TYPE_WEBUI; | |
70 if (ChildProcessSecurityPolicy::GetInstance()-> | |
71 HasExtensionBindings(host->id())) | |
72 host_type = RenderProcessHost::TYPE_EXTENSION; | |
73 | |
74 return host_type == type; | |
75 } | |
76 | |
77 // the global list of all renderer processes | |
78 IDMap<RenderProcessHost> all_hosts; | |
79 | |
80 } // namespace | |
81 | |
82 extern bool g_log_bug53991; | |
83 | |
84 // static | |
85 bool RenderProcessHost::run_renderer_in_process_ = false; | |
86 | |
87 // static | |
88 void RenderProcessHost::SetMaxRendererProcessCount(size_t count) { | |
89 max_renderer_count_override = count; | |
90 } | |
91 | |
92 RenderProcessHost::RenderProcessHost(Profile* profile) | |
93 : max_page_id_(-1), | |
94 fast_shutdown_started_(false), | |
95 deleting_soon_(false), | |
96 id_(ChildProcessInfo::GenerateChildProcessUniqueId()), | |
97 profile_(profile), | |
98 sudden_termination_allowed_(true), | |
99 ignore_input_events_(false) { | |
100 all_hosts.AddWithID(this, id()); | |
101 all_hosts.set_check_on_null_data(true); | |
102 // Initialize |child_process_activity_time_| to a reasonable value. | |
103 mark_child_process_activity_time(); | |
104 } | |
105 | |
106 RenderProcessHost::~RenderProcessHost() { | |
107 // In unit tests, Release() might not have been called. | |
108 if (all_hosts.Lookup(id())) | |
109 all_hosts.Remove(id()); | |
110 } | |
111 | |
112 void RenderProcessHost::Attach(IPC::Channel::Listener* listener, | |
113 int routing_id) { | |
114 VLOG_IF(1, g_log_bug53991) << "AddListener: (" << this << "): " << routing_id; | |
115 listeners_.AddWithID(listener, routing_id); | |
116 } | |
117 | |
118 void RenderProcessHost::Release(int listener_id) { | |
119 VLOG_IF(1, g_log_bug53991) << "RemListener: (" << this << "): " | |
120 << listener_id; | |
121 DCHECK(listeners_.Lookup(listener_id) != NULL); | |
122 listeners_.Remove(listener_id); | |
123 | |
124 // Make sure that all associated resource requests are stopped. | |
125 CancelResourceRequests(listener_id); | |
126 | |
127 // When no other owners of this object, we can delete ourselves | |
128 if (listeners_.IsEmpty()) { | |
129 NotificationService::current()->Notify( | |
130 NotificationType::RENDERER_PROCESS_TERMINATED, | |
131 Source<RenderProcessHost>(this), NotificationService::NoDetails()); | |
132 MessageLoop::current()->DeleteSoon(FROM_HERE, this); | |
133 deleting_soon_ = true; | |
134 | |
135 // Remove ourself from the list of renderer processes so that we can't be | |
136 // reused in between now and when the Delete task runs. | |
137 all_hosts.Remove(id()); | |
138 } | |
139 } | |
140 | |
141 void RenderProcessHost::ReportExpectingClose(int32 listener_id) { | |
142 listeners_expecting_close_.insert(listener_id); | |
143 } | |
144 | |
145 void RenderProcessHost::UpdateMaxPageID(int32 page_id) { | |
146 if (page_id > max_page_id_) | |
147 max_page_id_ = page_id; | |
148 } | |
149 | |
150 bool RenderProcessHost::FastShutdownForPageCount(size_t count) { | |
151 if (listeners_.size() == count) | |
152 return FastShutdownIfPossible(); | |
153 return false; | |
154 } | |
155 | |
156 // static | |
157 RenderProcessHost::iterator RenderProcessHost::AllHostsIterator() { | |
158 return iterator(&all_hosts); | |
159 } | |
160 | |
161 // static | |
162 RenderProcessHost* RenderProcessHost::FromID(int render_process_id) { | |
163 return all_hosts.Lookup(render_process_id); | |
164 } | |
165 | |
166 // static | |
167 bool RenderProcessHost::ShouldTryToUseExistingProcessHost() { | |
168 size_t renderer_process_count = all_hosts.size(); | |
169 | |
170 // NOTE: Sometimes it's necessary to create more render processes than | |
171 // GetMaxRendererProcessCount(), for instance when we want to create | |
172 // a renderer process for a profile that has no existing renderers. | |
173 // This is OK in moderation, since the GetMaxRendererProcessCount() | |
174 // is conservative. | |
175 | |
176 return run_renderer_in_process() || | |
177 (renderer_process_count >= GetMaxRendererProcessCount()); | |
178 } | |
179 | |
180 // static | |
181 RenderProcessHost* RenderProcessHost::GetExistingProcessHost(Profile* profile, | |
182 Type type) { | |
183 // First figure out which existing renderers we can use. | |
184 std::vector<RenderProcessHost*> suitable_renderers; | |
185 suitable_renderers.reserve(all_hosts.size()); | |
186 | |
187 iterator iter(AllHostsIterator()); | |
188 while (!iter.IsAtEnd()) { | |
189 if (run_renderer_in_process() || | |
190 IsSuitableHost(iter.GetCurrentValue(), profile, type)) | |
191 suitable_renderers.push_back(iter.GetCurrentValue()); | |
192 | |
193 iter.Advance(); | |
194 } | |
195 | |
196 // Now pick a random suitable renderer, if we have any. | |
197 if (!suitable_renderers.empty()) { | |
198 int suitable_count = static_cast<int>(suitable_renderers.size()); | |
199 int random_index = base::RandInt(0, suitable_count - 1); | |
200 return suitable_renderers[random_index]; | |
201 } | |
202 | |
203 return NULL; | |
204 } | |
OLD | NEW |