Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / updater / extension_updater.cc
index 9e1201b..c3f5cb4 100644 (file)
@@ -6,9 +6,9 @@
 
 #include <algorithm>
 #include <set>
-#include <vector>
 
 #include "base/bind.h"
+#include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
 #include "chrome/browser/extensions/api/module/module.h"
 #include "chrome/browser/extensions/crx_installer.h"
 #include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/updater/extension_downloader.h"
+#include "chrome/browser/extensions/pending_extension_manager.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/common/pref_names.h"
+#include "components/omaha_query_params/omaha_query_params.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
 #include "crypto/sha2.h"
-#include "extensions/browser/pending_extension_manager.h"
+#include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/extension_registry.h"
 #include "extensions/browser/pref_names.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_set.h"
 #include "extensions/common/manifest.h"
+#include "extensions/common/manifest_constants.h"
 
 using base::RandDouble;
 using base::RandInt;
 using base::Time;
 using base::TimeDelta;
 using content::BrowserThread;
+using extensions::Extension;
+using extensions::ExtensionSet;
+using omaha_query_params::OmahaQueryParams;
 
 typedef extensions::ExtensionDownloaderDelegate::Error Error;
 typedef extensions::ExtensionDownloaderDelegate::PingResult PingResult;
@@ -51,7 +56,7 @@ namespace {
 const int kStartupWaitSeconds = 60 * 5;
 
 // For sanity checking on update frequency - enforced in release mode only.
-#ifdef NDEBUG
+#if defined(NDEBUG)
 const int kMinUpdateFrequencySeconds = 30;
 #endif
 const int kMaxUpdateFrequencySeconds = 60 * 60 * 24 * 7;  // 7 days
@@ -60,6 +65,10 @@ const int kMaxUpdateFrequencySeconds = 60 * 60 * 24 * 7;  // 7 days
 // checks.
 const int kMinUpdateThrottleTime = 5;
 
+// The installsource query parameter to use when forcing updates due to NaCl
+// arch mismatch.
+const char kWrongMultiCrxInstallSource[] = "wrong_multi_crx";
+
 // When we've computed a days value, we want to make sure we don't send a
 // negative value (due to the system clock being set backwards, etc.), since -1
 // is a special sentinel value that means "never pinged", and other negative
@@ -88,6 +97,87 @@ int CalculateActivePingDays(const Time& last_active_ping_day,
   return SanitizeDays((Time::Now() - last_active_ping_day).InDays());
 }
 
+void RespondWithForcedUpdates(
+    const base::Callback<void(const std::set<std::string>&)>& callback,
+    scoped_ptr<std::set<std::string> > forced_updates) {
+  callback.Run(*forced_updates.get());
+}
+
+void DetermineForcedUpdatesOnBlockingPool(
+    scoped_ptr<std::vector<scoped_refptr<const Extension> > > extensions,
+    const base::Callback<void(const std::set<std::string>&)>& callback) {
+  scoped_ptr<std::set<std::string> > forced_updates(
+      new std::set<std::string>());
+  DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
+  for (std::vector<scoped_refptr<const Extension> >::const_iterator iter =
+          extensions->begin();
+       iter != extensions->end();
+       ++iter) {
+    scoped_refptr<const Extension> extension = *iter;
+    base::FilePath platform_specific_path = extension->path().Append(
+        extensions::kPlatformSpecificFolder);
+    if (base::PathExists(platform_specific_path)) {
+      bool force = true;
+      const base::ListValue* platforms;
+      if (extension->manifest()->GetList(extensions::manifest_keys::kPlatforms,
+                                         &platforms)) {
+        for (size_t i = 0; i < platforms->GetSize(); ++i) {
+          const base::DictionaryValue* p;
+          if (platforms->GetDictionary(i, &p)) {
+            std::string nacl_arch;
+            if (p->GetString(extensions::manifest_keys::kNaClArch,
+                             &nacl_arch) &&
+                nacl_arch == OmahaQueryParams::GetNaclArch()) {
+              std::string subpath;
+              if (p->GetString(extensions::manifest_keys::kSubPackagePath,
+                               &subpath)) {
+                // _platform_specific is part of the sub_package_path entry.
+                base::FilePath platform_specific_subpath =
+                    extension->path().AppendASCII(subpath);
+                if (base::PathExists(platform_specific_subpath)) {
+                  force = false;
+                }
+              }
+            }
+          }
+        }
+      }
+
+      if (force)
+        forced_updates->insert(extension->id());
+   }
+  }
+  BrowserThread::PostTask(
+      BrowserThread::UI,
+      FROM_HERE,
+      base::Bind(&RespondWithForcedUpdates,
+                 callback,
+                 base::Passed(&forced_updates)));
+}
+
+void CollectExtensionsFromSet(
+    const ExtensionSet& extensions,
+    std::vector<scoped_refptr<const Extension> >* paths) {
+  std::copy(extensions.begin(), extensions.end(), std::back_inserter(*paths));
+}
+
+void DetermineForcedUpdates(
+    content::BrowserContext* browser_context,
+    const base::Callback<void(const std::set<std::string>&)>& callback) {
+  scoped_ptr<std::vector<scoped_refptr<const Extension> > > extensions(
+      new std::vector<scoped_refptr<const Extension> >());
+  const extensions::ExtensionRegistry* registry =
+      extensions::ExtensionRegistry::Get(browser_context);
+  scoped_ptr<ExtensionSet> installed_extensions =
+      registry->GenerateInstalledExtensionsSet();
+  CollectExtensionsFromSet(*installed_extensions.get(), extensions.get());
+  BrowserThread::PostBlockingPoolTask(
+      FROM_HERE,
+      base::Bind(&DetermineForcedUpdatesOnBlockingPool,
+                 base::Passed(&extensions),
+                 callback));
+}
+
 }  // namespace
 
 namespace extensions {
@@ -101,16 +191,14 @@ ExtensionUpdater::FetchedCRXFile::FetchedCRXFile(
     const std::string& i,
     const base::FilePath& p,
     bool file_ownership_passed,
-    const GURL& u,
     const std::set<int>& request_ids)
     : extension_id(i),
       path(p),
       file_ownership_passed(file_ownership_passed),
-      download_url(u),
       request_ids(request_ids) {}
 
 ExtensionUpdater::FetchedCRXFile::FetchedCRXFile()
-    : path(), file_ownership_passed(true), download_url() {}
+    : path(), file_ownership_passed(true) {}
 
 ExtensionUpdater::FetchedCRXFile::~FetchedCRXFile() {}
 
@@ -130,36 +218,48 @@ struct ExtensionUpdater::ThrottleInfo {
   Time check_start;
 };
 
-ExtensionUpdater::ExtensionUpdater(ExtensionServiceInterface* service,
-                                   ExtensionPrefs* extension_prefs,
-                                   PrefService* prefs,
-                                   Profile* profile,
-                                   int frequency_seconds,
-                                   ExtensionCache* cache)
+ExtensionUpdater::ExtensionUpdater(
+    ExtensionServiceInterface* service,
+    ExtensionPrefs* extension_prefs,
+    PrefService* prefs,
+    Profile* profile,
+    int frequency_seconds,
+    ExtensionCache* cache,
+    const ExtensionDownloader::Factory& downloader_factory)
     : alive_(false),
-      weak_ptr_factory_(this),
-      service_(service), frequency_seconds_(frequency_seconds),
-      will_check_soon_(false), extension_prefs_(extension_prefs),
-      prefs_(prefs), profile_(profile),
+      service_(service),
+      downloader_factory_(downloader_factory),
+      frequency_seconds_(frequency_seconds),
+      will_check_soon_(false),
+      extension_prefs_(extension_prefs),
+      prefs_(prefs),
+      profile_(profile),
       next_request_id_(0),
+      extension_registry_observer_(this),
       crx_install_is_running_(false),
-      extension_cache_(cache) {
+      extension_cache_(cache),
+      weak_ptr_factory_(this) {
   DCHECK_GE(frequency_seconds_, 5);
   DCHECK_LE(frequency_seconds_, kMaxUpdateFrequencySeconds);
-#ifdef NDEBUG
+#if defined(NDEBUG)
   // In Release mode we enforce that update checks don't happen too often.
   frequency_seconds_ = std::max(frequency_seconds_, kMinUpdateFrequencySeconds);
 #endif
   frequency_seconds_ = std::min(frequency_seconds_, kMaxUpdateFrequencySeconds);
 
-  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
-                 content::NotificationService::AllBrowserContextsAndSources());
+  extension_registry_observer_.Add(ExtensionRegistry::Get(profile));
 }
 
 ExtensionUpdater::~ExtensionUpdater() {
   Stop();
 }
 
+void ExtensionUpdater::EnsureDownloaderCreated() {
+  if (!downloader_.get()) {
+    downloader_ = downloader_factory_.Run(this);
+  }
+}
+
 // The overall goal here is to balance keeping clients up to date while
 // avoiding a thundering herd against update servers.
 TimeDelta ExtensionUpdater::DetermineFirstCheckDelay() {
@@ -192,12 +292,13 @@ TimeDelta ExtensionUpdater::DetermineFirstCheckDelay() {
                                           kStartupWaitSeconds * 8));
   }
 
