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