Home | History | Annotate | Download | only in fileapi
      1 // Copyright 2013 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/browser/media_galleries/fileapi/safe_iapps_library_parser.h"
      6 
      7 #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
      8 #include "chrome/common/chrome_utility_messages.h"
      9 #include "content/public/browser/browser_thread.h"
     10 #include "content/public/browser/child_process_data.h"
     11 #include "ipc/ipc_platform_file.h"
     12 
     13 using content::BrowserThread;
     14 using content::UtilityProcessHost;
     15 
     16 namespace iapps {
     17 
     18 SafeIAppsLibraryParser::SafeIAppsLibraryParser()
     19     : parser_state_(INITIAL_STATE) {}
     20 
     21 void SafeIAppsLibraryParser::ParseIPhotoLibrary(
     22     const base::FilePath& library_file,
     23     const IPhotoParserCallback& callback) {
     24   library_file_ = library_file;
     25   iphoto_callback_ = callback;
     26   Start();
     27 }
     28 
     29 void SafeIAppsLibraryParser::ParseITunesLibrary(
     30     const base::FilePath& library_file,
     31     const ITunesParserCallback& callback) {
     32   library_file_ = library_file;
     33   itunes_callback_ = callback;
     34   Start();
     35 }
     36 
     37 void SafeIAppsLibraryParser::Start() {
     38   DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
     39 
     40   // |library_platform_file_| will be closed on the IO thread once it
     41   // has been handed off to the child process.
     42   library_platform_file_ = base::CreatePlatformFile(
     43       library_file_,
     44       base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
     45       NULL,   // created
     46       NULL);  // error_code
     47   if (library_platform_file_ == base::kInvalidPlatformFileValue) {
     48     VLOG(1) << "Could not open iApps library XML file: "
     49             << library_file_.value();
     50     BrowserThread::PostTask(
     51         BrowserThread::IO, FROM_HERE,
     52         base::Bind(&SafeIAppsLibraryParser::OnOpenLibraryFileFailed, this));
     53     return;
     54   }
     55 
     56   BrowserThread::PostTask(
     57       BrowserThread::IO, FROM_HERE,
     58       base::Bind(&SafeIAppsLibraryParser::StartProcessOnIOThread, this));
     59 }
     60 
     61 SafeIAppsLibraryParser::~SafeIAppsLibraryParser() {}
     62 
     63 void SafeIAppsLibraryParser::StartProcessOnIOThread() {
     64   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     65   DCHECK_EQ(INITIAL_STATE, parser_state_);
     66 
     67   scoped_refptr<base::MessageLoopProxy> message_loop_proxy =
     68       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
     69   utility_process_host_ =
     70       UtilityProcessHost::Create(this, message_loop_proxy.get())->AsWeakPtr();
     71   // Wait for the startup notification before sending the main IPC to the
     72   // utility process, so that we can dup the file handle.
     73   utility_process_host_->Send(new ChromeUtilityMsg_StartupPing);
     74   parser_state_ = PINGED_UTILITY_PROCESS_STATE;
     75 }
     76 
     77 void SafeIAppsLibraryParser::OnUtilityProcessStarted() {
     78   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     79   if (parser_state_ != PINGED_UTILITY_PROCESS_STATE)
     80     return;
     81 
     82   if (utility_process_host_->GetData().handle == base::kNullProcessHandle) {
     83     DLOG(ERROR) << "Child process handle is null";
     84     OnError();
     85     return;
     86   }
     87 
     88   if (!itunes_callback_.is_null()) {
     89     utility_process_host_->Send(
     90         new ChromeUtilityMsg_ParseITunesLibraryXmlFile(
     91             IPC::GetFileHandleForProcess(
     92                 library_platform_file_,
     93                 utility_process_host_->GetData().handle,
     94                 true /* close_source_handle */)));
     95   } else if (!iphoto_callback_.is_null()) {
     96 #if defined(OS_MACOSX)
     97     utility_process_host_->Send(
     98         new ChromeUtilityMsg_ParseIPhotoLibraryXmlFile(
     99             IPC::GetFileHandleForProcess(
    100                 library_platform_file_,
    101                 utility_process_host_->GetData().handle,
    102                 true /* close_source_handle */)));
    103 #endif
    104   }
    105 
    106   parser_state_ = STARTED_PARSING_STATE;
    107 }
    108 
    109 #if defined(OS_MACOSX)
    110 void SafeIAppsLibraryParser::OnGotIPhotoLibrary(
    111     bool result, const iphoto::parser::Library& library) {
    112   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    113   DCHECK(!iphoto_callback_.is_null());
    114 
    115   if (parser_state_ != STARTED_PARSING_STATE)
    116     return;
    117 
    118   MediaFileSystemBackend::MediaTaskRunner()->PostTask(
    119       FROM_HERE,
    120       base::Bind(iphoto_callback_, result, library));
    121   parser_state_ = FINISHED_PARSING_STATE;
    122 }
    123 #endif
    124 
    125 void SafeIAppsLibraryParser::OnGotITunesLibrary(
    126     bool result, const itunes::parser::Library& library) {
    127   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    128   DCHECK(!itunes_callback_.is_null());
    129 
    130   if (parser_state_ != STARTED_PARSING_STATE)
    131     return;
    132 
    133   MediaFileSystemBackend::MediaTaskRunner()->PostTask(
    134       FROM_HERE,
    135       base::Bind(itunes_callback_, result, library));
    136   parser_state_ = FINISHED_PARSING_STATE;
    137 }
    138 
    139 void SafeIAppsLibraryParser::OnOpenLibraryFileFailed() {
    140   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    141   OnError();
    142 }
    143 
    144 void SafeIAppsLibraryParser::OnProcessCrashed(int exit_code) {
    145   OnError();
    146 }
    147 
    148 void SafeIAppsLibraryParser::OnError() {
    149   parser_state_ = FINISHED_PARSING_STATE;
    150   if (!itunes_callback_.is_null())
    151     OnGotITunesLibrary(false /* failed */, itunes::parser::Library());
    152 
    153 #if defined(OS_MACOSX)
    154   if (!iphoto_callback_.is_null())
    155     OnGotIPhotoLibrary(false /* failed */, iphoto::parser::Library());
    156 #endif
    157 }
    158 
    159 bool SafeIAppsLibraryParser::OnMessageReceived(
    160     const IPC::Message& message) {
    161   bool handled = true;
    162   IPC_BEGIN_MESSAGE_MAP(SafeIAppsLibraryParser, message)
    163     IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted,
    164                         OnUtilityProcessStarted)
    165 #if defined(OS_MACOSX)
    166     IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GotIPhotoLibrary,
    167                         OnGotIPhotoLibrary)
    168 #endif
    169     IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GotITunesLibrary,
    170                         OnGotITunesLibrary)
    171     IPC_MESSAGE_UNHANDLED(handled = false)
    172   IPC_END_MESSAGE_MAP()
    173   return handled;
    174 }
    175 
    176 }  // namespace iapps
    177