// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CHROME_BROWSER_EXTENSIONS_EXTENSIONS_SERVICE_H_ #define CHROME_BROWSER_EXTENSIONS_EXTENSIONS_SERVICE_H_ #include <set> #include <string> #include <vector> #include "base/command_line.h" #include "base/file_path.h" #include "base/message_loop.h" #include "base/ref_counted.h" #include "base/task.h" #include "base/values.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension.h" class Browser; class DictionaryValue; class Extension; class ExtensionsServiceBackend; class GURL; class PrefService; class Profile; class ResourceDispatcherHost; class SkBitmap; class SiteInstance; class UserScriptMaster; typedef std::vector<Extension*> ExtensionList; // Manages installed and running Chromium extensions. class ExtensionsService : public base::RefCountedThreadSafe<ExtensionsService> { public: ExtensionsService(Profile* profile, MessageLoop* frontend_loop, MessageLoop* backend_loop, const std::string& registry_path); ~ExtensionsService(); // Gets the list of currently installed extensions. const ExtensionList* extensions() const { return &extensions_; } // Initialize and start all installed extensions. bool Init(); // Install the extension file at |extension_path|. Will install as an // update if an older version is already installed. // For fresh installs, this method also causes the extension to be // immediately loaded. void InstallExtension(const FilePath& extension_path); // Uninstalls the specified extension. Callers should only call this method // with extensions that exist and are "internal". void UninstallExtension(const std::string& extension_id); // Load the extension from the directory |extension_path|. void LoadExtension(const FilePath& extension_path); // Lookup an extension by |id|. Extension* GetExtensionByID(std::string id); // Gets a list of external extensions. If |external_extensions| is non-null, // a dictionary with all external extensions (including extensions installed // through the registry on Windows builds) and their preferences are // returned. If |killed_extensions| is non-null, a set of string IDs // containing all external extension IDs with the killbit set are returned. void GetExternalExtensions(DictionaryValue* external_extensions, std::set<std::string>* killed_extensions); // Gets the settings for an extension from preferences. If the key doesn't // exist, this function creates it (don't need to check return for NULL). DictionaryValue* GetOrCreateExtensionPref(const std::wstring& extension_id); // Writes a preference value for a particular extension |extension_id| under // the |key| specified. If |schedule_save| is true, it will also ask the // preference system to schedule a save to disk. bool UpdateExtensionPref(const std::wstring& extension_id, const std::wstring& key, Value* data_value, bool schedule_save); // The name of the file that the current active version number is stored in. static const char* kCurrentVersionFileName; void set_extensions_enabled(bool enabled) { extensions_enabled_ = enabled; } void set_show_extensions_prompts(bool enabled) { show_extensions_prompts_ = enabled; } bool extensions_enabled() { return extensions_enabled_; } bool show_extensions_prompts() { return show_extensions_prompts_; } private: // For OnExtensionLoaded, OnExtensionInstalled, and // OnExtensionVersionReinstalled. friend class ExtensionsServiceBackend; // Called by the backend when extensions have been loaded. void OnExtensionsLoaded(ExtensionList* extensions); // Called by the backend when an extensoin hsa been installed. void OnExtensionInstalled(Extension* extension, bool is_update); // Called by the backend when an external extension has been installed. void OnExternalExtensionInstalled( const std::string& id, Extension::Location location); // Called by the backend when an extension has been reinstalled. void OnExtensionVersionReinstalled(const std::string& id); // The name of the directory inside the profile where extensions are // installed to. static const char* kInstallDirectoryName; // Preferences for the owning profile. PrefService* prefs_; // The message loop to use with the backend. MessageLoop* backend_loop_; // The current list of installed extensions. ExtensionList extensions_; // The full path to the directory where extensions are installed. FilePath install_directory_; // Whether or not extensions are enabled. bool extensions_enabled_; // Whether to notify users when they attempt to install an extension. bool show_extensions_prompts_; // The backend that will do IO on behalf of this instance. scoped_refptr<ExtensionsServiceBackend> backend_; DISALLOW_COPY_AND_ASSIGN(ExtensionsService); }; // Implements IO for the ExtensionsService. // TODO(aa): This can probably move into the .cc file. class ExtensionsServiceBackend : public base::RefCountedThreadSafe<ExtensionsServiceBackend> { public: // |rdh| can be NULL in the case of test environment. // |registry_path| can be NULL *except* in the case of the test environment, // where it is specified to a temp location. ExtensionsServiceBackend(const FilePath& install_directory, ResourceDispatcherHost* rdh, MessageLoop* frontend_loop, const std::string& registry_path); // Loads extensions from the install directory. The extensions are assumed to // be unpacked in directories that are direct children of the specified path. // Errors are reported through ExtensionErrorReporter. On completion, // OnExtensionsLoaded() is called with any successfully loaded extensions. void LoadExtensionsFromInstallDirectory( scoped_refptr<ExtensionsService> frontend, DictionaryValue* extension_prefs); // Loads a single extension from |path| where |path| is the top directory of // a specific extension where its manifest file lives. // Errors are reported through ExtensionErrorReporter. On completion, // OnExtensionsLoadedFromDirectory() is called with any successfully loaded // extensions. // TODO(erikkay): It might be useful to be able to load a packed extension // (presumably into memory) without installing it. void LoadSingleExtension(const FilePath &path, scoped_refptr<ExtensionsService> frontend); // Install the extension file at |extension_path|. Errors are reported through // ExtensionErrorReporter. OnExtensionInstalled is called in the frontend on // success. void InstallExtension(const FilePath& extension_path, scoped_refptr<ExtensionsService> frontend); // Check externally updated extensions for updates and install if necessary. // Errors are reported through ExtensionErrorReporter. Succcess is not // reported. void CheckForExternalUpdates(std::set<std::string> ids_to_ignore, DictionaryValue* extension_prefs, scoped_refptr<ExtensionsService> frontend); // Deletes all versions of the extension from the filesystem. Note that only // extensions whose location() == INTERNAL can be uninstalled. Attempting to // uninstall other extensions will silently fail. void UninstallExtension(const std::string& extension_id); private: class UnpackerClient; friend class UnpackerClient; // Load a single extension from |extension_path|, the top directory of // a specific extension where its manifest file lives. Extension* LoadExtension(const FilePath& extension_path, bool require_id); // Load a single extension from |extension_path|, the top directory of // a versioned extension where its Current Version file lives. Extension* LoadExtensionCurrentVersion(const FilePath& extension_path); // Install a crx file at |extension_path|. If |expected_id| is not empty, it's // verified against the extension's manifest before installation. If // |from_external| is true, this extension install is from an external source, // ie the Windows registry, and will be marked as such. If the extension is // already installed, install the new version only if its version number is // greater than the current installed version. void InstallOrUpdateExtension(const FilePath& extension_path, const std::string& expected_id, bool from_external); // Finish installing an extension after it has been unpacked to // |temp_extension_dir| by our utility process. If |expected_id| is not // empty, it's verified against the extension's manifest before installation. // |manifest| and |images| are parsed information from the extension that // we want to write to disk in the browser process. void OnExtensionUnpacked( const FilePath& extension_path, const FilePath& temp_extension_dir, const std::string expected_id, bool from_external, const DictionaryValue& manifest, const std::vector< Tuple2<SkBitmap, FilePath> >& images); // Notify the frontend that there was an error loading an extension. void ReportExtensionLoadError(const FilePath& extension_path, const std::string& error); // Notify the frontend that extensions were loaded. void ReportExtensionsLoaded(ExtensionList* extensions); // Notify the frontend that there was an error installing an extension. void ReportExtensionInstallError(const FilePath& extension_path, const std::string& error); // Notify the frontend that the extension had already been installed. void ReportExtensionVersionReinstalled(const std::string& id); // Checks a set of strings (containing id's to ignore) in order to determine // if the extension should be installed. bool ShouldSkipInstallingExtension(const std::set<std::string>& ids_to_ignore, const std::string& id); // Installs the extension if the extension is a newer version or if the // extension hasn't been installed before. void CheckVersionAndInstallExtension(const std::string& id, const std::string& extension_version, const FilePath& extension_path, bool from_external); // Read the manifest from the front of the extension file. // Caller takes ownership of return value. DictionaryValue* ReadManifest(const FilePath& extension_path); // Reads the Current Version file from |dir| into |version_string|. bool ReadCurrentVersion(const FilePath& dir, std::string* version_string); // Check that the version to be installed is greater than the current // installed extension. bool CheckCurrentVersion(const std::string& version, const std::string& current_version, const FilePath& dest_dir); // Install the extension dir by moving it from |source| to |dest| safely. bool InstallDirSafely(const FilePath& source, const FilePath& dest); // Update the CurrentVersion file in |dest_dir| to |version|. bool SetCurrentVersion(const FilePath& dest_dir, std::string version); // For the extension in |version_path| with |id|, check to see if it's an // externally managed extension. If so return true if it should be // uninstalled. bool CheckExternalUninstall(DictionaryValue* extension_prefs, const FilePath& version_path, const std::string& id); // Should an extension of |id| and |version| be installed? // Returns true if no extension of type |id| is installed or if |version| // is greater than the current installed version. bool ShouldInstall(const std::string& id, const std::string& version); // The name of a temporary directory to install an extension into for // validation before finalizing install. static const char* kTempExtensionName; // This is a naked pointer which is set by each entry point. // The entry point is responsible for ensuring lifetime. ExtensionsService* frontend_; // The top-level extensions directory being installed to. FilePath install_directory_; // We only need a pointer to this to pass along to other interfaces. ResourceDispatcherHost* resource_dispatcher_host_; // Whether errors result in noisy alerts. bool alert_on_error_; // The message loop to use to call the frontend. MessageLoop* frontend_loop_; // The path to look for externally registered extensions in. This is a // registry key on windows, but it could be a similar string for the // appropriate system on other platforms in the future. std::string registry_path_; DISALLOW_COPY_AND_ASSIGN(ExtensionsServiceBackend); }; #endif // CHROME_BROWSER_EXTENSIONS_EXTENSIONS_SERVICE_H_