[Sync] Break up the Android BookmarksTest cases more.
[chromium-blink-merge.git] / chrome / utility / chrome_content_utility_client.cc
blob700e6a0d67bf4c1183e3c5261c5b001164d516e7
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_ANDROID) && defined(USE_SECCOMP_BPF)
42 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
43 #endif
45 #if defined(OS_WIN)
46 #include "chrome/utility/font_cache_handler_win.h"
47 #include "chrome/utility/shell_handler_win.h"
48 #endif
50 #if defined(ENABLE_EXTENSIONS)
51 #include "chrome/common/extensions/chrome_utility_extensions_messages.h"
52 #include "chrome/utility/extensions/extensions_handler.h"
53 #include "chrome/utility/image_writer/image_writer_handler.h"
54 #include "chrome/utility/media_galleries/ipc_data_source.h"
55 #include "chrome/utility/media_galleries/media_metadata_parser.h"
56 #endif
58 #if defined(ENABLE_PRINT_PREVIEW) || defined(OS_WIN)
59 #include "chrome/utility/printing_handler.h"
60 #endif
62 #if defined(ENABLE_MDNS)
63 #include "chrome/utility/local_discovery/service_discovery_message_handler.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 #endif
200 #if defined(ENABLE_EXTENSIONS)
201 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseMediaMetadata,
202 OnParseMediaMetadata)
203 #endif
204 #if defined(OS_CHROMEOS)
205 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_CreateZipFile, OnCreateZipFile)
206 #endif
207 #if defined(OS_ANDROID) && defined(USE_SECCOMP_BPF)
208 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_DetectSeccompSupport,
209 OnDetectSeccompSupport)
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 DecodeImageAndSend(encoded_data, shrink_to_fit, request_id);
305 #if defined(OS_CHROMEOS)
306 void ChromeContentUtilityClient::OnCreateZipFile(
307 const base::FilePath& src_dir,
308 const std::vector<base::FilePath>& src_relative_paths,
309 const base::FileDescriptor& dest_fd) {
310 // dest_fd should be closed in the function. See ipc/ipc_message_util.h for
311 // details.
312 base::ScopedFD fd_closer(dest_fd.fd);
313 bool succeeded = true;
315 // Check sanity of source relative paths. Reject if path is absolute or
316 // contains any attempt to reference a parent directory ("../" tricks).
317 for (std::vector<base::FilePath>::const_iterator iter =
318 src_relative_paths.begin(); iter != src_relative_paths.end();
319 ++iter) {
320 if (iter->IsAbsolute() || iter->ReferencesParent()) {
321 succeeded = false;
322 break;
326 if (succeeded)
327 succeeded = zip::ZipFiles(src_dir, src_relative_paths, dest_fd.fd);
329 if (succeeded)
330 Send(new ChromeUtilityHostMsg_CreateZipFile_Succeeded());
331 else
332 Send(new ChromeUtilityHostMsg_CreateZipFile_Failed());
333 ReleaseProcessIfNeeded();
335 #endif // defined(OS_CHROMEOS)
337 #if defined(OS_ANDROID) && defined(USE_SECCOMP_BPF)
338 void ChromeContentUtilityClient::OnDetectSeccompSupport() {
339 bool supports_prctl = sandbox::SandboxBPF::SupportsSeccompSandbox(
340 sandbox::SandboxBPF::SeccompLevel::SINGLE_THREADED);
341 Send(new ChromeUtilityHostMsg_DetectSeccompSupport_ResultPrctl(
342 supports_prctl));
344 // Probing for the seccomp syscall can provoke kernel panics in certain LGE
345 // devices. For now, this data will not be collected. In the future, this
346 // should detect SeccompLevel::MULTI_THREADED. http://crbug.com/478478
348 ReleaseProcessIfNeeded();
350 #endif // defined(OS_ANDROID) && defined(USE_SECCOMP_BPF)
352 #if defined(OS_CHROMEOS)
353 void ChromeContentUtilityClient::OnRobustJPEGDecodeImage(
354 const std::vector<unsigned char>& encoded_data,
355 int request_id) {
356 // Our robust jpeg decoding is using IJG libjpeg.
357 if (!encoded_data.empty()) {
358 scoped_ptr<SkBitmap> decoded_image(gfx::JPEGCodecRobustSlow::Decode(
359 &encoded_data[0], encoded_data.size()));
360 if (!decoded_image.get() || decoded_image->empty()) {
361 Send(new ChromeUtilityHostMsg_DecodeImage_Failed(request_id));
362 } else {
363 Send(new ChromeUtilityHostMsg_DecodeImage_Succeeded(*decoded_image,
364 request_id));
366 } else {
367 Send(new ChromeUtilityHostMsg_DecodeImage_Failed(request_id));
369 ReleaseProcessIfNeeded();
371 #endif // defined(OS_CHROMEOS)
373 void ChromeContentUtilityClient::OnPatchFileBsdiff(
374 const base::FilePath& input_file,
375 const base::FilePath& patch_file,
376 const base::FilePath& output_file) {
377 if (input_file.empty() || patch_file.empty() || output_file.empty()) {
378 Send(new ChromeUtilityHostMsg_PatchFile_Finished(-1));
379 } else {
380 const int patch_status = courgette::ApplyBinaryPatch(input_file,
381 patch_file,
382 output_file);
383 Send(new ChromeUtilityHostMsg_PatchFile_Finished(patch_status));
385 ReleaseProcessIfNeeded();
388 void ChromeContentUtilityClient::OnPatchFileCourgette(
389 const base::FilePath& input_file,
390 const base::FilePath& patch_file,
391 const base::FilePath& output_file) {
392 if (input_file.empty() || patch_file.empty() || output_file.empty()) {
393 Send(new ChromeUtilityHostMsg_PatchFile_Finished(-1));
394 } else {
395 const int patch_status = courgette::ApplyEnsemblePatch(
396 input_file.value().c_str(),
397 patch_file.value().c_str(),
398 output_file.value().c_str());
399 Send(new ChromeUtilityHostMsg_PatchFile_Finished(patch_status));
401 ReleaseProcessIfNeeded();
404 void ChromeContentUtilityClient::OnStartupPing() {
405 Send(new ChromeUtilityHostMsg_ProcessStarted);
406 // Don't release the process, we assume further messages are on the way.
409 #if defined(FULL_SAFE_BROWSING)
410 void ChromeContentUtilityClient::OnAnalyzeZipFileForDownloadProtection(
411 const IPC::PlatformFileForTransit& zip_file,
412 const IPC::PlatformFileForTransit& temp_file) {
413 safe_browsing::zip_analyzer::Results results;
414 safe_browsing::zip_analyzer::AnalyzeZipFile(
415 IPC::PlatformFileForTransitToFile(zip_file),
416 IPC::PlatformFileForTransitToFile(temp_file), &results);
417 Send(new ChromeUtilityHostMsg_AnalyzeZipFileForDownloadProtection_Finished(
418 results));
419 ReleaseProcessIfNeeded();
421 #endif
423 #if defined(ENABLE_EXTENSIONS)
424 // TODO(thestig): Try to move this to
425 // chrome/utility/extensions/extensions_handler.cc.
426 void ChromeContentUtilityClient::OnParseMediaMetadata(
427 const std::string& mime_type, int64 total_size, bool get_attached_images) {
428 // Only one IPCDataSource may be created and added to the list of handlers.
429 metadata::IPCDataSource* source = new metadata::IPCDataSource(total_size);
430 handlers_.push_back(source);
432 metadata::MediaMetadataParser* parser = new metadata::MediaMetadataParser(
433 source, mime_type, get_attached_images);
434 parser->Start(base::Bind(&FinishParseMediaMetadata, base::Owned(parser)));
436 #endif