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