utility_process_host.cc revision dc0f95d653279beabeb9817299e2902918ba123e
1// Copyright (c) 2009 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/utility_process_host.h" 6 7#include "app/app_switches.h" 8#include "base/command_line.h" 9#include "base/file_util.h" 10#include "base/message_loop.h" 11#include "base/values.h" 12#include "chrome/browser/browser_process.h" 13#include "chrome/common/chrome_switches.h" 14#include "chrome/common/indexed_db_key.h" 15#include "chrome/common/serialized_script_value.h" 16#include "chrome/common/utility_messages.h" 17#include "ipc/ipc_switches.h" 18#include "third_party/skia/include/core/SkBitmap.h" 19#include "ui/base/ui_base_switches.h" 20 21UtilityProcessHost::UtilityProcessHost(ResourceDispatcherHost* rdh, 22 Client* client, 23 BrowserThread::ID client_thread_id) 24 : BrowserChildProcessHost(UTILITY_PROCESS, rdh), 25 client_(client), 26 client_thread_id_(client_thread_id), 27 is_batch_mode_(false) { 28} 29 30UtilityProcessHost::~UtilityProcessHost() { 31 DCHECK(!is_batch_mode_); 32} 33 34bool UtilityProcessHost::StartExtensionUnpacker(const FilePath& extension) { 35 // Grant the subprocess access to the entire subdir the extension file is 36 // in, so that it can unpack to that dir. 37 if (!StartProcess(extension.DirName())) 38 return false; 39 40 Send(new UtilityMsg_UnpackExtension(extension)); 41 return true; 42} 43 44bool UtilityProcessHost::StartWebResourceUnpacker(const std::string& data) { 45 if (!StartProcess(FilePath())) 46 return false; 47 48 Send(new UtilityMsg_UnpackWebResource(data)); 49 return true; 50} 51 52bool UtilityProcessHost::StartUpdateManifestParse(const std::string& xml) { 53 if (!StartProcess(FilePath())) 54 return false; 55 56 Send(new UtilityMsg_ParseUpdateManifest(xml)); 57 return true; 58} 59 60bool UtilityProcessHost::StartImageDecoding( 61 const std::vector<unsigned char>& encoded_data) { 62 if (!StartProcess(FilePath())) 63 return false; 64 65 Send(new UtilityMsg_DecodeImage(encoded_data)); 66 return true; 67} 68 69bool UtilityProcessHost::StartIDBKeysFromValuesAndKeyPath( 70 int id, const std::vector<SerializedScriptValue>& serialized_values, 71 const string16& key_path) { 72 if (!StartProcess(FilePath())) 73 return false; 74 75 Send(new UtilityMsg_IDBKeysFromValuesAndKeyPath( 76 id, serialized_values, key_path)); 77 return true; 78} 79 80bool UtilityProcessHost::StartInjectIDBKey( 81 const IndexedDBKey& key, const SerializedScriptValue& value, 82 const string16& key_path) { 83 if (!StartProcess(FilePath())) 84 return false; 85 86 Send(new UtilityMsg_InjectIDBKey(key, value, key_path)); 87 return true; 88} 89 90bool UtilityProcessHost::StartBatchMode() { 91 CHECK(!is_batch_mode_); 92 is_batch_mode_ = StartProcess(FilePath()); 93 Send(new UtilityMsg_BatchMode_Started()); 94 return is_batch_mode_; 95} 96 97void UtilityProcessHost::EndBatchMode() { 98 CHECK(is_batch_mode_); 99 is_batch_mode_ = false; 100 Send(new UtilityMsg_BatchMode_Finished()); 101} 102 103FilePath UtilityProcessHost::GetUtilityProcessCmd() { 104 return GetChildPath(true); 105} 106 107bool UtilityProcessHost::StartProcess(const FilePath& exposed_dir) { 108 if (is_batch_mode_) 109 return true; 110 // Name must be set or metrics_service will crash in any test which 111 // launches a UtilityProcessHost. 112 set_name(L"utility process"); 113 114 if (!CreateChannel()) 115 return false; 116 117 FilePath exe_path = GetUtilityProcessCmd(); 118 if (exe_path.empty()) { 119 NOTREACHED() << "Unable to get utility process binary name."; 120 return false; 121 } 122 123 CommandLine* cmd_line = new CommandLine(exe_path); 124 cmd_line->AppendSwitchASCII(switches::kProcessType, 125 switches::kUtilityProcess); 126 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id()); 127 std::string locale = g_browser_process->GetApplicationLocale(); 128 cmd_line->AppendSwitchASCII(switches::kLang, locale); 129 130 SetCrashReporterCommandLine(cmd_line); 131 132 const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); 133 if (browser_command_line.HasSwitch(switches::kChromeFrame)) 134 cmd_line->AppendSwitch(switches::kChromeFrame); 135 if (browser_command_line.HasSwitch(switches::kNoSandbox)) 136 cmd_line->AppendSwitch(switches::kNoSandbox); 137 138 if (browser_command_line.HasSwitch( 139 switches::kEnableExperimentalExtensionApis)) { 140 cmd_line->AppendSwitch(switches::kEnableExperimentalExtensionApis); 141 } 142 143#if defined(OS_POSIX) 144 // TODO(port): Sandbox this on Linux. Also, zygote this to work with 145 // Linux updating. 146 bool has_cmd_prefix = browser_command_line.HasSwitch( 147 switches::kUtilityCmdPrefix); 148 if (has_cmd_prefix) { 149 // launch the utility child process with some prefix (usually "xterm -e gdb 150 // --args"). 151 cmd_line->PrependWrapper(browser_command_line.GetSwitchValueNative( 152 switches::kUtilityCmdPrefix)); 153 } 154 155 cmd_line->AppendSwitchPath(switches::kUtilityProcessAllowedDir, exposed_dir); 156#endif 157 158 Launch( 159#if defined(OS_WIN) 160 exposed_dir, 161#elif defined(OS_POSIX) 162 false, 163 base::environment_vector(), 164#endif 165 cmd_line); 166 167 return true; 168} 169 170bool UtilityProcessHost::OnMessageReceived(const IPC::Message& message) { 171 BrowserThread::PostTask( 172 client_thread_id_, FROM_HERE, 173 NewRunnableMethod(client_.get(), &Client::OnMessageReceived, message)); 174 return true; 175} 176 177void UtilityProcessHost::OnProcessCrashed(int exit_code) { 178 BrowserThread::PostTask( 179 client_thread_id_, FROM_HERE, 180 NewRunnableMethod(client_.get(), &Client::OnProcessCrashed, exit_code)); 181} 182 183bool UtilityProcessHost::CanShutdown() { 184 return true; 185} 186 187bool UtilityProcessHost::Client::OnMessageReceived( 188 const IPC::Message& message) { 189 bool handled = true; 190 IPC_BEGIN_MESSAGE_MAP(UtilityProcessHost, message) 191 IPC_MESSAGE_HANDLER(UtilityHostMsg_UnpackExtension_Succeeded, 192 Client::OnUnpackExtensionSucceeded) 193 IPC_MESSAGE_HANDLER(UtilityHostMsg_UnpackExtension_Failed, 194 Client::OnUnpackExtensionFailed) 195 IPC_MESSAGE_HANDLER(UtilityHostMsg_UnpackWebResource_Succeeded, 196 Client::OnUnpackWebResourceSucceeded) 197 IPC_MESSAGE_HANDLER(UtilityHostMsg_UnpackWebResource_Failed, 198 Client::OnUnpackWebResourceFailed) 199 IPC_MESSAGE_HANDLER(UtilityHostMsg_ParseUpdateManifest_Succeeded, 200 Client::OnParseUpdateManifestSucceeded) 201 IPC_MESSAGE_HANDLER(UtilityHostMsg_ParseUpdateManifest_Failed, 202 Client::OnParseUpdateManifestFailed) 203 IPC_MESSAGE_HANDLER(UtilityHostMsg_DecodeImage_Succeeded, 204 Client::OnDecodeImageSucceeded) 205 IPC_MESSAGE_HANDLER(UtilityHostMsg_DecodeImage_Failed, 206 Client::OnDecodeImageFailed) 207 IPC_MESSAGE_HANDLER(UtilityHostMsg_IDBKeysFromValuesAndKeyPath_Succeeded, 208 Client::OnIDBKeysFromValuesAndKeyPathSucceeded) 209 IPC_MESSAGE_HANDLER(UtilityHostMsg_IDBKeysFromValuesAndKeyPath_Failed, 210 Client::OnIDBKeysFromValuesAndKeyPathFailed) 211 IPC_MESSAGE_HANDLER(UtilityHostMsg_InjectIDBKey_Finished, 212 Client::OnInjectIDBKeyFinished) 213 IPC_MESSAGE_UNHANDLED(handled = false) 214 IPC_END_MESSAGE_MAP_EX() 215 return handled; 216} 217