Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(51)

Side by Side Diff: chrome/browser/extensions/installed_loader.cc

Issue 8417012: Refactor loading out of ExtensionService. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: finally Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 #include "chrome/browser/extensions/installed_loader.h"
6
7 #include "base/file_path.h"
8 #include "base/metrics/histogram.h"
9 #include "base/stringprintf.h"
10 #include "base/utf_string_conversions.h"
11 #include "base/values.h"
12 #include "chrome/browser/extensions/extension_prefs.h"
13 #include "chrome/browser/extensions/extension_service.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "chrome/common/extensions/extension.h"
16 #include "chrome/common/extensions/extension_file_util.h"
17 #include "chrome/common/extensions/extension_l10n_util.h"
18 #include "chrome/common/pref_names.h"
19 #include "content/public/browser/notification_service.h"
20 #include "content/browser/user_metrics.h"
21
22 namespace errors = extension_manifest_errors;
23
24 namespace {
25
26 // The following enumeration is used in histograms matching
27 // Extensions.ManifestReload* . Values may be added, as long as existing
28 // values are not changed.
29 enum ManifestReloadReason {
30 NOT_NEEDED = 0, // Reload not needed.
31 UNPACKED_DIR, // Unpacked directory.
32 NEEDS_RELOCALIZATION, // The locale has changed since we read this extension.
33 NUM_MANIFEST_RELOAD_REASONS
34 };
35
36 ManifestReloadReason ShouldReloadExtensionManifest(const ExtensionInfo& info) {
37 // Always reload manifests of unpacked extensions, because they can change
38 // on disk independent of the manifest in our prefs.
39 if (info.extension_location == Extension::LOAD)
40 return UNPACKED_DIR;
41
42 // Reload the manifest if it needs to be relocalized.
43 if (extension_l10n_util::ShouldRelocalizeManifest(info))
44 return NEEDS_RELOCALIZATION;
45
46 return NOT_NEEDED;
47 }
48
49 } // namespace
50
51 namespace extensions {
52
53 InstalledLoader::InstalledLoader(ExtensionService* extension_service)
54 : extension_service_(extension_service),
55 extension_prefs_(extension_service->extension_prefs()) {
56 }
57
58 InstalledLoader::~InstalledLoader() {
59 }
60
61 void InstalledLoader::Load(const ExtensionInfo& info, bool write_to_prefs) {
62 std::string error;
63 scoped_refptr<const Extension> extension(NULL);
64 // An explicit check against policy is required to behave correctly during
65 // startup. This is because extensions that were previously OK might have
66 // been blacklisted in policy while Chrome was not running.
67 if (!extension_prefs_->IsExtensionAllowedByPolicy(info.extension_id,
68 info.extension_location)) {
69 error = errors::kDisabledByPolicy;
70 } else if (info.extension_manifest.get()) {
71 extension = Extension::Create(
72 info.extension_path,
73 info.extension_location,
74 *info.extension_manifest,
75 GetCreationFlags(&info),
76 &error);
77 } else {
78 error = errors::kManifestUnreadable;
79 }
80
81 // Once installed, non-unpacked extensions cannot change their IDs (e.g., by
82 // updating the 'key' field in their manifest).
83 if (extension &&
84 extension->location() != Extension::LOAD &&
85 info.extension_id != extension->id()) {
86 error = errors::kCannotChangeExtensionID;
87 extension = NULL;
88 UserMetrics::RecordAction(UserMetricsAction("Extensions.IDChangedError"));
89 }
90
91 if (!extension) {
92 extension_service_->
93 ReportExtensionLoadError(info.extension_path, error, false);
94 return;
95 }
96
97 if (write_to_prefs)
98 extension_prefs_->UpdateManifest(extension);
99
100 extension_service_->AddExtension(extension);
101 }
102
103 void InstalledLoader::LoadAllExtensions() {
104 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
105
106 base::TimeTicks start_time = base::TimeTicks::Now();
107
108 scoped_ptr<ExtensionPrefs::ExtensionsInfo> extensions_info(
109 extension_prefs_->GetInstalledExtensionsInfo());
110
111 std::vector<int> reload_reason_counts(NUM_MANIFEST_RELOAD_REASONS, 0);
112 bool should_write_prefs = false;
113
114 for (size_t i = 0; i < extensions_info->size(); ++i) {
115 ExtensionInfo* info = extensions_info->at(i).get();
116
117 ManifestReloadReason reload_reason = ShouldReloadExtensionManifest(*info);
118 ++reload_reason_counts[reload_reason];
119 UMA_HISTOGRAM_ENUMERATION("Extensions.ManifestReloadEnumValue",
120 reload_reason, 100);
121
122 if (reload_reason != NOT_NEEDED) {
123 // Reloading an extension reads files from disk. We do this on the
124 // UI thread because reloads should be very rare, and the complexity
125 // added by delaying the time when the extensions service knows about
126 // all extensions is significant. See crbug.com/37548 for details.
127 // |allow_io| disables tests that file operations run on the file
128 // thread.
129 base::ThreadRestrictions::ScopedAllowIO allow_io;
130
131 std::string error;
132 scoped_refptr<const Extension> extension(
133 extension_file_util::LoadExtension(
134 info->extension_path,
135 info->extension_location,
136 GetCreationFlags(info),
137 &error));
138
139 if (extension.get()) {
140 extensions_info->at(i)->extension_manifest.reset(
141 static_cast<DictionaryValue*>(
142 extension->manifest_value()->DeepCopy()));
143 should_write_prefs = true;
144 }
145 }
146 }
147
148 for (size_t i = 0; i < extensions_info->size(); ++i) {
149 Load(*extensions_info->at(i), should_write_prefs);
150 }
151
152 extension_service_->OnLoadedInstalledExtensions();
153
154 // The histograms Extensions.ManifestReload* allow us to validate
155 // the assumption that reloading manifest is a rare event.
156 UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNotNeeded",
157 reload_reason_counts[NOT_NEEDED]);
158 UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadUnpackedDir",
159 reload_reason_counts[UNPACKED_DIR]);
160 UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNeedsRelocalization",
161 reload_reason_counts[NEEDS_RELOCALIZATION]);
162
163 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAll",
164 extension_service_->extensions()->size());
165 UMA_HISTOGRAM_COUNTS_100("Extensions.Disabled",
166 extension_service_->disabled_extensions()->size());
167
168 UMA_HISTOGRAM_TIMES("Extensions.LoadAllTime",
169 base::TimeTicks::Now() - start_time);
170
171 int app_user_count = 0;
172 int app_external_count = 0;
173 int hosted_app_count = 0;
174 int packaged_app_count = 0;
175 int user_script_count = 0;
176 int extension_user_count = 0;
177 int extension_external_count = 0;
178 int theme_count = 0;
179 int page_action_count = 0;
180 int browser_action_count = 0;
181 const ExtensionList* extensions = extension_service_->extensions();
182 ExtensionList::const_iterator ex;
183 for (ex = extensions->begin(); ex != extensions->end(); ++ex) {
184 Extension::Location location = (*ex)->location();
185 Extension::Type type = (*ex)->GetType();
186 if ((*ex)->is_app()) {
187 UMA_HISTOGRAM_ENUMERATION("Extensions.AppLocation",
188 location, 100);
189 } else if (type == Extension::TYPE_EXTENSION) {
190 UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionLocation",
191 location, 100);
192 }
193
194 // Don't count component extensions, since they are only extensions as an
195 // implementation detail.
196 if (location == Extension::COMPONENT)
197 continue;
198
199 // Don't count unpacked extensions, since they're a developer-specific
200 // feature.
201 if (location == Extension::LOAD)
202 continue;
203
204 // Using an enumeration shows us the total installed ratio across all users.
205 // Using the totals per user at each startup tells us the distribution of
206 // usage for each user (e.g. 40% of users have at least one app installed).
207 UMA_HISTOGRAM_ENUMERATION("Extensions.LoadType", type, 100);
208 switch (type) {
209 case Extension::TYPE_THEME:
210 ++theme_count;
211 break;
212 case Extension::TYPE_USER_SCRIPT:
213 ++user_script_count;
214 break;
215 case Extension::TYPE_HOSTED_APP:
216 ++hosted_app_count;
217 if (Extension::IsExternalLocation(location)) {
218 ++app_external_count;
219 } else {
220 ++app_user_count;
221 }
222 break;
223 case Extension::TYPE_PACKAGED_APP:
224 ++packaged_app_count;
225 if (Extension::IsExternalLocation(location)) {
226 ++app_external_count;
227 } else {
228 ++app_user_count;
229 }
230 break;
231 case Extension::TYPE_EXTENSION:
232 default:
233 if (Extension::IsExternalLocation(location)) {
234 ++extension_external_count;
235 } else {
236 ++extension_user_count;
237 }
238 break;
239 }
240 if ((*ex)->page_action() != NULL)
241 ++page_action_count;
242 if ((*ex)->browser_action() != NULL)
243 ++browser_action_count;
244
245 extension_service_->RecordPermissionMessagesHistogram(
246 ex->get(), "Extensions.Permissions_Load");
247 }
248 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadApp",
249 app_user_count + app_external_count);
250 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAppUser", app_user_count);
251 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAppExternal", app_external_count);
252 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadHostedApp", hosted_app_count);
253 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPackagedApp", packaged_app_count);
254 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtension",
255 extension_user_count + extension_external_count);
256 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtensionUser",
257 extension_user_count);
258 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtensionExternal",
259 extension_external_count);
260 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadUserScript", user_script_count);
261 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadTheme", theme_count);
262 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPageAction", page_action_count);
263 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadBrowserAction",
264 browser_action_count);
265 }
266
267 int InstalledLoader::GetCreationFlags(const ExtensionInfo* info) {
268 int flags = Extension::NO_FLAGS;
269 if (info->extension_location != Extension::LOAD)
270 flags |= Extension::REQUIRE_KEY;
271 if (Extension::ShouldDoStrictErrorChecking(info->extension_location))
272 flags |= Extension::STRICT_ERROR_CHECKS;
273 if (extension_prefs_->AllowFileAccess(info->extension_id))
274 flags |= Extension::ALLOW_FILE_ACCESS;
275 if (extension_prefs_->IsFromWebStore(info->extension_id))
276 flags |= Extension::FROM_WEBSTORE;
277 if (extension_prefs_->IsFromBookmark(info->extension_id))
278 flags |= Extension::FROM_BOOKMARK;
279 return flags;
280 }
281
282 } // namespace extensions
OLDNEW
« no previous file with comments | « chrome/browser/extensions/installed_loader.h ('k') | chrome/browser/extensions/network_delay_listener_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698