OLD | NEW |
| (Empty) |
1 // Copyright 2015 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 "components/update_client/action_update_check.h" | |
6 | |
7 #include <stddef.h> | |
8 #include <utility> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/bind_helpers.h" | |
12 #include "base/callback.h" | |
13 #include "base/location.h" | |
14 #include "base/logging.h" | |
15 #include "base/memory/ptr_util.h" | |
16 #include "base/single_thread_task_runner.h" | |
17 #include "base/threading/thread_task_runner_handle.h" | |
18 #include "base/version.h" | |
19 #include "components/update_client/action_update.h" | |
20 #include "components/update_client/configurator.h" | |
21 #include "components/update_client/update_checker.h" | |
22 #include "components/update_client/update_client.h" | |
23 #include "components/update_client/update_client_errors.h" | |
24 #include "components/update_client/utils.h" | |
25 | |
26 using std::string; | |
27 using std::vector; | |
28 | |
29 namespace update_client { | |
30 | |
31 namespace { | |
32 | |
33 // Returns true if the |proposed| version is newer than |current| version. | |
34 bool IsVersionNewer(const base::Version& current, const std::string& proposed) { | |
35 base::Version proposed_ver(proposed); | |
36 return proposed_ver.IsValid() && current.CompareTo(proposed_ver) < 0; | |
37 } | |
38 | |
39 } // namespace | |
40 | |
41 ActionUpdateCheck::ActionUpdateCheck( | |
42 std::unique_ptr<UpdateChecker> update_checker, | |
43 const base::Version& browser_version, | |
44 const std::string& extra_request_parameters) | |
45 : update_checker_(std::move(update_checker)), | |
46 browser_version_(browser_version), | |
47 extra_request_parameters_(extra_request_parameters) {} | |
48 | |
49 ActionUpdateCheck::~ActionUpdateCheck() { | |
50 DCHECK(thread_checker_.CalledOnValidThread()); | |
51 } | |
52 | |
53 void ActionUpdateCheck::Run(UpdateContext* update_context, Callback callback) { | |
54 DCHECK(thread_checker_.CalledOnValidThread()); | |
55 | |
56 ActionImpl::Run(update_context, callback); | |
57 | |
58 // Calls out to get the corresponding CrxComponent data for the CRXs in this | |
59 // update context. | |
60 vector<CrxComponent> crx_components; | |
61 update_context_->crx_data_callback.Run(update_context_->ids, &crx_components); | |
62 | |
63 for (size_t i = 0; i != crx_components.size(); ++i) { | |
64 std::unique_ptr<CrxUpdateItem> item = base::MakeUnique<CrxUpdateItem>(); | |
65 const CrxComponent& crx_component = crx_components[i]; | |
66 | |
67 item->id = GetCrxComponentID(crx_component); | |
68 item->component = crx_component; | |
69 item->last_check = base::TimeTicks::Now(); | |
70 item->crx_urls.clear(); | |
71 item->crx_diffurls.clear(); | |
72 item->previous_version = crx_component.version; | |
73 item->next_version = base::Version(); | |
74 item->previous_fp = crx_component.fingerprint; | |
75 item->next_fp.clear(); | |
76 item->on_demand = update_context->is_foreground; | |
77 item->diff_update_failed = false; | |
78 item->error_category = 0; | |
79 item->error_code = 0; | |
80 item->extra_code1 = 0; | |
81 item->diff_error_category = 0; | |
82 item->diff_error_code = 0; | |
83 item->diff_extra_code1 = 0; | |
84 item->download_metrics.clear(); | |
85 | |
86 CrxUpdateItem* item_ptr = item.get(); | |
87 update_context_->update_items[item_ptr->id] = std::move(item); | |
88 | |
89 ChangeItemState(item_ptr, CrxUpdateItem::State::kChecking); | |
90 } | |
91 | |
92 update_checker_->CheckForUpdates( | |
93 update_context_->update_items, extra_request_parameters_, | |
94 update_context_->enabled_component_updates, | |
95 base::Bind(&ActionUpdateCheck::UpdateCheckComplete, | |
96 base::Unretained(this))); | |
97 } | |
98 | |
99 void ActionUpdateCheck::UpdateCheckComplete( | |
100 int error, | |
101 const UpdateResponse::Results& results, | |
102 int retry_after_sec) { | |
103 DCHECK(thread_checker_.CalledOnValidThread()); | |
104 | |
105 update_context_->retry_after_sec = retry_after_sec; | |
106 | |
107 if (!error) | |
108 OnUpdateCheckSucceeded(results); | |
109 else | |
110 OnUpdateCheckFailed(error); | |
111 } | |
112 | |
113 void ActionUpdateCheck::OnUpdateCheckSucceeded( | |
114 const UpdateResponse::Results& results) { | |
115 DCHECK(thread_checker_.CalledOnValidThread()); | |
116 VLOG(1) << "Update check succeeded."; | |
117 | |
118 for (const auto& result : results.list) { | |
119 CrxUpdateItem* crx = FindUpdateItemById(result.extension_id); | |
120 if (!crx) { | |
121 VLOG(1) << "Component not found " << result.extension_id; | |
122 continue; | |
123 } | |
124 | |
125 DCHECK_EQ(CrxUpdateItem::State::kChecking, crx->state); | |
126 | |
127 if (result.status == "ok") | |
128 HandleUpdateCheckOK(result, crx); | |
129 else if (result.status == "noupdate") | |
130 HandleUpdateCheckNoupdate(result, crx); | |
131 else | |
132 HandleUpdateCheckError(result, crx); | |
133 } | |
134 | |
135 // All components that are not included in the update response are | |
136 // considered up to date. | |
137 ChangeAllItemsState(CrxUpdateItem::State::kChecking, | |
138 CrxUpdateItem::State::kUpToDate); | |
139 | |
140 if (update_context_->queue.empty()) { | |
141 VLOG(1) << "Update check completed but no action is needed."; | |
142 UpdateComplete(Error::NONE); | |
143 return; | |
144 } | |
145 | |
146 // Starts the execution flow of updating the CRXs in this context. | |
147 UpdateCrx(); | |
148 } | |
149 | |
150 void ActionUpdateCheck::HandleUpdateCheckOK( | |
151 const UpdateResponse::Result& result, | |
152 CrxUpdateItem* crx) { | |
153 DCHECK(thread_checker_.CalledOnValidThread()); | |
154 | |
155 const auto& manifest = result.manifest; | |
156 | |
157 if (manifest.version.empty()) { | |
158 // It can't update without a manifest version. | |
159 VLOG(1) << "No manifest version available for CRX: " << crx->id; | |
160 ChangeItemState(crx, CrxUpdateItem::State::kNoUpdate); | |
161 return; | |
162 } | |
163 | |
164 if (!IsVersionNewer(crx->component.version, manifest.version)) { | |
165 // The CRX is up to date. | |
166 VLOG(1) << "Component already up to date: " << crx->id; | |
167 ChangeItemState(crx, CrxUpdateItem::State::kUpToDate); | |
168 return; | |
169 } | |
170 | |
171 if (!manifest.browser_min_version.empty()) { | |
172 if (IsVersionNewer(browser_version_, manifest.browser_min_version)) { | |
173 // The CRX is not compatible with this Chrome version. | |
174 VLOG(1) << "Ignoring incompatible CRX: " << crx->id; | |
175 ChangeItemState(crx, CrxUpdateItem::State::kNoUpdate); | |
176 return; | |
177 } | |
178 } | |
179 | |
180 if (manifest.packages.size() != 1) { | |
181 // Assume one and only one package per CRX. | |
182 VLOG(1) << "Ignoring multiple packages for CRX: " << crx->id; | |
183 ChangeItemState(crx, CrxUpdateItem::State::kNoUpdate); | |
184 return; | |
185 } | |
186 | |
187 // Parse the members of the result and queue an upgrade for this CRX. | |
188 VLOG(1) << "Update found for CRX: " << crx->id; | |
189 | |
190 crx->next_version = base::Version(manifest.version); | |
191 const auto& package = manifest.packages.front(); | |
192 crx->next_fp = package.fingerprint; | |
193 | |
194 // Resolve the urls by combining the base urls with the package names. | |
195 for (const auto& crx_url : result.crx_urls) { | |
196 const GURL url = crx_url.Resolve(package.name); | |
197 if (url.is_valid()) | |
198 crx->crx_urls.push_back(url); | |
199 } | |
200 for (const auto& crx_diffurl : result.crx_diffurls) { | |
201 const GURL url = crx_diffurl.Resolve(package.namediff); | |
202 if (url.is_valid()) | |
203 crx->crx_diffurls.push_back(url); | |
204 } | |
205 | |
206 crx->hash_sha256 = package.hash_sha256; | |
207 crx->hashdiff_sha256 = package.hashdiff_sha256; | |
208 | |
209 ChangeItemState(crx, CrxUpdateItem::State::kCanUpdate); | |
210 | |
211 update_context_->queue.push(crx->id); | |
212 } | |
213 | |
214 void ActionUpdateCheck::HandleUpdateCheckNoupdate( | |
215 const UpdateResponse::Result& result, | |
216 CrxUpdateItem* crx) { | |
217 DCHECK(thread_checker_.CalledOnValidThread()); | |
218 VLOG(1) << "No update for CRX: " << crx->id; | |
219 ChangeItemState(crx, CrxUpdateItem::State::kNoUpdate); | |
220 } | |
221 | |
222 void ActionUpdateCheck::HandleUpdateCheckError( | |
223 const UpdateResponse::Result& result, | |
224 CrxUpdateItem* crx) { | |
225 DCHECK(thread_checker_.CalledOnValidThread()); | |
226 VLOG(1) << "Update error for CRX: " << crx->id << ", " << result.status; | |
227 ChangeItemState(crx, CrxUpdateItem::State::kNoUpdate); | |
228 } | |
229 | |
230 void ActionUpdateCheck::OnUpdateCheckFailed(int error) { | |
231 DCHECK(thread_checker_.CalledOnValidThread()); | |
232 DCHECK(error); | |
233 | |
234 VLOG(1) << "Update check failed." << error; | |
235 | |
236 ChangeAllItemsState(CrxUpdateItem::State::kChecking, | |
237 CrxUpdateItem::State::kNoUpdate); | |
238 | |
239 UpdateComplete(Error::UPDATE_CHECK_ERROR); | |
240 } | |
241 | |
242 } // namespace update_client | |
OLD | NEW |