Check that only a single delegate for the Android PolicyProvider exists.
[chromium-blink-merge.git] / chrome / utility / chrome_content_utility_client.cc
bloba9c67a133c7e1a4f4dec099deca72bc820651e0b
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/json/json_reader.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/time/time.h"
12 #include "chrome/common/chrome_utility_messages.h"
13 #include "chrome/common/safe_browsing/zip_analyzer.h"
14 #include "chrome/common/safe_browsing/zip_analyzer_results.h"
15 #include "chrome/utility/chrome_content_utility_ipc_whitelist.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/utility/profile_import_handler.h"
35 #include "net/proxy/mojo_proxy_resolver_factory_impl.h"
36 #endif
38 #if defined(OS_ANDROID) && defined(USE_SECCOMP_BPF)
39 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
40 #endif
42 #if defined(OS_WIN)
43 #include "chrome/utility/font_cache_handler_win.h"
44 #include "chrome/utility/shell_handler_win.h"
45 #endif
47 #if defined(ENABLE_EXTENSIONS)
48 #include "chrome/common/extensions/chrome_utility_extensions_messages.h"
49 #include "chrome/utility/extensions/extensions_handler.h"
50 #include "chrome/utility/image_writer/image_writer_handler.h"
51 #include "chrome/utility/media_galleries/ipc_data_source.h"
52 #include "chrome/utility/media_galleries/media_metadata_parser.h"
53 #endif
55 #if defined(ENABLE_PRINT_PREVIEW) || defined(OS_WIN)
56 #include "chrome/utility/printing_handler.h"
57 #endif
59 #if defined(ENABLE_MDNS)
60 #include "chrome/utility/local_discovery/service_discovery_message_handler.h"
61 #endif
63 namespace {
65 bool Send(IPC::Message* message) {
66 return content::UtilityThread::Get()->Send(message);
69 void ReleaseProcessIfNeeded() {
70 content::UtilityThread::Get()->ReleaseProcessIfNeeded();
73 #if defined(ENABLE_EXTENSIONS)
74 void FinishParseMediaMetadata(
75 metadata::MediaMetadataParser* /* parser */,
76 const extensions::api::media_galleries::MediaMetadata& metadata,
77 const std::vector<metadata::AttachedImage>& attached_images) {
78 Send(new ChromeUtilityHostMsg_ParseMediaMetadata_Finished(
79 true, *metadata.ToValue(), attached_images));
80 ReleaseProcessIfNeeded();
82 #endif
84 #if !defined(OS_ANDROID)
85 void CreateProxyResolverFactory(
86 mojo::InterfaceRequest<net::interfaces::ProxyResolverFactory> request) {
87 // MojoProxyResolverFactoryImpl is strongly bound to the Mojo message pipe it
88 // is connected to. When that message pipe is closed, either explicitly on the
89 // other end (in the browser process), or by a connection error, this object
90 // will be destroyed.
91 new net::MojoProxyResolverFactoryImpl(request.Pass());
93 #endif // OS_ANDROID
95 } // namespace
97 int64_t ChromeContentUtilityClient::max_ipc_message_size_ =
98 IPC::Channel::kMaximumMessageSize;
100 ChromeContentUtilityClient::ChromeContentUtilityClient()
101 : filter_messages_(false) {
102 #if !defined(OS_ANDROID)
103 handlers_.push_back(new ProfileImportHandler());
104 #endif
106 #if defined(ENABLE_EXTENSIONS)
107 handlers_.push_back(new extensions::ExtensionsHandler());
108 handlers_.push_back(new image_writer::ImageWriterHandler());
109 #endif
111 #if defined(ENABLE_PRINT_PREVIEW) || defined(OS_WIN)
112 handlers_.push_back(new PrintingHandler());
113 #endif
115 #if defined(ENABLE_MDNS)
116 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
117 switches::kUtilityProcessEnableMDns)) {
118 handlers_.push_back(new local_discovery::ServiceDiscoveryMessageHandler());
120 #endif
122 #if defined(OS_WIN)
123 handlers_.push_back(new ShellHandler());
124 handlers_.push_back(new FontCacheHandler());
125 #endif
128 ChromeContentUtilityClient::~ChromeContentUtilityClient() {
131 void ChromeContentUtilityClient::UtilityThreadStarted() {
132 #if defined(ENABLE_EXTENSIONS)
133 extensions::UtilityHandler::UtilityThreadStarted();
134 #endif
136 if (kMessageWhitelistSize > 0) {
137 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
138 if (command_line->HasSwitch(switches::kUtilityProcessRunningElevated)) {
139 message_id_whitelist_.insert(kMessageWhitelist,
140 kMessageWhitelist + kMessageWhitelistSize);
141 filter_messages_ = true;
146 bool ChromeContentUtilityClient::OnMessageReceived(
147 const IPC::Message& message) {
148 if (filter_messages_ && !ContainsKey(message_id_whitelist_, message.type()))
149 return false;
151 bool handled = true;
152 IPC_BEGIN_MESSAGE_MAP(ChromeContentUtilityClient, message)
153 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_DecodeImage, OnDecodeImage)
154 #if defined(OS_CHROMEOS)
155 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RobustJPEGDecodeImage,
156 OnRobustJPEGDecodeImage)
157 #endif // defined(OS_CHROMEOS)
158 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseJSON, OnParseJSON)
159 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_PatchFileBsdiff,
160 OnPatchFileBsdiff)
161 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_PatchFileCourgette,
162 OnPatchFileCourgette)
163 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_StartupPing, OnStartupPing)
164 #if defined(FULL_SAFE_BROWSING)
165 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_AnalyzeZipFileForDownloadProtection,
166 OnAnalyzeZipFileForDownloadProtection)
167 #endif
168 #if defined(ENABLE_EXTENSIONS)
169 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseMediaMetadata,
170 OnParseMediaMetadata)
171 #endif
172 #if defined(OS_CHROMEOS)
173 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_CreateZipFile, OnCreateZipFile)
174 #endif
175 #if defined(OS_ANDROID) && defined(USE_SECCOMP_BPF)
176 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_DetectSeccompSupport,
177 OnDetectSeccompSupport)
178 #endif
179 IPC_MESSAGE_UNHANDLED(handled = false)
180 IPC_END_MESSAGE_MAP()
182 for (Handlers::iterator it = handlers_.begin();
183 !handled && it != handlers_.end(); ++it) {
184 handled = (*it)->OnMessageReceived(message);
187 return handled;
190 void ChromeContentUtilityClient::RegisterMojoServices(
191 content::ServiceRegistry* registry) {
192 #if !defined(OS_ANDROID)
193 registry->AddService<net::interfaces::ProxyResolverFactory>(
194 base::Bind(CreateProxyResolverFactory));
195 #endif
198 // static
199 void ChromeContentUtilityClient::PreSandboxStartup() {
200 #if defined(ENABLE_EXTENSIONS)
201 extensions::ExtensionsHandler::PreSandboxStartup();
202 #endif
204 #if defined(ENABLE_MDNS)
205 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
206 switches::kUtilityProcessEnableMDns)) {
207 local_discovery::ServiceDiscoveryMessageHandler::PreSandboxStartup();
209 #endif // ENABLE_MDNS
212 // static
213 SkBitmap ChromeContentUtilityClient::DecodeImage(
214 const std::vector<unsigned char>& encoded_data, bool shrink_to_fit) {
215 SkBitmap decoded_image;
216 if (encoded_data.empty())
217 return decoded_image;
219 decoded_image = content::DecodeImage(&encoded_data[0],
220 gfx::Size(),
221 encoded_data.size());
223 int64_t struct_size = sizeof(ChromeUtilityHostMsg_DecodeImage_Succeeded);
224 int64_t image_size = decoded_image.computeSize64();
225 int halves = 0;
226 while (struct_size + (image_size >> 2*halves) > max_ipc_message_size_)
227 halves++;
228 if (halves) {
229 if (shrink_to_fit) {
230 // If decoded image is too large for IPC message, shrink it by halves.
231 // This prevents quality loss, and should never overshrink on displays
232 // smaller than 3600x2400.
233 // TODO (Issue 416916): Instead of shrinking, return via shared memory
234 decoded_image = skia::ImageOperations::Resize(
235 decoded_image, skia::ImageOperations::RESIZE_LANCZOS3,
236 decoded_image.width() >> halves, decoded_image.height() >> halves);
237 } else {
238 // Image too big for IPC message, but caller didn't request resize;
239 // pre-delete image so DecodeImageAndSend() will send an error.
240 decoded_image.reset();
241 LOG(ERROR) << "Decoded image too large for IPC message";
245 return decoded_image;
248 // static
249 void ChromeContentUtilityClient::DecodeImageAndSend(
250 const std::vector<unsigned char>& encoded_data,
251 bool shrink_to_fit,
252 int request_id) {
253 SkBitmap decoded_image = DecodeImage(encoded_data, shrink_to_fit);
255 if (decoded_image.empty()) {
256 Send(new ChromeUtilityHostMsg_DecodeImage_Failed(request_id));
257 } else {
258 Send(new ChromeUtilityHostMsg_DecodeImage_Succeeded(decoded_image,
259 request_id));
261 ReleaseProcessIfNeeded();
264 void ChromeContentUtilityClient::OnDecodeImage(
265 const std::vector<unsigned char>& encoded_data,
266 bool shrink_to_fit,
267 int request_id) {
268 DecodeImageAndSend(encoded_data, shrink_to_fit, request_id);
271 #if defined(OS_CHROMEOS)
272 void ChromeContentUtilityClient::OnCreateZipFile(
273 const base::FilePath& src_dir,
274 const std::vector<base::FilePath>& src_relative_paths,
275 const base::FileDescriptor& dest_fd) {
276 // dest_fd should be closed in the function. See ipc/ipc_message_util.h for
277 // details.
278 base::ScopedFD fd_closer(dest_fd.fd);
279 bool succeeded = true;
281 // Check sanity of source relative paths. Reject if path is absolute or
282 // contains any attempt to reference a parent directory ("../" tricks).
283 for (std::vector<base::FilePath>::const_iterator iter =
284 src_relative_paths.begin(); iter != src_relative_paths.end();
285 ++iter) {
286 if (iter->IsAbsolute() || iter->ReferencesParent()) {
287 succeeded = false;
288 break;
292 if (succeeded)
293 succeeded = zip::ZipFiles(src_dir, src_relative_paths, dest_fd.fd);
295 if (succeeded)
296 Send(new ChromeUtilityHostMsg_CreateZipFile_Succeeded());
297 else
298 Send(new ChromeUtilityHostMsg_CreateZipFile_Failed());
299 ReleaseProcessIfNeeded();
301 #endif // defined(OS_CHROMEOS)
303 #if defined(OS_ANDROID) && defined(USE_SECCOMP_BPF)
304 void ChromeContentUtilityClient::OnDetectSeccompSupport() {
305 bool supports_prctl = sandbox::SandboxBPF::SupportsSeccompSandbox(
306 sandbox::SandboxBPF::SeccompLevel::SINGLE_THREADED);
307 Send(new ChromeUtilityHostMsg_DetectSeccompSupport_ResultPrctl(
308 supports_prctl));
310 // Probing for the seccomp syscall can provoke kernel panics in certain LGE
311 // devices. For now, this data will not be collected. In the future, this
312 // should detect SeccompLevel::MULTI_THREADED. http://crbug.com/478478
314 ReleaseProcessIfNeeded();
316 #endif // defined(OS_ANDROID) && defined(USE_SECCOMP_BPF)
318 #if defined(OS_CHROMEOS)
319 void ChromeContentUtilityClient::OnRobustJPEGDecodeImage(
320 const std::vector<unsigned char>& encoded_data,
321 int request_id) {
322 // Our robust jpeg decoding is using IJG libjpeg.
323 if (!encoded_data.empty()) {
324 scoped_ptr<SkBitmap> decoded_image(gfx::JPEGCodecRobustSlow::Decode(
325 &encoded_data[0], encoded_data.size()));
326 if (!decoded_image.get() || decoded_image->empty()) {
327 Send(new ChromeUtilityHostMsg_DecodeImage_Failed(request_id));
328 } else {
329 Send(new ChromeUtilityHostMsg_DecodeImage_Succeeded(*decoded_image,
330 request_id));
332 } else {
333 Send(new ChromeUtilityHostMsg_DecodeImage_Failed(request_id));
335 ReleaseProcessIfNeeded();
337 #endif // defined(OS_CHROMEOS)
339 void ChromeContentUtilityClient::OnParseJSON(const std::string& json) {
340 int error_code;
341 std::string error;
342 base::Value* value = base::JSONReader::ReadAndReturnError(
343 json, base::JSON_PARSE_RFC, &error_code, &error);
344 if (value) {
345 base::ListValue wrapper;
346 wrapper.Append(value);
347 Send(new ChromeUtilityHostMsg_ParseJSON_Succeeded(wrapper));
348 } else {
349 Send(new ChromeUtilityHostMsg_ParseJSON_Failed(error));
351 ReleaseProcessIfNeeded();
354 void ChromeContentUtilityClient::OnPatchFileBsdiff(
355 const base::FilePath& input_file,
356 const base::FilePath& patch_file,
357 const base::FilePath& output_file) {
358 if (input_file.empty() || patch_file.empty() || output_file.empty()) {
359 Send(new ChromeUtilityHostMsg_PatchFile_Finished(-1));
360 } else {
361 const int patch_status = courgette::ApplyBinaryPatch(input_file,
362 patch_file,
363 output_file);
364 Send(new ChromeUtilityHostMsg_PatchFile_Finished(patch_status));
366 ReleaseProcessIfNeeded();
369 void ChromeContentUtilityClient::OnPatchFileCourgette(
370 const base::FilePath& input_file,
371 const base::FilePath& patch_file,
372 const base::FilePath& output_file) {
373 if (input_file.empty() || patch_file.empty() || output_file.empty()) {
374 Send(new ChromeUtilityHostMsg_PatchFile_Finished(-1));
375 } else {
376 const int patch_status = courgette::ApplyEnsemblePatch(
377 input_file.value().c_str(),
378 patch_file.value().c_str(),
379 output_file.value().c_str());
380 Send(new ChromeUtilityHostMsg_PatchFile_Finished(patch_status));
382 ReleaseProcessIfNeeded();
385 void ChromeContentUtilityClient::OnStartupPing() {
386 Send(new ChromeUtilityHostMsg_ProcessStarted);
387 // Don't release the process, we assume further messages are on the way.
390 #if defined(FULL_SAFE_BROWSING)
391 void ChromeContentUtilityClient::OnAnalyzeZipFileForDownloadProtection(
392 const IPC::PlatformFileForTransit& zip_file,
393 const IPC::PlatformFileForTransit& temp_file) {
394 safe_browsing::zip_analyzer::Results results;
395 safe_browsing::zip_analyzer::AnalyzeZipFile(
396 IPC::PlatformFileForTransitToFile(zip_file),
397 IPC::PlatformFileForTransitToFile(temp_file), &results);
398 Send(new ChromeUtilityHostMsg_AnalyzeZipFileForDownloadProtection_Finished(
399 results));
400 ReleaseProcessIfNeeded();
402 #endif
404 #if defined(ENABLE_EXTENSIONS)
405 // TODO(thestig): Try to move this to
406 // chrome/utility/extensions/extensions_handler.cc.
407 void ChromeContentUtilityClient::OnParseMediaMetadata(
408 const std::string& mime_type, int64 total_size, bool get_attached_images) {
409 // Only one IPCDataSource may be created and added to the list of handlers.
410 metadata::IPCDataSource* source = new metadata::IPCDataSource(total_size);
411 handlers_.push_back(source);
413 metadata::MediaMetadataParser* parser = new metadata::MediaMetadataParser(
414 source, mime_type, get_attached_images);
415 parser->Start(base::Bind(&FinishParseMediaMetadata, base::Owned(parser)));
417 #endif