summaryrefslogtreecommitdiffstats
path: root/chrome/browser/profiles/profile_keyed_base_factory.cc
blob: abc4fe7616e1169c58b8ea33ff2870092c6244f1 (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
150
151
152
153
154
155
156
157
158
159
160
161
162
// Copyright (c) 2012 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_keyed_base_factory.h"

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

void ProfileKeyedBaseFactory::SetTestingFactory(Profile* profile,
                                                FactoryFunction factory) {
  // Destroying the profile may cause us to lose data about whether |profile|
  // has our preferences registered on it (since the profile object itself
  // isn't dead). See if we need to readd it once we've gone through normal
  // destruction.
  bool add_profile = registered_preferences_.find(profile) !=
                     registered_preferences_.end();

  // We have to go through the shutdown and destroy mechanisms because there
  // are unit tests that create a service on a profile and then change the
  // testing service mid-test.
  ProfileShutdown(profile);
  ProfileDestroyed(profile);

  if (add_profile)
    registered_preferences_.insert(profile);

  factories_[profile] = factory;
}

ProfileKeyedBase* ProfileKeyedBaseFactory::SetTestingFactoryAndUse(
    Profile* profile,
    FactoryFunction factory) {
  DCHECK(factory);
  SetTestingFactory(profile, factory);
  return GetBaseForProfile(profile, true);
}

ProfileKeyedBaseFactory::ProfileKeyedBaseFactory(
    const char* name, ProfileDependencyManager* manager)
    : dependency_manager_(manager)
#ifndef NDEBUG
    , service_name_(name)
#endif
{
  dependency_manager_->AddComponent(this);
}

ProfileKeyedBaseFactory::~ProfileKeyedBaseFactory() {
  dependency_manager_->RemoveComponent(this);
}


void ProfileKeyedBaseFactory::DependsOn(ProfileKeyedBaseFactory* rhs) {
  dependency_manager_->AddEdge(rhs, this);
}

void ProfileKeyedBaseFactory::RegisterUserPrefsOnProfile(Profile* profile) {
  // Safe timing for pref registration is hard. Previously, we made Profile
  // responsible for all pref registration on every service that used
  // Profile. Now we don't and there are timing issues.
  //
  // With normal profiles, prefs can simply be registered at
  // ProfileDependencyManager::CreateProfileServices time. With incognito
  // profiles, we just never register since incognito profiles share the same
  // pref services with their parent profiles.
  //
  // TestingProfiles throw a wrench into the mix, in that some tests will
  // swap out the PrefService after we've registered user prefs on the original
  // PrefService. Test code that does this is responsible for either manually
  // invoking RegisterUserPrefs() on the appropriate ProfileKeyedServiceFactory
  // associated with the prefs they need, or they can use SetTestingFactory()
  // and create a service (since service creation with a factory method causes
  // registration to happen at service creation time).
  //
  // Now that services are responsible for declaring their preferences, we have
  // to enforce a uniquenes check here because some tests create one profile and
  // multiple services of the same type attached to that profile (serially, not
  // parallel) and we don't want to register multiple times on the same profile.
  DCHECK(!profile->IsOffTheRecord());

  std::set<Profile*>::iterator it = registered_preferences_.find(profile);
  if (it == registered_preferences_.end()) {
    RegisterUserPrefs(profile->GetPrefs());
    registered_preferences_.insert(profile);
  }
}

bool ProfileKeyedBaseFactory::ServiceRedirectedInIncognito() {
  return false;
}

bool ProfileKeyedBaseFactory::ServiceHasOwnInstanceInIncognito() {
  return false;
}

bool ProfileKeyedBaseFactory::ServiceIsCreatedWithProfile() {
  return false;
}

bool ProfileKeyedBaseFactory::ServiceIsNULLWhileTesting() {
  return false;
}

ProfileKeyedBase* ProfileKeyedBaseFactory::GetBaseForProfile(
    Profile* profile,
    bool create) {
#ifndef NDEBUG
  dependency_manager_->AssertProfileWasntDestroyed(profile);
#endif

  // Possibly handle Incognito mode.
  if (profile->IsOffTheRecord()) {
    if (ServiceRedirectedInIncognito()) {
      profile = profile->GetOriginalProfile();

#ifndef NDEBUG
      dependency_manager_->AssertProfileWasntDestroyed(profile);
#endif
    } else if (ServiceHasOwnInstanceInIncognito()) {
      // No-op; the pointers are already set correctly.
    } else {
      return NULL;
    }
  }

  ProfileKeyedBase* service = NULL;
  if (GetAssociation(profile, &service)) {
    return service;
  } else if (create) {
    // not found but creation allowed

    // Check to see if we have a per-Profile factory
    std::map<Profile*, FactoryFunction>::iterator jt = factories_.find(profile);
    if (jt != factories_.end()) {
      if (jt->second) {
        if (!profile->IsOffTheRecord())
          RegisterUserPrefsOnProfile(profile);
        service = jt->second(profile);
      } else {
        service = NULL;
      }
    } else {
      service = BuildServiceInstanceFor(profile);
    }
  } else {
    // not found, creation forbidden
    return NULL;
  }

  Associate(profile, service);
  return service;
}

void ProfileKeyedBaseFactory::ProfileDestroyed(Profile* profile) {
  // For unit tests, we also remove the factory function both so we don't
  // maintain a big map of dead pointers, but also since we may have a second
  // object that lives at the same address (see other comments about unit tests
  // in this file).
  factories_.erase(profile);
  registered_preferences_.erase(profile);
}