OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/extensions/component_loader.h" | 5 #include "chrome/browser/extensions/component_loader.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/path_service.h" | 8 #include "base/path_service.h" |
9 #include "base/json/json_value_serializer.h" | 9 #include "base/json/json_value_serializer.h" |
10 #include "chrome/browser/browser_process.h" | 10 #include "chrome/browser/browser_process.h" |
11 #include "chrome/browser/extensions/extension_service.h" | 11 #include "chrome/browser/extensions/extension_service.h" |
12 #include "chrome/browser/prefs/pref_change_registrar.h" | |
13 #include "chrome/browser/prefs/pref_notifier.h" | |
14 #include "chrome/browser/profiles/profile.h" | |
15 #include "chrome/common/chrome_notification_types.h" | |
12 #include "chrome/common/chrome_paths.h" | 16 #include "chrome/common/chrome_paths.h" |
13 #include "chrome/common/chrome_switches.h" | 17 #include "chrome/common/chrome_switches.h" |
14 #include "chrome/common/extensions/extension.h" | 18 #include "chrome/common/extensions/extension.h" |
15 #include "chrome/common/pref_names.h" | 19 #include "chrome/common/pref_names.h" |
20 #include "content/public/browser/notification_details.h" | |
21 #include "content/public/browser/notification_source.h" | |
16 #include "grit/browser_resources.h" | 22 #include "grit/browser_resources.h" |
17 #include "ui/base/resource/resource_bundle.h" | 23 #include "ui/base/resource/resource_bundle.h" |
18 | 24 |
19 #if defined(OFFICIAL_BUILD) | 25 #if defined(OFFICIAL_BUILD) |
20 #include "chrome/browser/defaults.h" | 26 #include "chrome/browser/defaults.h" |
21 #endif | 27 #endif |
22 | 28 |
23 namespace { | |
24 | |
25 typedef std::list<std::pair<FilePath::StringType, int> > | |
26 ComponentExtensionList; | |
27 | |
28 #if defined(FILE_MANAGER_EXTENSION) | |
29 void AddFileManagerExtension(ComponentExtensionList* component_extensions) { | |
30 #ifndef NDEBUG | |
31 const CommandLine* command_line = CommandLine::ForCurrentProcess(); | |
32 if (command_line->HasSwitch(switches::kFileManagerExtensionPath)) { | |
33 FilePath filemgr_extension_path = | |
34 command_line->GetSwitchValuePath(switches::kFileManagerExtensionPath); | |
35 component_extensions->push_back(std::make_pair( | |
36 filemgr_extension_path.value(), | |
37 IDR_FILEMANAGER_MANIFEST)); | |
38 return; | |
39 } | |
40 #endif // NDEBUG | |
41 component_extensions->push_back(std::make_pair( | |
42 FILE_PATH_LITERAL("file_manager"), | |
43 IDR_FILEMANAGER_MANIFEST)); | |
44 } | |
45 #endif // defined(FILE_MANAGER_EXTENSION) | |
46 | |
47 } // namespace | |
48 | |
49 namespace extensions { | 29 namespace extensions { |
50 | 30 |
51 bool ComponentLoader::ComponentExtensionInfo::Equals( | 31 ComponentLoader::ComponentLoader(ExtensionServiceInterface* extension_service, |
52 const ComponentExtensionInfo& other) const { | 32 PrefService* prefs, |
53 return other.manifest == manifest && other.root_directory == root_directory; | 33 PrefService* local_state) |
54 } | 34 : prefs_(prefs), |
35 local_state_(local_state), | |
36 extension_service_(extension_service) { | |
37 pref_change_registrar_.Init(prefs); | |
55 | 38 |
56 ComponentLoader::ComponentLoader(ExtensionService* extension_service) | 39 // This pref is set by policy. We have to watch it for change because on |
57 : extension_service_(extension_service) { | 40 // ChromeOS, policy isn't loaded until after the browser process is started. |
41 pref_change_registrar_.Add(prefs::kEnterpriseWebStoreURL, this); | |
58 } | 42 } |
59 | 43 |
60 ComponentLoader::~ComponentLoader() { | 44 ComponentLoader::~ComponentLoader() { |
61 } | 45 } |
62 | 46 |
63 void ComponentLoader::LoadAll() { | 47 void ComponentLoader::LoadAll() { |
64 for (RegisteredComponentExtensions::iterator it = | 48 for (RegisteredComponentExtensions::iterator it = |
65 component_extensions_.begin(); | 49 component_extensions_.begin(); |
66 it != component_extensions_.end(); ++it) { | 50 it != component_extensions_.end(); ++it) { |
67 Load(*it); | 51 Load(*it); |
68 } | 52 } |
69 } | 53 } |
70 | 54 |
55 DictionaryValue* ComponentLoader::ParseManifest( | |
56 const std::string& manifest_contents) const { | |
57 JSONStringValueSerializer serializer(manifest_contents); | |
58 scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL)); | |
59 | |
60 if (!manifest.get() || !manifest->IsType(Value::TYPE_DICTIONARY)) { | |
61 LOG(ERROR) << "Failed to parse extension manifest."; | |
62 return NULL; | |
63 } | |
64 // Transfer ownership to the caller. | |
65 return static_cast<DictionaryValue*>(manifest.release()); | |
66 } | |
67 | |
71 const Extension* ComponentLoader::Add( | 68 const Extension* ComponentLoader::Add( |
72 const std::string& manifest, const FilePath& root_directory) { | 69 int manifest_resource_id, |
73 ComponentExtensionInfo info(manifest, root_directory); | 70 const FilePath& root_directory) { |
74 Register(info); | 71 std::string manifest_contents = |
72 ResourceBundle::GetSharedInstance().GetRawDataResource( | |
73 manifest_resource_id).as_string(); | |
74 return Add(manifest_contents, root_directory); | |
75 } | |
76 | |
77 const Extension* ComponentLoader::Add( | |
78 std::string& manifest_contents, | |
79 const FilePath& root_directory) { | |
80 // The Value is kept for the lifetime of the ComponentLoader. This is | |
81 // required in case LoadAll() is called again. | |
82 DictionaryValue* manifest = ParseManifest(manifest_contents); | |
83 if (manifest) | |
84 return Add(manifest, root_directory); | |
85 return NULL; | |
86 } | |
87 | |
88 const Extension* ComponentLoader::Add( | |
89 const DictionaryValue* parsed_manifest, | |
90 const FilePath& root_directory) { | |
91 // Get the absolute path to the extension. | |
92 FilePath absolute_path(root_directory); | |
93 if (!absolute_path.IsAbsolute()) { | |
94 if (PathService::Get(chrome::DIR_RESOURCES, &absolute_path)) { | |
95 absolute_path = absolute_path.Append(root_directory); | |
96 } else { | |
97 NOTREACHED(); | |
98 } | |
99 } | |
100 | |
101 ComponentExtensionInfo info(parsed_manifest, absolute_path); | |
102 component_extensions_.push_back(info); | |
75 if (extension_service_->is_ready()) | 103 if (extension_service_->is_ready()) |
76 return Load(info); | 104 return Load(info); |
77 return NULL; | 105 return NULL; |
78 } | 106 } |
79 | 107 |
80 const Extension* ComponentLoader::Load(const ComponentExtensionInfo& info) { | 108 const Extension* ComponentLoader::Load(const ComponentExtensionInfo& info) { |
81 JSONStringValueSerializer serializer(info.manifest); | |
82 scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL)); | |
83 if (!manifest.get()) { | |
84 LOG(ERROR) << "Failed to parse manifest for extension"; | |
85 return NULL; | |
86 } | |
87 | |
88 int flags = Extension::REQUIRE_KEY; | 109 int flags = Extension::REQUIRE_KEY; |
89 if (Extension::ShouldDoStrictErrorChecking(Extension::COMPONENT)) | 110 if (Extension::ShouldDoStrictErrorChecking(Extension::COMPONENT)) |
90 flags |= Extension::STRICT_ERROR_CHECKS; | 111 flags |= Extension::STRICT_ERROR_CHECKS; |
91 std::string error; | 112 std::string error; |
92 scoped_refptr<const Extension> extension(Extension::Create( | 113 scoped_refptr<const Extension> extension(Extension::Create( |
93 info.root_directory, | 114 info.root_directory, |
94 Extension::COMPONENT, | 115 Extension::COMPONENT, |
95 *static_cast<DictionaryValue*>(manifest.get()), | 116 *info.manifest, |
96 flags, | 117 flags, |
97 &error)); | 118 &error)); |
98 if (!extension.get()) { | 119 if (!extension.get()) { |
99 LOG(ERROR) << error; | 120 LOG(ERROR) << error; |
100 return NULL; | 121 return NULL; |
101 } | 122 } |
102 extension_service_->AddExtension(extension); | 123 extension_service_->AddExtension(extension); |
103 return extension; | 124 return extension; |
104 } | 125 } |
105 | 126 |
106 void ComponentLoader::Remove(const std::string& manifest_str) { | 127 void ComponentLoader::Remove(const FilePath& root_directory) { |
107 // Unload the extension. | 128 // Find the ComponentExtensionInfo for the extension. |
108 JSONStringValueSerializer serializer(manifest_str); | 129 RegisteredComponentExtensions::iterator it = component_extensions_.begin(); |
109 scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL)); | 130 for (; it != component_extensions_.end(); ++it) { |
110 if (!manifest.get()) { | 131 if (it->root_directory == root_directory) |
111 LOG(ERROR) << "Failed to parse manifest for extension"; | 132 break; |
133 } | |
134 // If the extension is not in the list, there's nothing to do. | |
135 if (it == component_extensions_.end()) | |
112 return; | 136 return; |
113 } | 137 |
138 const DictionaryValue* manifest = it->manifest; | |
139 | |
140 // Remove the extension from the list of registered extensions. | |
141 *it = component_extensions_.back(); | |
142 component_extensions_.pop_back(); | |
143 | |
144 // Determine the extension id and unload the extension. | |
114 std::string public_key; | 145 std::string public_key; |
115 std::string public_key_bytes; | 146 std::string public_key_bytes; |
116 std::string id; | 147 std::string id; |
117 if (!static_cast<DictionaryValue*>(manifest.get())-> | 148 if (!manifest->GetString( |
118 GetString(extension_manifest_keys::kPublicKey, &public_key) || | 149 extension_manifest_keys::kPublicKey, &public_key) || |
119 !Extension::ParsePEMKeyBytes(public_key, &public_key_bytes) || | 150 !Extension::ParsePEMKeyBytes(public_key, &public_key_bytes) || |
120 !Extension::GenerateId(public_key_bytes, &id)) { | 151 !Extension::GenerateId(public_key_bytes, &id)) { |
121 LOG(ERROR) << "Failed to get extension id"; | 152 LOG(ERROR) << "Failed to get extension id"; |
122 return; | 153 return; |
123 } | 154 } |
124 extension_service_-> | 155 extension_service_-> |
125 UnloadExtension(id, extension_misc::UNLOAD_REASON_DISABLE); | 156 UnloadExtension(id, extension_misc::UNLOAD_REASON_DISABLE); |
126 | |
127 // Unregister the extension. | |
128 RegisteredComponentExtensions new_component_extensions; | |
129 for (RegisteredComponentExtensions::iterator it = | |
130 component_extensions_.begin(); | |
131 it != component_extensions_.end(); ++it) { | |
132 if (it->manifest != manifest_str) | |
133 new_component_extensions.push_back(*it); | |
134 } | |
135 component_extensions_.swap(new_component_extensions); | |
136 } | 157 } |
137 | 158 |
138 // We take ComponentExtensionList: | 159 void ComponentLoader::AddFileManagerExtension() { |
139 // path, manifest ID => full manifest, absolute path | 160 #if defined(FILE_MANAGER_EXTENSION) |
161 #ifndef NDEBUG | |
162 const CommandLine* command_line = CommandLine::ForCurrentProcess(); | |
163 if (command_line->HasSwitch(switches::kFileManagerExtensionPath)) { | |
164 FilePath filemgr_extension_path( | |
165 command_line->GetSwitchValuePath(switches::kFileManagerExtensionPath)); | |
166 Add(IDR_FILEMANAGER_MANIFEST, filemgr_extension_path); | |
167 return; | |
168 } | |
169 #endif // NDEBUG | |
170 Add(IDR_FILEMANAGER_MANIFEST, FilePath(FILE_PATH_LITERAL("file_manager"))); | |
171 #endif // defined(FILE_MANAGER_EXTENSION) | |
172 } | |
173 | |
174 void ComponentLoader::AddOrReloadEnterpriseWebStore() { | |
175 FilePath path(FILE_PATH_LITERAL("enterprise_web_store")); | |
176 | |
177 // Remove the extension if it was already loaded. | |
178 Remove(path); | |
Jeffrey Yasskin
2013/05/14 02:26:32
This Remove() call isn't working anymore, at least
| |
179 | |
180 std::string enterprise_webstore_url = | |
181 prefs_->GetString(prefs::kEnterpriseWebStoreURL); | |
182 | |
183 // Load the extension only if the URL preference is set. | |
184 if (!enterprise_webstore_url.empty()) { | |
185 std::string manifest_contents = | |
186 ResourceBundle::GetSharedInstance().GetRawDataResource( | |
187 IDR_ENTERPRISE_WEBSTORE_MANIFEST).as_string(); | |
188 | |
189 // The manifest is missing some values that are provided by policy. | |
190 DictionaryValue* manifest = ParseManifest(manifest_contents); | |
191 if (manifest) { | |
192 std::string name = prefs_->GetString(prefs::kEnterpriseWebStoreName); | |
193 manifest->SetString("app.launch.web_url", enterprise_webstore_url); | |
194 manifest->SetString("name", name); | |
195 Add(manifest, path); | |
196 } | |
197 } | |
198 } | |
199 | |
140 void ComponentLoader::AddDefaultComponentExtensions() { | 200 void ComponentLoader::AddDefaultComponentExtensions() { |
141 ComponentExtensionList component_extensions; | 201 Add(IDR_BOOKMARKS_MANIFEST, FilePath(FILE_PATH_LITERAL("bookmark_manager"))); |
142 | |
143 // Bookmark manager. | |
144 component_extensions.push_back(std::make_pair( | |
145 FILE_PATH_LITERAL("bookmark_manager"), | |
146 IDR_BOOKMARKS_MANIFEST)); | |
147 | 202 |
148 #if defined(FILE_MANAGER_EXTENSION) | 203 #if defined(FILE_MANAGER_EXTENSION) |
149 AddFileManagerExtension(&component_extensions); | 204 AddFileManagerExtension(); |
150 #endif | 205 #endif |
151 | 206 |
152 #if defined(USE_VIRTUAL_KEYBOARD) | 207 #if defined(USE_VIRTUAL_KEYBOARD) |
153 component_extensions.push_back(std::make_pair( | 208 Add(IDR_KEYBOARD_MANIFEST, FilePath(FILE_PATH_LITERAL("keyboard"))); |
154 FILE_PATH_LITERAL("keyboard"), | |
155 IDR_KEYBOARD_MANIFEST)); | |
156 #endif | 209 #endif |
157 | 210 |
158 #if defined(OS_CHROMEOS) | 211 #if defined(OS_CHROMEOS) |
159 component_extensions.push_back(std::make_pair( | 212 Add(IDR_MOBILE_MANIFEST, |
160 FILE_PATH_LITERAL("/usr/share/chromeos-assets/mobile"), | 213 FilePath(FILE_PATH_LITERAL("/usr/share/chromeos-assets/mobile"))); |
161 IDR_MOBILE_MANIFEST)); | |
162 | 214 |
163 const CommandLine* command_line = CommandLine::ForCurrentProcess(); | 215 const CommandLine* command_line = CommandLine::ForCurrentProcess(); |
164 if (command_line->HasSwitch(switches::kAuthExtensionPath)) { | 216 if (command_line->HasSwitch(switches::kAuthExtensionPath)) { |
165 FilePath auth_extension_path = | 217 FilePath auth_extension_path = |
166 command_line->GetSwitchValuePath(switches::kAuthExtensionPath); | 218 command_line->GetSwitchValuePath(switches::kAuthExtensionPath); |
167 component_extensions.push_back(std::make_pair( | 219 Add(IDR_GAIA_TEST_AUTH_MANIFEST, auth_extension_path); |
168 auth_extension_path.value(), | |
169 IDR_GAIA_TEST_AUTH_MANIFEST)); | |
170 } else { | 220 } else { |
171 component_extensions.push_back(std::make_pair( | 221 Add(IDR_GAIA_AUTH_MANIFEST, |
172 FILE_PATH_LITERAL("/usr/share/chromeos-assets/gaia_auth"), | 222 FilePath(FILE_PATH_LITERAL("/usr/share/chromeos-assets/gaia_auth"))); |
173 IDR_GAIA_AUTH_MANIFEST)); | |
174 } | 223 } |
175 | 224 |
176 #if defined(OFFICIAL_BUILD) | 225 #if defined(OFFICIAL_BUILD) |
177 if (browser_defaults::enable_help_app) { | 226 if (browser_defaults::enable_help_app) { |
178 component_extensions.push_back(std::make_pair( | 227 Add(IDR_HELP_MANIFEST, |
179 FILE_PATH_LITERAL("/usr/share/chromeos-assets/helpapp"), | 228 FilePath(FILE_PATH_LITERAL("/usr/share/chromeos-assets/helpapp"))); |
180 IDR_HELP_MANIFEST)); | |
181 } | 229 } |
182 #endif | 230 #endif |
183 #endif | 231 #endif // !defined(OS_CHROMEOS) |
184 | 232 |
185 // Web Store. | 233 Add(IDR_WEBSTORE_MANIFEST, FilePath(FILE_PATH_LITERAL("web_store"))); |
186 component_extensions.push_back(std::make_pair( | |
187 FILE_PATH_LITERAL("web_store"), | |
188 IDR_WEBSTORE_MANIFEST)); | |
189 | 234 |
190 #if !defined(OS_CHROMEOS) | 235 #if !defined(OS_CHROMEOS) |
191 // Cloud Print component app. Not required on Chrome OS. | 236 // Cloud Print component app. Not required on Chrome OS. |
192 component_extensions.push_back(std::make_pair( | 237 Add(IDR_CLOUDPRINT_MANIFEST, FilePath(FILE_PATH_LITERAL("cloud_print"))); |
193 FILE_PATH_LITERAL("cloud_print"), | 238 #endif |
194 IDR_CLOUDPRINT_MANIFEST)); | |
195 #endif // !defined(OS_CHROMEOS) | |
196 | |
197 for (ComponentExtensionList::iterator iter = component_extensions.begin(); | |
198 iter != component_extensions.end(); ++iter) { | |
199 FilePath path(iter->first); | |
200 if (!path.IsAbsolute()) { | |
201 if (PathService::Get(chrome::DIR_RESOURCES, &path)) { | |
202 path = path.Append(iter->first); | |
203 } else { | |
204 NOTREACHED(); | |
205 } | |
206 } | |
207 | |
208 std::string manifest = | |
209 ResourceBundle::GetSharedInstance().GetRawDataResource( | |
210 iter->second).as_string(); | |
211 Add(manifest, path); | |
212 } | |
213 | 239 |
214 #if defined(OS_CHROMEOS) | 240 #if defined(OS_CHROMEOS) |
215 // Register access extensions only if accessibility is enabled. | 241 // Register access extensions only if accessibility is enabled. |
216 if (g_browser_process->local_state()-> | 242 if (local_state_->GetBoolean(prefs::kAccessibilityEnabled)) { |
217 GetBoolean(prefs::kAccessibilityEnabled)) { | |
218 FilePath path = FilePath(extension_misc::kAccessExtensionPath) | 243 FilePath path = FilePath(extension_misc::kAccessExtensionPath) |
219 .AppendASCII(extension_misc::kChromeVoxDirectoryName); | 244 .AppendASCII(extension_misc::kChromeVoxDirectoryName); |
220 std::string manifest = | 245 Add(IDR_CHROMEVOX_MANIFEST, path); |
221 ResourceBundle::GetSharedInstance().GetRawDataResource( | |
222 IDR_CHROMEVOX_MANIFEST).as_string(); | |
223 Add(manifest, path); | |
224 } | 246 } |
225 #endif | 247 #endif |
248 | |
249 // If a URL for the enterprise webstore has been specified, load the | |
250 // component extension. This extension might also be loaded later, because | |
251 // it is specified by policy, and on ChromeOS policies are loaded after | |
252 // the browser process has started. | |
253 AddOrReloadEnterpriseWebStore(); | |
254 } | |
255 | |
256 void ComponentLoader::Observe( | |
257 int type, | |
258 const content::NotificationSource& source, | |
259 const content::NotificationDetails& details) { | |
260 if (type == chrome::NOTIFICATION_PREF_CHANGED) { | |
261 const std::string* name = | |
262 content::Details<const std::string>(details).ptr(); | |
263 if (*name == prefs::kEnterpriseWebStoreURL) | |
264 AddOrReloadEnterpriseWebStore(); | |
265 else | |
266 NOTREACHED(); | |
267 } else { | |
268 NOTREACHED(); | |
269 } | |
270 } | |
271 | |
272 // static | |
273 void ComponentLoader::RegisterUserPrefs(PrefService* prefs) { | |
274 prefs->RegisterStringPref(prefs::kEnterpriseWebStoreURL, | |
275 std::string() /* default_value */, | |
276 PrefService::UNSYNCABLE_PREF); | |
277 prefs->RegisterStringPref(prefs::kEnterpriseWebStoreName, | |
278 std::string() /* default_value */, | |
279 PrefService::UNSYNCABLE_PREF); | |
226 } | 280 } |
227 | 281 |
228 } // namespace extensions | 282 } // namespace extensions |
OLD | NEW |