summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authoraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2008-12-05 00:38:25 +0000
committeraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2008-12-05 00:38:25 +0000
commit6014d67a9c2006e15cfa09babfe5eaf63d57a331 (patch)
tree9c0d36df02bd5b4a0e7fca1fa23045e3e6f26f27 /chrome
parentfad84eab5e64996804824f2c7b8fce98da13b2cd (diff)
downloadchromium_src-6014d67a9c2006e15cfa09babfe5eaf63d57a331.zip
chromium_src-6014d67a9c2006e15cfa09babfe5eaf63d57a331.tar.gz
chromium_src-6014d67a9c2006e15cfa09babfe5eaf63d57a331.tar.bz2
Introduce ExtensionsService. Load extensions on startup from a directory in
the profile if a command-line flag is present. Please carefully scrutinize the threading/ref-counting schenanigans. Review URL: http://codereview.chromium.org/12876 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@6403 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/browser.scons1
-rw-r--r--chrome/browser/browser.vcproj8
-rw-r--r--chrome/browser/browser_init.cc6
-rw-r--r--chrome/browser/extensions/extension.cc41
-rw-r--r--chrome/browser/extensions/extension.h33
-rw-r--r--chrome/browser/extensions/extensions_service.cc130
-rw-r--r--chrome/browser/extensions/extensions_service.h106
-rw-r--r--chrome/browser/extensions/extensions_service_unittest.cc98
-rw-r--r--chrome/browser/profile.cc10
-rw-r--r--chrome/browser/profile.h7
-rw-r--r--chrome/common/chrome_switches.cc3
-rw-r--r--chrome/common/chrome_switches.h1
-rwxr-xr-xchrome/test/data/extensions/extension1/manifest10
-rwxr-xr-xchrome/test/data/extensions/extension2/manifest5
-rw-r--r--chrome/test/testing_profile.h3
-rw-r--r--chrome/test/unit/unit_tests.scons1
-rw-r--r--chrome/test/unit/unittests.vcproj4
17 files changed, 435 insertions, 32 deletions
diff --git a/chrome/browser/browser.scons b/chrome/browser/browser.scons
index c29cc02..d6c6334 100644
--- a/chrome/browser/browser.scons
+++ b/chrome/browser/browser.scons
@@ -59,6 +59,7 @@ if env['PLATFORM'] in ('posix', 'win32'):
'cross_site_request_manager.cc',
'download/save_file.cc',
'extensions/extension.cc',
+ 'extensions/extensions_service.cc',
'google_url_tracker.cc',
'google_util.cc',
'history/archived_database.cc',
diff --git a/chrome/browser/browser.vcproj b/chrome/browser/browser.vcproj
index 51140bc..fdfcfc7 100644
--- a/chrome/browser/browser.vcproj
+++ b/chrome/browser/browser.vcproj
@@ -2173,6 +2173,14 @@
RelativePath=".\extensions\extension.h"
>
</File>
+ <File
+ RelativePath=".\extensions\extensions_service.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\extensions\extensions_service.h"
+ >
+ </File>
</Filter>
<File
RelativePath=".\browser_trial.cc"
diff --git a/chrome/browser/browser_init.cc b/chrome/browser/browser_init.cc
index 0908689..b56c0b38 100644
--- a/chrome/browser/browser_init.cc
+++ b/chrome/browser/browser_init.cc
@@ -22,6 +22,7 @@
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/dom_ui/new_tab_ui.h"
+#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/first_run.h"
#include "chrome/browser/infobar_delegate.h"
#include "chrome/browser/navigation_controller.h"
@@ -480,6 +481,11 @@ bool BrowserInit::LaunchWithProfile::Launch(Profile* profile,
base::EventRecorder::current()->StartPlayback(script_path);
}
}
+
+ // Start up the extensions service
+ if (parsed_command_line.HasSwitch(switches::kEnableExtensions))
+ profile->GetExtensionsService()->Init();
+
return true;
}
diff --git a/chrome/browser/extensions/extension.cc b/chrome/browser/extensions/extension.cc
index d4fbe9f..b2db579 100644
--- a/chrome/browser/extensions/extension.cc
+++ b/chrome/browser/extensions/extension.cc
@@ -7,30 +7,35 @@
#include "base/logging.h"
#include "base/string_util.h"
-const std::wstring Extension::kFormatVersionKey(L"format_version");
-const std::wstring Extension::kIdKey(L"id");
-const std::wstring Extension::kNameKey(L"name");
-const std::wstring Extension::kDescriptionKey(L"description");
-const std::wstring Extension::kContentScriptsKey(L"content_scripts");
-
-const std::wstring Extension::kInvalidFormatVersionError(
+const FilePath::CharType* Extension::kManifestFilename =
+ FILE_PATH_LITERAL("manifest");
+
+const wchar_t* Extension::kFormatVersionKey = L"format_version";
+const wchar_t* Extension::kIdKey = L"id";
+const wchar_t* Extension::kNameKey = L"name";
+const wchar_t* Extension::kDescriptionKey = L"description";
+const wchar_t* Extension::kContentScriptsKey = L"content_scripts";
+
+const wchar_t* Extension::kInvalidManifestError =
+ L"Manifest is missing or invalid.";
+const wchar_t* Extension::kInvalidFormatVersionError =
StringPrintf(L"Required key '%ls' is missing or invalid",
- kFormatVersionKey.c_str()));
-const std::wstring Extension::kInvalidIdError(
+ kFormatVersionKey).c_str();
+const wchar_t* Extension::kInvalidIdError =
StringPrintf(L"Required key '%ls' is missing or invalid.",
- kIdKey.c_str()));
-const std::wstring Extension::kInvalidNameError(
+ kIdKey).c_str();
+const wchar_t* Extension::kInvalidNameError =
StringPrintf(L"Required key '%ls' is missing or has invalid type.",
- kNameKey.c_str()));
-const std::wstring Extension::kInvalidDescriptionError(
+ kNameKey).c_str();
+const wchar_t* Extension::kInvalidDescriptionError =
StringPrintf(L"Invalid type for '%ls' key.",
- kDescriptionKey.c_str()));
-const std::wstring Extension::kInvalidContentScriptsListError(
+ kDescriptionKey).c_str();
+const wchar_t* Extension::kInvalidContentScriptsListError =
StringPrintf(L"Invalid type for '%ls' key.",
- kContentScriptsKey.c_str()));
-const std::wstring Extension::kInvalidContentScriptError(
+ kContentScriptsKey).c_str();
+const wchar_t* Extension::kInvalidContentScriptError =
StringPrintf(L"Invalid type for %ls at index ",
- kContentScriptsKey.c_str()));
+ kContentScriptsKey).c_str();
bool Extension::InitFromValue(const DictionaryValue& source,
std::wstring* error) {
diff --git a/chrome/browser/extensions/extension.h b/chrome/browser/extensions/extension.h
index 16260e0..94127ac 100644
--- a/chrome/browser/extensions/extension.h
+++ b/chrome/browser/extensions/extension.h
@@ -2,12 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_H__
-#define CHROME_BROWSER_EXTENSIONS_EXTENSION_H__
+#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_H_
+#define CHROME_BROWSER_EXTENSIONS_EXTENSION_H_
#include <string>
#include <vector>
+#include "base/file_path.h"
#include "base/string16.h"
#include "base/values.h"
@@ -19,20 +20,24 @@ class Extension {
// The format for extension manifests that this code understands.
static const int kExpectedFormatVersion = 1;
+ // The name of the manifest inside an extension.
+ static const FilePath::CharType* kManifestFilename;
+
// Keys used in JSON representation of extensions.
- static const std::wstring kFormatVersionKey;
- static const std::wstring kIdKey;
- static const std::wstring kNameKey;
- static const std::wstring kDescriptionKey;
- static const std::wstring kContentScriptsKey;
+ static const wchar_t* kFormatVersionKey;
+ static const wchar_t* kIdKey;
+ static const wchar_t* kNameKey;
+ static const wchar_t* kDescriptionKey;
+ static const wchar_t* kContentScriptsKey;
// Error messages returned from InitFromValue().
- static const std::wstring kInvalidFormatVersionError;
- static const std::wstring kInvalidIdError;
- static const std::wstring kInvalidNameError;
- static const std::wstring kInvalidDescriptionError;
- static const std::wstring kInvalidContentScriptsListError;
- static const std::wstring kInvalidContentScriptError;
+ static const wchar_t* kInvalidFormatVersionError;
+ static const wchar_t* kInvalidManifestError;
+ static const wchar_t* kInvalidIdError;
+ static const wchar_t* kInvalidNameError;
+ static const wchar_t* kInvalidDescriptionError;
+ static const wchar_t* kInvalidContentScriptsListError;
+ static const wchar_t* kInvalidContentScriptError;
// A human-readable ID for the extension. The convention is to use something
// like 'com.example.myextension', but this is not currently enforced. An
@@ -68,4 +73,4 @@ class Extension {
DISALLOW_COPY_AND_ASSIGN(Extension);
};
-#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_H__
+#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_H_
diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc
new file mode 100644
index 0000000..67d508e
--- /dev/null
+++ b/chrome/browser/extensions/extensions_service.cc
@@ -0,0 +1,130 @@
+// Copyright (c) 2006-2008 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.
+
+#include "chrome/browser/extensions/extensions_service.h"
+
+#include "base/file_util.h"
+#include "base/values.h"
+#include "base/string_util.h"
+#include "base/thread.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/common/json_value_serializer.h"
+
+// ExtensionsService
+
+const FilePath::CharType* ExtensionsService::kInstallDirectoryName =
+ FILE_PATH_LITERAL("Extensions");
+
+ExtensionsService::ExtensionsService(const FilePath& profile_directory)
+ : message_loop_(MessageLoop::current()),
+ backend_(new ExtensionsServiceBackend),
+ install_directory_(profile_directory.Append(kInstallDirectoryName)) {
+}
+
+ExtensionsService::~ExtensionsService() {
+ for (ExtensionList::iterator iter = extensions_.begin();
+ iter != extensions_.end(); ++iter) {
+ delete *iter;
+ }
+}
+
+bool ExtensionsService::Init() {
+ // TODO(aa): This message loop should probably come from a backend
+ // interface, similar to how the message loop for the frontend comes
+ // from the frontend interface.
+ g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE,
+ NewRunnableMethod(backend_.get(),
+ &ExtensionsServiceBackend::LoadExtensionsFromDirectory,
+ install_directory_,
+ scoped_refptr<ExtensionsServiceFrontendInterface>(this)));
+ // TODO(aa): Load extensions from other registered directories.
+
+ return true;
+}
+
+MessageLoop* ExtensionsService::GetMessageLoop() {
+ return message_loop_;
+}
+
+void ExtensionsService::OnExtensionsLoadedFromDirectory(
+ ExtensionList* extensions) {
+ extensions_.assign(extensions->begin(), extensions->end());
+ delete extensions;
+
+ // TODO(aa): Notify extensions are loaded.
+}
+
+void ExtensionsService::OnExtensionLoadError(const std::wstring& error) {
+ // TODO(aa): Print the error message out somewhere better. Ideally we would
+ // use the JavaScript console I think, but that is complicated since these
+ // errors are not related to any particular page.
+ LOG(WARNING) << "Error loading extension: " << error;
+}
+
+
+// ExtensionsServicesBackend
+
+bool ExtensionsServiceBackend::LoadExtensionsFromDirectory(
+ const FilePath& path,
+ scoped_refptr<ExtensionsServiceFrontendInterface> frontend) {
+ // Find all child directories in the install directory and load their
+ // manifests. Post errors and results to the frontend.
+ scoped_ptr<ExtensionList> extensions(new ExtensionList);
+ file_util::FileEnumerator enumerator(path.ToWStringHack(),
+ false, // not recursive
+ file_util::FileEnumerator::DIRECTORIES);
+ for (std::wstring child_path = enumerator.Next(); !child_path.empty();
+ child_path = enumerator.Next()) {
+ FilePath manifest_path = FilePath::FromWStringHack(child_path).Append(
+ Extension::kManifestFilename);
+ if (!file_util::PathExists(manifest_path)) {
+ ReportExtensionLoadError(frontend.get(),
+ Extension::kInvalidManifestError);
+ continue;
+ }
+
+ JSONFileValueSerializer serializer(manifest_path.ToWStringHack());
+ Value* root = NULL;
+ if (!serializer.Deserialize(&root)) {
+ ReportExtensionLoadError(frontend.get(),
+ Extension::kInvalidManifestError);
+ continue;
+ }
+
+ if (!root->IsType(Value::TYPE_DICTIONARY)) {
+ ReportExtensionLoadError(frontend.get(),
+ Extension::kInvalidManifestError);
+ continue;
+ }
+
+ scoped_ptr<Extension> extension(new Extension());
+ std::wstring error;
+ if (!extension->InitFromValue(*static_cast<DictionaryValue*>(root),
+ &error)) {
+ ReportExtensionLoadError(frontend.get(),
+ Extension::kInvalidManifestError);
+ continue;
+ }
+
+ extensions->push_back(extension.release());
+ }
+
+ ReportExtensionsLoaded(frontend.get(), extensions.release());
+ return true;
+}
+
+void ExtensionsServiceBackend::ReportExtensionLoadError(
+ ExtensionsServiceFrontendInterface *frontend, const std::wstring &error) {
+ frontend->GetMessageLoop()->PostTask(FROM_HERE, NewRunnableMethod(
+ frontend, &ExtensionsServiceFrontendInterface::OnExtensionLoadError,
+ error));
+}
+
+void ExtensionsServiceBackend::ReportExtensionsLoaded(
+ ExtensionsServiceFrontendInterface *frontend, ExtensionList* extensions) {
+ frontend->GetMessageLoop()->PostTask(FROM_HERE, NewRunnableMethod(
+ frontend,
+ &ExtensionsServiceFrontendInterface::OnExtensionsLoadedFromDirectory,
+ extensions));
+}
diff --git a/chrome/browser/extensions/extensions_service.h b/chrome/browser/extensions/extensions_service.h
new file mode 100644
index 0000000..17f25b7
--- /dev/null
+++ b/chrome/browser/extensions/extensions_service.h
@@ -0,0 +1,106 @@
+// Copyright (c) 2006-2008 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 <vector>
+
+#include "base/file_path.h"
+#include "base/message_loop.h"
+#include "base/ref_counted.h"
+#include "base/task.h"
+#include "chrome/browser/extensions/extension.h"
+
+typedef std::vector<Extension*> ExtensionList;
+class ExtensionsServiceBackend;
+
+// Interface for the frontend to implement. Typically, this will be
+// ExtensionsService, but it can also be a test harness.
+class ExtensionsServiceFrontendInterface
+ : public base::RefCountedThreadSafe<ExtensionsServiceFrontendInterface> {
+ public:
+ virtual ~ExtensionsServiceFrontendInterface(){}
+
+ // The message loop to invoke the frontend's methods on.
+ virtual MessageLoop* GetMessageLoop() = 0;
+
+ // Called when loading an extension fails.
+ virtual void OnExtensionLoadError(const std::wstring& message) = 0;
+
+ // Called with results from LoadExtensionsFromDirectory(). The frontend
+ // takes ownership of the list.
+ virtual void OnExtensionsLoadedFromDirectory(ExtensionList* extensions) = 0;
+};
+
+
+// Manages installed and running Chromium extensions.
+class ExtensionsService : public ExtensionsServiceFrontendInterface {
+ public:
+ ExtensionsService(const FilePath& profile_directory);
+ ~ExtensionsService();
+
+ // Gets the list of currently installed extensions.
+ const ExtensionList* extensions() const {
+ return &extensions_;
+ }
+
+ // Initialize and start all installed extensions.
+ bool Init();
+
+ // ExtensionsServiceFrontendInterface
+ virtual MessageLoop* GetMessageLoop();
+ virtual void OnExtensionLoadError(const std::wstring& message);
+ virtual void OnExtensionsLoadedFromDirectory(ExtensionList* extensions);
+
+ private:
+ // The name of the directory inside the profile where extensions are
+ // installed to.
+ static const FilePath::CharType* kInstallDirectoryName;
+
+ // The message loop for the thread the ExtensionsService is running on.
+ MessageLoop* message_loop_;
+
+ // The backend that will do IO on behalf of this instance.
+ scoped_refptr<ExtensionsServiceBackend> backend_;
+
+ // The current list of installed extensions.
+ ExtensionList extensions_;
+
+ // The full path to the directory where extensions are installed.
+ FilePath install_directory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionsService);
+};
+
+// Implements IO for the ExtensionsService.
+// TODO(aa): Extract an interface out of this for testing the frontend, once the
+// frontend has significant logic to test.
+class ExtensionsServiceBackend
+ : public base::RefCountedThreadSafe<ExtensionsServiceBackend> {
+ public:
+ ExtensionsServiceBackend(){};
+
+ // Loads extensions from a directory. The extensions are assumed to be
+ // unpacked in directories that are direct children of the specified path.
+ // Errors are reported through OnExtensionLoadError(). On completion,
+ // OnExtensionsLoadedFromDirectory() is called with any successfully loaded
+ // extensions.
+ bool LoadExtensionsFromDirectory(
+ const FilePath &path,
+ scoped_refptr<ExtensionsServiceFrontendInterface> frontend);
+
+ private:
+ // Notify a frontend that there was an error loading an extension.
+ void ReportExtensionLoadError(ExtensionsServiceFrontendInterface* frontend,
+ const std::wstring& error);
+
+ // Notify a frontend that extensions were loaded.
+ void ReportExtensionsLoaded(ExtensionsServiceFrontendInterface* frontend,
+ ExtensionList* extensions);
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionsServiceBackend);
+};
+
+#endif // CHROME_BROWSER_EXTENSIONS_EXTENSIONS_SERVICE_H_
diff --git a/chrome/browser/extensions/extensions_service_unittest.cc b/chrome/browser/extensions/extensions_service_unittest.cc
new file mode 100644
index 0000000..22e891d
--- /dev/null
+++ b/chrome/browser/extensions/extensions_service_unittest.cc
@@ -0,0 +1,98 @@
+// Copyright (c) 2006-2008 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.
+
+#include <vector>
+
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "base/string_util.h"
+#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/json_value_serializer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class ExtensionsServiceTest : public testing::Test {
+};
+
+
+// A mock implementation of ExtensionsServiceFrontendInterface for testing the
+// backend.
+class ExtensionsServiceTestFrontend
+ : public ExtensionsServiceFrontendInterface {
+ public:
+ std::vector<std::wstring>* errors() {
+ return &errors_;
+ }
+
+ ExtensionList* extensions() {
+ return extensions_.get();
+ }
+
+ // ExtensionsServiceFrontendInterface
+ virtual MessageLoop* GetMessageLoop() {
+ return &message_loop_;
+ }
+
+ virtual void OnExtensionLoadError(const std::wstring& message) {
+ errors_.push_back(message);
+ }
+
+ virtual void OnExtensionsLoadedFromDirectory(ExtensionList* extensions) {
+ extensions_.reset(extensions);
+ }
+
+ private:
+ MessageLoop message_loop_;
+ scoped_ptr<ExtensionList> extensions_;
+ std::vector<std::wstring> errors_;
+};
+
+
+// Test loading extensions from the profile directory.
+TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectory) {
+#if defined(OS_WIN)
+ std::wstring extensions_dir;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_dir));
+ FilePath manifest_path = FilePath::FromWStringHack(extensions_dir).Append(
+ FILE_PATH_LITERAL("extensions"));
+
+ scoped_refptr<ExtensionsServiceBackend> backend(new ExtensionsServiceBackend);
+ scoped_refptr<ExtensionsServiceTestFrontend> frontend(
+ new ExtensionsServiceTestFrontend);
+
+ std::vector<Extension*> extensions;
+ EXPECT_TRUE(backend->LoadExtensionsFromDirectory(manifest_path,
+ scoped_refptr<ExtensionsServiceFrontendInterface>(frontend.get())));
+ frontend->GetMessageLoop()->RunAllPending();
+
+ // Note: There can be more errors if there are extra directories, like .svn
+ // directories.
+ EXPECT_TRUE(frontend->errors()->size() >= 2u);
+ EXPECT_EQ(Extension::kInvalidManifestError, frontend->errors()->at(0));
+ EXPECT_EQ(Extension::kInvalidManifestError, frontend->errors()->at(1));
+ EXPECT_EQ(2u, frontend->extensions()->size());
+
+ EXPECT_EQ(std::wstring(L"com.google.myextension1"),
+ frontend->extensions()->at(0)->id());
+ EXPECT_EQ(std::wstring(L"My extension 1"),
+ frontend->extensions()->at(0)->name());
+ EXPECT_EQ(std::wstring(L"The first extension that I made."),
+ frontend->extensions()->at(0)->description());
+ EXPECT_EQ(2u, frontend->extensions()->at(0)->content_scripts().size());
+ EXPECT_EQ(std::wstring(L"script1.user.js"),
+ frontend->extensions()->at(0)->content_scripts().at(0));
+ EXPECT_EQ(std::wstring(L"script2.user.js"),
+ frontend->extensions()->at(0)->content_scripts().at(1));
+
+ EXPECT_EQ(std::wstring(L"com.google.myextension2"),
+ frontend->extensions()->at(1)->id());
+ EXPECT_EQ(std::wstring(L"My extension 2"),
+ frontend->extensions()->at(1)->name());
+ EXPECT_EQ(std::wstring(L""),
+ frontend->extensions()->at(1)->description());
+ EXPECT_EQ(0u, frontend->extensions()->at(1)->content_scripts().size());
+#endif
+};
diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc
index fb3508a..76f2f16 100644
--- a/chrome/browser/profile.cc
+++ b/chrome/browser/profile.cc
@@ -17,6 +17,7 @@
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/greasemonkey_master.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/navigation_controller.h"
@@ -384,6 +385,10 @@ class OffTheRecordProfileImpl : public Profile,
return profile_->GetVisitedLinkMaster();
}
+ virtual ExtensionsService* GetExtensionsService() {
+ return profile_->GetExtensionsService();
+ }
+
virtual GreasemonkeyMaster* GetGreasemonkeyMaster() {
return profile_->GetGreasemonkeyMaster();
}
@@ -547,6 +552,7 @@ class OffTheRecordProfileImpl : public Profile,
ProfileImpl::ProfileImpl(const std::wstring& path)
: path_(path),
off_the_record_(false),
+ extensions_service_(new ExtensionsService(FilePath(path))),
history_service_created_(false),
created_web_data_service_(false),
created_download_manager_(false),
@@ -688,6 +694,10 @@ VisitedLinkMaster* ProfileImpl::GetVisitedLinkMaster() {
return visited_link_master_.get();
}
+ExtensionsService* ProfileImpl::GetExtensionsService() {
+ return extensions_service_.get();
+}
+
GreasemonkeyMaster* ProfileImpl::GetGreasemonkeyMaster() {
if (!greasemonkey_master_.get()) {
std::wstring script_dir_str;
diff --git a/chrome/browser/profile.h b/chrome/browser/profile.h
index cb3c2ac..51a5c32 100644
--- a/chrome/browser/profile.h
+++ b/chrome/browser/profile.h
@@ -24,6 +24,7 @@
class BookmarkModel;
class DownloadManager;
+class ExtensionsService;
class GreasemonkeyMaster;
class HistoryService;
class NavigationController;
@@ -102,6 +103,10 @@ class Profile {
// that this method is called.
virtual VisitedLinkMaster* GetVisitedLinkMaster() = 0;
+ // Retrieves a pointer to the ExtensionsService associated with this
+ // profile. The ExtensionsService is created at startup.
+ virtual ExtensionsService* GetExtensionsService() = 0;
+
// Retrieves a pointer to the GreasemonkeyMaster associated with this
// profile. The GreasemonkeyMaster is lazily created the first time
// that this method is called.
@@ -243,6 +248,7 @@ class ProfileImpl : public Profile,
virtual Profile* GetOriginalProfile();
virtual VisitedLinkMaster* GetVisitedLinkMaster();
virtual GreasemonkeyMaster* GetGreasemonkeyMaster();
+ virtual ExtensionsService* GetExtensionsService();
virtual HistoryService* GetHistoryService(ServiceAccessType sat);
virtual WebDataService* GetWebDataService(ServiceAccessType sat);
virtual PrefService* GetPrefs();
@@ -303,6 +309,7 @@ class ProfileImpl : public Profile,
std::wstring path_;
bool off_the_record_;
scoped_ptr<VisitedLinkMaster> visited_link_master_;
+ scoped_refptr<ExtensionsService> extensions_service_;
scoped_refptr<GreasemonkeyMaster> greasemonkey_master_;
scoped_ptr<PrefService> prefs_;
scoped_ptr<TemplateURLFetcher> template_url_fetcher_;
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 4d076f9..feccc82 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -336,6 +336,9 @@ const wchar_t kSdchFilter[] = L"enable-sdch";
// Enable Greasemonkey script support.
const wchar_t kEnableGreasemonkey[] = L"enable-greasemonkey";
+// Enable extensions.
+const wchar_t kEnableExtensions[] = L"enable-extensions";
+
// Causes the browser to launch directly in incognito mode.
const wchar_t kIncognito[] = L"incognito";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 7a75cb5..78e8212 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -130,6 +130,7 @@ extern const wchar_t kEnableP13n[];
extern const wchar_t kSdchFilter[];
extern const wchar_t kEnableGreasemonkey[];
+extern const wchar_t kEnableExtensions[];
extern const wchar_t kIncognito[];
extern const wchar_t kUseOldSafeBrowsing[];
diff --git a/chrome/test/data/extensions/extension1/manifest b/chrome/test/data/extensions/extension1/manifest
new file mode 100755
index 0000000..b475913
--- /dev/null
+++ b/chrome/test/data/extensions/extension1/manifest
@@ -0,0 +1,10 @@
+{
+ "format_version": 1,
+ "id": "com.google.myextension1",
+ "name": "My extension 1",
+ "description": "The first extension that I made.",
+ "content_scripts": [
+ "script1.user.js",
+ "script2.user.js"
+ ]
+}
diff --git a/chrome/test/data/extensions/extension2/manifest b/chrome/test/data/extensions/extension2/manifest
new file mode 100755
index 0000000..82b25d8d
--- /dev/null
+++ b/chrome/test/data/extensions/extension2/manifest
@@ -0,0 +1,5 @@
+{
+ "format_version": 1,
+ "id": "com.google.myextension2",
+ "name": "My extension 2"
+}
diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h
index 10b6fbe..4973682 100644
--- a/chrome/test/testing_profile.h
+++ b/chrome/test/testing_profile.h
@@ -66,6 +66,9 @@ class TestingProfile : public Profile {
virtual VisitedLinkMaster* GetVisitedLinkMaster() {
return NULL;
}
+ virtual ExtensionsService* GetExtensionsService() {
+ return NULL;
+ }
virtual GreasemonkeyMaster* GetGreasemonkeyMaster() {
return NULL;
}
diff --git a/chrome/test/unit/unit_tests.scons b/chrome/test/unit/unit_tests.scons
index 320dc09..df884b1 100644
--- a/chrome/test/unit/unit_tests.scons
+++ b/chrome/test/unit/unit_tests.scons
@@ -116,6 +116,7 @@ if env['PLATFORM'] in ('posix', 'win32'):
'$CHROME_DIR/browser/chrome_thread_unittest.cc',
'$CHROME_DIR/browser/extensions/extension_unittest.cc',
+ '$CHROME_DIR/browser/extensions/extensions_service_unittest.cc',
'$CHROME_DIR/browser/history/history_types_unittest.cc',
'$CHROME_DIR/browser/history/snippet_unittest.cc',
'$CHROME_DIR/browser/history/text_database_unittest.cc',
diff --git a/chrome/test/unit/unittests.vcproj b/chrome/test/unit/unittests.vcproj
index 826959f..ab3eda5 100644
--- a/chrome/test/unit/unittests.vcproj
+++ b/chrome/test/unit/unittests.vcproj
@@ -1033,6 +1033,10 @@
RelativePath="..\..\browser\extensions\extension_unittest.cc"
>
</File>
+ <File
+ RelativePath="..\..\browser\extensions\extensions_service_unittest.cc"
+ >
+ </File>
</Filter>
</Files>
<Globals>