Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(167)

Side by Side Diff: chrome/browser/component_updater/component_updater_service.cc

Issue 15908002: Differential updates for components. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/component_updater/component_updater_service.h" 5 #include "chrome/browser/component_updater/component_updater_service.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <set> 8 #include <set>
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/at_exit.h" 11 #include "base/at_exit.h"
12 #include "base/bind.h" 12 #include "base/bind.h"
13 #include "base/file_util.h" 13 #include "base/file_util.h"
14 #include "base/files/file_path.h" 14 #include "base/files/file_path.h"
15 #include "base/guid.h"
15 #include "base/logging.h" 16 #include "base/logging.h"
16 #include "base/memory/scoped_ptr.h" 17 #include "base/memory/scoped_ptr.h"
17 #include "base/stl_util.h" 18 #include "base/stl_util.h"
18 #include "base/string_util.h" 19 #include "base/string_util.h"
19 #include "base/stringprintf.h" 20 #include "base/stringprintf.h"
20 #include "base/strings/string_number_conversions.h" 21 #include "base/strings/string_number_conversions.h"
21 #include "base/strings/string_piece.h" 22 #include "base/strings/string_piece.h"
23 #include "base/sys_info.h"
22 #include "base/timer.h" 24 #include "base/timer.h"
23 #include "chrome/browser/browser_process.h" 25 #include "chrome/browser/browser_process.h"
26 #include "chrome/browser/component_updater/component_patcher.h"
24 #include "chrome/browser/component_updater/component_unpacker.h" 27 #include "chrome/browser/component_updater/component_unpacker.h"
25 #include "chrome/common/chrome_notification_types.h" 28 #include "chrome/common/chrome_notification_types.h"
26 #include "chrome/common/chrome_utility_messages.h" 29 #include "chrome/common/chrome_utility_messages.h"
27 #include "chrome/common/chrome_version_info.h" 30 #include "chrome/common/chrome_version_info.h"
28 #include "chrome/common/extensions/extension.h" 31 #include "chrome/common/extensions/extension.h"
32 #include "chrome/common/omaha_query_params/omaha_query_params.h"
29 #include "content/public/browser/browser_thread.h" 33 #include "content/public/browser/browser_thread.h"
30 #include "content/public/browser/notification_service.h" 34 #include "content/public/browser/notification_service.h"
31 #include "content/public/browser/utility_process_host.h" 35 #include "content/public/browser/utility_process_host.h"
32 #include "content/public/browser/utility_process_host_client.h" 36 #include "content/public/browser/utility_process_host_client.h"
33 #include "googleurl/src/gurl.h" 37 #include "googleurl/src/gurl.h"
34 #include "net/base/escape.h" 38 #include "net/base/escape.h"
35 #include "net/base/load_flags.h" 39 #include "net/base/load_flags.h"
36 #include "net/base/net_errors.h" 40 #include "net/base/net_errors.h"
37 #include "net/url_request/url_fetcher.h" 41 #include "net/url_request/url_fetcher.h"
38 #include "net/url_request/url_fetcher_delegate.h" 42 #include "net/url_request/url_fetcher_delegate.h"
39 #include "net/url_request/url_request_status.h" 43 #include "net/url_request/url_request_status.h"
40 44
41 using content::BrowserThread; 45 using content::BrowserThread;
42 using content::UtilityProcessHost; 46 using content::UtilityProcessHost;
43 using content::UtilityProcessHostClient; 47 using content::UtilityProcessHostClient;
44 using extensions::Extension; 48 using extensions::Extension;
45 49
46 // The component updater is designed to live until process shutdown, so 50 // The component updater is designed to live until process shutdown, so
47 // base::Bind() calls are not refcounted. 51 // base::Bind() calls are not refcounted.
48 52
49 namespace { 53 namespace {
54
55 typedef ComponentUpdateService::Configurator Config;
56
50 // Manifest sources, from most important to least important. 57 // Manifest sources, from most important to least important.
51 const CrxComponent::UrlSource kManifestSources[] = { 58 const CrxComponent::UrlSource kManifestSources[] = {
52 CrxComponent::BANDAID, 59 CrxComponent::BANDAID,
53 CrxComponent::CWS_PUBLIC, 60 CrxComponent::CWS_PUBLIC,
54 CrxComponent::CWS_SANDBOX 61 CrxComponent::CWS_SANDBOX,
55 }; 62 };
56 63
57 // Extends an omaha compatible update check url |query| string. Does 64 // Extends an omaha compatible update check url |query| string. Does
58 // not mutate the string if it would be longer than |limit| chars. 65 // not mutate the string if it would be longer than |limit| chars.
59 bool AddQueryString(const std::string& id, 66 bool AddQueryString(const std::string& id,
60 const std::string& version, 67 const std::string& version,
68 const std::string& fingerprint,
61 size_t limit, 69 size_t limit,
62 std::string* query) { 70 std::string* query) {
63 std::string additional = 71 std::string additional =
64 base::StringPrintf("id=%s&v=%s&uc", id.c_str(), version.c_str()); 72 base::StringPrintf("id=%s&v=%s&fp=%s&uc",
73 id.c_str(), version.c_str(), fingerprint.c_str());
65 additional = "x=" + net::EscapeQueryParamValue(additional, true); 74 additional = "x=" + net::EscapeQueryParamValue(additional, true);
66 if ((additional.size() + query->size() + 1) > limit) 75 if ((additional.size() + query->size() + 1) > limit)
67 return false; 76 return false;
68 if (!query->empty()) 77 if (!query->empty())
69 query->append(1, '&'); 78 query->append(1, '&');
70 query->append(additional); 79 query->append(additional);
71 return true; 80 return true;
72 } 81 }
73 82
74 // Create the final omaha compatible query. The |extra| is optional and can 83 // Create the final omaha compatible query. The |extra| is optional and can
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
156 net::LOAD_DISABLE_CACHE); 165 net::LOAD_DISABLE_CACHE);
157 // TODO(cpu): Define our retry and backoff policy. 166 // TODO(cpu): Define our retry and backoff policy.
158 fetcher->SetAutomaticallyRetryOn5xx(false); 167 fetcher->SetAutomaticallyRetryOn5xx(false);
159 if (save_to_file) { 168 if (save_to_file) {
160 fetcher->SaveResponseToTemporaryFile( 169 fetcher->SaveResponseToTemporaryFile(
161 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)); 170 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
162 } 171 }
163 fetcher->Start(); 172 fetcher->Start();
164 } 173 }
165 174
166 // Returs true if the url request of |fetcher| was succesful. 175 // Returns true if the url request of |fetcher| was succesful.
167 bool FetchSuccess(const net::URLFetcher& fetcher) { 176 bool FetchSuccess(const net::URLFetcher& fetcher) {
168 return (fetcher.GetStatus().status() == net::URLRequestStatus::SUCCESS) && 177 return (fetcher.GetStatus().status() == net::URLRequestStatus::SUCCESS) &&
169 (fetcher.GetResponseCode() == 200); 178 (fetcher.GetResponseCode() == 200);
170 } 179 }
171 180
181 // Returns the error code which occured during the fetch. This function
182 // is intended to be called for logging purposes only, since it folds different
183 // types of errors to fit them in the returned type. The function returns 0 if
184 // the fetch was successful. If errors happen, the function could return a
185 // network error, an http response code, or the status of the fetch, if the
186 // fetch is pending or canceled.
187 int GetFetchError(const net::URLFetcher& fetcher) {
188 if (FetchSuccess(fetcher))
189 return 0;
190
191 const net::URLRequestStatus::Status status(fetcher.GetStatus().status());
192 if (status == net::URLRequestStatus::FAILED)
193 return fetcher.GetStatus().error();
194
195 if (status == net::URLRequestStatus::IO_PENDING ||
196 status == net::URLRequestStatus::CANCELED)
197 return status;
198
199 const int response_code(fetcher.GetResponseCode());
200 if (status == net::URLRequestStatus::SUCCESS && response_code != 200)
201 return response_code;
202
203 return -1;
204 }
205
206
172 // This is the one and only per-item state structure. Designed to be hosted 207 // This is the one and only per-item state structure. Designed to be hosted
173 // in a std::vector or a std::list. The two main members are |component| 208 // in a std::vector or a std::list. The two main members are |component|
174 // which is supplied by the the component updater client and |status| which 209 // which is supplied by the the component updater client and |status| which
175 // is modified as the item is processed by the update pipeline. The expected 210 // is modified as the item is processed by the update pipeline. The expected
176 // transition graph is: 211 // transition graph is:
177 // error error error 212 //
178 // +--kNoUpdate<------<-------+------<------+------<------+ 213 // kNew
179 // | | | | 214 // |
180 // V yes | | | 215 // V
181 // kNew --->kChecking-->[update?]----->kCanUpdate-->kDownloading-->kUpdating 216 // +----------------------> kChecking -<---------+-----<-------+
182 // ^ | | 217 // | | | |
183 // | |no | 218 // | V no | |
184 // |--kUpToDate<---+ | 219 // kNoUpdate [update?] ->---- kUpToDate kUpdated
185 // | success | 220 // ^ | ^
186 // +--kUpdated<-------------------------------------------+ 221 // | yes | |
222 // | diff=false V |
223 // | +-----------> kCanUpdate |
224 // | | | |
225 // | | V no |
226 // | | [differential update?]->----+ |
227 // | | | | |
228 // | | yes | | |
229 // | | error V | |
230 // | +---------<- kDownloadingDiff | |
231 // | | | | |
232 // | | | | |
233 // | | error V | |
234 // | +---------<- kUpdatingDiff ->--------|-----------+ success
235 // | | |
236 // | error V |
237 // +----------------------------------------- kDownloading |
238 // | | |
239 // | error V |
240 // +------------------------------------------ kUpdating ->----+ success
187 // 241 //
188 struct CrxUpdateItem { 242 struct CrxUpdateItem {
189 enum Status { 243 enum Status {
190 kNew, 244 kNew,
191 kChecking, 245 kChecking,
192 kCanUpdate, 246 kCanUpdate,
247 kDownloadingDiff,
193 kDownloading, 248 kDownloading,
249 kUpdatingDiff,
194 kUpdating, 250 kUpdating,
195 kUpdated, 251 kUpdated,
196 kUpToDate, 252 kUpToDate,
197 kNoUpdate, 253 kNoUpdate,
198 kLastStatus 254 kLastStatus
199 }; 255 };
200 256
201 Status status; 257 Status status;
258 std::string id;
259 CrxComponent component;
260
261 base::Time last_check;
262
263 // True if the update response includes an update for this component.
264 bool is_update_available;
265
266 // True is a completion ping has been queued for this component. If an update
267 // is available for this component, one completion ping must be sent
268 // after the component has reached either the kNoUpdate or kUpdated states.
269 bool ping_queued;
270
271 // These members are initialized with their corresponding values from the
272 // update server response.
202 GURL crx_url; 273 GURL crx_url;
203 std::string id; 274 GURL diff_crx_url;
204 base::Time last_check; 275 std::string package_hash;
205 CrxComponent component; 276 std::string diff_package_hash;
277 int size;
278 int diff_size;
279
280 // The from/to version and fingerprint values.
281 Version previous_version;
206 Version next_version; 282 Version next_version;
283 std::string previous_fp;
284 std::string next_fp;
207 285
208 CrxUpdateItem() : status(kNew) {} 286 // True if the differential update failed for any reason.
287 bool diff_update_failed;
288
289 // The error information for full and differential updates.
290 int error_code;
291 int extra_code1;
292 int diff_error_code;
293 int diff_extra_code1;
294
295 CrxUpdateItem()
296 : status(kNew),
297 is_update_available(false),
298 ping_queued(false),
299 size(0),
300 diff_size(0),
301 diff_update_failed(false),
302 error_code(0),
303 extra_code1(0),
304 diff_error_code(0),
305 diff_extra_code1(0) {
306 }
209 307
210 // Function object used to find a specific component. 308 // Function object used to find a specific component.
211 class FindById { 309 class FindById {
212 public: 310 public:
213 explicit FindById(const std::string& id) : id_(id) {} 311 explicit FindById(const std::string& id) : id_(id) {}
214 312
215 bool operator() (CrxUpdateItem* item) const { 313 bool operator() (CrxUpdateItem* item) const {
216 return (item->id == id_); 314 return (item->id == id_);
217 } 315 }
218 private: 316 private:
219 const std::string& id_; 317 const std::string& id_;
220 }; 318 };
221 }; 319 };
222 320
321 // Returns true if a differential update is available for the update item.
322 bool IsDiffUpdateAvailable(const CrxUpdateItem* update_item) {
323 return update_item->diff_crx_url.is_valid();
324 }
325
326 // Returns true if a differential update is available, it has not failed yet,
327 // and the configuration allows it.
328 bool CanTryDiffUpdate(const CrxUpdateItem* update_item, const Config& config) {
329 return IsDiffUpdateAvailable(update_item) &&
330 !update_item->diff_update_failed &&
331 config.DeltasEnabled();
332 }
333
223 } // namespace. 334 } // namespace.
224 335
225 typedef ComponentUpdateService::Configurator Config;
226
227 CrxComponent::CrxComponent() 336 CrxComponent::CrxComponent()
228 : installer(NULL), 337 : installer(NULL),
229 source(BANDAID) { 338 source(BANDAID) {
230 } 339 }
231 340
232 CrxComponent::~CrxComponent() { 341 CrxComponent::~CrxComponent() {
233 } 342 }
234 343
235 ////////////////////////////////////////////////////////////////////////////// 344 //////////////////////////////////////////////////////////////////////////////
236 // The one and only implementation of the ComponentUpdateService interface. In 345 // The one and only implementation of the ComponentUpdateService interface. In
237 // charge of running the show. The main method is ProcessPendingItems() which 346 // charge of running the show. The main method is ProcessPendingItems() which
238 // is called periodically to do the upgrades/installs or the update checks. 347 // is called periodically to do the upgrades/installs or the update checks.
239 // An important consideration here is to be as "low impact" as we can to the 348 // An important consideration here is to be as "low impact" as we can to the
240 // rest of the browser, so even if we have many components registered and 349 // rest of the browser, so even if we have many components registered and
241 // eligible for update, we only do one thing at a time with pauses in between 350 // eligible for update, we only do one thing at a time with pauses in between
242 // the tasks. Also when we do network requests there is only one |url_fetcher_| 351 // the tasks. Also when we do network requests there is only one |url_fetcher_|
243 // in flight at at a time. 352 // in flight at a time.
244 // There are no locks in this code, the main structure |work_items_| is mutated 353 // There are no locks in this code, the main structure |work_items_| is mutated
245 // only from the UI thread. The unpack and installation is done in the file 354 // only from the UI thread. The unpack and installation is done in the file
246 // thread and the network requests are done in the IO thread and in the file 355 // thread and the network requests are done in the IO thread and in the file
247 // thread. 356 // thread.
248 class CrxUpdateService : public ComponentUpdateService { 357 class CrxUpdateService : public ComponentUpdateService {
249 public: 358 public:
250 explicit CrxUpdateService(ComponentUpdateService::Configurator* config); 359 explicit CrxUpdateService(ComponentUpdateService::Configurator* config);
251 360
252 virtual ~CrxUpdateService(); 361 virtual ~CrxUpdateService();
253 362
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
292 CrxUpdateService* service_; 401 CrxUpdateService* service_;
293 DISALLOW_COPY_AND_ASSIGN(ManifestParserBridge); 402 DISALLOW_COPY_AND_ASSIGN(ManifestParserBridge);
294 }; 403 };
295 404
296 // Context for a update check url request. See DelegateWithContext above. 405 // Context for a update check url request. See DelegateWithContext above.
297 struct UpdateContext { 406 struct UpdateContext {
298 base::Time start; 407 base::Time start;
299 UpdateContext() : start(base::Time::Now()) {} 408 UpdateContext() : start(base::Time::Now()) {}
300 }; 409 };
301 410
411 // Context for a completion ping.
412 struct PingContext {
413 };
414
302 // Context for a crx download url request. See DelegateWithContext above. 415 // Context for a crx download url request. See DelegateWithContext above.
303 struct CRXContext { 416 struct CRXContext {
304 ComponentInstaller* installer; 417 ComponentInstaller* installer;
305 std::vector<uint8> pk_hash; 418 std::vector<uint8> pk_hash;
306 std::string id; 419 std::string id;
420 std::string fingerprint;
307 CRXContext() : installer(NULL) {} 421 CRXContext() : installer(NULL) {}
308 }; 422 };
309 423
310 void OnURLFetchComplete(const net::URLFetcher* source, 424 void OnURLFetchComplete(const net::URLFetcher* source,
311 UpdateContext* context); 425 UpdateContext* context);
312 426
313 void OnURLFetchComplete(const net::URLFetcher* source, 427 void OnURLFetchComplete(const net::URLFetcher* source,
314 CRXContext* context); 428 CRXContext* context);
315 429
430 void OnURLFetchComplete(const net::URLFetcher* source,
431 PingContext* context);
432
316 private: 433 private:
317 // See ManifestParserBridge. 434 // See ManifestParserBridge.
318 void OnParseUpdateManifestSucceeded( 435 void OnParseUpdateManifestSucceeded(
319 const UpdateManifest::Results& results); 436 const UpdateManifest::Results& results);
320 437
321 // See ManifestParserBridge. 438 // See ManifestParserBridge.
322 void OnParseUpdateManifestFailed( 439 void OnParseUpdateManifestFailed(const std::string& error_message);
323 const std::string& error_message);
324 440
325 bool AddItemToUpdateCheck(CrxUpdateItem* item, std::string* query); 441 bool AddItemToUpdateCheck(CrxUpdateItem* item, std::string* query);
326 442
327 void ProcessPendingItems(); 443 void ProcessPendingItems();
328 444
329 void ScheduleNextRun(bool step_delay); 445 void ScheduleNextRun(bool step_delay);
330 446
331 void ParseManifest(const std::string& xml); 447 void ParseManifest(const std::string& xml);
332 448
333 void Install(const CRXContext* context, const base::FilePath& crx_path); 449 void Install(const CRXContext* context, const base::FilePath& crx_path);
334 450
335 void DoneInstalling(const std::string& component_id, 451 void DoneInstalling(const std::string& component_id,
336 ComponentUnpacker::Error error); 452 ComponentUnpacker::Error error,
453 int extended_error);
337 454
338 size_t ChangeItemStatus(CrxUpdateItem::Status from, 455 size_t ChangeItemStatus(CrxUpdateItem::Status from,
339 CrxUpdateItem::Status to); 456 CrxUpdateItem::Status to);
340 457
341 CrxUpdateItem* FindUpdateItemById(const std::string& id); 458 CrxUpdateItem* FindUpdateItemById(const std::string& id);
342 459
460 void SendPing(const std::string& ping);
461
462 // These functions build a ping request. Building the ping changes the state
463 // of the update item to indicate that a completion ping has been collected
464 // and queued for this item.
465 std::string BuildPing() const;
466 std::string BuildPingApps() const;
467 static std::string BuildPingEvent(CrxUpdateItem* item);
468
343 scoped_ptr<Config> config_; 469 scoped_ptr<Config> config_;
344 470
471 scoped_ptr<ComponentPatcher> component_patcher_;
472
345 scoped_ptr<net::URLFetcher> url_fetcher_; 473 scoped_ptr<net::URLFetcher> url_fetcher_;
346 474
475 scoped_ptr<net::URLFetcher> ping_sender_;
476
477 // A collection of every work item.
347 typedef std::vector<CrxUpdateItem*> UpdateItems; 478 typedef std::vector<CrxUpdateItem*> UpdateItems;
348 // A collection of every work item.
349 UpdateItems work_items_; 479 UpdateItems work_items_;
350 480
351 // A particular set of items from work_items_, which should be checked ASAP. 481 // A particular set of items from work_items_, which should be checked ASAP.
352 std::set<CrxUpdateItem*> requested_work_items_; 482 std::set<CrxUpdateItem*> requested_work_items_;
353 483
354 base::OneShotTimer<CrxUpdateService> timer_; 484 base::OneShotTimer<CrxUpdateService> timer_;
355 485
356 Version chrome_version_; 486 const Version chrome_version_;
487 const std::string prod_id_;
488 const std::string os_type_;
489 const std::string os_version_;
357 490
358 bool running_; 491 bool running_;
359 492
360 DISALLOW_COPY_AND_ASSIGN(CrxUpdateService); 493 DISALLOW_COPY_AND_ASSIGN(CrxUpdateService);
361 }; 494 };
362 495
363 ////////////////////////////////////////////////////////////////////////////// 496 //////////////////////////////////////////////////////////////////////////////
364 497
365 CrxUpdateService::CrxUpdateService( 498 CrxUpdateService::CrxUpdateService(ComponentUpdateService::Configurator* config)
366 ComponentUpdateService::Configurator* config)
367 : config_(config), 499 : config_(config),
500 component_patcher_(config->CreateComponentPatcher()),
368 chrome_version_(chrome::VersionInfo().Version()), 501 chrome_version_(chrome::VersionInfo().Version()),
502 prod_id_(chrome::OmahaQueryParams::GetProdIdString(
503 chrome::OmahaQueryParams::CHROME)),
504 os_type_(chrome::VersionInfo().OSType()),
505 os_version_(base::SysInfo().OperatingSystemVersion()),
369 running_(false) { 506 running_(false) {
370 } 507 }
371 508
372 CrxUpdateService::~CrxUpdateService() { 509 CrxUpdateService::~CrxUpdateService() {
373 // Because we are a singleton, at this point only the UI thread should be 510 // Because we are a singleton, at this point only the UI thread should be
374 // alive, this simplifies the management of the work that could be in 511 // alive, this simplifies the management of the work that could be in
375 // flight in other threads. 512 // flight in other threads.
376 Stop(); 513 Stop();
377 STLDeleteElements(&work_items_); 514 STLDeleteElements(&work_items_);
378 } 515 }
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
411 void CrxUpdateService::ScheduleNextRun(bool step_delay) { 548 void CrxUpdateService::ScheduleNextRun(bool step_delay) {
412 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 549 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
413 DCHECK(url_fetcher_.get() == NULL); 550 DCHECK(url_fetcher_.get() == NULL);
414 CHECK(!timer_.IsRunning()); 551 CHECK(!timer_.IsRunning());
415 // It could be the case that Stop() had been called while a url request 552 // It could be the case that Stop() had been called while a url request
416 // or unpacking was in flight, if so we arrive here but |running_| is 553 // or unpacking was in flight, if so we arrive here but |running_| is
417 // false. In that case do not loop again. 554 // false. In that case do not loop again.
418 if (!running_) 555 if (!running_)
419 return; 556 return;
420 557
558 if (!step_delay && config_->PingsEnabled()) {
559 const std::string ping(BuildPing());
560 if (!ping.empty()) {
561 SendPing(ping);
562 }
563 }
564
421 // Keep the delay short if in the middle of an update (step_delay), 565 // Keep the delay short if in the middle of an update (step_delay),
422 // or there are new requested_work_items_ that have not been processed yet. 566 // or there are new requested_work_items_ that have not been processed yet.
423 int64 delay = (step_delay || requested_work_items_.size() > 0) 567 int64 delay = (step_delay || requested_work_items_.size() > 0)
424 ? config_->StepDelay() : config_->NextCheckDelay(); 568 ? config_->StepDelay() : config_->NextCheckDelay();
425 569
426 if (!step_delay) { 570 if (!step_delay) {
427 content::NotificationService::current()->Notify( 571 content::NotificationService::current()->Notify(
428 chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, 572 chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING,
429 content::Source<ComponentUpdateService>(this), 573 content::Source<ComponentUpdateService>(this),
430 content::NotificationService::NoDetails()); 574 content::NotificationService::NoDetails());
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
484 CrxUpdateItem* uit; 628 CrxUpdateItem* uit;
485 uit = FindUpdateItemById(id); 629 uit = FindUpdateItemById(id);
486 if (uit) { 630 if (uit) {
487 uit->component = component; 631 uit->component = component;
488 return kReplaced; 632 return kReplaced;
489 } 633 }
490 634
491 uit = new CrxUpdateItem; 635 uit = new CrxUpdateItem;
492 uit->id.swap(id); 636 uit->id.swap(id);
493 uit->component = component; 637 uit->component = component;
638
494 work_items_.push_back(uit); 639 work_items_.push_back(uit);
495 // If this is the first component registered we call Start to 640 // If this is the first component registered we call Start to
496 // schedule the first timer. 641 // schedule the first timer.
497 if (running_ && (work_items_.size() == 1)) 642 if (running_ && (work_items_.size() == 1))
498 Start(); 643 Start();
499 644
500 return kOk; 645 return kOk;
501 } 646 }
502 647
503 // Sets a component to be checked for updates. 648 // Sets a component to be checked for updates.
504 // The componet to add is |crxit| and the |query| string is modified with the 649 // The componet to add is |crxit| and the |query| string is modified with the
505 // required omaha compatible query. Returns false when the query strings 650 // required omaha compatible query. Returns false when the query strings
506 // is longer than specified by UrlSizeLimit(). 651 // is longer than specified by UrlSizeLimit().
507 bool CrxUpdateService::AddItemToUpdateCheck(CrxUpdateItem* item, 652 bool CrxUpdateService::AddItemToUpdateCheck(CrxUpdateItem* item,
508 std::string* query) { 653 std::string* query) {
509 if (!AddQueryString(item->id, 654 if (!AddQueryString(item->id,
510 item->component.version.GetString(), 655 item->component.version.GetString(),
656 item->component.fingerprint,
511 config_->UrlSizeLimit(), query)) 657 config_->UrlSizeLimit(), query))
512 return false; 658 return false;
659
513 item->status = CrxUpdateItem::kChecking; 660 item->status = CrxUpdateItem::kChecking;
514 item->last_check = base::Time::Now(); 661 item->last_check = base::Time::Now();
662 item->is_update_available = false;
663 item->ping_queued = false;
664 item->previous_version = item->component.version;
665 item->next_version = Version();
666 item->previous_fp = item->component.fingerprint;
667 item->next_fp = "";
668 item->diff_update_failed = false;
669 item->error_code = 0;
670 item->extra_code1 = 0;
671 item->diff_error_code = 0;
672 item->diff_extra_code1 = 0;
515 return true; 673 return true;
516 } 674 }
517 675
518 // Start the process of checking for an update, for a particular component 676 // Start the process of checking for an update, for a particular component
519 // that was previously registered. 677 // that was previously registered.
520 ComponentUpdateService::Status CrxUpdateService::CheckForUpdateSoon( 678 ComponentUpdateService::Status CrxUpdateService::CheckForUpdateSoon(
521 const CrxComponent& component) { 679 const CrxComponent& component) {
522 if (component.pk_hash.empty() || 680 if (component.pk_hash.empty() ||
523 !component.version.IsValid() || 681 !component.version.IsValid() ||
524 !component.installer) 682 !component.installer)
(...skipping 12 matching lines...) Expand all
537 base::TimeDelta delta = base::Time::Now() - uit->last_check; 695 base::TimeDelta delta = base::Time::Now() - uit->last_check;
538 if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay())) { 696 if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay())) {
539 return kError; 697 return kError;
540 } 698 }
541 699
542 switch (uit->status) { 700 switch (uit->status) {
543 // If the item is already in the process of being updated, there is 701 // If the item is already in the process of being updated, there is
544 // no point in this call, so return kInProgress. 702 // no point in this call, so return kInProgress.
545 case CrxUpdateItem::kChecking: 703 case CrxUpdateItem::kChecking:
546 case CrxUpdateItem::kCanUpdate: 704 case CrxUpdateItem::kCanUpdate:
705 case CrxUpdateItem::kDownloadingDiff:
547 case CrxUpdateItem::kDownloading: 706 case CrxUpdateItem::kDownloading:
707 case CrxUpdateItem::kUpdatingDiff:
548 case CrxUpdateItem::kUpdating: 708 case CrxUpdateItem::kUpdating:
549 return kInProgress; 709 return kInProgress;
550 // Otherwise the item was already checked a while back (or it is new), 710 // Otherwise the item was already checked a while back (or it is new),
551 // set its status to kNew to give it a slightly higher priority. 711 // set its status to kNew to give it a slightly higher priority.
552 case CrxUpdateItem::kNew: 712 case CrxUpdateItem::kNew:
553 case CrxUpdateItem::kUpdated: 713 case CrxUpdateItem::kUpdated:
554 case CrxUpdateItem::kUpToDate: 714 case CrxUpdateItem::kUpToDate:
555 case CrxUpdateItem::kNoUpdate: 715 case CrxUpdateItem::kNoUpdate:
556 uit->status = CrxUpdateItem::kNew; 716 uit->status = CrxUpdateItem::kNew;
557 requested_work_items_.insert(uit); 717 requested_work_items_.insert(uit);
(...skipping 18 matching lines...) Expand all
576 void CrxUpdateService::ProcessPendingItems() { 736 void CrxUpdateService::ProcessPendingItems() {
577 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 737 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
578 // First check for ready upgrades and do one. The first 738 // First check for ready upgrades and do one. The first
579 // step is to fetch the crx package. 739 // step is to fetch the crx package.
580 for (UpdateItems::const_iterator it = work_items_.begin(); 740 for (UpdateItems::const_iterator it = work_items_.begin();
581 it != work_items_.end(); ++it) { 741 it != work_items_.end(); ++it) {
582 CrxUpdateItem* item = *it; 742 CrxUpdateItem* item = *it;
583 if (item->status != CrxUpdateItem::kCanUpdate) 743 if (item->status != CrxUpdateItem::kCanUpdate)
584 continue; 744 continue;
585 // Found component to update, start the process. 745 // Found component to update, start the process.
586 item->status = CrxUpdateItem::kDownloading;
587 CRXContext* context = new CRXContext; 746 CRXContext* context = new CRXContext;
588 context->pk_hash = item->component.pk_hash; 747 context->pk_hash = item->component.pk_hash;
589 context->id = item->id; 748 context->id = item->id;
590 context->installer = item->component.installer; 749 context->installer = item->component.installer;
750 context->fingerprint = item->next_fp;
751 GURL package_url;
752 if (CanTryDiffUpdate(item, *config_)) {
753 package_url = item->diff_crx_url;
754 item->status = CrxUpdateItem::kDownloadingDiff;
755 } else {
756 package_url = item->crx_url;
757 item->status = CrxUpdateItem::kDownloading;
758 }
591 url_fetcher_.reset(net::URLFetcher::Create( 759 url_fetcher_.reset(net::URLFetcher::Create(
592 0, item->crx_url, net::URLFetcher::GET, 760 0, package_url, net::URLFetcher::GET,
593 MakeContextDelegate(this, context))); 761 MakeContextDelegate(this, context)));
594 StartFetch(url_fetcher_.get(), config_->RequestContext(), true); 762 StartFetch(url_fetcher_.get(), config_->RequestContext(), true);
595 return; 763 return;
596 } 764 }
597 765
598 for (size_t ix = 0; ix != arraysize(kManifestSources); ++ix) { 766 for (size_t ix = 0; ix != arraysize(kManifestSources); ++ix) {
599 const CrxComponent::UrlSource manifest_source = kManifestSources[ix]; 767 const CrxComponent::UrlSource manifest_source = kManifestSources[ix];
600 768
601 std::string query; 769 std::string query;
602 // If no pending upgrades, we check if there are new components we have not 770 // If no pending upgrades, we check if there are new components we have not
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
745 } 913 }
746 if (!it->browser_min_version.empty()) { 914 if (!it->browser_min_version.empty()) {
747 if (IsVersionNewer(chrome_version_, it->browser_min_version)) { 915 if (IsVersionNewer(chrome_version_, it->browser_min_version)) {
748 // Does not apply for this chrome version. 916 // Does not apply for this chrome version.
749 crx->status = CrxUpdateItem::kNoUpdate; 917 crx->status = CrxUpdateItem::kNoUpdate;
750 continue; 918 continue;
751 } 919 }
752 } 920 }
753 // All test passed. Queue an upgrade for this component and fire the 921 // All test passed. Queue an upgrade for this component and fire the
754 // notifications. 922 // notifications.
923 crx->is_update_available = true;
755 crx->crx_url = it->crx_url; 924 crx->crx_url = it->crx_url;
925 crx->package_hash = it->package_hash;
926 crx->size = it->size;
927 crx->diff_crx_url = it->diff_crx_url;
928 crx->diff_package_hash = it->diff_package_hash;
929 crx->diff_size = it->diff_size;
756 crx->status = CrxUpdateItem::kCanUpdate; 930 crx->status = CrxUpdateItem::kCanUpdate;
757 crx->next_version = Version(it->version); 931 crx->next_version = Version(it->version);
932 crx->next_fp = it->package_fingerprint;
758 ++update_pending; 933 ++update_pending;
759 934
760 content::NotificationService::current()->Notify( 935 content::NotificationService::current()->Notify(
761 chrome::NOTIFICATION_COMPONENT_UPDATE_FOUND, 936 chrome::NOTIFICATION_COMPONENT_UPDATE_FOUND,
762 content::Source<std::string>(&crx->id), 937 content::Source<std::string>(&crx->id),
763 content::NotificationService::NoDetails()); 938 content::NotificationService::NoDetails());
764 } 939 }
765 940
766 // All the components that are not mentioned in the manifest we 941 // All the components that are not mentioned in the manifest we
767 // consider them up to date. 942 // consider them up to date.
(...skipping 14 matching lines...) Expand all
782 } 957 }
783 958
784 // Called when the CRX package has been downloaded to a temporary location. 959 // Called when the CRX package has been downloaded to a temporary location.
785 // Here we fire the notifications and schedule the component-specific installer 960 // Here we fire the notifications and schedule the component-specific installer
786 // to be called in the file thread. 961 // to be called in the file thread.
787 void CrxUpdateService::OnURLFetchComplete(const net::URLFetcher* source, 962 void CrxUpdateService::OnURLFetchComplete(const net::URLFetcher* source,
788 CRXContext* context) { 963 CRXContext* context) {
789 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 964 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
790 int error_code = net::OK; 965 int error_code = net::OK;
791 966
967 CrxUpdateItem* crx = FindUpdateItemById(context->id);
968
792 if (source->FileErrorOccurred(&error_code) || !FetchSuccess(*source)) { 969 if (source->FileErrorOccurred(&error_code) || !FetchSuccess(*source)) {
793 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloading, 970 if (crx->status == CrxUpdateItem::kDownloadingDiff) {
794 CrxUpdateItem::kNoUpdate); 971 crx->diff_error_code = GetFetchError(*source);
795 DCHECK_EQ(count, 1ul); 972 crx->diff_update_failed = true;
973 crx->status = CrxUpdateItem::kCanUpdate;
974 BrowserThread::PostTask(
975 BrowserThread::UI,
976 FROM_HERE,
977 base::Bind(&CrxUpdateService::ProcessPendingItems,
978 base::Unretained(this)));
979 return;
980 }
981 crx->error_code = GetFetchError(*source);
982 crx->status = CrxUpdateItem::kNoUpdate;
796 config_->OnEvent(Configurator::kNetworkError, CrxIdtoUMAId(context->id)); 983 config_->OnEvent(Configurator::kNetworkError, CrxIdtoUMAId(context->id));
797 url_fetcher_.reset(); 984 url_fetcher_.reset();
798 ScheduleNextRun(false); 985 ScheduleNextRun(false);
799 } else { 986 } else {
800 base::FilePath temp_crx_path; 987 base::FilePath temp_crx_path;
801 CHECK(source->GetResponseAsFilePath(true, &temp_crx_path)); 988 CHECK(source->GetResponseAsFilePath(true, &temp_crx_path));
802 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloading, 989 crx->status = (crx->status == CrxUpdateItem::kDownloadingDiff) ?
803 CrxUpdateItem::kUpdating); 990 CrxUpdateItem::kUpdatingDiff : CrxUpdateItem::kUpdating;
804 DCHECK_EQ(count, 1ul); 991
805 url_fetcher_.reset(); 992 url_fetcher_.reset();
806 993
807 content::NotificationService::current()->Notify( 994 content::NotificationService::current()->Notify(
808 chrome::NOTIFICATION_COMPONENT_UPDATE_READY, 995 chrome::NOTIFICATION_COMPONENT_UPDATE_READY,
809 content::Source<std::string>(&context->id), 996 content::Source<std::string>(&context->id),
810 content::NotificationService::NoDetails()); 997 content::NotificationService::NoDetails());
811 998
812 // Why unretained? See comment at top of file. 999 // Why unretained? See comment at top of file.
813 BrowserThread::PostDelayedTask( 1000 BrowserThread::PostDelayedTask(
814 BrowserThread::FILE, 1001 BrowserThread::FILE,
815 FROM_HERE, 1002 FROM_HERE,
816 base::Bind(&CrxUpdateService::Install, 1003 base::Bind(&CrxUpdateService::Install,
817 base::Unretained(this), 1004 base::Unretained(this),
818 context, 1005 context,
819 temp_crx_path), 1006 temp_crx_path),
820 base::TimeDelta::FromMilliseconds(config_->StepDelay())); 1007 base::TimeDelta::FromMilliseconds(config_->StepDelay()));
821 } 1008 }
822 } 1009 }
823 1010
824 // Install consists of digital signature verification, unpacking and then 1011 // Install consists of digital signature verification, unpacking and then
825 // calling the component specific installer. All that is handled by the 1012 // calling the component specific installer. All that is handled by the
826 // |unpacker|. If there is an error this function is in charge of deleting 1013 // |unpacker|. If there is an error this function is in charge of deleting
827 // the files created. 1014 // the files created.
828 void CrxUpdateService::Install(const CRXContext* context, 1015 void CrxUpdateService::Install(const CRXContext* context,
829 const base::FilePath& crx_path) { 1016 const base::FilePath& crx_path) {
830 // This function owns the |crx_path| and the |context| object. 1017 // This function owns the |crx_path| and the |context| object.
831 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 1018 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
832 ComponentUnpacker 1019 ComponentUnpacker unpacker(context->pk_hash,
833 unpacker(context->pk_hash, crx_path, context->installer); 1020 crx_path,
1021 context->fingerprint,
1022 component_patcher_.get(),
1023 context->installer);
834 if (!file_util::Delete(crx_path, false)) { 1024 if (!file_util::Delete(crx_path, false)) {
835 NOTREACHED() << crx_path.value(); 1025 NOTREACHED() << crx_path.value();
836 } 1026 }
837 // Why unretained? See comment at top of file. 1027 // Why unretained? See comment at top of file.
838 BrowserThread::PostDelayedTask( 1028 BrowserThread::PostDelayedTask(
839 BrowserThread::UI, 1029 BrowserThread::UI,
840 FROM_HERE, 1030 FROM_HERE,
841 base::Bind(&CrxUpdateService::DoneInstalling, base::Unretained(this), 1031 base::Bind(&CrxUpdateService::DoneInstalling, base::Unretained(this),
842 context->id, unpacker.error()), 1032 context->id, unpacker.error(), unpacker.extended_error()),
843 base::TimeDelta::FromMilliseconds(config_->StepDelay())); 1033 base::TimeDelta::FromMilliseconds(config_->StepDelay()));
844 delete context; 1034 delete context;
845 } 1035 }
846 1036
847 // Installation has been completed. Adjust the component status and 1037 // Installation has been completed. Adjust the component status and
848 // schedule the next check. 1038 // schedule the next check.
849 void CrxUpdateService::DoneInstalling(const std::string& component_id, 1039 void CrxUpdateService::DoneInstalling(const std::string& component_id,
850 ComponentUnpacker::Error error) { 1040 ComponentUnpacker::Error error,
1041 int extra_code) {
851 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1042 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
852 1043
853 CrxUpdateItem* item = FindUpdateItemById(component_id); 1044 CrxUpdateItem* item = FindUpdateItemById(component_id);
1045 if (item->status == CrxUpdateItem::kUpdatingDiff) {
1046 if (error != ComponentUnpacker::kNone) {
1047 item->diff_error_code = error;
1048 item->diff_extra_code1 = extra_code;
1049 item->diff_update_failed = true;
1050 item->status = CrxUpdateItem::kCanUpdate;
1051 BrowserThread::PostTask(
1052 BrowserThread::UI,
1053 FROM_HERE,
1054 base::Bind(&CrxUpdateService::ProcessPendingItems,
1055 base::Unretained(this)));
1056 return;
1057 }
1058 }
1059
1060 if (error != ComponentUnpacker::kNone) {
1061 item->error_code = error;
1062 item->extra_code1 = extra_code;
1063 }
1064
854 item->status = (error == ComponentUnpacker::kNone) ? CrxUpdateItem::kUpdated : 1065 item->status = (error == ComponentUnpacker::kNone) ? CrxUpdateItem::kUpdated :
855 CrxUpdateItem::kNoUpdate; 1066 CrxUpdateItem::kNoUpdate;
856 if (item->status == CrxUpdateItem::kUpdated) 1067 if (item->status == CrxUpdateItem::kUpdated) {
857 item->component.version = item->next_version; 1068 item->component.version = item->next_version;
1069 item->component.fingerprint = item->next_fp;
1070 }
858 1071
859 Configurator::Events event; 1072 Configurator::Events event;
860 switch (error) { 1073 switch (error) {
861 case ComponentUnpacker::kNone: 1074 case ComponentUnpacker::kNone:
862 event = Configurator::kComponentUpdated; 1075 event = Configurator::kComponentUpdated;
863 break; 1076 break;
864 case ComponentUnpacker::kInstallerError: 1077 case ComponentUnpacker::kInstallerError:
865 event = Configurator::kInstallerError; 1078 event = Configurator::kInstallerError;
866 break; 1079 break;
867 default: 1080 default:
868 event = Configurator::kUnpackError; 1081 event = Configurator::kUnpackError;
869 break; 1082 break;
870 } 1083 }
871 1084
872 config_->OnEvent(event, CrxIdtoUMAId(component_id)); 1085 config_->OnEvent(event, CrxIdtoUMAId(component_id));
873 ScheduleNextRun(false); 1086 ScheduleNextRun(false);
874 } 1087 }
875 1088
1089 void CrxUpdateService::SendPing(const std::string& ping) {
1090 VLOG(3) << "Sending ping. " << ping;
1091 const std::string ping_url(config_->PingUrl().spec());
1092 ping_sender_.reset(net::URLFetcher::Create(
1093 0, GURL(ping_url), net::URLFetcher::POST,
1094 MakeContextDelegate(this, new PingContext())));
1095 ping_sender_->SetUploadData(std::string("application/xml"), ping);
1096 StartFetch(ping_sender_.get(), config_->RequestContext(), false);
1097 }
1098
1099 void CrxUpdateService::OnURLFetchComplete(const net::URLFetcher* source,
1100 PingContext* context) {
1101 VLOG(3) << "Sending component update ping returned "
1102 << FetchSuccess(*source);
1103 ping_sender_.reset();
1104 }
1105
1106 // Builds a ping message for the update items that have completed. Returns
1107 // an empty string if there are no completed items.
1108 std::string CrxUpdateService::BuildPing() const {
1109 const std::string apps(BuildPingApps());
1110 if (apps.empty())
1111 return std::string();
1112
1113 const char response_format[] =
1114 "<o:gupdate xmlns:o=\"http://www.google.com/update2/request\" "
1115 "protocol=\"2.0\" version=\"%s-%s\" requestid=\"{%s}\"> "
1116 "<o:os platform=\"%s\" version=\"%s\"/> "
1117 "%s"
1118 "</o:gupdate>";
1119 const std::string response_envelope(
1120 base::StringPrintf(response_format,
1121 prod_id_.c_str(),
1122 chrome_version_.GetString().c_str(),
1123 base::GenerateGUID().c_str(),
1124 os_type_.c_str(),
1125 os_version_.c_str(),
1126 apps.c_str()));
1127 return response_envelope;
1128 }
1129
1130 // Returns a string containing the sequence of app elements inside the
1131 // ping message.
1132 std::string CrxUpdateService::BuildPingApps() const {
1133 const char app_format[] = "<o:app appid=\"%s\" version=\"%s\">%s</o:app>";
1134
1135 std::string ping_apps;
1136 for (UpdateItems::const_iterator it = work_items_.begin();
1137 it != work_items_.end(); ++it) {
1138 CrxUpdateItem* item = *it;
1139 // Only ping once if an update was available and the item is completed.
1140 if (item->is_update_available && !item->ping_queued &&
1141 (item->status == CrxUpdateItem::kNoUpdate ||
1142 item->status == CrxUpdateItem::kUpdated)) {
1143 const std::string version = item->component.version.GetString().c_str();
1144 ping_apps += base::StringPrintf(app_format,
1145 item->id.c_str(),
1146 version.c_str(),
1147 BuildPingEvent(item).c_str());
1148 }
1149 }
1150 return ping_apps;
1151 }
1152
1153 // Returns a string representing one ping event for an update item.
1154 std::string CrxUpdateService::BuildPingEvent(CrxUpdateItem* item) {
1155 DCHECK(item->status == CrxUpdateItem::kNoUpdate ||
1156 item->status == CrxUpdateItem::kUpdated);
1157 DCHECK(item->is_update_available);
1158
1159 using base::StringAppendF;
1160
1161 std::string ping_event("<o:event eventtype=\"3\"");
1162 const int event_result = item->status == CrxUpdateItem::kUpdated;
1163 StringAppendF(&ping_event, " eventresult=\"%d\"", event_result);
1164 StringAppendF(&ping_event, " previousversion=\"%s\"",
1165 item->previous_version.GetString().c_str());
1166 StringAppendF(&ping_event, " nextversion=\"%s\"",
1167 item->next_version.GetString().c_str());
1168 if (item->error_code) {
1169 StringAppendF(&ping_event, " errorcode=\"%d\"", item->error_code);
1170 }
1171 if (item->extra_code1) {
1172 StringAppendF(&ping_event, " extracode1=\"%d\"", item->extra_code1);
1173 }
1174 if (IsDiffUpdateAvailable(item)) {
1175 StringAppendF(&ping_event, " diffresult=\"%d\"", !item->diff_update_failed);
1176 }
1177 if (item->diff_error_code) {
1178 StringAppendF(&ping_event, " differrorcode=\"%d\"", item->diff_error_code);
1179 }
1180 if (item->diff_extra_code1) {
1181 StringAppendF(&ping_event,
1182 " diffextracode1=\"%d\"",
1183 item->diff_extra_code1);
1184 }
1185 if (!item->previous_fp.empty()) {
1186 StringAppendF(&ping_event, " previousfp=\"%s\"", item->previous_fp.c_str());
1187 }
1188 if (!item->next_fp.empty()) {
1189 StringAppendF(&ping_event, " nextfp=\"%s\"", item->next_fp.c_str());
1190 }
1191 StringAppendF(&ping_event, "/>");
1192 item->ping_queued = true;
1193 return ping_event;
1194 }
1195
1196
876 // The component update factory. Using the component updater as a singleton 1197 // The component update factory. Using the component updater as a singleton
877 // is the job of the browser process. 1198 // is the job of the browser process.
878 ComponentUpdateService* ComponentUpdateServiceFactory( 1199 ComponentUpdateService* ComponentUpdateServiceFactory(
879 ComponentUpdateService::Configurator* config) { 1200 ComponentUpdateService::Configurator* config) {
880 DCHECK(config); 1201 DCHECK(config);
881 return new CrxUpdateService(config); 1202 return new CrxUpdateService(config);
882 } 1203 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698