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