1// Copyright (c) 2011 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_EXTENSION_SERVICE_H_ 6#define CHROME_BROWSER_EXTENSIONS_EXTENSION_SERVICE_H_ 7#pragma once 8 9#include <map> 10#include <set> 11#include <string> 12#include <vector> 13 14#include "base/command_line.h" 15#include "base/file_path.h" 16#include "base/gtest_prod_util.h" 17#include "base/memory/linked_ptr.h" 18#include "base/memory/ref_counted.h" 19#include "base/task.h" 20#include "base/time.h" 21#include "base/tuple.h" 22#include "base/version.h" 23#include "chrome/browser/extensions/apps_promo.h" 24#include "chrome/browser/extensions/extension_icon_manager.h" 25#include "chrome/browser/extensions/extension_menu_manager.h" 26#include "chrome/browser/extensions/extension_prefs.h" 27#include "chrome/browser/extensions/extension_process_manager.h" 28#include "chrome/browser/extensions/extension_toolbar_model.h" 29#include "chrome/browser/extensions/extensions_quota_service.h" 30#include "chrome/browser/extensions/external_extension_provider_interface.h" 31#include "chrome/browser/extensions/pending_extension_manager.h" 32#include "chrome/browser/extensions/sandboxed_extension_unpacker.h" 33#include "chrome/browser/prefs/pref_change_registrar.h" 34#include "chrome/common/extensions/extension.h" 35#include "content/browser/browser_thread.h" 36#include "content/common/notification_observer.h" 37#include "content/common/notification_registrar.h" 38#include "content/common/property_bag.h" 39 40class ExtensionBrowserEventRouter; 41class ExtensionPreferenceEventRouter; 42class ExtensionServiceBackend; 43struct ExtensionSyncData; 44class ExtensionToolbarModel; 45class ExtensionUpdater; 46class GURL; 47class PendingExtensionManager; 48class Profile; 49class Version; 50 51// This is an interface class to encapsulate the dependencies that 52// various classes have on ExtensionService. This allows easy mocking. 53class ExtensionServiceInterface { 54 public: 55 virtual ~ExtensionServiceInterface() {} 56 virtual const ExtensionList* extensions() const = 0; 57 virtual const ExtensionList* disabled_extensions() const = 0; 58 virtual PendingExtensionManager* pending_extension_manager() = 0; 59 virtual void UpdateExtension(const std::string& id, 60 const FilePath& path, 61 const GURL& download_url) = 0; 62 virtual const Extension* GetExtensionById(const std::string& id, 63 bool include_disabled) const = 0; 64 65 virtual bool UninstallExtension(const std::string& extension_id, 66 bool external_uninstall, 67 std::string* error) = 0; 68 69 virtual bool IsExtensionEnabled(const std::string& extension_id) const = 0; 70 virtual bool IsExternalExtensionUninstalled( 71 const std::string& extension_id) const = 0; 72 virtual void EnableExtension(const std::string& extension_id) = 0; 73 virtual void DisableExtension(const std::string& extension_id) = 0; 74 75 virtual void UpdateExtensionBlacklist( 76 const std::vector<std::string>& blacklist) = 0; 77 virtual void CheckAdminBlacklist() = 0; 78 79 virtual bool IsIncognitoEnabled(const std::string& extension_id) const = 0; 80 virtual void SetIsIncognitoEnabled(const std::string& extension_id, 81 bool enabled) = 0; 82 83 // Safe to call multiple times in a row. 84 // 85 // TODO(akalin): Remove this method (and others) once we refactor 86 // themes sync to not use it directly. 87 virtual void CheckForUpdatesSoon() = 0; 88 89 // Take any actions required to make the local state of the 90 // extension match the state in |extension_sync_data| (including 91 // installing/uninstalling the extension). 92 // 93 // TODO(akalin): We'll eventually need a separate method for app 94 // sync. See http://crbug.com/58077 and http://crbug.com/61447. 95 virtual void ProcessSyncData( 96 const ExtensionSyncData& extension_sync_data, 97 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow) = 0; 98 99 // TODO(akalin): Add a method like: 100 // 101 // virtual void 102 // GetInitialSyncData(bool (*filter)(Extension), 103 // map<string, ExtensionSyncData>* out) const; 104 // 105 // which would fill |out| with sync data for the extensions that 106 // match |filter|. Sync would use this for the initial syncing 107 // step. 108}; 109 110// Manages installed and running Chromium extensions. 111class ExtensionService 112 : public base::RefCountedThreadSafe<ExtensionService, 113 BrowserThread::DeleteOnUIThread>, 114 public ExtensionServiceInterface, 115 public ExternalExtensionProviderInterface::VisitorInterface, 116 public NotificationObserver { 117 public: 118 // Information about a registered component extension. 119 struct ComponentExtensionInfo { 120 ComponentExtensionInfo(const std::string& manifest, 121 const FilePath& root_directory) 122 : manifest(manifest), 123 root_directory(root_directory) { 124 } 125 126 // The extension's manifest. This is required for component extensions so 127 // that ExtensionService doesn't need to go to disk to load them. 128 std::string manifest; 129 130 // Directory where the extension is stored. 131 FilePath root_directory; 132 }; 133 134 // The name of the directory inside the profile where extensions are 135 // installed to. 136 static const char* kInstallDirectoryName; 137 138 // If auto-updates are turned on, default to running every 5 hours. 139 static const int kDefaultUpdateFrequencySeconds = 60 * 60 * 5; 140 141 // The name of the file that the current active version number is stored in. 142 static const char* kCurrentVersionFileName; 143 144 // Determine if a given extension download should be treated as if it came 145 // from the gallery. Note that this is requires *both* that the download_url 146 // match and that the download was referred from a gallery page. 147 bool IsDownloadFromGallery(const GURL& download_url, 148 const GURL& referrer_url); 149 150 // Determine if the downloaded extension came from the theme mini-gallery, 151 // Used to test if we need to show the "Loading" dialog for themes. 152 static bool IsDownloadFromMiniGallery(const GURL& download_url); 153 154 // Returns the Extension of hosted or packaged apps, NULL otherwise. 155 const Extension* GetInstalledApp(const GURL& url); 156 157 // Returns whether the URL is from either a hosted or packaged app. 158 bool IsInstalledApp(const GURL& url); 159 160 // Attempts to uninstall an extension from a given ExtensionService. Returns 161 // true iff the target extension exists. 162 static bool UninstallExtensionHelper(ExtensionService* extensions_service, 163 const std::string& extension_id); 164 165 // Constructor stores pointers to |profile| and |extension_prefs| but 166 // ownership remains at caller. 167 ExtensionService(Profile* profile, 168 const CommandLine* command_line, 169 const FilePath& install_directory, 170 ExtensionPrefs* extension_prefs, 171 bool autoupdate_enabled, 172 bool extensions_enabled); 173 174 // Gets the list of currently installed extensions. 175 virtual const ExtensionList* extensions() const; 176 virtual const ExtensionList* disabled_extensions() const; 177 virtual const ExtensionList* terminated_extensions() const; 178 179 // Gets the object managing the set of pending extensions. 180 virtual PendingExtensionManager* pending_extension_manager(); 181 182 // Registers an extension to be loaded as a component extension. 183 void register_component_extension(const ComponentExtensionInfo& info) { 184 component_extension_manifests_.push_back(info); 185 } 186 187 const FilePath& install_directory() const { return install_directory_; } 188 189 AppsPromo* apps_promo() { return &apps_promo_; } 190 191 // Whether this extension can run in an incognito window. 192 virtual bool IsIncognitoEnabled(const std::string& extension_id) const; 193 virtual void SetIsIncognitoEnabled(const std::string& extension_id, 194 bool enabled); 195 196 // Returns true if the given extension can see events and data from another 197 // sub-profile (incognito to original profile, or vice versa). 198 bool CanCrossIncognito(const Extension* extension); 199 200 // Whether this extension can inject scripts into pages with file URLs. 201 bool AllowFileAccess(const Extension* extension); 202 // Will reload the extension since this permission is applied at loading time 203 // only. 204 void SetAllowFileAccess(const Extension* extension, bool allow); 205 206 // Getter and setter for the Browser Action visibility in the toolbar. 207 bool GetBrowserActionVisibility(const Extension* extension); 208 void SetBrowserActionVisibility(const Extension* extension, bool visible); 209 210 // Whether the background page, if any, is ready. We don't load other 211 // components until then. If there is no background page, we consider it to 212 // be ready. 213 bool IsBackgroundPageReady(const Extension* extension); 214 void SetBackgroundPageReady(const Extension* extension); 215 216 // Getter and setter for the flag that specifies whether the extension is 217 // being upgraded. 218 bool IsBeingUpgraded(const Extension* extension); 219 void SetBeingUpgraded(const Extension* extension, bool value); 220 221 // Getter for the extension's runtime data PropertyBag. 222 PropertyBag* GetPropertyBag(const Extension* extension); 223 224 // Initialize and start all installed extensions. 225 void Init(); 226 227 // Start up the extension event routers. 228 void InitEventRouters(); 229 230 // Look up an extension by ID. 231 virtual const Extension* GetExtensionById(const std::string& id, 232 bool include_disabled) const; 233 234 // Looks up a terminated (crashed) extension by ID. GetExtensionById does 235 // not include terminated extensions. 236 virtual const Extension* GetTerminatedExtension(const std::string& id); 237 238 // Updates a currently-installed extension with the contents from 239 // |extension_path|. 240 // TODO(aa): This method can be removed. ExtensionUpdater could use 241 // CrxInstaller directly instead. 242 virtual void UpdateExtension(const std::string& id, 243 const FilePath& extension_path, 244 const GURL& download_url); 245 246 // Reloads the specified extension. 247 void ReloadExtension(const std::string& extension_id); 248 249 // Uninstalls the specified extension. Callers should only call this method 250 // with extensions that exist. |external_uninstall| is a magical parameter 251 // that is only used to send information to ExtensionPrefs, which external 252 // callers should never set to true. 253 // TODO(aa): Remove |external_uninstall| -- this information should be passed 254 // to ExtensionPrefs some other way. 255 virtual bool UninstallExtension(const std::string& extension_id, 256 bool external_uninstall, 257 std::string* error); 258 259 virtual bool IsExtensionEnabled(const std::string& extension_id) const; 260 virtual bool IsExternalExtensionUninstalled( 261 const std::string& extension_id) const; 262 263 // Enable or disable an extension. No action if the extension is already 264 // enabled/disabled. 265 virtual void EnableExtension(const std::string& extension_id); 266 virtual void DisableExtension(const std::string& extension_id); 267 268 // Updates the |extension|'s granted permissions lists to include all 269 // permissions in the |extension|'s manifest. 270 void GrantPermissions(const Extension* extension); 271 272 // Updates the |extension|'s granted permissions lists to include all 273 // permissions in the |extension|'s manifest and re-enables the 274 // extension. 275 void GrantPermissionsAndEnableExtension(const Extension* extension); 276 277 // Loads the extension from the directory |extension_path|. 278 void LoadExtension(const FilePath& extension_path); 279 280 // Loads any component extensions. 281 void LoadComponentExtensions(); 282 283 // Loads particular component extension. 284 const Extension* LoadComponentExtension(const ComponentExtensionInfo& info); 285 286 // Loads all known extensions (used by startup and testing code). 287 void LoadAllExtensions(); 288 289 // Continues loading all know extensions. It can be called from 290 // LoadAllExtensions or from file thread if we had to relocalize manifest 291 // (write_to_prefs is true in that case). 292 void ContinueLoadAllExtensions(ExtensionPrefs::ExtensionsInfo* info, 293 base::TimeTicks start_time, 294 bool write_to_prefs); 295 296 // Check for updates (or potentially new extensions from external providers) 297 void CheckForExternalUpdates(); 298 299 // Unload the specified extension. 300 void UnloadExtension(const std::string& extension_id, 301 UnloadedExtensionInfo::Reason reason); 302 303 // Unload all extensions. This is currently only called on shutdown, and 304 // does not send notifications. 305 void UnloadAllExtensions(); 306 307 // Called only by testing. 308 void ReloadExtensions(); 309 310 // Scan the extension directory and clean up the cruft. 311 void GarbageCollectExtensions(); 312 313 // The App that represents the web store. 314 const Extension* GetWebStoreApp(); 315 316 // Lookup an extension by |url|. 317 const Extension* GetExtensionByURL(const GURL& url); 318 319 // If there is an extension for the specified url it is returned. Otherwise 320 // returns the extension whose web extent contains |url|. 321 const Extension* GetExtensionByWebExtent(const GURL& url); 322 323 // Returns an extension that contains any URL that overlaps with the given 324 // extent, if one exists. 325 const Extension* GetExtensionByOverlappingWebExtent( 326 const ExtensionExtent& extent); 327 328 // Returns true if |url| should get extension api bindings and be permitted 329 // to make api calls. Note that this is independent of what extension 330 // permissions the given extension has been granted. 331 bool ExtensionBindingsAllowed(const GURL& url); 332 333 // Returns the icon to display in the omnibox for the given extension. 334 const SkBitmap& GetOmniboxIcon(const std::string& extension_id); 335 336 // Returns the icon to display in the omnibox popup window for the given 337 // extension. 338 const SkBitmap& GetOmniboxPopupIcon(const std::string& extension_id); 339 340 // Called when the initial extensions load has completed. 341 virtual void OnLoadedInstalledExtensions(); 342 343 // Adds |extension| to this ExtensionService and notifies observers than an 344 // extension has been loaded. Called by the backend after an extension has 345 // been loaded from a file and installed. 346 void AddExtension(const Extension* extension); 347 348 // Called by the backend when an extension has been installed. 349 void OnExtensionInstalled(const Extension* extension); 350 351 // Checks if the privileges requested by |extension| have increased, and if 352 // so, disables the extension and prompts the user to approve the change. 353 void DisableIfPrivilegeIncrease(const Extension* extension); 354 355 // Go through each extensions in pref, unload blacklisted extensions 356 // and update the blacklist state in pref. 357 virtual void UpdateExtensionBlacklist( 358 const std::vector<std::string>& blacklist); 359 360 // Go through each extension and unload those that the network admin has 361 // put on the blacklist (not to be confused with the Google managed blacklist 362 // set of extensions. 363 virtual void CheckAdminBlacklist(); 364 365 virtual void CheckForUpdatesSoon(); 366 367 virtual void ProcessSyncData( 368 const ExtensionSyncData& extension_sync_data, 369 PendingExtensionInfo::ShouldAllowInstallPredicate 370 should_allow_install); 371 372 void set_extensions_enabled(bool enabled) { extensions_enabled_ = enabled; } 373 bool extensions_enabled() { return extensions_enabled_; } 374 375 void set_show_extensions_prompts(bool enabled) { 376 show_extensions_prompts_ = enabled; 377 } 378 379 bool show_extensions_prompts() { 380 return show_extensions_prompts_; 381 } 382 383 Profile* profile(); 384 385 // Profile calls this when it is being destroyed so that we know not to call 386 // it. 387 void DestroyingProfile(); 388 389 // TODO(skerner): Change to const ExtensionPrefs& extension_prefs() const, 390 // ExtensionPrefs* mutable_extension_prefs(). 391 ExtensionPrefs* extension_prefs(); 392 393 // Whether the extension service is ready. 394 // TODO(skerner): Get rid of this method. crbug.com/63756 395 bool is_ready() { return ready_; } 396 397 // Note that this may return NULL if autoupdate is not turned on. 398 ExtensionUpdater* updater(); 399 400 ExtensionToolbarModel* toolbar_model() { return &toolbar_model_; } 401 402 ExtensionsQuotaService* quota_service() { return "a_service_; } 403 404 ExtensionMenuManager* menu_manager() { return &menu_manager_; } 405 406 ExtensionBrowserEventRouter* browser_event_router() { 407 return browser_event_router_.get(); 408 } 409 410 // Notify the frontend that there was an error loading an extension. 411 // This method is public because ExtensionServiceBackend can post to here. 412 void ReportExtensionLoadError(const FilePath& extension_path, 413 const std::string& error, 414 NotificationType type, 415 bool be_noisy); 416 417 // ExtensionHost of background page calls this method right after its render 418 // view has been created. 419 void DidCreateRenderViewForBackgroundPage(ExtensionHost* host); 420 421 // For the extension in |version_path| with |id|, check to see if it's an 422 // externally managed extension. If so, uninstall it. 423 void CheckExternalUninstall(const std::string& id); 424 425 // Clear all ExternalExtensionProviders. 426 void ClearProvidersForTesting(); 427 428 // Adds an ExternalExtensionProviderInterface for the service to use during 429 // testing. Takes ownership of |test_provider|. 430 void AddProviderForTesting(ExternalExtensionProviderInterface* test_provider); 431 432 // ExternalExtensionProvider::Visitor implementation. 433 virtual void OnExternalExtensionFileFound(const std::string& id, 434 const Version* version, 435 const FilePath& path, 436 Extension::Location location); 437 438 virtual void OnExternalExtensionUpdateUrlFound(const std::string& id, 439 const GURL& update_url, 440 Extension::Location location); 441 442 virtual void OnExternalProviderReady(); 443 444 // NotificationObserver 445 virtual void Observe(NotificationType type, 446 const NotificationSource& source, 447 const NotificationDetails& details); 448 449 // Whether there are any apps installed. Component apps are not included. 450 bool HasApps() const; 451 452 // Gets the set of loaded app ids. Component apps are not included. 453 ExtensionIdSet GetAppIds() const; 454 455 // Record a histogram using the PermissionMessage enum values for each 456 // permission in |e|. 457 // NOTE: If this is ever called with high frequency, the implementation may 458 // need to be made more efficient. 459 static void RecordPermissionMessagesHistogram( 460 const Extension* e, const char* histogram); 461 462 private: 463 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>; 464 friend class DeleteTask<ExtensionService>; 465 466 // Contains Extension data that can change during the life of the process, 467 // but does not persist across restarts. 468 struct ExtensionRuntimeData { 469 // True if the background page is ready. 470 bool background_page_ready; 471 472 // True while the extension is being upgraded. 473 bool being_upgraded; 474 475 // Generic bag of runtime data that users can associate with extensions. 476 PropertyBag property_bag; 477 478 ExtensionRuntimeData(); 479 ~ExtensionRuntimeData(); 480 }; 481 typedef std::map<std::string, ExtensionRuntimeData> ExtensionRuntimeDataMap; 482 483 struct NaClModuleInfo { 484 NaClModuleInfo(); 485 ~NaClModuleInfo(); 486 487 GURL url; 488 std::string mime_type; 489 }; 490 typedef std::list<NaClModuleInfo> NaClModuleInfoList; 491 492 virtual ~ExtensionService(); 493 494 // Clear all persistent data that may have been stored by the extension. 495 void ClearExtensionData(const GURL& extension_url); 496 497 // Look up an extension by ID, optionally including either or both of enabled 498 // and disabled extensions. 499 const Extension* GetExtensionByIdInternal(const std::string& id, 500 bool include_enabled, 501 bool include_disabled) const; 502 503 504 // Keep track of terminated extensions. 505 void TrackTerminatedExtension(const Extension* extension); 506 void UntrackTerminatedExtension(const std::string& id); 507 508 // Handles sending notification that |extension| was loaded. 509 void NotifyExtensionLoaded(const Extension* extension); 510 511 // Handles sending notification that |extension| was unloaded. 512 void NotifyExtensionUnloaded(const Extension* extension, 513 UnloadedExtensionInfo::Reason reason); 514 515 // Helper that updates the active extension list used for crash reporting. 516 void UpdateActiveExtensionsInCrashReporter(); 517 518 // Helper method. Loads extension from prefs. 519 void LoadInstalledExtension(const ExtensionInfo& info, bool write_to_prefs); 520 521 // We implement some Pepper plug-ins using NaCl to take advantage of NaCl's 522 // strong sandbox. Typically, these NaCl modules are stored in extensions 523 // and registered here. Not all NaCl modules need to register for a MIME 524 // type, just the ones that are responsible for rendering a particular MIME 525 // type, like application/pdf. Note: We only register NaCl modules in the 526 // browser process. 527 void RegisterNaClModule(const GURL& url, const std::string& mime_type); 528 void UnregisterNaClModule(const GURL& url); 529 530 // Call UpdatePluginListWithNaClModules() after registering or unregistering 531 // a NaCl module to see those changes reflected in the PluginList. 532 void UpdatePluginListWithNaClModules(); 533 534 NaClModuleInfoList::iterator FindNaClModule(const GURL& url); 535 536 // The profile this ExtensionService is part of. 537 Profile* profile_; 538 539 // Preferences for the owning profile (weak reference). 540 ExtensionPrefs* extension_prefs_; 541 542 // The current list of installed extensions. 543 // TODO(aa): This should use chrome/common/extensions/extension_set.h. 544 ExtensionList extensions_; 545 546 // The list of installed extensions that have been disabled. 547 ExtensionList disabled_extensions_; 548 549 // The list of installed extensions that have been terminated. 550 ExtensionList terminated_extensions_; 551 552 // Used to quickly check if an extension was terminated. 553 std::set<std::string> terminated_extension_ids_; 554 555 // Hold the set of pending extensions. 556 PendingExtensionManager pending_extension_manager_; 557 558 // The map of extension IDs to their runtime data. 559 ExtensionRuntimeDataMap extension_runtime_data_; 560 561 // The full path to the directory where extensions are installed. 562 FilePath install_directory_; 563 564 // Whether or not extensions are enabled. 565 bool extensions_enabled_; 566 567 // Whether to notify users when they attempt to install an extension. 568 bool show_extensions_prompts_; 569 570 // The backend that will do IO on behalf of this instance. 571 scoped_refptr<ExtensionServiceBackend> backend_; 572 573 // Used by dispatchers to limit API quota for individual extensions. 574 ExtensionsQuotaService quota_service_; 575 576 // Record that Init() has been called, and NotificationType::EXTENSIONS_READY 577 // has fired. 578 bool ready_; 579 580 // Our extension updater, if updates are turned on. 581 scoped_ptr<ExtensionUpdater> updater_; 582 583 // The model that tracks extensions with BrowserAction buttons. 584 ExtensionToolbarModel toolbar_model_; 585 586 // Map unloaded extensions' ids to their paths. When a temporarily loaded 587 // extension is unloaded, we lose the infomation about it and don't have 588 // any in the extension preferences file. 589 typedef std::map<std::string, FilePath> UnloadedExtensionPathMap; 590 UnloadedExtensionPathMap unloaded_extension_paths_; 591 592 // Map disabled extensions' ids to their paths. When a temporarily loaded 593 // extension is disabled before it is reloaded, keep track of the path so that 594 // it can be re-enabled upon a successful load. 595 typedef std::map<std::string, FilePath> DisabledExtensionPathMap; 596 DisabledExtensionPathMap disabled_extension_paths_; 597 598 // Map of inspector cookies that are detached, waiting for an extension to be 599 // reloaded. 600 typedef std::map<std::string, int> OrphanedDevTools; 601 OrphanedDevTools orphaned_dev_tools_; 602 603 NotificationRegistrar registrar_; 604 PrefChangeRegistrar pref_change_registrar_; 605 606 // Keeps track of menu items added by extensions. 607 ExtensionMenuManager menu_manager_; 608 609 // Keeps track of favicon-sized omnibox icons for extensions. 610 ExtensionIconManager omnibox_icon_manager_; 611 ExtensionIconManager omnibox_popup_icon_manager_; 612 613 // List of registered component extensions (see Extension::Location). 614 typedef std::vector<ComponentExtensionInfo> RegisteredComponentExtensions; 615 RegisteredComponentExtensions component_extension_manifests_; 616 617 // Manages the promotion of the web store. 618 AppsPromo apps_promo_; 619 620 // Flag to make sure event routers are only initialized once. 621 bool event_routers_initialized_; 622 623 scoped_ptr<ExtensionBrowserEventRouter> browser_event_router_; 624 625 scoped_ptr<ExtensionPreferenceEventRouter> preference_event_router_; 626 627 // A collection of external extension providers. Each provider reads 628 // a source of external extension information. Examples include the 629 // windows registry and external_extensions.json. 630 ProviderCollection external_extension_providers_; 631 632 // Set to true by OnExternalExtensionUpdateUrlFound() when an external 633 // extension URL is found. Used in CheckForExternalUpdates() to see 634 // if an update check is needed to install pending extensions. 635 bool external_extension_url_added_; 636 637 NaClModuleInfoList nacl_module_list_; 638 639 FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest, 640 InstallAppsWithUnlimtedStorage); 641 FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest, 642 InstallAppsAndCheckStorageProtection); 643 DISALLOW_COPY_AND_ASSIGN(ExtensionService); 644}; 645 646#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_SERVICE_H_ 647