summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcpu@chromium.org <cpu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-08 18:42:25 +0000
committercpu@chromium.org <cpu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-08 18:42:25 +0000
commit4576e9f095e767e8b78861e2cdde6d6730ad5267 (patch)
tree69df195ef0855087872358b99ca9025cbf442eb1
parent0afa1c4259d103037bbce99a5b52057aaaef4f34 (diff)
downloadchromium_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.cc56
-rw-r--r--chrome/installer/util/master_preferences.cc7
-rw-r--r--chrome/installer/util/master_preferences.h43
-rw-r--r--chrome/installer/util/master_preferences_unittest.cc39
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));
+}