Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(368)

Side by Side Diff: extensions/browser/api/lock_screen_data/item_storage.cc

Issue 2934293003: The chrome.lockScreen.data API implementation (Closed)
Patch Set: . Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 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 "extensions/browser/api/lock_screen_data/item_storage.h"
6
7 #include <set>
8 #include <utility>
9
10 #include "base/guid.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/values.h"
13 #include "components/prefs/pref_registry_simple.h"
14 #include "components/prefs/pref_service.h"
15 #include "components/prefs/scoped_user_pref_update.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "extensions/browser/api/lock_screen_data/data_item.h"
18 #include "extensions/browser/api/lock_screen_data/operation_result.h"
19 #include "extensions/browser/api/storage/local_value_store_cache.h"
20 #include "extensions/browser/event_router.h"
21 #include "extensions/browser/extension_registry.h"
22 #include "extensions/browser/extensions_browser_client.h"
23 #include "extensions/browser/value_store/value_store.h"
24 #include "extensions/browser/value_store/value_store_factory_impl.h"
25 #include "extensions/common/api/lock_screen_data.h"
26
27 namespace extensions {
28
29 namespace lock_screen_data {
30
31 namespace {
32
33 const char kLockScreenDataPrefKey[] = "lockScreenDataItems";
34
35 ItemStorage* g_data_item_storage = nullptr;
36
37 ItemStorage::ItemFactoryCallback* g_test_item_factory_callback = nullptr;
38 ItemStorage::RegisteredItemsGetter* g_test_registered_items_getter_callback =
39 nullptr;
40 ItemStorage::ItemStoreDeleter* g_test_delete_all_items_callback = nullptr;
41
42 std::unique_ptr<DataItem> CreateDataItem(const std::string& item_id,
43 const std::string& extension_id,
44 content::BrowserContext* context,
45 ValueStoreCache* value_store_cache,
46 base::SequencedTaskRunner* task_runner,
47 const std::string& crypto_key) {
48 return g_test_item_factory_callback
49 ? g_test_item_factory_callback->Run(item_id, extension_id,
50 crypto_key)
51 : base::MakeUnique<DataItem>(item_id, extension_id, context,
52 value_store_cache, task_runner,
53 crypto_key);
54 }
55
56 void GetRegisteredItems(const std::string& extension_id,
57 content::BrowserContext* context,
58 ValueStoreCache* value_store_cache,
59 base::SequencedTaskRunner* task_runner,
60 const DataItem::RegisteredValuesCallback& callback) {
61 if (g_test_registered_items_getter_callback) {
62 g_test_registered_items_getter_callback->Run(extension_id, callback);
63 return;
64 }
65 DataItem::GetRegisteredValuesForExtension(
66 context, value_store_cache, task_runner, extension_id, callback);
67 }
68
69 void DeleteAllItems(const std::string& extension_id,
70 content::BrowserContext* context,
71 ValueStoreCache* value_store_cache,
72 base::SequencedTaskRunner* task_runner,
73 const base::Closure& callback) {
74 if (g_test_delete_all_items_callback) {
75 g_test_delete_all_items_callback->Run(extension_id, callback);
76 return;
77 }
78 DataItem::DeleteAllItemsForExtension(context, value_store_cache, task_runner,
79 extension_id, callback);
80 }
81
82 void ReleaseValueStoreCache(std::unique_ptr<LocalValueStoreCache> cache) {
83 // Nothing to do. Used only to defer |cache| destruction to the FILE thread.
84 }
85
86 } // namespace
87
88 // static
89 ItemStorage* ItemStorage::Get(content::BrowserContext* context) {
90 if (g_data_item_storage && !g_data_item_storage->IsContextAllowed(context))
91 return nullptr;
92 return g_data_item_storage;
93 }
94
95 // static
96 void ItemStorage::RegisterLocalState(PrefRegistrySimple* registry) {
97 registry->RegisterDictionaryPref(kLockScreenDataPrefKey);
98 }
99
100 ItemStorage::ItemStorage(content::BrowserContext* context,
101 PrefService* local_state,
102 const std::string& crypto_key,
103 const base::FilePath& storage_root)
104 : context_(context),
105 user_id_(
106 ExtensionsBrowserClient::Get()->GetUserIdHashFromContext(context)),
107 crypto_key_(crypto_key),
108 local_state_(local_state),
109 storage_root_(storage_root.Append(user_id_)),
110 extension_registry_observer_(this),
111 value_store_cache_(base::MakeUnique<LocalValueStoreCache>(
112 new ValueStoreFactoryImpl(storage_root))),
113 weak_ptr_factory_(this) {
114 CHECK(!user_id_.empty());
115 extension_registry_observer_.Add(ExtensionRegistry::Get(context));
116 task_runner_ = content::BrowserThread::GetTaskRunnerForThread(
117 content::BrowserThread::FILE);
118
119 DCHECK(!g_data_item_storage);
120 g_data_item_storage = this;
121
122 ClearUninstalledAppData();
123 }
124
125 ItemStorage::~ItemStorage() {
126 data_item_cache_.clear();
127
128 task_runner_->PostTask(
129 FROM_HERE, base::Bind(&ReleaseValueStoreCache,
130 base::Passed(std::move(value_store_cache_))));
131
132 DCHECK_EQ(g_data_item_storage, this);
133 g_data_item_storage = nullptr;
134 }
135
136 // static
137 void ItemStorage::SetItemProvidersForTesting(
138 RegisteredItemsGetter* items_getter_callback,
139 ItemFactoryCallback* factory_callback,
140 ItemStoreDeleter* deleter_callback) {
141 g_test_registered_items_getter_callback = items_getter_callback;
142 g_test_item_factory_callback = factory_callback;
143 g_test_delete_all_items_callback = deleter_callback;
144 }
145
146 void ItemStorage::SetSessionLocked(bool session_locked) {
147 SessionLockedState new_state = session_locked
148 ? SessionLockedState::kLocked
149 : SessionLockedState::kNotLocked;
150 if (new_state == session_locked_state_)
151 return;
152
153 bool was_locked = session_locked_state_ == SessionLockedState::kLocked;
154 session_locked_state_ = new_state;
155
156 if (session_locked_state_ != SessionLockedState::kNotLocked)
157 return;
158
159 std::set<std::string> extensions = GetExtensionsWithDataItems(false);
160 for (const auto& id : extensions) {
161 // If the session state is unlocked, dispatch Item availability events to
162 // apps with available data items.
163 api::lock_screen_data::DataItemsAvailableEvent event_args;
164 event_args.was_locked = was_locked;
165
166 std::unique_ptr<Event> event = base::MakeUnique<Event>(
167 events::LOCK_SCREEN_DATA_ON_DATA_ITEMS_AVAILABLE,
168 api::lock_screen_data::OnDataItemsAvailable::kEventName,
169 api::lock_screen_data::OnDataItemsAvailable::Create(event_args));
170 EventRouter::Get(context_)->DispatchEventToExtension(id, std::move(event));
171 }
172 }
173
174 void ItemStorage::CreateItem(const std::string& extension_id,
175 const CreateCallback& callback) {
176 EnsureCacheForExtensionLoaded(
177 extension_id,
178 base::Bind(&ItemStorage::CreateItemImpl, weak_ptr_factory_.GetWeakPtr(),
179 extension_id, callback));
180 }
181
182 void ItemStorage::GetAllForExtension(const std::string& extension_id,
183 const DataItemListCallback& callback) {
184 EnsureCacheForExtensionLoaded(
185 extension_id,
186 base::Bind(&ItemStorage::GetAllForExtensionImpl,
187 weak_ptr_factory_.GetWeakPtr(), extension_id, callback));
188 }
189
190 void ItemStorage::SetItemContent(const std::string& extension_id,
191 const std::string& item_id,
192 const std::vector<char>& data,
193 const ItemStorage::WriteCallback& callback) {
194 EnsureCacheForExtensionLoaded(
195 extension_id, base::Bind(&ItemStorage::SetItemContentImpl,
196 weak_ptr_factory_.GetWeakPtr(), extension_id,
197 item_id, data, callback));
198 }
199
200 void ItemStorage::GetItemContent(const std::string& extension_id,
201 const std::string& item_id,
202 const ItemStorage::ReadCallback& callback) {
203 EnsureCacheForExtensionLoaded(
204 extension_id, base::Bind(&ItemStorage::GetItemContentImpl,
205 weak_ptr_factory_.GetWeakPtr(), extension_id,
206 item_id, callback));
207 }
208
209 void ItemStorage::DeleteItem(const std::string& extension_id,
210 const std::string& item_id,
211 const WriteCallback& callback) {
212 EnsureCacheForExtensionLoaded(
213 extension_id,
214 base::Bind(&ItemStorage::DeleteItemImpl, weak_ptr_factory_.GetWeakPtr(),
215 extension_id, item_id, callback));
216 }
217
218 void ItemStorage::OnExtensionUninstalled(
219 content::BrowserContext* browser_context,
220 const Extension* extension,
221 UninstallReason reason) {
222 ClearExtensionData(extension->id());
223 }
224
225 ItemStorage::CachedExtensionData::CachedExtensionData() = default;
226
227 ItemStorage::CachedExtensionData::~CachedExtensionData() = default;
228
229 bool ItemStorage::IsContextAllowed(content::BrowserContext* context) {
230 switch (session_locked_state_) {
231 case SessionLockedState::kUnknown:
232 return false;
233 case SessionLockedState::kLocked:
234 return ExtensionsBrowserClient::Get()->IsLockScreenContext(context);
235 case SessionLockedState::kNotLocked:
236 return context_ == context;
237 }
238 NOTREACHED() << "Unknown session locked state";
239 return false;
240 }
241
242 void ItemStorage::CreateItemImpl(const std::string& extension_id,
243 const CreateCallback& callback) {
244 std::unique_ptr<DataItem> item =
245 CreateDataItem(base::GenerateGUID(), extension_id, context_,
246 value_store_cache_.get(), task_runner_.get(), crypto_key_);
247 DataItem* item_ptr = item.get();
248 item_ptr->Register(
249 base::Bind(&ItemStorage::OnItemRegistered, weak_ptr_factory_.GetWeakPtr(),
250 base::Passed(std::move(item)), extension_id, callback));
251 }
252
253 void ItemStorage::GetAllForExtensionImpl(const std::string& extension_id,
254 const DataItemListCallback& callback) {
255 std::vector<const DataItem*> items;
256 ExtensionDataMap::iterator extension_data =
257 data_item_cache_.find(extension_id);
258 if (extension_data == data_item_cache_.end()) {
259 callback.Run(items);
260 return;
261 }
262
263 for (const auto& item : extension_data->second.data_items) {
264 if (!item.second)
265 continue;
266 items.push_back(item.second.get());
267 }
268
269 callback.Run(items);
270 }
271
272 void ItemStorage::SetItemContentImpl(
273 const std::string& extension_id,
274 const std::string& item_id,
275 const std::vector<char>& data,
276 const ItemStorage::WriteCallback& callback) {
277 DataItem* item = FindItem(extension_id, item_id);
278 if (!item) {
279 callback.Run(OperationResult::kNotFound);
280 return;
281 }
282
283 item->Write(data, callback);
284 }
285
286 void ItemStorage::GetItemContentImpl(const std::string& extension_id,
287 const std::string& item_id,
288 const ReadCallback& callback) {
289 DataItem* item = FindItem(extension_id, item_id);
290 if (!item) {
291 callback.Run(OperationResult::kNotFound, nullptr);
292 return;
293 }
294
295 item->Read(callback);
296 }
297
298 void ItemStorage::DeleteItemImpl(const std::string& extension_id,
299 const std::string& item_id,
300 const WriteCallback& callback) {
301 DataItem* item = FindItem(extension_id, item_id);
302 if (!item) {
303 callback.Run(OperationResult::kNotFound);
304 return;
305 }
306
307 item->Delete(base::Bind(&ItemStorage::OnItemDeleted, base::Unretained(this),
308 extension_id, item_id, callback));
309 }
310
311 void ItemStorage::OnItemRegistered(std::unique_ptr<DataItem> item,
312 const std::string& extension_id,
313 const CreateCallback& callback,
314 OperationResult result) {
315 if (result != OperationResult::kSuccess) {
316 callback.Run(result, nullptr);
317 return;
318 }
319
320 DataItem* item_ptr = item.get();
321 data_item_cache_[extension_id].data_items.emplace(item_ptr->id(),
322 std::move(item));
323
324 {
325 DictionaryPrefUpdate update(local_state_, kLockScreenDataPrefKey);
326 update->SetInteger(user_id_ + "." + extension_id,
327 data_item_cache_[extension_id].data_items.size());
328 }
329
330 callback.Run(OperationResult::kSuccess, item_ptr);
331 }
332
333 void ItemStorage::OnItemDeleted(const std::string& extension_id,
334 const std::string& item_id,
335 const WriteCallback& callback,
336 OperationResult result) {
337 data_item_cache_[extension_id].data_items.erase(item_id);
338 {
339 DictionaryPrefUpdate update(local_state_, kLockScreenDataPrefKey);
340 update->SetInteger(user_id_ + "." + extension_id,
341 data_item_cache_[extension_id].data_items.size());
342 }
343
344 callback.Run(result);
345 }
346
347 void ItemStorage::EnsureCacheForExtensionLoaded(const std::string& extension_id,
348 const base::Closure& callback) {
349 CachedExtensionData* data = &data_item_cache_[extension_id];
350 if (data->state == CachedExtensionData::State::kLoaded) {
351 callback.Run();
352 return;
353 }
354
355 data->load_callbacks.push_back(callback);
356
357 if (data->state == CachedExtensionData::State::kLoading)
358 return;
359
360 data->state = CachedExtensionData::State::kLoading;
361
362 GetRegisteredItems(extension_id, context_, value_store_cache_.get(),
363 task_runner_.get(),
364 base::Bind(&ItemStorage::OnGotExtensionItems,
365 weak_ptr_factory_.GetWeakPtr(), extension_id));
366 }
367
368 void ItemStorage::OnGotExtensionItems(
369 const std::string& extension_id,
370 OperationResult result,
371 std::unique_ptr<base::DictionaryValue> items) {
372 ExtensionDataMap::iterator data = data_item_cache_.find(extension_id);
373 if (data == data_item_cache_.end() ||
374 data->second.state != CachedExtensionData::State::kLoading) {
375 return;
376 }
377
378 if (result == OperationResult::kSuccess) {
379 for (base::DictionaryValue::Iterator item_iter(*items);
380 !item_iter.IsAtEnd(); item_iter.Advance()) {
381 std::unique_ptr<DataItem> item = CreateDataItem(
382 item_iter.key(), extension_id, context_, value_store_cache_.get(),
383 task_runner_.get(), crypto_key_);
384 data->second.data_items.emplace(item_iter.key(), std::move(item));
385 }
386 }
387
388 DictionaryPrefUpdate update(local_state_, kLockScreenDataPrefKey);
389 update->SetInteger(user_id_ + "." + extension_id,
390 data->second.data_items.size());
391
392 data->second.state = CachedExtensionData::State::kLoaded;
393
394 std::vector<base::Closure> callbacks;
395 callbacks.swap(data->second.load_callbacks);
396 for (auto& callback : callbacks)
397 callback.Run();
398 }
399
400 DataItem* ItemStorage::FindItem(const std::string& extension_id,
401 const std::string& item_id) {
402 ExtensionDataMap::iterator extension_data =
403 data_item_cache_.find(extension_id);
404 if (extension_data == data_item_cache_.end())
405 return nullptr;
406
407 if (extension_data->second.state != CachedExtensionData::State::kLoaded)
408 return nullptr;
409 DataItemMap::iterator item_it =
410 extension_data->second.data_items.find(item_id);
411 if (item_it == extension_data->second.data_items.end())
412 return nullptr;
413
414 if (!item_it->second)
415 return nullptr;
416 return item_it->second.get();
417 }
418
419 std::set<std::string> ItemStorage::GetExtensionsWithDataItems(
420 bool include_empty) {
421 std::set<std::string> result;
422
423 const base::DictionaryValue* user_data = nullptr;
424 const base::DictionaryValue* items =
425 local_state_->GetDictionary(kLockScreenDataPrefKey);
426 if (!items || !items->GetDictionary(user_id_, &user_data) || !user_data)
427 return result;
428
429 for (base::DictionaryValue::Iterator extension_iter(*user_data);
430 !extension_iter.IsAtEnd(); extension_iter.Advance()) {
431 if (extension_iter.value().is_int() &&
432 (include_empty || extension_iter.value().GetInt() > 0)) {
433 result.insert(extension_iter.key());
434 }
435 }
436 return result;
437 }
438
439 void ItemStorage::ClearUninstalledAppData() {
440 std::set<std::string> extensions =
441 GetExtensionsWithDataItems(true /* include_empty */);
442 for (const auto& id : extensions) {
443 if (!ExtensionRegistry::Get(context_)->GetInstalledExtension(id))
444 ClearExtensionData(id);
445 }
446 }
447
448 void ItemStorage::ClearExtensionData(const std::string& id) {
449 DeleteAllItems(id, context_, value_store_cache_.get(), task_runner_.get(),
450 base::Bind(&ItemStorage::RemoveExtensionFromLocalState,
451 weak_ptr_factory_.GetWeakPtr(), id));
452 }
453
454 void ItemStorage::RemoveExtensionFromLocalState(const std::string& id) {
455 {
456 DictionaryPrefUpdate update(local_state_, kLockScreenDataPrefKey);
457 update->Remove(user_id_ + "." + id, nullptr);
458 }
459
460 ExtensionDataMap::iterator it = data_item_cache_.find(id);
461 if (it == data_item_cache_.end())
462 return;
463
464 std::vector<base::Closure> callbacks;
465 callbacks.swap(it->second.load_callbacks);
466
467 data_item_cache_.erase(it);
468
469 for (auto& callback : callbacks)
470 callback.Run();
471 }
472
473 } // namespace lock_screen_data
474 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698