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

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: more checks Created 4 years, 3 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) {
69 DCHECK(observer);
70 if (!observers_.HasObserver(observer))
71 return;
65 observers_.RemoveObserver(observer); 72 observers_.RemoveObserver(observer);
73 --observers_count_;
66 // Once the last observer is gone, clear cached data. 74 // Once the last observer is gone, clear cached data.
67 if (!observers_.might_have_observers()) 75 if (observers_count_ == 0)
68 ClearCache(); 76 ClearCache();
69 } 77 }
70 78
71 void DownloadUIAdapter::OfflinePageModelLoaded(OfflinePageModel* model) { 79 void DownloadUIAdapter::OfflinePageModelLoaded(OfflinePageModel* model) {
72 // This signal is not used here. 80 // This signal is not used here.
73 } 81 }
74 82
75 void DownloadUIAdapter::OfflinePageModelChanged(OfflinePageModel* model) { 83 void DownloadUIAdapter::OfflinePageModelChanged(OfflinePageModel* model) {
76 DCHECK(model == model_); 84 DCHECK(model == model_);
77 model_->GetAllPages( 85 model_->GetAllPages(
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 GURL DownloadUIAdapter::GetOfflineUrlByGuid( 133 GURL DownloadUIAdapter::GetOfflineUrlByGuid(
126 const std::string& guid) const { 134 const std::string& guid) const {
127 // TODO(dimich): when requests are also in the cache, filter them out. 135 // TODO(dimich): when requests are also in the cache, filter them out.
128 // Requests do not yet have offline URL. 136 // Requests do not yet have offline URL.
129 DownloadUIItems::const_iterator it = items_.find(guid); 137 DownloadUIItems::const_iterator it = items_.find(guid);
130 if (it != items_.end()) 138 if (it != items_.end())
131 return it->second->offline_url; 139 return it->second->offline_url;
132 return GURL(); 140 return GURL();
133 } 141 }
134 142
143 // Note that several LoadCache calls may be issued before the async GetAllPages
144 // comes back.
135 void DownloadUIAdapter::LoadCache() { 145 void DownloadUIAdapter::LoadCache() {
136 DCHECK(!is_loaded_);
137 // TODO(dimich): Add fetching from RequestQueue as well. 146 // TODO(dimich): Add fetching from RequestQueue as well.
138 model_->AddObserver(this); 147 state_ = State::LOADING;
139 model_->GetAllPages( 148 model_->GetAllPages(
140 base::Bind(&DownloadUIAdapter::OnOfflinePagesLoaded, 149 base::Bind(&DownloadUIAdapter::OnOfflinePagesLoaded,
141 weak_ptr_factory_.GetWeakPtr())); 150 weak_ptr_factory_.GetWeakPtr()));
142 } 151 }
143 152
144 void DownloadUIAdapter::ClearCache() { 153 void DownloadUIAdapter::ClearCache() {
145 model_->RemoveObserver(this); 154 // Once loaded, this class starts to observe the model. Only remove observer
155 // if it was added.
156 if (state_ == State::LOADED)
157 model_->RemoveObserver(this);
146 items_.clear(); 158 items_.clear();
147 is_loaded_ = false; 159 state_ = State::NOT_LOADED;
148 } 160 }
149 161
150 void DownloadUIAdapter::OnOfflinePagesLoaded( 162 void DownloadUIAdapter::OnOfflinePagesLoaded(
151 const MultipleOfflinePageItemResult& pages) { 163 const MultipleOfflinePageItemResult& pages) {
164 // If multiple observers register quickly, the cache might be already loaded
165 // by the previous LoadCache call. At the same time, if all observers already
166 // left, there is no reason to populate the cache.
167 if (state_ != State::LOADING)
168 return;
152 for (const auto& page : pages) { 169 for (const auto& page : pages) {
153 if (IsVisibleInUI(page.client_id)) { 170 if (IsVisibleInUI(page.client_id)) {
154 std::string guid = page.client_id.id; 171 std::string guid = page.client_id.id;
155 DCHECK(items_.find(guid) == items_.end()); 172 DCHECK(items_.find(guid) == items_.end());
156 items_[guid] = base::MakeUnique<ItemInfo>(page); 173 items_[guid] = base::MakeUnique<ItemInfo>(page);
157 } 174 }
158 } 175 }
159 is_loaded_ = true; 176 model_->AddObserver(this);
177 state_ = State::LOADED;
160 FOR_EACH_OBSERVER(Observer, observers_, ItemsLoaded()); 178 FOR_EACH_OBSERVER(Observer, observers_, ItemsLoaded());
161 } 179 }
162 180
163 void DownloadUIAdapter::NotifyItemsLoaded(Observer* observer) { 181 void DownloadUIAdapter::NotifyItemsLoaded(Observer* observer) {
164 if (observer && observers_.HasObserver(observer)) 182 if (observer && observers_.HasObserver(observer))
165 observer->ItemsLoaded(); 183 observer->ItemsLoaded();
166 } 184 }
167 185
168 // This method is only called by OPM when a single item added. 186 // This method is only called by OPM when a single item added.
169 // TODO(dimich): change OPM to have real OnPageAdded/OnPageUpdated and 187 // 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. 210 // TODO(dimich): Consider adding UMA to record user actions.
193 } 211 }
194 212
195 bool DownloadUIAdapter::IsVisibleInUI(const ClientId& client_id) { 213 bool DownloadUIAdapter::IsVisibleInUI(const ClientId& client_id) {
196 const std::string& name_space = client_id.name_space; 214 const std::string& name_space = client_id.name_space;
197 return (name_space == kAsyncNamespace || name_space == kDownloadNamespace) && 215 return (name_space == kAsyncNamespace || name_space == kDownloadNamespace) &&
198 base::IsValidGUID(client_id.id); 216 base::IsValidGUID(client_id.id);
199 } 217 }
200 218
201 } // namespace offline_pages 219 } // namespace offline_pages
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698