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
SetTestingFactory(content::BrowserContext * context,TestingFactoryFunction testing_factory)13 void 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
34 scoped_refptr<RefcountedBrowserContextKeyedService>
SetTestingFactoryAndUse(content::BrowserContext * context,TestingFactoryFunction testing_factory)35 RefcountedBrowserContextKeyedServiceFactory::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
43 RefcountedBrowserContextKeyedServiceFactory::
RefcountedBrowserContextKeyedServiceFactory(const char * name,BrowserContextDependencyManager * manager)44 RefcountedBrowserContextKeyedServiceFactory(
45 const char* name,
46 BrowserContextDependencyManager* manager)
47 : BrowserContextKeyedBaseFactory(name, manager) {}
48
49 RefcountedBrowserContextKeyedServiceFactory::
~RefcountedBrowserContextKeyedServiceFactory()50 ~RefcountedBrowserContextKeyedServiceFactory() {
51 DCHECK(mapping_.empty());
52 }
53
54 scoped_refptr<RefcountedBrowserContextKeyedService>
GetServiceForBrowserContext(content::BrowserContext * context,bool create)55 RefcountedBrowserContextKeyedServiceFactory::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
Associate(content::BrowserContext * context,const scoped_refptr<RefcountedBrowserContextKeyedService> & service)92 void 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
BrowserContextShutdown(content::BrowserContext * context)99 void 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
BrowserContextDestroyed(content::BrowserContext * context)106 void 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
SetEmptyTestingFactory(content::BrowserContext * context)121 void RefcountedBrowserContextKeyedServiceFactory::SetEmptyTestingFactory(
122 content::BrowserContext* context) {
123 SetTestingFactory(context, NULL);
124 }
125
HasTestingFactory(content::BrowserContext * context)126 bool RefcountedBrowserContextKeyedServiceFactory::HasTestingFactory(
127 content::BrowserContext* context) {
128 return testing_factories_.find(context) != testing_factories_.end();
129 }
130
CreateServiceNow(content::BrowserContext * context)131 void RefcountedBrowserContextKeyedServiceFactory::CreateServiceNow(
132 content::BrowserContext* context) {
133 GetServiceForBrowserContext(context, true);
134 }
135