OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/common/child_process_host.h" | 5 #include "content/common/child_process_host.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/file_path.h" | 8 #include "base/file_path.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
59 .Append(kContentsName) | 59 .Append(kContentsName) |
60 .Append(kMacOSName) | 60 .Append(kMacOSName) |
61 .Append(new_basename); | 61 .Append(new_basename); |
62 | 62 |
63 return new_path; | 63 return new_path; |
64 } | 64 } |
65 | 65 |
66 } // namespace | 66 } // namespace |
67 #endif // OS_MACOSX | 67 #endif // OS_MACOSX |
68 | 68 |
| 69 #if defined (OS_WIN) |
| 70 // Types used in PreCacheFont |
| 71 namespace { |
| 72 typedef std::vector<string16> FontNameVector; |
| 73 typedef std::map<int, FontNameVector> PidToFontNames; |
| 74 } |
| 75 #endif // OS_WIN |
| 76 |
69 ChildProcessHost::ChildProcessHost() | 77 ChildProcessHost::ChildProcessHost() |
70 : ALLOW_THIS_IN_INITIALIZER_LIST(listener_(this)), | 78 : ALLOW_THIS_IN_INITIALIZER_LIST(listener_(this)), |
71 opening_channel_(false) { | 79 opening_channel_(false) { |
72 } | 80 } |
73 | 81 |
74 ChildProcessHost::~ChildProcessHost() { | 82 ChildProcessHost::~ChildProcessHost() { |
75 for (size_t i = 0; i < filters_.size(); ++i) { | 83 for (size_t i = 0; i < filters_.size(); ++i) { |
76 filters_[i]->OnChannelClosing(); | 84 filters_[i]->OnChannelClosing(); |
77 filters_[i]->OnFilterRemoved(); | 85 filters_[i]->OnFilterRemoved(); |
78 } | 86 } |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 // intolerant of a non-executable heap to work properly on 10.7. This | 132 // intolerant of a non-executable heap to work properly on 10.7. This |
125 // results in Chromium Helper EH.app or Google Chrome Helper EH.app. | 133 // results in Chromium Helper EH.app or Google Chrome Helper EH.app. |
126 child_path = TransformPathForFeature(child_path, "EH"); | 134 child_path = TransformPathForFeature(child_path, "EH"); |
127 } | 135 } |
128 #endif | 136 #endif |
129 | 137 |
130 return child_path; | 138 return child_path; |
131 } | 139 } |
132 | 140 |
133 #if defined(OS_WIN) | 141 #if defined(OS_WIN) |
| 142 ChildProcessHost::FontCache::CacheElement::CacheElement() |
| 143 : font_(NULL), dc_(NULL), ref_count_(0) { |
| 144 } |
| 145 |
| 146 ChildProcessHost::FontCache::CacheElement::~CacheElement() { |
| 147 if (font_) { |
| 148 DeleteObject(font_); |
| 149 } |
| 150 if (dc_) { |
| 151 DeleteDC(dc_); |
| 152 } |
| 153 } |
| 154 |
| 155 ChildProcessHost::FontCache::FontCache() { |
| 156 } |
| 157 |
| 158 ChildProcessHost::FontCache::~FontCache() { |
| 159 } |
| 160 |
134 // static | 161 // static |
135 void ChildProcessHost::PreCacheFont(LOGFONT font) { | 162 ChildProcessHost::FontCache* ChildProcessHost::FontCache::GetInstance() { |
136 // If a child process is running in a sandbox, GetTextMetrics() | 163 return Singleton<ChildProcessHost::FontCache>::get(); |
137 // can sometimes fail. If a font has not been loaded | 164 } |
138 // previously, GetTextMetrics() will try to load the font | |
139 // from the font file. However, the sandboxed process does | |
140 // not have permissions to access any font files and | |
141 // the call fails. So we make the browser pre-load the | |
142 // font for us by using a dummy call to GetTextMetrics of | |
143 // the same font. | |
144 | 165 |
145 // Maintain a circular queue for the fonts and DCs to be cached. | 166 void ChildProcessHost::FontCache::PreCacheFont(LOGFONT font, int pid) { |
146 // font_index maintains next available location in the queue. | 167 typedef std::map<string16, ChildProcessHost::FontCache::CacheElement> |
147 static const int kFontCacheSize = 32; | 168 FontNameToElement; |
148 static HFONT fonts[kFontCacheSize] = {0}; | |
149 static HDC hdcs[kFontCacheSize] = {0}; | |
150 static size_t font_index = 0; | |
151 | 169 |
152 UMA_HISTOGRAM_COUNTS_100("Memory.CachedFontAndDC", | 170 base::AutoLock lock(mutex_); |
153 fonts[kFontCacheSize-1] ? kFontCacheSize : static_cast<int>(font_index)); | |
154 | 171 |
| 172 // Fetch the font into memory. |
| 173 // No matter the font is cached or not, we load it to avoid GDI swapping out |
| 174 // that font file. |
155 HDC hdc = GetDC(NULL); | 175 HDC hdc = GetDC(NULL); |
156 HFONT font_handle = CreateFontIndirect(&font); | 176 HFONT font_handle = CreateFontIndirect(&font); |
157 DCHECK(NULL != font_handle); | 177 DCHECK(NULL != font_handle); |
158 | 178 |
159 HGDIOBJ old_font = SelectObject(hdc, font_handle); | 179 HGDIOBJ old_font = SelectObject(hdc, font_handle); |
160 DCHECK(NULL != old_font); | 180 DCHECK(NULL != old_font); |
161 | 181 |
162 TEXTMETRIC tm; | 182 TEXTMETRIC tm; |
163 BOOL ret = GetTextMetrics(hdc, &tm); | 183 BOOL ret = GetTextMetrics(hdc, &tm); |
164 DCHECK(ret); | 184 DCHECK(ret); |
165 | 185 |
166 if (fonts[font_index] || hdcs[font_index]) { | 186 string16 font_name = font.lfFaceName; |
167 // We already have too many fonts, we will delete one and take it's place. | 187 int ref_count_inc = 1; |
168 DeleteObject(fonts[font_index]); | 188 FontNameVector::iterator it = std::find(pid_font_map_[pid].begin(), |
169 ReleaseDC(NULL, hdcs[font_index]); | 189 pid_font_map_[pid].end(), |
| 190 font_name); |
| 191 if (it == pid_font_map_[pid].end()) { // Requested font is new to cache. |
| 192 pid_font_map_[pid].push_back(font_name); |
| 193 } else { |
| 194 ref_count_inc = 0; |
170 } | 195 } |
171 | 196 |
172 fonts[font_index] = font_handle; | 197 if (cache_[font_name].ref_count_ == 0) { // Requested font is new to cache. |
173 hdcs[font_index] = hdc; | 198 cache_[font_name].ref_count_ = 1; |
174 font_index = (font_index + 1) % kFontCacheSize; | 199 } else { // Requested font is already in cache, release old handles. |
| 200 DeleteObject(cache_[font_name].font_); |
| 201 DeleteDC(cache_[font_name].dc_); |
| 202 } |
| 203 cache_[font_name].font_ = font_handle; |
| 204 cache_[font_name].dc_ = hdc; |
| 205 cache_[font_name].ref_count_ += ref_count_inc; |
| 206 } |
| 207 |
| 208 void ChildProcessHost::FontCache::ReleaseCachedFonts(int pid) { |
| 209 typedef std::map<string16, ChildProcessHost::FontCache::CacheElement> |
| 210 FontNameToElement; |
| 211 |
| 212 base::AutoLock lock(mutex_); |
| 213 |
| 214 PidToFontNames::iterator it; |
| 215 it = pid_font_map_.find(pid); |
| 216 if (it == pid_font_map_.end()) { |
| 217 return; |
| 218 } |
| 219 |
| 220 for (FontNameVector::iterator i = it->second.begin(), e = it->second.end(); |
| 221 i != e; ++i) { |
| 222 FontNameToElement::iterator element; |
| 223 element = cache_.find(*i); |
| 224 if (element != cache_.end()) { |
| 225 --((*element).second.ref_count_); |
| 226 } |
| 227 } |
| 228 |
| 229 pid_font_map_.erase(it); |
| 230 for (FontNameToElement::iterator i = cache_.begin(); i != cache_.end(); ) { |
| 231 if (i->second.ref_count_ == 0) { |
| 232 cache_.erase(i++); |
| 233 } else { |
| 234 ++i; |
| 235 } |
| 236 } |
| 237 } |
| 238 |
| 239 // static |
| 240 void ChildProcessHost::PreCacheFont(LOGFONT font, int pid) { |
| 241 // If a child process is running in a sandbox, GetTextMetrics() |
| 242 // can sometimes fail. If a font has not been loaded |
| 243 // previously, GetTextMetrics() will try to load the font |
| 244 // from the font file. However, the sandboxed process does |
| 245 // not have permissions to access any font files and |
| 246 // the call fails. So we make the browser pre-load the |
| 247 // font for us by using a dummy call to GetTextMetrics of |
| 248 // the same font. |
| 249 // This means the browser process just loads the font into memory so that |
| 250 // when GDI attempt to query that font info in child process, it does not |
| 251 // need to load that file, hence no permission issues there. Therefore, |
| 252 // when a font is asked to be cached, we always recreates the font object |
| 253 // to avoid the case that an in-cache font is swapped out by GDI. |
| 254 ChildProcessHost::FontCache::GetInstance()->PreCacheFont(font, pid); |
| 255 } |
| 256 |
| 257 // static |
| 258 void ChildProcessHost::ReleaseCachedFonts(int pid) { |
| 259 // Release cached fonts that requested from a pid by decrementing the ref |
| 260 // count. When ref count is zero, the handles are released. |
| 261 ChildProcessHost::FontCache::GetInstance()->ReleaseCachedFonts(pid); |
175 } | 262 } |
176 #endif // OS_WIN | 263 #endif // OS_WIN |
177 | 264 |
178 | 265 |
179 bool ChildProcessHost::CreateChannel() { | 266 bool ChildProcessHost::CreateChannel() { |
180 channel_id_ = ChildProcessInfo::GenerateRandomChannelID(this); | 267 channel_id_ = ChildProcessInfo::GenerateRandomChannelID(this); |
181 channel_.reset(new IPC::Channel( | 268 channel_.reset(new IPC::Channel( |
182 channel_id_, IPC::Channel::MODE_SERVER, &listener_)); | 269 channel_id_, IPC::Channel::MODE_SERVER, &listener_)); |
183 if (!channel_->Connect()) | 270 if (!channel_->Connect()) |
184 return false; | 271 return false; |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
304 for (size_t i = 0; i < host_->filters_.size(); ++i) | 391 for (size_t i = 0; i < host_->filters_.size(); ++i) |
305 host_->filters_[i]->OnChannelError(); | 392 host_->filters_[i]->OnChannelError(); |
306 | 393 |
307 // This will delete host_, which will also destroy this! | 394 // This will delete host_, which will also destroy this! |
308 host_->OnChildDisconnected(); | 395 host_->OnChildDisconnected(); |
309 } | 396 } |
310 | 397 |
311 void ChildProcessHost::ForceShutdown() { | 398 void ChildProcessHost::ForceShutdown() { |
312 Send(new ChildProcessMsg_Shutdown()); | 399 Send(new ChildProcessMsg_Shutdown()); |
313 } | 400 } |
OLD | NEW |