| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2010 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/common/child_process_host.h" | |
| 6 | |
| 7 #include "base/command_line.h" | |
| 8 #include "base/file_path.h" | |
| 9 #include "base/metrics/histogram.h" | |
| 10 #include "base/path_service.h" | |
| 11 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" | |
| 12 #include "chrome/common/child_process_info.h" | |
| 13 #include "content/common/child_process_messages.h" | |
| 14 #include "content/common/content_paths.h" | |
| 15 #include "content/common/content_switches.h" | |
| 16 #include "ipc/ipc_logging.h" | |
| 17 | |
| 18 #if defined(OS_LINUX) | |
| 19 #include "base/linux_util.h" | |
| 20 #endif // OS_LINUX | |
| 21 | |
| 22 ChildProcessHost::ChildProcessHost() | |
| 23 : ALLOW_THIS_IN_INITIALIZER_LIST(listener_(this)), | |
| 24 opening_channel_(false) { | |
| 25 } | |
| 26 | |
| 27 ChildProcessHost::~ChildProcessHost() { | |
| 28 for (size_t i = 0; i < filters_.size(); ++i) { | |
| 29 filters_[i]->OnChannelClosing(); | |
| 30 filters_[i]->OnFilterRemoved(); | |
| 31 } | |
| 32 } | |
| 33 | |
| 34 void ChildProcessHost::AddFilter(IPC::ChannelProxy::MessageFilter* filter) { | |
| 35 filters_.push_back(filter); | |
| 36 | |
| 37 if (channel_.get()) | |
| 38 filter->OnFilterAdded(channel_.get()); | |
| 39 } | |
| 40 | |
| 41 // static | |
| 42 FilePath ChildProcessHost::GetChildPath(bool allow_self) { | |
| 43 FilePath child_path; | |
| 44 | |
| 45 child_path = CommandLine::ForCurrentProcess()->GetSwitchValuePath( | |
| 46 switches::kBrowserSubprocessPath); | |
| 47 if (!child_path.empty()) | |
| 48 return child_path; | |
| 49 | |
| 50 #if defined(OS_LINUX) | |
| 51 // Use /proc/self/exe rather than our known binary path so updates | |
| 52 // can't swap out the binary from underneath us. | |
| 53 // When running under Valgrind, forking /proc/self/exe ends up forking the | |
| 54 // Valgrind executable, which then crashes. However, it's almost safe to | |
| 55 // assume that the updates won't happen while testing with Valgrind tools. | |
| 56 if (allow_self && !RunningOnValgrind()) | |
| 57 return FilePath("/proc/self/exe"); | |
| 58 #endif | |
| 59 | |
| 60 // On most platforms, the child executable is the same as the current | |
| 61 // executable. | |
| 62 PathService::Get(content::CHILD_PROCESS_EXE, &child_path); | |
| 63 return child_path; | |
| 64 } | |
| 65 | |
| 66 #if defined(OS_WIN) | |
| 67 // static | |
| 68 void ChildProcessHost::PreCacheFont(LOGFONT font) { | |
| 69 // If a child process is running in a sandbox, GetTextMetrics() | |
| 70 // can sometimes fail. If a font has not been loaded | |
| 71 // previously, GetTextMetrics() will try to load the font | |
| 72 // from the font file. However, the sandboxed process does | |
| 73 // not have permissions to access any font files and | |
| 74 // the call fails. So we make the browser pre-load the | |
| 75 // font for us by using a dummy call to GetTextMetrics of | |
| 76 // the same font. | |
| 77 | |
| 78 // Maintain a circular queue for the fonts and DCs to be cached. | |
| 79 // font_index maintains next available location in the queue. | |
| 80 static const int kFontCacheSize = 32; | |
| 81 static HFONT fonts[kFontCacheSize] = {0}; | |
| 82 static HDC hdcs[kFontCacheSize] = {0}; | |
| 83 static size_t font_index = 0; | |
| 84 | |
| 85 UMA_HISTOGRAM_COUNTS_100("Memory.CachedFontAndDC", | |
| 86 fonts[kFontCacheSize-1] ? kFontCacheSize : static_cast<int>(font_index)); | |
| 87 | |
| 88 HDC hdc = GetDC(NULL); | |
| 89 HFONT font_handle = CreateFontIndirect(&font); | |
| 90 DCHECK(NULL != font_handle); | |
| 91 | |
| 92 HGDIOBJ old_font = SelectObject(hdc, font_handle); | |
| 93 DCHECK(NULL != old_font); | |
| 94 | |
| 95 TEXTMETRIC tm; | |
| 96 BOOL ret = GetTextMetrics(hdc, &tm); | |
| 97 DCHECK(ret); | |
| 98 | |
| 99 if (fonts[font_index] || hdcs[font_index]) { | |
| 100 // We already have too many fonts, we will delete one and take it's place. | |
| 101 DeleteObject(fonts[font_index]); | |
| 102 ReleaseDC(NULL, hdcs[font_index]); | |
| 103 } | |
| 104 | |
| 105 fonts[font_index] = font_handle; | |
| 106 hdcs[font_index] = hdc; | |
| 107 font_index = (font_index + 1) % kFontCacheSize; | |
| 108 } | |
| 109 #endif // OS_WIN | |
| 110 | |
| 111 | |
| 112 bool ChildProcessHost::CreateChannel() { | |
| 113 channel_id_ = ChildProcessInfo::GenerateRandomChannelID(this); | |
| 114 channel_.reset(new IPC::Channel( | |
| 115 channel_id_, IPC::Channel::MODE_SERVER, &listener_)); | |
| 116 if (!channel_->Connect()) | |
| 117 return false; | |
| 118 | |
| 119 for (size_t i = 0; i < filters_.size(); ++i) | |
| 120 filters_[i]->OnFilterAdded(channel_.get()); | |
| 121 | |
| 122 // Make sure these messages get sent first. | |
| 123 #if defined(IPC_MESSAGE_LOG_ENABLED) | |
| 124 bool enabled = IPC::Logging::GetInstance()->Enabled(); | |
| 125 Send(new ChildProcessMsg_SetIPCLoggingEnabled(enabled)); | |
| 126 #endif | |
| 127 | |
| 128 Send(new ChildProcessMsg_AskBeforeShutdown()); | |
| 129 | |
| 130 opening_channel_ = true; | |
| 131 | |
| 132 return true; | |
| 133 } | |
| 134 | |
| 135 void ChildProcessHost::InstanceCreated() { | |
| 136 Notify(NotificationType::CHILD_INSTANCE_CREATED); | |
| 137 } | |
| 138 | |
| 139 bool ChildProcessHost::OnMessageReceived(const IPC::Message& msg) { | |
| 140 return false; | |
| 141 } | |
| 142 | |
| 143 void ChildProcessHost::OnChannelConnected(int32 peer_pid) { | |
| 144 } | |
| 145 | |
| 146 void ChildProcessHost::OnChannelError() { | |
| 147 } | |
| 148 | |
| 149 bool ChildProcessHost::Send(IPC::Message* message) { | |
| 150 if (!channel_.get()) { | |
| 151 delete message; | |
| 152 return false; | |
| 153 } | |
| 154 return channel_->Send(message); | |
| 155 } | |
| 156 | |
| 157 void ChildProcessHost::OnChildDied() { | |
| 158 delete this; | |
| 159 } | |
| 160 | |
| 161 void ChildProcessHost::ShutdownStarted() { | |
| 162 } | |
| 163 | |
| 164 void ChildProcessHost::Notify(NotificationType type) { | |
| 165 } | |
| 166 | |
| 167 ChildProcessHost::ListenerHook::ListenerHook(ChildProcessHost* host) | |
| 168 : host_(host) { | |
| 169 } | |
| 170 | |
| 171 bool ChildProcessHost::ListenerHook::OnMessageReceived( | |
| 172 const IPC::Message& msg) { | |
| 173 #ifdef IPC_MESSAGE_LOG_ENABLED | |
| 174 IPC::Logging* logger = IPC::Logging::GetInstance(); | |
| 175 if (msg.type() == IPC_LOGGING_ID) { | |
| 176 logger->OnReceivedLoggingMessage(msg); | |
| 177 return true; | |
| 178 } | |
| 179 | |
| 180 if (logger->Enabled()) | |
| 181 logger->OnPreDispatchMessage(msg); | |
| 182 #endif | |
| 183 | |
| 184 bool handled = false; | |
| 185 for (size_t i = 0; i < host_->filters_.size(); ++i) { | |
| 186 if (host_->filters_[i]->OnMessageReceived(msg)) { | |
| 187 handled = true; | |
| 188 break; | |
| 189 } | |
| 190 } | |
| 191 | |
| 192 if (!handled && msg.type() == ChildProcessHostMsg_ShutdownRequest::ID) { | |
| 193 if (host_->CanShutdown()) | |
| 194 host_->Send(new ChildProcessMsg_Shutdown()); | |
| 195 handled = true; | |
| 196 } | |
| 197 | |
| 198 if (!handled) | |
| 199 handled = host_->OnMessageReceived(msg); | |
| 200 | |
| 201 #ifdef IPC_MESSAGE_LOG_ENABLED | |
| 202 if (logger->Enabled()) | |
| 203 logger->OnPostDispatchMessage(msg, host_->channel_id_); | |
| 204 #endif | |
| 205 return handled; | |
| 206 } | |
| 207 | |
| 208 void ChildProcessHost::ListenerHook::OnChannelConnected(int32 peer_pid) { | |
| 209 host_->opening_channel_ = false; | |
| 210 host_->OnChannelConnected(peer_pid); | |
| 211 // Notify in the main loop of the connection. | |
| 212 host_->Notify(NotificationType::CHILD_PROCESS_HOST_CONNECTED); | |
| 213 | |
| 214 for (size_t i = 0; i < host_->filters_.size(); ++i) | |
| 215 host_->filters_[i]->OnChannelConnected(peer_pid); | |
| 216 } | |
| 217 | |
| 218 void ChildProcessHost::ListenerHook::OnChannelError() { | |
| 219 host_->opening_channel_ = false; | |
| 220 host_->OnChannelError(); | |
| 221 | |
| 222 for (size_t i = 0; i < host_->filters_.size(); ++i) | |
| 223 host_->filters_[i]->OnChannelError(); | |
| 224 | |
| 225 // This will delete host_, which will also destroy this! | |
| 226 host_->OnChildDied(); | |
| 227 } | |
| 228 | |
| 229 void ChildProcessHost::ForceShutdown() { | |
| 230 Send(new ChildProcessMsg_Shutdown()); | |
| 231 } | |
| OLD | NEW |