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