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 |