10f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "components/nacl/browser/nacl_browser.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
8010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/files/file_proxy.h"
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
10ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/pickle.h"
1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/rand_util.h"
153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/time/time.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/windows_version.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "build/build_config.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "url/gurl.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// An arbitrary delay to coalesce multiple writes to the cache.
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kValidationCacheCoalescingTimeMS = 6000;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kValidationCacheSequenceName[] = "NaClValidationCache";
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const base::FilePath::CharType kValidationCacheFileName[] =
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FILE_PATH_LITERAL("nacl_validation_cache.bin");
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const bool kValidationCacheEnabledByDefault = true;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Keep the cache bounded to an arbitrary size.  If it's too small, useful
3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// entries could be evicted when multiple .nexes are loaded at once.  On the
3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// other hand, entries are not always claimed (and hence removed), so the size
3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// of the cache will likely saturate at its maximum size.
3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Entries may not be claimed for two main reasons. 1) the NaCl process could
3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// be killed while it is loading.  2) the trusted NaCl plugin opens files using
3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// the code path but doesn't resolve them.
3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// TODO(ncbray) don't cache files that the plugin will not resolve.
3990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const int kFilePathCacheSize = 100;
4090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const base::FilePath::StringType NaClIrtName() {
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath::StringType irt_name(FILE_PATH_LITERAL("nacl_irt_"));
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(ARCH_CPU_X86_FAMILY)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(ARCH_CPU_X86_64)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is64 = true;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_WIN)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is64 = (base::win::OSInfo::GetInstance()->wow64_status() ==
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               base::win::OSInfo::WOW64_ENABLED);
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is64 = false;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is64)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    irt_name.append(FILE_PATH_LITERAL("x86_64"));
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    irt_name.append(FILE_PATH_LITERAL("x86_32"));
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(ARCH_CPU_ARMEL)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  irt_name.append(FILE_PATH_LITERAL("arm"));
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(ARCH_CPU_MIPSEL)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  irt_name.append(FILE_PATH_LITERAL("mips32"));
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#error Add support for your architecture to NaCl IRT file selection
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  irt_name.append(FILE_PATH_LITERAL(".nexe"));
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return irt_name;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CheckEnvVar(const char* name, bool default_value) {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool result = default_value;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* var = getenv(name);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (var && strlen(var) > 0) {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = var[0] != '0';
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ReadCache(const base::FilePath& filename, std::string* data) {
7958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!base::ReadFileToString(filename, data)) {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Zero-size data used as an in-band error code.
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data->clear();
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WriteCache(const base::FilePath& filename, const Pickle* pickle) {
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::WriteFile(filename, static_cast<const char*>(pickle->data()),
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       pickle->size());
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void RemoveCache(const base::FilePath& filename,
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 const base::Closure& callback) {
927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::DeleteFile(filename, false);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   callback);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void LogCacheQuery(nacl::NaClBrowser::ValidationCacheStatus status) {
98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Query", status,
99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                            nacl::NaClBrowser::CACHE_MAX);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void LogCacheSet(nacl::NaClBrowser::ValidationCacheStatus status) {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Bucket zero is reserved for future use.
104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Set", status,
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                            nacl::NaClBrowser::CACHE_MAX);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Crash throttling parameters.
1093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)const size_t kMaxCrashesPerInterval = 3;
1103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)const int64 kCrashesIntervalInSeconds = 120;
1113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace nacl {
11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
116116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbase::File OpenNaClReadExecImpl(const base::FilePath& file_path,
117116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                bool is_executable) {
11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Get a file descriptor. On Windows, we need 'GENERIC_EXECUTE' in order to
11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // memory map the executable.
12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // IMPORTANT: This file descriptor must not have write access - that could
12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // allow a NaCl inner sandbox escape.
122116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  uint32 flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
123116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (is_executable)
124116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    flags |= base::File::FLAG_EXECUTE;  // Windows only flag.
125116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::File file(file_path, flags);
126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!file.IsValid())
127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return file.Pass();
128f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Check that the file does not reference a directory. Returning a descriptor
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // to an extension directory could allow an outer sandbox escape. openat(...)
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // could be used to traverse into the file system.
132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::File::Info file_info;
133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!file.GetInfo(&file_info) || file_info.is_directory)
134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return base::File();
135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return file.Pass();
13790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
13890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NaClBrowser::NaClBrowser()
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : irt_filepath_(),
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      irt_state_(NaClResourceUninitialized),
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      validation_cache_file_path_(),
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      validation_cache_is_enabled_(
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          CheckEnvVar("NACL_VALIDATION_CACHE",
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      kValidationCacheEnabledByDefault)),
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      validation_cache_is_modified_(false),
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      validation_cache_state_(NaClResourceUninitialized),
14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      path_cache_(kFilePathCacheSize),
1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      ok_(true),
1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      weak_factory_(this) {
1517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid NaClBrowser::SetDelegate(NaClBrowserDelegate* delegate) {
1547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
1557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  nacl_browser->browser_delegate_.reset(delegate);
1567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1587dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochNaClBrowserDelegate* NaClBrowser::GetDelegate() {
1598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // The delegate is not owned by the IO thread.  This accessor method can be
1608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // called from other threads.
1617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(GetInstance()->browser_delegate_.get() != NULL);
1627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return GetInstance()->browser_delegate_.get();
1637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid NaClBrowser::EarlyStartup() {
1668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InitIrtFilePath();
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InitValidationCacheFilePath();
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NaClBrowser::~NaClBrowser() {
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::InitIrtFilePath() {
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Allow the IRT library to be overridden via an environment
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // variable.  This allows the NaCl/Chromium integration bot to
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // specify a newly-built IRT rather than using a prebuilt one
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // downloaded via Chromium's DEPS file.  We use the same environment
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // variable that the standalone NaCl PPAPI plugin accepts.
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* irt_path_var = getenv("NACL_IRT_LIBRARY");
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (irt_path_var != NULL) {
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath::StringType path_string(
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        irt_path_var, const_cast<const char*>(strchr(irt_path_var, '\0')));
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    irt_filepath_ = base::FilePath(path_string);
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath plugin_dir;
1877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (!browser_delegate_->GetPluginDirectory(&plugin_dir)) {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DLOG(ERROR) << "Failed to locate the plugins directory, NaCl disabled.";
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      MarkAsFailed();
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    irt_filepath_ = plugin_dir.Append(NaClIrtName());
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
196eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_WIN)
197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool NaClBrowser::GetNaCl64ExePath(base::FilePath* exe_path) {
198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::FilePath module_path;
199eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!PathService::Get(base::FILE_MODULE, &module_path)) {
200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    LOG(ERROR) << "NaCl process launch failed: could not resolve module";
201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
202eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  *exe_path = module_path.DirName().Append(L"nacl64");
204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return true;
205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
206eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NaClBrowser* NaClBrowser::GetInstance() {
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Singleton<NaClBrowser>::get();
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NaClBrowser::IsReady() const {
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (IsOk() &&
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          irt_state_ == NaClResourceReady &&
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          validation_cache_state_ == NaClResourceReady);
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NaClBrowser::IsOk() const {
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ok_;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
222010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)const base::File& NaClBrowser::IrtFile() const {
2238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_EQ(irt_state_, NaClResourceReady);
225010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  CHECK(irt_file_.IsValid());
226010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return irt_file_;
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::EnsureAllResourcesAvailable() {
2308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EnsureIrtAvailable();
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EnsureValidationCacheAvailable();
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Load the IRT async.
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::EnsureIrtAvailable() {
2378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsOk() && irt_state_ == NaClResourceUninitialized) {
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    irt_state_ = NaClResourceRequested;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(ncbray) use blocking pool.
241010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    scoped_ptr<base::FileProxy> file_proxy(new base::FileProxy(
242010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        content::BrowserThread::GetMessageLoopProxyForThread(
243010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                content::BrowserThread::FILE).get()));
244010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    base::FileProxy* proxy = file_proxy.get();
245010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (!proxy->CreateOrOpen(irt_filepath_,
246010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                             base::File::FLAG_OPEN | base::File::FLAG_READ,
247010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                             base::Bind(&NaClBrowser::OnIrtOpened,
248010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                        weak_factory_.GetWeakPtr(),
249010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                        Passed(&file_proxy)))) {
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Internal error, NaCl disabled.";
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      MarkAsFailed();
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
256010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void NaClBrowser::OnIrtOpened(scoped_ptr<base::FileProxy> file_proxy,
257010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                              base::File::Error error_code) {
2588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(irt_state_, NaClResourceRequested);
260010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (file_proxy->IsValid()) {
261010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    irt_file_ = file_proxy->TakeFile();
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to open NaCl IRT file \""
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << irt_filepath_.LossyDisplayName()
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << "\": " << error_code;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MarkAsFailed();
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  irt_state_ = NaClResourceReady;
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckWaiting();
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
272cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void NaClBrowser::SetProcessGdbDebugStubPort(int process_id, int port) {
273cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  gdb_debug_stub_port_map_[process_id] = port;
274cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (port != kGdbDebugStubPortUnknown &&
275cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      !debug_stub_port_listener_.is_null()) {
276cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    content::BrowserThread::PostTask(
277cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        content::BrowserThread::IO,
278cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        FROM_HERE,
279cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        base::Bind(debug_stub_port_listener_, port));
280cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NaClBrowser::SetGdbDebugStubPortListener(
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::Callback<void(int)> listener) {
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  debug_stub_port_listener_ = listener;
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NaClBrowser::ClearGdbDebugStubPortListener() {
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  debug_stub_port_listener_.Reset();
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
292cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)int NaClBrowser::GetProcessGdbDebugStubPort(int process_id) {
293cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  GdbDebugStubPortMap::iterator i = gdb_debug_stub_port_map_.find(process_id);
294cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (i != gdb_debug_stub_port_map_.end()) {
295cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return i->second;
296cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
297cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return kGdbDebugStubPortUnused;
298cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
299cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::InitValidationCacheFilePath() {
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Determine where the validation cache resides in the file system.  It
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // exists in Chrome's cache directory and is not tied to any specific
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // profile.
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start by finding the user data directory.
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath user_data_dir;
3067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!browser_delegate_->GetUserDirectory(&user_data_dir)) {
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RunWithoutValidationCache();
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The cache directory may or may not be the user data directory.
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath cache_file_path;
3127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  browser_delegate_->GetCacheDirectory(&cache_file_path);
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Append the base file name to the cache directory.
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  validation_cache_file_path_ =
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cache_file_path.Append(kValidationCacheFileName);
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::EnsureValidationCacheAvailable() {
3208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsOk() && validation_cache_state_ == NaClResourceUninitialized) {
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ValidationCacheIsEnabled()) {
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      validation_cache_state_ = NaClResourceRequested;
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Structure for carrying data between the callbacks.
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string* data = new std::string();
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We can get away not giving this a sequence ID because this is the first
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // task and further file access will not occur until after we get a
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // response.
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!content::BrowserThread::PostBlockingPoolTaskAndReply(
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              FROM_HERE,
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              base::Bind(ReadCache, validation_cache_file_path_, data),
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              base::Bind(&NaClBrowser::OnValidationCacheLoaded,
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         weak_factory_.GetWeakPtr(),
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         base::Owned(data)))) {
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        RunWithoutValidationCache();
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      RunWithoutValidationCache();
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::OnValidationCacheLoaded(const std::string *data) {
3458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Did the cache get cleared before the load completed?  If so, ignore the
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // incoming data.
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (validation_cache_state_ == NaClResourceReady)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (data->size() == 0) {
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No file found.
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    validation_cache_.Reset();
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Pickle pickle(data->data(), data->size());
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    validation_cache_.Deserialize(&pickle);
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  validation_cache_state_ = NaClResourceReady;
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckWaiting();
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::RunWithoutValidationCache() {
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Be paranoid.
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  validation_cache_.Reset();
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  validation_cache_is_enabled_ = false;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  validation_cache_state_ = NaClResourceReady;
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckWaiting();
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::CheckWaiting() {
3718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsOk() || IsReady()) {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Queue the waiting tasks into the message loop.  This helps avoid
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // re-entrancy problems that could occur if the closure was invoked
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // directly.  For example, this could result in use-after-free of the
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // process host.
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (std::vector<base::Closure>::iterator iter = waiting_.begin();
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         iter != waiting_.end(); ++iter) {
37990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      base::MessageLoop::current()->PostTask(FROM_HERE, *iter);
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    waiting_.clear();
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::MarkAsFailed() {
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ok_ = false;
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckWaiting();
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::WaitForResources(const base::Closure& reply) {
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  waiting_.push_back(reply);
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EnsureAllResourcesAvailable();
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckWaiting();
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const base::FilePath& NaClBrowser::GetIrtFilePath() {
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return irt_filepath_;
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
40090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void NaClBrowser::PutFilePath(const base::FilePath& path, uint64* file_token_lo,
40190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                              uint64* file_token_hi) {
4028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
40390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  while (true) {
40490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    uint64 file_token[2] = {base::RandUint64(), base::RandUint64()};
40590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // A zero file_token indicates there is no file_token, if we get zero, ask
40690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // for another number.
40790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (file_token[0] != 0 || file_token[1] != 0) {
40890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // If the file_token is in use, ask for another number.
40990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      std::string key(reinterpret_cast<char*>(file_token), sizeof(file_token));
41090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      PathCacheType::iterator iter = path_cache_.Peek(key);
41190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if (iter == path_cache_.end()) {
41290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        path_cache_.Put(key, path);
41390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        *file_token_lo = file_token[0];
41490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        *file_token_hi = file_token[1];
41590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        break;
41690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
41790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
41890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
41990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
42090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
42190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool NaClBrowser::GetFilePath(uint64 file_token_lo, uint64 file_token_hi,
42290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                              base::FilePath* path) {
4238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
42490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  uint64 file_token[2] = {file_token_lo, file_token_hi};
42590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::string key(reinterpret_cast<char*>(file_token), sizeof(file_token));
42690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  PathCacheType::iterator iter = path_cache_.Peek(key);
42790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (iter == path_cache_.end()) {
42890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    *path = base::FilePath(FILE_PATH_LITERAL(""));
42990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return false;
43090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
43190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  *path = iter->second;
43290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  path_cache_.Erase(iter);
43390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return true;
43490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
43590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
43690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NaClBrowser::QueryKnownToValidate(const std::string& signature,
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       bool off_the_record) {
4398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (off_the_record) {
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we're off the record, don't reorder the main cache.
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return validation_cache_.QueryKnownToValidate(signature, false) ||
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        off_the_record_validation_cache_.QueryKnownToValidate(signature, true);
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool result = validation_cache_.QueryKnownToValidate(signature, true);
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LogCacheQuery(result ? CACHE_HIT : CACHE_MISS);
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Queries can modify the MRU order of the cache.
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MarkValidationCacheAsModified();
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::SetKnownToValidate(const std::string& signature,
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     bool off_the_record) {
4558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (off_the_record) {
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    off_the_record_validation_cache_.SetKnownToValidate(signature);
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    validation_cache_.SetKnownToValidate(signature);
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The number of sets should be equal to the number of cache misses, minus
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // validation failures and successful validations where stubout occurs.
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LogCacheSet(CACHE_HIT);
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MarkValidationCacheAsModified();
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::ClearValidationCache(const base::Closure& callback) {
4688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note: this method may be called before EnsureValidationCacheAvailable has
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // been invoked.  In other words, this method may be called before any NaCl
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // processes have been created.  This method must succeed and invoke the
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // callback in such a case.  If it does not invoke the callback, Chrome's UI
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will hang in that case.
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  validation_cache_.Reset();
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  off_the_record_validation_cache_.Reset();
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (validation_cache_file_path_.empty()) {
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Can't figure out what file to remove, but don't drop the callback.
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     callback);
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Delegate the removal of the cache from the filesystem to another thread
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to avoid blocking the IO thread.
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This task is dispatched immediately, not delayed and coalesced, because
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the user interface for cache clearing is likely waiting for the callback.
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // In addition, we need to make sure the cache is actually cleared before
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // invoking the callback to meet the implicit guarantees of the UI.
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::BrowserThread::PostBlockingPoolSequencedTask(
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        kValidationCacheSequenceName,
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(RemoveCache, validation_cache_file_path_, callback));
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure any delayed tasks to persist the cache to the filesystem are
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // squelched.
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  validation_cache_is_modified_ = false;
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the cache is cleared before it is loaded from the filesystem, act as if
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we just loaded an empty cache.
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (validation_cache_state_ != NaClResourceReady) {
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    validation_cache_state_ = NaClResourceReady;
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CheckWaiting();
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::MarkValidationCacheAsModified() {
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!validation_cache_is_modified_) {
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Wait before persisting to disk.  This can coalesce multiple cache
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // modifications info a single disk write.
51090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostDelayedTask(
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         FROM_HERE,
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         base::Bind(&NaClBrowser::PersistValidationCache,
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    weak_factory_.GetWeakPtr()),
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         base::TimeDelta::FromMilliseconds(kValidationCacheCoalescingTimeMS));
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    validation_cache_is_modified_ = true;
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::PersistValidationCache() {
5208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // validation_cache_is_modified_ may be false if the cache was cleared while
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // this delayed task was pending.
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // validation_cache_file_path_ may be empty if something went wrong during
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // initialization.
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (validation_cache_is_modified_ && !validation_cache_file_path_.empty()) {
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Pickle* pickle = new Pickle();
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    validation_cache_.Serialize(pickle);
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Pass the serialized data to another thread to write to disk.  File IO is
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // not allowed on the IO thread (which is the thread this method runs on)
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // because it can degrade the responsiveness of the browser.
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The task is sequenced so that multiple writes happen in order.
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::BrowserThread::PostBlockingPoolSequencedTask(
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        kValidationCacheSequenceName,
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(WriteCache, validation_cache_file_path_,
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   base::Owned(pickle)));
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  validation_cache_is_modified_ = false;
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
542cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void NaClBrowser::OnProcessEnd(int process_id) {
543cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  gdb_debug_stub_port_map_.erase(process_id);
544cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
545cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
5463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void NaClBrowser::OnProcessCrashed() {
5473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
5483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (crash_times_.size() == kMaxCrashesPerInterval) {
5493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    crash_times_.pop_front();
5503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
5513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  base::Time time = base::Time::Now();
5523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  crash_times_.push_back(time);
5533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
5543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
5553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool NaClBrowser::IsThrottled() {
5563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
5573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (crash_times_.size() != kMaxCrashesPerInterval) {
5583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
5593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
5603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  base::TimeDelta delta = base::Time::Now() - crash_times_.front();
5613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return delta.InSeconds() <= kCrashesIntervalInSeconds;
5623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
5630f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
5640f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}  // namespace nacl
565