Home | History | Annotate | Download | only in download
      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
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/download/chrome_download_manager_delegate.h"
      6 
      7 #include <string>
      8 
      9 #include "base/bind.h"
     10 #include "base/bind_helpers.h"
     11 #include "base/callback.h"
     12 #include "base/file_util.h"
     13 #include "base/prefs/pref_member.h"
     14 #include "base/prefs/pref_service.h"
     15 #include "base/rand_util.h"
     16 #include "base/strings/stringprintf.h"
     17 #include "base/strings/utf_string_conversions.h"
     18 #include "base/time/time.h"
     19 #include "chrome/browser/browser_process.h"
     20 #include "chrome/browser/chrome_notification_types.h"
     21 #include "chrome/browser/download/download_completion_blocker.h"
     22 #include "chrome/browser/download/download_crx_util.h"
     23 #include "chrome/browser/download/download_file_picker.h"
     24 #include "chrome/browser/download/download_history.h"
     25 #include "chrome/browser/download/download_path_reservation_tracker.h"
     26 #include "chrome/browser/download/download_prefs.h"
     27 #include "chrome/browser/download/download_service.h"
     28 #include "chrome/browser/download/download_service_factory.h"
     29 #include "chrome/browser/download/download_target_determiner.h"
     30 #include "chrome/browser/download/download_util.h"
     31 #include "chrome/browser/download/save_package_file_picker.h"
     32 #include "chrome/browser/extensions/api/downloads/downloads_api.h"
     33 #include "chrome/browser/extensions/crx_installer.h"
     34 #include "chrome/browser/platform_util.h"
     35 #include "chrome/browser/profiles/profile.h"
     36 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
     37 #include "chrome/common/chrome_constants.h"
     38 #include "chrome/common/pref_names.h"
     39 #include "components/user_prefs/pref_registry_syncable.h"
     40 #include "content/public/browser/download_item.h"
     41 #include "content/public/browser/download_manager.h"
     42 #include "content/public/browser/notification_source.h"
     43 #include "extensions/common/constants.h"
     44 
     45 #if defined(OS_CHROMEOS)
     46 #include "chrome/browser/chromeos/drive/download_handler.h"
     47 #include "chrome/browser/chromeos/drive/file_system_util.h"
     48 #endif
     49 
     50 using content::BrowserThread;
     51 using content::DownloadItem;
     52 using content::DownloadManager;
     53 using safe_browsing::DownloadProtectionService;
     54 
     55 namespace {
     56 
     57 // String pointer used for identifying safebrowing data associated with
     58 // a download item.
     59 static const char safe_browsing_id[] = "Safe Browsing ID";
     60 
     61 // The state of a safebrowsing check.
     62 class SafeBrowsingState : public DownloadCompletionBlocker {
     63  public:
     64   SafeBrowsingState()
     65     : verdict_(DownloadProtectionService::SAFE) {
     66   }
     67 
     68   virtual ~SafeBrowsingState();
     69 
     70   // The verdict that we got from calling CheckClientDownload. Only valid to
     71   // call if |is_complete()|.
     72   DownloadProtectionService::DownloadCheckResult verdict() const {
     73     return verdict_;
     74   }
     75 
     76   void SetVerdict(DownloadProtectionService::DownloadCheckResult result) {
     77     verdict_ = result;
     78     CompleteDownload();
     79   }
     80 
     81  private:
     82   DownloadProtectionService::DownloadCheckResult verdict_;
     83 
     84   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingState);
     85 };
     86 
     87 SafeBrowsingState::~SafeBrowsingState() {}
     88 
     89 // Used with GetPlatformDownloadPath() to indicate which platform path to
     90 // return.
     91 enum PlatformDownloadPathType {
     92   // Return the platform specific target path.
     93   PLATFORM_TARGET_PATH,
     94 
     95   // Return the platform specific current path. If the download is in-progress
     96   // and the download location is a local filesystem path, then
     97   // GetPlatformDownloadPath will return the path to the intermediate file.
     98   PLATFORM_CURRENT_PATH
     99 };
    100 
    101 // Returns a path in the form that that is expected by platform_util::OpenItem /
    102 // platform_util::ShowItemInFolder / DownloadTargetDeterminer.
    103 //
    104 // DownloadItems corresponding to Drive downloads use a temporary file as the
    105 // target path. The paths returned by DownloadItem::GetFullPath() /
    106 // GetTargetFilePath() refer to this temporary file. This function looks up the
    107 // corresponding path in Drive for these downloads.
    108 //
    109 // How the platform path is determined is based on PlatformDownloadPathType.
    110 base::FilePath GetPlatformDownloadPath(Profile* profile,
    111                                        const DownloadItem* download,
    112                                        PlatformDownloadPathType path_type) {
    113 #if defined(OS_CHROMEOS)
    114   // Drive downloads always return the target path for all types.
    115   drive::DownloadHandler* drive_download_handler =
    116       drive::DownloadHandler::GetForProfile(profile);
    117   if (drive_download_handler &&
    118       drive_download_handler->IsDriveDownload(download))
    119     return drive_download_handler->GetTargetPath(download);
    120 #endif
    121 
    122   if (path_type == PLATFORM_TARGET_PATH)
    123     return download->GetTargetFilePath();
    124   return download->GetFullPath();
    125 }
    126 
    127 // Callback invoked by DownloadProtectionService::CheckClientDownload.
    128 // |is_content_check_supported| is true if the SB service supports scanning the
    129 // download for malicious content.
    130 // |callback| is invoked with a danger type determined as follows:
    131 //
    132 // Danger type is (in order of preference):
    133 //   * DANGEROUS_URL, if the URL is a known malware site.
    134 //   * MAYBE_DANGEROUS_CONTENT, if the content will be scanned for
    135 //         malware. I.e. |is_content_check_supported| is true.
    136 //   * NOT_DANGEROUS.
    137 void CheckDownloadUrlDone(
    138     const DownloadTargetDeterminerDelegate::CheckDownloadUrlCallback& callback,
    139     bool is_content_check_supported,
    140     DownloadProtectionService::DownloadCheckResult result) {
    141   content::DownloadDangerType danger_type;
    142   if (result == DownloadProtectionService::SAFE) {
    143     // If this type of files is handled by the enhanced SafeBrowsing download
    144     // protection, mark it as potentially dangerous content until we are done
    145     // with scanning it.
    146     if (is_content_check_supported)
    147       danger_type = content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT;
    148     else
    149       danger_type = content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS;
    150   } else {
    151     // If the URL is malicious, we'll use that as the danger type. The results
    152     // of the content check, if one is performed, will be ignored.
    153     danger_type = content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL;
    154   }
    155   callback.Run(danger_type);
    156 }
    157 
    158 }  // namespace
    159 
    160 ChromeDownloadManagerDelegate::ChromeDownloadManagerDelegate(Profile* profile)
    161     : profile_(profile),
    162       next_download_id_(content::DownloadItem::kInvalidId),
    163       download_prefs_(new DownloadPrefs(profile)) {
    164 }
    165 
    166 ChromeDownloadManagerDelegate::~ChromeDownloadManagerDelegate() {
    167 }
    168 
    169 void ChromeDownloadManagerDelegate::SetDownloadManager(DownloadManager* dm) {
    170   download_manager_ = dm;
    171 }
    172 
    173 void ChromeDownloadManagerDelegate::Shutdown() {
    174   download_prefs_.reset();
    175 }
    176 
    177 void ChromeDownloadManagerDelegate::SetNextId(uint32 next_id) {
    178   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    179   DCHECK(!profile_->IsOffTheRecord());
    180   DCHECK_NE(content::DownloadItem::kInvalidId, next_id);
    181   next_download_id_ = next_id;
    182 
    183   IdCallbackVector callbacks;
    184   id_callbacks_.swap(callbacks);
    185   for (IdCallbackVector::const_iterator it = callbacks.begin();
    186        it != callbacks.end(); ++it) {
    187     ReturnNextId(*it);
    188   }
    189 }
    190 
    191 void ChromeDownloadManagerDelegate::GetNextId(
    192     const content::DownloadIdCallback& callback) {
    193   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    194   if (profile_->IsOffTheRecord()) {
    195     content::BrowserContext::GetDownloadManager(
    196         profile_->GetOriginalProfile())->GetDelegate()->GetNextId(callback);
    197     return;
    198   }
    199   if (next_download_id_ == content::DownloadItem::kInvalidId) {
    200     id_callbacks_.push_back(callback);
    201     return;
    202   }
    203   ReturnNextId(callback);
    204 }
    205 
    206 void ChromeDownloadManagerDelegate::ReturnNextId(
    207     const content::DownloadIdCallback& callback) {
    208   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    209   DCHECK(!profile_->IsOffTheRecord());
    210   DCHECK_NE(content::DownloadItem::kInvalidId, next_download_id_);
    211   callback.Run(next_download_id_++);
    212 }
    213 
    214 bool ChromeDownloadManagerDelegate::DetermineDownloadTarget(
    215     DownloadItem* download,
    216     const content::DownloadTargetCallback& callback) {
    217   DownloadTargetDeterminer::Start(
    218       download,
    219       GetPlatformDownloadPath(
    220           profile_, download, PLATFORM_TARGET_PATH),
    221       download_prefs_.get(),
    222       this,
    223       callback);
    224   return true;
    225 }
    226 
    227 bool ChromeDownloadManagerDelegate::ShouldOpenFileBasedOnExtension(
    228     const base::FilePath& path) {
    229   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    230   if (path.Extension().empty())
    231     return false;
    232   // TODO(asanka): This determination is done based on |path|, while
    233   // ShouldOpenDownload() detects extension downloads based on the
    234   // characteristics of the download. Reconcile this. http://crbug.com/167702
    235   if (path.MatchesExtension(extensions::kExtensionFileExtension))
    236     return false;
    237   return download_prefs_->IsAutoOpenEnabledBasedOnExtension(path);
    238 }
    239 
    240 // static
    241 void ChromeDownloadManagerDelegate::DisableSafeBrowsing(DownloadItem* item) {
    242   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    243 #if defined(FULL_SAFE_BROWSING)
    244   SafeBrowsingState* state = static_cast<SafeBrowsingState*>(
    245       item->GetUserData(&safe_browsing_id));
    246   if (!state) {
    247     state = new SafeBrowsingState();
    248     item->SetUserData(&safe_browsing_id, state);
    249   }
    250   state->SetVerdict(DownloadProtectionService::SAFE);
    251 #endif
    252 }
    253 
    254 bool ChromeDownloadManagerDelegate::IsDownloadReadyForCompletion(
    255     DownloadItem* item,
    256     const base::Closure& internal_complete_callback) {
    257   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    258 #if defined(FULL_SAFE_BROWSING)
    259   SafeBrowsingState* state = static_cast<SafeBrowsingState*>(
    260       item->GetUserData(&safe_browsing_id));
    261   if (!state) {
    262     // Begin the safe browsing download protection check.
    263     DownloadProtectionService* service = GetDownloadProtectionService();
    264     if (service) {
    265       VLOG(2) << __FUNCTION__ << "() Start SB download check for download = "
    266               << item->DebugString(false);
    267       state = new SafeBrowsingState();
    268       state->set_callback(internal_complete_callback);
    269       item->SetUserData(&safe_browsing_id, state);
    270       service->CheckClientDownload(
    271           item,
    272           base::Bind(
    273               &ChromeDownloadManagerDelegate::CheckClientDownloadDone,
    274               this,
    275               item->GetId()));
    276       return false;
    277     }
    278   } else if (!state->is_complete()) {
    279     // Don't complete the download until we have an answer.
    280     state->set_callback(internal_complete_callback);
    281     return false;
    282   }
    283 #endif
    284   return true;
    285 }
    286 
    287 void ChromeDownloadManagerDelegate::ShouldCompleteDownloadInternal(
    288     uint32 download_id,
    289     const base::Closure& user_complete_callback) {
    290   DownloadItem* item = download_manager_->GetDownload(download_id);
    291   if (!item)
    292     return;
    293   if (ShouldCompleteDownload(item, user_complete_callback))
    294     user_complete_callback.Run();
    295 }
    296 
    297 bool ChromeDownloadManagerDelegate::ShouldCompleteDownload(
    298     DownloadItem* item,
    299     const base::Closure& user_complete_callback) {
    300   return IsDownloadReadyForCompletion(item, base::Bind(
    301       &ChromeDownloadManagerDelegate::ShouldCompleteDownloadInternal,
    302       this, item->GetId(), user_complete_callback));
    303 }
    304 
    305 bool ChromeDownloadManagerDelegate::ShouldOpenDownload(
    306     DownloadItem* item, const content::DownloadOpenDelayedCallback& callback) {
    307   if (download_crx_util::IsExtensionDownload(*item)) {
    308     scoped_refptr<extensions::CrxInstaller> crx_installer =
    309         download_crx_util::OpenChromeExtension(profile_, *item);
    310 
    311     // CRX_INSTALLER_DONE will fire when the install completes.  At that
    312     // time, Observe() will call the passed callback.
    313     registrar_.Add(
    314         this,
    315         chrome::NOTIFICATION_CRX_INSTALLER_DONE,
    316         content::Source<extensions::CrxInstaller>(crx_installer.get()));
    317 
    318     crx_installers_[crx_installer.get()] = callback;
    319     // The status text and percent complete indicator will change now
    320     // that we are installing a CRX.  Update observers so that they pick
    321     // up the change.
    322     item->UpdateObservers();
    323     return false;
    324   }
    325 
    326   return true;
    327 }
    328 
    329 bool ChromeDownloadManagerDelegate::GenerateFileHash() {
    330 #if defined(FULL_SAFE_BROWSING)
    331   return profile_->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled) &&
    332       g_browser_process->safe_browsing_service()->DownloadBinHashNeeded();
    333 #else
    334   return false;
    335 #endif
    336 }
    337 
    338 void ChromeDownloadManagerDelegate::GetSaveDir(
    339     content::BrowserContext* browser_context,
    340     base::FilePath* website_save_dir,
    341     base::FilePath* download_save_dir,
    342     bool* skip_dir_check) {
    343   *website_save_dir = download_prefs_->SaveFilePath();
    344   DCHECK(!website_save_dir->empty());
    345   *download_save_dir = download_prefs_->DownloadPath();
    346   *skip_dir_check = false;
    347 #if defined(OS_CHROMEOS)
    348   *skip_dir_check = drive::util::IsUnderDriveMountPoint(*website_save_dir);
    349 #endif
    350 }
    351 
    352 void ChromeDownloadManagerDelegate::ChooseSavePath(
    353     content::WebContents* web_contents,
    354     const base::FilePath& suggested_path,
    355     const base::FilePath::StringType& default_extension,
    356     bool can_save_as_complete,
    357     const content::SavePackagePathPickedCallback& callback) {
    358   // Deletes itself.
    359   new SavePackageFilePicker(
    360       web_contents,
    361       suggested_path,
    362       default_extension,
    363       can_save_as_complete,
    364       download_prefs_.get(),
    365       callback);
    366 }
    367 
    368 void ChromeDownloadManagerDelegate::OpenDownload(DownloadItem* download) {
    369   DCHECK_EQ(DownloadItem::COMPLETE, download->GetState());
    370   if (!download->CanOpenDownload())
    371     return;
    372   base::FilePath platform_path(
    373       GetPlatformDownloadPath(profile_, download, PLATFORM_TARGET_PATH));
    374   DCHECK(!platform_path.empty());
    375   platform_util::OpenItem(platform_path);
    376 }
    377 
    378 void ChromeDownloadManagerDelegate::ShowDownloadInShell(
    379     DownloadItem* download) {
    380   if (!download->CanShowInFolder())
    381     return;
    382   base::FilePath platform_path(
    383       GetPlatformDownloadPath(profile_, download, PLATFORM_CURRENT_PATH));
    384   DCHECK(!platform_path.empty());
    385   platform_util::ShowItemInFolder(platform_path);
    386 }
    387 
    388 void ChromeDownloadManagerDelegate::CheckForFileExistence(
    389     DownloadItem* download,
    390     const content::CheckForFileExistenceCallback& callback) {
    391 #if defined(OS_CHROMEOS)
    392   drive::DownloadHandler* drive_download_handler =
    393       drive::DownloadHandler::GetForProfile(profile_);
    394   if (drive_download_handler &&
    395       drive_download_handler->IsDriveDownload(download)) {
    396     drive_download_handler->CheckForFileExistence(download, callback);
    397     return;
    398   }
    399 #endif
    400   BrowserThread::PostTaskAndReplyWithResult(
    401       BrowserThread::FILE, FROM_HERE,
    402       base::Bind(&base::PathExists, download->GetTargetFilePath()),
    403       callback);
    404 }
    405 
    406 std::string
    407 ChromeDownloadManagerDelegate::ApplicationClientIdForFileScanning() const {
    408   return std::string(chrome::kApplicationClientIDStringForAVScanning);
    409 }
    410 
    411 DownloadProtectionService*
    412     ChromeDownloadManagerDelegate::GetDownloadProtectionService() {
    413   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    414 #if defined(FULL_SAFE_BROWSING)
    415   SafeBrowsingService* sb_service = g_browser_process->safe_browsing_service();
    416   if (sb_service && sb_service->download_protection_service() &&
    417       profile_->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled)) {
    418     return sb_service->download_protection_service();
    419   }
    420 #endif
    421   return NULL;
    422 }
    423 
    424 void ChromeDownloadManagerDelegate::NotifyExtensions(
    425     DownloadItem* download,
    426     const base::FilePath& virtual_path,
    427     const NotifyExtensionsCallback& callback) {
    428   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    429 #if !defined(OS_ANDROID)
    430   ExtensionDownloadsEventRouter* router =
    431       DownloadServiceFactory::GetForBrowserContext(profile_)->
    432       GetExtensionEventRouter();
    433   if (router) {
    434     base::Closure original_path_callback =
    435         base::Bind(callback, base::FilePath(),
    436                    DownloadPathReservationTracker::UNIQUIFY);
    437     router->OnDeterminingFilename(download, virtual_path.BaseName(),
    438                                   original_path_callback,
    439                                   callback);
    440     return;
    441   }
    442 #endif
    443   callback.Run(base::FilePath(), DownloadPathReservationTracker::UNIQUIFY);
    444 }
    445 
    446 void ChromeDownloadManagerDelegate::ReserveVirtualPath(
    447     content::DownloadItem* download,
    448     const base::FilePath& virtual_path,
    449     bool create_directory,
    450     DownloadPathReservationTracker::FilenameConflictAction conflict_action,
    451     const DownloadTargetDeterminerDelegate::ReservedPathCallback& callback) {
    452   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    453   DCHECK(!virtual_path.empty());
    454 #if defined(OS_CHROMEOS)
    455   // TODO(asanka): Handle path reservations for virtual paths as well.
    456   //               http://crbug.com/151618
    457   if (drive::util::IsUnderDriveMountPoint(virtual_path)) {
    458     callback.Run(virtual_path, true);
    459     return;
    460   }
    461 #endif
    462   DownloadPathReservationTracker::GetReservedPath(
    463       download,
    464       virtual_path,
    465       download_prefs_->DownloadPath(),
    466       create_directory,
    467       conflict_action,
    468       callback);
    469 }
    470 
    471 void ChromeDownloadManagerDelegate::PromptUserForDownloadPath(
    472     DownloadItem* download,
    473     const base::FilePath& suggested_path,
    474     const DownloadTargetDeterminerDelegate::FileSelectedCallback& callback) {
    475   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    476   DownloadFilePicker::ShowFilePicker(download, suggested_path, callback);
    477 }
    478 
    479 void ChromeDownloadManagerDelegate::DetermineLocalPath(
    480     DownloadItem* download,
    481     const base::FilePath& virtual_path,
    482     const DownloadTargetDeterminerDelegate::LocalPathCallback& callback) {
    483   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    484 #if defined(OS_CHROMEOS)
    485   drive::DownloadHandler* drive_download_handler =
    486       drive::DownloadHandler::GetForProfile(profile_);
    487   if (drive_download_handler) {
    488     drive_download_handler->SubstituteDriveDownloadPath(
    489         virtual_path, download, callback);
    490     return;
    491   }
    492 #endif
    493   callback.Run(virtual_path);
    494 }
    495 
    496 void ChromeDownloadManagerDelegate::CheckDownloadUrl(
    497     DownloadItem* download,
    498     const base::FilePath& suggested_path,
    499     const CheckDownloadUrlCallback& callback) {
    500   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    501 
    502 #if defined(FULL_SAFE_BROWSING)
    503   safe_browsing::DownloadProtectionService* service =
    504       GetDownloadProtectionService();
    505   if (service) {
    506     bool is_content_check_supported =
    507         service->IsSupportedDownload(*download, suggested_path);
    508     VLOG(2) << __FUNCTION__ << "() Start SB URL check for download = "
    509             << download->DebugString(false);
    510     service->CheckDownloadUrl(*download,
    511                               base::Bind(&CheckDownloadUrlDone,
    512                                          callback,
    513                                          is_content_check_supported));
    514     return;
    515   }
    516 #endif
    517   callback.Run(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
    518 }
    519 
    520 void ChromeDownloadManagerDelegate::CheckClientDownloadDone(
    521     uint32 download_id,
    522     DownloadProtectionService::DownloadCheckResult result) {
    523   DownloadItem* item = download_manager_->GetDownload(download_id);
    524   if (!item || (item->GetState() != DownloadItem::IN_PROGRESS))
    525     return;
    526 
    527   VLOG(2) << __FUNCTION__ << "() download = " << item->DebugString(false)
    528           << " verdict = " << result;
    529   // We only mark the content as being dangerous if the download's safety state
    530   // has not been set to DANGEROUS yet.  We don't want to show two warnings.
    531   if (item->GetDangerType() == content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS ||
    532       item->GetDangerType() ==
    533       content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT) {
    534     content::DownloadDangerType danger_type =
    535         content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS;
    536     switch (result) {
    537       case DownloadProtectionService::SAFE:
    538         // Do nothing.
    539         break;
    540       case DownloadProtectionService::DANGEROUS:
    541         danger_type = content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT;
    542         break;
    543       case DownloadProtectionService::UNCOMMON:
    544         danger_type = content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT;
    545         break;
    546       case DownloadProtectionService::DANGEROUS_HOST:
    547         danger_type = content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST;
    548         break;
    549       case DownloadProtectionService::POTENTIALLY_UNWANTED:
    550         danger_type = content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED;
    551         break;
    552     }
    553 
    554     if (danger_type != content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS)
    555       item->OnContentCheckCompleted(danger_type);
    556   }
    557 
    558   SafeBrowsingState* state = static_cast<SafeBrowsingState*>(
    559       item->GetUserData(&safe_browsing_id));
    560   state->SetVerdict(result);
    561 }
    562 
    563 // content::NotificationObserver implementation.
    564 void ChromeDownloadManagerDelegate::Observe(
    565     int type,
    566     const content::NotificationSource& source,
    567     const content::NotificationDetails& details) {
    568   DCHECK(type == chrome::NOTIFICATION_CRX_INSTALLER_DONE);
    569 
    570   registrar_.Remove(this,
    571                     chrome::NOTIFICATION_CRX_INSTALLER_DONE,
    572                     source);
    573 
    574   scoped_refptr<extensions::CrxInstaller> installer =
    575       content::Source<extensions::CrxInstaller>(source).ptr();
    576   content::DownloadOpenDelayedCallback callback =
    577       crx_installers_[installer.get()];
    578   crx_installers_.erase(installer.get());
    579   callback.Run(installer->did_handle_successfully());
    580 }
    581