Supervised user import: Listen for profile creation/deletion
[chromium-blink-merge.git] / chrome / utility / chrome_content_utility_client.cc
blob111ac99c49b6405840988b078b17fbc79d933e3f
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/codec/jpeg_codec.h"
28 #include "ui/gfx/geometry/size.h"
30 #if !defined(OS_ANDROID)
31 #include "chrome/utility/profile_import_handler.h"
32 #include "net/proxy/mojo_proxy_resolver_factory_impl.h"
33 #endif
35 #if defined(OS_ANDROID) && defined(USE_SECCOMP_BPF)
36 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
37 #endif
39 #if defined(OS_WIN)
40 #include "chrome/utility/font_cache_handler_win.h"
41 #include "chrome/utility/shell_handler_win.h"
42 #endif
44 #if defined(ENABLE_EXTENSIONS)
45 #include "chrome/common/extensions/chrome_utility_extensions_messages.h"
46 #include "chrome/utility/extensions/extensions_handler.h"
47 #include "chrome/utility/image_writer/image_writer_handler.h"
48 #include "chrome/utility/media_galleries/ipc_data_source.h"
49 #include "chrome/utility/media_galleries/media_metadata_parser.h"
50 #endif
52 #if defined(ENABLE_PRINT_PREVIEW) || defined(OS_WIN)
53 #include "chrome/utility/printing_handler.h"
54 #endif
56 #if defined(ENABLE_MDNS)
57 #include "chrome/utility/local_discovery/service_discovery_message_handler.h"
58 #endif
60 namespace {
62 bool Send(IPC::Message* message) {
63 return content::UtilityThread::Get()->Send(message);
66 void ReleaseProcessIfNeeded() {
67 content::UtilityThread::Get()->ReleaseProcessIfNeeded();
70 #if defined(ENABLE_EXTENSIONS)
71 void FinishParseMediaMetadata(
72 metadata::MediaMetadataParser* /* parser */,
73 const extensions::api::media_galleries::MediaMetadata& metadata,
74 const std::vector<metadata::AttachedImage>& attached_images) {
75 Send(new ChromeUtilityHostMsg_ParseMediaMetadata_Finished(
76 true, *metadata.ToValue(), attached_images));
77 ReleaseProcessIfNeeded();
79 #endif
81 #if !defined(OS_ANDROID)
82 void CreateProxyResolverFactory(
83 mojo::InterfaceRequest<net::interfaces::ProxyResolverFactory> request) {
84 // MojoProxyResolverFactoryImpl is strongly bound to the Mojo message pipe it
85 // is connected to. When that message pipe is closed, either explicitly on the
86 // other end (in the browser process), or by a connection error, this object
87 // will be destroyed.
88 new net::MojoProxyResolverFactoryImpl(request.Pass());
90 #endif // OS_ANDROID
92 } // namespace
94 int64_t ChromeContentUtilityClient::max_ipc_message_size_ =
95 IPC::Channel::kMaximumMessageSize;
97 ChromeContentUtilityClient::ChromeContentUtilityClient()
98 : filter_messages_(false) {
99 #if !defined(OS_ANDROID)
100 handlers_.push_back(new ProfileImportHandler());
101 #endif
103 #if defined(ENABLE_EXTENSIONS)
104 handlers_.push_back(new extensions::ExtensionsHandler());
105 handlers_.push_back(new image_writer::ImageWriterHandler());
106 #endif
108 #if defined(ENABLE_PRINT_PREVIEW) || defined(OS_WIN)
109 handlers_.push_back(new PrintingHandler());
110 #endif
112 #if defined(ENABLE_MDNS)
113 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
114 switches::kUtilityProcessEnableMDns)) {
115 handlers_.push_back(new local_discovery::ServiceDiscoveryMessageHandler());
117 #endif
119 #if defined(OS_WIN)
120 handlers_.push_back(new ShellHandler());
121 handlers_.push_back(new FontCacheHandler());
122 #endif
125 ChromeContentUtilityClient::~ChromeContentUtilityClient() {
128 void ChromeContentUtilityClient::UtilityThreadStarted() {
129 #if defined(ENABLE_EXTENSIONS)
130 extensions::UtilityHandler::UtilityThreadStarted();
131 #endif
133 if (kMessageWhitelistSize > 0) {
134 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
135 if (command_line->HasSwitch(switches::kUtilityProcessRunningElevated)) {
136 message_id_whitelist_.insert(kMessageWhitelist,
137 kMessageWhitelist + kMessageWhitelistSize);
138 filter_messages_ = true;
143 bool ChromeContentUtilityClient::OnMessageReceived(
144 const IPC::Message& message) {
145 if (filter_messages_ && !ContainsKey(message_id_whitelist_, message.type()))
146 return false;
148 bool handled = true;
149 IPC_BEGIN_MESSAGE_MAP(ChromeContentUtilityClient, message)
150 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_DecodeImage, OnDecodeImage)
151 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RobustJPEGDecodeImage,
152 OnRobustJPEGDecodeImage)
153 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseJSON, OnParseJSON)
154 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_PatchFileBsdiff,
155 OnPatchFileBsdiff)
156 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_PatchFileCourgette,
157 OnPatchFileCourgette)
158 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_StartupPing, OnStartupPing)
159 #if defined(FULL_SAFE_BROWSING)
160 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_AnalyzeZipFileForDownloadProtection,
161 OnAnalyzeZipFileForDownloadProtection)
162 #endif
163 #if defined(ENABLE_EXTENSIONS)
164 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseMediaMetadata,
165 OnParseMediaMetadata)
166 #endif
167 #if defined(OS_CHROMEOS)
168 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_CreateZipFile, OnCreateZipFile)
169 #endif
170 #if defined(OS_ANDROID) && defined(USE_SECCOMP_BPF)
171 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_DetectSeccompSupport,
172 OnDetectSeccompSupport)
173 #endif
174 IPC_MESSAGE_UNHANDLED(handled = false)
175 IPC_END_MESSAGE_MAP()
177 for (Handlers::iterator it = handlers_.begin();
178 !handled && it != handlers_.end(); ++it) {
179 handled = (*it)->OnMessageReceived(message);
182 return handled;
185 void ChromeContentUtilityClient::RegisterMojoServices(
186 content::ServiceRegistry* registry) {
187 #if !defined(OS_ANDROID)
188 registry->AddService<net::interfaces::ProxyResolverFactory>(
189 base::Bind(CreateProxyResolverFactory));
190 #endif
193 // static
194 void ChromeContentUtilityClient::PreSandboxStartup() {
195 #if defined(ENABLE_EXTENSIONS)
196 extensions::ExtensionsHandler::PreSandboxStartup();
197 #endif
199 #if defined(ENABLE_MDNS)
200 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
201 switches::kUtilityProcessEnableMDns)) {
202 local_discovery::ServiceDiscoveryMessageHandler::PreSandboxStartup();
204 #endif // ENABLE_MDNS
207 // static
208 SkBitmap ChromeContentUtilityClient::DecodeImage(
209 const std::vector<unsigned char>& encoded_data, bool shrink_to_fit) {
210 SkBitmap decoded_image;
211 if (encoded_data.empty())
212 return decoded_image;
214 decoded_image = content::DecodeImage(&encoded_data[0],
215 gfx::Size(),
216 encoded_data.size());
218 int64_t struct_size = sizeof(ChromeUtilityHostMsg_DecodeImage_Succeeded);
219 int64_t image_size = decoded_image.computeSize64();
220 int halves = 0;
221 while (struct_size + (image_size >> 2*halves) > max_ipc_message_size_)
222 halves++;
223 if (halves) {
224 if (shrink_to_fit) {
225 // If decoded image is too large for IPC message, shrink it by halves.
226 // This prevents quality loss, and should never overshrink on displays
227 // smaller than 3600x2400.
228 // TODO (Issue 416916): Instead of shrinking, return via shared memory
229 decoded_image = skia::ImageOperations::Resize(
230 decoded_image, skia::ImageOperations::RESIZE_LANCZOS3,
231 decoded_image.width() >> halves, decoded_image.height() >> halves);
232 } else {
233 // Image too big for IPC message, but caller didn't request resize;
234 // pre-delete image so DecodeImageAndSend() will send an error.
235 decoded_image.reset();
236 LOG(ERROR) << "Decoded image too large for IPC message";
240 return decoded_image;
243 // static
244 void ChromeContentUtilityClient::DecodeImageAndSend(
245 const std::vector<unsigned char>& encoded_data,
246 bool shrink_to_fit,
247 int request_id) {
248 SkBitmap decoded_image = DecodeImage(encoded_data, shrink_to_fit);
250 if (decoded_image.empty()) {
251 Send(new ChromeUtilityHostMsg_DecodeImage_Failed(request_id));
252 } else {
253 Send(new ChromeUtilityHostMsg_DecodeImage_Succeeded(decoded_image,
254 request_id));
256 ReleaseProcessIfNeeded();
259 void ChromeContentUtilityClient::OnDecodeImage(
260 const std::vector<unsigned char>& encoded_data,
261 bool shrink_to_fit,
262 int request_id) {
263 DecodeImageAndSend(encoded_data, shrink_to_fit, request_id);
266 #if defined(OS_CHROMEOS)
267 void ChromeContentUtilityClient::OnCreateZipFile(
268 const base::FilePath& src_dir,
269 const std::vector<base::FilePath>& src_relative_paths,
270 const base::FileDescriptor& dest_fd) {
271 // dest_fd should be closed in the function. See ipc/ipc_message_util.h for
272 // details.
273 base::ScopedFD fd_closer(dest_fd.fd);
274 bool succeeded = true;
276 // Check sanity of source relative paths. Reject if path is absolute or
277 // contains any attempt to reference a parent directory ("../" tricks).
278 for (std::vector<base::FilePath>::const_iterator iter =
279 src_relative_paths.begin(); iter != src_relative_paths.end();
280 ++iter) {
281 if (iter->IsAbsolute() || iter->ReferencesParent()) {
282 succeeded = false;
283 break;
287 if (succeeded)
288 succeeded = zip::ZipFiles(src_dir, src_relative_paths, dest_fd.fd);
290 if (succeeded)
291 Send(new ChromeUtilityHostMsg_CreateZipFile_Succeeded());
292 else
293 Send(new ChromeUtilityHostMsg_CreateZipFile_Failed());
294 ReleaseProcessIfNeeded();
296 #endif // defined(OS_CHROMEOS)
298 #if defined(OS_ANDROID) && defined(USE_SECCOMP_BPF)
299 void ChromeContentUtilityClient::OnDetectSeccompSupport() {
300 bool supports_prctl = sandbox::SandboxBPF::SupportsSeccompSandbox(
301 sandbox::SandboxBPF::SeccompLevel::SINGLE_THREADED);
302 Send(new ChromeUtilityHostMsg_DetectSeccompSupport_ResultPrctl(
303 supports_prctl));
305 // Probing for the seccomp syscall can provoke kernel panics in certain LGE
306 // devices. For now, this data will not be collected. In the future, this
307 // should detect SeccompLevel::MULTI_THREADED. http://crbug.com/478478
309 ReleaseProcessIfNeeded();
311 #endif // defined(OS_ANDROID) && defined(USE_SECCOMP_BPF)
313 void ChromeContentUtilityClient::OnRobustJPEGDecodeImage(
314 const std::vector<unsigned char>& encoded_data,
315 int request_id) {
316 // Our robust jpeg decoding is using IJG libjpeg.
317 if (gfx::JPEGCodec::JpegLibraryVariant() == gfx::JPEGCodec::IJG_LIBJPEG &&
318 !encoded_data.empty()) {
319 scoped_ptr<SkBitmap> decoded_image(gfx::JPEGCodec::Decode(
320 &encoded_data[0], encoded_data.size()));
321 if (!decoded_image.get() || decoded_image->empty()) {
322 Send(new ChromeUtilityHostMsg_DecodeImage_Failed(request_id));
323 } else {
324 Send(new ChromeUtilityHostMsg_DecodeImage_Succeeded(*decoded_image,
325 request_id));
327 } else {
328 Send(new ChromeUtilityHostMsg_DecodeImage_Failed(request_id));
330 ReleaseProcessIfNeeded();
333 void ChromeContentUtilityClient::OnParseJSON(const std::string& json) {
334 int error_code;
335 std::string error;
336 base::Value* value = base::JSONReader::ReadAndReturnError(
337 json, base::JSON_PARSE_RFC, &error_code, &error);
338 if (value) {
339 base::ListValue wrapper;
340 wrapper.Append(value);
341 Send(new ChromeUtilityHostMsg_ParseJSON_Succeeded(wrapper));
342 } else {
343 Send(new ChromeUtilityHostMsg_ParseJSON_Failed(error));
345 ReleaseProcessIfNeeded();
348 void ChromeContentUtilityClient::OnPatchFileBsdiff(
349 const base::FilePath& input_file,
350 const base::FilePath& patch_file,
351 const base::FilePath& output_file) {
352 if (input_file.empty() || patch_file.empty() || output_file.empty()) {
353 Send(new ChromeUtilityHostMsg_PatchFile_Finished(-1));
354 } else {
355 const int patch_status = courgette::ApplyBinaryPatch(input_file,
356 patch_file,
357 output_file);
358 Send(new ChromeUtilityHostMsg_PatchFile_Finished(patch_status));
360 ReleaseProcessIfNeeded();
363 void ChromeContentUtilityClient::OnPatchFileCourgette(
364 const base::FilePath& input_file,
365 const base::FilePath& patch_file,
366 const base::FilePath& output_file) {
367 if (input_file.empty() || patch_file.empty() || output_file.empty()) {
368 Send(new ChromeUtilityHostMsg_PatchFile_Finished(-1));
369 } else {
370 const int patch_status = courgette::ApplyEnsemblePatch(
371 input_file.value().c_str(),
372 patch_file.value().c_str(),
373 output_file.value().c_str());
374 Send(new ChromeUtilityHostMsg_PatchFile_Finished(patch_status));
376 ReleaseProcessIfNeeded();
379 void ChromeContentUtilityClient::OnStartupPing() {
380 Send(new ChromeUtilityHostMsg_ProcessStarted);
381 // Don't release the process, we assume further messages are on the way.
384 #if defined(FULL_SAFE_BROWSING)
385 void ChromeContentUtilityClient::OnAnalyzeZipFileForDownloadProtection(
386 const IPC::PlatformFileForTransit& zip_file,
387 const IPC::PlatformFileForTransit& temp_file) {
388 safe_browsing::zip_analyzer::Results results;
389 safe_browsing::zip_analyzer::AnalyzeZipFile(
390 IPC::PlatformFileForTransitToFile(zip_file),
391 IPC::PlatformFileForTransitToFile(temp_file), &results);
392 Send(new ChromeUtilityHostMsg_AnalyzeZipFileForDownloadProtection_Finished(
393 results));
394 ReleaseProcessIfNeeded();
396 #endif
398 #if defined(ENABLE_EXTENSIONS)
399 // TODO(thestig): Try to move this to
400 // chrome/utility/extensions/extensions_handler.cc.
401 void ChromeContentUtilityClient::OnParseMediaMetadata(
402 const std::string& mime_type, int64 total_size, bool get_attached_images) {
403 // Only one IPCDataSource may be created and added to the list of handlers.
404 metadata::IPCDataSource* source = new metadata::IPCDataSource(total_size);
405 handlers_.push_back(source);
407 metadata::MediaMetadataParser* parser = new metadata::MediaMetadataParser(
408 source, mime_type, get_attached_images);
409 parser->Start(base::Bind(&FinishParseMediaMetadata, base::Owned(parser)));
411 #endif