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 #ifndef CHROME_BROWSER_EXTENSIONS_WEBSTORE_INSTALLER_H_ 6 #define CHROME_BROWSER_EXTENSIONS_WEBSTORE_INSTALLER_H_ 7 8 #include <list> 9 #include <string> 10 11 #include "base/compiler_specific.h" 12 #include "base/memory/ref_counted.h" 13 #include "base/memory/scoped_ptr.h" 14 #include "base/scoped_observer.h" 15 #include "base/supports_user_data.h" 16 #include "base/timer/timer.h" 17 #include "base/values.h" 18 #include "base/version.h" 19 #include "chrome/browser/extensions/extension_install_prompt.h" 20 #include "content/public/browser/browser_thread.h" 21 #include "content/public/browser/download_interrupt_reasons.h" 22 #include "content/public/browser/download_item.h" 23 #include "content/public/browser/notification_observer.h" 24 #include "content/public/browser/notification_registrar.h" 25 #include "content/public/browser/web_contents_observer.h" 26 #include "extensions/browser/extension_registry_observer.h" 27 #include "extensions/common/manifest_handlers/shared_module_info.h" 28 #include "ui/gfx/image/image_skia.h" 29 #include "url/gurl.h" 30 31 class Profile; 32 33 namespace base { 34 class FilePath; 35 } 36 37 namespace content { 38 class WebContents; 39 } 40 41 namespace extensions { 42 43 class CrxInstaller; 44 class Extension; 45 class ExtensionRegistry; 46 class Manifest; 47 48 // Downloads and installs extensions from the web store. 49 class WebstoreInstaller : public content::NotificationObserver, 50 public ExtensionRegistryObserver, 51 public content::DownloadItem::Observer, 52 public content::WebContentsObserver, 53 public base::RefCountedThreadSafe< 54 WebstoreInstaller, 55 content::BrowserThread::DeleteOnUIThread> { 56 public: 57 enum InstallSource { 58 // Inline installs trigger slightly different behavior (install source 59 // is different, download referrers are the item's page in the gallery). 60 INSTALL_SOURCE_INLINE, 61 INSTALL_SOURCE_APP_LAUNCHER, 62 INSTALL_SOURCE_OTHER 63 }; 64 65 enum FailureReason { 66 FAILURE_REASON_CANCELLED, 67 FAILURE_REASON_DEPENDENCY_NOT_FOUND, 68 FAILURE_REASON_DEPENDENCY_NOT_SHARED_MODULE, 69 FAILURE_REASON_OTHER 70 }; 71 72 enum ManifestCheckLevel { 73 // Do not check for any manifest equality. 74 MANIFEST_CHECK_LEVEL_NONE, 75 76 // Only check that the expected and actual permissions have the same 77 // effective permissions. 78 MANIFEST_CHECK_LEVEL_LOOSE, 79 80 // All data in the expected and actual manifests must match. 81 MANIFEST_CHECK_LEVEL_STRICT, 82 }; 83 84 class Delegate { 85 public: 86 virtual void OnExtensionDownloadStarted(const std::string& id, 87 content::DownloadItem* item); 88 virtual void OnExtensionDownloadProgress(const std::string& id, 89 content::DownloadItem* item); 90 virtual void OnExtensionInstallSuccess(const std::string& id) = 0; 91 virtual void OnExtensionInstallFailure(const std::string& id, 92 const std::string& error, 93 FailureReason reason) = 0; 94 95 protected: ~Delegate()96 virtual ~Delegate() {} 97 }; 98 99 // Contains information about what parts of the extension install process can 100 // be skipped or modified. If one of these is present, it means that a CRX 101 // download was initiated by WebstoreInstaller. The Approval instance should 102 // be checked further for additional details. 103 struct Approval : public base::SupportsUserData::Data { 104 static scoped_ptr<Approval> CreateWithInstallPrompt(Profile* profile); 105 106 // Creates an Approval for installing a shared module. 107 static scoped_ptr<Approval> CreateForSharedModule(Profile* profile); 108 109 // Creates an Approval that will skip putting up an install confirmation 110 // prompt if the actual manifest from the extension to be installed matches 111 // |parsed_manifest|. The |strict_manifest_check| controls whether we want 112 // to require an exact manifest match, or are willing to tolerate a looser 113 // check just that the effective permissions are the same. 114 static scoped_ptr<Approval> CreateWithNoInstallPrompt( 115 Profile* profile, 116 const std::string& extension_id, 117 scoped_ptr<base::DictionaryValue> parsed_manifest, 118 bool strict_manifest_check); 119 120 virtual ~Approval(); 121 122 // The extension id that was approved for installation. 123 std::string extension_id; 124 125 // The profile the extension should be installed into. 126 Profile* profile; 127 128 // The expected manifest, before localization. 129 scoped_ptr<Manifest> manifest; 130 131 // Whether to use a bubble notification when an app is installed, instead of 132 // the default behavior of transitioning to the new tab page. 133 bool use_app_installed_bubble; 134 135 // Whether to skip the post install UI like the extension installed bubble. 136 bool skip_post_install_ui; 137 138 // Whether to skip the install dialog once the extension has been downloaded 139 // and unpacked. One reason this can be true is that in the normal webstore 140 // installation, the dialog is shown earlier, before any download is done, 141 // so there's no need to show it again. 142 bool skip_install_dialog; 143 144 // Whether we should enable the launcher before installing the app. 145 bool enable_launcher; 146 147 // Manifest check level for checking actual manifest against expected 148 // manifest. 149 ManifestCheckLevel manifest_check_level; 150 151 // Used to show the install dialog. 152 ExtensionInstallPrompt::ShowDialogCallback show_dialog_callback; 153 154 // The icon to use to display the extension while it is installing. 155 gfx::ImageSkia installing_icon; 156 157 // A dummy extension created from |manifest|; 158 scoped_refptr<Extension> dummy_extension; 159 160 // Required minimum version. 161 scoped_ptr<Version> minimum_version; 162 163 // Ephemeral apps are transiently installed. 164 bool is_ephemeral; 165 166 // The authuser index required to download the item being installed. May be 167 // the empty string, in which case no authuser parameter is used. 168 std::string authuser; 169 170 private: 171 Approval(); 172 }; 173 174 // Gets the Approval associated with the |download|, or NULL if there's none. 175 // Note that the Approval is owned by |download|. 176 static const Approval* GetAssociatedApproval( 177 const content::DownloadItem& download); 178 179 // Creates a WebstoreInstaller for downloading and installing the extension 180 // with the given |id| from the Chrome Web Store. If |delegate| is not NULL, 181 // it will be notified when the install succeeds or fails. The installer will 182 // use the specified |controller| to download the extension. Only one 183 // WebstoreInstaller can use a specific controller at any given time. This 184 // also associates the |approval| with this install. 185 // Note: the delegate should stay alive until being called back. 186 WebstoreInstaller(Profile* profile, 187 Delegate* delegate, 188 content::WebContents* web_contents, 189 const std::string& id, 190 scoped_ptr<Approval> approval, 191 InstallSource source); 192 193 // Starts downloading and installing the extension. 194 void Start(); 195 196 // content::NotificationObserver. 197 virtual void Observe(int type, 198 const content::NotificationSource& source, 199 const content::NotificationDetails& details) OVERRIDE; 200 201 // ExtensionRegistryObserver. 202 virtual void OnExtensionInstalled(content::BrowserContext* browser_context, 203 const Extension* extension) OVERRIDE; 204 205 // Removes the reference to the delegate passed in the constructor. Used when 206 // the delegate object must be deleted before this object. 207 void InvalidateDelegate(); 208 209 // Instead of using the default download directory, use |directory| instead. 210 // This does *not* transfer ownership of |directory|. 211 static void SetDownloadDirectoryForTests(base::FilePath* directory); 212 213 private: 214 FRIEND_TEST_ALL_PREFIXES(WebstoreInstallerTest, PlatformParams); 215 friend struct content::BrowserThread::DeleteOnThread< 216 content::BrowserThread::UI>; 217 friend class base::DeleteHelper<WebstoreInstaller>; 218 virtual ~WebstoreInstaller(); 219 220 // Helper to get install URL. 221 static GURL GetWebstoreInstallURL(const std::string& extension_id, 222 InstallSource source); 223 224 // DownloadManager::DownloadUrl callback. 225 void OnDownloadStarted(content::DownloadItem* item, 226 content::DownloadInterruptReason interrupt_reason); 227 228 // DownloadItem::Observer implementation: 229 virtual void OnDownloadUpdated(content::DownloadItem* download) OVERRIDE; 230 virtual void OnDownloadDestroyed(content::DownloadItem* download) OVERRIDE; 231 232 // Downloads next pending module in |pending_modules_|. 233 void DownloadNextPendingModule(); 234 235 // Downloads and installs a single Crx with the given |extension_id|. 236 // This function is used for both the extension Crx and dependences. 237 void DownloadCrx(const std::string& extension_id, InstallSource source); 238 239 // Starts downloading the extension to |file_path|. 240 void StartDownload(const base::FilePath& file_path); 241 242 // Updates the InstallTracker with the latest download progress. 243 void UpdateDownloadProgress(); 244 245 // Creates and starts CrxInstaller for the downloaded extension package. 246 void StartCrxInstaller(const content::DownloadItem& item); 247 248 // Reports an install |error| to the delegate for the given extension if this 249 // managed its installation. This also removes the associated PendingInstall. 250 void ReportFailure(const std::string& error, FailureReason reason); 251 252 // Reports a successful install to the delegate for the given extension if 253 // this managed its installation. This also removes the associated 254 // PendingInstall. 255 void ReportSuccess(); 256 257 // Records stats regarding an interrupted webstore download item. 258 void RecordInterrupt(const content::DownloadItem* download) const; 259 260 content::NotificationRegistrar registrar_; 261 ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver> 262 extension_registry_observer_; 263 Profile* profile_; 264 Delegate* delegate_; 265 std::string id_; 266 InstallSource install_source_; 267 // The DownloadItem is owned by the DownloadManager and is valid from when 268 // OnDownloadStarted is called (with no error) until OnDownloadDestroyed(). 269 content::DownloadItem* download_item_; 270 // Used to periodically update the extension's download status. This will 271 // trigger at least every second, though sometimes more frequently (depending 272 // on number of modules, etc). 273 base::OneShotTimer<WebstoreInstaller> download_progress_timer_; 274 scoped_ptr<Approval> approval_; 275 GURL download_url_; 276 scoped_refptr<CrxInstaller> crx_installer_; 277 278 // Pending modules. 279 std::list<SharedModuleInfo::ImportInfo> pending_modules_; 280 // Total extension modules we need download and install (the main module and 281 // depedences). 282 int total_modules_; 283 bool download_started_; 284 }; 285 286 } // namespace extensions 287 288 #endif // CHROME_BROWSER_EXTENSIONS_WEBSTORE_INSTALLER_H_ 289