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 14using content::BrowserThread; 15using content::UtilityProcessHost; 16 17namespace iapps { 18 19SafeIAppsLibraryParser::SafeIAppsLibraryParser() 20 : parser_state_(INITIAL_STATE) {} 21 22void 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 30void 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 38void 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 59SafeIAppsLibraryParser::~SafeIAppsLibraryParser() {} 60 61void 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 75void 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) 106void 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 121void 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 135void SafeIAppsLibraryParser::OnOpenLibraryFileFailed() { 136 DCHECK_CURRENTLY_ON(BrowserThread::IO); 137 OnError(); 138} 139 140void SafeIAppsLibraryParser::OnProcessCrashed(int exit_code) { 141 OnError(); 142} 143 144void 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 155bool 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