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