xref: /aosp_15_r20/external/cronet/components/nacl/browser/nacl_browser.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/nacl_browser.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <stddef.h>
8*6777b538SAndroid Build Coastguard Worker #include <utility>
9*6777b538SAndroid Build Coastguard Worker 
10*6777b538SAndroid Build Coastguard Worker #include "base/command_line.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/containers/span.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/files/file_proxy.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/files/file_util.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/lazy_instance.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/location.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_macros.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/path_service.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/pickle.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/rand_util.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/task/single_thread_task_runner.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/time/time.h"
22*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
23*6777b538SAndroid Build Coastguard Worker #include "content/public/browser/browser_task_traits.h"
24*6777b538SAndroid Build Coastguard Worker #include "content/public/browser/browser_thread.h"
25*6777b538SAndroid Build Coastguard Worker #include "url/gurl.h"
26*6777b538SAndroid Build Coastguard Worker 
27*6777b538SAndroid Build Coastguard Worker namespace {
28*6777b538SAndroid Build Coastguard Worker 
29*6777b538SAndroid Build Coastguard Worker // Tasks posted in this file are on the critical path of displaying the official
30*6777b538SAndroid Build Coastguard Worker // virtual keyboard on Chrome OS. https://crbug.com/976542
31*6777b538SAndroid Build Coastguard Worker constexpr base::TaskPriority kUserBlocking = base::TaskPriority::USER_BLOCKING;
32*6777b538SAndroid Build Coastguard Worker 
33*6777b538SAndroid Build Coastguard Worker // An arbitrary delay to coalesce multiple writes to the cache.
34*6777b538SAndroid Build Coastguard Worker const int kValidationCacheCoalescingTimeMS = 6000;
35*6777b538SAndroid Build Coastguard Worker const base::FilePath::CharType kValidationCacheFileName[] =
36*6777b538SAndroid Build Coastguard Worker     FILE_PATH_LITERAL("nacl_validation_cache.bin");
37*6777b538SAndroid Build Coastguard Worker 
38*6777b538SAndroid Build Coastguard Worker const bool kValidationCacheEnabledByDefault = true;
39*6777b538SAndroid Build Coastguard Worker 
NaClIrtName()40*6777b538SAndroid Build Coastguard Worker const base::FilePath::StringType NaClIrtName() {
41*6777b538SAndroid Build Coastguard Worker   base::FilePath::StringType irt_name(FILE_PATH_LITERAL("nacl_irt_"));
42*6777b538SAndroid Build Coastguard Worker 
43*6777b538SAndroid Build Coastguard Worker #if defined(ARCH_CPU_X86_FAMILY)
44*6777b538SAndroid Build Coastguard Worker #if defined(ARCH_CPU_X86_64)
45*6777b538SAndroid Build Coastguard Worker   irt_name.append(FILE_PATH_LITERAL("x86_64"));
46*6777b538SAndroid Build Coastguard Worker #else
47*6777b538SAndroid Build Coastguard Worker   irt_name.append(FILE_PATH_LITERAL("x86_32"));
48*6777b538SAndroid Build Coastguard Worker #endif
49*6777b538SAndroid Build Coastguard Worker #elif defined(ARCH_CPU_ARM_FAMILY)
50*6777b538SAndroid Build Coastguard Worker   irt_name.append(FILE_PATH_LITERAL("arm"));
51*6777b538SAndroid Build Coastguard Worker #elif defined(ARCH_CPU_MIPSEL)
52*6777b538SAndroid Build Coastguard Worker   irt_name.append(FILE_PATH_LITERAL("mips32"));
53*6777b538SAndroid Build Coastguard Worker #else
54*6777b538SAndroid Build Coastguard Worker #error Add support for your architecture to NaCl IRT file selection
55*6777b538SAndroid Build Coastguard Worker #endif
56*6777b538SAndroid Build Coastguard Worker   irt_name.append(FILE_PATH_LITERAL(".nexe"));
57*6777b538SAndroid Build Coastguard Worker   return irt_name;
58*6777b538SAndroid Build Coastguard Worker }
59*6777b538SAndroid Build Coastguard Worker 
60*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(IS_ANDROID)
CheckEnvVar(const char * name,bool default_value)61*6777b538SAndroid Build Coastguard Worker bool CheckEnvVar(const char* name, bool default_value) {
62*6777b538SAndroid Build Coastguard Worker   bool result = default_value;
63*6777b538SAndroid Build Coastguard Worker   const char* var = getenv(name);
64*6777b538SAndroid Build Coastguard Worker   if (var && strlen(var) > 0) {
65*6777b538SAndroid Build Coastguard Worker     result = var[0] != '0';
66*6777b538SAndroid Build Coastguard Worker   }
67*6777b538SAndroid Build Coastguard Worker   return result;
68*6777b538SAndroid Build Coastguard Worker }
69*6777b538SAndroid Build Coastguard Worker #endif
70*6777b538SAndroid Build Coastguard Worker 
ReadCache(const base::FilePath & filename,std::string * data)71*6777b538SAndroid Build Coastguard Worker void ReadCache(const base::FilePath& filename, std::string* data) {
72*6777b538SAndroid Build Coastguard Worker   if (!base::ReadFileToString(filename, data)) {
73*6777b538SAndroid Build Coastguard Worker     // Zero-size data used as an in-band error code.
74*6777b538SAndroid Build Coastguard Worker     data->clear();
75*6777b538SAndroid Build Coastguard Worker   }
76*6777b538SAndroid Build Coastguard Worker }
77*6777b538SAndroid Build Coastguard Worker 
WriteCache(const base::FilePath & filename,const base::Pickle * pickle)78*6777b538SAndroid Build Coastguard Worker void WriteCache(const base::FilePath& filename, const base::Pickle* pickle) {
79*6777b538SAndroid Build Coastguard Worker   base::WriteFile(filename,
80*6777b538SAndroid Build Coastguard Worker                   base::make_span(static_cast<const uint8_t*>(pickle->data()),
81*6777b538SAndroid Build Coastguard Worker                                   pickle->size()));
82*6777b538SAndroid Build Coastguard Worker }
83*6777b538SAndroid Build Coastguard Worker 
RemoveCache(const base::FilePath & filename,base::OnceClosure callback)84*6777b538SAndroid Build Coastguard Worker void RemoveCache(const base::FilePath& filename, base::OnceClosure callback) {
85*6777b538SAndroid Build Coastguard Worker   base::DeleteFile(filename);
86*6777b538SAndroid Build Coastguard Worker   content::GetIOThreadTaskRunner({})->PostTask(FROM_HERE, std::move(callback));
87*6777b538SAndroid Build Coastguard Worker }
88*6777b538SAndroid Build Coastguard Worker 
LogCacheQuery(nacl::NaClBrowser::ValidationCacheStatus status)89*6777b538SAndroid Build Coastguard Worker void LogCacheQuery(nacl::NaClBrowser::ValidationCacheStatus status) {
90*6777b538SAndroid Build Coastguard Worker   UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Query", status,
91*6777b538SAndroid Build Coastguard Worker                             nacl::NaClBrowser::CACHE_MAX);
92*6777b538SAndroid Build Coastguard Worker }
93*6777b538SAndroid Build Coastguard Worker 
LogCacheSet(nacl::NaClBrowser::ValidationCacheStatus status)94*6777b538SAndroid Build Coastguard Worker void LogCacheSet(nacl::NaClBrowser::ValidationCacheStatus status) {
95*6777b538SAndroid Build Coastguard Worker   // Bucket zero is reserved for future use.
96*6777b538SAndroid Build Coastguard Worker   UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Set", status,
97*6777b538SAndroid Build Coastguard Worker                             nacl::NaClBrowser::CACHE_MAX);
98*6777b538SAndroid Build Coastguard Worker }
99*6777b538SAndroid Build Coastguard Worker 
100*6777b538SAndroid Build Coastguard Worker // Crash throttling parameters.
101*6777b538SAndroid Build Coastguard Worker const size_t kMaxCrashesPerInterval = 3;
102*6777b538SAndroid Build Coastguard Worker const int64_t kCrashesIntervalInSeconds = 120;
103*6777b538SAndroid Build Coastguard Worker 
104*6777b538SAndroid Build Coastguard Worker // Holds the NaClBrowserDelegate, which is leaked on shutdown.
105*6777b538SAndroid Build Coastguard Worker NaClBrowserDelegate* g_browser_delegate = nullptr;
106*6777b538SAndroid Build Coastguard Worker 
107*6777b538SAndroid Build Coastguard Worker }  // namespace
108*6777b538SAndroid Build Coastguard Worker 
109*6777b538SAndroid Build Coastguard Worker namespace nacl {
110*6777b538SAndroid Build Coastguard Worker 
OpenNaClReadExecImpl(const base::FilePath & file_path,bool is_executable)111*6777b538SAndroid Build Coastguard Worker base::File OpenNaClReadExecImpl(const base::FilePath& file_path,
112*6777b538SAndroid Build Coastguard Worker                                 bool is_executable) {
113*6777b538SAndroid Build Coastguard Worker   // Get a file descriptor. On Windows, we need 'GENERIC_EXECUTE' in order to
114*6777b538SAndroid Build Coastguard Worker   // memory map the executable.
115*6777b538SAndroid Build Coastguard Worker   // IMPORTANT: This file descriptor must not have write access - that could
116*6777b538SAndroid Build Coastguard Worker   // allow a NaCl inner sandbox escape.
117*6777b538SAndroid Build Coastguard Worker   uint32_t flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
118*6777b538SAndroid Build Coastguard Worker   if (is_executable)
119*6777b538SAndroid Build Coastguard Worker     flags |= base::File::FLAG_WIN_EXECUTE;  // Windows only flag.
120*6777b538SAndroid Build Coastguard Worker   base::File file(file_path, flags);
121*6777b538SAndroid Build Coastguard Worker   if (!file.IsValid())
122*6777b538SAndroid Build Coastguard Worker     return file;
123*6777b538SAndroid Build Coastguard Worker 
124*6777b538SAndroid Build Coastguard Worker   // Check that the file does not reference a directory. Returning a descriptor
125*6777b538SAndroid Build Coastguard Worker   // to an extension directory could allow an outer sandbox escape. openat(...)
126*6777b538SAndroid Build Coastguard Worker   // could be used to traverse into the file system.
127*6777b538SAndroid Build Coastguard Worker   base::File::Info file_info;
128*6777b538SAndroid Build Coastguard Worker   if (!file.GetInfo(&file_info) || file_info.is_directory)
129*6777b538SAndroid Build Coastguard Worker     return base::File();
130*6777b538SAndroid Build Coastguard Worker 
131*6777b538SAndroid Build Coastguard Worker   return file;
132*6777b538SAndroid Build Coastguard Worker }
133*6777b538SAndroid Build Coastguard Worker 
NaClBrowser()134*6777b538SAndroid Build Coastguard Worker NaClBrowser::NaClBrowser() {
135*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(IS_ANDROID)
136*6777b538SAndroid Build Coastguard Worker   validation_cache_is_enabled_ =
137*6777b538SAndroid Build Coastguard Worker       CheckEnvVar("NACL_VALIDATION_CACHE", kValidationCacheEnabledByDefault);
138*6777b538SAndroid Build Coastguard Worker #endif
139*6777b538SAndroid Build Coastguard Worker       DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
140*6777b538SAndroid Build Coastguard Worker }
141*6777b538SAndroid Build Coastguard Worker 
SetDelegate(std::unique_ptr<NaClBrowserDelegate> delegate)142*6777b538SAndroid Build Coastguard Worker void NaClBrowser::SetDelegate(std::unique_ptr<NaClBrowserDelegate> delegate) {
143*6777b538SAndroid Build Coastguard Worker   // In the browser SetDelegate is called after threads are initialized.
144*6777b538SAndroid Build Coastguard Worker   // In tests it is called before initializing BrowserThreads.
145*6777b538SAndroid Build Coastguard Worker   if (content::BrowserThread::IsThreadInitialized(content::BrowserThread::UI)) {
146*6777b538SAndroid Build Coastguard Worker     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
147*6777b538SAndroid Build Coastguard Worker   }
148*6777b538SAndroid Build Coastguard Worker   DCHECK(delegate);
149*6777b538SAndroid Build Coastguard Worker   DCHECK(!g_browser_delegate);
150*6777b538SAndroid Build Coastguard Worker   g_browser_delegate = delegate.release();
151*6777b538SAndroid Build Coastguard Worker }
152*6777b538SAndroid Build Coastguard Worker 
GetDelegate()153*6777b538SAndroid Build Coastguard Worker NaClBrowserDelegate* NaClBrowser::GetDelegate() {
154*6777b538SAndroid Build Coastguard Worker   // NaClBrowser calls this on the IO thread, not the UI thread.
155*6777b538SAndroid Build Coastguard Worker   DCHECK(g_browser_delegate);
156*6777b538SAndroid Build Coastguard Worker   return g_browser_delegate;
157*6777b538SAndroid Build Coastguard Worker }
158*6777b538SAndroid Build Coastguard Worker 
ClearAndDeleteDelegate()159*6777b538SAndroid Build Coastguard Worker void NaClBrowser::ClearAndDeleteDelegate() {
160*6777b538SAndroid Build Coastguard Worker   DCHECK(g_browser_delegate);
161*6777b538SAndroid Build Coastguard Worker   delete g_browser_delegate;
162*6777b538SAndroid Build Coastguard Worker   g_browser_delegate = nullptr;
163*6777b538SAndroid Build Coastguard Worker }
164*6777b538SAndroid Build Coastguard Worker 
EarlyStartup()165*6777b538SAndroid Build Coastguard Worker void NaClBrowser::EarlyStartup() {
166*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
167*6777b538SAndroid Build Coastguard Worker   InitIrtFilePath();
168*6777b538SAndroid Build Coastguard Worker   InitValidationCacheFilePath();
169*6777b538SAndroid Build Coastguard Worker }
170*6777b538SAndroid Build Coastguard Worker 
~NaClBrowser()171*6777b538SAndroid Build Coastguard Worker NaClBrowser::~NaClBrowser() {
172*6777b538SAndroid Build Coastguard Worker   NOTREACHED();
173*6777b538SAndroid Build Coastguard Worker }
174*6777b538SAndroid Build Coastguard Worker 
InitIrtFilePath()175*6777b538SAndroid Build Coastguard Worker void NaClBrowser::InitIrtFilePath() {
176*6777b538SAndroid Build Coastguard Worker   // Allow the IRT library to be overridden via an environment
177*6777b538SAndroid Build Coastguard Worker   // variable.  This allows the NaCl/Chromium integration bot to
178*6777b538SAndroid Build Coastguard Worker   // specify a newly-built IRT rather than using a prebuilt one
179*6777b538SAndroid Build Coastguard Worker   // downloaded via Chromium's DEPS file.  We use the same environment
180*6777b538SAndroid Build Coastguard Worker   // variable that the standalone NaCl PPAPI plugin accepts.
181*6777b538SAndroid Build Coastguard Worker   const char* irt_path_var = getenv("NACL_IRT_LIBRARY");
182*6777b538SAndroid Build Coastguard Worker   if (irt_path_var != NULL) {
183*6777b538SAndroid Build Coastguard Worker     base::FilePath::StringType path_string(
184*6777b538SAndroid Build Coastguard Worker         irt_path_var, const_cast<const char*>(strchr(irt_path_var, '\0')));
185*6777b538SAndroid Build Coastguard Worker     irt_filepath_ = base::FilePath(path_string);
186*6777b538SAndroid Build Coastguard Worker   } else {
187*6777b538SAndroid Build Coastguard Worker     base::FilePath plugin_dir;
188*6777b538SAndroid Build Coastguard Worker     if (!GetDelegate()->GetPluginDirectory(&plugin_dir)) {
189*6777b538SAndroid Build Coastguard Worker       DLOG(ERROR) << "Failed to locate the plugins directory, NaCl disabled.";
190*6777b538SAndroid Build Coastguard Worker       MarkAsFailed();
191*6777b538SAndroid Build Coastguard Worker       return;
192*6777b538SAndroid Build Coastguard Worker     }
193*6777b538SAndroid Build Coastguard Worker     irt_filepath_ = plugin_dir.Append(NaClIrtName());
194*6777b538SAndroid Build Coastguard Worker   }
195*6777b538SAndroid Build Coastguard Worker }
196*6777b538SAndroid Build Coastguard Worker 
197*6777b538SAndroid Build Coastguard Worker // static
GetInstanceInternal()198*6777b538SAndroid Build Coastguard Worker NaClBrowser* NaClBrowser::GetInstanceInternal() {
199*6777b538SAndroid Build Coastguard Worker   static NaClBrowser* g_instance = nullptr;
200*6777b538SAndroid Build Coastguard Worker   if (!g_instance)
201*6777b538SAndroid Build Coastguard Worker     g_instance = new NaClBrowser();
202*6777b538SAndroid Build Coastguard Worker   return g_instance;
203*6777b538SAndroid Build Coastguard Worker }
204*6777b538SAndroid Build Coastguard Worker 
GetInstance()205*6777b538SAndroid Build Coastguard Worker NaClBrowser* NaClBrowser::GetInstance() {
206*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
207*6777b538SAndroid Build Coastguard Worker   return GetInstanceInternal();
208*6777b538SAndroid Build Coastguard Worker }
209*6777b538SAndroid Build Coastguard Worker 
IsReady() const210*6777b538SAndroid Build Coastguard Worker bool NaClBrowser::IsReady() const {
211*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
212*6777b538SAndroid Build Coastguard Worker   return (IsOk() &&
213*6777b538SAndroid Build Coastguard Worker           irt_state_ == NaClResourceReady &&
214*6777b538SAndroid Build Coastguard Worker           validation_cache_state_ == NaClResourceReady);
215*6777b538SAndroid Build Coastguard Worker }
216*6777b538SAndroid Build Coastguard Worker 
IsOk() const217*6777b538SAndroid Build Coastguard Worker bool NaClBrowser::IsOk() const {
218*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
219*6777b538SAndroid Build Coastguard Worker   return !has_failed_;
220*6777b538SAndroid Build Coastguard Worker }
221*6777b538SAndroid Build Coastguard Worker 
IrtFile() const222*6777b538SAndroid Build Coastguard Worker const base::File& NaClBrowser::IrtFile() const {
223*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
224*6777b538SAndroid Build Coastguard Worker   CHECK_EQ(irt_state_, NaClResourceReady);
225*6777b538SAndroid Build Coastguard Worker   CHECK(irt_file_.IsValid());
226*6777b538SAndroid Build Coastguard Worker   return irt_file_;
227*6777b538SAndroid Build Coastguard Worker }
228*6777b538SAndroid Build Coastguard Worker 
EnsureAllResourcesAvailable()229*6777b538SAndroid Build Coastguard Worker void NaClBrowser::EnsureAllResourcesAvailable() {
230*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
231*6777b538SAndroid Build Coastguard Worker   EnsureIrtAvailable();
232*6777b538SAndroid Build Coastguard Worker   EnsureValidationCacheAvailable();
233*6777b538SAndroid Build Coastguard Worker }
234*6777b538SAndroid Build Coastguard Worker 
235*6777b538SAndroid Build Coastguard Worker // Load the IRT async.
EnsureIrtAvailable()236*6777b538SAndroid Build Coastguard Worker void NaClBrowser::EnsureIrtAvailable() {
237*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
238*6777b538SAndroid Build Coastguard Worker   if (IsOk() && irt_state_ == NaClResourceUninitialized) {
239*6777b538SAndroid Build Coastguard Worker     irt_state_ = NaClResourceRequested;
240*6777b538SAndroid Build Coastguard Worker     auto task_runner = base::ThreadPool::CreateTaskRunner(
241*6777b538SAndroid Build Coastguard Worker         {base::MayBlock(), kUserBlocking,
242*6777b538SAndroid Build Coastguard Worker          base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN});
243*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<base::FileProxy> file_proxy(
244*6777b538SAndroid Build Coastguard Worker         new base::FileProxy(task_runner.get()));
245*6777b538SAndroid Build Coastguard Worker     base::FileProxy* proxy = file_proxy.get();
246*6777b538SAndroid Build Coastguard Worker     if (!proxy->CreateOrOpen(
247*6777b538SAndroid Build Coastguard Worker             irt_filepath_, base::File::FLAG_OPEN | base::File::FLAG_READ,
248*6777b538SAndroid Build Coastguard Worker             base::BindOnce(&NaClBrowser::OnIrtOpened, base::Unretained(this),
249*6777b538SAndroid Build Coastguard Worker                            std::move(file_proxy)))) {
250*6777b538SAndroid Build Coastguard Worker       LOG(ERROR) << "Internal error, NaCl disabled.";
251*6777b538SAndroid Build Coastguard Worker       MarkAsFailed();
252*6777b538SAndroid Build Coastguard Worker     }
253*6777b538SAndroid Build Coastguard Worker   }
254*6777b538SAndroid Build Coastguard Worker }
255*6777b538SAndroid Build Coastguard Worker 
OnIrtOpened(std::unique_ptr<base::FileProxy> file_proxy,base::File::Error error_code)256*6777b538SAndroid Build Coastguard Worker void NaClBrowser::OnIrtOpened(std::unique_ptr<base::FileProxy> file_proxy,
257*6777b538SAndroid Build Coastguard Worker                               base::File::Error error_code) {
258*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
259*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(irt_state_, NaClResourceRequested);
260*6777b538SAndroid Build Coastguard Worker   if (file_proxy->IsValid()) {
261*6777b538SAndroid Build Coastguard Worker     irt_file_ = file_proxy->TakeFile();
262*6777b538SAndroid Build Coastguard Worker   } else {
263*6777b538SAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to open NaCl IRT file \""
264*6777b538SAndroid Build Coastguard Worker                << irt_filepath_.LossyDisplayName()
265*6777b538SAndroid Build Coastguard Worker                << "\": " << error_code;
266*6777b538SAndroid Build Coastguard Worker     MarkAsFailed();
267*6777b538SAndroid Build Coastguard Worker   }
268*6777b538SAndroid Build Coastguard Worker   irt_state_ = NaClResourceReady;
269*6777b538SAndroid Build Coastguard Worker   CheckWaiting();
270*6777b538SAndroid Build Coastguard Worker }
271*6777b538SAndroid Build Coastguard Worker 
SetProcessGdbDebugStubPort(int process_id,int port)272*6777b538SAndroid Build Coastguard Worker void NaClBrowser::SetProcessGdbDebugStubPort(int process_id, int port) {
273*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
274*6777b538SAndroid Build Coastguard Worker   gdb_debug_stub_port_map_[process_id] = port;
275*6777b538SAndroid Build Coastguard Worker   if (port != kGdbDebugStubPortUnknown &&
276*6777b538SAndroid Build Coastguard Worker       !debug_stub_port_listener_.is_null()) {
277*6777b538SAndroid Build Coastguard Worker     content::GetIOThreadTaskRunner({})->PostTask(
278*6777b538SAndroid Build Coastguard Worker         FROM_HERE, base::BindOnce(debug_stub_port_listener_, port));
279*6777b538SAndroid Build Coastguard Worker   }
280*6777b538SAndroid Build Coastguard Worker }
281*6777b538SAndroid Build Coastguard Worker 
282*6777b538SAndroid Build Coastguard Worker // static
SetGdbDebugStubPortListenerForTest(base::RepeatingCallback<void (int)> listener)283*6777b538SAndroid Build Coastguard Worker void NaClBrowser::SetGdbDebugStubPortListenerForTest(
284*6777b538SAndroid Build Coastguard Worker     base::RepeatingCallback<void(int)> listener) {
285*6777b538SAndroid Build Coastguard Worker   GetInstanceInternal()->debug_stub_port_listener_ = listener;
286*6777b538SAndroid Build Coastguard Worker }
287*6777b538SAndroid Build Coastguard Worker 
288*6777b538SAndroid Build Coastguard Worker // static
ClearGdbDebugStubPortListenerForTest()289*6777b538SAndroid Build Coastguard Worker void NaClBrowser::ClearGdbDebugStubPortListenerForTest() {
290*6777b538SAndroid Build Coastguard Worker   GetInstanceInternal()->debug_stub_port_listener_.Reset();
291*6777b538SAndroid Build Coastguard Worker }
292*6777b538SAndroid Build Coastguard Worker 
GetProcessGdbDebugStubPort(int process_id)293*6777b538SAndroid Build Coastguard Worker int NaClBrowser::GetProcessGdbDebugStubPort(int process_id) {
294*6777b538SAndroid Build Coastguard Worker   // Called from TaskManager TaskGroup impl, on CrBrowserMain.
295*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
296*6777b538SAndroid Build Coastguard Worker   auto i = gdb_debug_stub_port_map_.find(process_id);
297*6777b538SAndroid Build Coastguard Worker   if (i != gdb_debug_stub_port_map_.end()) {
298*6777b538SAndroid Build Coastguard Worker     return i->second;
299*6777b538SAndroid Build Coastguard Worker   }
300*6777b538SAndroid Build Coastguard Worker   return kGdbDebugStubPortUnused;
301*6777b538SAndroid Build Coastguard Worker }
302*6777b538SAndroid Build Coastguard Worker 
InitValidationCacheFilePath()303*6777b538SAndroid Build Coastguard Worker void NaClBrowser::InitValidationCacheFilePath() {
304*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
305*6777b538SAndroid Build Coastguard Worker   // Determine where the validation cache resides in the file system.  It
306*6777b538SAndroid Build Coastguard Worker   // exists in Chrome's cache directory and is not tied to any specific
307*6777b538SAndroid Build Coastguard Worker   // profile.
308*6777b538SAndroid Build Coastguard Worker   // Start by finding the user data directory.
309*6777b538SAndroid Build Coastguard Worker   base::FilePath user_data_dir;
310*6777b538SAndroid Build Coastguard Worker   if (!GetDelegate()->GetUserDirectory(&user_data_dir)) {
311*6777b538SAndroid Build Coastguard Worker     RunWithoutValidationCache();
312*6777b538SAndroid Build Coastguard Worker     return;
313*6777b538SAndroid Build Coastguard Worker   }
314*6777b538SAndroid Build Coastguard Worker   // The cache directory may or may not be the user data directory.
315*6777b538SAndroid Build Coastguard Worker   base::FilePath cache_file_path;
316*6777b538SAndroid Build Coastguard Worker   GetDelegate()->GetCacheDirectory(&cache_file_path);
317*6777b538SAndroid Build Coastguard Worker   // Append the base file name to the cache directory.
318*6777b538SAndroid Build Coastguard Worker 
319*6777b538SAndroid Build Coastguard Worker   validation_cache_file_path_ =
320*6777b538SAndroid Build Coastguard Worker       cache_file_path.Append(kValidationCacheFileName);
321*6777b538SAndroid Build Coastguard Worker }
322*6777b538SAndroid Build Coastguard Worker 
EnsureValidationCacheAvailable()323*6777b538SAndroid Build Coastguard Worker void NaClBrowser::EnsureValidationCacheAvailable() {
324*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
325*6777b538SAndroid Build Coastguard Worker   if (IsOk() && validation_cache_state_ == NaClResourceUninitialized) {
326*6777b538SAndroid Build Coastguard Worker     if (ValidationCacheIsEnabled()) {
327*6777b538SAndroid Build Coastguard Worker       validation_cache_state_ = NaClResourceRequested;
328*6777b538SAndroid Build Coastguard Worker 
329*6777b538SAndroid Build Coastguard Worker       // Structure for carrying data between the callbacks.
330*6777b538SAndroid Build Coastguard Worker       std::string* data = new std::string();
331*6777b538SAndroid Build Coastguard Worker       // We can get away not giving this a sequence ID because this is the first
332*6777b538SAndroid Build Coastguard Worker       // task and further file access will not occur until after we get a
333*6777b538SAndroid Build Coastguard Worker       // response.
334*6777b538SAndroid Build Coastguard Worker       base::ThreadPool::PostTaskAndReply(
335*6777b538SAndroid Build Coastguard Worker           FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
336*6777b538SAndroid Build Coastguard Worker           base::BindOnce(ReadCache, validation_cache_file_path_, data),
337*6777b538SAndroid Build Coastguard Worker           base::BindOnce(&NaClBrowser::OnValidationCacheLoaded,
338*6777b538SAndroid Build Coastguard Worker                          base::Unretained(this), base::Owned(data)));
339*6777b538SAndroid Build Coastguard Worker     } else {
340*6777b538SAndroid Build Coastguard Worker       RunWithoutValidationCache();
341*6777b538SAndroid Build Coastguard Worker     }
342*6777b538SAndroid Build Coastguard Worker   }
343*6777b538SAndroid Build Coastguard Worker }
344*6777b538SAndroid Build Coastguard Worker 
OnValidationCacheLoaded(const std::string * data)345*6777b538SAndroid Build Coastguard Worker void NaClBrowser::OnValidationCacheLoaded(const std::string *data) {
346*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
347*6777b538SAndroid Build Coastguard Worker   // Did the cache get cleared before the load completed?  If so, ignore the
348*6777b538SAndroid Build Coastguard Worker   // incoming data.
349*6777b538SAndroid Build Coastguard Worker   if (validation_cache_state_ == NaClResourceReady)
350*6777b538SAndroid Build Coastguard Worker     return;
351*6777b538SAndroid Build Coastguard Worker 
352*6777b538SAndroid Build Coastguard Worker   if (data->size() == 0) {
353*6777b538SAndroid Build Coastguard Worker     // No file found.
354*6777b538SAndroid Build Coastguard Worker     validation_cache_.Reset();
355*6777b538SAndroid Build Coastguard Worker   } else {
356*6777b538SAndroid Build Coastguard Worker     base::Pickle pickle =
357*6777b538SAndroid Build Coastguard Worker         base::Pickle::WithUnownedBuffer(base::as_byte_span(*data));
358*6777b538SAndroid Build Coastguard Worker     validation_cache_.Deserialize(&pickle);
359*6777b538SAndroid Build Coastguard Worker   }
360*6777b538SAndroid Build Coastguard Worker   validation_cache_state_ = NaClResourceReady;
361*6777b538SAndroid Build Coastguard Worker   CheckWaiting();
362*6777b538SAndroid Build Coastguard Worker }
363*6777b538SAndroid Build Coastguard Worker 
RunWithoutValidationCache()364*6777b538SAndroid Build Coastguard Worker void NaClBrowser::RunWithoutValidationCache() {
365*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
366*6777b538SAndroid Build Coastguard Worker   // Be paranoid.
367*6777b538SAndroid Build Coastguard Worker   validation_cache_.Reset();
368*6777b538SAndroid Build Coastguard Worker   validation_cache_is_enabled_ = false;
369*6777b538SAndroid Build Coastguard Worker   validation_cache_state_ = NaClResourceReady;
370*6777b538SAndroid Build Coastguard Worker   CheckWaiting();
371*6777b538SAndroid Build Coastguard Worker }
372*6777b538SAndroid Build Coastguard Worker 
CheckWaiting()373*6777b538SAndroid Build Coastguard Worker void NaClBrowser::CheckWaiting() {
374*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
375*6777b538SAndroid Build Coastguard Worker   if (!IsOk() || IsReady()) {
376*6777b538SAndroid Build Coastguard Worker     // Queue the waiting tasks into the message loop.  This helps avoid
377*6777b538SAndroid Build Coastguard Worker     // re-entrancy problems that could occur if the closure was invoked
378*6777b538SAndroid Build Coastguard Worker     // directly.  For example, this could result in use-after-free of the
379*6777b538SAndroid Build Coastguard Worker     // process host.
380*6777b538SAndroid Build Coastguard Worker     for (auto iter = waiting_.begin(); iter != waiting_.end(); ++iter) {
381*6777b538SAndroid Build Coastguard Worker       base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
382*6777b538SAndroid Build Coastguard Worker           FROM_HERE, std::move(*iter));
383*6777b538SAndroid Build Coastguard Worker     }
384*6777b538SAndroid Build Coastguard Worker     waiting_.clear();
385*6777b538SAndroid Build Coastguard Worker   }
386*6777b538SAndroid Build Coastguard Worker }
387*6777b538SAndroid Build Coastguard Worker 
MarkAsFailed()388*6777b538SAndroid Build Coastguard Worker void NaClBrowser::MarkAsFailed() {
389*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
390*6777b538SAndroid Build Coastguard Worker   has_failed_ = true;
391*6777b538SAndroid Build Coastguard Worker   CheckWaiting();
392*6777b538SAndroid Build Coastguard Worker }
393*6777b538SAndroid Build Coastguard Worker 
WaitForResources(base::OnceClosure reply)394*6777b538SAndroid Build Coastguard Worker void NaClBrowser::WaitForResources(base::OnceClosure reply) {
395*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
396*6777b538SAndroid Build Coastguard Worker   waiting_.push_back(std::move(reply));
397*6777b538SAndroid Build Coastguard Worker   EnsureAllResourcesAvailable();
398*6777b538SAndroid Build Coastguard Worker   CheckWaiting();
399*6777b538SAndroid Build Coastguard Worker }
400*6777b538SAndroid Build Coastguard Worker 
GetIrtFilePath()401*6777b538SAndroid Build Coastguard Worker const base::FilePath& NaClBrowser::GetIrtFilePath() {
402*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
403*6777b538SAndroid Build Coastguard Worker   return irt_filepath_;
404*6777b538SAndroid Build Coastguard Worker }
405*6777b538SAndroid Build Coastguard Worker 
PutFilePath(const base::FilePath & path,uint64_t * file_token_lo,uint64_t * file_token_hi)406*6777b538SAndroid Build Coastguard Worker void NaClBrowser::PutFilePath(const base::FilePath& path,
407*6777b538SAndroid Build Coastguard Worker                               uint64_t* file_token_lo,
408*6777b538SAndroid Build Coastguard Worker                               uint64_t* file_token_hi) {
409*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
410*6777b538SAndroid Build Coastguard Worker   while (true) {
411*6777b538SAndroid Build Coastguard Worker     uint64_t file_token[2] = {base::RandUint64(), base::RandUint64()};
412*6777b538SAndroid Build Coastguard Worker     // A zero file_token indicates there is no file_token, if we get zero, ask
413*6777b538SAndroid Build Coastguard Worker     // for another number.
414*6777b538SAndroid Build Coastguard Worker     if (file_token[0] != 0 || file_token[1] != 0) {
415*6777b538SAndroid Build Coastguard Worker       // If the file_token is in use, ask for another number.
416*6777b538SAndroid Build Coastguard Worker       std::string key(reinterpret_cast<char*>(file_token), sizeof(file_token));
417*6777b538SAndroid Build Coastguard Worker       auto iter = path_cache_.Peek(key);
418*6777b538SAndroid Build Coastguard Worker       if (iter == path_cache_.end()) {
419*6777b538SAndroid Build Coastguard Worker         path_cache_.Put(key, path);
420*6777b538SAndroid Build Coastguard Worker         *file_token_lo = file_token[0];
421*6777b538SAndroid Build Coastguard Worker         *file_token_hi = file_token[1];
422*6777b538SAndroid Build Coastguard Worker         break;
423*6777b538SAndroid Build Coastguard Worker       }
424*6777b538SAndroid Build Coastguard Worker     }
425*6777b538SAndroid Build Coastguard Worker   }
426*6777b538SAndroid Build Coastguard Worker }
427*6777b538SAndroid Build Coastguard Worker 
GetFilePath(uint64_t file_token_lo,uint64_t file_token_hi,base::FilePath * path)428*6777b538SAndroid Build Coastguard Worker bool NaClBrowser::GetFilePath(uint64_t file_token_lo,
429*6777b538SAndroid Build Coastguard Worker                               uint64_t file_token_hi,
430*6777b538SAndroid Build Coastguard Worker                               base::FilePath* path) {
431*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
432*6777b538SAndroid Build Coastguard Worker   uint64_t file_token[2] = {file_token_lo, file_token_hi};
433*6777b538SAndroid Build Coastguard Worker   std::string key(reinterpret_cast<char*>(file_token), sizeof(file_token));
434*6777b538SAndroid Build Coastguard Worker   auto iter = path_cache_.Peek(key);
435*6777b538SAndroid Build Coastguard Worker   if (iter == path_cache_.end()) {
436*6777b538SAndroid Build Coastguard Worker     *path = base::FilePath(FILE_PATH_LITERAL(""));
437*6777b538SAndroid Build Coastguard Worker     return false;
438*6777b538SAndroid Build Coastguard Worker   }
439*6777b538SAndroid Build Coastguard Worker   *path = iter->second;
440*6777b538SAndroid Build Coastguard Worker   path_cache_.Erase(iter);
441*6777b538SAndroid Build Coastguard Worker   return true;
442*6777b538SAndroid Build Coastguard Worker }
443*6777b538SAndroid Build Coastguard Worker 
444*6777b538SAndroid Build Coastguard Worker 
QueryKnownToValidate(const std::string & signature,bool off_the_record)445*6777b538SAndroid Build Coastguard Worker bool NaClBrowser::QueryKnownToValidate(const std::string& signature,
446*6777b538SAndroid Build Coastguard Worker                                        bool off_the_record) {
447*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
448*6777b538SAndroid Build Coastguard Worker   if (off_the_record) {
449*6777b538SAndroid Build Coastguard Worker     // If we're off the record, don't reorder the main cache.
450*6777b538SAndroid Build Coastguard Worker     return validation_cache_.QueryKnownToValidate(signature, false) ||
451*6777b538SAndroid Build Coastguard Worker         off_the_record_validation_cache_.QueryKnownToValidate(signature, true);
452*6777b538SAndroid Build Coastguard Worker   } else {
453*6777b538SAndroid Build Coastguard Worker     bool result = validation_cache_.QueryKnownToValidate(signature, true);
454*6777b538SAndroid Build Coastguard Worker     LogCacheQuery(result ? CACHE_HIT : CACHE_MISS);
455*6777b538SAndroid Build Coastguard Worker     // Queries can modify the MRU order of the cache.
456*6777b538SAndroid Build Coastguard Worker     MarkValidationCacheAsModified();
457*6777b538SAndroid Build Coastguard Worker     return result;
458*6777b538SAndroid Build Coastguard Worker   }
459*6777b538SAndroid Build Coastguard Worker }
460*6777b538SAndroid Build Coastguard Worker 
SetKnownToValidate(const std::string & signature,bool off_the_record)461*6777b538SAndroid Build Coastguard Worker void NaClBrowser::SetKnownToValidate(const std::string& signature,
462*6777b538SAndroid Build Coastguard Worker                                      bool off_the_record) {
463*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
464*6777b538SAndroid Build Coastguard Worker   if (off_the_record) {
465*6777b538SAndroid Build Coastguard Worker     off_the_record_validation_cache_.SetKnownToValidate(signature);
466*6777b538SAndroid Build Coastguard Worker   } else {
467*6777b538SAndroid Build Coastguard Worker     validation_cache_.SetKnownToValidate(signature);
468*6777b538SAndroid Build Coastguard Worker     // The number of sets should be equal to the number of cache misses, minus
469*6777b538SAndroid Build Coastguard Worker     // validation failures and successful validations where stubout occurs.
470*6777b538SAndroid Build Coastguard Worker     LogCacheSet(CACHE_HIT);
471*6777b538SAndroid Build Coastguard Worker     MarkValidationCacheAsModified();
472*6777b538SAndroid Build Coastguard Worker   }
473*6777b538SAndroid Build Coastguard Worker }
474*6777b538SAndroid Build Coastguard Worker 
ClearValidationCache(base::OnceClosure callback)475*6777b538SAndroid Build Coastguard Worker void NaClBrowser::ClearValidationCache(base::OnceClosure callback) {
476*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
477*6777b538SAndroid Build Coastguard Worker   // Note: this method may be called before EnsureValidationCacheAvailable has
478*6777b538SAndroid Build Coastguard Worker   // been invoked.  In other words, this method may be called before any NaCl
479*6777b538SAndroid Build Coastguard Worker   // processes have been created.  This method must succeed and invoke the
480*6777b538SAndroid Build Coastguard Worker   // callback in such a case.  If it does not invoke the callback, Chrome's UI
481*6777b538SAndroid Build Coastguard Worker   // will hang in that case.
482*6777b538SAndroid Build Coastguard Worker   validation_cache_.Reset();
483*6777b538SAndroid Build Coastguard Worker   off_the_record_validation_cache_.Reset();
484*6777b538SAndroid Build Coastguard Worker 
485*6777b538SAndroid Build Coastguard Worker   if (validation_cache_file_path_.empty()) {
486*6777b538SAndroid Build Coastguard Worker     // Can't figure out what file to remove, but don't drop the callback.
487*6777b538SAndroid Build Coastguard Worker     content::GetIOThreadTaskRunner({})->PostTask(FROM_HERE,
488*6777b538SAndroid Build Coastguard Worker                                                  std::move(callback));
489*6777b538SAndroid Build Coastguard Worker   } else {
490*6777b538SAndroid Build Coastguard Worker     // Delegate the removal of the cache from the filesystem to another thread
491*6777b538SAndroid Build Coastguard Worker     // to avoid blocking the IO thread.
492*6777b538SAndroid Build Coastguard Worker     // This task is dispatched immediately, not delayed and coalesced, because
493*6777b538SAndroid Build Coastguard Worker     // the user interface for cache clearing is likely waiting for the callback.
494*6777b538SAndroid Build Coastguard Worker     // In addition, we need to make sure the cache is actually cleared before
495*6777b538SAndroid Build Coastguard Worker     // invoking the callback to meet the implicit guarantees of the UI.
496*6777b538SAndroid Build Coastguard Worker     file_task_runner_->PostTask(
497*6777b538SAndroid Build Coastguard Worker         FROM_HERE, base::BindOnce(RemoveCache, validation_cache_file_path_,
498*6777b538SAndroid Build Coastguard Worker                                   std::move(callback)));
499*6777b538SAndroid Build Coastguard Worker   }
500*6777b538SAndroid Build Coastguard Worker 
501*6777b538SAndroid Build Coastguard Worker   // Make sure any delayed tasks to persist the cache to the filesystem are
502*6777b538SAndroid Build Coastguard Worker   // squelched.
503*6777b538SAndroid Build Coastguard Worker   validation_cache_is_modified_ = false;
504*6777b538SAndroid Build Coastguard Worker 
505*6777b538SAndroid Build Coastguard Worker   // If the cache is cleared before it is loaded from the filesystem, act as if
506*6777b538SAndroid Build Coastguard Worker   // we just loaded an empty cache.
507*6777b538SAndroid Build Coastguard Worker   if (validation_cache_state_ != NaClResourceReady) {
508*6777b538SAndroid Build Coastguard Worker     validation_cache_state_ = NaClResourceReady;
509*6777b538SAndroid Build Coastguard Worker     CheckWaiting();
510*6777b538SAndroid Build Coastguard Worker   }
511*6777b538SAndroid Build Coastguard Worker }
512*6777b538SAndroid Build Coastguard Worker 
MarkValidationCacheAsModified()513*6777b538SAndroid Build Coastguard Worker void NaClBrowser::MarkValidationCacheAsModified() {
514*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
515*6777b538SAndroid Build Coastguard Worker   if (!validation_cache_is_modified_) {
516*6777b538SAndroid Build Coastguard Worker     // Wait before persisting to disk.  This can coalesce multiple cache
517*6777b538SAndroid Build Coastguard Worker     // modifications info a single disk write.
518*6777b538SAndroid Build Coastguard Worker     base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
519*6777b538SAndroid Build Coastguard Worker         FROM_HERE,
520*6777b538SAndroid Build Coastguard Worker         base::BindOnce(&NaClBrowser::PersistValidationCache,
521*6777b538SAndroid Build Coastguard Worker                        base::Unretained(this)),
522*6777b538SAndroid Build Coastguard Worker         base::Milliseconds(kValidationCacheCoalescingTimeMS));
523*6777b538SAndroid Build Coastguard Worker     validation_cache_is_modified_ = true;
524*6777b538SAndroid Build Coastguard Worker   }
525*6777b538SAndroid Build Coastguard Worker }
526*6777b538SAndroid Build Coastguard Worker 
PersistValidationCache()527*6777b538SAndroid Build Coastguard Worker void NaClBrowser::PersistValidationCache() {
528*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
529*6777b538SAndroid Build Coastguard Worker   // validation_cache_is_modified_ may be false if the cache was cleared while
530*6777b538SAndroid Build Coastguard Worker   // this delayed task was pending.
531*6777b538SAndroid Build Coastguard Worker   // validation_cache_file_path_ may be empty if something went wrong during
532*6777b538SAndroid Build Coastguard Worker   // initialization.
533*6777b538SAndroid Build Coastguard Worker   if (validation_cache_is_modified_ && !validation_cache_file_path_.empty()) {
534*6777b538SAndroid Build Coastguard Worker     base::Pickle* pickle = new base::Pickle();
535*6777b538SAndroid Build Coastguard Worker     validation_cache_.Serialize(pickle);
536*6777b538SAndroid Build Coastguard Worker 
537*6777b538SAndroid Build Coastguard Worker     // Pass the serialized data to another thread to write to disk.  File IO is
538*6777b538SAndroid Build Coastguard Worker     // not allowed on the IO thread (which is the thread this method runs on)
539*6777b538SAndroid Build Coastguard Worker     // because it can degrade the responsiveness of the browser.
540*6777b538SAndroid Build Coastguard Worker     // The task is sequenced so that multiple writes happen in order.
541*6777b538SAndroid Build Coastguard Worker     file_task_runner_->PostTask(
542*6777b538SAndroid Build Coastguard Worker         FROM_HERE, base::BindOnce(WriteCache, validation_cache_file_path_,
543*6777b538SAndroid Build Coastguard Worker                                   base::Owned(pickle)));
544*6777b538SAndroid Build Coastguard Worker   }
545*6777b538SAndroid Build Coastguard Worker   validation_cache_is_modified_ = false;
546*6777b538SAndroid Build Coastguard Worker }
547*6777b538SAndroid Build Coastguard Worker 
OnProcessEnd(int process_id)548*6777b538SAndroid Build Coastguard Worker void NaClBrowser::OnProcessEnd(int process_id) {
549*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
550*6777b538SAndroid Build Coastguard Worker   gdb_debug_stub_port_map_.erase(process_id);
551*6777b538SAndroid Build Coastguard Worker }
552*6777b538SAndroid Build Coastguard Worker 
OnProcessCrashed()553*6777b538SAndroid Build Coastguard Worker void NaClBrowser::OnProcessCrashed() {
554*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
555*6777b538SAndroid Build Coastguard Worker   if (crash_times_.size() == kMaxCrashesPerInterval) {
556*6777b538SAndroid Build Coastguard Worker     crash_times_.pop_front();
557*6777b538SAndroid Build Coastguard Worker   }
558*6777b538SAndroid Build Coastguard Worker   base::Time time = base::Time::Now();
559*6777b538SAndroid Build Coastguard Worker   crash_times_.push_back(time);
560*6777b538SAndroid Build Coastguard Worker }
561*6777b538SAndroid Build Coastguard Worker 
IsThrottled()562*6777b538SAndroid Build Coastguard Worker bool NaClBrowser::IsThrottled() {
563*6777b538SAndroid Build Coastguard Worker   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
564*6777b538SAndroid Build Coastguard Worker   if (crash_times_.size() != kMaxCrashesPerInterval) {
565*6777b538SAndroid Build Coastguard Worker     return false;
566*6777b538SAndroid Build Coastguard Worker   }
567*6777b538SAndroid Build Coastguard Worker   base::TimeDelta delta = base::Time::Now() - crash_times_.front();
568*6777b538SAndroid Build Coastguard Worker   return delta.InSeconds() <= kCrashesIntervalInSeconds;
569*6777b538SAndroid Build Coastguard Worker }
570*6777b538SAndroid Build Coastguard Worker 
571*6777b538SAndroid Build Coastguard Worker }  // namespace nacl
572