1 // Copyright 2014 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/update_client.h"
6
7 #include <algorithm>
8 #include <queue>
9 #include <set>
10 #include <utility>
11 #include <vector>
12
13 #include "base/bind.h"
14 #include "base/callback.h"
15 #include "base/check_op.h"
16 #include "base/location.h"
17 #include "base/macros.h"
18 #include "base/observer_list.h"
19 #include "base/stl_util.h"
20 #include "base/threading/thread_checker.h"
21 #include "base/threading/thread_task_runner_handle.h"
22 #include "components/crx_file/crx_verifier.h"
23 #include "components/prefs/pref_registry_simple.h"
24 #include "components/update_client/configurator.h"
25 #include "components/update_client/crx_update_item.h"
26 #include "components/update_client/persisted_data.h"
27 #include "components/update_client/ping_manager.h"
28 #include "components/update_client/protocol_parser.h"
29 #include "components/update_client/task_send_registration_ping.h"
30 #include "components/update_client/task_send_uninstall_ping.h"
31 #include "components/update_client/task_update.h"
32 #include "components/update_client/update_checker.h"
33 #include "components/update_client/update_client_errors.h"
34 #include "components/update_client/update_client_internal.h"
35 #include "components/update_client/update_engine.h"
36 #include "components/update_client/utils.h"
37 #include "url/gurl.h"
38
39 namespace update_client {
40
InstallParams(const std::string & run,const std::string & arguments)41 CrxInstaller::InstallParams::InstallParams(const std::string& run,
42 const std::string& arguments)
43 : run(run), arguments(arguments) {}
44
CrxUpdateItem()45 CrxUpdateItem::CrxUpdateItem() : state(ComponentState::kNew) {}
46 CrxUpdateItem::~CrxUpdateItem() = default;
47 CrxUpdateItem::CrxUpdateItem(const CrxUpdateItem& other) = default;
48
CrxComponent()49 CrxComponent::CrxComponent()
50 : allows_background_download(true),
51 requires_network_encryption(true),
52 crx_format_requirement(
53 crx_file::VerifierFormat::CRX3_WITH_PUBLISHER_PROOF),
54 supports_group_policy_enable_component_updates(false) {}
55 CrxComponent::CrxComponent(const CrxComponent& other) = default;
56 CrxComponent::~CrxComponent() = default;
57
58 // It is important that an instance of the UpdateClient binds an unretained
59 // pointer to itself. Otherwise, a life time circular dependency between this
60 // instance and its inner members prevents the destruction of this instance.
61 // Using unretained references is allowed in this case since the life time of
62 // the UpdateClient instance exceeds the life time of its inner members,
63 // including any thread objects that might execute callbacks bound to it.
UpdateClientImpl(scoped_refptr<Configurator> config,scoped_refptr<PingManager> ping_manager,UpdateChecker::Factory update_checker_factory)64 UpdateClientImpl::UpdateClientImpl(
65 scoped_refptr<Configurator> config,
66 scoped_refptr<PingManager> ping_manager,
67 UpdateChecker::Factory update_checker_factory)
68 : config_(config),
69 ping_manager_(ping_manager),
70 update_engine_(base::MakeRefCounted<UpdateEngine>(
71 config,
72 update_checker_factory,
73 ping_manager_.get(),
74 base::BindRepeating(&UpdateClientImpl::NotifyObservers,
75 base::Unretained(this)))) {}
76
~UpdateClientImpl()77 UpdateClientImpl::~UpdateClientImpl() {
78 DCHECK(thread_checker_.CalledOnValidThread());
79
80 DCHECK(task_queue_.empty());
81 DCHECK(tasks_.empty());
82
83 config_ = nullptr;
84 }
85
Install(const std::string & id,CrxDataCallback crx_data_callback,CrxStateChangeCallback crx_state_change_callback,Callback callback)86 void UpdateClientImpl::Install(const std::string& id,
87 CrxDataCallback crx_data_callback,
88 CrxStateChangeCallback crx_state_change_callback,
89 Callback callback) {
90 DCHECK(thread_checker_.CalledOnValidThread());
91
92 if (IsUpdating(id)) {
93 std::move(callback).Run(Error::UPDATE_IN_PROGRESS);
94 return;
95 }
96
97 std::vector<std::string> ids = {id};
98
99 // Install tasks are run concurrently and never queued up. They are always
100 // considered foreground tasks.
101 constexpr bool kIsForeground = true;
102 RunTask(base::MakeRefCounted<TaskUpdate>(
103 update_engine_.get(), kIsForeground, ids, std::move(crx_data_callback),
104 crx_state_change_callback,
105 base::BindOnce(&UpdateClientImpl::OnTaskComplete, this,
106 std::move(callback))));
107 }
108
Update(const std::vector<std::string> & ids,CrxDataCallback crx_data_callback,CrxStateChangeCallback crx_state_change_callback,bool is_foreground,Callback callback)109 void UpdateClientImpl::Update(const std::vector<std::string>& ids,
110 CrxDataCallback crx_data_callback,
111 CrxStateChangeCallback crx_state_change_callback,
112 bool is_foreground,
113 Callback callback) {
114 DCHECK(thread_checker_.CalledOnValidThread());
115
116 auto task = base::MakeRefCounted<TaskUpdate>(
117 update_engine_.get(), is_foreground, ids, std::move(crx_data_callback),
118 crx_state_change_callback,
119 base::BindOnce(&UpdateClientImpl::OnTaskComplete, this,
120 std::move(callback)));
121
122 // If no other tasks are running at the moment, run this update task.
123 // Otherwise, queue the task up.
124 if (tasks_.empty()) {
125 RunTask(task);
126 } else {
127 task_queue_.push_back(task);
128 }
129 }
130
RunTask(scoped_refptr<Task> task)131 void UpdateClientImpl::RunTask(scoped_refptr<Task> task) {
132 DCHECK(thread_checker_.CalledOnValidThread());
133 base::ThreadTaskRunnerHandle::Get()->PostTask(
134 FROM_HERE, base::BindOnce(&Task::Run, base::Unretained(task.get())));
135 tasks_.insert(task);
136 }
137
OnTaskComplete(Callback callback,scoped_refptr<Task> task,Error error)138 void UpdateClientImpl::OnTaskComplete(Callback callback,
139 scoped_refptr<Task> task,
140 Error error) {
141 DCHECK(thread_checker_.CalledOnValidThread());
142 DCHECK(task);
143
144 base::ThreadTaskRunnerHandle::Get()->PostTask(
145 FROM_HERE, base::BindOnce(std::move(callback), error));
146
147 // Remove the task from the set of the running tasks. Only tasks handled by
148 // the update engine can be in this data structure.
149 DCHECK_EQ(1u, tasks_.count(task));
150 tasks_.erase(task);
151
152 if (is_stopped_)
153 return;
154
155 // Pick up a task from the queue if the queue has pending tasks and no other
156 // task is running.
157 if (tasks_.empty() && !task_queue_.empty()) {
158 auto task = task_queue_.front();
159 task_queue_.pop_front();
160 RunTask(task);
161 }
162 }
163
AddObserver(Observer * observer)164 void UpdateClientImpl::AddObserver(Observer* observer) {
165 DCHECK(thread_checker_.CalledOnValidThread());
166 observer_list_.AddObserver(observer);
167 }
168
RemoveObserver(Observer * observer)169 void UpdateClientImpl::RemoveObserver(Observer* observer) {
170 DCHECK(thread_checker_.CalledOnValidThread());
171 observer_list_.RemoveObserver(observer);
172 }
173
NotifyObservers(Observer::Events event,const std::string & id)174 void UpdateClientImpl::NotifyObservers(Observer::Events event,
175 const std::string& id) {
176 DCHECK(thread_checker_.CalledOnValidThread());
177 for (auto& observer : observer_list_)
178 observer.OnEvent(event, id);
179 }
180
GetCrxUpdateState(const std::string & id,CrxUpdateItem * update_item) const181 bool UpdateClientImpl::GetCrxUpdateState(const std::string& id,
182 CrxUpdateItem* update_item) const {
183 return update_engine_->GetUpdateState(id, update_item);
184 }
185
IsUpdating(const std::string & id) const186 bool UpdateClientImpl::IsUpdating(const std::string& id) const {
187 DCHECK(thread_checker_.CalledOnValidThread());
188
189 for (const auto& task : tasks_) {
190 const auto ids = task->GetIds();
191 if (base::Contains(ids, id)) {
192 return true;
193 }
194 }
195
196 for (const auto& task : task_queue_) {
197 const auto ids = task->GetIds();
198 if (base::Contains(ids, id)) {
199 return true;
200 }
201 }
202
203 return false;
204 }
205
Stop()206 void UpdateClientImpl::Stop() {
207 DCHECK(thread_checker_.CalledOnValidThread());
208
209 is_stopped_ = true;
210
211 // In the current implementation it is sufficient to cancel the pending
212 // tasks only. The tasks that are run by the update engine will stop
213 // making progress naturally, as the main task runner stops running task
214 // actions. Upon the browser shutdown, the resources employed by the active
215 // tasks will leak, as the operating system kills the thread associated with
216 // the update engine task runner. Further refactoring may be needed in this
217 // area, to cancel the running tasks by canceling the current action update.
218 // This behavior would be expected, correct, and result in no resource leaks
219 // in all cases, in shutdown or not.
220 //
221 // Cancel the pending tasks. These tasks are safe to cancel and delete since
222 // they have not picked up by the update engine, and not shared with any
223 // task runner yet.
224 while (!task_queue_.empty()) {
225 auto task = task_queue_.front();
226 task_queue_.pop_front();
227 task->Cancel();
228 }
229 }
230
SendUninstallPing(const std::string & id,const base::Version & version,int reason,Callback callback)231 void UpdateClientImpl::SendUninstallPing(const std::string& id,
232 const base::Version& version,
233 int reason,
234 Callback callback) {
235 DCHECK(thread_checker_.CalledOnValidThread());
236
237 RunTask(base::MakeRefCounted<TaskSendUninstallPing>(
238 update_engine_.get(), id, version, reason,
239 base::BindOnce(&UpdateClientImpl::OnTaskComplete, this,
240 std::move(callback))));
241 }
242
SendRegistrationPing(const std::string & id,const base::Version & version,Callback callback)243 void UpdateClientImpl::SendRegistrationPing(const std::string& id,
244 const base::Version& version,
245 Callback callback) {
246 DCHECK(thread_checker_.CalledOnValidThread());
247
248 RunTask(base::MakeRefCounted<TaskSendRegistrationPing>(
249 update_engine_.get(), id, version,
250 base::BindOnce(&UpdateClientImpl::OnTaskComplete, this,
251 std::move(callback))));
252 }
253
UpdateClientFactory(scoped_refptr<Configurator> config)254 scoped_refptr<UpdateClient> UpdateClientFactory(
255 scoped_refptr<Configurator> config) {
256 return base::MakeRefCounted<UpdateClientImpl>(
257 config, base::MakeRefCounted<PingManager>(config),
258 &UpdateChecker::Create);
259 }
260
RegisterPrefs(PrefRegistrySimple * registry)261 void RegisterPrefs(PrefRegistrySimple* registry) {
262 PersistedData::RegisterPrefs(registry);
263 }
264
265 // This function has the exact same implementation as RegisterPrefs. We have
266 // this implementation here to make the intention more clear that is local user
267 // profile access is needed.
RegisterProfilePrefs(PrefRegistrySimple * registry)268 void RegisterProfilePrefs(PrefRegistrySimple* registry) {
269 PersistedData::RegisterPrefs(registry);
270 }
271
272 } // namespace update_client
273