Chromium Code Reviews| OLD | NEW |
|---|---|
| 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/compiler_specific.h" | 13 #include "base/compiler_specific.h" |
| 14 #include "base/file_util.h" | 14 #include "base/file_util.h" |
| 15 #include "base/files/file_path.h" | 15 #include "base/files/file_path.h" |
| 16 #include "base/logging.h" | 16 #include "base/logging.h" |
| 17 #include "base/memory/scoped_ptr.h" | 17 #include "base/memory/scoped_ptr.h" |
| 18 #include "base/memory/weak_ptr.h" | |
| 18 #include "base/stl_util.h" | 19 #include "base/stl_util.h" |
| 19 #include "base/strings/string_number_conversions.h" | 20 #include "base/strings/string_number_conversions.h" |
| 20 #include "base/strings/string_piece.h" | 21 #include "base/strings/string_piece.h" |
| 21 #include "base/strings/string_util.h" | 22 #include "base/strings/string_util.h" |
| 22 #include "base/strings/stringprintf.h" | 23 #include "base/strings/stringprintf.h" |
| 23 #include "base/timer/timer.h" | 24 #include "base/timer/timer.h" |
| 24 #include "chrome/browser/browser_process.h" | 25 #include "chrome/browser/browser_process.h" |
| 25 #include "chrome/browser/component_updater/component_patcher.h" | 26 #include "chrome/browser/component_updater/component_patcher.h" |
| 26 #include "chrome/browser/component_updater/component_unpacker.h" | 27 #include "chrome/browser/component_updater/component_unpacker.h" |
| 27 #include "chrome/browser/component_updater/component_updater_ping_manager.h" | 28 #include "chrome/browser/component_updater/component_updater_ping_manager.h" |
| 28 #include "chrome/browser/component_updater/crx_update_item.h" | 29 #include "chrome/browser/component_updater/crx_update_item.h" |
| 29 #include "chrome/common/chrome_utility_messages.h" | 30 #include "chrome/common/chrome_utility_messages.h" |
| 30 #include "chrome/common/chrome_version_info.h" | 31 #include "chrome/common/chrome_version_info.h" |
| 31 #include "chrome/common/extensions/extension.h" | 32 #include "chrome/common/extensions/extension.h" |
| 32 #include "content/public/browser/browser_thread.h" | 33 #include "content/public/browser/browser_thread.h" |
| 34 #include "content/public/browser/resource_controller.h" | |
| 35 #include "content/public/browser/resource_throttle.h" | |
| 33 #include "content/public/browser/utility_process_host.h" | 36 #include "content/public/browser/utility_process_host.h" |
| 34 #include "content/public/browser/utility_process_host_client.h" | 37 #include "content/public/browser/utility_process_host_client.h" |
| 35 #include "net/base/escape.h" | 38 #include "net/base/escape.h" |
| 36 #include "net/base/load_flags.h" | 39 #include "net/base/load_flags.h" |
| 37 #include "net/base/net_errors.h" | 40 #include "net/base/net_errors.h" |
| 38 #include "net/url_request/url_fetcher.h" | 41 #include "net/url_request/url_fetcher.h" |
| 39 #include "net/url_request/url_fetcher_delegate.h" | 42 #include "net/url_request/url_fetcher_delegate.h" |
| 43 #include "net/url_request/url_request.h" | |
| 40 #include "net/url_request/url_request_status.h" | 44 #include "net/url_request/url_request_status.h" |
| 41 #include "url/gurl.h" | 45 #include "url/gurl.h" |
| 42 | 46 |
| 43 using content::BrowserThread; | 47 using content::BrowserThread; |
| 44 using content::UtilityProcessHost; | 48 using content::UtilityProcessHost; |
| 45 using content::UtilityProcessHostClient; | 49 using content::UtilityProcessHostClient; |
| 46 using extensions::Extension; | 50 using extensions::Extension; |
| 47 | 51 |
| 48 // The component updater is designed to live until process shutdown, so | 52 // The component updater is designed to live until process shutdown, so |
| 49 // base::Bind() calls are not refcounted. | 53 // base::Bind() calls are not refcounted. |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 229 return HexStringToID(StringToLowerASCII(base::HexEncode(&component.pk_hash[0], | 233 return HexStringToID(StringToLowerASCII(base::HexEncode(&component.pk_hash[0], |
| 230 component.pk_hash.size()/2))); | 234 component.pk_hash.size()/2))); |
| 231 } | 235 } |
| 232 | 236 |
| 233 CrxComponentInfo::CrxComponentInfo() { | 237 CrxComponentInfo::CrxComponentInfo() { |
| 234 } | 238 } |
| 235 | 239 |
| 236 CrxComponentInfo::~CrxComponentInfo() { | 240 CrxComponentInfo::~CrxComponentInfo() { |
| 237 } | 241 } |
| 238 | 242 |
| 243 /////////////////////////////////////////////////////////////////////////////// | |
| 244 // In charge of blocking url requests until the |crx_id| component has been | |
| 245 // updated. This class is touched solely from the IO thread. The UI thread | |
| 246 // can post tasks to it via weak pointers. By default the request is blocked | |
| 247 // unless the CrxUpdateService calls Unblock(). | |
| 248 // The lifetime is controlled by Chrome's resource loader so the component | |
| 249 // updater cannot touch objects from this class except via weak pointers. | |
| 250 class CUResourceThrottle | |
| 251 : public content::ResourceThrottle, | |
| 252 public base::SupportsWeakPtr<CUResourceThrottle> { | |
| 253 public: | |
| 254 explicit CUResourceThrottle(const net::URLRequest* request); | |
| 255 virtual ~CUResourceThrottle(); | |
| 256 // Overriden from ResourceThrottle. | |
| 257 virtual void WillStartRequest(bool* defer) OVERRIDE; | |
| 258 virtual void WillRedirectRequest(const GURL& new_url, bool* defer) OVERRIDE; | |
| 259 | |
| 260 // Component updater calls this function via PostTask to unblock the request. | |
| 261 void Unblock(); | |
| 262 | |
| 263 private: | |
| 264 enum State { | |
| 265 NEW, | |
| 266 BLOCKED, | |
| 267 UNBLOCKED | |
| 268 }; | |
| 269 | |
| 270 State state_; | |
| 271 }; | |
| 272 | |
| 273 void UnblockResourceThrottle(base::WeakPtr<CUResourceThrottle> rt) { | |
| 274 BrowserThread::PostTask( | |
| 275 BrowserThread::IO, | |
| 276 FROM_HERE, | |
| 277 base::Bind(&CUResourceThrottle::Unblock, rt)); | |
| 278 } | |
| 279 | |
| 280 void UnblockandReapAllThrottles( | |
| 281 std::vector<base::WeakPtr<CUResourceThrottle>>* throttles) { | |
| 282 std::vector<base::WeakPtr<CUResourceThrottle>>::iterator it; | |
| 283 for (it == throttles->begin(); it != throttles->end(); ++it) | |
| 284 UnblockResourceThrottle(*it); | |
|
Sorin Jianu
2013/10/31 18:43:58
I share your concern about loops without {}. That
cpu_(ooo_6.6-7.5)
2013/10/31 21:36:08
Most chromistas would object to that.
| |
| 285 throttles->clear(); | |
| 286 } | |
| 287 | |
| 239 ////////////////////////////////////////////////////////////////////////////// | 288 ////////////////////////////////////////////////////////////////////////////// |
| 240 // The one and only implementation of the ComponentUpdateService interface. In | 289 // The one and only implementation of the ComponentUpdateService interface. In |
| 241 // charge of running the show. The main method is ProcessPendingItems() which | 290 // charge of running the show. The main method is ProcessPendingItems() which |
| 242 // is called periodically to do the upgrades/installs or the update checks. | 291 // is called periodically to do the upgrades/installs or the update checks. |
| 243 // An important consideration here is to be as "low impact" as we can to the | 292 // An important consideration here is to be as "low impact" as we can to the |
| 244 // rest of the browser, so even if we have many components registered and | 293 // rest of the browser, so even if we have many components registered and |
| 245 // eligible for update, we only do one thing at a time with pauses in between | 294 // eligible for update, we only do one thing at a time with pauses in between |
| 246 // the tasks. Also when we do network requests there is only one |url_fetcher_| | 295 // the tasks. Also when we do network requests there is only one |url_fetcher_| |
| 247 // in flight at a time. | 296 // in flight at a time. |
| 248 // There are no locks in this code, the main structure |work_items_| is mutated | 297 // There are no locks in this code, the main structure |work_items_| is mutated |
| 249 // only from the UI thread. The unpack and installation is done in the file | 298 // only from the UI thread. The unpack and installation is done in the file |
| 250 // thread and the network requests are done in the IO thread and in the file | 299 // thread and the network requests are done in the IO thread and in the file |
| 251 // thread. | 300 // thread. |
| 252 class CrxUpdateService : public ComponentUpdateService { | 301 class CrxUpdateService : public ComponentUpdateService { |
| 253 public: | 302 public: |
| 254 explicit CrxUpdateService(ComponentUpdateService::Configurator* config); | 303 explicit CrxUpdateService(ComponentUpdateService::Configurator* config); |
| 255 | 304 |
| 256 virtual ~CrxUpdateService(); | 305 virtual ~CrxUpdateService(); |
| 257 | 306 |
| 258 // Overrides for ComponentUpdateService. | 307 // Overrides for ComponentUpdateService. |
| 259 virtual Status Start() OVERRIDE; | 308 virtual Status Start() OVERRIDE; |
| 260 virtual Status Stop() OVERRIDE; | 309 virtual Status Stop() OVERRIDE; |
| 261 virtual Status RegisterComponent(const CrxComponent& component) OVERRIDE; | 310 virtual Status RegisterComponent(const CrxComponent& component) OVERRIDE; |
| 262 virtual Status OnDemandUpdate(const std::string& component_id) OVERRIDE; | 311 virtual Status OnDemandUpdate(const std::string& component_id) OVERRIDE; |
| 263 virtual void GetComponents( | 312 virtual void GetComponents( |
| 264 std::vector<CrxComponentInfo>* components) OVERRIDE; | 313 std::vector<CrxComponentInfo>* components) OVERRIDE; |
| 314 virtual content::ResourceThrottle* GetOnDemandResourceThrottle( | |
| 315 net::URLRequest* request, const char* crx_id) OVERRIDE; | |
| 265 | 316 |
| 266 // The only purpose of this class is to forward the | 317 // The only purpose of this class is to forward the |
| 267 // UtilityProcessHostClient callbacks so CrxUpdateService does | 318 // UtilityProcessHostClient callbacks so CrxUpdateService does |
| 268 // not have to derive from it because that is refcounted. | 319 // not have to derive from it because that is refcounted. |
| 269 class ManifestParserBridge : public UtilityProcessHostClient { | 320 class ManifestParserBridge : public UtilityProcessHostClient { |
| 270 public: | 321 public: |
| 271 explicit ManifestParserBridge(CrxUpdateService* service) | 322 explicit ManifestParserBridge(CrxUpdateService* service) |
| 272 : service_(service) {} | 323 : service_(service) {} |
| 273 | 324 |
| 274 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { | 325 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 335 }; | 386 }; |
| 336 | 387 |
| 337 // See ManifestParserBridge. | 388 // See ManifestParserBridge. |
| 338 void OnParseUpdateManifestSucceeded(const UpdateManifest::Results& results); | 389 void OnParseUpdateManifestSucceeded(const UpdateManifest::Results& results); |
| 339 | 390 |
| 340 // See ManifestParserBridge. | 391 // See ManifestParserBridge. |
| 341 void OnParseUpdateManifestFailed(const std::string& error_message); | 392 void OnParseUpdateManifestFailed(const std::string& error_message); |
| 342 | 393 |
| 343 bool AddItemToUpdateCheck(CrxUpdateItem* item, std::string* query); | 394 bool AddItemToUpdateCheck(CrxUpdateItem* item, std::string* query); |
| 344 | 395 |
| 396 Status OnDemandUpdateInternal(CrxUpdateItem* item); | |
| 397 | |
| 345 void ProcessPendingItems(); | 398 void ProcessPendingItems(); |
| 346 | 399 |
| 347 CrxUpdateItem* FindReadyComponent(); | 400 CrxUpdateItem* FindReadyComponent(); |
| 348 | 401 |
| 349 void UpdateComponent(CrxUpdateItem* workitem); | 402 void UpdateComponent(CrxUpdateItem* workitem); |
| 350 | 403 |
| 351 void AddUpdateCheckItems(std::string* query); | 404 void AddUpdateCheckItems(std::string* query); |
| 352 | 405 |
| 353 void DoUpdateCheck(const std::string& query); | 406 void DoUpdateCheck(const std::string& query); |
| 354 | 407 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 367 size_t ChangeItemStatus(CrxUpdateItem::Status from, | 420 size_t ChangeItemStatus(CrxUpdateItem::Status from, |
| 368 CrxUpdateItem::Status to); | 421 CrxUpdateItem::Status to); |
| 369 | 422 |
| 370 CrxUpdateItem* FindUpdateItemById(const std::string& id); | 423 CrxUpdateItem* FindUpdateItemById(const std::string& id); |
| 371 | 424 |
| 372 void NotifyComponentObservers(ComponentObserver::Events event, | 425 void NotifyComponentObservers(ComponentObserver::Events event, |
| 373 int extra) const; | 426 int extra) const; |
| 374 | 427 |
| 375 bool HasOnDemandItems() const; | 428 bool HasOnDemandItems() const; |
| 376 | 429 |
| 430 void OnNewResourceThrottle(base::WeakPtr<CUResourceThrottle> rt, | |
| 431 const std::string& crx_id); | |
| 432 | |
| 377 scoped_ptr<ComponentUpdateService::Configurator> config_; | 433 scoped_ptr<ComponentUpdateService::Configurator> config_; |
| 378 | 434 |
| 379 scoped_ptr<ComponentPatcher> component_patcher_; | 435 scoped_ptr<ComponentPatcher> component_patcher_; |
| 380 | 436 |
| 381 scoped_ptr<net::URLFetcher> url_fetcher_; | 437 scoped_ptr<net::URLFetcher> url_fetcher_; |
| 382 | 438 |
| 383 scoped_ptr<component_updater::PingManager> ping_manager_; | 439 scoped_ptr<component_updater::PingManager> ping_manager_; |
| 384 | 440 |
| 385 // A collection of every work item. | 441 // A collection of every work item. |
| 386 typedef std::vector<CrxUpdateItem*> UpdateItems; | 442 typedef std::vector<CrxUpdateItem*> UpdateItems; |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 545 break; | 601 break; |
| 546 case CrxUpdateItem::kNew: | 602 case CrxUpdateItem::kNew: |
| 547 case CrxUpdateItem::kChecking: | 603 case CrxUpdateItem::kChecking: |
| 548 case CrxUpdateItem::kDownloading: | 604 case CrxUpdateItem::kDownloading: |
| 549 case CrxUpdateItem::kDownloadingDiff: | 605 case CrxUpdateItem::kDownloadingDiff: |
| 550 case CrxUpdateItem::kLastStatus: | 606 case CrxUpdateItem::kLastStatus: |
| 551 // No notification for these states. | 607 // No notification for these states. |
| 552 break; | 608 break; |
| 553 } | 609 } |
| 554 } | 610 } |
| 611 | |
| 612 // Free possible pending network requests. | |
| 613 if ((to == CrxUpdateItem::kUpdated) || | |
| 614 (to == CrxUpdateItem::kUpToDate) || | |
| 615 (to == CrxUpdateItem::kNoUpdate)) { | |
| 616 UnblockandReapAllThrottles(&item->throttles); | |
| 617 } | |
| 555 } | 618 } |
| 556 | 619 |
| 557 // Changes all the components in |work_items_| that have |from| status to | 620 // Changes all the components in |work_items_| that have |from| status to |
| 558 // |to| status and returns how many have been changed. | 621 // |to| status and returns how many have been changed. |
| 559 size_t CrxUpdateService::ChangeItemStatus(CrxUpdateItem::Status from, | 622 size_t CrxUpdateService::ChangeItemStatus(CrxUpdateItem::Status from, |
| 560 CrxUpdateItem::Status to) { | 623 CrxUpdateItem::Status to) { |
| 561 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 624 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 562 size_t count = 0; | 625 size_t count = 0; |
| 563 for (UpdateItems::iterator it = work_items_.begin(); | 626 for (UpdateItems::iterator it = work_items_.begin(); |
| 564 it != work_items_.end(); ++it) { | 627 it != work_items_.end(); ++it) { |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 634 item->diff_error_code = 0; | 697 item->diff_error_code = 0; |
| 635 item->diff_extra_code1 = 0; | 698 item->diff_extra_code1 = 0; |
| 636 return true; | 699 return true; |
| 637 } | 700 } |
| 638 | 701 |
| 639 // Start the process of checking for an update, for a particular component | 702 // Start the process of checking for an update, for a particular component |
| 640 // that was previously registered. | 703 // that was previously registered. |
| 641 // |component_id| is a value returned from GetCrxComponentID(). | 704 // |component_id| is a value returned from GetCrxComponentID(). |
| 642 ComponentUpdateService::Status CrxUpdateService::OnDemandUpdate( | 705 ComponentUpdateService::Status CrxUpdateService::OnDemandUpdate( |
| 643 const std::string& component_id) { | 706 const std::string& component_id) { |
| 644 CrxUpdateItem* uit; | 707 return OnDemandUpdateInternal(FindUpdateItemById(component_id)); |
| 645 uit = FindUpdateItemById(component_id); | 708 } |
| 709 | |
| 710 ComponentUpdateService::Status CrxUpdateService::OnDemandUpdateInternal( | |
| 711 CrxUpdateItem* uit) { | |
| 646 if (!uit) | 712 if (!uit) |
| 647 return kError; | 713 return kError; |
| 648 | |
| 649 // Check if the request is too soon. | 714 // Check if the request is too soon. |
| 650 base::TimeDelta delta = base::Time::Now() - uit->last_check; | 715 base::TimeDelta delta = base::Time::Now() - uit->last_check; |
| 651 if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay())) | 716 if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay())) |
| 652 return kError; | 717 return kError; |
| 653 | 718 |
| 654 switch (uit->status) { | 719 switch (uit->status) { |
| 655 // If the item is already in the process of being updated, there is | 720 // If the item is already in the process of being updated, there is |
| 656 // no point in this call, so return kInProgress. | 721 // no point in this call, so return kInProgress. |
| 657 case CrxUpdateItem::kChecking: | 722 case CrxUpdateItem::kChecking: |
| 658 case CrxUpdateItem::kCanUpdate: | 723 case CrxUpdateItem::kCanUpdate: |
| (...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1062 void CrxUpdateService::NotifyComponentObservers( | 1127 void CrxUpdateService::NotifyComponentObservers( |
| 1063 ComponentObserver::Events event, int extra) const { | 1128 ComponentObserver::Events event, int extra) const { |
| 1064 for (UpdateItems::const_iterator it = work_items_.begin(); | 1129 for (UpdateItems::const_iterator it = work_items_.begin(); |
| 1065 it != work_items_.end(); ++it) { | 1130 it != work_items_.end(); ++it) { |
| 1066 ComponentObserver* observer = (*it)->component.observer; | 1131 ComponentObserver* observer = (*it)->component.observer; |
| 1067 if (observer) | 1132 if (observer) |
| 1068 observer->OnEvent(event, 0); | 1133 observer->OnEvent(event, 0); |
| 1069 } | 1134 } |
| 1070 } | 1135 } |
| 1071 | 1136 |
| 1137 content::ResourceThrottle* CrxUpdateService::GetOnDemandResourceThrottle( | |
| 1138 net::URLRequest* request, const char* crx_id) { | |
| 1139 // We give the raw pointer to the caller, who will delete it at will | |
| 1140 // and we keep for ourselves a weak pointer to it so we can post tasks | |
| 1141 // from the UI thread without having to track lifetime directly. | |
| 1142 CUResourceThrottle* rt = new CUResourceThrottle(request); | |
| 1143 BrowserThread::PostTask( | |
| 1144 BrowserThread::UI, | |
| 1145 FROM_HERE, | |
| 1146 base::Bind(&CrxUpdateService::OnNewResourceThrottle, | |
| 1147 base::Unretained(this), | |
| 1148 rt->AsWeakPtr(), | |
| 1149 crx_id)); | |
| 1150 return rt; | |
| 1151 } | |
| 1152 | |
| 1153 void CrxUpdateService::OnNewResourceThrottle( | |
| 1154 base::WeakPtr<CUResourceThrottle> rt, const std::string& crx_id) { | |
| 1155 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 1156 // Check if we can on-demand update, else unblock the request anyway. | |
| 1157 CrxUpdateItem* item = FindUpdateItemById(crx_id); | |
| 1158 Status status = OnDemandUpdateInternal(item); | |
| 1159 if (status == kOk || status == kInProgress) { | |
| 1160 item->throttles.push_back(rt); | |
| 1161 return; | |
| 1162 } | |
| 1163 UnblockResourceThrottle(rt); | |
| 1164 } | |
| 1165 | |
| 1166 /////////////////////////////////////////////////////////////////////////////// | |
| 1167 | |
| 1168 CUResourceThrottle::CUResourceThrottle(const net::URLRequest* request) | |
| 1169 : state_(NEW) { | |
| 1170 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 1171 } | |
| 1172 | |
| 1173 CUResourceThrottle::~CUResourceThrottle() { | |
| 1174 } | |
| 1175 | |
| 1176 void CUResourceThrottle::WillStartRequest(bool* defer) { | |
| 1177 if (state_ != UNBLOCKED) { | |
| 1178 state_ = BLOCKED; | |
| 1179 *defer = true; | |
| 1180 } else { | |
| 1181 *defer = false; | |
| 1182 } | |
| 1183 } | |
| 1184 | |
| 1185 void CUResourceThrottle::WillRedirectRequest(const GURL& new_url, bool* defer) { | |
| 1186 WillStartRequest(defer); | |
| 1187 } | |
| 1188 | |
| 1189 void CUResourceThrottle::Unblock() { | |
| 1190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 1191 if (state_ == BLOCKED) | |
| 1192 controller()->Resume(); | |
| 1193 state_ = UNBLOCKED; | |
| 1194 } | |
| 1195 | |
| 1072 // The component update factory. Using the component updater as a singleton | 1196 // The component update factory. Using the component updater as a singleton |
| 1073 // is the job of the browser process. | 1197 // is the job of the browser process. |
| 1074 ComponentUpdateService* ComponentUpdateServiceFactory( | 1198 ComponentUpdateService* ComponentUpdateServiceFactory( |
| 1075 ComponentUpdateService::Configurator* config) { | 1199 ComponentUpdateService::Configurator* config) { |
| 1076 DCHECK(config); | 1200 DCHECK(config); |
| 1077 return new CrxUpdateService(config); | 1201 return new CrxUpdateService(config); |
| 1078 } | 1202 } |
| OLD | NEW |