update_engine.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  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. #include "components/update_client/update_engine.h"
  5. #include <algorithm>
  6. #include <memory>
  7. #include <string>
  8. #include <utility>
  9. #include "base/bind.h"
  10. #include "base/callback.h"
  11. #include "base/callback_helpers.h"
  12. #include "base/check_op.h"
  13. #include "base/guid.h"
  14. #include "base/location.h"
  15. #include "base/strings/strcat.h"
  16. #include "base/threading/thread_task_runner_handle.h"
  17. #include "components/prefs/pref_service.h"
  18. #include "components/update_client/component.h"
  19. #include "components/update_client/configurator.h"
  20. #include "components/update_client/crx_update_item.h"
  21. #include "components/update_client/persisted_data.h"
  22. #include "components/update_client/protocol_parser.h"
  23. #include "components/update_client/update_checker.h"
  24. #include "components/update_client/update_client.h"
  25. #include "components/update_client/update_client_errors.h"
  26. #include "components/update_client/utils.h"
  27. #include "third_party/abseil-cpp/absl/types/optional.h"
  28. namespace update_client {
  29. UpdateContext::UpdateContext(
  30. scoped_refptr<Configurator> config,
  31. bool is_foreground,
  32. bool is_install,
  33. const std::vector<std::string>& ids,
  34. UpdateClient::CrxStateChangeCallback crx_state_change_callback,
  35. const UpdateEngine::NotifyObserversCallback& notify_observers_callback,
  36. UpdateEngine::Callback callback,
  37. PersistedData* persisted_data)
  38. : config(config),
  39. is_foreground(is_foreground),
  40. is_install(is_install),
  41. ids(ids),
  42. crx_state_change_callback(crx_state_change_callback),
  43. notify_observers_callback(notify_observers_callback),
  44. callback(std::move(callback)),
  45. session_id(base::StrCat({"{", base::GenerateGUID(), "}"})),
  46. persisted_data(persisted_data) {
  47. for (const auto& id : ids) {
  48. components.insert(
  49. std::make_pair(id, std::make_unique<Component>(*this, id)));
  50. }
  51. }
  52. UpdateContext::~UpdateContext() = default;
  53. UpdateEngine::UpdateEngine(
  54. scoped_refptr<Configurator> config,
  55. UpdateChecker::Factory update_checker_factory,
  56. scoped_refptr<PingManager> ping_manager,
  57. const NotifyObserversCallback& notify_observers_callback)
  58. : config_(config),
  59. update_checker_factory_(update_checker_factory),
  60. ping_manager_(ping_manager),
  61. metadata_(
  62. std::make_unique<PersistedData>(config->GetPrefService(),
  63. config->GetActivityDataService())),
  64. notify_observers_callback_(notify_observers_callback) {}
  65. UpdateEngine::~UpdateEngine() {
  66. DCHECK(thread_checker_.CalledOnValidThread());
  67. }
  68. base::RepeatingClosure UpdateEngine::Update(
  69. bool is_foreground,
  70. bool is_install,
  71. const std::vector<std::string>& ids,
  72. UpdateClient::CrxDataCallback crx_data_callback,
  73. UpdateClient::CrxStateChangeCallback crx_state_change_callback,
  74. Callback callback) {
  75. DCHECK(thread_checker_.CalledOnValidThread());
  76. if (ids.empty()) {
  77. base::ThreadTaskRunnerHandle::Get()->PostTask(
  78. FROM_HERE,
  79. base::BindOnce(std::move(callback), Error::INVALID_ARGUMENT));
  80. return base::DoNothing();
  81. }
  82. if (IsThrottled(is_foreground)) {
  83. base::ThreadTaskRunnerHandle::Get()->PostTask(
  84. FROM_HERE, base::BindOnce(std::move(callback), Error::RETRY_LATER));
  85. return base::DoNothing();
  86. }
  87. // Calls out to get the corresponding CrxComponent data for the components.
  88. const std::vector<absl::optional<CrxComponent>> crx_components =
  89. std::move(crx_data_callback).Run(ids);
  90. if (crx_components.size() < ids.size()) {
  91. base::ThreadTaskRunnerHandle::Get()->PostTask(
  92. FROM_HERE,
  93. base::BindOnce(std::move(callback), Error::BAD_CRX_DATA_CALLBACK));
  94. return base::DoNothing();
  95. }
  96. const auto update_context = base::MakeRefCounted<UpdateContext>(
  97. config_, is_foreground, is_install, ids, crx_state_change_callback,
  98. notify_observers_callback_, std::move(callback), metadata_.get());
  99. DCHECK(!update_context->session_id.empty());
  100. const auto result = update_contexts_.insert(
  101. std::make_pair(update_context->session_id, update_context));
  102. DCHECK(result.second);
  103. for (size_t i = 0; i != update_context->ids.size(); ++i) {
  104. const auto& id = update_context->ids[i];
  105. DCHECK(update_context->components[id]->state() == ComponentState::kNew);
  106. const auto crx_component = crx_components[i];
  107. if (crx_component) {
  108. // This component can be checked for updates.
  109. DCHECK_EQ(id, GetCrxComponentID(*crx_component));
  110. auto& component = update_context->components[id];
  111. component->set_crx_component(*crx_component);
  112. component->set_previous_version(component->crx_component()->version);
  113. component->set_previous_fp(component->crx_component()->fingerprint);
  114. update_context->components_to_check_for_updates.push_back(id);
  115. } else {
  116. // |CrxDataCallback| did not return a CrxComponent instance for this
  117. // component, which most likely, has been uninstalled. This component
  118. // is going to be transitioned to an error state when the its |Handle|
  119. // method is called later on by the engine.
  120. update_context->component_queue.push(id);
  121. }
  122. }
  123. base::ThreadTaskRunnerHandle::Get()->PostTask(
  124. FROM_HERE,
  125. base::BindOnce(update_context->components_to_check_for_updates.empty()
  126. ? &UpdateEngine::HandleComponent
  127. : &UpdateEngine::DoUpdateCheck,
  128. this, update_context));
  129. return base::BindRepeating(
  130. [](scoped_refptr<UpdateContext> context) {
  131. context->is_cancelled = true;
  132. },
  133. update_context);
  134. }
  135. void UpdateEngine::DoUpdateCheck(scoped_refptr<UpdateContext> update_context) {
  136. DCHECK(thread_checker_.CalledOnValidThread());
  137. DCHECK(update_context);
  138. // Make the components transition from |kNew| to |kChecking| state.
  139. for (const auto& id : update_context->components_to_check_for_updates)
  140. update_context->components[id]->Handle(base::DoNothing());
  141. update_context->update_checker =
  142. update_checker_factory_(config_, metadata_.get());
  143. update_context->update_checker->CheckForUpdates(
  144. update_context, config_->ExtraRequestParams(),
  145. base::BindOnce(&UpdateEngine::UpdateCheckResultsAvailable, this,
  146. update_context));
  147. }
  148. void UpdateEngine::UpdateCheckResultsAvailable(
  149. scoped_refptr<UpdateContext> update_context,
  150. const absl::optional<ProtocolParser::Results>& results,
  151. ErrorCategory error_category,
  152. int error,
  153. int retry_after_sec) {
  154. DCHECK(thread_checker_.CalledOnValidThread());
  155. DCHECK(update_context);
  156. update_context->retry_after_sec = retry_after_sec;
  157. // Only positive values for throttle_sec are effective. 0 means that no
  158. // throttling occurs and it resets |throttle_updates_until_|.
  159. // Negative values are not trusted and are ignored.
  160. constexpr int kMaxRetryAfterSec = 24 * 60 * 60; // 24 hours.
  161. const int throttle_sec =
  162. std::min(update_context->retry_after_sec, kMaxRetryAfterSec);
  163. if (throttle_sec >= 0) {
  164. throttle_updates_until_ =
  165. throttle_sec ? base::TimeTicks::Now() + base::Seconds(throttle_sec)
  166. : base::TimeTicks();
  167. }
  168. update_context->update_check_error = error;
  169. if (error) {
  170. DCHECK(!results);
  171. for (const auto& id : update_context->components_to_check_for_updates) {
  172. DCHECK_EQ(1u, update_context->components.count(id));
  173. auto& component = update_context->components.at(id);
  174. component->SetUpdateCheckResult(absl::nullopt,
  175. ErrorCategory::kUpdateCheck, error);
  176. }
  177. base::ThreadTaskRunnerHandle::Get()->PostTask(
  178. FROM_HERE, base::BindOnce(&UpdateEngine::UpdateCheckComplete, this,
  179. update_context));
  180. return;
  181. }
  182. DCHECK(results);
  183. DCHECK_EQ(0, error);
  184. std::map<std::string, ProtocolParser::Result> id_to_result;
  185. for (const auto& result : results->list)
  186. id_to_result[result.extension_id] = result;
  187. for (const auto& id : update_context->components_to_check_for_updates) {
  188. DCHECK_EQ(1u, update_context->components.count(id));
  189. auto& component = update_context->components.at(id);
  190. const auto& it = id_to_result.find(id);
  191. if (it != id_to_result.end()) {
  192. const auto result = it->second;
  193. const auto pair = [](const std::string& status) {
  194. // First, handle app status literals which can be folded down as an
  195. // updatecheck status
  196. if (status == "error-unknownApplication")
  197. return std::make_pair(ErrorCategory::kUpdateCheck,
  198. ProtocolError::UNKNOWN_APPLICATION);
  199. if (status == "restricted")
  200. return std::make_pair(ErrorCategory::kUpdateCheck,
  201. ProtocolError::RESTRICTED_APPLICATION);
  202. if (status == "error-invalidAppId")
  203. return std::make_pair(ErrorCategory::kUpdateCheck,
  204. ProtocolError::INVALID_APPID);
  205. // If the parser has return a valid result and the status is not one of
  206. // the literals above, then this must be a success an not a parse error.
  207. return std::make_pair(ErrorCategory::kNone, ProtocolError::NONE);
  208. }(result.status);
  209. component->SetUpdateCheckResult(result, pair.first,
  210. static_cast<int>(pair.second));
  211. } else {
  212. component->SetUpdateCheckResult(
  213. absl::nullopt, ErrorCategory::kUpdateCheck,
  214. static_cast<int>(ProtocolError::UPDATE_RESPONSE_NOT_FOUND));
  215. }
  216. }
  217. base::ThreadTaskRunnerHandle::Get()->PostTask(
  218. FROM_HERE,
  219. base::BindOnce(&UpdateEngine::UpdateCheckComplete, this, update_context));
  220. }
  221. void UpdateEngine::UpdateCheckComplete(
  222. scoped_refptr<UpdateContext> update_context) {
  223. DCHECK(thread_checker_.CalledOnValidThread());
  224. DCHECK(update_context);
  225. for (const auto& id : update_context->components_to_check_for_updates) {
  226. update_context->component_queue.push(id);
  227. // Handle the |kChecking| state and transition the component to the
  228. // next state, depending on the update check results.
  229. DCHECK_EQ(1u, update_context->components.count(id));
  230. auto& component = update_context->components.at(id);
  231. DCHECK_EQ(component->state(), ComponentState::kChecking);
  232. component->Handle(base::DoNothing());
  233. }
  234. base::ThreadTaskRunnerHandle::Get()->PostTask(
  235. FROM_HERE,
  236. base::BindOnce(&UpdateEngine::HandleComponent, this, update_context));
  237. }
  238. void UpdateEngine::HandleComponent(
  239. scoped_refptr<UpdateContext> update_context) {
  240. DCHECK(thread_checker_.CalledOnValidThread());
  241. DCHECK(update_context);
  242. auto& queue = update_context->component_queue;
  243. if (queue.empty()) {
  244. const Error error = update_context->update_check_error
  245. ? Error::UPDATE_CHECK_ERROR
  246. : Error::NONE;
  247. base::ThreadTaskRunnerHandle::Get()->PostTask(
  248. FROM_HERE, base::BindOnce(&UpdateEngine::UpdateComplete, this,
  249. update_context, error));
  250. return;
  251. }
  252. const auto& id = queue.front();
  253. DCHECK_EQ(1u, update_context->components.count(id));
  254. const auto& component = update_context->components.at(id);
  255. DCHECK(component);
  256. auto& next_update_delay = update_context->next_update_delay;
  257. if (!next_update_delay.is_zero() && component->IsUpdateAvailable()) {
  258. base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
  259. FROM_HERE,
  260. base::BindOnce(&UpdateEngine::HandleComponent, this, update_context),
  261. next_update_delay);
  262. next_update_delay = base::TimeDelta();
  263. component->NotifyWait();
  264. return;
  265. }
  266. component->Handle(base::BindOnce(&UpdateEngine::HandleComponentComplete, this,
  267. update_context));
  268. }
  269. void UpdateEngine::HandleComponentComplete(
  270. scoped_refptr<UpdateContext> update_context) {
  271. DCHECK(thread_checker_.CalledOnValidThread());
  272. DCHECK(update_context);
  273. auto& queue = update_context->component_queue;
  274. DCHECK(!queue.empty());
  275. const auto& id = queue.front();
  276. DCHECK_EQ(1u, update_context->components.count(id));
  277. const auto& component = update_context->components.at(id);
  278. DCHECK(component);
  279. base::OnceClosure callback =
  280. base::BindOnce(&UpdateEngine::HandleComponent, this, update_context);
  281. if (component->IsHandled()) {
  282. update_context->next_update_delay = component->GetUpdateDuration();
  283. queue.pop();
  284. if (!component->events().empty()) {
  285. ping_manager_->SendPing(
  286. *component, *metadata_,
  287. base::BindOnce([](base::OnceClosure callback, int,
  288. const std::string&) { std::move(callback).Run(); },
  289. std::move(callback)));
  290. return;
  291. }
  292. }
  293. base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
  294. }
  295. void UpdateEngine::UpdateComplete(scoped_refptr<UpdateContext> update_context,
  296. Error error) {
  297. DCHECK(thread_checker_.CalledOnValidThread());
  298. DCHECK(update_context);
  299. const auto num_erased = update_contexts_.erase(update_context->session_id);
  300. DCHECK_EQ(1u, num_erased);
  301. base::ThreadTaskRunnerHandle::Get()->PostTask(
  302. FROM_HERE, base::BindOnce(std::move(update_context->callback), error));
  303. }
  304. bool UpdateEngine::GetUpdateState(const std::string& id,
  305. CrxUpdateItem* update_item) {
  306. DCHECK(thread_checker_.CalledOnValidThread());
  307. for (const auto& context : update_contexts_) {
  308. const auto& components = context.second->components;
  309. const auto it = components.find(id);
  310. if (it != components.end()) {
  311. *update_item = it->second->GetCrxUpdateItem();
  312. return true;
  313. }
  314. }
  315. return false;
  316. }
  317. bool UpdateEngine::IsThrottled(bool is_foreground) const {
  318. DCHECK(thread_checker_.CalledOnValidThread());
  319. if (is_foreground || throttle_updates_until_.is_null())
  320. return false;
  321. const auto now(base::TimeTicks::Now());
  322. // Throttle the calls in the interval (t - 1 day, t) to limit the effect of
  323. // unset clocks or clock drift.
  324. return throttle_updates_until_ - base::Days(1) < now &&
  325. now < throttle_updates_until_;
  326. }
  327. void UpdateEngine::SendUninstallPing(const CrxComponent& crx_component,
  328. int reason,
  329. Callback callback) {
  330. DCHECK(thread_checker_.CalledOnValidThread());
  331. const std::string& id = crx_component.app_id;
  332. const auto update_context = base::MakeRefCounted<UpdateContext>(
  333. config_, false, false, std::vector<std::string>{id},
  334. UpdateClient::CrxStateChangeCallback(),
  335. UpdateEngine::NotifyObserversCallback(), std::move(callback),
  336. metadata_.get());
  337. DCHECK(!update_context->session_id.empty());
  338. const auto result = update_contexts_.insert(
  339. std::make_pair(update_context->session_id, update_context));
  340. DCHECK(result.second);
  341. DCHECK(update_context);
  342. DCHECK_EQ(1u, update_context->ids.size());
  343. DCHECK_EQ(1u, update_context->components.count(id));
  344. const auto& component = update_context->components.at(id);
  345. component->Uninstall(crx_component, reason);
  346. update_context->component_queue.push(id);
  347. base::ThreadTaskRunnerHandle::Get()->PostTask(
  348. FROM_HERE,
  349. base::BindOnce(&UpdateEngine::HandleComponent, this, update_context));
  350. }
  351. } // namespace update_client