blob: 72578a8831e9e29a1744f79bea88d65c09458ee6 [file] [log] [blame]
// Copyright (c) 2012 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/safe_browsing/sandboxed_zip_analyzer.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/threading/sequenced_worker_pool.h"
#include "chrome/common/chrome_utility_messages.h"
#include "chrome/common/safe_browsing/zip_analyzer.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/child_process_data.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/content_switches.h"
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_platform_file.h"
using content::BrowserThread;
namespace safe_browsing {
SandboxedZipAnalyzer::SandboxedZipAnalyzer(
const base::FilePath& zip_file,
const ResultCallback& result_callback)
: zip_file_name_(zip_file),
callback_(result_callback),
callback_called_(false) {
}
void SandboxedZipAnalyzer::Start() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
// Starting the analyzer will block on opening the zip file, so run this
// on a worker thread. The task does not need to block shutdown.
if (!BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior(
FROM_HERE,
base::Bind(&SandboxedZipAnalyzer::AnalyzeInSandbox, this),
base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)) {
NOTREACHED();
}
}
SandboxedZipAnalyzer::~SandboxedZipAnalyzer() {
// If we're using UtilityProcessHost, we may not be destroyed on
// the UI or IO thread.
}
void SandboxedZipAnalyzer::AnalyzeInSandbox() {
zip_file_.Initialize(zip_file_name_,
base::File::FLAG_OPEN | base::File::FLAG_READ);
if (!zip_file_.IsValid()) {
VLOG(1) << "Could not open zip file: " << zip_file_name_.value();
if (!BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&SandboxedZipAnalyzer::OnAnalyzeZipFileFinished, this,
zip_analyzer::Results()))) {
NOTREACHED();
}
return;
}
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&SandboxedZipAnalyzer::StartProcessOnIOThread, this));
// The file will be closed on the IO thread once it has been handed
// off to the child process.
}
bool SandboxedZipAnalyzer::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(SandboxedZipAnalyzer, message)
IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted,
OnUtilityProcessStarted)
IPC_MESSAGE_HANDLER(
ChromeUtilityHostMsg_AnalyzeZipFileForDownloadProtection_Finished,
OnAnalyzeZipFileFinished)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void SandboxedZipAnalyzer::OnAnalyzeZipFileFinished(
const zip_analyzer::Results& results) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (callback_called_)
return;
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(callback_, results));
callback_called_ = true;
}
void SandboxedZipAnalyzer::StartProcessOnIOThread() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
utility_process_host_ = content::UtilityProcessHost::Create(
this,
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO).get())
->AsWeakPtr();
utility_process_host_->Send(new ChromeUtilityMsg_StartupPing);
// Wait for the startup notification before sending the main IPC to the
// utility process, so that we can dup the file handle.
}
void SandboxedZipAnalyzer::OnUtilityProcessStarted() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
base::ProcessHandle utility_process =
content::RenderProcessHost::run_renderer_in_process() ?
base::GetCurrentProcessHandle() :
utility_process_host_->GetData().handle;
if (utility_process == base::kNullProcessHandle) {
DLOG(ERROR) << "Child process handle is null";
}
utility_process_host_->Send(
new ChromeUtilityMsg_AnalyzeZipFileForDownloadProtection(
IPC::TakeFileHandleForProcess(zip_file_.Pass(), utility_process)));
}
} // namespace safe_browsing