summaryrefslogtreecommitdiffstats
path: root/chrome/browser/profiles/profile_dependency_manager.cc
blob: 8b9a1fac5b95c49c87e80703aa45934c241f9192 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/profiles/profile_dependency_manager.h"

#include <algorithm>
#include <deque>
#include <iterator>

#include "base/bind.h"
#include "chrome/browser/profiles/profile_keyed_base_factory.h"
#include "content/public/browser/browser_context.h"

#ifndef NDEBUG
#include "base/command_line.h"
#include "base/file_util.h"
#include "chrome/common/chrome_switches.h"
#endif

class Profile;

void ProfileDependencyManager::AddComponent(
    ProfileKeyedBaseFactory* component) {
  dependency_graph_.AddNode(component);
}

void ProfileDependencyManager::RemoveComponent(
    ProfileKeyedBaseFactory* component) {
  dependency_graph_.RemoveNode(component);
}

void ProfileDependencyManager::AddEdge(ProfileKeyedBaseFactory* depended,
                                       ProfileKeyedBaseFactory* dependee) {
  dependency_graph_.AddEdge(depended, dependee);
}

void ProfileDependencyManager::CreateProfileServices(
    content::BrowserContext* profile, bool is_testing_profile) {
#ifndef NDEBUG
  // Unmark |profile| as dead. This exists because of unit tests, which will
  // often have similar stack structures. 0xWhatever might be created, go out
  // of scope, and then a new Profile object might be created at 0xWhatever.
  dead_profile_pointers_.erase(profile);
#endif

  std::vector<DependencyNode*> construction_order;
  if (!dependency_graph_.GetConstructionOrder(&construction_order)) {
    NOTREACHED();
  }

#ifndef NDEBUG
  DumpProfileDependencies(profile);
#endif

  for (size_t i = 0; i < construction_order.size(); i++) {
    ProfileKeyedBaseFactory* factory =
        static_cast<ProfileKeyedBaseFactory*>(construction_order[i]);

    if (!profile->IsOffTheRecord()) {
      // We only register preferences on normal profiles because the incognito
      // profile shares the pref service with the normal one.
      factory->RegisterUserPrefsOnProfile(profile);
    }

    if (is_testing_profile && factory->ServiceIsNULLWhileTesting()) {
      factory->SetEmptyTestingFactory(profile);
    } else if (factory->ServiceIsCreatedWithProfile()) {
      // Create the service.
      factory->CreateServiceNow(profile);
    }
  }
}

void ProfileDependencyManager::DestroyProfileServices(
    content::BrowserContext* profile) {
  std::vector<DependencyNode*> destruction_order;
  if (!dependency_graph_.GetDestructionOrder(&destruction_order)) {
    NOTREACHED();
  }

#ifndef NDEBUG
  DumpProfileDependencies(profile);
#endif

  for (size_t i = 0; i < destruction_order.size(); i++) {
    ProfileKeyedBaseFactory* factory =
        static_cast<ProfileKeyedBaseFactory*>(destruction_order[i]);
    factory->ProfileShutdown(profile);
  }

#ifndef NDEBUG
  // The profile is now dead to the rest of the program.
  dead_profile_pointers_.insert(profile);
#endif

  for (size_t i = 0; i < destruction_order.size(); i++) {
    ProfileKeyedBaseFactory* factory =
        static_cast<ProfileKeyedBaseFactory*>(destruction_order[i]);
    factory->ProfileDestroyed(profile);
  }
}

#ifndef NDEBUG
void ProfileDependencyManager::AssertProfileWasntDestroyed(
    content::BrowserContext* profile) {
  if (dead_profile_pointers_.find(profile) != dead_profile_pointers_.end()) {
    NOTREACHED() << "Attempted to access a Profile that was ShutDown(). This "
                 << "is most likely a heap smasher in progress. After "
                 << "ProfileKeyedService::Shutdown() completes, your service "
                 << "MUST NOT refer to depended Profile services again.";
  }
}
#endif

// static
ProfileDependencyManager* ProfileDependencyManager::GetInstance() {
  return Singleton<ProfileDependencyManager>::get();
}

ProfileDependencyManager::ProfileDependencyManager() {
}

ProfileDependencyManager::~ProfileDependencyManager() {
}

#ifndef NDEBUG
namespace {

std::string ProfileKeyedBaseFactoryGetNodeName(DependencyNode* node) {
  return static_cast<ProfileKeyedBaseFactory*>(node)->name();
}

}  // namespace

void ProfileDependencyManager::DumpProfileDependencies(
    content::BrowserContext* profile) {
  // Whenever we try to build a destruction ordering, we should also dump a
  // dependency graph to "/path/to/profile/profile-dependencies.dot".
  if (CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kDumpProfileDependencyGraph)) {
    base::FilePath dot_file =
        profile->GetPath().AppendASCII("profile-dependencies.dot");
    std::string contents = dependency_graph_.DumpAsGraphviz(
        "Profile", base::Bind(&ProfileKeyedBaseFactoryGetNodeName));
    file_util::WriteFile(dot_file, contents.c_str(), contents.size());
  }
}
#endif  // NDEBUG