1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// found in the LICENSE file.
490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "components/keyed_service/content/browser_context_dependency_manager.h"
690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <algorithm>
890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <deque>
990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <iterator>
1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/bind.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/debug/trace_event.h"
13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "components/keyed_service/content/browser_context_keyed_base_factory.h"
1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "content/public/browser/browser_context.h"
1590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#ifndef NDEBUG
1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/command_line.h"
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// Dumps dependency information about our browser context keyed services
217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// into a dot file in the browser context directory.
227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)const char kDumpBrowserContextDependencyGraphFlag[] =
237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    "dump-browser-context-graph";
247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#endif  // NDEBUG
2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void BrowserContextDependencyManager::AddComponent(
2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    BrowserContextKeyedBaseFactory* component) {
2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  dependency_graph_.AddNode(component);
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void BrowserContextDependencyManager::RemoveComponent(
3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    BrowserContextKeyedBaseFactory* component) {
3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  dependency_graph_.RemoveNode(component);
3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void BrowserContextDependencyManager::AddEdge(
3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    BrowserContextKeyedBaseFactory* depended,
3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    BrowserContextKeyedBaseFactory* dependee) {
3990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  dependency_graph_.AddEdge(depended, dependee);
4090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
4190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
42a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void BrowserContextDependencyManager::RegisterProfilePrefsForServices(
43a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const content::BrowserContext* context,
44a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    user_prefs::PrefRegistrySyncable* pref_registry) {
45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  std::vector<DependencyNode*> construction_order;
46a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!dependency_graph_.GetConstructionOrder(&construction_order)) {
47a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    NOTREACHED();
48a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
49a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
50a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  for (std::vector<DependencyNode*>::const_iterator it =
51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)           construction_order.begin();
52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       it != construction_order.end();
53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       ++it) {
54a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    BrowserContextKeyedBaseFactory* factory =
55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        static_cast<BrowserContextKeyedBaseFactory*>(*it);
56a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    factory->RegisterProfilePrefsIfNecessaryForContext(context, pref_registry);
57a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
58a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
59a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void BrowserContextDependencyManager::CreateBrowserContextServices(
613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    content::BrowserContext* context) {
62a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DoCreateBrowserContextServices(context, false);
633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void BrowserContextDependencyManager::CreateBrowserContextServicesForTest(
66a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    content::BrowserContext* context) {
67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DoCreateBrowserContextServices(context, true);
683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void BrowserContextDependencyManager::DoCreateBrowserContextServices(
713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    content::BrowserContext* context,
72a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    bool is_testing_context) {
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  TRACE_EVENT0(
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "browser",
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "BrowserContextDependencyManager::DoCreateBrowserContextServices")
7690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#ifndef NDEBUG
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MarkBrowserContextLiveForTesting(context);
7890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#endif
7990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  will_create_browser_context_services_callbacks_.Notify(context);
810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<DependencyNode*> construction_order;
8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!dependency_graph_.GetConstructionOrder(&construction_order)) {
8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    NOTREACHED();
8590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
8690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#ifndef NDEBUG
8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DumpBrowserContextDependencies(context);
8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#endif
9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (size_t i = 0; i < construction_order.size(); i++) {
9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    BrowserContextKeyedBaseFactory* factory =
9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        static_cast<BrowserContextKeyedBaseFactory*>(construction_order[i]);
94116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (is_testing_context && factory->ServiceIsNULLWhileTesting() &&
95116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        !factory->HasTestingFactory(context)) {
9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      factory->SetEmptyTestingFactory(context);
9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    } else if (factory->ServiceIsCreatedWithBrowserContext()) {
9890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // Create the service.
9990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      factory->CreateServiceNow(context);
10090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
10190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
10390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
10490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void BrowserContextDependencyManager::DestroyBrowserContextServices(
10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    content::BrowserContext* context) {
10690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<DependencyNode*> destruction_order;
10790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!dependency_graph_.GetDestructionOrder(&destruction_order)) {
10890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    NOTREACHED();
10990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
11090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#ifndef NDEBUG
11290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DumpBrowserContextDependencies(context);
11390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#endif
11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (size_t i = 0; i < destruction_order.size(); i++) {
11690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    BrowserContextKeyedBaseFactory* factory =
11790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        static_cast<BrowserContextKeyedBaseFactory*>(destruction_order[i]);
11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    factory->BrowserContextShutdown(context);
11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#ifndef NDEBUG
12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // The context is now dead to the rest of the program.
12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  dead_context_pointers_.insert(context);
12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#endif
12590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (size_t i = 0; i < destruction_order.size(); i++) {
12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    BrowserContextKeyedBaseFactory* factory =
12890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        static_cast<BrowserContextKeyedBaseFactory*>(destruction_order[i]);
12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    factory->BrowserContextDestroyed(context);
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochscoped_ptr<base::CallbackList<void(content::BrowserContext*)>::Subscription>
1340529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochBrowserContextDependencyManager::
1350529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochRegisterWillCreateBrowserContextServicesCallbackForTesting(
1360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const base::Callback<void(content::BrowserContext*)>& callback) {
1370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return will_create_browser_context_services_callbacks_.Add(callback);
1380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
1390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#ifndef NDEBUG
14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void BrowserContextDependencyManager::AssertBrowserContextWasntDestroyed(
14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    content::BrowserContext* context) {
14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (dead_context_pointers_.find(context) != dead_context_pointers_.end()) {
14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    NOTREACHED() << "Attempted to access a BrowserContext that was ShutDown(). "
14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                 << "This is most likely a heap smasher in progress. After "
146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 << "KeyedService::Shutdown() completes, your "
14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                 << "service MUST NOT refer to depended BrowserContext "
14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                 << "services again.";
14990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void BrowserContextDependencyManager::MarkBrowserContextLiveForTesting(
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    content::BrowserContext* context) {
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  dead_context_pointers_.erase(context);
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
15690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#endif
15790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// static
15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)BrowserContextDependencyManager*
16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)BrowserContextDependencyManager::GetInstance() {
16190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return Singleton<BrowserContextDependencyManager>::get();
16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
16390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
164a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)BrowserContextDependencyManager::BrowserContextDependencyManager() {}
16590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)BrowserContextDependencyManager::~BrowserContextDependencyManager() {}
16790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
16890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#ifndef NDEBUG
16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace {
17090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)std::string BrowserContextKeyedBaseFactoryGetNodeName(DependencyNode* node) {
17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return static_cast<BrowserContextKeyedBaseFactory*>(node)->name();
17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
17490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace
17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void BrowserContextDependencyManager::DumpBrowserContextDependencies(
17890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    content::BrowserContext* context) {
17990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Whenever we try to build a destruction ordering, we should also dump a
18090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // dependency graph to "/path/to/context/context-dependencies.dot".
18190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (CommandLine::ForCurrentProcess()->HasSwitch(
1827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          kDumpBrowserContextDependencyGraphFlag)) {
18390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::FilePath dot_file =
18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        context->GetPath().AppendASCII("browser-context-dependencies.dot");
18590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::string contents = dependency_graph_.DumpAsGraphviz(
18690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        "BrowserContext",
18790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::Bind(&BrowserContextKeyedBaseFactoryGetNodeName));
188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::WriteFile(dot_file, contents.c_str(), contents.size());
18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#endif  // NDEBUG
192