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

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

Issue 8417012: Refactor loading out of ExtensionService. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: 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_extension_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
Aaron Boodman 2011/10/28 22:21:58 Nit: reformat comment.
Yoyo Zhou 2011/10/31 21:58:15 Done.
27 // Extensions.ManifestReload* . Values may be added, as long
28 // as existing values are not changed.
29 enum ManifestReloadReason {
30 NOT_NEEDED = 0, // Reload not needed.
31 UNPACKED_DIR, // Unpacked directory
32 NEEDS_RELOCALIZATION, // The local 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 InstalledExtensionLoader::InstalledExtensionLoader(
52 ExtensionService* extension_service,
53 ExtensionPrefs* extension_prefs)
54 : extension_service_(extension_service),
55 extension_prefs_(extension_prefs) {
56 }
57
58 InstalledExtensionLoader::~InstalledExtensionLoader() {
59 }
60
61 void InstalledExtensionLoader::Load(const ExtensionInfo& info,
62 bool write_to_prefs) {
63 std::string error;
64 scoped_refptr<const Extension> extension(NULL);
65 if (!extension_prefs_->IsExtensionAllowedByPolicy(info.extension_id)) {
66 error = errors::kDisabledByPolicy;
67 } else if (info.extension_manifest.get()) {
68 extension = Extension::Create(
69 info.extension_path,
70 info.extension_location,
71 *info.extension_manifest,
72 GetExtensionCreateFlagsForInstalledExtension(&info),
73 &error);
74 } else {
75 error = errors::kManifestUnreadable;
76 }
77
78 // Once installed, non-unpacked extensions cannot change their IDs (e.g., by
79 // updating the 'key' field in their manifest).
80 if (extension &&
81 extension->location() != Extension::LOAD &&
82 info.extension_id != extension->id()) {
83 error = errors::kCannotChangeExtensionID;
84 extension = NULL;
85 UserMetrics::RecordAction(UserMetricsAction("Extensions.IDChangedError"));
86 }
87
88 if (!extension) {
89 extension_service()->
90 ReportExtensionLoadError(info.extension_path, error, false);
Aaron Boodman 2011/10/28 22:21:58 TODO(aa): Remove ReportExtensionLoadError. It does
Yoyo Zhou 2011/10/31 21:58:15 Added this TODO. It's really a Profile dependency
91 return;
92 }
93
94 if (write_to_prefs)
95 extension_prefs_->UpdateManifest(extension);
96
97 extension_service()->AddExtension(extension);
Aaron Boodman 2011/10/28 22:21:58 We tend to just use the members directly inside th
98 }
99
100 void InstalledExtensionLoader::LoadAllExtensions() {
101 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
102
103 base::TimeTicks start_time = base::TimeTicks::Now();
104
105 // Load the previously installed extensions.
Aaron Boodman 2011/10/28 22:21:58 Seems like this comment can go now, since that is
106 scoped_ptr<ExtensionPrefs::ExtensionsInfo> extensions_info(
107 extension_prefs_->GetInstalledExtensionsInfo());
108
109 std::vector<int> reload_reason_counts(NUM_MANIFEST_RELOAD_REASONS, 0);
110 bool should_write_prefs = false;
111
112 for (size_t i = 0; i < extensions_info->size(); ++i) {
113 ExtensionInfo* info = extensions_info->at(i).get();
114
115 ManifestReloadReason reload_reason = ShouldReloadExtensionManifest(*info);
116 ++reload_reason_counts[reload_reason];
117 UMA_HISTOGRAM_ENUMERATION("Extensions.ManifestReloadEnumValue",
118 reload_reason, 100);
119
120 if (reload_reason != NOT_NEEDED) {
121 // Reloading an extension reads files from disk. We do this on the
122 // UI thread because reloads should be very rare, and the complexity
123 // added by delaying the time when the extensions service knows about
124 // all extensions is significant. See crbug.com/37548 for details.
125 // |allow_io| disables tests that file operations run on the file
126 // thread.
127 base::ThreadRestrictions::ScopedAllowIO allow_io;
128
129 std::string error;
130 scoped_refptr<const Extension> extension(
131 extension_file_util::LoadExtension(
132 info->extension_path,
133 info->extension_location,
134 GetExtensionCreateFlagsForInstalledExtension(info),
135 &error));
136
137 if (extension.get()) {
138 extensions_info->at(i)->extension_manifest.reset(
139 static_cast<DictionaryValue*>(
140 extension->manifest_value()->DeepCopy()));
141 should_write_prefs = true;
142 }
143 }
144 }
145
146 for (size_t i = 0; i < extensions_info->size(); ++i) {
147 Load(*extensions_info->at(i), should_write_prefs);
Aaron Boodman 2011/10/28 22:21:58 1. Doesn't this write prefs for all extensions, ev
Yoyo Zhou 2011/10/31 21:58:15 Yes, this looks silly. I think I'd like to change
148 }
149
150 extension_service()->OnLoadedInstalledExtensions();
151
152 // The histograms Extensions.ManifestReload* allow us to validate
153 // the assumption that reloading manifest is a rare event.
154 UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNotNeeded",
155 reload_reason_counts[NOT_NEEDED]);
156 UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadUnpackedDir",
157 reload_reason_counts[UNPACKED_DIR]);
158 UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNeedsRelocalization",
159 reload_reason_counts[NEEDS_RELOCALIZATION]);
160
161 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAll",
162 extension_service()->extensions()->size());
163 UMA_HISTOGRAM_COUNTS_100("Extensions.Disabled",
164 extension_service()->disabled_extensions()->size());
165
166 UMA_HISTOGRAM_TIMES("Extensions.LoadAllTime",
167 base::TimeTicks::Now() - start_time);
168
169 int app_user_count = 0;
170 int app_external_count = 0;
171 int hosted_app_count = 0;
172 int packaged_app_count = 0;
173 int user_script_count = 0;
174 int extension_user_count = 0;
175 int extension_external_count = 0;
176 int theme_count = 0;
177 int page_action_count = 0;
178 int browser_action_count = 0;
179 const ExtensionList* extensions = extension_service()->extensions();
180 ExtensionList::const_iterator ex;
181 for (ex = extensions->begin(); ex != extensions->end(); ++ex) {
182 Extension::Location location = (*ex)->location();
183 Extension::Type type = (*ex)->GetType();
184 if ((*ex)->is_app()) {
185 UMA_HISTOGRAM_ENUMERATION("Extensions.AppLocation",
186 location, 100);
187 } else if (type == Extension::TYPE_EXTENSION) {
188 UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionLocation",
189 location, 100);
190 }
191
192 // Don't count component extensions, since they are only extensions as an
193 // implementation detail.
194 if (location == Extension::COMPONENT)
Aaron Boodman 2011/10/28 22:21:58 It seems like this part of the histograms code is
Yoyo Zhou 2011/10/31 21:58:15 Hmm, it doesn't count component extensions or LOAD
Aaron Boodman 2011/10/31 22:33:25 Ok, if you want to be correct.
195 continue;
196
197 // Don't count unpacked extensions, since they're a developer-specific
198 // feature.
199 if (location == Extension::LOAD)
200 continue;
201
202 // Using an enumeration shows us the total installed ratio across all users.
203 // Using the totals per user at each startup tells us the distribution of
204 // usage for each user (e.g. 40% of users have at least one app installed).
205 UMA_HISTOGRAM_ENUMERATION("Extensions.LoadType", type, 100);
206 switch (type) {
207 case Extension::TYPE_THEME:
208 ++theme_count;
209 break;
210 case Extension::TYPE_USER_SCRIPT:
211 ++user_script_count;
212 break;
213 case Extension::TYPE_HOSTED_APP:
214 ++hosted_app_count;
215 if (Extension::IsExternalLocation(location)) {
216 ++app_external_count;
217 } else {
218 ++app_user_count;
219 }
220 break;
221 case Extension::TYPE_PACKAGED_APP:
222 ++packaged_app_count;
223 if (Extension::IsExternalLocation(location)) {
224 ++app_external_count;
225 } else {
226 ++app_user_count;
227 }
228 break;
229 case Extension::TYPE_EXTENSION:
230 default:
231 if (Extension::IsExternalLocation(location)) {
232 ++extension_external_count;
233 } else {
234 ++extension_user_count;
235 }
236 break;
237 }
238 if ((*ex)->page_action() != NULL)
239 ++page_action_count;
240 if ((*ex)->browser_action() != NULL)
241 ++browser_action_count;
242
243 extension_service()->RecordPermissionMessagesHistogram(
244 ex->get(), "Extensions.Permissions_Load");
245 }
246 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadApp",
247 app_user_count + app_external_count);
248 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAppUser", app_user_count);
249 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAppExternal", app_external_count);
250 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadHostedApp", hosted_app_count);
251 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPackagedApp", packaged_app_count);
252 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtension",
253 extension_user_count + extension_external_count);
254 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtensionUser",
255 extension_user_count);
256 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtensionExternal",
257 extension_external_count);
258 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadUserScript", user_script_count);
259 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadTheme", theme_count);
260 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPageAction", page_action_count);
261 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadBrowserAction",
262 browser_action_count);
263 }
264
265 int InstalledExtensionLoader::GetExtensionCreateFlagsForInstalledExtension(
Aaron Boodman 2011/10/28 22:21:58 How about just: GetCreationFlags? The rest of the
Yoyo Zhou 2011/10/31 21:58:15 Yes.
266 const ExtensionInfo* info) {
267 int flags = Extension::NO_FLAGS;
268 if (info->extension_location != Extension::LOAD)
269 flags |= Extension::REQUIRE_KEY;
270 if (Extension::ShouldDoStrictErrorChecking(info->extension_location))
271 flags |= Extension::STRICT_ERROR_CHECKS;
272 if (extension_prefs_->AllowFileAccess(info->extension_id))
273 flags |= Extension::ALLOW_FILE_ACCESS;
274 if (extension_prefs_->IsFromWebStore(info->extension_id))
275 flags |= Extension::FROM_WEBSTORE;
276 if (extension_prefs_->IsFromBookmark(info->extension_id))
277 flags |= Extension::FROM_BOOKMARK;
278 return flags;
279 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698