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

Side by Side Diff: components/offline_pages/downloads/download_ui_adapter.cc

Issue 2264233002: Fix a crash in DownloadUIAddapter that happens when Java bridge is created/removed quickly while (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix the test Created 4 years, 4 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
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/offline_pages/downloads/download_ui_adapter.h" 5 #include "components/offline_pages/downloads/download_ui_adapter.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/guid.h" 8 #include "base/guid.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/memory/ptr_util.h" 10 #include "base/memory/ptr_util.h"
(...skipping 10 matching lines...) Expand all
21 21
22 DownloadUIAdapter::ItemInfo::ItemInfo(const OfflinePageItem& page) 22 DownloadUIAdapter::ItemInfo::ItemInfo(const OfflinePageItem& page)
23 : ui_item(base::MakeUnique<DownloadUIItem>(page)), 23 : ui_item(base::MakeUnique<DownloadUIItem>(page)),
24 offline_id(page.offline_id), 24 offline_id(page.offline_id),
25 offline_url(page.GetOfflineURL()) {} 25 offline_url(page.GetOfflineURL()) {}
26 26
27 DownloadUIAdapter::ItemInfo::~ItemInfo() {} 27 DownloadUIAdapter::ItemInfo::~ItemInfo() {}
28 28
29 DownloadUIAdapter::DownloadUIAdapter(OfflinePageModel* model) 29 DownloadUIAdapter::DownloadUIAdapter(OfflinePageModel* model)
30 : model_(model), 30 : model_(model),
31 is_loaded_(false), 31 state_(State::NOT_LOADED),
32 observers_count_(0),
32 weak_ptr_factory_(this) { 33 weak_ptr_factory_(this) {
33 } 34 }
34 35
35 DownloadUIAdapter::~DownloadUIAdapter() { } 36 DownloadUIAdapter::~DownloadUIAdapter() { }
36 37
37 // static 38 // static
38 DownloadUIAdapter* DownloadUIAdapter::FromOfflinePageModel( 39 DownloadUIAdapter* DownloadUIAdapter::FromOfflinePageModel(
39 OfflinePageModel* offline_page_model) { 40 OfflinePageModel* offline_page_model) {
40 DownloadUIAdapter* adapter = static_cast<DownloadUIAdapter*>( 41 DownloadUIAdapter* adapter = static_cast<DownloadUIAdapter*>(
41 offline_page_model->GetUserData(kDownloadUIAdapterKey)); 42 offline_page_model->GetUserData(kDownloadUIAdapterKey));
42 if (!adapter) { 43 if (!adapter) {
43 adapter = new DownloadUIAdapter(offline_page_model); 44 adapter = new DownloadUIAdapter(offline_page_model);
44 offline_page_model->SetUserData(kDownloadUIAdapterKey, adapter); 45 offline_page_model->SetUserData(kDownloadUIAdapterKey, adapter);
45 } 46 }
46 return adapter; 47 return adapter;
47 } 48 }
48 49
49 void DownloadUIAdapter::AddObserver(Observer* observer) { 50 void DownloadUIAdapter::AddObserver(Observer* observer) {
50 DCHECK(observer); 51 DCHECK(observer);
51 if (!observers_.might_have_observers()) 52 if (observers_.HasObserver(observer))
53 return;
54 if (observers_count_ == 0)
52 LoadCache(); 55 LoadCache();
53 observers_.AddObserver(observer); 56 observers_.AddObserver(observer);
57 ++observers_count_;
54 // If the items are already loaded, post the notification right away. 58 // If the items are already loaded, post the notification right away.
55 // Don't just invoke it from here to avoid reentrancy in the client. 59 // Don't just invoke it from here to avoid reentrancy in the client.
56 if (is_loaded_) { 60 if (state_ == State::LOADED) {
57 base::ThreadTaskRunnerHandle::Get()->PostTask( 61 base::ThreadTaskRunnerHandle::Get()->PostTask(
58 FROM_HERE, base::Bind(&DownloadUIAdapter::NotifyItemsLoaded, 62 FROM_HERE, base::Bind(&DownloadUIAdapter::NotifyItemsLoaded,
59 weak_ptr_factory_.GetWeakPtr(), 63 weak_ptr_factory_.GetWeakPtr(),
60 base::Unretained(observer))); 64 base::Unretained(observer)));
61 } 65 }
62 } 66 }
63 67
64 void DownloadUIAdapter::RemoveObserver(Observer* observer) { 68 void DownloadUIAdapter::RemoveObserver(Observer* observer) {
fgorski 2016/08/23 01:31:58 what about here? if (observers_.HasObserver(observ
65 observers_.RemoveObserver(observer); 69 observers_.RemoveObserver(observer);
70 --observers_count_;
66 // Once the last observer is gone, clear cached data. 71 // Once the last observer is gone, clear cached data.
67 if (!observers_.might_have_observers()) 72 if (observers_count_ == 0)
68 ClearCache(); 73 ClearCache();
69 } 74 }
70 75
71 void DownloadUIAdapter::OfflinePageModelLoaded(OfflinePageModel* model) { 76 void DownloadUIAdapter::OfflinePageModelLoaded(OfflinePageModel* model) {
72 // This signal is not used here. 77 // This signal is not used here.
73 } 78 }
74 79
75 void DownloadUIAdapter::OfflinePageModelChanged(OfflinePageModel* model) { 80 void DownloadUIAdapter::OfflinePageModelChanged(OfflinePageModel* model) {
76 DCHECK(model == model_); 81 DCHECK(model == model_);
77 model_->GetAllPages( 82 model_->GetAllPages(
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 GURL DownloadUIAdapter::GetOfflineUrlByGuid( 130 GURL DownloadUIAdapter::GetOfflineUrlByGuid(
126 const std::string& guid) const { 131 const std::string& guid) const {
127 // TODO(dimich): when requests are also in the cache, filter them out. 132 // TODO(dimich): when requests are also in the cache, filter them out.
128 // Requests do not yet have offline URL. 133 // Requests do not yet have offline URL.
129 DownloadUIItems::const_iterator it = items_.find(guid); 134 DownloadUIItems::const_iterator it = items_.find(guid);
130 if (it != items_.end()) 135 if (it != items_.end())
131 return it->second->offline_url; 136 return it->second->offline_url;
132 return GURL(); 137 return GURL();
133 } 138 }
134 139
140 // Note that several LoadCache calls may be issued before the async GetAllPages
141 // comes back.
135 void DownloadUIAdapter::LoadCache() { 142 void DownloadUIAdapter::LoadCache() {
136 DCHECK(!is_loaded_);
137 // TODO(dimich): Add fetching from RequestQueue as well. 143 // TODO(dimich): Add fetching from RequestQueue as well.
138 model_->AddObserver(this); 144 state_ = State::LOADING;
139 model_->GetAllPages( 145 model_->GetAllPages(
140 base::Bind(&DownloadUIAdapter::OnOfflinePagesLoaded, 146 base::Bind(&DownloadUIAdapter::OnOfflinePagesLoaded,
141 weak_ptr_factory_.GetWeakPtr())); 147 weak_ptr_factory_.GetWeakPtr()));
142 } 148 }
143 149
144 void DownloadUIAdapter::ClearCache() { 150 void DownloadUIAdapter::ClearCache() {
145 model_->RemoveObserver(this); 151 // Once loaded, this class starts to observe the model. Only remove observer
152 // if it was added.
153 if (state_ == State::LOADED)
154 model_->RemoveObserver(this);
146 items_.clear(); 155 items_.clear();
147 is_loaded_ = false; 156 state_ = State::NOT_LOADED;
148 } 157 }
149 158
150 void DownloadUIAdapter::OnOfflinePagesLoaded( 159 void DownloadUIAdapter::OnOfflinePagesLoaded(
151 const MultipleOfflinePageItemResult& pages) { 160 const MultipleOfflinePageItemResult& pages) {
161 // If multiple observers register quickly, the cache might be already loaded
162 // by the previous LoadCache call. At the same time, if all observers already
163 // left, there is no reason to populate the cache.
164 if (state_ != State::LOADING)
165 return;
152 for (const auto& page : pages) { 166 for (const auto& page : pages) {
153 if (IsVisibleInUI(page.client_id)) { 167 if (IsVisibleInUI(page.client_id)) {
154 std::string guid = page.client_id.id; 168 std::string guid = page.client_id.id;
155 DCHECK(items_.find(guid) == items_.end()); 169 DCHECK(items_.find(guid) == items_.end());
156 items_[guid] = base::MakeUnique<ItemInfo>(page); 170 items_[guid] = base::MakeUnique<ItemInfo>(page);
157 } 171 }
158 } 172 }
159 is_loaded_ = true; 173 model_->AddObserver(this);
174 state_ = State::LOADED;
160 FOR_EACH_OBSERVER(Observer, observers_, ItemsLoaded()); 175 FOR_EACH_OBSERVER(Observer, observers_, ItemsLoaded());
161 } 176 }
162 177
163 void DownloadUIAdapter::NotifyItemsLoaded(Observer* observer) { 178 void DownloadUIAdapter::NotifyItemsLoaded(Observer* observer) {
164 if (observer && observers_.HasObserver(observer)) 179 if (observer && observers_.HasObserver(observer))
165 observer->ItemsLoaded(); 180 observer->ItemsLoaded();
166 } 181 }
167 182
168 // This method is only called by OPM when a single item added. 183 // This method is only called by OPM when a single item added.
169 // TODO(dimich): change OPM to have real OnPageAdded/OnPageUpdated and 184 // TODO(dimich): change OPM to have real OnPageAdded/OnPageUpdated and
(...skipping 22 matching lines...) Expand all
192 // TODO(dimich): Consider adding UMA to record user actions. 207 // TODO(dimich): Consider adding UMA to record user actions.
193 } 208 }
194 209
195 bool DownloadUIAdapter::IsVisibleInUI(const ClientId& client_id) { 210 bool DownloadUIAdapter::IsVisibleInUI(const ClientId& client_id) {
196 const std::string& name_space = client_id.name_space; 211 const std::string& name_space = client_id.name_space;
197 return (name_space == kAsyncNamespace || name_space == kDownloadNamespace) && 212 return (name_space == kAsyncNamespace || name_space == kDownloadNamespace) &&
198 base::IsValidGUID(client_id.id); 213 base::IsValidGUID(client_id.id);
199 } 214 }
200 215
201 } // namespace offline_pages 216 } // namespace offline_pages
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698