15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/webstore_installer.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
78bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include <vector>
88bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/metrics/field_trial.h"
14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/metrics/histogram.h"
15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/metrics/sparse_histogram.h"
16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/path_service.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/rand_util.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
22effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/time/time.h"
237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/download/download_crx_util.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/download/download_prefs.h"
26ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "chrome/browser/download/download_stats.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/crx_installer.h"
28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/extensions/install_tracker.h"
29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/extensions/install_tracker_factory.h"
30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/extensions/install_verifier.h"
31c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "chrome/browser/extensions/shared_module_service.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_list.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h"
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/common/chrome_paths.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.h"
3703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "components/crx_file/id_util.h"
38116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "components/omaha_query_params/omaha_query_params.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/download_manager.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/download_save_info.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/download_url_parameters.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/navigation_controller.h"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/navigation_entry.h"
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_details.h"
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h"
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_source.h"
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/render_process_host.h"
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/render_view_host.h"
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h"
51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/browser/extension_registry.h"
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system.h"
53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/common/extension_urls.h"
553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "extensions/common/manifest_constants.h"
56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/manifest_handlers/shared_module_info.h"
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/escape.h"
587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_CHROMEOS)
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/drive/file_system_util.h"
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserContext;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::DownloadItem;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::DownloadManager;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::NavigationController;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::DownloadUrlParameters;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Key used to attach the Approval to the DownloadItem.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kApprovalKey[] = "extensions.webstore_installer";
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kInvalidIdError[] = "Invalid id";
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kDownloadDirectoryError[] = "Could not create download directory";
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kDownloadCanceledError[] = "Download canceled";
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kDownloadInterruptedError[] = "Download interrupted";
80a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)const char kInvalidDownloadError[] =
81a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    "Download was not a valid extension or user script";
828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)const char kDependencyNotFoundError[] = "Dependency not found";
838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)const char kDependencyNotSharedModuleError[] =
84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    "Dependency is not shared module";
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kInlineInstallSource[] = "inline";
86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst char kDefaultInstallSource[] = "ondemand";
8768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kAppLauncherInstallSource[] = "applauncher";
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
890de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)// TODO(rockot): Share this duplicated constant with the extension updater.
900de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)// See http://crbug.com/371398.
910de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)const char kAuthUserQueryKey[] = "authuser";
920de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
93effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochconst size_t kTimeRemainingMinutesThreshold = 1u;
94effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
95f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Folder for downloading crx files from the webstore. This is used so that the
96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// crx files don't go via the usual downloads folder.
97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const base::FilePath::CharType kWebstoreDownloadFolder[] =
98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    FILE_PATH_LITERAL("Webstore Downloads");
99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath* g_download_directory_for_tests = NULL;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Must be executed on the FILE thread.
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GetDownloadFilePath(
104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const base::FilePath& download_directory,
105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const std::string& id,
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::Callback<void(const base::FilePath&)>& callback) {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ensure the download directory exists. TODO(asargent) - make this use
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // common code from the downloads system.
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!base::DirectoryExists(download_directory)) {
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!base::CreateDirectory(download_directory)) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              base::Bind(callback, base::FilePath()));
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is to help avoid a race condition between when we generate this
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // filename and when the download starts writing to it (think concurrently
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // running sharded browser tests installing the same test file, for
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // instance).
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string random_number =
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Uint64ToString(base::RandGenerator(kuint16max));
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath file =
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      download_directory.AppendASCII(id + "_" + random_number + ".crx");
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int uniquifier =
128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::GetUniquePathNumber(file, base::FilePath::StringType());
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (uniquifier > 0) {
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    file = file.InsertBeforeExtensionASCII(
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::StringPrintf(" (%d)", uniquifier));
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          base::Bind(callback, file));
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1380de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)void MaybeAppendAuthUserParameter(const std::string& authuser, GURL* url) {
1390de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  if (authuser.empty())
1400de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    return;
1410de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  std::string old_query = url->query();
1420de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  url::Component query(0, old_query.length());
1430de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  url::Component key, value;
1440de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  // Ensure that the URL doesn't already specify an authuser parameter.
1450de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  while (url::ExtractQueryKeyValue(
1460de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)             old_query.c_str(), &query, &key, &value)) {
1470de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    std::string key_string = old_query.substr(key.begin, key.len);
1480de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    if (key_string == kAuthUserQueryKey) {
1490de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      return;
1500de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    }
1510de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  }
1520de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  if (!old_query.empty()) {
1530de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    old_query += "&";
1540de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  }
1550de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  std::string authuser_param = base::StringPrintf(
1560de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      "%s=%s",
1570de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      kAuthUserQueryKey,
1580de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      authuser.c_str());
1590de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
1600de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  // TODO(rockot): Share this duplicated code with the extension updater.
1610de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  // See http://crbug.com/371398.
1620de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  std::string new_query_string = old_query + authuser_param;
1630de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  url::Component new_query(0, new_query_string.length());
1640de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  url::Replacements<char> replacements;
1650de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  replacements.SetQuery(new_query_string.c_str(), new_query);
1660de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  *url = url->ReplaceComponents(replacements);
1670de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)}
1680de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions {
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// static
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)GURL WebstoreInstaller::GetWebstoreInstallURL(
175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const std::string& extension_id,
176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    InstallSource source) {
1778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  std::string install_source;
1788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  switch (source) {
1798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    case INSTALL_SOURCE_INLINE:
1808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      install_source = kInlineInstallSource;
1818bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      break;
1828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    case INSTALL_SOURCE_APP_LAUNCHER:
1838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      install_source = kAppLauncherInstallSource;
1848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      break;
1858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    case INSTALL_SOURCE_OTHER:
1868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      install_source = kDefaultInstallSource;
1878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
1888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CommandLine* cmd_line = CommandLine::ForCurrentProcess();
190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (cmd_line->HasSwitch(switches::kAppsGalleryDownloadURL)) {
191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::string download_url =
192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        cmd_line->GetSwitchValueASCII(switches::kAppsGalleryDownloadURL);
193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return GURL(base::StringPrintf(download_url.c_str(),
194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                   extension_id.c_str()));
195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::vector<std::string> params;
197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  params.push_back("id=" + extension_id);
198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!install_source.empty())
199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    params.push_back("installsource=" + install_source);
200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  params.push_back("uc");
201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string url_string = extension_urls::GetWebstoreUpdateUrl().spec();
202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GURL url(url_string + "?response=redirect&" +
204116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch           omaha_query_params::OmahaQueryParams::Get(
205116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch               omaha_query_params::OmahaQueryParams::CRX) +
206116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch           "&x=" + net::EscapeQueryParamValue(JoinString(params, '&'), true));
207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(url.is_valid());
208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return url;
210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebstoreInstaller::Delegate::OnExtensionDownloadStarted(
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& id,
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::DownloadItem* item) {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebstoreInstaller::Delegate::OnExtensionDownloadProgress(
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& id,
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::DownloadItem* item) {
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebstoreInstaller::Approval::Approval()
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : profile(NULL),
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      use_app_installed_bubble(false),
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      skip_post_install_ui(false),
2267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      skip_install_dialog(false),
227424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      enable_launcher(false),
228f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      manifest_check_level(MANIFEST_CHECK_LEVEL_STRICT),
229f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      is_ephemeral(false) {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<WebstoreInstaller::Approval>
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebstoreInstaller::Approval::CreateWithInstallPrompt(Profile* profile) {
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<Approval> result(new Approval());
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result->profile = profile;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result.Pass();
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<WebstoreInstaller::Approval>
2408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)WebstoreInstaller::Approval::CreateForSharedModule(Profile* profile) {
2418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  scoped_ptr<Approval> result(new Approval());
2428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  result->profile = profile;
2438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  result->skip_install_dialog = true;
244116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  result->skip_post_install_ui = true;
2458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  result->manifest_check_level = MANIFEST_CHECK_LEVEL_NONE;
2468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return result.Pass();
2478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
2488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)scoped_ptr<WebstoreInstaller::Approval>
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Profile* profile,
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& extension_id,
253424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    scoped_ptr<base::DictionaryValue> parsed_manifest,
254424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    bool strict_manifest_check) {
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<Approval> result(new Approval());
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result->extension_id = extension_id;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result->profile = profile;
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result->manifest = scoped_ptr<Manifest>(
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new Manifest(Manifest::INVALID_LOCATION,
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   scoped_ptr<base::DictionaryValue>(
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       parsed_manifest->DeepCopy())));
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result->skip_install_dialog = true;
2638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  result->manifest_check_level = strict_manifest_check ?
2648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    MANIFEST_CHECK_LEVEL_STRICT : MANIFEST_CHECK_LEVEL_LOOSE;
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result.Pass();
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebstoreInstaller::Approval::~Approval() {}
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const WebstoreInstaller::Approval* WebstoreInstaller::GetAssociatedApproval(
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const DownloadItem& download) {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return static_cast<const Approval*>(download.GetUserData(kApprovalKey));
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebstoreInstaller::WebstoreInstaller(Profile* profile,
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     Delegate* delegate,
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     content::WebContents* web_contents,
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     const std::string& id,
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     scoped_ptr<Approval> approval,
28068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                     InstallSource source)
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : content::WebContentsObserver(web_contents),
282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      extension_registry_observer_(this),
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      profile_(profile),
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate_(delegate),
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      id_(id),
2868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      install_source_(source),
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      download_item_(NULL),
2888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      approval_(approval.release()),
2898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      total_modules_(0),
2908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      download_started_(false) {
291effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(web_contents);
29368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
2945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  registrar_.Add(this,
2955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 extensions::NOTIFICATION_EXTENSION_INSTALL_ERROR,
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 content::Source<CrxInstaller>(NULL));
297cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  extension_registry_observer_.Add(ExtensionRegistry::Get(profile));
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebstoreInstaller::Start() {
301effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddRef();  // Balanced in ReportSuccess and ReportFailure.
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!crx_file::id_util::IdIsValid(id_)) {
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReportFailure(kInvalidIdError, FAILURE_REASON_OTHER);
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3098bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  ExtensionService* extension_service =
3108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    ExtensionSystem::Get(profile_)->extension_service();
3111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (approval_.get() && approval_->dummy_extension.get()) {
3121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    extension_service->shared_module_service()->CheckImports(
3131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        approval_->dummy_extension.get(), &pending_modules_, &pending_modules_);
3141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Do not check the return value of CheckImports, the CRX installer
3151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // will report appropriate error messages and fail to install if there
3161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // is an import error.
3178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
3188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
3198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Add the extension main module into the list.
3208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  SharedModuleInfo::ImportInfo info;
3218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  info.extension_id = id_;
3228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  pending_modules_.push_back(info);
3238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
3248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  total_modules_ = pending_modules_.size();
3258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
326f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  std::set<std::string> ids;
327f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  std::list<SharedModuleInfo::ImportInfo>::const_iterator i;
328f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (i = pending_modules_.begin(); i != pending_modules_.end(); ++i) {
329f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ids.insert(i->extension_id);
330f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
331f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ExtensionSystem::Get(profile_)->install_verifier()->AddProvisional(ids);
332f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
333eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string name;
3343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!approval_->manifest->value()->GetString(manifest_keys::kName, &name)) {
335eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    NOTREACHED();
336eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
337eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  extensions::InstallTracker* tracker =
3385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      extensions::InstallTrackerFactory::GetForBrowserContext(profile_);
339f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  extensions::InstallObserver::ExtensionInstallParams params(
340f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      id_,
341f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      name,
342f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      approval_->installing_icon,
343f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      approval_->manifest->is_app(),
344eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      approval_->manifest->is_platform_app());
345f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  params.is_ephemeral = approval_->is_ephemeral;
346f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  tracker->OnBeginExtensionInstall(params);
347effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
348effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  tracker->OnBeginExtensionDownload(id_);
349effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
350effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // TODO(crbug.com/305343): Query manifest of dependencies before
351effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // downloading & installing those dependencies.
352effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DownloadNextPendingModule();
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebstoreInstaller::Observe(int type,
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const content::NotificationSource& source,
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const content::NotificationDetails& details) {
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (type) {
3595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case extensions::NOTIFICATION_EXTENSION_INSTALL_ERROR: {
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CrxInstaller* crx_installer = content::Source<CrxInstaller>(source).ptr();
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CHECK(crx_installer);
3620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      if (crx_installer != crx_installer_.get())
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(rdevlin.cronin): Continue removing std::string errors and
366a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // replacing with base::string16. See crbug.com/71980.
367a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const base::string16* error =
368a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          content::Details<const base::string16>(details).ptr();
3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const std::string utf8_error = base::UTF16ToUTF8(*error);
3700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      crx_installer_ = NULL;
3710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      // ReportFailure releases a reference to this object so it must be the
3720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      // last operation in this method.
3730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      ReportFailure(utf8_error, FAILURE_REASON_OTHER);
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
382f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void WebstoreInstaller::OnExtensionInstalled(
383cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    content::BrowserContext* browser_context,
384116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const Extension* extension,
385116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    bool is_update) {
386cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  CHECK(profile_->IsSameProfile(Profile::FromBrowserContext(browser_context)));
387cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (pending_modules_.empty())
388cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
389cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SharedModuleInfo::ImportInfo info = pending_modules_.front();
390cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (extension->id() != info.extension_id)
391cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
392cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  pending_modules_.pop_front();
393cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
394116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Clean up local state from the current download.
395116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (download_item_) {
396116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    download_item_->RemoveObserver(this);
397116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    download_item_->Remove();
398116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    download_item_ = NULL;
399116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
400116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  crx_installer_ = NULL;
401116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
402cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (pending_modules_.empty()) {
403cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    CHECK_EQ(extension->id(), id_);
404cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ReportSuccess();
405cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else {
406cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const Version version_required(info.minimum_version);
407cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (version_required.IsValid() &&
408cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        extension->version()->CompareTo(version_required) < 0) {
409cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      // It should not happen, CrxInstaller will make sure the version is
410cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      // equal or newer than version_required.
411cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ReportFailure(kDependencyNotFoundError,
412cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                    FAILURE_REASON_DEPENDENCY_NOT_FOUND);
413cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    } else if (!SharedModuleInfo::IsSharedModule(extension)) {
414cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      // It should not happen, CrxInstaller will make sure it is a shared
415cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      // module.
416cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ReportFailure(kDependencyNotSharedModuleError,
417cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                    FAILURE_REASON_DEPENDENCY_NOT_SHARED_MODULE);
418cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    } else {
419cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      DownloadNextPendingModule();
420cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
421cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
422cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
423cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebstoreInstaller::InvalidateDelegate() {
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_ = NULL;
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WebstoreInstaller::SetDownloadDirectoryForTests(
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath* directory) {
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_download_directory_for_tests = directory;
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebstoreInstaller::~WebstoreInstaller() {
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (download_item_) {
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    download_item_->RemoveObserver(this);
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    download_item_ = NULL;
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebstoreInstaller::OnDownloadStarted(
4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DownloadItem* item,
4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    content::DownloadInterruptReason interrupt_reason) {
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!item) {
4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK_NE(content::DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason);
4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ReportFailure(content::DownloadInterruptReasonToString(interrupt_reason),
4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  FAILURE_REASON_OTHER);
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(content::DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason);
4518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(!pending_modules_.empty());
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  download_item_ = item;
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  download_item_->AddObserver(this);
4548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (pending_modules_.size() > 1) {
4558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    // We are downloading a shared module. We need create an approval for it.
4568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    scoped_ptr<Approval> approval = Approval::CreateForSharedModule(profile_);
4578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    const SharedModuleInfo::ImportInfo& info = pending_modules_.front();
4588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    approval->extension_id = info.extension_id;
4598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    const Version version_required(info.minimum_version);
4608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
4618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (version_required.IsValid()) {
4628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      approval->minimum_version.reset(
4638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          new Version(version_required));
4648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    }
4658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    download_item_->SetUserData(kApprovalKey, approval.release());
4668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  } else {
4678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    // It is for the main module of the extension. We should use the provided
4688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    // |approval_|.
4698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (approval_)
4708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      download_item_->SetUserData(kApprovalKey, approval_.release());
4718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
4728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
4738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!download_started_) {
4748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (delegate_)
4758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      delegate_->OnExtensionDownloadStarted(id_, download_item_);
4768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    download_started_ = true;
4778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebstoreInstaller::OnDownloadUpdated(DownloadItem* download) {
481116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  CHECK_EQ(download_item_, download);
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (download->GetState()) {
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case DownloadItem::CANCELLED:
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReportFailure(kDownloadCanceledError, FAILURE_REASON_CANCELLED);
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case DownloadItem::INTERRUPTED:
488f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      RecordInterrupt(download);
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReportFailure(kDownloadInterruptedError, FAILURE_REASON_OTHER);
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case DownloadItem::COMPLETE:
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Wait for other notifications if the download is really an extension.
493eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (!download_crx_util::IsExtensionDownload(*download)) {
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ReportFailure(kInvalidDownloadError, FAILURE_REASON_OTHER);
4950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      } else {
4960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        if (crx_installer_.get())
4970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          return;  // DownloadItemImpl calls the observer twice, ignore it.
4980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        StartCrxInstaller(*download);
4990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
500116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        if (pending_modules_.size() == 1) {
5010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          // The download is the last module - the extension main module.
5020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          if (delegate_)
5030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            delegate_->OnExtensionDownloadProgress(id_, download);
5040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          extensions::InstallTracker* tracker =
5055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)              extensions::InstallTrackerFactory::GetForBrowserContext(profile_);
5060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          tracker->OnDownloadProgress(id_, 100);
5070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        }
508eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      }
509effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      // Stop the progress timer if it's running.
510effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      download_progress_timer_.Stop();
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
512eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    case DownloadItem::IN_PROGRESS: {
5138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      if (delegate_ && pending_modules_.size() == 1) {
5148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        // Only report download progress for the main module to |delegrate_|.
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        delegate_->OnExtensionDownloadProgress(id_, download);
5168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      }
517effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      UpdateDownloadProgress();
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
519eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Continue listening if the download is not in one of the above states.
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebstoreInstaller::OnDownloadDestroyed(DownloadItem* download) {
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_EQ(download_item_, download);
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  download_item_->RemoveObserver(this);
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  download_item_ = NULL;
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void WebstoreInstaller::DownloadNextPendingModule() {
5338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  CHECK(!pending_modules_.empty());
5348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (pending_modules_.size() == 1) {
5358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    DCHECK_EQ(id_, pending_modules_.front().extension_id);
5368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    DownloadCrx(id_, install_source_);
5378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  } else {
5388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    DownloadCrx(pending_modules_.front().extension_id, INSTALL_SOURCE_OTHER);
5398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
5408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
5418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
5428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void WebstoreInstaller::DownloadCrx(
543f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const std::string& extension_id,
544f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    InstallSource source) {
5458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  download_url_ = GetWebstoreInstallURL(extension_id, source);
5460de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  MaybeAppendAuthUserParameter(approval_->authuser, &download_url_);
547f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
548cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::FilePath user_data_dir;
549cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
550cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::FilePath download_path = user_data_dir.Append(kWebstoreDownloadFolder);
551f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
5525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::FilePath download_directory(g_download_directory_for_tests ?
5535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      *g_download_directory_for_tests : download_path);
5545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_CHROMEOS)
5565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Do not use drive for extension downloads.
5575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (drive::util::IsUnderDriveMountPoint(download_directory)) {
5585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    download_directory = DownloadPrefs::FromBrowserContext(
5595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        profile_)->GetDefaultDownloadDirectoryForProfile();
5605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
5625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  BrowserThread::PostTask(
5648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      BrowserThread::FILE, FROM_HERE,
565116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::Bind(&GetDownloadFilePath, download_directory, extension_id,
5668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        base::Bind(&WebstoreInstaller::StartDownload, this)));
5678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
5688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// http://crbug.com/165634
5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// http://crbug.com/126013
5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The current working theory is that one of the many pointers dereferenced in
5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// here is occasionally deleted before all of its referers are nullified,
5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// probably in a callback race. After this comment is released, the crash
5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// reports should narrow down exactly which pointer it is.  Collapsing all the
5752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// early-returns into a single branch makes it hard to see exactly which pointer
5762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// it is.
5772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WebstoreInstaller::StartDownload(const base::FilePath& file) {
578effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (file.empty()) {
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ReportFailure(kDownloadDirectoryError, FAILURE_REASON_OTHER);
5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DownloadManager* download_manager =
5865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      BrowserContext::GetDownloadManager(profile_);
5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!download_manager) {
5882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ReportFailure(kDownloadDirectoryError, FAILURE_REASON_OTHER);
5892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
5902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  content::WebContents* contents = web_contents();
5935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!contents) {
5942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ReportFailure(kDownloadDirectoryError, FAILURE_REASON_OTHER);
5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
5962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!contents->GetRenderProcessHost()) {
5982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ReportFailure(kDownloadDirectoryError, FAILURE_REASON_OTHER);
5992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
6002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!contents->GetRenderViewHost()) {
6022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ReportFailure(kDownloadDirectoryError, FAILURE_REASON_OTHER);
6032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
6042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  content::NavigationController& controller = contents->GetController();
6075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!controller.GetBrowserContext()) {
6082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ReportFailure(kDownloadDirectoryError, FAILURE_REASON_OTHER);
6092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
6102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!controller.GetBrowserContext()->GetResourceContext()) {
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReportFailure(kDownloadDirectoryError, FAILURE_REASON_OTHER);
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The download url for the given extension is contained in |download_url_|.
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We will navigate the current tab to this url to start the download. The
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // download system will then pass the crx to the CrxInstaller.
619ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  RecordDownloadSource(DOWNLOAD_INITIATED_BY_WEBSTORE_INSTALLER);
6205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int render_process_host_id = contents->GetRenderProcessHost()->GetID();
6212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int render_view_host_routing_id =
6225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      contents->GetRenderViewHost()->GetRoutingID();
6232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  content::ResourceContext* resource_context =
6245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      controller.GetBrowserContext()->GetResourceContext();
6252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<DownloadUrlParameters> params(new DownloadUrlParameters(
6262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      download_url_,
6272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      render_process_host_id,
6282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      render_view_host_routing_id ,
6292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      resource_context));
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params->set_file_path(file);
6315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (controller.GetVisibleEntry())
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    params->set_referrer(
6335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        content::Referrer(controller.GetVisibleEntry()->GetURL(),
634f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                          blink::WebReferrerPolicyDefault));
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params->set_callback(base::Bind(&WebstoreInstaller::OnDownloadStarted, this));
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  download_manager->DownloadUrl(params.Pass());
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
639effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid WebstoreInstaller::UpdateDownloadProgress() {
640effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // If the download has gone away, or isn't in progress (in which case we can't
641effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // give a good progress estimate), stop any running timers and return.
642effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!download_item_ ||
643effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      download_item_->GetState() != DownloadItem::IN_PROGRESS) {
644effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    download_progress_timer_.Stop();
645effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
646effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
647effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
648effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  int percent = download_item_->PercentComplete();
649116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Only report progress if percent is more than 0 or we have finished
650116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // downloading at least one of the pending modules.
651116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  int finished_modules = total_modules_ - pending_modules_.size();
652116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (finished_modules > 0 && percent < 0)
653116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    percent = 0;
654effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (percent >= 0) {
655effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    percent = (percent + (finished_modules * 100)) / total_modules_;
656effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    extensions::InstallTracker* tracker =
6575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        extensions::InstallTrackerFactory::GetForBrowserContext(profile_);
658effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    tracker->OnDownloadProgress(id_, percent);
659effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
660effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
661effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // If there's enough time remaining on the download to warrant an update,
662effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // set the timer (overwriting any current timers). Otherwise, stop the
663effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // timer.
664effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  base::TimeDelta time_remaining;
665effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (download_item_->TimeRemaining(&time_remaining) &&
666effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      time_remaining >
667effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          base::TimeDelta::FromSeconds(kTimeRemainingMinutesThreshold)) {
668effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    download_progress_timer_.Start(
669effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        FROM_HERE,
670effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        base::TimeDelta::FromSeconds(kTimeRemainingMinutesThreshold),
671effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        this,
672effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        &WebstoreInstaller::UpdateDownloadProgress);
673effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  } else {
674effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    download_progress_timer_.Stop();
675effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
676effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
677effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
6780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid WebstoreInstaller::StartCrxInstaller(const DownloadItem& download) {
6790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(!crx_installer_.get());
6810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
6820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  ExtensionService* service = ExtensionSystem::Get(profile_)->
6830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      extension_service();
6840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  CHECK(service);
6850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
6860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  const Approval* approval = GetAssociatedApproval(download);
6870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(approval);
6880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
6890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  crx_installer_ = download_crx_util::CreateCrxInstaller(profile_, download);
6900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
6910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  crx_installer_->set_expected_id(approval->extension_id);
6920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  crx_installer_->set_is_gallery_install(true);
6930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  crx_installer_->set_allow_silent_install(true);
6940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
6950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  crx_installer_->InstallCrx(download.GetFullPath());
6960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
6970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebstoreInstaller::ReportFailure(const std::string& error,
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      FailureReason reason) {
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate_) {
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->OnExtensionInstallFailure(id_, error, reason);
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_ = NULL;
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  extensions::InstallTracker* tracker =
7065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      extensions::InstallTrackerFactory::GetForBrowserContext(profile_);
707eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  tracker->OnInstallFailure(id_);
708eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Release();  // Balanced in Start().
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebstoreInstaller::ReportSuccess() {
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate_) {
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->OnExtensionInstallSuccess(id_);
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_ = NULL;
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Release();  // Balanced in Start().
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
721f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void WebstoreInstaller::RecordInterrupt(const DownloadItem* download) const {
722f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  UMA_HISTOGRAM_SPARSE_SLOWLY("Extensions.WebstoreDownload.InterruptReason",
723f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                              download->GetLastReason());
724f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
725f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Use logarithmic bin sizes up to 1 TB.
726f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const int kNumBuckets = 30;
727f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const int64 kMaxSizeKb = 1 << kNumBuckets;
728f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  UMA_HISTOGRAM_CUSTOM_COUNTS(
729f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      "Extensions.WebstoreDownload.InterruptReceivedKBytes",
730f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      download->GetReceivedBytes() / 1024,
731f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      1,
732f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      kMaxSizeKb,
733f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      kNumBuckets);
734f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int64 total_bytes = download->GetTotalBytes();
735f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (total_bytes >= 0) {
736f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    UMA_HISTOGRAM_CUSTOM_COUNTS(
737f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        "Extensions.WebstoreDownload.InterruptTotalKBytes",
738f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        total_bytes / 1024,
739f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        1,
740f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        kMaxSizeKb,
741f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        kNumBuckets);
742f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
743f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  UMA_HISTOGRAM_BOOLEAN(
744f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      "Extensions.WebstoreDownload.InterruptTotalSizeUnknown",
745f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      total_bytes <= 0);
746f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
747f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace extensions
749