nacl_browser.cc revision 010d83a9304c5a91596085d917d248abff47903a
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" 8a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "base/file_util.h" 9010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/files/file_proxy.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) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum ValidationCacheStatus { 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CACHE_MISS = 0, 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CACHE_HIT, 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CACHE_MAX 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Keep the cache bounded to an arbitrary size. If it's too small, useful 3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// entries could be evicted when multiple .nexes are loaded at once. On the 3990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// other hand, entries are not always claimed (and hence removed), so the size 4090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// of the cache will likely saturate at its maximum size. 4190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Entries may not be claimed for two main reasons. 1) the NaCl process could 4290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// be killed while it is loading. 2) the trusted NaCl plugin opens files using 4390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// the code path but doesn't resolve them. 4490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// TODO(ncbray) don't cache files that the plugin will not resolve. 4590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const int kFilePathCacheSize = 100; 4690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const base::FilePath::StringType NaClIrtName() { 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath::StringType irt_name(FILE_PATH_LITERAL("nacl_irt_")); 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(ARCH_CPU_X86_FAMILY) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(ARCH_CPU_X86_64) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is64 = true; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_WIN) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is64 = (base::win::OSInfo::GetInstance()->wow64_status() == 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::OSInfo::WOW64_ENABLED); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is64 = false; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is64) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) irt_name.append(FILE_PATH_LITERAL("x86_64")); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) irt_name.append(FILE_PATH_LITERAL("x86_32")); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(ARCH_CPU_ARMEL) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) irt_name.append(FILE_PATH_LITERAL("arm")); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(ARCH_CPU_MIPSEL) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) irt_name.append(FILE_PATH_LITERAL("mips32")); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#error Add support for your architecture to NaCl IRT file selection 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) irt_name.append(FILE_PATH_LITERAL(".nexe")); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return irt_name; 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CheckEnvVar(const char* name, bool default_value) { 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool result = default_value; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* var = getenv(name); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (var && strlen(var) > 0) { 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = var[0] != '0'; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ReadCache(const base::FilePath& filename, std::string* data) { 8558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!base::ReadFileToString(filename, data)) { 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Zero-size data used as an in-band error code. 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data->clear(); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WriteCache(const base::FilePath& filename, const Pickle* pickle) { 92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::WriteFile(filename, static_cast<const char*>(pickle->data()), 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pickle->size()); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void RemoveCache(const base::FilePath& filename, 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::Closure& callback) { 987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch base::DeleteFile(filename, false); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LogCacheQuery(ValidationCacheStatus status) { 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Query", status, CACHE_MAX); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LogCacheSet(ValidationCacheStatus status) { 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Bucket zero is reserved for future use. 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Set", status, CACHE_MAX); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Crash throttling parameters. 1133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)const size_t kMaxCrashesPerInterval = 3; 1143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)const int64 kCrashesIntervalInSeconds = 120; 1153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace nacl { 11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)base::File OpenNaClExecutableImpl(const base::FilePath& file_path) { 12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Get a file descriptor. On Windows, we need 'GENERIC_EXECUTE' in order to 12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // memory map the executable. 12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // IMPORTANT: This file descriptor must not have write access - that could 12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // allow a NaCl inner sandbox escape. 125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::File file(file_path, 126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) (base::File::FLAG_OPEN | 127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::File::FLAG_READ | 128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::File::FLAG_EXECUTE)); // Windows only flag. 129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!file.IsValid()) 130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return file.Pass(); 131f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Check that the file does not reference a directory. Returning a descriptor 13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // to an extension directory could allow an outer sandbox escape. openat(...) 13490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // could be used to traverse into the file system. 135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::File::Info file_info; 136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!file.GetInfo(&file_info) || file_info.is_directory) 137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return base::File(); 138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return file.Pass(); 14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NaClBrowser::NaClBrowser() 143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : weak_factory_(this), 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) irt_filepath_(), 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) irt_state_(NaClResourceUninitialized), 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validation_cache_file_path_(), 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validation_cache_is_enabled_( 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckEnvVar("NACL_VALIDATION_CACHE", 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kValidationCacheEnabledByDefault)), 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validation_cache_is_modified_(false), 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validation_cache_state_(NaClResourceUninitialized), 15290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) path_cache_(kFilePathCacheSize), 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ok_(true) { 1547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch} 1557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid NaClBrowser::SetDelegate(NaClBrowserDelegate* delegate) { 1577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch NaClBrowser* nacl_browser = NaClBrowser::GetInstance(); 1587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch nacl_browser->browser_delegate_.reset(delegate); 1597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch} 1607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1617dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochNaClBrowserDelegate* NaClBrowser::GetDelegate() { 1628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // The delegate is not owned by the IO thread. This accessor method can be 1638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // called from other threads. 1647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch DCHECK(GetInstance()->browser_delegate_.get() != NULL); 1657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return GetInstance()->browser_delegate_.get(); 1667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch} 1677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid NaClBrowser::EarlyStartup() { 1698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InitIrtFilePath(); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InitValidationCacheFilePath(); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NaClBrowser::~NaClBrowser() { 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::InitIrtFilePath() { 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Allow the IRT library to be overridden via an environment 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // variable. This allows the NaCl/Chromium integration bot to 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // specify a newly-built IRT rather than using a prebuilt one 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // downloaded via Chromium's DEPS file. We use the same environment 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // variable that the standalone NaCl PPAPI plugin accepts. 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* irt_path_var = getenv("NACL_IRT_LIBRARY"); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (irt_path_var != NULL) { 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath::StringType path_string( 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) irt_path_var, const_cast<const char*>(strchr(irt_path_var, '\0'))); 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) irt_filepath_ = base::FilePath(path_string); 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath plugin_dir; 1907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (!browser_delegate_->GetPluginDirectory(&plugin_dir)) { 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(ERROR) << "Failed to locate the plugins directory, NaCl disabled."; 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MarkAsFailed(); 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) irt_filepath_ = plugin_dir.Append(NaClIrtName()); 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 199eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_WIN) 200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool NaClBrowser::GetNaCl64ExePath(base::FilePath* exe_path) { 201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::FilePath module_path; 202eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!PathService::Get(base::FILE_MODULE, &module_path)) { 203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch LOG(ERROR) << "NaCl process launch failed: could not resolve module"; 204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 206eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch *exe_path = module_path.DirName().Append(L"nacl64"); 207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return true; 208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 209eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif 210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NaClBrowser* NaClBrowser::GetInstance() { 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Singleton<NaClBrowser>::get(); 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NaClBrowser::IsReady() const { 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (IsOk() && 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) irt_state_ == NaClResourceReady && 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validation_cache_state_ == NaClResourceReady); 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NaClBrowser::IsOk() const { 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ok_; 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)const base::File& NaClBrowser::IrtFile() const { 2268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_EQ(irt_state_, NaClResourceReady); 228010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) CHECK(irt_file_.IsValid()); 229010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return irt_file_; 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::EnsureAllResourcesAvailable() { 2338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnsureIrtAvailable(); 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnsureValidationCacheAvailable(); 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Load the IRT async. 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::EnsureIrtAvailable() { 2408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsOk() && irt_state_ == NaClResourceUninitialized) { 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) irt_state_ = NaClResourceRequested; 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(ncbray) use blocking pool. 244010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) scoped_ptr<base::FileProxy> file_proxy(new base::FileProxy( 245010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) content::BrowserThread::GetMessageLoopProxyForThread( 246010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) content::BrowserThread::FILE).get())); 247010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) base::FileProxy* proxy = file_proxy.get(); 248010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (!proxy->CreateOrOpen(irt_filepath_, 249010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) base::File::FLAG_OPEN | base::File::FLAG_READ, 250010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) base::Bind(&NaClBrowser::OnIrtOpened, 251010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) weak_factory_.GetWeakPtr(), 252010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) Passed(&file_proxy)))) { 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Internal error, NaCl disabled."; 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MarkAsFailed(); 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 259010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void NaClBrowser::OnIrtOpened(scoped_ptr<base::FileProxy> file_proxy, 260010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) base::File::Error error_code) { 2618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(irt_state_, NaClResourceRequested); 263010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (file_proxy->IsValid()) { 264010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) irt_file_ = file_proxy->TakeFile(); 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Failed to open NaCl IRT file \"" 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << irt_filepath_.LossyDisplayName() 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "\": " << error_code; 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MarkAsFailed(); 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) irt_state_ = NaClResourceReady; 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckWaiting(); 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NaClBrowser::FireGdbDebugStubPortOpened(int port) { 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::BrowserThread::PostTask( 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::BrowserThread::IO, 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(debug_stub_port_listener_, port)); 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool NaClBrowser::HasGdbDebugStubPortListener() { 2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return !debug_stub_port_listener_.is_null(); 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NaClBrowser::SetGdbDebugStubPortListener( 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Callback<void(int)> listener) { 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) debug_stub_port_listener_ = listener; 2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NaClBrowser::ClearGdbDebugStubPortListener() { 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) debug_stub_port_listener_.Reset(); 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::InitValidationCacheFilePath() { 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Determine where the validation cache resides in the file system. It 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // exists in Chrome's cache directory and is not tied to any specific 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // profile. 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start by finding the user data directory. 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath user_data_dir; 3017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (!browser_delegate_->GetUserDirectory(&user_data_dir)) { 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RunWithoutValidationCache(); 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The cache directory may or may not be the user data directory. 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath cache_file_path; 3077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch browser_delegate_->GetCacheDirectory(&cache_file_path); 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Append the base file name to the cache directory. 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validation_cache_file_path_ = 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cache_file_path.Append(kValidationCacheFileName); 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::EnsureValidationCacheAvailable() { 3158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsOk() && validation_cache_state_ == NaClResourceUninitialized) { 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ValidationCacheIsEnabled()) { 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validation_cache_state_ = NaClResourceRequested; 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Structure for carrying data between the callbacks. 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* data = new std::string(); 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We can get away not giving this a sequence ID because this is the first 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // task and further file access will not occur until after we get a 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // response. 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!content::BrowserThread::PostBlockingPoolTaskAndReply( 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(ReadCache, validation_cache_file_path_, data), 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&NaClBrowser::OnValidationCacheLoaded, 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) weak_factory_.GetWeakPtr(), 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Owned(data)))) { 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RunWithoutValidationCache(); 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RunWithoutValidationCache(); 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::OnValidationCacheLoaded(const std::string *data) { 3408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Did the cache get cleared before the load completed? If so, ignore the 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // incoming data. 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (validation_cache_state_ == NaClResourceReady) 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (data->size() == 0) { 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No file found. 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validation_cache_.Reset(); 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Pickle pickle(data->data(), data->size()); 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validation_cache_.Deserialize(&pickle); 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validation_cache_state_ = NaClResourceReady; 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckWaiting(); 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::RunWithoutValidationCache() { 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Be paranoid. 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validation_cache_.Reset(); 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validation_cache_is_enabled_ = false; 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validation_cache_state_ = NaClResourceReady; 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckWaiting(); 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::CheckWaiting() { 3668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsOk() || IsReady()) { 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Queue the waiting tasks into the message loop. This helps avoid 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // re-entrancy problems that could occur if the closure was invoked 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // directly. For example, this could result in use-after-free of the 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // process host. 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (std::vector<base::Closure>::iterator iter = waiting_.begin(); 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iter != waiting_.end(); ++iter) { 37490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::MessageLoop::current()->PostTask(FROM_HERE, *iter); 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) waiting_.clear(); 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::MarkAsFailed() { 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ok_ = false; 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckWaiting(); 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::WaitForResources(const base::Closure& reply) { 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) waiting_.push_back(reply); 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnsureAllResourcesAvailable(); 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckWaiting(); 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const base::FilePath& NaClBrowser::GetIrtFilePath() { 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return irt_filepath_; 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 39590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void NaClBrowser::PutFilePath(const base::FilePath& path, uint64* file_token_lo, 39690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) uint64* file_token_hi) { 3978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 39890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) while (true) { 39990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) uint64 file_token[2] = {base::RandUint64(), base::RandUint64()}; 40090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // A zero file_token indicates there is no file_token, if we get zero, ask 40190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // for another number. 40290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (file_token[0] != 0 || file_token[1] != 0) { 40390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // If the file_token is in use, ask for another number. 40490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string key(reinterpret_cast<char*>(file_token), sizeof(file_token)); 40590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PathCacheType::iterator iter = path_cache_.Peek(key); 40690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (iter == path_cache_.end()) { 40790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) path_cache_.Put(key, path); 40890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *file_token_lo = file_token[0]; 40990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *file_token_hi = file_token[1]; 41090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) break; 41190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 41290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 41390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 41490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 41590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 41690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool NaClBrowser::GetFilePath(uint64 file_token_lo, uint64 file_token_hi, 41790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::FilePath* path) { 4188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 41990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) uint64 file_token[2] = {file_token_lo, file_token_hi}; 42090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string key(reinterpret_cast<char*>(file_token), sizeof(file_token)); 42190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PathCacheType::iterator iter = path_cache_.Peek(key); 42290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (iter == path_cache_.end()) { 42390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *path = base::FilePath(FILE_PATH_LITERAL("")); 42490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return false; 42590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 42690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *path = iter->second; 42790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) path_cache_.Erase(iter); 42890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return true; 42990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 43090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 43190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NaClBrowser::QueryKnownToValidate(const std::string& signature, 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool off_the_record) { 4348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (off_the_record) { 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we're off the record, don't reorder the main cache. 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return validation_cache_.QueryKnownToValidate(signature, false) || 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) off_the_record_validation_cache_.QueryKnownToValidate(signature, true); 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool result = validation_cache_.QueryKnownToValidate(signature, true); 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LogCacheQuery(result ? CACHE_HIT : CACHE_MISS); 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Queries can modify the MRU order of the cache. 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MarkValidationCacheAsModified(); 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::SetKnownToValidate(const std::string& signature, 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool off_the_record) { 4508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (off_the_record) { 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) off_the_record_validation_cache_.SetKnownToValidate(signature); 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validation_cache_.SetKnownToValidate(signature); 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The number of sets should be equal to the number of cache misses, minus 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // validation failures and successful validations where stubout occurs. 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LogCacheSet(CACHE_HIT); 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MarkValidationCacheAsModified(); 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::ClearValidationCache(const base::Closure& callback) { 4638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note: this method may be called before EnsureValidationCacheAvailable has 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // been invoked. In other words, this method may be called before any NaCl 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // processes have been created. This method must succeed and invoke the 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // callback in such a case. If it does not invoke the callback, Chrome's UI 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // will hang in that case. 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validation_cache_.Reset(); 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) off_the_record_validation_cache_.Reset(); 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (validation_cache_file_path_.empty()) { 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Can't figure out what file to remove, but don't drop the callback. 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback); 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Delegate the removal of the cache from the filesystem to another thread 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to avoid blocking the IO thread. 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This task is dispatched immediately, not delayed and coalesced, because 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the user interface for cache clearing is likely waiting for the callback. 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In addition, we need to make sure the cache is actually cleared before 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // invoking the callback to meet the implicit guarantees of the UI. 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::BrowserThread::PostBlockingPoolSequencedTask( 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kValidationCacheSequenceName, 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(RemoveCache, validation_cache_file_path_, callback)); 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make sure any delayed tasks to persist the cache to the filesystem are 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // squelched. 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validation_cache_is_modified_ = false; 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the cache is cleared before it is loaded from the filesystem, act as if 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we just loaded an empty cache. 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (validation_cache_state_ != NaClResourceReady) { 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validation_cache_state_ = NaClResourceReady; 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckWaiting(); 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::MarkValidationCacheAsModified() { 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!validation_cache_is_modified_) { 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Wait before persisting to disk. This can coalesce multiple cache 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // modifications info a single disk write. 50590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::MessageLoop::current()->PostDelayedTask( 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&NaClBrowser::PersistValidationCache, 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) weak_factory_.GetWeakPtr()), 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::TimeDelta::FromMilliseconds(kValidationCacheCoalescingTimeMS)); 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validation_cache_is_modified_ = true; 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrowser::PersistValidationCache() { 5158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // validation_cache_is_modified_ may be false if the cache was cleared while 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // this delayed task was pending. 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // validation_cache_file_path_ may be empty if something went wrong during 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // initialization. 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (validation_cache_is_modified_ && !validation_cache_file_path_.empty()) { 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Pickle* pickle = new Pickle(); 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validation_cache_.Serialize(pickle); 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Pass the serialized data to another thread to write to disk. File IO is 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // not allowed on the IO thread (which is the thread this method runs on) 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // because it can degrade the responsiveness of the browser. 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The task is sequenced so that multiple writes happen in order. 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::BrowserThread::PostBlockingPoolSequencedTask( 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kValidationCacheSequenceName, 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(WriteCache, validation_cache_file_path_, 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Owned(pickle))); 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validation_cache_is_modified_ = false; 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 5373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void NaClBrowser::OnProcessCrashed() { 5383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 5393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if (crash_times_.size() == kMaxCrashesPerInterval) { 5403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) crash_times_.pop_front(); 5413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 5423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) base::Time time = base::Time::Now(); 5433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) crash_times_.push_back(time); 5443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)} 5453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 5463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool NaClBrowser::IsThrottled() { 5473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 5483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if (crash_times_.size() != kMaxCrashesPerInterval) { 5493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return false; 5503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 5513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) base::TimeDelta delta = base::Time::Now() - crash_times_.front(); 5523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return delta.InSeconds() <= kCrashesIntervalInSeconds; 5533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)} 5540f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 5550f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)} // namespace nacl 556