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