// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/media_galleries/fileapi/safe_itunes_library_parser.h" #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h" #include "chrome/common/chrome_utility_messages.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/child_process_data.h" #include "ipc/ipc_platform_file.h" using content::BrowserThread; using content::UtilityProcessHost; namespace itunes { SafeITunesLibraryParser::SafeITunesLibraryParser( const base::FilePath& itunes_library_file, const ParserCallback& callback) : itunes_library_file_(itunes_library_file), callback_(callback), parser_state_(INITIAL_STATE) {} void SafeITunesLibraryParser::Start() { DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread()); // |itunes_library_platform_file_| will be closed on the IO thread once it // has been handed off to the child process. itunes_library_platform_file_ = base::CreatePlatformFile( itunes_library_file_, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, NULL, // created NULL); // error_code if (itunes_library_platform_file_ == base::kInvalidPlatformFileValue) { VLOG(1) << "Could not open iTunes library XML file: " << itunes_library_file_.value(); callback_.Run(false /* failed */, parser::Library()); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&SafeITunesLibraryParser::OnOpenLibraryFileFailed, this)); return; } BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&SafeITunesLibraryParser::StartProcessOnIOThread, this)); } SafeITunesLibraryParser::~SafeITunesLibraryParser() {} void SafeITunesLibraryParser::StartProcessOnIOThread() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DCHECK_EQ(INITIAL_STATE, parser_state_); scoped_refptr message_loop_proxy = BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO); utility_process_host_ = UtilityProcessHost::Create(this, message_loop_proxy.get())->AsWeakPtr(); // Wait for the startup notification before sending the main IPC to the // utility process, so that we can dup the file handle. utility_process_host_->Send(new ChromeUtilityMsg_StartupPing); parser_state_ = PINGED_UTILITY_PROCESS_STATE; } void SafeITunesLibraryParser::OnUtilityProcessStarted() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); if (parser_state_ != PINGED_UTILITY_PROCESS_STATE) return; if (utility_process_host_->GetData().handle == base::kNullProcessHandle) DLOG(ERROR) << "Child process handle is null"; utility_process_host_->Send( new ChromeUtilityMsg_ParseITunesLibraryXmlFile( IPC::GetFileHandleForProcess( itunes_library_platform_file_, utility_process_host_->GetData().handle, true /* close_source_handle */))); parser_state_ = STARTED_PARSING_STATE; } void SafeITunesLibraryParser::OnGotITunesLibrary( bool result, const parser::Library& library) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); if (parser_state_ != STARTED_PARSING_STATE) return; MediaFileSystemBackend::MediaTaskRunner()->PostTask( FROM_HERE, base::Bind(callback_, result, library)); parser_state_ = FINISHED_PARSING_STATE; } void SafeITunesLibraryParser::OnOpenLibraryFileFailed() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); parser_state_ = FINISHED_PARSING_STATE; } void SafeITunesLibraryParser::OnProcessCrashed(int exit_code) { OnGotITunesLibrary(false /* failed */, parser::Library()); } bool SafeITunesLibraryParser::OnMessageReceived( const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(SafeITunesLibraryParser, message) IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted, OnUtilityProcessStarted) IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GotITunesLibrary, OnGotITunesLibrary) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } } // namespace itunes