No dual_mode on Win10+ shortcuts.
[chromium-blink-merge.git] / chrome / browser / safe_browsing / sandboxed_zip_analyzer.cc
blob417f4cd872b97807134e251b2c4f69ca67f133ae
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"
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/files/file_util.h"
10 #include "base/location.h"
11 #include "base/logging.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_results.h"
15 #include "chrome/grit/generated_resources.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/child_process_data.h"
18 #include "content/public/browser/render_process_host.h"
19 #include "content/public/common/content_switches.h"
20 #include "ipc/ipc_message_macros.h"
21 #include "ipc/ipc_platform_file.h"
22 #include "ui/base/l10n/l10n_util.h"
24 using content::BrowserThread;
26 namespace safe_browsing {
28 SandboxedZipAnalyzer::SandboxedZipAnalyzer(
29 const base::FilePath& zip_file,
30 const ResultCallback& result_callback)
31 : zip_file_name_(zip_file),
32 callback_(result_callback),
33 callback_called_(false) {
36 void SandboxedZipAnalyzer::Start() {
37 DCHECK_CURRENTLY_ON(BrowserThread::UI);
38 // Starting the analyzer will block on opening the zip file, so run this
39 // on a worker thread. The task does not need to block shutdown.
40 if (!BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior(
41 FROM_HERE,
42 base::Bind(&SandboxedZipAnalyzer::AnalyzeInSandbox, this),
43 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)) {
44 NOTREACHED();
48 SandboxedZipAnalyzer::~SandboxedZipAnalyzer() {
49 // If we're using UtilityProcessHost, we may not be destroyed on
50 // the UI or IO thread.
51 CloseTemporaryFile();
54 void SandboxedZipAnalyzer::CloseTemporaryFile() {
55 if (!temp_file_.IsValid())
56 return;
57 // Close the temporary file in the blocking pool since doing so will delete
58 // the file.
59 if (!BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior(
60 FROM_HERE, base::Bind(&base::File::Close,
61 base::Owned(new base::File(temp_file_.Pass()))),
62 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)) {
63 NOTREACHED();
67 void SandboxedZipAnalyzer::AnalyzeInSandbox() {
68 // This zip file will be closed on the IO thread once it has been handed
69 // off to the child process.
70 zip_file_.Initialize(zip_file_name_,
71 base::File::FLAG_OPEN | base::File::FLAG_READ);
72 if (!zip_file_.IsValid()) {
73 DVLOG(1) << "Could not open zip file: " << zip_file_name_.value();
74 if (!BrowserThread::PostTask(
75 BrowserThread::IO, FROM_HERE,
76 base::Bind(&SandboxedZipAnalyzer::OnAnalyzeZipFileFinished, this,
77 zip_analyzer::Results()))) {
78 NOTREACHED();
80 return;
83 // This temp file will be closed in the blocking pool when results from the
84 // analyzer return.
85 base::FilePath temp_path;
86 if (base::CreateTemporaryFile(&temp_path)) {
87 temp_file_.Initialize(temp_path, (base::File::FLAG_CREATE_ALWAYS |
88 base::File::FLAG_READ |
89 base::File::FLAG_WRITE |
90 base::File::FLAG_TEMPORARY |
91 base::File::FLAG_DELETE_ON_CLOSE));
93 DVLOG_IF(1, !temp_file_.IsValid())
94 << "Could not open temporary output file: " << temp_path.value();
96 BrowserThread::PostTask(
97 BrowserThread::IO, FROM_HERE,
98 base::Bind(&SandboxedZipAnalyzer::StartProcessOnIOThread, this));
101 bool SandboxedZipAnalyzer::OnMessageReceived(const IPC::Message& message) {
102 bool handled = true;
103 IPC_BEGIN_MESSAGE_MAP(SandboxedZipAnalyzer, message)
104 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted,
105 OnUtilityProcessStarted)
106 IPC_MESSAGE_HANDLER(
107 ChromeUtilityHostMsg_AnalyzeZipFileForDownloadProtection_Finished,
108 OnAnalyzeZipFileFinished)
109 IPC_MESSAGE_UNHANDLED(handled = false)
110 IPC_END_MESSAGE_MAP()
111 return handled;
114 void SandboxedZipAnalyzer::StartProcessOnIOThread() {
115 DCHECK_CURRENTLY_ON(BrowserThread::IO);
116 utility_process_host_ = content::UtilityProcessHost::Create(
117 this,
118 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO).get())
119 ->AsWeakPtr();
120 utility_process_host_->SetName(l10n_util::GetStringUTF16(
121 IDS_UTILITY_PROCESS_SAFE_BROWSING_ZIP_FILE_ANALYZER_NAME));
122 utility_process_host_->Send(new ChromeUtilityMsg_StartupPing);
123 // Wait for the startup notification before sending the main IPC to the
124 // utility process, so that we can dup the file handle.
127 void SandboxedZipAnalyzer::OnUtilityProcessStarted() {
128 DCHECK_CURRENTLY_ON(BrowserThread::IO);
129 base::ProcessHandle utility_process =
130 content::RenderProcessHost::run_renderer_in_process() ?
131 base::GetCurrentProcessHandle() :
132 utility_process_host_->GetData().handle;
134 if (utility_process == base::kNullProcessHandle) {
135 DLOG(ERROR) << "Child process handle is null";
137 utility_process_host_->Send(
138 new ChromeUtilityMsg_AnalyzeZipFileForDownloadProtection(
139 IPC::TakeFileHandleForProcess(zip_file_.Pass(), utility_process),
140 IPC::GetFileHandleForProcess(temp_file_.GetPlatformFile(),
141 utility_process,
142 false /* !close_source_handle */)));
145 void SandboxedZipAnalyzer::OnAnalyzeZipFileFinished(
146 const zip_analyzer::Results& results) {
147 DCHECK_CURRENTLY_ON(BrowserThread::IO);
148 if (callback_called_)
149 return;
150 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
151 base::Bind(callback_, results));
152 callback_called_ = true;
153 CloseTemporaryFile();
156 } // namespace safe_browsing