xref: /aosp_15_r20/external/cronet/components/nacl/browser/pnacl_host.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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