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