summaryrefslogtreecommitdiffstats
path: root/components/update_client/action_update_check.cc
blob: cfff7677253c2d06d6068418e769a56c369f0f20 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/update_client/action_update_check.h"

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/single_thread_task_runner.h"
#include "base/thread_task_runner_handle.h"
#include "base/version.h"
#include "components/update_client/action_update.h"
#include "components/update_client/configurator.h"
#include "components/update_client/update_checker.h"
#include "components/update_client/update_client.h"
#include "components/update_client/utils.h"

using std::string;
using std::vector;

namespace update_client {

namespace {

// Returns true if the |proposed| version is newer than |current| version.
bool IsVersionNewer(const Version& current, const std::string& proposed) {
  Version proposed_ver(proposed);
  return proposed_ver.IsValid() && current.CompareTo(proposed_ver) < 0;
}

}  // namespace

ActionUpdateCheck::ActionUpdateCheck(
    scoped_ptr<UpdateChecker> update_checker,
    const base::Version& browser_version,
    const std::string& extra_request_parameters)
    : update_checker_(update_checker.Pass()),
      browser_version_(browser_version),
      extra_request_parameters_(extra_request_parameters) {
}

ActionUpdateCheck::~ActionUpdateCheck() {
  DCHECK(thread_checker_.CalledOnValidThread());
}

void ActionUpdateCheck::Run(UpdateContext* update_context, Callback callback) {
  DCHECK(thread_checker_.CalledOnValidThread());

  ActionImpl::Run(update_context, callback);

  // Calls out to get the corresponding CrxComponent data for the CRXs in this
  // update context.
  vector<CrxComponent> crx_components;
  update_context_->crx_data_callback.Run(update_context_->ids, &crx_components);

  update_context_->update_items.reserve(crx_components.size());

  for (size_t i = 0; i != crx_components.size(); ++i) {
    scoped_ptr<CrxUpdateItem> item(new CrxUpdateItem);
    const CrxComponent& crx_component = crx_components[i];

    item->id = GetCrxComponentID(crx_component);
    item->component = crx_component;
    item->last_check = base::Time::Now();
    item->crx_urls.clear();
    item->crx_diffurls.clear();
    item->previous_version = crx_component.version;
    item->next_version = Version();
    item->previous_fp = crx_component.fingerprint;
    item->next_fp.clear();
    item->on_demand = update_context->is_foreground;
    item->diff_update_failed = false;
    item->error_category = 0;
    item->error_code = 0;
    item->extra_code1 = 0;
    item->diff_error_category = 0;
    item->diff_error_code = 0;
    item->diff_extra_code1 = 0;
    item->download_metrics.clear();

    update_context_->update_items.push_back(item.get());

    ChangeItemState(item.get(), CrxUpdateItem::State::kChecking);
    ignore_result(item.release());
  }

  update_checker_->CheckForUpdates(
      update_context_->update_items, extra_request_parameters_,
      base::Bind(&ActionUpdateCheck::UpdateCheckComplete,
                 base::Unretained(this)));
}

void ActionUpdateCheck::UpdateCheckComplete(
    const GURL& original_url,
    int error,
    const std::string& error_message,
    const UpdateResponse::Results& results) {
  DCHECK(thread_checker_.CalledOnValidThread());

  VLOG(1) << "Update check completed from: " << original_url.spec();

  if (!error)
    OnUpdateCheckSucceeded(results);
  else
    OnUpdateCheckFailed(error, error_message);
}

void ActionUpdateCheck::OnUpdateCheckSucceeded(
    const UpdateResponse::Results& results) {
  DCHECK(thread_checker_.CalledOnValidThread());
  VLOG(1) << "Update check succeeded.";
  std::vector<UpdateResponse::Result>::const_iterator it;
  for (it = results.list.begin(); it != results.list.end(); ++it) {
    CrxUpdateItem* crx = FindUpdateItemById(it->extension_id);
    if (!crx)
      continue;

    if (crx->state != CrxUpdateItem::State::kChecking) {
      NOTREACHED();
      continue;  // Not updating this CRX now.
    }

    if (it->manifest.version.empty()) {
      // No version means no update available.
      ChangeItemState(crx, CrxUpdateItem::State::kNoUpdate);
      VLOG(1) << "No update available for CRX: " << crx->id;
      continue;
    }

    if (!IsVersionNewer(crx->component.version, it->manifest.version)) {
      // The CRX is up to date.
      ChangeItemState(crx, CrxUpdateItem::State::kUpToDate);
      VLOG(1) << "Component already up-to-date: " << crx->id;
      continue;
    }

    if (!it->manifest.browser_min_version.empty()) {
      if (IsVersionNewer(browser_version_, it->manifest.browser_min_version)) {
        // The CRX is not compatible with this Chrome version.
        VLOG(1) << "Ignoring incompatible CRX: " << crx->id;
        ChangeItemState(crx, CrxUpdateItem::State::kNoUpdate);
        continue;
      }
    }

    if (it->manifest.packages.size() != 1) {
      // Assume one and only one package per CRX.
      VLOG(1) << "Ignoring multiple packages for CRX: " << crx->id;
      ChangeItemState(crx, CrxUpdateItem::State::kNoUpdate);
      continue;
    }

    // Parse the members of the result and queue an upgrade for this CRX.
    crx->next_version = Version(it->manifest.version);

    VLOG(1) << "Update found for CRX: " << crx->id;

    const auto& package(it->manifest.packages[0]);
    crx->next_fp = package.fingerprint;

    // Resolve the urls by combining the base urls with the package names.
    for (size_t i = 0; i != it->crx_urls.size(); ++i) {
      const GURL url(it->crx_urls[i].Resolve(package.name));
      if (url.is_valid())
        crx->crx_urls.push_back(url);
    }
    for (size_t i = 0; i != it->crx_diffurls.size(); ++i) {
      const GURL url(it->crx_diffurls[i].Resolve(package.namediff));
      if (url.is_valid())
        crx->crx_diffurls.push_back(url);
    }

    ChangeItemState(crx, CrxUpdateItem::State::kCanUpdate);

    update_context_->queue.push(crx->id);
  }

  // All components that are not included in the update response are
  // considered up to date.
  ChangeAllItemsState(CrxUpdateItem::State::kChecking,
                      CrxUpdateItem::State::kUpToDate);

  if (update_context_->queue.empty()) {
    VLOG(1) << "Update check completed but no update is needed.";
    UpdateComplete(0);
    return;
  }

  // Starts the execution flow of updating the CRXs in this context.
  UpdateCrx();
}

void ActionUpdateCheck::OnUpdateCheckFailed(int error,
                                            const std::string& error_message) {
  DCHECK(thread_checker_.CalledOnValidThread());
  DCHECK(error);

  VLOG(1) << "Update check failed." << error;

  ChangeAllItemsState(CrxUpdateItem::State::kChecking,
                      CrxUpdateItem::State::kNoUpdate);

  UpdateComplete(error);
}

}  // namespace update_client