diff options
author | cpu@chromium.org <cpu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-08 18:42:25 +0000 |
---|---|---|
committer | cpu@chromium.org <cpu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-08 18:42:25 +0000 |
commit | 4576e9f095e767e8b78861e2cdde6d6730ad5267 (patch) | |
tree | 69df195ef0855087872358b99ca9025cbf442eb1 | |
parent | 0afa1c4259d103037bbce99a5b52057aaaef4f34 (diff) | |
download | chromium_src-4576e9f095e767e8b78861e2cdde6d6730ad5267.zip chromium_src-4576e9f095e767e8b78861e2cdde6d6730ad5267.tar.gz chromium_src-4576e9f095e767e8b78861e2cdde6d6730ad5267.tar.bz2 |
Add support for auto-installing extensions at first run via master prefs
This a even lower impact method, with no new fields added.
This is how it works:
1- The extension pared down manifest goes into the master prefs
2- The master prefs become the prefs at first run
3- First run notices an extensions block, an triggers an extensions check
4- The full extension gets updated then
BUG=37573
TEST=ut included, also see bug
Review URL: http://codereview.chromium.org/669218
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@40914 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/first_run_win.cc | 56 | ||||
-rw-r--r-- | chrome/installer/util/master_preferences.cc | 7 | ||||
-rw-r--r-- | chrome/installer/util/master_preferences.h | 43 | ||||
-rw-r--r-- | chrome/installer/util/master_preferences_unittest.cc | 39 |
4 files changed, 143 insertions, 2 deletions
diff --git a/chrome/browser/first_run_win.cc b/chrome/browser/first_run_win.cc index faaef63..c57126c 100644 --- a/chrome/browser/first_run_win.cc +++ b/chrome/browser/first_run_win.cc @@ -27,8 +27,13 @@ #include "base/string_util.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_switches.h" +#include "chrome/common/notification_registrar.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/notification_type.h" #include "chrome/common/pref_names.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_updater.h" #include "chrome/browser/hang_monitor/hung_window_detector.h" #include "chrome/browser/importer/importer.h" #include "chrome/browser/pref_service.h" @@ -151,6 +156,51 @@ bool WriteEULAtoTempFile(FilePath* eula_path) { return (file_util::WriteFile(*eula_path, terms.c_str(), terms.size()) > 0); } +// Helper class that performs delayed first-run tasks that need more of the +// chrome infrastructure to be up an running before they can be attempted. +class FirsRunDelayedTasks : public NotificationObserver { + public: + enum Tasks { + NO_TASK, + INSTALL_EXTENSIONS + }; + + explicit FirsRunDelayedTasks(Tasks task) { + if (task == INSTALL_EXTENSIONS) { + registrar_.Add(this, NotificationType::EXTENSIONS_READY, + NotificationService::AllSources()); + } + registrar_.Add(this, NotificationType::BROWSER_CLOSED, + NotificationService::AllSources()); + } + + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + // After processing the notification we always delete ourselves. + if (type.value == NotificationType::EXTENSIONS_READY) + DoExtensionWork(Source<Profile>(source).ptr()->GetExtensionsService()); + delete this; + return; + } + + private: + // Private ctor forces it to be created only in the heap. + ~FirsRunDelayedTasks() {} + + // The extension work is to basically trigger an extension update check. + // If the extension specified in the master pref is older than the live + // extension it will get updated which is the same as get it installed. + void DoExtensionWork(ExtensionsService* service) { + if (!service) + return; + service->updater()->CheckNow(); + return; + } + + NotificationRegistrar registrar_; +}; + } // namespace bool FirstRun::CreateChromeDesktopShortcut() { @@ -247,6 +297,12 @@ bool FirstRun::ProcessMasterPreferences(const FilePath& user_data_dir, if (!file_util::CopyFile(master_prefs, user_prefs)) return true; + DictionaryValue* extensions = 0; + if (installer_util::HasExtensionsBlock(prefs.get(), &extensions)) { + LOG(INFO) << "Extensions block found in master preferences"; + new FirsRunDelayedTasks(FirsRunDelayedTasks::INSTALL_EXTENSIONS); + } + // Add a special exception for import_search_engine preference. // Even though we skip all other import_* preferences below, if // skip-first-run-ui is not specified, we make exception for this one diff --git a/chrome/installer/util/master_preferences.cc b/chrome/installer/util/master_preferences.cc index cf26c3e..1e94257 100644 --- a/chrome/installer/util/master_preferences.cc +++ b/chrome/installer/util/master_preferences.cc @@ -56,6 +56,7 @@ const wchar_t kMakeChromeDefaultForUser[] = L"make_chrome_default_for_user"; const wchar_t kRequireEula[] = L"require_eula"; const wchar_t kSystemLevel[] = L"system_level"; const wchar_t kVerboseLogging[] = L"verbose_logging"; +const wchar_t kExtensionsBlock[] = L"extensions.settings"; } bool GetDistroBooleanPreference(const DictionaryValue* prefs, @@ -130,4 +131,10 @@ bool SetDistroBooleanPreference(DictionaryValue* prefs, return true; } +bool HasExtensionsBlock(const DictionaryValue* prefs, + DictionaryValue** extensions) { + return (prefs->GetDictionary(master_preferences::kExtensionsBlock, + extensions)); +} + } // installer_util diff --git a/chrome/installer/util/master_preferences.h b/chrome/installer/util/master_preferences.h index ee750a4..96d2fb6 100644 --- a/chrome/installer/util/master_preferences.h +++ b/chrome/installer/util/master_preferences.h @@ -58,6 +58,8 @@ extern const wchar_t kRequireEula[]; extern const wchar_t kSystemLevel[]; // Boolean. Run installer in verbose mode. Cmd line override present. extern const wchar_t kVerboseLogging[]; +// Name of the block that contains the extensions on the master preferences. +extern const wchar_t kExtensionsBlock[]; } // This is the default name for the master preferences file used to pre-set @@ -161,6 +163,45 @@ std::vector<std::wstring> GetDefaultBookmarks(const DictionaryValue* prefs); bool SetDistroBooleanPreference(DictionaryValue* prefs, const std::wstring& name, bool value); -} + +// The master preferences can also contain a regular extensions +// preference block. If so, the extensions referenced there will be +// installed during the first run experience. +// An extension can go in the master prefs needs just the basic +// elements such as: +// 1- An extension entry under settings, assigned by the gallery +// 2- The "location" : 1 entry +// 3- A minimal "manifest" block with key, name, permissions, update url +// and version. The version needs to be lower than the version of +// the extension that is hosted in the gallery. +// 4- The "path" entry with the version as last component +// 5- The "state" : 1 entry +// +// The following is an example of a master pref file that installs +// Google XYZ: +// +// { +// "extensions": { +// "settings": { +// "ppflmjolhbonpkbkooiamcnenbmbjcbb": { +// "location": 1, +// "manifest": { +// "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4<rest of key ommited>", +// "name": "Google XYZ (Installing...)", +// "permissions": [ "tabs", "http://xyz.google.com/" ], +// "update_url": "http://fixme.com/fixme/fixme/crx", +// "version": "0.0" +// }, +// "path": "ppflmjolhbonpkbkooiamcnenbmbjcbb\\0.0", +// "state": 1 +// } +// } +// } +// } +// +bool HasExtensionsBlock(const DictionaryValue* prefs, + DictionaryValue** extensions); + +} // namespace installer_util #endif // CHROME_INSTALLER_UTIL_MASTER_PREFERENCES_H_ diff --git a/chrome/installer/util/master_preferences_unittest.cc b/chrome/installer/util/master_preferences_unittest.cc index 18e560f..8ff41e0 100644 --- a/chrome/installer/util/master_preferences_unittest.cc +++ b/chrome/installer/util/master_preferences_unittest.cc @@ -4,8 +4,10 @@ // // Unit tests for master preferences related methods. -#include "base/scoped_ptr.h" #include "base/file_util.h" +#include "base/path_service.h" +#include "base/scoped_ptr.h" +#include "chrome/common/chrome_paths.h" #include "chrome/common/json_value_serializer.h" #include "chrome/installer/util/master_preferences.h" #include "testing/gtest/include/gtest/gtest.h" @@ -229,3 +231,38 @@ TEST_F(MasterPreferencesTest, FirstRunBookMarks) { EXPECT_EQ(L"http://google.com/b1", bookmarks[0]); EXPECT_EQ(L"https://google.com/b2", bookmarks[1]); } + +// In this test instead of using our synthetic json file, we use an +// actual test case from the extensions unittest. The hope here is that if +// they change something in the manifest this test will break, but in +// general it is expected the extension format to be backwards compatible. +TEST(MasterPrefsExtension, ValidateExtensionJSON) { + FilePath prefs_path; + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &prefs_path)); + prefs_path = prefs_path.AppendASCII("extensions") + .AppendASCII("good").AppendASCII("Preferences"); + + scoped_ptr<DictionaryValue> prefs( + installer_util::ParseDistributionPreferences(prefs_path)); + ASSERT_TRUE(prefs.get() != NULL); + DictionaryValue* extensions = NULL; + EXPECT_TRUE(installer_util::HasExtensionsBlock(prefs.get(), &extensions)); + int location = 0; + EXPECT_TRUE(extensions->GetInteger( + L"behllobkkfkfnphdnhnkndlbkcpglgmj.location", &location)); + int state = 0; + EXPECT_TRUE(extensions->GetInteger( + L"behllobkkfkfnphdnhnkndlbkcpglgmj.state", &state)); + std::wstring path; + EXPECT_TRUE(extensions->GetString( + L"behllobkkfkfnphdnhnkndlbkcpglgmj.path", &path)); + std::wstring key; + EXPECT_TRUE(extensions->GetString( + L"behllobkkfkfnphdnhnkndlbkcpglgmj.manifest.key", &key)); + std::wstring name; + EXPECT_TRUE(extensions->GetString( + L"behllobkkfkfnphdnhnkndlbkcpglgmj.manifest.name", &name)); + std::wstring version; + EXPECT_TRUE(extensions->GetString( + L"behllobkkfkfnphdnhnkndlbkcpglgmj.manifest.version", &version)); +} |