-  // Read the persisted next check time, and use that if it isn't too soon.
-  // Otherwise pick something random.
+  // Read the persisted next check time, and use that if it isn't too soon
+  // or too late. Otherwise pick something random.
   Time saved_next = Time::FromInternalValue(prefs_->GetInt64(
       pref_names::kNextUpdateCheck));
   Time earliest = now + TimeDelta::FromSeconds(kStartupWaitSeconds);
-  if (saved_next >= earliest) {
+  Time latest = now + TimeDelta::FromSeconds(frequency_seconds_);
+  if (saved_next >= earliest && saved_next <= latest) {
     return saved_next - now;
   } else {
     return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds,
@@ -293,6 +394,11 @@ bool ExtensionUpdater::WillCheckSoon() const {
   return will_check_soon_;
 }
 
+void ExtensionUpdater::SetExtensionCacheForTesting(
+    ExtensionCache* extension_cache) {
+  extension_cache_ = extension_cache;
+}
+
 void ExtensionUpdater::DoCheckSoon() {
   DCHECK(will_check_soon_);
   CheckNow(default_params_);
@@ -324,6 +430,16 @@ void ExtensionUpdater::AddToDownloader(
 }
 
 void ExtensionUpdater::CheckNow(const CheckParams& params) {
+  DetermineForcedUpdates(
+      profile_,
+      base::Bind(&ExtensionUpdater::OnForcedUpdatesDetermined,
+                 weak_ptr_factory_.GetWeakPtr(),
+                 params));
+}
+
+void ExtensionUpdater::OnForcedUpdatesDetermined(
+    const CheckParams& params,
+    const std::set<std::string>& forced_updates) {
   int request_id = next_request_id_++;
 
   VLOG(2) << "Starting update check " << request_id;
@@ -336,10 +452,9 @@ void ExtensionUpdater::CheckNow(const CheckParams& params) {
   request.callback = params.callback;
   request.install_immediately = params.install_immediately;
 
-  if (!downloader_.get()) {
-    downloader_.reset(
-        new ExtensionDownloader(this, profile_->GetRequestContext()));
-  }
+  EnsureDownloaderCreated();
+
+  forced_updates_ = forced_updates;
 
   // Add fetch records for extensions that should be fetched by an update URL.
   // These extensions are not yet installed. They come from group policy
@@ -366,8 +481,9 @@ void ExtensionUpdater::CheckNow(const CheckParams& params) {
         request.in_progress_ids_.push_back(*iter);
     }
 
-    AddToDownloader(service_->extensions(), pending_ids, request_id);
-    AddToDownloader(service_->disabled_extensions(), pending_ids, request_id);
+    ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
+    AddToDownloader(&registry->enabled_extensions(), pending_ids, request_id);
+    AddToDownloader(&registry->disabled_extensions(), pending_ids, request_id);
   } else {
     for (std::list<std::string>::const_iterator it = params.ids.begin();
          it != params.ids.end(); ++it) {
@@ -482,8 +598,7 @@ void ExtensionUpdater::OnExtensionDownloadFinished(
 
   VLOG(2) << download_url << " written to " << path.value();
 
-  FetchedCRXFile fetched(id, path, file_ownership_passed, download_url,
-                         request_ids);
+  FetchedCRXFile fetched(id, path, file_ownership_passed, request_ids);
   fetched_crx_files_.push(fetched);
 
   // MaybeInstallCRXFile() removes extensions from |in_progress_ids_| after
@@ -498,6 +613,8 @@ bool ExtensionUpdater::GetPingDataForExtension(
   ping_data->rollcall_days = CalculatePingDays(
       extension_prefs_->LastPingDay(id));
   ping_data->is_enabled = service_->IsExtensionEnabled(id);
+  if (!ping_data->is_enabled)
+    ping_data->disable_reasons = extension_prefs_->GetDisableReasons(id);
   ping_data->active_days =
       CalculateActivePingDays(extension_prefs_->LastActivePingDay(id),
                               extension_prefs_->GetActiveBit(id));
@@ -528,6 +645,18 @@ bool ExtensionUpdater::GetExtensionExistingVersion(const std::string& id,
   return true;
 }
 
+bool ExtensionUpdater::ShouldForceUpdate(
+    const std::string& extension_id,
+    std::string* source) {
+  bool force = forced_updates_.find(extension_id) != forced_updates_.end();
+  // Currently the only reason to force is a NaCl arch mismatch with the
+  // installed extension contents.
+  if (force) {
+    *source = kWrongMultiCrxInstallSource;
+  }
+  return force;
+}
+
 void ExtensionUpdater::UpdatePingData(const std::string& id,
                                       const PingResult& ping_result) {
   DCHECK(alive_);
@@ -557,7 +686,6 @@ void ExtensionUpdater::MaybeInstallCRXFile() {
     if (service_->UpdateExtension(crx_file.extension_id,
                                   crx_file.path,
                                   crx_file.file_ownership_passed,
-                                  crx_file.download_url,
                                   &installer)) {
       crx_install_is_running_ = true;
       current_crx_file_ = crx_file;
@@ -566,7 +694,7 @@ void ExtensionUpdater::MaybeInstallCRXFile() {
           it != crx_file.request_ids.end(); ++it) {
         InProgressCheck& request = requests_in_progress_[*it];
         if (request.install_immediately) {
-          installer->set_install_wait_for_idle(false);
+          installer->set_install_immediately(true);
           break;
         }
       }
@@ -574,7 +702,7 @@ void ExtensionUpdater::MaybeInstallCRXFile() {
       // Source parameter ensures that we only see the completion event for the
       // the installer we started.
       registrar_.Add(this,
-                     chrome::NOTIFICATION_CRX_INSTALLER_DONE,
+                     extensions::NOTIFICATION_CRX_INSTALLER_DONE,
                      content::Source<CrxInstaller>(installer));
     } else {
       for (std::set<int>::const_iterator it = crx_file.request_ids.begin();
@@ -597,41 +725,35 @@ void ExtensionUpdater::MaybeInstallCRXFile() {
 void ExtensionUpdater::Observe(int type,
                                const content::NotificationSource& source,
                                const content::NotificationDetails& details) {
-  switch (type) {
-    case chrome::NOTIFICATION_CRX_INSTALLER_DONE: {
-      // No need to listen for CRX_INSTALLER_DONE anymore.
-      registrar_.Remove(this,
-                        chrome::NOTIFICATION_CRX_INSTALLER_DONE,
-                        source);
-      crx_install_is_running_ = false;
-
-      const FetchedCRXFile& crx_file = current_crx_file_;
-      for (std::set<int>::const_iterator it = crx_file.request_ids.begin();
-          it != crx_file.request_ids.end(); ++it) {
-        InProgressCheck& request = requests_in_progress_[*it];
-        request.in_progress_ids_.remove(crx_file.extension_id);
-        NotifyIfFinished(*it);
-      }
+  DCHECK_EQ(type, extensions::NOTIFICATION_CRX_INSTALLER_DONE);
 
-      // If any files are available to update, start one.
-      MaybeInstallCRXFile();
-      break;
-    }
-    case chrome::NOTIFICATION_EXTENSION_INSTALLED: {
-      const Extension* extension =
-          content::Details<const InstalledExtensionInfo>(details)->extension;
-      if (extension)
-        throttle_info_.erase(extension->id());
-      break;
-    }
-    default:
-      NOTREACHED();
+  registrar_.Remove(this, extensions::NOTIFICATION_CRX_INSTALLER_DONE, source);
+  crx_install_is_running_ = false;
+
+  const FetchedCRXFile& crx_file = current_crx_file_;
+  for (std::set<int>::const_iterator it = crx_file.request_ids.begin();
+      it != crx_file.request_ids.end(); ++it) {
+    InProgressCheck& request = requests_in_progress_[*it];
+    request.in_progress_ids_.remove(crx_file.extension_id);
+    NotifyIfFinished(*it);
   }
+
+  // If any files are available to update, start one.
+  MaybeInstallCRXFile();
+}
+
+void ExtensionUpdater::OnExtensionWillBeInstalled(
+    content::BrowserContext* browser_context,
+    const Extension* extension,
+    bool is_update,
+    bool from_ephemeral,
+    const std::string& old_name) {
+  throttle_info_.erase(extension->id());
 }
 
 void ExtensionUpdater::NotifyStarted() {
   content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_EXTENSION_UPDATING_STARTED,
+      extensions::NOTIFICATION_EXTENSION_UPDATING_STARTED,
       content::Source<Profile>(profile_),
       content::NotificationService::NoDetails());
 }