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