Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/nacl/browser/nacl_browser.h" | 5 #include "components/nacl/browser/nacl_browser.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/files/file_proxy.h" | 10 #include "base/files/file_proxy.h" |
| 11 #include "base/files/file_util.h" | 11 #include "base/files/file_util.h" |
| 12 #include "base/lazy_instance.h" | |
| 12 #include "base/location.h" | 13 #include "base/location.h" |
| 13 #include "base/metrics/histogram_macros.h" | 14 #include "base/metrics/histogram_macros.h" |
| 14 #include "base/path_service.h" | 15 #include "base/path_service.h" |
| 15 #include "base/pickle.h" | 16 #include "base/pickle.h" |
| 16 #include "base/rand_util.h" | 17 #include "base/rand_util.h" |
| 17 #include "base/single_thread_task_runner.h" | 18 #include "base/single_thread_task_runner.h" |
| 18 #include "base/threading/thread_task_runner_handle.h" | 19 #include "base/threading/thread_task_runner_handle.h" |
| 19 #include "base/time/time.h" | 20 #include "base/time/time.h" |
| 20 #include "build/build_config.h" | 21 #include "build/build_config.h" |
| 21 #include "content/public/browser/browser_thread.h" | 22 #include "content/public/browser/browser_thread.h" |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 111 void LogCacheSet(nacl::NaClBrowser::ValidationCacheStatus status) { | 112 void LogCacheSet(nacl::NaClBrowser::ValidationCacheStatus status) { |
| 112 // Bucket zero is reserved for future use. | 113 // Bucket zero is reserved for future use. |
| 113 UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Set", status, | 114 UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Set", status, |
| 114 nacl::NaClBrowser::CACHE_MAX); | 115 nacl::NaClBrowser::CACHE_MAX); |
| 115 } | 116 } |
| 116 | 117 |
| 117 // Crash throttling parameters. | 118 // Crash throttling parameters. |
| 118 const size_t kMaxCrashesPerInterval = 3; | 119 const size_t kMaxCrashesPerInterval = 3; |
| 119 const int64_t kCrashesIntervalInSeconds = 120; | 120 const int64_t kCrashesIntervalInSeconds = 120; |
| 120 | 121 |
| 122 // Holds the NaClBrowserDelegate, which is leaked on shutdown. | |
| 123 NaClBrowserDelegate* g_browser_delegate = nullptr; | |
| 124 | |
| 121 } // namespace | 125 } // namespace |
| 122 | 126 |
| 123 namespace nacl { | 127 namespace nacl { |
| 124 | 128 |
| 125 base::File OpenNaClReadExecImpl(const base::FilePath& file_path, | 129 base::File OpenNaClReadExecImpl(const base::FilePath& file_path, |
| 126 bool is_executable) { | 130 bool is_executable) { |
| 127 // Get a file descriptor. On Windows, we need 'GENERIC_EXECUTE' in order to | 131 // Get a file descriptor. On Windows, we need 'GENERIC_EXECUTE' in order to |
| 128 // memory map the executable. | 132 // memory map the executable. |
| 129 // IMPORTANT: This file descriptor must not have write access - that could | 133 // IMPORTANT: This file descriptor must not have write access - that could |
| 130 // allow a NaCl inner sandbox escape. | 134 // allow a NaCl inner sandbox escape. |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 146 } | 150 } |
| 147 | 151 |
| 148 NaClBrowser::NaClBrowser() | 152 NaClBrowser::NaClBrowser() |
| 149 : irt_filepath_(), | 153 : irt_filepath_(), |
| 150 irt_state_(NaClResourceUninitialized), | 154 irt_state_(NaClResourceUninitialized), |
| 151 validation_cache_file_path_(), | 155 validation_cache_file_path_(), |
| 152 validation_cache_is_enabled_(false), | 156 validation_cache_is_enabled_(false), |
| 153 validation_cache_is_modified_(false), | 157 validation_cache_is_modified_(false), |
| 154 validation_cache_state_(NaClResourceUninitialized), | 158 validation_cache_state_(NaClResourceUninitialized), |
| 155 path_cache_(kFilePathCacheSize), | 159 path_cache_(kFilePathCacheSize), |
| 156 ok_(true), | 160 has_failed_(false) { |
| 157 weak_factory_(this) { | |
| 158 #if !defined(OS_ANDROID) | 161 #if !defined(OS_ANDROID) |
| 159 validation_cache_is_enabled_ = | 162 validation_cache_is_enabled_ = |
| 160 CheckEnvVar("NACL_VALIDATION_CACHE", | 163 CheckEnvVar("NACL_VALIDATION_CACHE", |
| 161 kValidationCacheEnabledByDefault); | 164 kValidationCacheEnabledByDefault); |
| 162 #endif | 165 #endif |
| 166 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
| 163 } | 167 } |
| 164 | 168 |
| 165 void NaClBrowser::SetDelegate(NaClBrowserDelegate* delegate) { | 169 void NaClBrowser::SetDelegate(std::unique_ptr<NaClBrowserDelegate> delegate) { |
| 166 NaClBrowser* nacl_browser = NaClBrowser::GetInstance(); | 170 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
|
Wez
2017/01/14 01:53:11
bradnelson: Turns out that this breaks several tes
| |
| 167 nacl_browser->browser_delegate_.reset(delegate); | 171 DCHECK(delegate); |
| 172 DCHECK(!g_browser_delegate); | |
| 173 g_browser_delegate = delegate.release(); | |
| 168 } | 174 } |
| 169 | 175 |
| 170 NaClBrowserDelegate* NaClBrowser::GetDelegate() { | 176 NaClBrowserDelegate* NaClBrowser::GetDelegate() { |
| 171 // The delegate is not owned by the IO thread. This accessor method can be | 177 // NaClBrowser calls this on the IO thread, not the UI thread. |
| 172 // called from other threads. | 178 DCHECK(g_browser_delegate); |
| 173 DCHECK(GetInstance()->browser_delegate_.get() != NULL); | 179 return g_browser_delegate; |
| 174 return GetInstance()->browser_delegate_.get(); | 180 } |
| 181 | |
| 182 void NaClBrowser::ClearAndDeleteDelegateForTest() { | |
| 183 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 184 DCHECK(g_browser_delegate); | |
| 185 delete g_browser_delegate; | |
| 186 g_browser_delegate = nullptr; | |
| 175 } | 187 } |
| 176 | 188 |
| 177 void NaClBrowser::EarlyStartup() { | 189 void NaClBrowser::EarlyStartup() { |
| 178 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 190 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 179 InitIrtFilePath(); | 191 InitIrtFilePath(); |
| 180 InitValidationCacheFilePath(); | 192 InitValidationCacheFilePath(); |
| 181 } | 193 } |
| 182 | 194 |
| 183 NaClBrowser::~NaClBrowser() { | 195 NaClBrowser::~NaClBrowser() { |
| 196 NOTREACHED(); | |
| 184 } | 197 } |
| 185 | 198 |
| 186 void NaClBrowser::InitIrtFilePath() { | 199 void NaClBrowser::InitIrtFilePath() { |
| 187 // Allow the IRT library to be overridden via an environment | 200 // Allow the IRT library to be overridden via an environment |
| 188 // variable. This allows the NaCl/Chromium integration bot to | 201 // variable. This allows the NaCl/Chromium integration bot to |
| 189 // specify a newly-built IRT rather than using a prebuilt one | 202 // specify a newly-built IRT rather than using a prebuilt one |
| 190 // downloaded via Chromium's DEPS file. We use the same environment | 203 // downloaded via Chromium's DEPS file. We use the same environment |
| 191 // variable that the standalone NaCl PPAPI plugin accepts. | 204 // variable that the standalone NaCl PPAPI plugin accepts. |
| 192 const char* irt_path_var = getenv("NACL_IRT_LIBRARY"); | 205 const char* irt_path_var = getenv("NACL_IRT_LIBRARY"); |
| 193 if (irt_path_var != NULL) { | 206 if (irt_path_var != NULL) { |
| 194 base::FilePath::StringType path_string( | 207 base::FilePath::StringType path_string( |
| 195 irt_path_var, const_cast<const char*>(strchr(irt_path_var, '\0'))); | 208 irt_path_var, const_cast<const char*>(strchr(irt_path_var, '\0'))); |
| 196 irt_filepath_ = base::FilePath(path_string); | 209 irt_filepath_ = base::FilePath(path_string); |
| 197 } else { | 210 } else { |
| 198 base::FilePath plugin_dir; | 211 base::FilePath plugin_dir; |
| 199 if (!browser_delegate_->GetPluginDirectory(&plugin_dir)) { | 212 if (!GetDelegate()->GetPluginDirectory(&plugin_dir)) { |
| 200 DLOG(ERROR) << "Failed to locate the plugins directory, NaCl disabled."; | 213 DLOG(ERROR) << "Failed to locate the plugins directory, NaCl disabled."; |
| 201 MarkAsFailed(); | 214 MarkAsFailed(); |
| 202 return; | 215 return; |
| 203 } | 216 } |
| 204 irt_filepath_ = plugin_dir.Append(NaClIrtName()); | 217 irt_filepath_ = plugin_dir.Append(NaClIrtName()); |
| 205 } | 218 } |
| 206 } | 219 } |
| 207 | 220 |
| 208 #if defined(OS_WIN) | 221 #if defined(OS_WIN) |
| 209 bool NaClBrowser::GetNaCl64ExePath(base::FilePath* exe_path) { | 222 bool NaClBrowser::GetNaCl64ExePath(base::FilePath* exe_path) { |
| 223 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
| 210 base::FilePath module_path; | 224 base::FilePath module_path; |
| 211 if (!PathService::Get(base::FILE_MODULE, &module_path)) { | 225 if (!PathService::Get(base::FILE_MODULE, &module_path)) { |
| 212 LOG(ERROR) << "NaCl process launch failed: could not resolve module"; | 226 LOG(ERROR) << "NaCl process launch failed: could not resolve module"; |
| 213 return false; | 227 return false; |
| 214 } | 228 } |
| 215 *exe_path = module_path.DirName().Append(L"nacl64"); | 229 *exe_path = module_path.DirName().Append(L"nacl64"); |
| 216 return true; | 230 return true; |
| 217 } | 231 } |
| 218 #endif | 232 #endif |
| 219 | 233 |
| 220 NaClBrowser* NaClBrowser::GetInstance() { | 234 NaClBrowser* NaClBrowser::GetInstance() { |
| 221 return base::Singleton<NaClBrowser>::get(); | 235 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 236 static NaClBrowser* g_instance = nullptr; | |
| 237 if (!g_instance) | |
| 238 g_instance = new NaClBrowser(); | |
| 239 return g_instance; | |
| 222 } | 240 } |
| 223 | 241 |
| 224 bool NaClBrowser::IsReady() const { | 242 bool NaClBrowser::IsReady() const { |
| 243 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
| 225 return (IsOk() && | 244 return (IsOk() && |
| 226 irt_state_ == NaClResourceReady && | 245 irt_state_ == NaClResourceReady && |
| 227 validation_cache_state_ == NaClResourceReady); | 246 validation_cache_state_ == NaClResourceReady); |
| 228 } | 247 } |
| 229 | 248 |
| 230 bool NaClBrowser::IsOk() const { | 249 bool NaClBrowser::IsOk() const { |
| 231 return ok_; | 250 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 251 return !has_failed_; | |
| 232 } | 252 } |
| 233 | 253 |
| 234 const base::File& NaClBrowser::IrtFile() const { | 254 const base::File& NaClBrowser::IrtFile() const { |
| 235 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 255 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 236 CHECK_EQ(irt_state_, NaClResourceReady); | 256 CHECK_EQ(irt_state_, NaClResourceReady); |
| 237 CHECK(irt_file_.IsValid()); | 257 CHECK(irt_file_.IsValid()); |
| 238 return irt_file_; | 258 return irt_file_; |
| 239 } | 259 } |
| 240 | 260 |
| 241 void NaClBrowser::EnsureAllResourcesAvailable() { | 261 void NaClBrowser::EnsureAllResourcesAvailable() { |
| 242 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 262 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 243 EnsureIrtAvailable(); | 263 EnsureIrtAvailable(); |
| 244 EnsureValidationCacheAvailable(); | 264 EnsureValidationCacheAvailable(); |
| 245 } | 265 } |
| 246 | 266 |
| 247 // Load the IRT async. | 267 // Load the IRT async. |
| 248 void NaClBrowser::EnsureIrtAvailable() { | 268 void NaClBrowser::EnsureIrtAvailable() { |
| 249 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 269 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 250 if (IsOk() && irt_state_ == NaClResourceUninitialized) { | 270 if (IsOk() && irt_state_ == NaClResourceUninitialized) { |
| 251 irt_state_ = NaClResourceRequested; | 271 irt_state_ = NaClResourceRequested; |
| 252 // TODO(ncbray) use blocking pool. | 272 // TODO(ncbray) use blocking pool. |
| 253 std::unique_ptr<base::FileProxy> file_proxy( | 273 std::unique_ptr<base::FileProxy> file_proxy( |
| 254 new base::FileProxy(content::BrowserThread::GetTaskRunnerForThread( | 274 new base::FileProxy(content::BrowserThread::GetTaskRunnerForThread( |
| 255 content::BrowserThread::FILE) | 275 content::BrowserThread::FILE) |
| 256 .get())); | 276 .get())); |
| 257 base::FileProxy* proxy = file_proxy.get(); | 277 base::FileProxy* proxy = file_proxy.get(); |
| 258 if (!proxy->CreateOrOpen(irt_filepath_, | 278 if (!proxy->CreateOrOpen( |
| 259 base::File::FLAG_OPEN | base::File::FLAG_READ, | 279 irt_filepath_, base::File::FLAG_OPEN | base::File::FLAG_READ, |
| 260 base::Bind(&NaClBrowser::OnIrtOpened, | 280 base::Bind(&NaClBrowser::OnIrtOpened, base::Unretained(this), |
| 261 weak_factory_.GetWeakPtr(), | 281 base::Passed(&file_proxy)))) { |
| 262 Passed(&file_proxy)))) { | |
| 263 LOG(ERROR) << "Internal error, NaCl disabled."; | 282 LOG(ERROR) << "Internal error, NaCl disabled."; |
| 264 MarkAsFailed(); | 283 MarkAsFailed(); |
| 265 } | 284 } |
| 266 } | 285 } |
| 267 } | 286 } |
| 268 | 287 |
| 269 void NaClBrowser::OnIrtOpened(std::unique_ptr<base::FileProxy> file_proxy, | 288 void NaClBrowser::OnIrtOpened(std::unique_ptr<base::FileProxy> file_proxy, |
| 270 base::File::Error error_code) { | 289 base::File::Error error_code) { |
| 271 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 290 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 272 DCHECK_EQ(irt_state_, NaClResourceRequested); | 291 DCHECK_EQ(irt_state_, NaClResourceRequested); |
| 273 if (file_proxy->IsValid()) { | 292 if (file_proxy->IsValid()) { |
| 274 irt_file_ = file_proxy->TakeFile(); | 293 irt_file_ = file_proxy->TakeFile(); |
| 275 } else { | 294 } else { |
| 276 LOG(ERROR) << "Failed to open NaCl IRT file \"" | 295 LOG(ERROR) << "Failed to open NaCl IRT file \"" |
| 277 << irt_filepath_.LossyDisplayName() | 296 << irt_filepath_.LossyDisplayName() |
| 278 << "\": " << error_code; | 297 << "\": " << error_code; |
| 279 MarkAsFailed(); | 298 MarkAsFailed(); |
| 280 } | 299 } |
| 281 irt_state_ = NaClResourceReady; | 300 irt_state_ = NaClResourceReady; |
| 282 CheckWaiting(); | 301 CheckWaiting(); |
| 283 } | 302 } |
| 284 | 303 |
| 285 void NaClBrowser::SetProcessGdbDebugStubPort(int process_id, int port) { | 304 void NaClBrowser::SetProcessGdbDebugStubPort(int process_id, int port) { |
| 305 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
| 286 gdb_debug_stub_port_map_[process_id] = port; | 306 gdb_debug_stub_port_map_[process_id] = port; |
| 287 if (port != kGdbDebugStubPortUnknown && | 307 if (port != kGdbDebugStubPortUnknown && |
| 288 !debug_stub_port_listener_.is_null()) { | 308 !debug_stub_port_listener_.is_null()) { |
| 289 content::BrowserThread::PostTask( | 309 content::BrowserThread::PostTask( |
| 290 content::BrowserThread::IO, | 310 content::BrowserThread::IO, |
| 291 FROM_HERE, | 311 FROM_HERE, |
| 292 base::Bind(debug_stub_port_listener_, port)); | 312 base::Bind(debug_stub_port_listener_, port)); |
| 293 } | 313 } |
| 294 } | 314 } |
| 295 | 315 |
| 296 void NaClBrowser::SetGdbDebugStubPortListener( | 316 void NaClBrowser::SetGdbDebugStubPortListenerForTest( |
| 297 base::Callback<void(int)> listener) { | 317 base::Callback<void(int)> listener) { |
| 318 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
| 298 debug_stub_port_listener_ = listener; | 319 debug_stub_port_listener_ = listener; |
| 299 } | 320 } |
| 300 | 321 |
| 301 void NaClBrowser::ClearGdbDebugStubPortListener() { | 322 void NaClBrowser::ClearGdbDebugStubPortListenerForTest() { |
| 323 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
| 302 debug_stub_port_listener_.Reset(); | 324 debug_stub_port_listener_.Reset(); |
| 303 } | 325 } |
| 304 | 326 |
| 305 int NaClBrowser::GetProcessGdbDebugStubPort(int process_id) { | 327 int NaClBrowser::GetProcessGdbDebugStubPort(int process_id) { |
| 328 // Called from TaskManager TaskGroup impl, on CrBrowserMain. | |
| 329 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
| 306 GdbDebugStubPortMap::iterator i = gdb_debug_stub_port_map_.find(process_id); | 330 GdbDebugStubPortMap::iterator i = gdb_debug_stub_port_map_.find(process_id); |
| 307 if (i != gdb_debug_stub_port_map_.end()) { | 331 if (i != gdb_debug_stub_port_map_.end()) { |
| 308 return i->second; | 332 return i->second; |
| 309 } | 333 } |
| 310 return kGdbDebugStubPortUnused; | 334 return kGdbDebugStubPortUnused; |
| 311 } | 335 } |
| 312 | 336 |
| 313 void NaClBrowser::InitValidationCacheFilePath() { | 337 void NaClBrowser::InitValidationCacheFilePath() { |
| 338 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
| 314 // Determine where the validation cache resides in the file system. It | 339 // Determine where the validation cache resides in the file system. It |
| 315 // exists in Chrome's cache directory and is not tied to any specific | 340 // exists in Chrome's cache directory and is not tied to any specific |
| 316 // profile. | 341 // profile. |
| 317 // Start by finding the user data directory. | 342 // Start by finding the user data directory. |
| 318 base::FilePath user_data_dir; | 343 base::FilePath user_data_dir; |
| 319 if (!browser_delegate_->GetUserDirectory(&user_data_dir)) { | 344 if (!GetDelegate()->GetUserDirectory(&user_data_dir)) { |
| 320 RunWithoutValidationCache(); | 345 RunWithoutValidationCache(); |
| 321 return; | 346 return; |
| 322 } | 347 } |
| 323 // The cache directory may or may not be the user data directory. | 348 // The cache directory may or may not be the user data directory. |
| 324 base::FilePath cache_file_path; | 349 base::FilePath cache_file_path; |
| 325 browser_delegate_->GetCacheDirectory(&cache_file_path); | 350 GetDelegate()->GetCacheDirectory(&cache_file_path); |
| 326 // Append the base file name to the cache directory. | 351 // Append the base file name to the cache directory. |
| 327 | 352 |
| 328 validation_cache_file_path_ = | 353 validation_cache_file_path_ = |
| 329 cache_file_path.Append(kValidationCacheFileName); | 354 cache_file_path.Append(kValidationCacheFileName); |
| 330 } | 355 } |
| 331 | 356 |
| 332 void NaClBrowser::EnsureValidationCacheAvailable() { | 357 void NaClBrowser::EnsureValidationCacheAvailable() { |
| 333 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 358 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 334 if (IsOk() && validation_cache_state_ == NaClResourceUninitialized) { | 359 if (IsOk() && validation_cache_state_ == NaClResourceUninitialized) { |
| 335 if (ValidationCacheIsEnabled()) { | 360 if (ValidationCacheIsEnabled()) { |
| 336 validation_cache_state_ = NaClResourceRequested; | 361 validation_cache_state_ = NaClResourceRequested; |
| 337 | 362 |
| 338 // Structure for carrying data between the callbacks. | 363 // Structure for carrying data between the callbacks. |
| 339 std::string* data = new std::string(); | 364 std::string* data = new std::string(); |
| 340 // We can get away not giving this a sequence ID because this is the first | 365 // We can get away not giving this a sequence ID because this is the first |
| 341 // task and further file access will not occur until after we get a | 366 // task and further file access will not occur until after we get a |
| 342 // response. | 367 // response. |
| 343 if (!content::BrowserThread::PostBlockingPoolTaskAndReply( | 368 if (!content::BrowserThread::PostBlockingPoolTaskAndReply( |
| 344 FROM_HERE, | 369 FROM_HERE, |
| 345 base::Bind(ReadCache, validation_cache_file_path_, data), | 370 base::Bind(ReadCache, validation_cache_file_path_, data), |
| 346 base::Bind(&NaClBrowser::OnValidationCacheLoaded, | 371 base::Bind(&NaClBrowser::OnValidationCacheLoaded, |
| 347 weak_factory_.GetWeakPtr(), | 372 base::Unretained(this), base::Owned(data)))) { |
| 348 base::Owned(data)))) { | |
| 349 RunWithoutValidationCache(); | 373 RunWithoutValidationCache(); |
| 350 } | 374 } |
| 351 } else { | 375 } else { |
| 352 RunWithoutValidationCache(); | 376 RunWithoutValidationCache(); |
| 353 } | 377 } |
| 354 } | 378 } |
| 355 } | 379 } |
| 356 | 380 |
| 357 void NaClBrowser::OnValidationCacheLoaded(const std::string *data) { | 381 void NaClBrowser::OnValidationCacheLoaded(const std::string *data) { |
| 358 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 382 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 359 // Did the cache get cleared before the load completed? If so, ignore the | 383 // Did the cache get cleared before the load completed? If so, ignore the |
| 360 // incoming data. | 384 // incoming data. |
| 361 if (validation_cache_state_ == NaClResourceReady) | 385 if (validation_cache_state_ == NaClResourceReady) |
| 362 return; | 386 return; |
| 363 | 387 |
| 364 if (data->size() == 0) { | 388 if (data->size() == 0) { |
| 365 // No file found. | 389 // No file found. |
| 366 validation_cache_.Reset(); | 390 validation_cache_.Reset(); |
| 367 } else { | 391 } else { |
| 368 base::Pickle pickle(data->data(), data->size()); | 392 base::Pickle pickle(data->data(), data->size()); |
| 369 validation_cache_.Deserialize(&pickle); | 393 validation_cache_.Deserialize(&pickle); |
| 370 } | 394 } |
| 371 validation_cache_state_ = NaClResourceReady; | 395 validation_cache_state_ = NaClResourceReady; |
| 372 CheckWaiting(); | 396 CheckWaiting(); |
| 373 } | 397 } |
| 374 | 398 |
| 375 void NaClBrowser::RunWithoutValidationCache() { | 399 void NaClBrowser::RunWithoutValidationCache() { |
| 400 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
| 376 // Be paranoid. | 401 // Be paranoid. |
| 377 validation_cache_.Reset(); | 402 validation_cache_.Reset(); |
| 378 validation_cache_is_enabled_ = false; | 403 validation_cache_is_enabled_ = false; |
| 379 validation_cache_state_ = NaClResourceReady; | 404 validation_cache_state_ = NaClResourceReady; |
| 380 CheckWaiting(); | 405 CheckWaiting(); |
| 381 } | 406 } |
| 382 | 407 |
| 383 void NaClBrowser::CheckWaiting() { | 408 void NaClBrowser::CheckWaiting() { |
| 384 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 409 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 385 if (!IsOk() || IsReady()) { | 410 if (!IsOk() || IsReady()) { |
| 386 // Queue the waiting tasks into the message loop. This helps avoid | 411 // Queue the waiting tasks into the message loop. This helps avoid |
| 387 // re-entrancy problems that could occur if the closure was invoked | 412 // re-entrancy problems that could occur if the closure was invoked |
| 388 // directly. For example, this could result in use-after-free of the | 413 // directly. For example, this could result in use-after-free of the |
| 389 // process host. | 414 // process host. |
| 390 for (std::vector<base::Closure>::iterator iter = waiting_.begin(); | 415 for (std::vector<base::Closure>::iterator iter = waiting_.begin(); |
| 391 iter != waiting_.end(); ++iter) { | 416 iter != waiting_.end(); ++iter) { |
| 392 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, *iter); | 417 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, *iter); |
| 393 } | 418 } |
| 394 waiting_.clear(); | 419 waiting_.clear(); |
| 395 } | 420 } |
| 396 } | 421 } |
| 397 | 422 |
| 398 void NaClBrowser::MarkAsFailed() { | 423 void NaClBrowser::MarkAsFailed() { |
| 399 ok_ = false; | 424 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 425 has_failed_ = true; | |
| 400 CheckWaiting(); | 426 CheckWaiting(); |
| 401 } | 427 } |
| 402 | 428 |
| 403 void NaClBrowser::WaitForResources(const base::Closure& reply) { | 429 void NaClBrowser::WaitForResources(const base::Closure& reply) { |
| 430 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
| 404 waiting_.push_back(reply); | 431 waiting_.push_back(reply); |
| 405 EnsureAllResourcesAvailable(); | 432 EnsureAllResourcesAvailable(); |
| 406 CheckWaiting(); | 433 CheckWaiting(); |
| 407 } | 434 } |
| 408 | 435 |
| 409 const base::FilePath& NaClBrowser::GetIrtFilePath() { | 436 const base::FilePath& NaClBrowser::GetIrtFilePath() { |
| 437 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
| 410 return irt_filepath_; | 438 return irt_filepath_; |
| 411 } | 439 } |
| 412 | 440 |
| 413 void NaClBrowser::PutFilePath(const base::FilePath& path, | 441 void NaClBrowser::PutFilePath(const base::FilePath& path, |
| 414 uint64_t* file_token_lo, | 442 uint64_t* file_token_lo, |
| 415 uint64_t* file_token_hi) { | 443 uint64_t* file_token_hi) { |
| 416 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 444 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 417 while (true) { | 445 while (true) { |
| 418 uint64_t file_token[2] = {base::RandUint64(), base::RandUint64()}; | 446 uint64_t file_token[2] = {base::RandUint64(), base::RandUint64()}; |
| 419 // A zero file_token indicates there is no file_token, if we get zero, ask | 447 // A zero file_token indicates there is no file_token, if we get zero, ask |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 512 | 540 |
| 513 // If the cache is cleared before it is loaded from the filesystem, act as if | 541 // If the cache is cleared before it is loaded from the filesystem, act as if |
| 514 // we just loaded an empty cache. | 542 // we just loaded an empty cache. |
| 515 if (validation_cache_state_ != NaClResourceReady) { | 543 if (validation_cache_state_ != NaClResourceReady) { |
| 516 validation_cache_state_ = NaClResourceReady; | 544 validation_cache_state_ = NaClResourceReady; |
| 517 CheckWaiting(); | 545 CheckWaiting(); |
| 518 } | 546 } |
| 519 } | 547 } |
| 520 | 548 |
| 521 void NaClBrowser::MarkValidationCacheAsModified() { | 549 void NaClBrowser::MarkValidationCacheAsModified() { |
| 550 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
| 522 if (!validation_cache_is_modified_) { | 551 if (!validation_cache_is_modified_) { |
| 523 // Wait before persisting to disk. This can coalesce multiple cache | 552 // Wait before persisting to disk. This can coalesce multiple cache |
| 524 // modifications info a single disk write. | 553 // modifications info a single disk write. |
| 525 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 554 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| 526 FROM_HERE, base::Bind(&NaClBrowser::PersistValidationCache, | 555 FROM_HERE, base::Bind(&NaClBrowser::PersistValidationCache, |
| 527 weak_factory_.GetWeakPtr()), | 556 base::Unretained(this)), |
| 528 base::TimeDelta::FromMilliseconds(kValidationCacheCoalescingTimeMS)); | 557 base::TimeDelta::FromMilliseconds(kValidationCacheCoalescingTimeMS)); |
| 529 validation_cache_is_modified_ = true; | 558 validation_cache_is_modified_ = true; |
| 530 } | 559 } |
| 531 } | 560 } |
| 532 | 561 |
| 533 void NaClBrowser::PersistValidationCache() { | 562 void NaClBrowser::PersistValidationCache() { |
| 534 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 563 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 535 // validation_cache_is_modified_ may be false if the cache was cleared while | 564 // validation_cache_is_modified_ may be false if the cache was cleared while |
| 536 // this delayed task was pending. | 565 // this delayed task was pending. |
| 537 // validation_cache_file_path_ may be empty if something went wrong during | 566 // validation_cache_file_path_ may be empty if something went wrong during |
| 538 // initialization. | 567 // initialization. |
| 539 if (validation_cache_is_modified_ && !validation_cache_file_path_.empty()) { | 568 if (validation_cache_is_modified_ && !validation_cache_file_path_.empty()) { |
| 540 base::Pickle* pickle = new base::Pickle(); | 569 base::Pickle* pickle = new base::Pickle(); |
| 541 validation_cache_.Serialize(pickle); | 570 validation_cache_.Serialize(pickle); |
| 542 | 571 |
| 543 // Pass the serialized data to another thread to write to disk. File IO is | 572 // Pass the serialized data to another thread to write to disk. File IO is |
| 544 // not allowed on the IO thread (which is the thread this method runs on) | 573 // not allowed on the IO thread (which is the thread this method runs on) |
| 545 // because it can degrade the responsiveness of the browser. | 574 // because it can degrade the responsiveness of the browser. |
| 546 // The task is sequenced so that multiple writes happen in order. | 575 // The task is sequenced so that multiple writes happen in order. |
| 547 content::BrowserThread::PostBlockingPoolSequencedTask( | 576 content::BrowserThread::PostBlockingPoolSequencedTask( |
| 548 kValidationCacheSequenceName, | 577 kValidationCacheSequenceName, |
| 549 FROM_HERE, | 578 FROM_HERE, |
| 550 base::Bind(WriteCache, validation_cache_file_path_, | 579 base::Bind(WriteCache, validation_cache_file_path_, |
| 551 base::Owned(pickle))); | 580 base::Owned(pickle))); |
| 552 } | 581 } |
| 553 validation_cache_is_modified_ = false; | 582 validation_cache_is_modified_ = false; |
| 554 } | 583 } |
| 555 | 584 |
| 556 void NaClBrowser::OnProcessEnd(int process_id) { | 585 void NaClBrowser::OnProcessEnd(int process_id) { |
| 586 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
| 557 gdb_debug_stub_port_map_.erase(process_id); | 587 gdb_debug_stub_port_map_.erase(process_id); |
| 558 } | 588 } |
| 559 | 589 |
| 560 void NaClBrowser::OnProcessCrashed() { | 590 void NaClBrowser::OnProcessCrashed() { |
| 561 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 591 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 562 if (crash_times_.size() == kMaxCrashesPerInterval) { | 592 if (crash_times_.size() == kMaxCrashesPerInterval) { |
| 563 crash_times_.pop_front(); | 593 crash_times_.pop_front(); |
| 564 } | 594 } |
| 565 base::Time time = base::Time::Now(); | 595 base::Time time = base::Time::Now(); |
| 566 crash_times_.push_back(time); | 596 crash_times_.push_back(time); |
| 567 } | 597 } |
| 568 | 598 |
| 569 bool NaClBrowser::IsThrottled() { | 599 bool NaClBrowser::IsThrottled() { |
| 570 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 600 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 571 if (crash_times_.size() != kMaxCrashesPerInterval) { | 601 if (crash_times_.size() != kMaxCrashesPerInterval) { |
| 572 return false; | 602 return false; |
| 573 } | 603 } |
| 574 base::TimeDelta delta = base::Time::Now() - crash_times_.front(); | 604 base::TimeDelta delta = base::Time::Now() - crash_times_.front(); |
| 575 return delta.InSeconds() <= kCrashesIntervalInSeconds; | 605 return delta.InSeconds() <= kCrashesIntervalInSeconds; |
| 576 } | 606 } |
| 577 | 607 |
| 578 } // namespace nacl | 608 } // namespace nacl |
| OLD | NEW |