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