1// Copyright 2014 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.
4
5#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
6
7#include <map>
8
9#include "base/logging.h"
10#include "base/stl_util.h"
11#include "components/keyed_service/content/browser_context_dependency_manager.h"
12#include "components/keyed_service/core/keyed_service.h"
13#include "content/public/browser/browser_context.h"
14
15void BrowserContextKeyedServiceFactory::SetTestingFactory(
16    content::BrowserContext* context,
17    TestingFactoryFunction testing_factory) {
18  // Destroying the context may cause us to lose data about whether |context|
19  // has our preferences registered on it (since the context object itself
20  // isn't dead). See if we need to readd it once we've gone through normal
21  // destruction.
22  bool add_context = ArePreferencesSetOn(context);
23
24#ifndef NDEBUG
25  // Ensure that |context| is not marked as stale (e.g., due to it aliasing an
26  // instance that was destroyed in an earlier test) in order to avoid accesses
27  // to |context| in |BrowserContextShutdown| from causing
28  // |AssertBrowserContextWasntDestroyed| to raise an error.
29  dependency_manager_->MarkBrowserContextLiveForTesting(context);
30#endif
31
32  // We have to go through the shutdown and destroy mechanisms because there
33  // are unit tests that create a service on a context and then change the
34  // testing service mid-test.
35  BrowserContextShutdown(context);
36  BrowserContextDestroyed(context);
37
38  if (add_context)
39    MarkPreferencesSetOn(context);
40
41  testing_factories_[context] = testing_factory;
42}
43
44KeyedService* BrowserContextKeyedServiceFactory::SetTestingFactoryAndUse(
45    content::BrowserContext* context,
46    TestingFactoryFunction testing_factory) {
47  DCHECK(testing_factory);
48  SetTestingFactory(context, testing_factory);
49  return GetServiceForBrowserContext(context, true);
50}
51
52BrowserContextKeyedServiceFactory::BrowserContextKeyedServiceFactory(
53    const char* name,
54    BrowserContextDependencyManager* manager)
55    : BrowserContextKeyedBaseFactory(name, manager) {}
56
57BrowserContextKeyedServiceFactory::~BrowserContextKeyedServiceFactory() {
58  DCHECK(mapping_.empty());
59}
60
61KeyedService* BrowserContextKeyedServiceFactory::GetServiceForBrowserContext(
62    content::BrowserContext* context,
63    bool create) {
64  context = GetBrowserContextToUse(context);
65  if (!context)
66    return NULL;
67
68  // NOTE: If you modify any of the logic below, make sure to update the
69  // refcounted version in refcounted_context_keyed_service_factory.cc!
70  BrowserContextKeyedServices::const_iterator it = mapping_.find(context);
71  if (it != mapping_.end())
72    return it->second;
73
74  // Object not found.
75  if (!create)
76    return NULL;  // And we're forbidden from creating one.
77
78  // Create new object.
79  // Check to see if we have a per-BrowserContext testing factory that we should
80  // use instead of default behavior.
81  KeyedService* service = NULL;
82  BrowserContextOverriddenTestingFunctions::const_iterator jt =
83      testing_factories_.find(context);
84  if (jt != testing_factories_.end()) {
85    if (jt->second) {
86      if (!context->IsOffTheRecord())
87        RegisterUserPrefsOnBrowserContextForTest(context);
88      service = jt->second(context);
89    }
90  } else {
91    service = BuildServiceInstanceFor(context);
92  }
93
94  Associate(context, service);
95  return service;
96}
97
98void BrowserContextKeyedServiceFactory::Associate(
99    content::BrowserContext* context,
100    KeyedService* service) {
101  DCHECK(!ContainsKey(mapping_, context));
102  mapping_.insert(std::make_pair(context, service));
103}
104
105void BrowserContextKeyedServiceFactory::Disassociate(
106    content::BrowserContext* context) {
107  BrowserContextKeyedServices::iterator it = mapping_.find(context);
108  if (it != mapping_.end()) {
109    delete it->second;
110    mapping_.erase(it);
111  }
112}
113
114void BrowserContextKeyedServiceFactory::BrowserContextShutdown(
115    content::BrowserContext* context) {
116  BrowserContextKeyedServices::iterator it = mapping_.find(context);
117  if (it != mapping_.end() && it->second)
118    it->second->Shutdown();
119}
120
121void BrowserContextKeyedServiceFactory::BrowserContextDestroyed(
122    content::BrowserContext* context) {
123  Disassociate(context);
124
125  // For unit tests, we also remove the factory function both so we don't
126  // maintain a big map of dead pointers, but also since we may have a second
127  // object that lives at the same address (see other comments about unit tests
128  // in this file).
129  testing_factories_.erase(context);
130
131  BrowserContextKeyedBaseFactory::BrowserContextDestroyed(context);
132}
133
134void BrowserContextKeyedServiceFactory::SetEmptyTestingFactory(
135    content::BrowserContext* context) {
136  SetTestingFactory(context, NULL);
137}
138
139bool BrowserContextKeyedServiceFactory::HasTestingFactory(
140    content::BrowserContext* context) {
141  return testing_factories_.find(context) != testing_factories_.end();
142}
143
144void BrowserContextKeyedServiceFactory::CreateServiceNow(
145    content::BrowserContext* context) {
146  GetServiceForBrowserContext(context, true);
147}
148