Home | History | Annotate | Download | only in utility
      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.
      4 
      5 #include "chrome/utility/chrome_content_utility_client.h"
      6 
      7 #include "base/base64.h"
      8 #include "base/bind.h"
      9 #include "base/command_line.h"
     10 #include "base/files/file_path.h"
     11 #include "base/json/json_reader.h"
     12 #include "base/memory/ref_counted.h"
     13 #include "base/path_service.h"
     14 #include "base/time/time.h"
     15 #include "chrome/common/chrome_utility_messages.h"
     16 #include "chrome/common/extensions/chrome_extensions_client.h"
     17 #include "chrome/common/extensions/update_manifest.h"
     18 #include "chrome/common/safe_browsing/zip_analyzer.h"
     19 #include "chrome/utility/chrome_content_utility_ipc_whitelist.h"
     20 #include "chrome/utility/extensions/unpacker.h"
     21 #include "chrome/utility/image_writer/image_writer_handler.h"
     22 #include "chrome/utility/profile_import_handler.h"
     23 #include "chrome/utility/web_resource_unpacker.h"
     24 #include "content/public/child/image_decoder_utils.h"
     25 #include "content/public/common/content_paths.h"
     26 #include "content/public/common/content_switches.h"
     27 #include "content/public/utility/utility_thread.h"
     28 #include "courgette/courgette.h"
     29 #include "courgette/third_party/bsdiff.h"
     30 #include "extensions/common/extension.h"
     31 #include "extensions/common/extension_l10n_util.h"
     32 #include "extensions/common/manifest.h"
     33 #include "media/base/media.h"
     34 #include "media/base/media_file_checker.h"
     35 #include "third_party/skia/include/core/SkBitmap.h"
     36 #include "third_party/zlib/google/zip.h"
     37 #include "ui/base/ui_base_switches.h"
     38 #include "ui/gfx/codec/jpeg_codec.h"
     39 #include "ui/gfx/rect.h"
     40 #include "ui/gfx/size.h"
     41 
     42 #if defined(OS_WIN)
     43 #include "chrome/common/extensions/api/networking_private/networking_private_crypto.h"
     44 #include "chrome/utility/media_galleries/itunes_pref_parser_win.h"
     45 #include "components/wifi/wifi_service.h"
     46 #endif  // defined(OS_WIN)
     47 
     48 #if defined(OS_MACOSX)
     49 #include "chrome/utility/media_galleries/iphoto_library_parser.h"
     50 #endif  // defined(OS_MACOSX)
     51 
     52 #if defined(OS_WIN) || defined(OS_MACOSX)
     53 #include "chrome/utility/media_galleries/iapps_xml_utils.h"
     54 #include "chrome/utility/media_galleries/itunes_library_parser.h"
     55 #include "chrome/utility/media_galleries/picasa_album_table_reader.h"
     56 #include "chrome/utility/media_galleries/picasa_albums_indexer.h"
     57 #endif  // defined(OS_WIN) || defined(OS_MACOSX)
     58 
     59 #if !defined(OS_ANDROID) && !defined(OS_IOS)
     60 #include "chrome/common/media_galleries/metadata_types.h"
     61 #include "chrome/utility/media_galleries/image_metadata_extractor.h"
     62 #include "chrome/utility/media_galleries/ipc_data_source.h"
     63 #include "chrome/utility/media_galleries/media_metadata_parser.h"
     64 #endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
     65 
     66 #if defined(ENABLE_FULL_PRINTING)
     67 #include "chrome/utility/printing_handler.h"
     68 #endif
     69 
     70 #if defined(ENABLE_MDNS)
     71 #include "chrome/utility/local_discovery/service_discovery_message_handler.h"
     72 #endif
     73 
     74 namespace {
     75 
     76 bool Send(IPC::Message* message) {
     77   return content::UtilityThread::Get()->Send(message);
     78 }
     79 
     80 void ReleaseProcessIfNeeded() {
     81   content::UtilityThread::Get()->ReleaseProcessIfNeeded();
     82 }
     83 
     84 #if !defined(OS_ANDROID) && !defined(OS_IOS)
     85 void FinishParseMediaMetadata(
     86     metadata::MediaMetadataParser* parser,
     87     const extensions::api::media_galleries::MediaMetadata& metadata,
     88     const std::vector<metadata::AttachedImage>& attached_images) {
     89   Send(new ChromeUtilityHostMsg_ParseMediaMetadata_Finished(
     90       true, *metadata.ToValue(), attached_images));
     91   ReleaseProcessIfNeeded();
     92 }
     93 #endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
     94 
     95 }  // namespace
     96 
     97 ChromeContentUtilityClient::ChromeContentUtilityClient()
     98     : filter_messages_(false) {
     99 #if !defined(OS_ANDROID)
    100   handlers_.push_back(new ProfileImportHandler());
    101 #endif
    102 
    103 #if defined(ENABLE_FULL_PRINTING)
    104   handlers_.push_back(new PrintingHandler());
    105 #endif
    106 
    107 #if defined(ENABLE_MDNS)
    108   if (CommandLine::ForCurrentProcess()->HasSwitch(
    109           switches::kUtilityProcessEnableMDns)) {
    110     handlers_.push_back(new local_discovery::ServiceDiscoveryMessageHandler());
    111   }
    112 #endif
    113 
    114   handlers_.push_back(new image_writer::ImageWriterHandler());
    115 }
    116 
    117 ChromeContentUtilityClient::~ChromeContentUtilityClient() {
    118 }
    119 
    120 void ChromeContentUtilityClient::UtilityThreadStarted() {
    121   CommandLine* command_line = CommandLine::ForCurrentProcess();
    122   std::string lang = command_line->GetSwitchValueASCII(switches::kLang);
    123   if (!lang.empty())
    124     extension_l10n_util::SetProcessLocale(lang);
    125 
    126   if (command_line->HasSwitch(switches::kUtilityProcessRunningElevated)) {
    127     message_id_whitelist_.insert(kMessageWhitelist,
    128                                  kMessageWhitelist + kMessageWhitelistSize);
    129     filter_messages_ = true;
    130   }
    131 }
    132 
    133 bool ChromeContentUtilityClient::OnMessageReceived(
    134     const IPC::Message& message) {
    135   if (filter_messages_ && !ContainsKey(message_id_whitelist_, message.type()))
    136     return false;
    137 
    138   bool handled = true;
    139   IPC_BEGIN_MESSAGE_MAP(ChromeContentUtilityClient, message)
    140     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_UnpackExtension, OnUnpackExtension)
    141     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_UnpackWebResource,
    142                         OnUnpackWebResource)
    143     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseUpdateManifest,
    144                         OnParseUpdateManifest)
    145     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_DecodeImage, OnDecodeImage)
    146     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_DecodeImageBase64, OnDecodeImageBase64)
    147     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RobustJPEGDecodeImage,
    148                         OnRobustJPEGDecodeImage)
    149     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseJSON, OnParseJSON)
    150     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_PatchFileBsdiff,
    151                         OnPatchFileBsdiff)
    152     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_PatchFileCourgette,
    153                         OnPatchFileCourgette)
    154     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_StartupPing, OnStartupPing)
    155     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_AnalyzeZipFileForDownloadProtection,
    156                         OnAnalyzeZipFileForDownloadProtection)
    157 
    158 #if !defined(OS_ANDROID) && !defined(OS_IOS)
    159     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_CheckMediaFile, OnCheckMediaFile)
    160     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseMediaMetadata,
    161                         OnParseMediaMetadata)
    162 #endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
    163 
    164 #if defined(OS_CHROMEOS)
    165     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_CreateZipFile, OnCreateZipFile)
    166 #endif  // defined(OS_CHROMEOS)
    167 
    168 #if defined(OS_WIN)
    169     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseITunesPrefXml,
    170                         OnParseITunesPrefXml)
    171 #endif  // defined(OS_WIN)
    172 
    173 #if defined(OS_MACOSX)
    174     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseIPhotoLibraryXmlFile,
    175                         OnParseIPhotoLibraryXmlFile)
    176 #endif  // defined(OS_MACOSX)
    177 
    178 #if defined(OS_WIN) || defined(OS_MACOSX)
    179     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseITunesLibraryXmlFile,
    180                         OnParseITunesLibraryXmlFile)
    181     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParsePicasaPMPDatabase,
    182                         OnParsePicasaPMPDatabase)
    183     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_IndexPicasaAlbumsContents,
    184                         OnIndexPicasaAlbumsContents)
    185 #endif  // defined(OS_WIN) || defined(OS_MACOSX)
    186 
    187 #if defined(OS_WIN)
    188     IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetAndEncryptWiFiCredentials,
    189                         OnGetAndEncryptWiFiCredentials)
    190 #endif  // defined(OS_WIN)
    191 
    192     IPC_MESSAGE_UNHANDLED(handled = false)
    193   IPC_END_MESSAGE_MAP()
    194 
    195   for (Handlers::iterator it = handlers_.begin();
    196        !handled && it != handlers_.end(); ++it) {
    197     handled = (*it)->OnMessageReceived(message);
    198   }
    199 
    200   return handled;
    201 }
    202 
    203 // static
    204 void ChromeContentUtilityClient::PreSandboxStartup() {
    205 #if defined(ENABLE_FULL_PRINTING)
    206   PrintingHandler::PreSandboxStartup();
    207 #endif
    208 
    209 #if defined(ENABLE_MDNS)
    210   if (CommandLine::ForCurrentProcess()->HasSwitch(
    211           switches::kUtilityProcessEnableMDns)) {
    212     local_discovery::ServiceDiscoveryMessageHandler::PreSandboxStartup();
    213   }
    214 #endif  // ENABLE_MDNS
    215 
    216 #if !defined(OS_ANDROID) && !defined(OS_IOS)
    217   // Initialize libexif for image metadata parsing.
    218   metadata::ImageMetadataExtractor::InitializeLibrary();
    219 #endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
    220 
    221   // Load media libraries for media file validation.
    222   base::FilePath media_path;
    223   PathService::Get(content::DIR_MEDIA_LIBS, &media_path);
    224   if (!media_path.empty())
    225     media::InitializeMediaLibrary(media_path);
    226 }
    227 
    228 void ChromeContentUtilityClient::OnUnpackExtension(
    229     const base::FilePath& extension_path,
    230     const std::string& extension_id,
    231     int location,
    232     int creation_flags) {
    233   CHECK_GT(location, extensions::Manifest::INVALID_LOCATION);
    234   CHECK_LT(location, extensions::Manifest::NUM_LOCATIONS);
    235   extensions::ExtensionsClient::Set(
    236       extensions::ChromeExtensionsClient::GetInstance());
    237   extensions::Unpacker unpacker(
    238       extension_path,
    239       extension_id,
    240       static_cast<extensions::Manifest::Location>(location),
    241       creation_flags);
    242   if (unpacker.Run() && unpacker.DumpImagesToFile() &&
    243       unpacker.DumpMessageCatalogsToFile()) {
    244     Send(new ChromeUtilityHostMsg_UnpackExtension_Succeeded(
    245         *unpacker.parsed_manifest()));
    246   } else {
    247     Send(new ChromeUtilityHostMsg_UnpackExtension_Failed(
    248         unpacker.error_message()));
    249   }
    250 
    251   ReleaseProcessIfNeeded();
    252 }
    253 
    254 void ChromeContentUtilityClient::OnUnpackWebResource(
    255     const std::string& resource_data) {
    256   // Parse json data.
    257   // TODO(mrc): Add the possibility of a template that controls parsing, and
    258   // the ability to download and verify images.
    259   WebResourceUnpacker unpacker(resource_data);
    260   if (unpacker.Run()) {
    261     Send(new ChromeUtilityHostMsg_UnpackWebResource_Succeeded(
    262         *unpacker.parsed_json()));
    263   } else {
    264     Send(new ChromeUtilityHostMsg_UnpackWebResource_Failed(
    265         unpacker.error_message()));
    266   }
    267 
    268   ReleaseProcessIfNeeded();
    269 }
    270 
    271 void ChromeContentUtilityClient::OnParseUpdateManifest(const std::string& xml) {
    272   UpdateManifest manifest;
    273   if (!manifest.Parse(xml)) {
    274     Send(new ChromeUtilityHostMsg_ParseUpdateManifest_Failed(
    275         manifest.errors()));
    276   } else {
    277     Send(new ChromeUtilityHostMsg_ParseUpdateManifest_Succeeded(
    278         manifest.results()));
    279   }
    280   ReleaseProcessIfNeeded();
    281 }
    282 
    283 void ChromeContentUtilityClient::OnDecodeImage(
    284     const std::vector<unsigned char>& encoded_data) {
    285   const SkBitmap& decoded_image = content::DecodeImage(&encoded_data[0],
    286                                                        gfx::Size(),
    287                                                        encoded_data.size());
    288   if (decoded_image.empty()) {
    289     Send(new ChromeUtilityHostMsg_DecodeImage_Failed());
    290   } else {
    291     Send(new ChromeUtilityHostMsg_DecodeImage_Succeeded(decoded_image));
    292   }
    293   ReleaseProcessIfNeeded();
    294 }
    295 
    296 void ChromeContentUtilityClient::OnDecodeImageBase64(
    297     const std::string& encoded_string) {
    298   std::string decoded_string;
    299 
    300   if (!base::Base64Decode(encoded_string, &decoded_string)) {
    301     Send(new ChromeUtilityHostMsg_DecodeImage_Failed());
    302     return;
    303   }
    304 
    305   std::vector<unsigned char> decoded_vector(decoded_string.size());
    306   for (size_t i = 0; i < decoded_string.size(); ++i) {
    307     decoded_vector[i] = static_cast<unsigned char>(decoded_string[i]);
    308   }
    309 
    310   OnDecodeImage(decoded_vector);
    311 }
    312 
    313 #if defined(OS_CHROMEOS)
    314 void ChromeContentUtilityClient::OnCreateZipFile(
    315     const base::FilePath& src_dir,
    316     const std::vector<base::FilePath>& src_relative_paths,
    317     const base::FileDescriptor& dest_fd) {
    318   bool succeeded = true;
    319 
    320   // Check sanity of source relative paths. Reject if path is absolute or
    321   // contains any attempt to reference a parent directory ("../" tricks).
    322   for (std::vector<base::FilePath>::const_iterator iter =
    323            src_relative_paths.begin(); iter != src_relative_paths.end();
    324        ++iter) {
    325     if (iter->IsAbsolute() || iter->ReferencesParent()) {
    326       succeeded = false;
    327       break;
    328     }
    329   }
    330 
    331   if (succeeded)
    332     succeeded = zip::ZipFiles(src_dir, src_relative_paths, dest_fd.fd);
    333 
    334   if (succeeded)
    335     Send(new ChromeUtilityHostMsg_CreateZipFile_Succeeded());
    336   else
    337     Send(new ChromeUtilityHostMsg_CreateZipFile_Failed());
    338   ReleaseProcessIfNeeded();
    339 }
    340 #endif  // defined(OS_CHROMEOS)
    341 
    342 void ChromeContentUtilityClient::OnRobustJPEGDecodeImage(
    343     const std::vector<unsigned char>& encoded_data) {
    344   // Our robust jpeg decoding is using IJG libjpeg.
    345   if (gfx::JPEGCodec::JpegLibraryVariant() == gfx::JPEGCodec::IJG_LIBJPEG) {
    346     scoped_ptr<SkBitmap> decoded_image(gfx::JPEGCodec::Decode(
    347         &encoded_data[0], encoded_data.size()));
    348     if (!decoded_image.get() || decoded_image->empty()) {
    349       Send(new ChromeUtilityHostMsg_DecodeImage_Failed());
    350     } else {
    351       Send(new ChromeUtilityHostMsg_DecodeImage_Succeeded(*decoded_image));
    352     }
    353   } else {
    354     Send(new ChromeUtilityHostMsg_DecodeImage_Failed());
    355   }
    356   ReleaseProcessIfNeeded();
    357 }
    358 
    359 void ChromeContentUtilityClient::OnParseJSON(const std::string& json) {
    360   int error_code;
    361   std::string error;
    362   base::Value* value = base::JSONReader::ReadAndReturnError(
    363       json, base::JSON_PARSE_RFC, &error_code, &error);
    364   if (value) {
    365     base::ListValue wrapper;
    366     wrapper.Append(value);
    367     Send(new ChromeUtilityHostMsg_ParseJSON_Succeeded(wrapper));
    368   } else {
    369     Send(new ChromeUtilityHostMsg_ParseJSON_Failed(error));
    370   }
    371   ReleaseProcessIfNeeded();
    372 }
    373 
    374 void ChromeContentUtilityClient::OnPatchFileBsdiff(
    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_Failed(-1));
    380   } else {
    381     const int patch_status = courgette::ApplyBinaryPatch(input_file,
    382                                                          patch_file,
    383                                                          output_file);
    384     if (patch_status != courgette::OK)
    385       Send(new ChromeUtilityHostMsg_PatchFile_Failed(patch_status));
    386     else
    387       Send(new ChromeUtilityHostMsg_PatchFile_Succeeded());
    388   }
    389   ReleaseProcessIfNeeded();
    390 }
    391 
    392 void ChromeContentUtilityClient::OnPatchFileCourgette(
    393     const base::FilePath& input_file,
    394     const base::FilePath& patch_file,
    395     const base::FilePath& output_file) {
    396   if (input_file.empty() || patch_file.empty() || output_file.empty()) {
    397     Send(new ChromeUtilityHostMsg_PatchFile_Failed(-1));
    398   } else {
    399     const int patch_status = courgette::ApplyEnsemblePatch(
    400         input_file.value().c_str(),
    401         patch_file.value().c_str(),
    402         output_file.value().c_str());
    403     if (patch_status != courgette::C_OK)
    404       Send(new ChromeUtilityHostMsg_PatchFile_Failed(patch_status));
    405     else
    406       Send(new ChromeUtilityHostMsg_PatchFile_Succeeded());
    407   }
    408   ReleaseProcessIfNeeded();
    409 }
    410 
    411 void ChromeContentUtilityClient::OnStartupPing() {
    412   Send(new ChromeUtilityHostMsg_ProcessStarted);
    413   // Don't release the process, we assume further messages are on the way.
    414 }
    415 
    416 void ChromeContentUtilityClient::OnAnalyzeZipFileForDownloadProtection(
    417     const IPC::PlatformFileForTransit& zip_file) {
    418   safe_browsing::zip_analyzer::Results results;
    419   safe_browsing::zip_analyzer::AnalyzeZipFile(
    420       IPC::PlatformFileForTransitToFile(zip_file), &results);
    421   Send(new ChromeUtilityHostMsg_AnalyzeZipFileForDownloadProtection_Finished(
    422       results));
    423   ReleaseProcessIfNeeded();
    424 }
    425 
    426 #if !defined(OS_ANDROID) && !defined(OS_IOS)
    427 void ChromeContentUtilityClient::OnCheckMediaFile(
    428     int64 milliseconds_of_decoding,
    429     const IPC::PlatformFileForTransit& media_file) {
    430   media::MediaFileChecker checker(
    431       IPC::PlatformFileForTransitToFile(media_file));
    432   const bool check_success = checker.Start(
    433       base::TimeDelta::FromMilliseconds(milliseconds_of_decoding));
    434   Send(new ChromeUtilityHostMsg_CheckMediaFile_Finished(check_success));
    435   ReleaseProcessIfNeeded();
    436 }
    437 
    438 void ChromeContentUtilityClient::OnParseMediaMetadata(
    439     const std::string& mime_type, int64 total_size, bool get_attached_images) {
    440   // Only one IPCDataSource may be created and added to the list of handlers.
    441   metadata::IPCDataSource* source = new metadata::IPCDataSource(total_size);
    442   handlers_.push_back(source);
    443 
    444   metadata::MediaMetadataParser* parser = new metadata::MediaMetadataParser(
    445       source, mime_type, get_attached_images);
    446   parser->Start(base::Bind(&FinishParseMediaMetadata, base::Owned(parser)));
    447 }
    448 #endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
    449 
    450 #if defined(OS_WIN)
    451 void ChromeContentUtilityClient::OnParseITunesPrefXml(
    452     const std::string& itunes_xml_data) {
    453   base::FilePath library_path(
    454       itunes::FindLibraryLocationInPrefXml(itunes_xml_data));
    455   Send(new ChromeUtilityHostMsg_GotITunesDirectory(library_path));
    456   ReleaseProcessIfNeeded();
    457 }
    458 #endif  // defined(OS_WIN)
    459 
    460 #if defined(OS_MACOSX)
    461 void ChromeContentUtilityClient::OnParseIPhotoLibraryXmlFile(
    462     const IPC::PlatformFileForTransit& iphoto_library_file) {
    463   iphoto::IPhotoLibraryParser parser;
    464   base::File file = IPC::PlatformFileForTransitToFile(iphoto_library_file);
    465   bool result = parser.Parse(iapps::ReadFileAsString(file.Pass()));
    466   Send(new ChromeUtilityHostMsg_GotIPhotoLibrary(result, parser.library()));
    467   ReleaseProcessIfNeeded();
    468 }
    469 #endif  // defined(OS_MACOSX)
    470 
    471 #if defined(OS_WIN) || defined(OS_MACOSX)
    472 void ChromeContentUtilityClient::OnParseITunesLibraryXmlFile(
    473     const IPC::PlatformFileForTransit& itunes_library_file) {
    474   itunes::ITunesLibraryParser parser;
    475   base::File file = IPC::PlatformFileForTransitToFile(itunes_library_file);
    476   bool result = parser.Parse(iapps::ReadFileAsString(file.Pass()));
    477   Send(new ChromeUtilityHostMsg_GotITunesLibrary(result, parser.library()));
    478   ReleaseProcessIfNeeded();
    479 }
    480 
    481 void ChromeContentUtilityClient::OnParsePicasaPMPDatabase(
    482     const picasa::AlbumTableFilesForTransit& album_table_files) {
    483   picasa::AlbumTableFiles files;
    484   files.indicator_file =
    485       IPC::PlatformFileForTransitToFile(album_table_files.indicator_file);
    486   files.category_file =
    487       IPC::PlatformFileForTransitToFile(album_table_files.category_file);
    488   files.date_file =
    489       IPC::PlatformFileForTransitToFile(album_table_files.date_file);
    490   files.filename_file =
    491       IPC::PlatformFileForTransitToFile(album_table_files.filename_file);
    492   files.name_file =
    493       IPC::PlatformFileForTransitToFile(album_table_files.name_file);
    494   files.token_file =
    495       IPC::PlatformFileForTransitToFile(album_table_files.token_file);
    496   files.uid_file =
    497       IPC::PlatformFileForTransitToFile(album_table_files.uid_file);
    498 
    499   picasa::PicasaAlbumTableReader reader(files.Pass());
    500   bool parse_success = reader.Init();
    501   Send(new ChromeUtilityHostMsg_ParsePicasaPMPDatabase_Finished(
    502       parse_success,
    503       reader.albums(),
    504       reader.folders()));
    505   ReleaseProcessIfNeeded();
    506 }
    507 
    508 void ChromeContentUtilityClient::OnIndexPicasaAlbumsContents(
    509     const picasa::AlbumUIDSet& album_uids,
    510     const std::vector<picasa::FolderINIContents>& folders_inis) {
    511   picasa::PicasaAlbumsIndexer indexer(album_uids);
    512   indexer.ParseFolderINI(folders_inis);
    513 
    514   Send(new ChromeUtilityHostMsg_IndexPicasaAlbumsContents_Finished(
    515       indexer.albums_images()));
    516   ReleaseProcessIfNeeded();
    517 }
    518 #endif  // defined(OS_WIN) || defined(OS_MACOSX)
    519 
    520 #if defined(OS_WIN)
    521 void ChromeContentUtilityClient::OnGetAndEncryptWiFiCredentials(
    522     const std::string& network_guid,
    523     const std::vector<uint8>& public_key) {
    524   scoped_ptr<wifi::WiFiService> wifi_service(wifi::WiFiService::Create());
    525   wifi_service->Initialize(NULL);
    526 
    527   std::string key_data;
    528   std::string error;
    529   wifi_service->GetKeyFromSystem(network_guid, &key_data, &error);
    530 
    531   std::vector<uint8> ciphertext;
    532   bool success = error.empty() && !key_data.empty();
    533   if (success) {
    534     NetworkingPrivateCrypto crypto;
    535     success = crypto.EncryptByteString(public_key, key_data, &ciphertext);
    536   }
    537 
    538   Send(new ChromeUtilityHostMsg_GotEncryptedWiFiCredentials(ciphertext,
    539                                                             success));
    540 }
    541 #endif  // defined(OS_WIN)
    542