nacl_browser.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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