OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2011 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 "chrome/browser/extensions/extension_settings.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/json/json_reader.h" | |
9 #include "base/json/json_writer.h" | |
10 #include "base/logging.h" | |
11 #include "base/memory/scoped_ptr.h" | |
12 #include "content/browser/browser_thread.h" | |
13 #include "chrome/browser/extensions/extension_settings_leveldb_storage.h" | |
14 #include "chrome/browser/extensions/extension_settings_noop_storage.h" | |
15 #include "chrome/browser/extensions/extension_settings_storage_cache.h" | |
16 #include "third_party/leveldb/include/leveldb/iterator.h" | |
17 #include "third_party/leveldb/include/leveldb/write_batch.h" | |
18 | |
19 // TODO(kalman): Policy for dots in the key names. Make sure the behaviour of | |
20 // DictionaryValue and JSON classes is consistent with leveldb. | |
21 // TODO(kalman): Integration tests. | |
22 // TODO(kalman): More unit tests (see extension_settings_storage_unittest.cc). | |
23 // TODO(kalman): Use structured cloning rather than JSON. | |
24 // TODO(kalman): Quotas. | |
25 | |
26 ExtensionSettings::ExtensionSettings(const FilePath& base_path) | |
27 : base_path_(base_path) { | |
28 } | |
29 | |
30 ExtensionSettings::~ExtensionSettings() { | |
31 std::map<std::string, ExtensionSettingsStorage*>::iterator it; | |
32 for (it = storage_objs_.begin(); it != storage_objs_.end(); ++it) { | |
33 it->second->DeleteSoon(); | |
34 } | |
35 } | |
36 | |
37 void ExtensionSettings::GetStorage( | |
38 const std::string& extension_id, | |
39 const ExtensionSettings::Callback& callback) { | |
40 if (!GetExistingStorage(extension_id, callback)) { | |
41 StartCreationOfStorage( | |
42 extension_id, | |
43 ExtensionSettingsStorage::LEVELDB, | |
44 ExtensionSettingsStorage::NOOP, | |
45 true, | |
46 callback); | |
47 } | |
48 } | |
49 | |
50 void ExtensionSettings::GetStorageForTesting( | |
51 ExtensionSettingsStorage::Type type, | |
52 bool cached, | |
53 const std::string& extension_id, | |
54 const Callback& callback) { | |
55 if (!GetExistingStorage(extension_id, callback)) { | |
56 StartCreationOfStorage(extension_id, type, type, cached, callback); | |
57 } | |
58 } | |
59 | |
60 bool ExtensionSettings::GetExistingStorage( | |
61 const std::string& extension_id, const Callback& callback) { | |
62 std::map<std::string, ExtensionSettingsStorage*>::iterator existing = | |
63 storage_objs_.find(extension_id); | |
64 if (existing == storage_objs_.end()) { | |
65 // No existing storage. | |
66 return false; | |
67 } | |
68 // Existing storage. Reply with that. | |
69 ExtensionSettingsStorage* storage = existing->second; | |
70 DCHECK(storage != NULL); | |
71 MessageLoop::current()->PostTask( | |
72 FROM_HERE, | |
73 base::Bind( | |
74 &Callback::Run, | |
75 base::Unretained(new Callback(callback)), | |
Matt Perry
2011/06/29 18:08:11
you're leaking the new Callback here. I don't beli
not at google - send to devlin
2011/08/03 06:36:51
Done.
| |
76 storage)); | |
77 return true; | |
78 } | |
79 | |
80 void ExtensionSettings::StartCreationOfStorage( | |
81 const std::string& extension_id, | |
82 ExtensionSettingsStorage::Type type, | |
83 ExtensionSettingsStorage::Type fallback_type, | |
84 bool cached, | |
85 const Callback& callback) { | |
86 // Make sure we're not deleted mid-callback. | |
87 // Released in EndCreationOfStorage(). | |
88 AddRef(); | |
Matt Perry
2011/06/29 18:08:11
base::Bind normally handles this for you - except
not at google - send to devlin
2011/08/03 06:36:51
Actually it should be fine to just let Bind() refc
Matt Perry
2011/08/03 19:33:52
if Bind holds the last reference, then the Release
Matt Perry
2011/08/03 19:33:52
Bind will release its reference when the task is r
not at google - send to devlin
2011/08/03 22:06:55
Changed to RefCountedThreadSafe.
The last referen
| |
89 BrowserThread::PostTask( | |
90 BrowserThread::FILE, | |
91 FROM_HERE, | |
92 base::Bind( | |
93 &ExtensionSettings::CreateStorageOnFileThread, | |
94 base::Unretained(this), | |
95 extension_id, | |
96 type, | |
97 fallback_type, | |
98 cached, | |
99 callback)); | |
100 } | |
101 | |
102 void ExtensionSettings::CreateStorageOnFileThread( | |
103 const std::string& extension_id, | |
104 ExtensionSettingsStorage::Type type, | |
105 ExtensionSettingsStorage::Type fallback_type, | |
106 bool cached, | |
107 const Callback& callback) { | |
108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
109 ExtensionSettingsStorage* storage = CreateStorage(extension_id, type, cached); | |
110 if (storage == NULL && fallback_type != type) { | |
111 storage = CreateStorage(extension_id, fallback_type, cached); | |
112 } | |
113 DCHECK(storage != NULL); | |
114 BrowserThread::PostTask( | |
115 BrowserThread::UI, | |
116 FROM_HERE, | |
117 base::Bind( | |
118 &ExtensionSettings::EndCreationOfStorage, | |
119 base::Unretained(this), | |
120 extension_id, | |
121 storage, | |
122 callback)); | |
123 } | |
124 | |
125 ExtensionSettingsStorage* ExtensionSettings::CreateStorage( | |
126 const std::string& extension_id, | |
127 ExtensionSettingsStorage::Type type, | |
128 bool cached) { | |
129 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
130 ExtensionSettingsStorage* storage = NULL; | |
131 switch (type) { | |
132 case ExtensionSettingsStorage::NOOP: | |
133 storage = new ExtensionSettingsNoopStorage(); | |
134 break; | |
135 case ExtensionSettingsStorage::LEVELDB: | |
136 storage = ExtensionSettingsLeveldbStorage::Create( | |
137 base_path_, extension_id); | |
138 break; | |
139 default: | |
140 NOTREACHED(); | |
141 } | |
142 if (storage != NULL && cached) { | |
143 storage = new ExtensionSettingsStorageCache(storage); | |
144 } | |
145 return storage; | |
146 } | |
147 | |
148 void ExtensionSettings::EndCreationOfStorage( | |
149 const std::string& extension_id, | |
150 ExtensionSettingsStorage* storage, | |
151 const Callback& callback) { | |
152 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
153 // Cache the result now. To avoid a race condition, check again to see | |
154 // whether a storage has been created already; if so, use that one. | |
155 std::map<std::string, ExtensionSettingsStorage*>::iterator existing = | |
156 storage_objs_.find(extension_id); | |
157 if (existing == storage_objs_.end()) { | |
158 storage_objs_[extension_id] = storage; | |
159 } else { | |
160 delete storage; | |
161 storage = existing->second; | |
162 DCHECK(storage != NULL); | |
163 } | |
164 callback.Run(storage); | |
165 // Release reference added by StartCreationOfStorage(). | |
166 Release(); | |
167 } | |
OLD | NEW |