1*6777b538SAndroid Build Coastguard Worker // Copyright 2013 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "components/nacl/browser/pnacl_host.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <memory>
8*6777b538SAndroid Build Coastguard Worker #include <utility>
9*6777b538SAndroid Build Coastguard Worker
10*6777b538SAndroid Build Coastguard Worker #include "base/debug/leak_annotations.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/files/file_path.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/files/file_util.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback_helpers.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/numerics/safe_math.h"
18*6777b538SAndroid Build Coastguard Worker #include "components/nacl/browser/nacl_browser.h"
19*6777b538SAndroid Build Coastguard Worker #include "components/nacl/browser/pnacl_translation_cache.h"
20*6777b538SAndroid Build Coastguard Worker #include "content/public/browser/browser_task_traits.h"
21*6777b538SAndroid Build Coastguard Worker #include "content/public/browser/browser_thread.h"
22*6777b538SAndroid Build Coastguard Worker #include "net/base/io_buffer.h"
23*6777b538SAndroid Build Coastguard Worker #include "net/base/net_errors.h"
24*6777b538SAndroid Build Coastguard Worker
25*6777b538SAndroid Build Coastguard Worker using content::BrowserThread;
26*6777b538SAndroid Build Coastguard Worker
27*6777b538SAndroid Build Coastguard Worker namespace {
28*6777b538SAndroid Build Coastguard Worker
29*6777b538SAndroid Build Coastguard Worker static const base::FilePath::CharType kTranslationCacheDirectoryName[] =
30*6777b538SAndroid Build Coastguard Worker FILE_PATH_LITERAL("PnaclTranslationCache");
31*6777b538SAndroid Build Coastguard Worker // Delay to wait for initialization of the cache backend
32*6777b538SAndroid Build Coastguard Worker static const int kTranslationCacheInitializationDelayMs = 20;
33*6777b538SAndroid Build Coastguard Worker
CloseBaseFile(base::File file)34*6777b538SAndroid Build Coastguard Worker void CloseBaseFile(base::File file) {
35*6777b538SAndroid Build Coastguard Worker base::ThreadPool::PostTask(FROM_HERE,
36*6777b538SAndroid Build Coastguard Worker {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
37*6777b538SAndroid Build Coastguard Worker base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
38*6777b538SAndroid Build Coastguard Worker base::DoNothingWithBoundArgs(std::move(file)));
39*6777b538SAndroid Build Coastguard Worker }
40*6777b538SAndroid Build Coastguard Worker
41*6777b538SAndroid Build Coastguard Worker } // namespace
42*6777b538SAndroid Build Coastguard Worker
43*6777b538SAndroid Build Coastguard Worker namespace pnacl {
44*6777b538SAndroid Build Coastguard Worker
45*6777b538SAndroid Build Coastguard Worker class FileProxy {
46*6777b538SAndroid Build Coastguard Worker public:
47*6777b538SAndroid Build Coastguard Worker FileProxy(std::unique_ptr<base::File> file, PnaclHost* host);
48*6777b538SAndroid Build Coastguard Worker int Write(scoped_refptr<net::DrainableIOBuffer> buffer);
49*6777b538SAndroid Build Coastguard Worker void WriteDone(const PnaclHost::TranslationID& id, int result);
50*6777b538SAndroid Build Coastguard Worker
51*6777b538SAndroid Build Coastguard Worker private:
52*6777b538SAndroid Build Coastguard Worker std::unique_ptr<base::File> file_;
53*6777b538SAndroid Build Coastguard Worker raw_ptr<PnaclHost> host_;
54*6777b538SAndroid Build Coastguard Worker };
55*6777b538SAndroid Build Coastguard Worker
FileProxy(std::unique_ptr<base::File> file,PnaclHost * host)56*6777b538SAndroid Build Coastguard Worker FileProxy::FileProxy(std::unique_ptr<base::File> file, PnaclHost* host)
57*6777b538SAndroid Build Coastguard Worker : file_(std::move(file)), host_(host) {}
58*6777b538SAndroid Build Coastguard Worker
Write(scoped_refptr<net::DrainableIOBuffer> buffer)59*6777b538SAndroid Build Coastguard Worker int FileProxy::Write(scoped_refptr<net::DrainableIOBuffer> buffer) {
60*6777b538SAndroid Build Coastguard Worker int rv = file_->Write(0, buffer->data(), buffer->size());
61*6777b538SAndroid Build Coastguard Worker if (rv == -1)
62*6777b538SAndroid Build Coastguard Worker PLOG(ERROR) << "FileProxy::Write error";
63*6777b538SAndroid Build Coastguard Worker return rv;
64*6777b538SAndroid Build Coastguard Worker }
65*6777b538SAndroid Build Coastguard Worker
WriteDone(const PnaclHost::TranslationID & id,int result)66*6777b538SAndroid Build Coastguard Worker void FileProxy::WriteDone(const PnaclHost::TranslationID& id, int result) {
67*6777b538SAndroid Build Coastguard Worker host_->OnBufferCopiedToTempFile(id, std::move(file_), result);
68*6777b538SAndroid Build Coastguard Worker }
69*6777b538SAndroid Build Coastguard Worker
70*6777b538SAndroid Build Coastguard Worker PnaclHost::PnaclHost() = default;
71*6777b538SAndroid Build Coastguard Worker
GetInstance()72*6777b538SAndroid Build Coastguard Worker PnaclHost* PnaclHost::GetInstance() {
73*6777b538SAndroid Build Coastguard Worker static PnaclHost* instance = nullptr;
74*6777b538SAndroid Build Coastguard Worker if (!instance) {
75*6777b538SAndroid Build Coastguard Worker instance = new PnaclHost;
76*6777b538SAndroid Build Coastguard Worker ANNOTATE_LEAKING_OBJECT_PTR(instance);
77*6777b538SAndroid Build Coastguard Worker }
78*6777b538SAndroid Build Coastguard Worker return instance;
79*6777b538SAndroid Build Coastguard Worker }
80*6777b538SAndroid Build Coastguard Worker
PendingTranslation()81*6777b538SAndroid Build Coastguard Worker PnaclHost::PendingTranslation::PendingTranslation()
82*6777b538SAndroid Build Coastguard Worker : process_handle(base::kNullProcessHandle),
83*6777b538SAndroid Build Coastguard Worker nexe_fd(nullptr),
84*6777b538SAndroid Build Coastguard Worker got_nexe_fd(false),
85*6777b538SAndroid Build Coastguard Worker got_cache_reply(false),
86*6777b538SAndroid Build Coastguard Worker got_cache_hit(false),
87*6777b538SAndroid Build Coastguard Worker is_incognito(false),
88*6777b538SAndroid Build Coastguard Worker callback(NexeFdCallback()),
89*6777b538SAndroid Build Coastguard Worker cache_info(nacl::PnaclCacheInfo()) {}
90*6777b538SAndroid Build Coastguard Worker
91*6777b538SAndroid Build Coastguard Worker PnaclHost::PendingTranslation::PendingTranslation(
92*6777b538SAndroid Build Coastguard Worker const PendingTranslation& other) = default;
93*6777b538SAndroid Build Coastguard Worker
~PendingTranslation()94*6777b538SAndroid Build Coastguard Worker PnaclHost::PendingTranslation::~PendingTranslation() {
95*6777b538SAndroid Build Coastguard Worker if (nexe_fd)
96*6777b538SAndroid Build Coastguard Worker delete nexe_fd;
97*6777b538SAndroid Build Coastguard Worker }
98*6777b538SAndroid Build Coastguard Worker
TranslationMayBeCached(const PendingTranslationMap::iterator & entry)99*6777b538SAndroid Build Coastguard Worker bool PnaclHost::TranslationMayBeCached(
100*6777b538SAndroid Build Coastguard Worker const PendingTranslationMap::iterator& entry) {
101*6777b538SAndroid Build Coastguard Worker return !entry->second.is_incognito &&
102*6777b538SAndroid Build Coastguard Worker !entry->second.cache_info.has_no_store_header;
103*6777b538SAndroid Build Coastguard Worker }
104*6777b538SAndroid Build Coastguard Worker
105*6777b538SAndroid Build Coastguard Worker /////////////////////////////////////// Initialization
106*6777b538SAndroid Build Coastguard Worker
GetCachePath()107*6777b538SAndroid Build Coastguard Worker static base::FilePath GetCachePath() {
108*6777b538SAndroid Build Coastguard Worker NaClBrowserDelegate* browser_delegate = nacl::NaClBrowser::GetDelegate();
109*6777b538SAndroid Build Coastguard Worker // Determine where the translation cache resides in the file system. It
110*6777b538SAndroid Build Coastguard Worker // exists in Chrome's cache directory and is not tied to any specific
111*6777b538SAndroid Build Coastguard Worker // profile. If we fail, return an empty path.
112*6777b538SAndroid Build Coastguard Worker // Start by finding the user data directory.
113*6777b538SAndroid Build Coastguard Worker base::FilePath user_data_dir;
114*6777b538SAndroid Build Coastguard Worker if (!browser_delegate ||
115*6777b538SAndroid Build Coastguard Worker !browser_delegate->GetUserDirectory(&user_data_dir)) {
116*6777b538SAndroid Build Coastguard Worker return base::FilePath();
117*6777b538SAndroid Build Coastguard Worker }
118*6777b538SAndroid Build Coastguard Worker // The cache directory may or may not be the user data directory.
119*6777b538SAndroid Build Coastguard Worker base::FilePath cache_file_path;
120*6777b538SAndroid Build Coastguard Worker browser_delegate->GetCacheDirectory(&cache_file_path);
121*6777b538SAndroid Build Coastguard Worker
122*6777b538SAndroid Build Coastguard Worker // Append the base file name to the cache directory.
123*6777b538SAndroid Build Coastguard Worker return cache_file_path.Append(kTranslationCacheDirectoryName);
124*6777b538SAndroid Build Coastguard Worker }
125*6777b538SAndroid Build Coastguard Worker
OnCacheInitialized(int net_error)126*6777b538SAndroid Build Coastguard Worker void PnaclHost::OnCacheInitialized(int net_error) {
127*6777b538SAndroid Build Coastguard Worker DCHECK(thread_checker_.CalledOnValidThread());
128*6777b538SAndroid Build Coastguard Worker // If the cache was cleared before the load completed, ignore.
129*6777b538SAndroid Build Coastguard Worker if (cache_state_ == CacheReady)
130*6777b538SAndroid Build Coastguard Worker return;
131*6777b538SAndroid Build Coastguard Worker if (net_error != net::OK) {
132*6777b538SAndroid Build Coastguard Worker // This will cause the cache to attempt to re-init on the next call to
133*6777b538SAndroid Build Coastguard Worker // GetNexeFd.
134*6777b538SAndroid Build Coastguard Worker cache_state_ = CacheUninitialized;
135*6777b538SAndroid Build Coastguard Worker } else {
136*6777b538SAndroid Build Coastguard Worker cache_state_ = CacheReady;
137*6777b538SAndroid Build Coastguard Worker }
138*6777b538SAndroid Build Coastguard Worker }
139*6777b538SAndroid Build Coastguard Worker
Init()140*6777b538SAndroid Build Coastguard Worker void PnaclHost::Init() {
141*6777b538SAndroid Build Coastguard Worker // Extra check that we're on the real UI thread since this version of
142*6777b538SAndroid Build Coastguard Worker // Init isn't used in unit tests.
143*6777b538SAndroid Build Coastguard Worker DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
144*6777b538SAndroid Build Coastguard Worker DCHECK(thread_checker_.CalledOnValidThread());
145*6777b538SAndroid Build Coastguard Worker base::FilePath cache_path(GetCachePath());
146*6777b538SAndroid Build Coastguard Worker if (cache_path.empty() || cache_state_ != CacheUninitialized)
147*6777b538SAndroid Build Coastguard Worker return;
148*6777b538SAndroid Build Coastguard Worker disk_cache_ = std::make_unique<PnaclTranslationCache>();
149*6777b538SAndroid Build Coastguard Worker cache_state_ = CacheInitializing;
150*6777b538SAndroid Build Coastguard Worker int rv = disk_cache_->InitOnDisk(
151*6777b538SAndroid Build Coastguard Worker cache_path,
152*6777b538SAndroid Build Coastguard Worker base::BindOnce(&PnaclHost::OnCacheInitialized, base::Unretained(this)));
153*6777b538SAndroid Build Coastguard Worker if (rv != net::ERR_IO_PENDING)
154*6777b538SAndroid Build Coastguard Worker OnCacheInitialized(rv);
155*6777b538SAndroid Build Coastguard Worker }
156*6777b538SAndroid Build Coastguard Worker
157*6777b538SAndroid Build Coastguard Worker // Initialize for testing, optionally using the in-memory backend, and manually
158*6777b538SAndroid Build Coastguard Worker // setting the temporary file directory instead of using the system directory,
159*6777b538SAndroid Build Coastguard Worker // and re-initializing file task runner.
InitForTest(base::FilePath temp_dir,bool in_memory)160*6777b538SAndroid Build Coastguard Worker void PnaclHost::InitForTest(base::FilePath temp_dir, bool in_memory) {
161*6777b538SAndroid Build Coastguard Worker DCHECK(thread_checker_.CalledOnValidThread());
162*6777b538SAndroid Build Coastguard Worker file_task_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
163*6777b538SAndroid Build Coastguard Worker {base::MayBlock(), base::TaskPriority::USER_VISIBLE});
164*6777b538SAndroid Build Coastguard Worker disk_cache_ = std::make_unique<PnaclTranslationCache>();
165*6777b538SAndroid Build Coastguard Worker cache_state_ = CacheInitializing;
166*6777b538SAndroid Build Coastguard Worker temp_dir_ = temp_dir;
167*6777b538SAndroid Build Coastguard Worker int rv;
168*6777b538SAndroid Build Coastguard Worker if (in_memory) {
169*6777b538SAndroid Build Coastguard Worker rv = disk_cache_->InitInMemory(
170*6777b538SAndroid Build Coastguard Worker base::BindOnce(&PnaclHost::OnCacheInitialized, base::Unretained(this)));
171*6777b538SAndroid Build Coastguard Worker } else {
172*6777b538SAndroid Build Coastguard Worker rv = disk_cache_->InitOnDisk(
173*6777b538SAndroid Build Coastguard Worker temp_dir,
174*6777b538SAndroid Build Coastguard Worker base::BindOnce(&PnaclHost::OnCacheInitialized, base::Unretained(this)));
175*6777b538SAndroid Build Coastguard Worker }
176*6777b538SAndroid Build Coastguard Worker if (rv != net::ERR_IO_PENDING)
177*6777b538SAndroid Build Coastguard Worker OnCacheInitialized(rv);
178*6777b538SAndroid Build Coastguard Worker }
179*6777b538SAndroid Build Coastguard Worker
180*6777b538SAndroid Build Coastguard Worker ///////////////////////////////////////// Temp files
181*6777b538SAndroid Build Coastguard Worker
182*6777b538SAndroid Build Coastguard Worker // Create a temporary file on |file_task_runner_|.
183*6777b538SAndroid Build Coastguard Worker // static
DoCreateTemporaryFile(base::FilePath temp_dir,TempFileCallback cb)184*6777b538SAndroid Build Coastguard Worker void PnaclHost::DoCreateTemporaryFile(base::FilePath temp_dir,
185*6777b538SAndroid Build Coastguard Worker TempFileCallback cb) {
186*6777b538SAndroid Build Coastguard Worker base::FilePath file_path;
187*6777b538SAndroid Build Coastguard Worker base::File file;
188*6777b538SAndroid Build Coastguard Worker bool rv = temp_dir.empty()
189*6777b538SAndroid Build Coastguard Worker ? base::CreateTemporaryFile(&file_path)
190*6777b538SAndroid Build Coastguard Worker : base::CreateTemporaryFileInDir(temp_dir, &file_path);
191*6777b538SAndroid Build Coastguard Worker if (!rv) {
192*6777b538SAndroid Build Coastguard Worker PLOG(ERROR) << "Temp file creation failed.";
193*6777b538SAndroid Build Coastguard Worker } else {
194*6777b538SAndroid Build Coastguard Worker uint32_t flags = base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_READ |
195*6777b538SAndroid Build Coastguard Worker base::File::FLAG_WRITE | base::File::FLAG_WIN_TEMPORARY |
196*6777b538SAndroid Build Coastguard Worker base::File::FLAG_DELETE_ON_CLOSE;
197*6777b538SAndroid Build Coastguard Worker // This temporary file is being passed to an untrusted process.
198*6777b538SAndroid Build Coastguard Worker flags = base::File::AddFlagsForPassingToUntrustedProcess(flags);
199*6777b538SAndroid Build Coastguard Worker file.Initialize(file_path, flags);
200*6777b538SAndroid Build Coastguard Worker
201*6777b538SAndroid Build Coastguard Worker if (!file.IsValid())
202*6777b538SAndroid Build Coastguard Worker PLOG(ERROR) << "Temp file open failed: " << file.error_details();
203*6777b538SAndroid Build Coastguard Worker }
204*6777b538SAndroid Build Coastguard Worker content::GetUIThreadTaskRunner({})->PostTask(
205*6777b538SAndroid Build Coastguard Worker FROM_HERE, base::BindOnce(cb, std::move(file)));
206*6777b538SAndroid Build Coastguard Worker }
207*6777b538SAndroid Build Coastguard Worker
CreateTemporaryFile(TempFileCallback cb)208*6777b538SAndroid Build Coastguard Worker void PnaclHost::CreateTemporaryFile(TempFileCallback cb) {
209*6777b538SAndroid Build Coastguard Worker if (!file_task_runner_->PostTask(
210*6777b538SAndroid Build Coastguard Worker FROM_HERE,
211*6777b538SAndroid Build Coastguard Worker base::BindOnce(&PnaclHost::DoCreateTemporaryFile, temp_dir_, cb))) {
212*6777b538SAndroid Build Coastguard Worker DCHECK(thread_checker_.CalledOnValidThread());
213*6777b538SAndroid Build Coastguard Worker cb.Run(base::File());
214*6777b538SAndroid Build Coastguard Worker }
215*6777b538SAndroid Build Coastguard Worker }
216*6777b538SAndroid Build Coastguard Worker
217*6777b538SAndroid Build Coastguard Worker ///////////////////////////////////////// GetNexeFd implementation
218*6777b538SAndroid Build Coastguard Worker ////////////////////// Common steps
219*6777b538SAndroid Build Coastguard Worker
GetNexeFd(int render_process_id,int pp_instance,bool is_incognito,const nacl::PnaclCacheInfo & cache_info,const NexeFdCallback & cb)220*6777b538SAndroid Build Coastguard Worker void PnaclHost::GetNexeFd(int render_process_id,
221*6777b538SAndroid Build Coastguard Worker int pp_instance,
222*6777b538SAndroid Build Coastguard Worker bool is_incognito,
223*6777b538SAndroid Build Coastguard Worker const nacl::PnaclCacheInfo& cache_info,
224*6777b538SAndroid Build Coastguard Worker const NexeFdCallback& cb) {
225*6777b538SAndroid Build Coastguard Worker DCHECK(thread_checker_.CalledOnValidThread());
226*6777b538SAndroid Build Coastguard Worker if (cache_state_ == CacheUninitialized) {
227*6777b538SAndroid Build Coastguard Worker Init();
228*6777b538SAndroid Build Coastguard Worker }
229*6777b538SAndroid Build Coastguard Worker if (cache_state_ != CacheReady) {
230*6777b538SAndroid Build Coastguard Worker // If the backend hasn't yet initialized, try the request again later.
231*6777b538SAndroid Build Coastguard Worker content::GetUIThreadTaskRunner({})->PostDelayedTask(
232*6777b538SAndroid Build Coastguard Worker FROM_HERE,
233*6777b538SAndroid Build Coastguard Worker base::BindOnce(&PnaclHost::GetNexeFd, base::Unretained(this),
234*6777b538SAndroid Build Coastguard Worker render_process_id, pp_instance, is_incognito, cache_info,
235*6777b538SAndroid Build Coastguard Worker cb),
236*6777b538SAndroid Build Coastguard Worker base::Milliseconds(kTranslationCacheInitializationDelayMs));
237*6777b538SAndroid Build Coastguard Worker return;
238*6777b538SAndroid Build Coastguard Worker }
239*6777b538SAndroid Build Coastguard Worker
240*6777b538SAndroid Build Coastguard Worker TranslationID id(render_process_id, pp_instance);
241*6777b538SAndroid Build Coastguard Worker auto entry = pending_translations_.find(id);
242*6777b538SAndroid Build Coastguard Worker if (entry != pending_translations_.end()) {
243*6777b538SAndroid Build Coastguard Worker // Existing translation must have been abandonded. Clean it up.
244*6777b538SAndroid Build Coastguard Worker LOG(ERROR) << "GetNexeFd for already-pending translation";
245*6777b538SAndroid Build Coastguard Worker pending_translations_.erase(entry);
246*6777b538SAndroid Build Coastguard Worker }
247*6777b538SAndroid Build Coastguard Worker
248*6777b538SAndroid Build Coastguard Worker std::string cache_key(disk_cache_->GetKey(cache_info));
249*6777b538SAndroid Build Coastguard Worker if (cache_key.empty()) {
250*6777b538SAndroid Build Coastguard Worker LOG(ERROR) << "GetNexeFd: Invalid cache info";
251*6777b538SAndroid Build Coastguard Worker cb.Run(base::File(), false);
252*6777b538SAndroid Build Coastguard Worker return;
253*6777b538SAndroid Build Coastguard Worker }
254*6777b538SAndroid Build Coastguard Worker
255*6777b538SAndroid Build Coastguard Worker PendingTranslation pt;
256*6777b538SAndroid Build Coastguard Worker pt.callback = cb;
257*6777b538SAndroid Build Coastguard Worker pt.cache_info = cache_info;
258*6777b538SAndroid Build Coastguard Worker pt.cache_key = cache_key;
259*6777b538SAndroid Build Coastguard Worker pt.is_incognito = is_incognito;
260*6777b538SAndroid Build Coastguard Worker pending_translations_[id] = pt;
261*6777b538SAndroid Build Coastguard Worker SendCacheQueryAndTempFileRequest(cache_key, id);
262*6777b538SAndroid Build Coastguard Worker }
263*6777b538SAndroid Build Coastguard Worker
264*6777b538SAndroid Build Coastguard Worker // Dispatch the cache read request and the temp file creation request
265*6777b538SAndroid Build Coastguard Worker // simultaneously; currently we need a temp file regardless of whether the
266*6777b538SAndroid Build Coastguard Worker // request hits.
SendCacheQueryAndTempFileRequest(const std::string & cache_key,const TranslationID & id)267*6777b538SAndroid Build Coastguard Worker void PnaclHost::SendCacheQueryAndTempFileRequest(const std::string& cache_key,
268*6777b538SAndroid Build Coastguard Worker const TranslationID& id) {
269*6777b538SAndroid Build Coastguard Worker DCHECK(thread_checker_.CalledOnValidThread());
270*6777b538SAndroid Build Coastguard Worker pending_backend_operations_++;
271*6777b538SAndroid Build Coastguard Worker disk_cache_->GetNexe(cache_key, base::BindOnce(&PnaclHost::OnCacheQueryReturn,
272*6777b538SAndroid Build Coastguard Worker base::Unretained(this), id));
273*6777b538SAndroid Build Coastguard Worker
274*6777b538SAndroid Build Coastguard Worker CreateTemporaryFile(base::BindRepeating(&PnaclHost::OnTempFileReturn,
275*6777b538SAndroid Build Coastguard Worker base::Unretained(this), id));
276*6777b538SAndroid Build Coastguard Worker }
277*6777b538SAndroid Build Coastguard Worker
278*6777b538SAndroid Build Coastguard Worker // Callback from the translation cache query. |id| is bound from
279*6777b538SAndroid Build Coastguard Worker // SendCacheQueryAndTempFileRequest, |net_error| is a net::Error code (which for
280*6777b538SAndroid Build Coastguard Worker // our purposes means a hit if it's net::OK (i.e. 0). |buffer| is allocated
281*6777b538SAndroid Build Coastguard Worker // by PnaclTranslationCache and now belongs to PnaclHost.
282*6777b538SAndroid Build Coastguard Worker // (Bound callbacks must re-lookup the TranslationID because the translation
283*6777b538SAndroid Build Coastguard Worker // could be cancelled before they get called).
OnCacheQueryReturn(const TranslationID & id,int net_error,scoped_refptr<net::DrainableIOBuffer> buffer)284*6777b538SAndroid Build Coastguard Worker void PnaclHost::OnCacheQueryReturn(
285*6777b538SAndroid Build Coastguard Worker const TranslationID& id,
286*6777b538SAndroid Build Coastguard Worker int net_error,
287*6777b538SAndroid Build Coastguard Worker scoped_refptr<net::DrainableIOBuffer> buffer) {
288*6777b538SAndroid Build Coastguard Worker DCHECK(thread_checker_.CalledOnValidThread());
289*6777b538SAndroid Build Coastguard Worker pending_backend_operations_--;
290*6777b538SAndroid Build Coastguard Worker auto entry(pending_translations_.find(id));
291*6777b538SAndroid Build Coastguard Worker if (entry == pending_translations_.end()) {
292*6777b538SAndroid Build Coastguard Worker LOG(ERROR) << "OnCacheQueryReturn: id not found";
293*6777b538SAndroid Build Coastguard Worker DeInitIfSafe();
294*6777b538SAndroid Build Coastguard Worker return;
295*6777b538SAndroid Build Coastguard Worker }
296*6777b538SAndroid Build Coastguard Worker PendingTranslation* pt = &entry->second;
297*6777b538SAndroid Build Coastguard Worker pt->got_cache_reply = true;
298*6777b538SAndroid Build Coastguard Worker pt->got_cache_hit = (net_error == net::OK);
299*6777b538SAndroid Build Coastguard Worker if (pt->got_cache_hit)
300*6777b538SAndroid Build Coastguard Worker pt->nexe_read_buffer = buffer;
301*6777b538SAndroid Build Coastguard Worker CheckCacheQueryReady(entry);
302*6777b538SAndroid Build Coastguard Worker }
303*6777b538SAndroid Build Coastguard Worker
304*6777b538SAndroid Build Coastguard Worker // Callback from temp file creation. |id| is bound from
305*6777b538SAndroid Build Coastguard Worker // SendCacheQueryAndTempFileRequest, and |file| is the created file.
306*6777b538SAndroid Build Coastguard Worker // If there was an error, file is invalid.
307*6777b538SAndroid Build Coastguard Worker // (Bound callbacks must re-lookup the TranslationID because the translation
308*6777b538SAndroid Build Coastguard Worker // could be cancelled before they get called).
OnTempFileReturn(const TranslationID & id,base::File file)309*6777b538SAndroid Build Coastguard Worker void PnaclHost::OnTempFileReturn(const TranslationID& id,
310*6777b538SAndroid Build Coastguard Worker base::File file) {
311*6777b538SAndroid Build Coastguard Worker DCHECK(thread_checker_.CalledOnValidThread());
312*6777b538SAndroid Build Coastguard Worker auto entry(pending_translations_.find(id));
313*6777b538SAndroid Build Coastguard Worker if (entry == pending_translations_.end()) {
314*6777b538SAndroid Build Coastguard Worker // The renderer may have signaled an error or closed while the temp
315*6777b538SAndroid Build Coastguard Worker // file was being created.
316*6777b538SAndroid Build Coastguard Worker LOG(ERROR) << "OnTempFileReturn: id not found";
317*6777b538SAndroid Build Coastguard Worker CloseBaseFile(std::move(file));
318*6777b538SAndroid Build Coastguard Worker return;
319*6777b538SAndroid Build Coastguard Worker }
320*6777b538SAndroid Build Coastguard Worker if (!file.IsValid()) {
321*6777b538SAndroid Build Coastguard Worker // This translation will fail, but we need to retry any translation
322*6777b538SAndroid Build Coastguard Worker // waiting for its result.
323*6777b538SAndroid Build Coastguard Worker LOG(ERROR) << "OnTempFileReturn: temp file creation failed";
324*6777b538SAndroid Build Coastguard Worker std::string key(entry->second.cache_key);
325*6777b538SAndroid Build Coastguard Worker entry->second.callback.Run(base::File(), false);
326*6777b538SAndroid Build Coastguard Worker bool may_be_cached = TranslationMayBeCached(entry);
327*6777b538SAndroid Build Coastguard Worker pending_translations_.erase(entry);
328*6777b538SAndroid Build Coastguard Worker // No translations will be waiting for entries that will not be stored.
329*6777b538SAndroid Build Coastguard Worker if (may_be_cached)
330*6777b538SAndroid Build Coastguard Worker RequeryMatchingTranslations(key);
331*6777b538SAndroid Build Coastguard Worker return;
332*6777b538SAndroid Build Coastguard Worker }
333*6777b538SAndroid Build Coastguard Worker PendingTranslation* pt = &entry->second;
334*6777b538SAndroid Build Coastguard Worker pt->got_nexe_fd = true;
335*6777b538SAndroid Build Coastguard Worker pt->nexe_fd = new base::File(std::move(file));
336*6777b538SAndroid Build Coastguard Worker CheckCacheQueryReady(entry);
337*6777b538SAndroid Build Coastguard Worker }
338*6777b538SAndroid Build Coastguard Worker
339*6777b538SAndroid Build Coastguard Worker // Check whether both the cache query and the temp file have returned, and check
340*6777b538SAndroid Build Coastguard Worker // whether we actually got a hit or not.
CheckCacheQueryReady(const PendingTranslationMap::iterator & entry)341*6777b538SAndroid Build Coastguard Worker void PnaclHost::CheckCacheQueryReady(
342*6777b538SAndroid Build Coastguard Worker const PendingTranslationMap::iterator& entry) {
343*6777b538SAndroid Build Coastguard Worker DCHECK(thread_checker_.CalledOnValidThread());
344*6777b538SAndroid Build Coastguard Worker PendingTranslation* pt = &entry->second;
345*6777b538SAndroid Build Coastguard Worker if (!(pt->got_cache_reply && pt->got_nexe_fd))
346*6777b538SAndroid Build Coastguard Worker return;
347*6777b538SAndroid Build Coastguard Worker if (!pt->got_cache_hit) {
348*6777b538SAndroid Build Coastguard Worker // Check if there is already a pending translation for this file. If there
349*6777b538SAndroid Build Coastguard Worker // is, we will wait for it to come back, to avoid redundant translations.
350*6777b538SAndroid Build Coastguard Worker for (auto it = pending_translations_.begin();
351*6777b538SAndroid Build Coastguard Worker it != pending_translations_.end(); ++it) {
352*6777b538SAndroid Build Coastguard Worker // Another translation matches if it's a request for the same file,
353*6777b538SAndroid Build Coastguard Worker if (it->second.cache_key == entry->second.cache_key &&
354*6777b538SAndroid Build Coastguard Worker // and it's not this translation,
355*6777b538SAndroid Build Coastguard Worker it->first != entry->first &&
356*6777b538SAndroid Build Coastguard Worker // and it can be stored in the cache,
357*6777b538SAndroid Build Coastguard Worker TranslationMayBeCached(it) &&
358*6777b538SAndroid Build Coastguard Worker // and it's already gotten past this check and returned the miss.
359*6777b538SAndroid Build Coastguard Worker it->second.got_cache_reply &&
360*6777b538SAndroid Build Coastguard Worker it->second.got_nexe_fd) {
361*6777b538SAndroid Build Coastguard Worker return;
362*6777b538SAndroid Build Coastguard Worker }
363*6777b538SAndroid Build Coastguard Worker }
364*6777b538SAndroid Build Coastguard Worker ReturnMiss(entry);
365*6777b538SAndroid Build Coastguard Worker return;
366*6777b538SAndroid Build Coastguard Worker }
367*6777b538SAndroid Build Coastguard Worker
368*6777b538SAndroid Build Coastguard Worker std::unique_ptr<base::File> file(pt->nexe_fd);
369*6777b538SAndroid Build Coastguard Worker pt->nexe_fd = nullptr;
370*6777b538SAndroid Build Coastguard Worker pt->got_nexe_fd = false;
371*6777b538SAndroid Build Coastguard Worker FileProxy* proxy(new FileProxy(std::move(file), this));
372*6777b538SAndroid Build Coastguard Worker
373*6777b538SAndroid Build Coastguard Worker base::ThreadPool::PostTaskAndReplyWithResult(
374*6777b538SAndroid Build Coastguard Worker FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
375*6777b538SAndroid Build Coastguard Worker base::BindOnce(&FileProxy::Write, base::Unretained(proxy),
376*6777b538SAndroid Build Coastguard Worker pt->nexe_read_buffer),
377*6777b538SAndroid Build Coastguard Worker base::BindOnce(&FileProxy::WriteDone, base::Owned(proxy), entry->first));
378*6777b538SAndroid Build Coastguard Worker }
379*6777b538SAndroid Build Coastguard Worker
380*6777b538SAndroid Build Coastguard Worker //////////////////// GetNexeFd miss path
381*6777b538SAndroid Build Coastguard Worker // Return the temp fd to the renderer, reporting a miss.
ReturnMiss(const PendingTranslationMap::iterator & entry)382*6777b538SAndroid Build Coastguard Worker void PnaclHost::ReturnMiss(const PendingTranslationMap::iterator& entry) {
383*6777b538SAndroid Build Coastguard Worker // Return the fd
384*6777b538SAndroid Build Coastguard Worker PendingTranslation* pt = &entry->second;
385*6777b538SAndroid Build Coastguard Worker NexeFdCallback cb(pt->callback);
386*6777b538SAndroid Build Coastguard Worker cb.Run(*pt->nexe_fd, false);
387*6777b538SAndroid Build Coastguard Worker if (!pt->nexe_fd->IsValid()) {
388*6777b538SAndroid Build Coastguard Worker // Bad FD is unrecoverable, so clear out the entry.
389*6777b538SAndroid Build Coastguard Worker pending_translations_.erase(entry);
390*6777b538SAndroid Build Coastguard Worker }
391*6777b538SAndroid Build Coastguard Worker }
392*6777b538SAndroid Build Coastguard Worker
393*6777b538SAndroid Build Coastguard Worker // On error, just return a null refptr.
394*6777b538SAndroid Build Coastguard Worker // static
CopyFileToBuffer(std::unique_ptr<base::File> file)395*6777b538SAndroid Build Coastguard Worker scoped_refptr<net::DrainableIOBuffer> PnaclHost::CopyFileToBuffer(
396*6777b538SAndroid Build Coastguard Worker std::unique_ptr<base::File> file) {
397*6777b538SAndroid Build Coastguard Worker scoped_refptr<net::DrainableIOBuffer> buffer;
398*6777b538SAndroid Build Coastguard Worker
399*6777b538SAndroid Build Coastguard Worker // TODO(eroman): Maximum size should be changed to size_t once that is
400*6777b538SAndroid Build Coastguard Worker // what IOBuffer requires. crbug.com/488553. Also I don't think the
401*6777b538SAndroid Build Coastguard Worker // max size should be inclusive here...
402*6777b538SAndroid Build Coastguard Worker int64_t file_size = file->GetLength();
403*6777b538SAndroid Build Coastguard Worker if (file_size < 0 || file_size > std::numeric_limits<int>::max()) {
404*6777b538SAndroid Build Coastguard Worker PLOG(ERROR) << "Get file length failed " << file_size;
405*6777b538SAndroid Build Coastguard Worker return buffer;
406*6777b538SAndroid Build Coastguard Worker }
407*6777b538SAndroid Build Coastguard Worker
408*6777b538SAndroid Build Coastguard Worker buffer = base::MakeRefCounted<net::DrainableIOBuffer>(
409*6777b538SAndroid Build Coastguard Worker base::MakeRefCounted<net::IOBufferWithSize>(
410*6777b538SAndroid Build Coastguard Worker base::checked_cast<size_t>(file_size)),
411*6777b538SAndroid Build Coastguard Worker base::checked_cast<size_t>(file_size));
412*6777b538SAndroid Build Coastguard Worker if (file->Read(0, buffer->data(), buffer->size()) != file_size) {
413*6777b538SAndroid Build Coastguard Worker PLOG(ERROR) << "CopyFileToBuffer file read failed";
414*6777b538SAndroid Build Coastguard Worker buffer = nullptr;
415*6777b538SAndroid Build Coastguard Worker }
416*6777b538SAndroid Build Coastguard Worker return buffer;
417*6777b538SAndroid Build Coastguard Worker }
418*6777b538SAndroid Build Coastguard Worker
419*6777b538SAndroid Build Coastguard Worker // Called by the renderer in the miss path to report a finished translation
TranslationFinished(int render_process_id,int pp_instance,bool success)420*6777b538SAndroid Build Coastguard Worker void PnaclHost::TranslationFinished(int render_process_id,
421*6777b538SAndroid Build Coastguard Worker int pp_instance,
422*6777b538SAndroid Build Coastguard Worker bool success) {
423*6777b538SAndroid Build Coastguard Worker DCHECK(thread_checker_.CalledOnValidThread());
424*6777b538SAndroid Build Coastguard Worker if (cache_state_ != CacheReady)
425*6777b538SAndroid Build Coastguard Worker return;
426*6777b538SAndroid Build Coastguard Worker TranslationID id(render_process_id, pp_instance);
427*6777b538SAndroid Build Coastguard Worker auto entry(pending_translations_.find(id));
428*6777b538SAndroid Build Coastguard Worker if (entry == pending_translations_.end()) {
429*6777b538SAndroid Build Coastguard Worker LOG(ERROR) << "TranslationFinished: TranslationID " << render_process_id
430*6777b538SAndroid Build Coastguard Worker << "," << pp_instance << " not found.";
431*6777b538SAndroid Build Coastguard Worker return;
432*6777b538SAndroid Build Coastguard Worker }
433*6777b538SAndroid Build Coastguard Worker bool store_nexe = true;
434*6777b538SAndroid Build Coastguard Worker // If this is a premature response (i.e. we haven't returned a temp file
435*6777b538SAndroid Build Coastguard Worker // yet) or if it's an unsuccessful translation, or if we are incognito,
436*6777b538SAndroid Build Coastguard Worker // don't store in the cache.
437*6777b538SAndroid Build Coastguard Worker // TODO(dschuff): use a separate in-memory cache for incognito
438*6777b538SAndroid Build Coastguard Worker // translations.
439*6777b538SAndroid Build Coastguard Worker if (!entry->second.got_nexe_fd || !entry->second.got_cache_reply ||
440*6777b538SAndroid Build Coastguard Worker !success || !TranslationMayBeCached(entry)) {
441*6777b538SAndroid Build Coastguard Worker store_nexe = false;
442*6777b538SAndroid Build Coastguard Worker } else {
443*6777b538SAndroid Build Coastguard Worker std::unique_ptr<base::File> file(entry->second.nexe_fd);
444*6777b538SAndroid Build Coastguard Worker entry->second.nexe_fd = nullptr;
445*6777b538SAndroid Build Coastguard Worker entry->second.got_nexe_fd = false;
446*6777b538SAndroid Build Coastguard Worker
447*6777b538SAndroid Build Coastguard Worker base::ThreadPool::PostTaskAndReplyWithResult(
448*6777b538SAndroid Build Coastguard Worker FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
449*6777b538SAndroid Build Coastguard Worker base::BindOnce(&PnaclHost::CopyFileToBuffer, std::move(file)),
450*6777b538SAndroid Build Coastguard Worker base::BindOnce(&PnaclHost::StoreTranslatedNexe, base::Unretained(this),
451*6777b538SAndroid Build Coastguard Worker id));
452*6777b538SAndroid Build Coastguard Worker }
453*6777b538SAndroid Build Coastguard Worker
454*6777b538SAndroid Build Coastguard Worker if (!store_nexe) {
455*6777b538SAndroid Build Coastguard Worker // If store_nexe is true, the fd will be closed by CopyFileToBuffer.
456*6777b538SAndroid Build Coastguard Worker if (entry->second.got_nexe_fd) {
457*6777b538SAndroid Build Coastguard Worker std::unique_ptr<base::File> file(entry->second.nexe_fd);
458*6777b538SAndroid Build Coastguard Worker entry->second.nexe_fd = nullptr;
459*6777b538SAndroid Build Coastguard Worker CloseBaseFile(std::move(*file.get()));
460*6777b538SAndroid Build Coastguard Worker }
461*6777b538SAndroid Build Coastguard Worker pending_translations_.erase(entry);
462*6777b538SAndroid Build Coastguard Worker }
463*6777b538SAndroid Build Coastguard Worker }
464*6777b538SAndroid Build Coastguard Worker
465*6777b538SAndroid Build Coastguard Worker // Store the translated nexe in the translation cache. Called back with the
466*6777b538SAndroid Build Coastguard Worker // TranslationID from the host and the result of CopyFileToBuffer.
467*6777b538SAndroid Build Coastguard Worker // (Bound callbacks must re-lookup the TranslationID because the translation
468*6777b538SAndroid Build Coastguard Worker // could be cancelled before they get called).
StoreTranslatedNexe(TranslationID id,scoped_refptr<net::DrainableIOBuffer> buffer)469*6777b538SAndroid Build Coastguard Worker void PnaclHost::StoreTranslatedNexe(
470*6777b538SAndroid Build Coastguard Worker TranslationID id,
471*6777b538SAndroid Build Coastguard Worker scoped_refptr<net::DrainableIOBuffer> buffer) {
472*6777b538SAndroid Build Coastguard Worker DCHECK(thread_checker_.CalledOnValidThread());
473*6777b538SAndroid Build Coastguard Worker if (cache_state_ != CacheReady)
474*6777b538SAndroid Build Coastguard Worker return;
475*6777b538SAndroid Build Coastguard Worker auto it(pending_translations_.find(id));
476*6777b538SAndroid Build Coastguard Worker if (it == pending_translations_.end()) {
477*6777b538SAndroid Build Coastguard Worker LOG(ERROR) << "StoreTranslatedNexe: TranslationID " << id.first << ","
478*6777b538SAndroid Build Coastguard Worker << id.second << " not found.";
479*6777b538SAndroid Build Coastguard Worker return;
480*6777b538SAndroid Build Coastguard Worker }
481*6777b538SAndroid Build Coastguard Worker
482*6777b538SAndroid Build Coastguard Worker if (!buffer.get()) {
483*6777b538SAndroid Build Coastguard Worker LOG(ERROR) << "Error reading translated nexe";
484*6777b538SAndroid Build Coastguard Worker return;
485*6777b538SAndroid Build Coastguard Worker }
486*6777b538SAndroid Build Coastguard Worker pending_backend_operations_++;
487*6777b538SAndroid Build Coastguard Worker disk_cache_->StoreNexe(it->second.cache_key, buffer.get(),
488*6777b538SAndroid Build Coastguard Worker base::BindOnce(&PnaclHost::OnTranslatedNexeStored,
489*6777b538SAndroid Build Coastguard Worker base::Unretained(this), it->first));
490*6777b538SAndroid Build Coastguard Worker }
491*6777b538SAndroid Build Coastguard Worker
492*6777b538SAndroid Build Coastguard Worker // After we know the nexe has been stored, we can clean up, and unblock any
493*6777b538SAndroid Build Coastguard Worker // outstanding requests for the same file.
494*6777b538SAndroid Build Coastguard Worker // (Bound callbacks must re-lookup the TranslationID because the translation
495*6777b538SAndroid Build Coastguard Worker // could be cancelled before they get called).
OnTranslatedNexeStored(const TranslationID & id,int net_error)496*6777b538SAndroid Build Coastguard Worker void PnaclHost::OnTranslatedNexeStored(const TranslationID& id, int net_error) {
497*6777b538SAndroid Build Coastguard Worker auto entry(pending_translations_.find(id));
498*6777b538SAndroid Build Coastguard Worker pending_backend_operations_--;
499*6777b538SAndroid Build Coastguard Worker if (entry == pending_translations_.end()) {
500*6777b538SAndroid Build Coastguard Worker // If the renderer closed while we were storing the nexe, we land here.
501*6777b538SAndroid Build Coastguard Worker // Make sure we try to de-init.
502*6777b538SAndroid Build Coastguard Worker DeInitIfSafe();
503*6777b538SAndroid Build Coastguard Worker return;
504*6777b538SAndroid Build Coastguard Worker }
505*6777b538SAndroid Build Coastguard Worker std::string key(entry->second.cache_key);
506*6777b538SAndroid Build Coastguard Worker pending_translations_.erase(entry);
507*6777b538SAndroid Build Coastguard Worker RequeryMatchingTranslations(key);
508*6777b538SAndroid Build Coastguard Worker }
509*6777b538SAndroid Build Coastguard Worker
510*6777b538SAndroid Build Coastguard Worker // Check if any pending translations match |key|. If so, re-issue the cache
511*6777b538SAndroid Build Coastguard Worker // query. In the overlapped miss case, we expect a hit this time, but a miss
512*6777b538SAndroid Build Coastguard Worker // is also possible in case of an error.
RequeryMatchingTranslations(const std::string & key)513*6777b538SAndroid Build Coastguard Worker void PnaclHost::RequeryMatchingTranslations(const std::string& key) {
514*6777b538SAndroid Build Coastguard Worker DCHECK(thread_checker_.CalledOnValidThread());
515*6777b538SAndroid Build Coastguard Worker // Check for outstanding misses to this same file
516*6777b538SAndroid Build Coastguard Worker for (auto it = pending_translations_.begin();
517*6777b538SAndroid Build Coastguard Worker it != pending_translations_.end(); ++it) {
518*6777b538SAndroid Build Coastguard Worker if (it->second.cache_key == key) {
519*6777b538SAndroid Build Coastguard Worker // Re-send the cache read request. This time we expect a hit, but if
520*6777b538SAndroid Build Coastguard Worker // something goes wrong, it will just handle it like a miss.
521*6777b538SAndroid Build Coastguard Worker it->second.got_cache_reply = false;
522*6777b538SAndroid Build Coastguard Worker pending_backend_operations_++;
523*6777b538SAndroid Build Coastguard Worker disk_cache_->GetNexe(key,
524*6777b538SAndroid Build Coastguard Worker base::BindOnce(&PnaclHost::OnCacheQueryReturn,
525*6777b538SAndroid Build Coastguard Worker base::Unretained(this), it->first));
526*6777b538SAndroid Build Coastguard Worker }
527*6777b538SAndroid Build Coastguard Worker }
528*6777b538SAndroid Build Coastguard Worker }
529*6777b538SAndroid Build Coastguard Worker
530*6777b538SAndroid Build Coastguard Worker //////////////////// GetNexeFd hit path
531*6777b538SAndroid Build Coastguard Worker
OnBufferCopiedToTempFile(const TranslationID & id,std::unique_ptr<base::File> file,int file_error)532*6777b538SAndroid Build Coastguard Worker void PnaclHost::OnBufferCopiedToTempFile(const TranslationID& id,
533*6777b538SAndroid Build Coastguard Worker std::unique_ptr<base::File> file,
534*6777b538SAndroid Build Coastguard Worker int file_error) {
535*6777b538SAndroid Build Coastguard Worker DCHECK(thread_checker_.CalledOnValidThread());
536*6777b538SAndroid Build Coastguard Worker auto entry(pending_translations_.find(id));
537*6777b538SAndroid Build Coastguard Worker if (entry == pending_translations_.end()) {
538*6777b538SAndroid Build Coastguard Worker CloseBaseFile(std::move(*file.get()));
539*6777b538SAndroid Build Coastguard Worker return;
540*6777b538SAndroid Build Coastguard Worker }
541*6777b538SAndroid Build Coastguard Worker if (file_error == -1) {
542*6777b538SAndroid Build Coastguard Worker // Write error on the temp file. Request a new file and start over.
543*6777b538SAndroid Build Coastguard Worker CloseBaseFile(std::move(*file.get()));
544*6777b538SAndroid Build Coastguard Worker CreateTemporaryFile(base::BindRepeating(
545*6777b538SAndroid Build Coastguard Worker &PnaclHost::OnTempFileReturn, base::Unretained(this), entry->first));
546*6777b538SAndroid Build Coastguard Worker return;
547*6777b538SAndroid Build Coastguard Worker }
548*6777b538SAndroid Build Coastguard Worker entry->second.callback.Run(*file.get(), true);
549*6777b538SAndroid Build Coastguard Worker CloseBaseFile(std::move(*file.get()));
550*6777b538SAndroid Build Coastguard Worker pending_translations_.erase(entry);
551*6777b538SAndroid Build Coastguard Worker }
552*6777b538SAndroid Build Coastguard Worker
553*6777b538SAndroid Build Coastguard Worker ///////////////////
554*6777b538SAndroid Build Coastguard Worker
RendererClosing(int render_process_id)555*6777b538SAndroid Build Coastguard Worker void PnaclHost::RendererClosing(int render_process_id) {
556*6777b538SAndroid Build Coastguard Worker DCHECK(thread_checker_.CalledOnValidThread());
557*6777b538SAndroid Build Coastguard Worker if (cache_state_ != CacheReady)
558*6777b538SAndroid Build Coastguard Worker return;
559*6777b538SAndroid Build Coastguard Worker for (auto it = pending_translations_.begin();
560*6777b538SAndroid Build Coastguard Worker it != pending_translations_.end();) {
561*6777b538SAndroid Build Coastguard Worker auto to_erase(it++);
562*6777b538SAndroid Build Coastguard Worker if (to_erase->first.first == render_process_id) {
563*6777b538SAndroid Build Coastguard Worker // Clean up the open files.
564*6777b538SAndroid Build Coastguard Worker if (to_erase->second.nexe_fd) {
565*6777b538SAndroid Build Coastguard Worker std::unique_ptr<base::File> file(to_erase->second.nexe_fd);
566*6777b538SAndroid Build Coastguard Worker to_erase->second.nexe_fd = nullptr;
567*6777b538SAndroid Build Coastguard Worker CloseBaseFile(std::move(*file.get()));
568*6777b538SAndroid Build Coastguard Worker }
569*6777b538SAndroid Build Coastguard Worker std::string key(to_erase->second.cache_key);
570*6777b538SAndroid Build Coastguard Worker bool may_be_cached = TranslationMayBeCached(to_erase);
571*6777b538SAndroid Build Coastguard Worker pending_translations_.erase(to_erase);
572*6777b538SAndroid Build Coastguard Worker // No translations will be waiting for entries that will not be stored.
573*6777b538SAndroid Build Coastguard Worker if (may_be_cached)
574*6777b538SAndroid Build Coastguard Worker RequeryMatchingTranslations(key);
575*6777b538SAndroid Build Coastguard Worker }
576*6777b538SAndroid Build Coastguard Worker }
577*6777b538SAndroid Build Coastguard Worker DeInitIfSafe();
578*6777b538SAndroid Build Coastguard Worker }
579*6777b538SAndroid Build Coastguard Worker
580*6777b538SAndroid Build Coastguard Worker ////////////////// Cache data removal
ClearTranslationCacheEntriesBetween(base::Time initial_time,base::Time end_time,base::OnceClosure callback)581*6777b538SAndroid Build Coastguard Worker void PnaclHost::ClearTranslationCacheEntriesBetween(
582*6777b538SAndroid Build Coastguard Worker base::Time initial_time,
583*6777b538SAndroid Build Coastguard Worker base::Time end_time,
584*6777b538SAndroid Build Coastguard Worker base::OnceClosure callback) {
585*6777b538SAndroid Build Coastguard Worker DCHECK(thread_checker_.CalledOnValidThread());
586*6777b538SAndroid Build Coastguard Worker if (cache_state_ == CacheUninitialized) {
587*6777b538SAndroid Build Coastguard Worker Init();
588*6777b538SAndroid Build Coastguard Worker }
589*6777b538SAndroid Build Coastguard Worker if (cache_state_ == CacheInitializing) {
590*6777b538SAndroid Build Coastguard Worker // If the backend hasn't yet initialized, try the request again later.
591*6777b538SAndroid Build Coastguard Worker content::GetUIThreadTaskRunner({})->PostDelayedTask(
592*6777b538SAndroid Build Coastguard Worker FROM_HERE,
593*6777b538SAndroid Build Coastguard Worker base::BindOnce(&PnaclHost::ClearTranslationCacheEntriesBetween,
594*6777b538SAndroid Build Coastguard Worker base::Unretained(this), initial_time, end_time,
595*6777b538SAndroid Build Coastguard Worker std::move(callback)),
596*6777b538SAndroid Build Coastguard Worker base::Milliseconds(kTranslationCacheInitializationDelayMs));
597*6777b538SAndroid Build Coastguard Worker return;
598*6777b538SAndroid Build Coastguard Worker }
599*6777b538SAndroid Build Coastguard Worker pending_backend_operations_++;
600*6777b538SAndroid Build Coastguard Worker
601*6777b538SAndroid Build Coastguard Worker auto split_callback = base::SplitOnceCallback(std::move(callback));
602*6777b538SAndroid Build Coastguard Worker int rv = disk_cache_->DoomEntriesBetween(
603*6777b538SAndroid Build Coastguard Worker initial_time, end_time,
604*6777b538SAndroid Build Coastguard Worker base::BindOnce(&PnaclHost::OnEntriesDoomed, base::Unretained(this),
605*6777b538SAndroid Build Coastguard Worker std::move(split_callback.first)));
606*6777b538SAndroid Build Coastguard Worker if (rv != net::ERR_IO_PENDING)
607*6777b538SAndroid Build Coastguard Worker OnEntriesDoomed(std::move(split_callback.second), rv);
608*6777b538SAndroid Build Coastguard Worker }
609*6777b538SAndroid Build Coastguard Worker
OnEntriesDoomed(base::OnceClosure callback,int net_error)610*6777b538SAndroid Build Coastguard Worker void PnaclHost::OnEntriesDoomed(base::OnceClosure callback, int net_error) {
611*6777b538SAndroid Build Coastguard Worker DCHECK(thread_checker_.CalledOnValidThread());
612*6777b538SAndroid Build Coastguard Worker content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE, std::move(callback));
613*6777b538SAndroid Build Coastguard Worker pending_backend_operations_--;
614*6777b538SAndroid Build Coastguard Worker // When clearing the cache, the UI is blocked on all the cache-clearing
615*6777b538SAndroid Build Coastguard Worker // operations, and freeing the backend actually blocks the IO thread. So
616*6777b538SAndroid Build Coastguard Worker // instead of calling DeInitIfSafe directly, post it for later.
617*6777b538SAndroid Build Coastguard Worker content::GetUIThreadTaskRunner({})->PostTask(
618*6777b538SAndroid Build Coastguard Worker FROM_HERE,
619*6777b538SAndroid Build Coastguard Worker base::BindOnce(&PnaclHost::DeInitIfSafe, base::Unretained(this)));
620*6777b538SAndroid Build Coastguard Worker }
621*6777b538SAndroid Build Coastguard Worker
622*6777b538SAndroid Build Coastguard Worker // Destroying the cache backend causes it to post tasks to the cache thread to
623*6777b538SAndroid Build Coastguard Worker // flush to disk. PnaclHost is leaked on shutdown because registering it as a
624*6777b538SAndroid Build Coastguard Worker // Singleton with AtExitManager would result in it not being destroyed until all
625*6777b538SAndroid Build Coastguard Worker // the browser threads have gone away and it's too late to post anything
626*6777b538SAndroid Build Coastguard Worker // (attempting to do so hangs shutdown) at that point anyways. So we make sure
627*6777b538SAndroid Build Coastguard Worker // to destroy it when we no longer have any outstanding operations that need it.
628*6777b538SAndroid Build Coastguard Worker // These include pending translations, cache clear requests, and requests to
629*6777b538SAndroid Build Coastguard Worker // read or write translated nexes. We check when renderers close, when cache
630*6777b538SAndroid Build Coastguard Worker // clear requests finish, and when backend operations complete.
631*6777b538SAndroid Build Coastguard Worker
632*6777b538SAndroid Build Coastguard Worker // It is not safe to delete the backend while it is initializing, nor if it has
633*6777b538SAndroid Build Coastguard Worker // outstanding entry open requests; it is in theory safe to delete it with
634*6777b538SAndroid Build Coastguard Worker // outstanding read/write requests, but because that distinction is hidden
635*6777b538SAndroid Build Coastguard Worker // inside PnaclTranslationCache, we do not delete the backend if there are any
636*6777b538SAndroid Build Coastguard Worker // backend requests in flight. As a last resort in the destructor, we just leak
637*6777b538SAndroid Build Coastguard Worker // the backend to avoid hanging shutdown.
DeInitIfSafe()638*6777b538SAndroid Build Coastguard Worker void PnaclHost::DeInitIfSafe() {
639*6777b538SAndroid Build Coastguard Worker DCHECK(pending_backend_operations_ >= 0);
640*6777b538SAndroid Build Coastguard Worker if (pending_translations_.empty() &&
641*6777b538SAndroid Build Coastguard Worker pending_backend_operations_ <= 0 &&
642*6777b538SAndroid Build Coastguard Worker cache_state_ == CacheReady) {
643*6777b538SAndroid Build Coastguard Worker cache_state_ = CacheUninitialized;
644*6777b538SAndroid Build Coastguard Worker disk_cache_.reset();
645*6777b538SAndroid Build Coastguard Worker }
646*6777b538SAndroid Build Coastguard Worker }
647*6777b538SAndroid Build Coastguard Worker
648*6777b538SAndroid Build Coastguard Worker } // namespace pnacl
649