Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / chrome / utility / chrome_content_utility_client.cc
blob3d09c61f611b5fccba435eb6e103f3064e794112
1 // Copyright (c) 2012 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.
5 #include "chrome/utility/chrome_content_utility_client.h"
7 #include "base/command_line.h"
8 #include "base/files/file_path.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/time/time.h"
11 #include "chrome/common/chrome_utility_messages.h"
12 #include "chrome/common/safe_browsing/zip_analyzer.h"
13 #include "chrome/common/safe_browsing/zip_analyzer_results.h"
14 #include "chrome/utility/chrome_content_utility_ipc_whitelist.h"
15 #include "chrome/utility/safe_json_parser_handler.h"
16 #include "chrome/utility/utility_message_handler.h"
17 #include "content/public/child/image_decoder_utils.h"
18 #include "content/public/common/content_switches.h"
19 #include "content/public/common/service_registry.h"
20 #include "content/public/utility/utility_thread.h"
21 #include "courgette/courgette.h"
22 #include "courgette/third_party/bsdiff.h"
23 #include "ipc/ipc_channel.h"
24 #include "skia/ext/image_operations.h"
25 #include "third_party/skia/include/core/SkBitmap.h"
26 #include "third_party/zlib/google/zip.h"
27 #include "ui/gfx/geometry/size.h"
29 #if defined(OS_CHROMEOS)
30 #include "ui/gfx/chromeos/codec/jpeg_codec_robust_slow.h"
31 #endif
33 #if !defined(OS_ANDROID)
34 #include "chrome/common/resource_usage_reporter.mojom.h"
35 #include "chrome/utility/profile_import_handler.h"
36 #include "net/proxy/mojo_proxy_resolver_factory_impl.h"
37 #include "net/proxy/proxy_resolver_v8.h"
38 #include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h"
39 #endif
41 #if defined(OS_WIN)
42 #include "chrome/utility/font_cache_handler_win.h"
43 #include "chrome/utility/shell_handler_win.h"
44 #endif
46 #if defined(ENABLE_EXTENSIONS)
47 #include "chrome/common/extensions/chrome_utility_extensions_messages.h"
48 #include "chrome/utility/extensions/extensions_handler.h"
49 #include "chrome/utility/image_writer/image_writer_handler.h"
50 #include "chrome/utility/media_galleries/ipc_data_source.h"
51 #include "chrome/utility/media_galleries/media_metadata_parser.h"
52 #endif
54 #if defined(ENABLE_PRINT_PREVIEW) || defined(OS_WIN)
55 #include "chrome/utility/printing_handler.h"
56 #endif
58 #if defined(ENABLE_MDNS)
59 #include "chrome/utility/local_discovery/service_discovery_message_handler.h"
60 #endif
62 #if defined(OS_MACOSX) && defined(FULL_SAFE_BROWSING)
63 #include "chrome/utility/safe_browsing/mac/dmg_analyzer.h"
64 #endif
66 namespace {
68 bool Send(IPC::Message* message) {
69 return content::UtilityThread::Get()->Send(message);
72 void ReleaseProcessIfNeeded() {
73 content::UtilityThread::Get()->ReleaseProcessIfNeeded();
76 #if defined(ENABLE_EXTENSIONS)
77 void FinishParseMediaMetadata(
78 metadata::MediaMetadataParser* /* parser */,
79 const extensions::api::media_galleries::MediaMetadata& metadata,
80 const std::vector<metadata::AttachedImage>& attached_images) {
81 Send(new ChromeUtilityHostMsg_ParseMediaMetadata_Finished(
82 true, *metadata.ToValue(), attached_images));
83 ReleaseProcessIfNeeded();
85 #endif
87 #if !defined(OS_ANDROID)
88 void CreateProxyResolverFactory(
89 mojo::InterfaceRequest<net::interfaces::ProxyResolverFactory> request) {
90 // MojoProxyResolverFactoryImpl is strongly bound to the Mojo message pipe it
91 // is connected to. When that message pipe is closed, either explicitly on the
92 // other end (in the browser process), or by a connection error, this object
93 // will be destroyed.
94 new net::MojoProxyResolverFactoryImpl(request.Pass());
97 class ResourceUsageReporterImpl : public ResourceUsageReporter {
98 public:
99 explicit ResourceUsageReporterImpl(
100 mojo::InterfaceRequest<ResourceUsageReporter> req)
101 : binding_(this, req.Pass()) {}
102 ~ResourceUsageReporterImpl() override {}
104 private:
105 void GetUsageData(
106 const mojo::Callback<void(ResourceUsageDataPtr)>& callback) override {
107 ResourceUsageDataPtr data = ResourceUsageData::New();
108 size_t total_heap_size = net::ProxyResolverV8::GetTotalHeapSize();
109 if (total_heap_size) {
110 data->reports_v8_stats = true;
111 data->v8_bytes_allocated = total_heap_size;
112 data->v8_bytes_used = net::ProxyResolverV8::GetUsedHeapSize();
114 callback.Run(data.Pass());
117 mojo::StrongBinding<ResourceUsageReporter> binding_;
120 void CreateResourceUsageReporter(
121 mojo::InterfaceRequest<ResourceUsageReporter> request) {
122 new ResourceUsageReporterImpl(request.Pass());
124 #endif // OS_ANDROID
126 } // namespace
128 int64_t ChromeContentUtilityClient::max_ipc_message_size_ =
129 IPC::Channel::kMaximumMessageSize;
131 ChromeContentUtilityClient::ChromeContentUtilityClient()
132 : filter_messages_(false) {
133 #if !defined(OS_ANDROID)
134 handlers_.push_back(new ProfileImportHandler());
135 #endif
137 #if defined(ENABLE_EXTENSIONS)
138 handlers_.push_back(new extensions::ExtensionsHandler());
139 handlers_.push_back(new image_writer::ImageWriterHandler());
140 #endif
142 #if defined(ENABLE_PRINT_PREVIEW) || defined(OS_WIN)
143 handlers_.push_back(new PrintingHandler());
144 #endif
146 #if defined(ENABLE_MDNS)
147 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
148 switches::kUtilityProcessEnableMDns)) {
149 handlers_.push_back(new local_discovery::ServiceDiscoveryMessageHandler());
151 #endif
153 #if defined(OS_WIN)
154 handlers_.push_back(new ShellHandler());
155 handlers_.push_back(new FontCacheHandler());
156 #endif
158 handlers_.push_back(new SafeJsonParserHandler());
161 ChromeContentUtilityClient::~ChromeContentUtilityClient() {
164 void ChromeContentUtilityClient::UtilityThreadStarted() {
165 #if defined(ENABLE_EXTENSIONS)
166 extensions::UtilityHandler::UtilityThreadStarted();
167 #endif
169 if (kMessageWhitelistSize > 0) {
170 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
171 if (command_line->HasSwitch(switches::kUtilityProcessRunningElevated)) {
172 message_id_whitelist_.insert(kMessageWhitelist,
173 kMessageWhitelist + kMessageWhitelistSize);
174 filter_messages_ = true;
179 bool ChromeContentUtilityClient::OnMessageReceived(
180 const IPC::Message& message) {
181 if (filter_messages_ && !ContainsKey(message_id_whitelist_, message.type()))
182 return false;
184 bool handled = true;
185 IPC_BEGIN_MESSAGE_MAP(ChromeContentUtilityClient, message)
186 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_DecodeImage, OnDecodeImage)
187 #if defined(OS_CHROMEOS)
188 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RobustJPEGDecodeImage,
189 OnRobustJPEGDecodeImage)
190 #endif // defined(OS_CHROMEOS)
191 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_PatchFileBsdiff,
192 OnPatchFileBsdiff)
193 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_PatchFileCourgette,
194 OnPatchFileCourgette)
195 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_StartupPing, OnStartupPing)
196 #if defined(FULL_SAFE_BROWSING)
197 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_AnalyzeZipFileForDownloadProtection,
198 OnAnalyzeZipFileForDownloadProtection)
199 #if defined(OS_MACOSX)
200 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_AnalyzeDmgFileForDownloadProtection,
201 OnAnalyzeDmgFileForDownloadProtection)
202 #endif
203 #endif
204 #if defined(ENABLE_EXTENSIONS)
205 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseMediaMetadata,
206 OnParseMediaMetadata)
207 #endif
208 #if defined(OS_CHROMEOS)
209 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_CreateZipFile, OnCreateZipFile)
210 #endif
211 IPC_MESSAGE_UNHANDLED(handled = false)
212 IPC_END_MESSAGE_MAP()
214 for (Handlers::iterator it = handlers_.begin();
215 !handled && it != handlers_.end(); ++it) {
216 handled = (*it)->OnMessageReceived(message);
219 return handled;
222 void ChromeContentUtilityClient::RegisterMojoServices(
223 content::ServiceRegistry* registry) {
224 #if !defined(OS_ANDROID)
225 registry->AddService<net::interfaces::ProxyResolverFactory>(
226 base::Bind(CreateProxyResolverFactory));
227 registry->AddService<ResourceUsageReporter>(
228 base::Bind(CreateResourceUsageReporter));
229 #endif
232 // static
233 void ChromeContentUtilityClient::PreSandboxStartup() {
234 #if defined(ENABLE_EXTENSIONS)
235 extensions::ExtensionsHandler::PreSandboxStartup();
236 #endif
238 #if defined(ENABLE_MDNS)
239 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
240 switches::kUtilityProcessEnableMDns)) {
241 local_discovery::ServiceDiscoveryMessageHandler::PreSandboxStartup();
243 #endif // ENABLE_MDNS
246 // static
247 SkBitmap ChromeContentUtilityClient::DecodeImage(
248 const std::vector<unsigned char>& encoded_data, bool shrink_to_fit) {
249 SkBitmap decoded_image;
250 if (encoded_data.empty())
251 return decoded_image;
253 decoded_image = content::DecodeImage(&encoded_data[0],
254 gfx::Size(),
255 encoded_data.size());
257 int64_t struct_size = sizeof(ChromeUtilityHostMsg_DecodeImage_Succeeded);
258 int64_t image_size = decoded_image.computeSize64();
259 int halves = 0;
260 while (struct_size + (image_size >> 2*halves) > max_ipc_message_size_)
261 halves++;
262 if (halves) {
263 if (shrink_to_fit) {
264 // If decoded image is too large for IPC message, shrink it by halves.
265 // This prevents quality loss, and should never overshrink on displays
266 // smaller than 3600x2400.
267 // TODO (Issue 416916): Instead of shrinking, return via shared memory
268 decoded_image = skia::ImageOperations::Resize(
269 decoded_image, skia::ImageOperations::RESIZE_LANCZOS3,
270 decoded_image.width() >> halves, decoded_image.height() >> halves);
271 } else {
272 // Image too big for IPC message, but caller didn't request resize;
273 // pre-delete image so DecodeImageAndSend() will send an error.
274 decoded_image.reset();
275 LOG(ERROR) << "Decoded image too large for IPC message";
279 return decoded_image;
282 // static
283 void ChromeContentUtilityClient::DecodeImageAndSend(
284 const std::vector<unsigned char>& encoded_data,
285 bool shrink_to_fit,
286 int request_id) {
287 SkBitmap decoded_image = DecodeImage(encoded_data, shrink_to_fit);
289 if (decoded_image.empty()) {
290 Send(new ChromeUtilityHostMsg_DecodeImage_Failed(request_id));
291 } else {
292 Send(new ChromeUtilityHostMsg_DecodeImage_Succeeded(decoded_image,
293 request_id));
295 ReleaseProcessIfNeeded();
298 void ChromeContentUtilityClient::OnDecodeImage(
299 const std::vector<unsigned char>& encoded_data,
300 bool shrink_to_fit,
301 int request_id) {
302 content::UtilityThread::Get()->EnsureBlinkInitialized();
303 DecodeImageAndSend(encoded_data, shrink_to_fit, request_id);
306 #if defined(OS_CHROMEOS)
307 void ChromeContentUtilityClient::OnCreateZipFile(
308 const base::FilePath& src_dir,
309 const std::vector<base::FilePath>& src_relative_paths,
310 const base::FileDescriptor& dest_fd) {
311 // dest_fd should be closed in the function. See ipc/ipc_message_util.h for
312 // details.
313 base::ScopedFD fd_closer(dest_fd.fd);
314 bool succeeded = true;
316 // Check sanity of source relative paths. Reject if path is absolute or
317 // contains any attempt to reference a parent directory ("../" tricks).
318 for (std::vector<base::FilePath>::const_iterator iter =
319 src_relative_paths.begin(); iter != src_relative_paths.end();
320 ++iter) {
321 if (iter->IsAbsolute() || iter->ReferencesParent()) {
322 succeeded = false;
323 break;
327 if (succeeded)
328 succeeded = zip::ZipFiles(src_dir, src_relative_paths, dest_fd.fd);
330 if (succeeded)
331 Send(new ChromeUtilityHostMsg_CreateZipFile_Succeeded());
332 else
333 Send(new ChromeUtilityHostMsg_CreateZipFile_Failed());
334 ReleaseProcessIfNeeded();
336 #endif // defined(OS_CHROMEOS)
338 #if defined(OS_CHROMEOS)
339 void ChromeContentUtilityClient::OnRobustJPEGDecodeImage(
340 const std::vector<unsigned char>& encoded_data,
341 int request_id) {
342 // Our robust jpeg decoding is using IJG libjpeg.
343 if (!encoded_data.empty()) {
344 scoped_ptr<SkBitmap> decoded_image(gfx::JPEGCodecRobustSlow::Decode(
345 &encoded_data[0], encoded_data.size()));
346 if (!decoded_image.get() || decoded_image->empty()) {
347 Send(new ChromeUtilityHostMsg_DecodeImage_Failed(request_id));
348 } else {
349 Send(new ChromeUtilityHostMsg_DecodeImage_Succeeded(*decoded_image,
350 request_id));
352 } else {
353 Send(new ChromeUtilityHostMsg_DecodeImage_Failed(request_id));
355 ReleaseProcessIfNeeded();
357 #endif // defined(OS_CHROMEOS)
359 void ChromeContentUtilityClient::OnPatchFileBsdiff(
360 const base::FilePath& input_file,
361 const base::FilePath& patch_file,
362 const base::FilePath& output_file) {
363 if (input_file.empty() || patch_file.empty() || output_file.empty()) {
364 Send(new ChromeUtilityHostMsg_PatchFile_Finished(-1));
365 } else {
366 const int patch_status = courgette::ApplyBinaryPatch(input_file,
367 patch_file,
368 output_file);
369 Send(new ChromeUtilityHostMsg_PatchFile_Finished(patch_status));
371 ReleaseProcessIfNeeded();
374 void ChromeContentUtilityClient::OnPatchFileCourgette(
375 const base::FilePath& input_file,
376 const base::FilePath& patch_file,
377 const base::FilePath& output_file) {
378 if (input_file.empty() || patch_file.empty() || output_file.empty()) {
379 Send(new ChromeUtilityHostMsg_PatchFile_Finished(-1));
380 } else {
381 const int patch_status = courgette::ApplyEnsemblePatch(
382 input_file.value().c_str(),
383 patch_file.value().c_str(),
384 output_file.value().c_str());
385 Send(new ChromeUtilityHostMsg_PatchFile_Finished(patch_status));
387 ReleaseProcessIfNeeded();
390 void ChromeContentUtilityClient::OnStartupPing() {
391 Send(new ChromeUtilityHostMsg_ProcessStarted);
392 // Don't release the process, we assume further messages are on the way.
395 #if defined(FULL_SAFE_BROWSING)
396 void ChromeContentUtilityClient::OnAnalyzeZipFileForDownloadProtection(
397 const IPC::PlatformFileForTransit& zip_file,
398 const IPC::PlatformFileForTransit& temp_file) {
399 safe_browsing::zip_analyzer::Results results;
400 safe_browsing::zip_analyzer::AnalyzeZipFile(
401 IPC::PlatformFileForTransitToFile(zip_file),
402 IPC::PlatformFileForTransitToFile(temp_file), &results);
403 Send(new ChromeUtilityHostMsg_AnalyzeZipFileForDownloadProtection_Finished(
404 results));
405 ReleaseProcessIfNeeded();
408 #if defined(OS_MACOSX)
409 void ChromeContentUtilityClient::OnAnalyzeDmgFileForDownloadProtection(
410 const IPC::PlatformFileForTransit& dmg_file) {
411 safe_browsing::zip_analyzer::Results results;
412 safe_browsing::dmg::AnalyzeDMGFile(
413 IPC::PlatformFileForTransitToFile(dmg_file), &results);
414 Send(new ChromeUtilityHostMsg_AnalyzeDmgFileForDownloadProtection_Finished(
415 results));
416 ReleaseProcessIfNeeded();
418 #endif
420 #endif
422 #if defined(ENABLE_EXTENSIONS)
423 // TODO(thestig): Try to move this to
424 // chrome/utility/extensions/extensions_handler.cc.
425 void ChromeContentUtilityClient::OnParseMediaMetadata(
426 const std::string& mime_type, int64 total_size, bool get_attached_images) {
427 // Only one IPCDataSource may be created and added to the list of handlers.
428 metadata::IPCDataSource* source = new metadata::IPCDataSource(total_size);
429 handlers_.push_back(source);
431 metadata::MediaMetadataParser* parser = new metadata::MediaMetadataParser(
432 source, mime_type, get_attached_images);
433 parser->Start(base::Bind(&FinishParseMediaMetadata, base::Owned(parser)));
435 #endif