Supervised user import: Listen for profile creation/deletion
[chromium-blink-merge.git] / content / browser / browser_thread_impl.cc
blob78e3836dadeef038f5db6e1a7fd0b1a3352fd8b6
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/browser_thread_impl.h"
7 #include <string>
9 #include "base/atomicops.h"
10 #include "base/bind.h"
11 #include "base/compiler_specific.h"
12 #include "base/lazy_instance.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/message_loop/message_loop_proxy.h"
15 #include "base/threading/sequenced_worker_pool.h"
16 #include "base/threading/thread_restrictions.h"
17 #include "content/public/browser/browser_thread_delegate.h"
18 #include "content/public/browser/content_browser_client.h"
19 #include "net/disk_cache/simple/simple_backend_impl.h"
21 #if defined(OS_ANDROID)
22 #include "base/android/jni_android.h"
23 #endif
25 namespace content {
27 namespace {
29 // Friendly names for the well-known threads.
30 static const char* g_browser_thread_names[BrowserThread::ID_COUNT] = {
31 "", // UI (name assembled in browser_main.cc).
32 "Chrome_DBThread", // DB
33 "Chrome_FileThread", // FILE
34 "Chrome_FileUserBlockingThread", // FILE_USER_BLOCKING
35 "Chrome_ProcessLauncherThread", // PROCESS_LAUNCHER
36 "Chrome_CacheThread", // CACHE
37 "Chrome_IOThread", // IO
40 // An implementation of MessageLoopProxy to be used in conjunction
41 // with BrowserThread.
42 class BrowserThreadMessageLoopProxy : public base::MessageLoopProxy {
43 public:
44 explicit BrowserThreadMessageLoopProxy(BrowserThread::ID identifier)
45 : id_(identifier) {
48 // MessageLoopProxy implementation.
49 bool PostDelayedTask(const tracked_objects::Location& from_here,
50 const base::Closure& task,
51 base::TimeDelta delay) override {
52 return BrowserThread::PostDelayedTask(id_, from_here, task, delay);
55 bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
56 const base::Closure& task,
57 base::TimeDelta delay) override {
58 return BrowserThread::PostNonNestableDelayedTask(id_, from_here, task,
59 delay);
62 bool RunsTasksOnCurrentThread() const override {
63 return BrowserThread::CurrentlyOn(id_);
66 protected:
67 ~BrowserThreadMessageLoopProxy() override {}
69 private:
70 BrowserThread::ID id_;
71 DISALLOW_COPY_AND_ASSIGN(BrowserThreadMessageLoopProxy);
74 // A separate helper is used just for the proxies, in order to avoid needing
75 // to initialize the globals to create a proxy.
76 struct BrowserThreadProxies {
77 BrowserThreadProxies() {
78 for (int i = 0; i < BrowserThread::ID_COUNT; ++i) {
79 proxies[i] =
80 new BrowserThreadMessageLoopProxy(static_cast<BrowserThread::ID>(i));
84 scoped_refptr<base::MessageLoopProxy> proxies[BrowserThread::ID_COUNT];
87 base::LazyInstance<BrowserThreadProxies>::Leaky
88 g_proxies = LAZY_INSTANCE_INITIALIZER;
90 struct BrowserThreadGlobals {
91 BrowserThreadGlobals()
92 : blocking_pool(new base::SequencedWorkerPool(3, "BrowserBlocking")) {
93 memset(threads, 0, BrowserThread::ID_COUNT * sizeof(threads[0]));
94 memset(thread_delegates, 0,
95 BrowserThread::ID_COUNT * sizeof(thread_delegates[0]));
98 // This lock protects |threads|. Do not read or modify that array
99 // without holding this lock. Do not block while holding this lock.
100 base::Lock lock;
102 // This array is protected by |lock|. The threads are not owned by this
103 // array. Typically, the threads are owned on the UI thread by
104 // BrowserMainLoop. BrowserThreadImpl objects remove themselves from this
105 // array upon destruction.
106 BrowserThreadImpl* threads[BrowserThread::ID_COUNT];
108 // Only atomic operations are used on this array. The delegates are not owned
109 // by this array, rather by whoever calls BrowserThread::SetDelegate.
110 BrowserThreadDelegate* thread_delegates[BrowserThread::ID_COUNT];
112 const scoped_refptr<base::SequencedWorkerPool> blocking_pool;
115 base::LazyInstance<BrowserThreadGlobals>::Leaky
116 g_globals = LAZY_INSTANCE_INITIALIZER;
118 } // namespace
120 BrowserThreadImpl::BrowserThreadImpl(ID identifier)
121 : Thread(g_browser_thread_names[identifier]),
122 identifier_(identifier) {
123 Initialize();
126 BrowserThreadImpl::BrowserThreadImpl(ID identifier,
127 base::MessageLoop* message_loop)
128 : Thread(message_loop->thread_name()), identifier_(identifier) {
129 set_message_loop(message_loop);
130 Initialize();
133 // static
134 void BrowserThreadImpl::ShutdownThreadPool() {
135 // The goal is to make it impossible for chrome to 'infinite loop' during
136 // shutdown, but to reasonably expect that all BLOCKING_SHUTDOWN tasks queued
137 // during shutdown get run. There's nothing particularly scientific about the
138 // number chosen.
139 const int kMaxNewShutdownBlockingTasks = 1000;
140 BrowserThreadGlobals& globals = g_globals.Get();
141 globals.blocking_pool->Shutdown(kMaxNewShutdownBlockingTasks);
144 // static
145 void BrowserThreadImpl::FlushThreadPoolHelperForTesting() {
146 // We don't want to create a pool if none exists.
147 if (g_globals == NULL)
148 return;
149 g_globals.Get().blocking_pool->FlushForTesting();
150 disk_cache::SimpleBackendImpl::FlushWorkerPoolForTesting();
153 void BrowserThreadImpl::Init() {
154 BrowserThreadGlobals& globals = g_globals.Get();
156 using base::subtle::AtomicWord;
157 AtomicWord* storage =
158 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
159 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
160 BrowserThreadDelegate* delegate =
161 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
162 if (delegate) {
163 delegate->Init();
164 message_loop()->PostTask(FROM_HERE,
165 base::Bind(&BrowserThreadDelegate::InitAsync,
166 // Delegate is expected to exist for the
167 // duration of the thread's lifetime
168 base::Unretained(delegate)));
172 // We disable optimizations for this block of functions so the compiler doesn't
173 // merge them all together.
174 MSVC_DISABLE_OPTIMIZE()
175 MSVC_PUSH_DISABLE_WARNING(4748)
177 NOINLINE void BrowserThreadImpl::UIThreadRun(base::MessageLoop* message_loop) {
178 volatile int line_number = __LINE__;
179 Thread::Run(message_loop);
180 CHECK_GT(line_number, 0);
183 NOINLINE void BrowserThreadImpl::DBThreadRun(base::MessageLoop* message_loop) {
184 volatile int line_number = __LINE__;
185 Thread::Run(message_loop);
186 CHECK_GT(line_number, 0);
189 NOINLINE void BrowserThreadImpl::FileThreadRun(
190 base::MessageLoop* message_loop) {
191 volatile int line_number = __LINE__;
192 Thread::Run(message_loop);
193 CHECK_GT(line_number, 0);
196 NOINLINE void BrowserThreadImpl::FileUserBlockingThreadRun(
197 base::MessageLoop* message_loop) {
198 volatile int line_number = __LINE__;
199 Thread::Run(message_loop);
200 CHECK_GT(line_number, 0);
203 NOINLINE void BrowserThreadImpl::ProcessLauncherThreadRun(
204 base::MessageLoop* message_loop) {
205 volatile int line_number = __LINE__;
206 Thread::Run(message_loop);
207 CHECK_GT(line_number, 0);
210 NOINLINE void BrowserThreadImpl::CacheThreadRun(
211 base::MessageLoop* message_loop) {
212 volatile int line_number = __LINE__;
213 Thread::Run(message_loop);
214 CHECK_GT(line_number, 0);
217 NOINLINE void BrowserThreadImpl::IOThreadRun(base::MessageLoop* message_loop) {
218 volatile int line_number = __LINE__;
219 Thread::Run(message_loop);
220 CHECK_GT(line_number, 0);
223 MSVC_POP_WARNING()
224 MSVC_ENABLE_OPTIMIZE();
226 void BrowserThreadImpl::Run(base::MessageLoop* message_loop) {
227 #if defined(OS_ANDROID)
228 // Not to reset thread name to "Thread-???" by VM, attach VM with thread name.
229 // Though it may create unnecessary VM thread objects, keeping thread name
230 // gives more benefit in debugging in the platform.
231 if (!thread_name().empty()) {
232 base::android::AttachCurrentThreadWithName(thread_name());
234 #endif
236 BrowserThread::ID thread_id = ID_COUNT;
237 if (!GetCurrentThreadIdentifier(&thread_id))
238 return Thread::Run(message_loop);
240 switch (thread_id) {
241 case BrowserThread::UI:
242 return UIThreadRun(message_loop);
243 case BrowserThread::DB:
244 return DBThreadRun(message_loop);
245 case BrowserThread::FILE:
246 return FileThreadRun(message_loop);
247 case BrowserThread::FILE_USER_BLOCKING:
248 return FileUserBlockingThreadRun(message_loop);
249 case BrowserThread::PROCESS_LAUNCHER:
250 return ProcessLauncherThreadRun(message_loop);
251 case BrowserThread::CACHE:
252 return CacheThreadRun(message_loop);
253 case BrowserThread::IO:
254 return IOThreadRun(message_loop);
255 case BrowserThread::ID_COUNT:
256 CHECK(false); // This shouldn't actually be reached!
257 break;
259 Thread::Run(message_loop);
262 void BrowserThreadImpl::CleanUp() {
263 BrowserThreadGlobals& globals = g_globals.Get();
265 using base::subtle::AtomicWord;
266 AtomicWord* storage =
267 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
268 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
269 BrowserThreadDelegate* delegate =
270 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
272 if (delegate)
273 delegate->CleanUp();
276 void BrowserThreadImpl::Initialize() {
277 BrowserThreadGlobals& globals = g_globals.Get();
279 base::AutoLock lock(globals.lock);
280 DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT);
281 DCHECK(globals.threads[identifier_] == NULL);
282 globals.threads[identifier_] = this;
285 BrowserThreadImpl::~BrowserThreadImpl() {
286 // All Thread subclasses must call Stop() in the destructor. This is
287 // doubly important here as various bits of code check they are on
288 // the right BrowserThread.
289 Stop();
291 BrowserThreadGlobals& globals = g_globals.Get();
292 base::AutoLock lock(globals.lock);
293 globals.threads[identifier_] = NULL;
294 #ifndef NDEBUG
295 // Double check that the threads are ordered correctly in the enumeration.
296 for (int i = identifier_ + 1; i < ID_COUNT; ++i) {
297 DCHECK(!globals.threads[i]) <<
298 "Threads must be listed in the reverse order that they die";
300 #endif
303 // static
304 bool BrowserThreadImpl::PostTaskHelper(
305 BrowserThread::ID identifier,
306 const tracked_objects::Location& from_here,
307 const base::Closure& task,
308 base::TimeDelta delay,
309 bool nestable) {
310 DCHECK(identifier >= 0 && identifier < ID_COUNT);
311 // Optimization: to avoid unnecessary locks, we listed the ID enumeration in
312 // order of lifetime. So no need to lock if we know that the target thread
313 // outlives current thread.
314 // Note: since the array is so small, ok to loop instead of creating a map,
315 // which would require a lock because std::map isn't thread safe, defeating
316 // the whole purpose of this optimization.
317 BrowserThread::ID current_thread = ID_COUNT;
318 bool target_thread_outlives_current =
319 GetCurrentThreadIdentifier(&current_thread) &&
320 current_thread >= identifier;
322 BrowserThreadGlobals& globals = g_globals.Get();
323 if (!target_thread_outlives_current)
324 globals.lock.Acquire();
326 base::MessageLoop* message_loop =
327 globals.threads[identifier] ? globals.threads[identifier]->message_loop()
328 : NULL;
329 if (message_loop) {
330 if (nestable) {
331 message_loop->PostDelayedTask(from_here, task, delay);
332 } else {
333 message_loop->PostNonNestableDelayedTask(from_here, task, delay);
337 if (!target_thread_outlives_current)
338 globals.lock.Release();
340 return !!message_loop;
343 // static
344 bool BrowserThread::PostBlockingPoolTask(
345 const tracked_objects::Location& from_here,
346 const base::Closure& task) {
347 return g_globals.Get().blocking_pool->PostWorkerTask(from_here, task);
350 // static
351 bool BrowserThread::PostBlockingPoolTaskAndReply(
352 const tracked_objects::Location& from_here,
353 const base::Closure& task,
354 const base::Closure& reply) {
355 return g_globals.Get().blocking_pool->PostTaskAndReply(
356 from_here, task, reply);
359 // static
360 bool BrowserThread::PostBlockingPoolSequencedTask(
361 const std::string& sequence_token_name,
362 const tracked_objects::Location& from_here,
363 const base::Closure& task) {
364 return g_globals.Get().blocking_pool->PostNamedSequencedWorkerTask(
365 sequence_token_name, from_here, task);
368 // static
369 void BrowserThread::PostAfterStartupTask(
370 const tracked_objects::Location& from_here,
371 const scoped_refptr<base::TaskRunner>& task_runner,
372 const base::Closure& task) {
373 GetContentClient()->browser()->PostAfterStartupTask(from_here, task_runner,
374 task);
377 // static
378 base::SequencedWorkerPool* BrowserThread::GetBlockingPool() {
379 return g_globals.Get().blocking_pool.get();
382 // static
383 bool BrowserThread::IsThreadInitialized(ID identifier) {
384 if (g_globals == NULL)
385 return false;
387 BrowserThreadGlobals& globals = g_globals.Get();
388 base::AutoLock lock(globals.lock);
389 DCHECK(identifier >= 0 && identifier < ID_COUNT);
390 return globals.threads[identifier] != NULL;
393 // static
394 bool BrowserThread::CurrentlyOn(ID identifier) {
395 // We shouldn't use MessageLoop::current() since it uses LazyInstance which
396 // may be deleted by ~AtExitManager when a WorkerPool thread calls this
397 // function.
398 // http://crbug.com/63678
399 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
400 BrowserThreadGlobals& globals = g_globals.Get();
401 base::AutoLock lock(globals.lock);
402 DCHECK(identifier >= 0 && identifier < ID_COUNT);
403 return globals.threads[identifier] &&
404 globals.threads[identifier]->message_loop() ==
405 base::MessageLoop::current();
408 static const char* GetThreadName(BrowserThread::ID thread) {
409 if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT)
410 return g_browser_thread_names[thread];
411 if (thread == BrowserThread::UI)
412 return "Chrome_UIThread";
413 return "Unknown Thread";
416 // static
417 std::string BrowserThread::GetDCheckCurrentlyOnErrorMessage(ID expected) {
418 const base::MessageLoop* message_loop = base::MessageLoop::current();
419 ID actual_browser_thread;
420 const char* actual_name = "Unknown Thread";
421 if (message_loop && !message_loop->thread_name().empty()) {
422 actual_name = message_loop->thread_name().c_str();
423 } else if (GetCurrentThreadIdentifier(&actual_browser_thread)) {
424 actual_name = GetThreadName(actual_browser_thread);
426 std::string result = "Must be called on ";
427 result += GetThreadName(expected);
428 result += "; actually called on ";
429 result += actual_name;
430 result += ".";
431 return result;
434 // static
435 bool BrowserThread::IsMessageLoopValid(ID identifier) {
436 if (g_globals == NULL)
437 return false;
439 BrowserThreadGlobals& globals = g_globals.Get();
440 base::AutoLock lock(globals.lock);
441 DCHECK(identifier >= 0 && identifier < ID_COUNT);
442 return globals.threads[identifier] &&
443 globals.threads[identifier]->message_loop();
446 // static
447 bool BrowserThread::PostTask(ID identifier,
448 const tracked_objects::Location& from_here,
449 const base::Closure& task) {
450 return BrowserThreadImpl::PostTaskHelper(
451 identifier, from_here, task, base::TimeDelta(), true);
454 // static
455 bool BrowserThread::PostDelayedTask(ID identifier,
456 const tracked_objects::Location& from_here,
457 const base::Closure& task,
458 base::TimeDelta delay) {
459 return BrowserThreadImpl::PostTaskHelper(
460 identifier, from_here, task, delay, true);
463 // static
464 bool BrowserThread::PostNonNestableTask(
465 ID identifier,
466 const tracked_objects::Location& from_here,
467 const base::Closure& task) {
468 return BrowserThreadImpl::PostTaskHelper(
469 identifier, from_here, task, base::TimeDelta(), false);
472 // static
473 bool BrowserThread::PostNonNestableDelayedTask(
474 ID identifier,
475 const tracked_objects::Location& from_here,
476 const base::Closure& task,
477 base::TimeDelta delay) {
478 return BrowserThreadImpl::PostTaskHelper(
479 identifier, from_here, task, delay, false);
482 // static
483 bool BrowserThread::PostTaskAndReply(
484 ID identifier,
485 const tracked_objects::Location& from_here,
486 const base::Closure& task,
487 const base::Closure& reply) {
488 return GetMessageLoopProxyForThread(identifier)->PostTaskAndReply(from_here,
489 task,
490 reply);
493 // static
494 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) {
495 if (g_globals == NULL)
496 return false;
498 // We shouldn't use MessageLoop::current() since it uses LazyInstance which
499 // may be deleted by ~AtExitManager when a WorkerPool thread calls this
500 // function.
501 // http://crbug.com/63678
502 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
503 base::MessageLoop* cur_message_loop = base::MessageLoop::current();
504 BrowserThreadGlobals& globals = g_globals.Get();
505 for (int i = 0; i < ID_COUNT; ++i) {
506 if (globals.threads[i] &&
507 globals.threads[i]->message_loop() == cur_message_loop) {
508 *identifier = globals.threads[i]->identifier_;
509 return true;
513 return false;
516 // static
517 scoped_refptr<base::MessageLoopProxy>
518 BrowserThread::GetMessageLoopProxyForThread(ID identifier) {
519 return g_proxies.Get().proxies[identifier];
522 // static
523 base::MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) {
524 if (g_globals == NULL)
525 return NULL;
527 BrowserThreadGlobals& globals = g_globals.Get();
528 base::AutoLock lock(globals.lock);
529 base::Thread* thread = globals.threads[identifier];
530 DCHECK(thread);
531 base::MessageLoop* loop = thread->message_loop();
532 return loop;
535 // static
536 void BrowserThread::SetDelegate(ID identifier,
537 BrowserThreadDelegate* delegate) {
538 using base::subtle::AtomicWord;
539 BrowserThreadGlobals& globals = g_globals.Get();
540 AtomicWord* storage = reinterpret_cast<AtomicWord*>(
541 &globals.thread_delegates[identifier]);
542 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange(
543 storage, reinterpret_cast<AtomicWord>(delegate));
545 // This catches registration when previously registered.
546 DCHECK(!delegate || !old_pointer);
549 } // namespace content