1 // Copyright (c) 2012 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.
5 #include "chrome/browser/safe_browsing/sandboxed_zip_analyzer.h"
8 #include "base/command_line.h"
9 #include "base/location.h"
10 #include "base/logging.h"
11 #include "base/platform_file.h"
12 #include "base/threading/sequenced_worker_pool.h"
13 #include "chrome/common/chrome_utility_messages.h"
14 #include "chrome/common/safe_browsing/zip_analyzer.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/browser/child_process_data.h"
17 #include "content/public/browser/render_process_host.h"
18 #include "content/public/common/content_switches.h"
19 #include "ipc/ipc_message_macros.h"
20 #include "ipc/ipc_platform_file.h"
22 using content::BrowserThread
;
24 namespace safe_browsing
{
26 SandboxedZipAnalyzer::SandboxedZipAnalyzer(
27 const base::FilePath
& zip_file
,
28 const ResultCallback
& result_callback
)
29 : zip_file_name_(zip_file
),
30 callback_(result_callback
),
31 callback_called_(false) {
34 void SandboxedZipAnalyzer::Start() {
35 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
36 // Starting the analyzer will block on opening the zip file, so run this
37 // on a worker thread. The task does not need to block shutdown.
38 if (!BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior(
40 base::Bind(&SandboxedZipAnalyzer::AnalyzeInSandbox
, this),
41 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN
)) {
46 SandboxedZipAnalyzer::~SandboxedZipAnalyzer() {
47 // If we're using UtilityProcessHost, we may not be destroyed on
48 // the UI or IO thread.
51 void SandboxedZipAnalyzer::AnalyzeInSandbox() {
52 zip_file_
.Initialize(zip_file_name_
,
53 base::File::FLAG_OPEN
| base::File::FLAG_READ
);
54 if (!zip_file_
.IsValid()) {
55 VLOG(1) << "Could not open zip file: " << zip_file_name_
.value();
56 if (!BrowserThread::PostTask(
57 BrowserThread::IO
, FROM_HERE
,
58 base::Bind(&SandboxedZipAnalyzer::OnAnalyzeZipFileFinished
, this,
59 zip_analyzer::Results()))) {
65 BrowserThread::PostTask(
66 BrowserThread::IO
, FROM_HERE
,
67 base::Bind(&SandboxedZipAnalyzer::StartProcessOnIOThread
, this));
68 // The file will be closed on the IO thread once it has been handed
69 // off to the child process.
72 bool SandboxedZipAnalyzer::OnMessageReceived(const IPC::Message
& message
) {
74 IPC_BEGIN_MESSAGE_MAP(SandboxedZipAnalyzer
, message
)
75 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted
,
76 OnUtilityProcessStarted
)
78 ChromeUtilityHostMsg_AnalyzeZipFileForDownloadProtection_Finished
,
79 OnAnalyzeZipFileFinished
)
80 IPC_MESSAGE_UNHANDLED(handled
= false)
85 void SandboxedZipAnalyzer::OnAnalyzeZipFileFinished(
86 const zip_analyzer::Results
& results
) {
87 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
90 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
91 base::Bind(callback_
, results
));
92 callback_called_
= true;
95 void SandboxedZipAnalyzer::StartProcessOnIOThread() {
96 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
97 utility_process_host_
= content::UtilityProcessHost::Create(
99 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO
).get())
101 utility_process_host_
->Send(new ChromeUtilityMsg_StartupPing
);
102 // Wait for the startup notification before sending the main IPC to the
103 // utility process, so that we can dup the file handle.
106 void SandboxedZipAnalyzer::OnUtilityProcessStarted() {
107 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
108 base::ProcessHandle utility_process
=
109 content::RenderProcessHost::run_renderer_in_process() ?
110 base::GetCurrentProcessHandle() :
111 utility_process_host_
->GetData().handle
;
113 if (utility_process
== base::kNullProcessHandle
) {
114 DLOG(ERROR
) << "Child process handle is null";
116 utility_process_host_
->Send(
117 new ChromeUtilityMsg_AnalyzeZipFileForDownloadProtection(
118 IPC::TakeFileHandleForProcess(zip_file_
.Pass(), utility_process
)));
121 } // namespace safe_browsing