Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/metrics/extensions_metrics_provider.h" | 5 #include "chrome/browser/metrics/extensions_metrics_provider.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
| 11 #include "base/strings/stringprintf.h" | 11 #include "base/strings/stringprintf.h" |
| 12 #include "chrome/browser/browser_process.h" | 12 #include "chrome/browser/browser_process.h" |
| 13 #include "chrome/browser/extensions/install_verifier.h" | |
| 13 #include "chrome/browser/profiles/profile_manager.h" | 14 #include "chrome/browser/profiles/profile_manager.h" |
| 14 #include "components/metrics/metrics_log.h" | 15 #include "components/metrics/metrics_log.h" |
| 15 #include "components/metrics/metrics_state_manager.h" | 16 #include "components/metrics/metrics_state_manager.h" |
| 16 #include "components/metrics/proto/system_profile.pb.h" | 17 #include "components/metrics/proto/system_profile.pb.h" |
| 17 #include "extensions/browser/extension_registry.h" | 18 #include "extensions/browser/extension_registry.h" |
| 19 #include "extensions/browser/extension_system.h" | |
| 18 #include "extensions/common/extension_set.h" | 20 #include "extensions/common/extension_set.h" |
| 19 #include "third_party/smhasher/src/City.h" | 21 #include "third_party/smhasher/src/City.h" |
| 20 | 22 |
| 21 namespace { | 23 namespace { |
| 22 | 24 |
| 23 // The number of possible hash keys that a client may use. The UMA client_id | 25 // The number of possible hash keys that a client may use. The UMA client_id |
| 24 // value is reduced modulo this value to produce the key used by that | 26 // value is reduced modulo this value to produce the key used by that |
| 25 // particular client. | 27 // particular client. |
| 26 const size_t kExtensionListClientKeys = 4096; | 28 const size_t kExtensionListClientKeys = 4096; |
| 27 | 29 |
| 28 // The number of hash buckets into which extension IDs are mapped. This sets | 30 // The number of hash buckets into which extension IDs are mapped. This sets |
| 29 // the possible output range of the HashExtension function. | 31 // the possible output range of the HashExtension function. |
| 30 const size_t kExtensionListBuckets = 1024; | 32 const size_t kExtensionListBuckets = 1024; |
| 31 | 33 |
| 34 enum ExtensionState { | |
| 35 NO_EXTENSIONS, | |
| 36 FROM_STORE_VERIFIED, | |
| 37 FROM_STORE_UNVERIFIED, | |
| 38 OFF_STORE | |
|
Alexei Svitkine (slow)
2014/08/12 15:22:39
Can you use the proto's enum directly instead of t
jwd
2014/08/12 18:45:28
Done.
| |
| 39 }; | |
| 40 | |
| 41 metrics::SystemProfileProto::ExtensionsState ExtensionStateAsProto( | |
| 42 ExtensionState value) { | |
| 43 switch (value) { | |
| 44 case NO_EXTENSIONS: | |
| 45 return metrics::SystemProfileProto::NO_EXTENSIONS; | |
| 46 case FROM_STORE_VERIFIED: | |
| 47 return metrics::SystemProfileProto::NO_OFFSTORE_VERIFIED; | |
| 48 case FROM_STORE_UNVERIFIED: | |
| 49 return metrics::SystemProfileProto::NO_OFFSTORE_UNVERIFIED; | |
| 50 case OFF_STORE: | |
| 51 return metrics::SystemProfileProto::HAS_OFFSTORE; | |
| 52 } | |
| 53 NOTREACHED(); | |
| 54 return metrics::SystemProfileProto::NO_EXTENSIONS; | |
| 55 } | |
| 56 | |
| 57 // Determines if the |extension| is an extension (can use extension APIs) and is | |
| 58 // not from the webstore. If local information claims the extension is from the | |
| 59 // webstore, we attempt to verifie with the |InstallVerifier| by checking if it | |
|
Alexei Svitkine (slow)
2014/08/12 15:22:39
Nit: verify
jwd
2014/08/12 18:45:28
Done.
| |
| 60 // has been explicitly deemed invalid. If the |InstallVerifier| is inactive or | |
|
Alexei Svitkine (slow)
2014/08/12 15:22:39
Nit: No need for |'s around InstallVerifier since
jwd
2014/08/12 18:45:28
Done.
| |
| 61 // if the extension is unknown to the |InstallVerifier|, the local information | |
| 62 // is trusted. | |
| 63 ExtensionState IsOffStoreExtension( | |
| 64 const extensions::Extension& extension, | |
| 65 const extensions::InstallVerifier& verifier) { | |
| 66 if (!extension.is_extension() && !extension.is_legacy_packaged_app()) | |
| 67 return NO_EXTENSIONS; | |
| 68 | |
| 69 // Component extensions are considered safe. | |
| 70 if (extension.location() == extensions::Manifest::COMPONENT || | |
| 71 extension.location() == extensions::Manifest::EXTERNAL_COMPONENT) { | |
| 72 return NO_EXTENSIONS; | |
| 73 } | |
| 74 | |
| 75 if (verifier.AllowedByEnterprisePolicy(extension.id())) | |
| 76 return NO_EXTENSIONS; | |
| 77 | |
| 78 if (!extensions::InstallVerifier::FromStore(extension)) | |
| 79 return OFF_STORE; | |
| 80 | |
| 81 // Local information about the extension implies it is from the store. We try | |
| 82 // to use the install verifier to vereify this. | |
| 83 if (!verifier.IsKnownId(extension.id())) | |
| 84 return FROM_STORE_UNVERIFIED; | |
| 85 | |
| 86 if (verifier.IsInvalid(extension.id())) | |
| 87 return OFF_STORE; | |
| 88 else | |
|
Alexei Svitkine (slow)
2014/08/12 15:22:39
Nit: Remove else and unindent return below.
jwd
2014/08/12 18:45:28
Done.
| |
| 89 return FROM_STORE_VERIFIED; | |
| 90 } | |
| 91 | |
| 92 ExtensionState CheckForOffStore(const extensions::ExtensionSet& extensions, | |
| 93 const extensions::InstallVerifier& verifier) { | |
| 94 ExtensionState extensions_state = NO_EXTENSIONS; | |
| 95 for (extensions::ExtensionSet::const_iterator it = extensions.begin(); | |
| 96 it != extensions.end(); | |
| 97 ++it) { | |
|
Alexei Svitkine (slow)
2014/08/12 15:22:39
Nit: for (size_t i = 0; i < extensions.size(); ++i
jwd
2014/08/12 18:45:28
Done below, not done her as discussed.
| |
| 98 extensions_state = | |
| 99 std::max(extensions_state, IsOffStoreExtension(**it, verifier)); | |
| 100 } | |
| 101 return extensions_state; | |
| 102 } | |
| 103 | |
| 32 } // namespace | 104 } // namespace |
| 33 | 105 |
| 34 ExtensionsMetricsProvider::ExtensionsMetricsProvider( | 106 ExtensionsMetricsProvider::ExtensionsMetricsProvider( |
| 35 metrics::MetricsStateManager* metrics_state_manager) | 107 metrics::MetricsStateManager* metrics_state_manager) |
| 36 : metrics_state_manager_(metrics_state_manager), cached_profile_(NULL) { | 108 : metrics_state_manager_(metrics_state_manager), cached_profile_(NULL) { |
| 37 DCHECK(metrics_state_manager_); | 109 DCHECK(metrics_state_manager_); |
| 38 } | 110 } |
| 39 | 111 |
| 40 ExtensionsMetricsProvider::~ExtensionsMetricsProvider() { | 112 ExtensionsMetricsProvider::~ExtensionsMetricsProvider() { |
| 41 } | 113 } |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 67 cached_profile_ = profile_manager->GetProfileByPath( | 139 cached_profile_ = profile_manager->GetProfileByPath( |
| 68 profile_manager->GetLastUsedProfileDir(profile_manager->user_data_dir())); | 140 profile_manager->GetLastUsedProfileDir(profile_manager->user_data_dir())); |
| 69 if (cached_profile_) { | 141 if (cached_profile_) { |
| 70 // Ensure that the returned profile is not an incognito profile. | 142 // Ensure that the returned profile is not an incognito profile. |
| 71 cached_profile_ = cached_profile_->GetOriginalProfile(); | 143 cached_profile_ = cached_profile_->GetOriginalProfile(); |
| 72 } | 144 } |
| 73 return cached_profile_; | 145 return cached_profile_; |
| 74 } | 146 } |
| 75 | 147 |
| 76 scoped_ptr<extensions::ExtensionSet> | 148 scoped_ptr<extensions::ExtensionSet> |
| 77 ExtensionsMetricsProvider::GetInstalledExtensions() { | 149 ExtensionsMetricsProvider::GetInstalledExtensions(Profile* profile) { |
| 78 #if defined(ENABLE_EXTENSIONS) | 150 #if defined(ENABLE_EXTENSIONS) |
| 79 // UMA reports do not support multiple profiles, but extensions are installed | |
| 80 // per-profile. We return the extensions installed in the primary profile. | |
| 81 // In the future, we might consider reporting data about extensions in all | |
| 82 // profiles. | |
| 83 Profile* profile = GetMetricsProfile(); | |
| 84 if (profile) { | 151 if (profile) { |
| 85 return extensions::ExtensionRegistry::Get(profile) | 152 return extensions::ExtensionRegistry::Get(profile) |
| 86 ->GenerateInstalledExtensionsSet(); | 153 ->GenerateInstalledExtensionsSet(); |
| 87 } | 154 } |
| 88 #endif // defined(ENABLE_EXTENSIONS) | 155 #endif // defined(ENABLE_EXTENSIONS) |
| 89 return scoped_ptr<extensions::ExtensionSet>(); | 156 return scoped_ptr<extensions::ExtensionSet>(); |
| 90 } | 157 } |
| 91 | 158 |
| 92 uint64 ExtensionsMetricsProvider::GetClientID() { | 159 uint64 ExtensionsMetricsProvider::GetClientID() { |
| 93 // TODO(blundell): Create a MetricsLog::ClientIDAsInt() API and call it | 160 // TODO(blundell): Create a MetricsLog::ClientIDAsInt() API and call it |
| 94 // here as well as in MetricsLog's population of the client_id field of | 161 // here as well as in MetricsLog's population of the client_id field of |
| 95 // the uma_proto. | 162 // the uma_proto. |
| 96 return MetricsLog::Hash(metrics_state_manager_->client_id()); | 163 return MetricsLog::Hash(metrics_state_manager_->client_id()); |
| 97 } | 164 } |
| 98 | 165 |
| 99 void ExtensionsMetricsProvider::ProvideSystemProfileMetrics( | 166 void ExtensionsMetricsProvider::ProvideSystemProfileMetrics( |
| 100 metrics::SystemProfileProto* system_profile) { | 167 metrics::SystemProfileProto* system_profile) { |
| 101 scoped_ptr<extensions::ExtensionSet> extensions(GetInstalledExtensions()); | 168 ProvideOffStoreMetric(system_profile); |
| 169 ProvideOccupiedBucketMetric(system_profile); | |
| 170 } | |
| 171 | |
| 172 void ExtensionsMetricsProvider::ProvideOffStoreMetric( | |
| 173 metrics::SystemProfileProto* system_profile) { | |
| 174 ProfileManager* profile_manager = g_browser_process->profile_manager(); | |
| 175 if (!profile_manager) | |
| 176 return; | |
| 177 | |
| 178 ExtensionState extensions_state = NO_EXTENSIONS; | |
| 179 | |
| 180 std::vector<Profile*> profiles = profile_manager->GetLoadedProfiles(); | |
|
Alexei Svitkine (slow)
2014/08/12 15:22:40
Add a comment explaining how we treat multi-profil
jwd
2014/08/12 18:45:28
Done.
| |
| 181 for (std::vector<Profile*>::const_iterator it = profiles.begin(); | |
| 182 it != profiles.end(); | |
| 183 ++it) { | |
| 184 extensions::InstallVerifier* verifier = | |
| 185 extensions::ExtensionSystem::Get(*it)->install_verifier(); | |
| 186 | |
| 187 scoped_ptr<extensions::ExtensionSet> extensions( | |
| 188 GetInstalledExtensions(*it)); | |
| 189 | |
| 190 extensions_state = std::max(extensions_state, | |
|
Alexei Svitkine (slow)
2014/08/12 15:22:39
Nit: This deserves a comment.
Alexei Svitkine (slow)
2014/08/12 15:22:39
Nit: Add a comment about the max() logic.
jwd
2014/08/12 18:45:28
Done.
jwd
2014/08/12 18:45:28
Done.
| |
| 191 CheckForOffStore(*extensions.get(), *verifier)); | |
| 192 } | |
| 193 | |
| 194 system_profile->set_offstore_extensions_state( | |
| 195 ExtensionStateAsProto(extensions_state)); | |
| 196 } | |
| 197 | |
| 198 void ExtensionsMetricsProvider::ProvideOccupiedBucketMetric( | |
| 199 metrics::SystemProfileProto* system_profile) { | |
| 200 // UMA reports do not support multiple profiles, but extensions are installed | |
| 201 // per-profile. We return the extensions installed in the primary profile. | |
| 202 // In the future, we might consider reporting data about extensions in all | |
| 203 // profiles. | |
| 204 Profile* profile = GetMetricsProfile(); | |
| 205 | |
| 206 scoped_ptr<extensions::ExtensionSet> extensions( | |
| 207 GetInstalledExtensions(profile)); | |
| 102 if (!extensions) | 208 if (!extensions) |
| 103 return; | 209 return; |
| 104 | 210 |
| 105 const int client_key = GetClientID() % kExtensionListClientKeys; | 211 const int client_key = GetClientID() % kExtensionListClientKeys; |
| 106 | 212 |
| 107 std::set<int> buckets; | 213 std::set<int> buckets; |
| 108 for (extensions::ExtensionSet::const_iterator it = extensions->begin(); | 214 for (extensions::ExtensionSet::const_iterator it = extensions->begin(); |
| 109 it != extensions->end(); | 215 it != extensions->end(); |
| 110 ++it) { | 216 ++it) { |
| 111 buckets.insert(HashExtension((*it)->id(), client_key)); | 217 buckets.insert(HashExtension((*it)->id(), client_key)); |
| 112 } | 218 } |
| 113 | 219 |
| 114 for (std::set<int>::const_iterator it = buckets.begin(); it != buckets.end(); | 220 for (std::set<int>::const_iterator it = buckets.begin(); it != buckets.end(); |
| 115 ++it) { | 221 ++it) { |
| 116 system_profile->add_occupied_extension_bucket(*it); | 222 system_profile->add_occupied_extension_bucket(*it); |
| 117 } | 223 } |
| 118 } | 224 } |
| OLD | NEW |