| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/profiles/profile_statistics.h" | 5 #include "chrome/browser/profiles/profile_statistics.h" |
| 6 | 6 |
| 7 #include <set> | |
| 8 | |
| 9 #include "base/bind.h" | 7 #include "base/bind.h" |
| 10 #include "base/macros.h" | 8 #include "base/macros.h" |
| 11 #include "base/memory/ref_counted.h" | |
| 12 #include "base/task_runner.h" | |
| 13 #include "base/time/time.h" | |
| 14 #include "chrome/browser/bookmarks/bookmark_model_factory.h" | |
| 15 #include "chrome/browser/browser_process.h" | 9 #include "chrome/browser/browser_process.h" |
| 16 #include "chrome/browser/history/history_service_factory.h" | 10 #include "chrome/browser/profiles/profile.h" |
| 17 #include "chrome/browser/password_manager/password_store_factory.h" | |
| 18 #include "chrome/browser/profiles/profile_attributes_entry.h" | 11 #include "chrome/browser/profiles/profile_attributes_entry.h" |
| 19 #include "chrome/browser/profiles/profile_attributes_storage.h" | 12 #include "chrome/browser/profiles/profile_attributes_storage.h" |
| 20 #include "chrome/browser/profiles/profile_manager.h" | 13 #include "chrome/browser/profiles/profile_manager.h" |
| 21 #include "components/bookmarks/browser/bookmark_model.h" | 14 #include "chrome/browser/profiles/profile_statistics_aggregator.h" |
| 22 #include "components/bookmarks/browser/bookmark_model_observer.h" | |
| 23 #include "components/history/core/browser/history_service.h" | |
| 24 #include "components/password_manager/core/browser/password_store.h" | |
| 25 #include "components/password_manager/core/browser/password_store_consumer.h" | |
| 26 #include "components/prefs/pref_service.h" | |
| 27 #include "content/public/browser/browser_thread.h" | |
| 28 | 15 |
| 29 namespace { | 16 ProfileStatistics::ProfileStatistics(Profile* profile) |
| 30 | 17 : profile_(profile), aggregator_(nullptr), weak_ptr_factory_(this) { |
| 31 struct ProfileStatValue { | |
| 32 int count; | |
| 33 bool success; // false means the statistics failed to load | |
| 34 }; | |
| 35 | |
| 36 int CountBookmarksFromNode(const bookmarks::BookmarkNode* node) { | |
| 37 int count = 0; | |
| 38 if (node->is_url()) { | |
| 39 ++count; | |
| 40 } else { | |
| 41 for (int i = 0; i < node->child_count(); ++i) | |
| 42 count += CountBookmarksFromNode(node->GetChild(i)); | |
| 43 } | |
| 44 return count; | |
| 45 } | 18 } |
| 46 | 19 |
| 47 class ProfileStatisticsAggregator | 20 ProfileStatistics::~ProfileStatistics() { |
| 48 : public base::RefCountedThreadSafe<ProfileStatisticsAggregator> { | |
| 49 // This class is used internally by GetProfileStatistics and | |
| 50 // StoreProfileStatisticsToCache. | |
| 51 // | |
| 52 // The class collects statistical information about the profile and returns | |
| 53 // the information via a callback function. Currently bookmarks, history, | |
| 54 // logins and preferences are counted. | |
| 55 // | |
| 56 // The class is RefCounted because this is needed for CancelableTaskTracker | |
| 57 // to function properly. Once all tasks are run (or cancelled) the instance is | |
| 58 // automatically destructed. | |
| 59 | |
| 60 public: | |
| 61 ProfileStatisticsAggregator(Profile* profile, | |
| 62 const profiles::ProfileStatisticsCallback& callback, | |
| 63 base::CancelableTaskTracker* tracker); | |
| 64 | |
| 65 private: | |
| 66 friend class base::RefCountedThreadSafe<ProfileStatisticsAggregator>; | |
| 67 ~ProfileStatisticsAggregator() {} | |
| 68 | |
| 69 void Init(); | |
| 70 | |
| 71 // Callback functions | |
| 72 // Normal callback. Appends result to |profile_category_stats_|, and then call | |
| 73 // the external callback. All other callbacks call this function. | |
| 74 void StatisticsCallback(const char* category, ProfileStatValue result); | |
| 75 // Callback for reporting success. | |
| 76 void StatisticsCallbackSuccess(const char* category, int count); | |
| 77 // Callback for reporting failure. | |
| 78 void StatisticsCallbackFailure(const char* category); | |
| 79 // Callback for history. | |
| 80 void StatisticsCallbackHistory(history::HistoryCountResult result); | |
| 81 | |
| 82 // Bookmark counting. | |
| 83 void WaitOrCountBookmarks(); | |
| 84 void CountBookmarks(bookmarks::BookmarkModel* bookmark_model); | |
| 85 | |
| 86 class BookmarkModelHelper | |
| 87 : public bookmarks::BookmarkModelObserver { | |
| 88 public: | |
| 89 explicit BookmarkModelHelper(ProfileStatisticsAggregator* parent) | |
| 90 : parent_(parent) {} | |
| 91 | |
| 92 void BookmarkModelLoaded(bookmarks::BookmarkModel* model, | |
| 93 bool ids_reassigned) | |
| 94 override { | |
| 95 // Remove observer before release, otherwise it may become a dangling | |
| 96 // reference. | |
| 97 model->RemoveObserver(this); | |
| 98 parent_->CountBookmarks(model); | |
| 99 parent_->Release(); | |
| 100 } | |
| 101 | |
| 102 void BookmarkNodeMoved(bookmarks::BookmarkModel* model, | |
| 103 const bookmarks::BookmarkNode* old_parent, | |
| 104 int old_index, | |
| 105 const bookmarks::BookmarkNode* new_parent, | |
| 106 int new_index) override {} | |
| 107 | |
| 108 void BookmarkNodeAdded(bookmarks::BookmarkModel* model, | |
| 109 const bookmarks::BookmarkNode* parent, | |
| 110 int index) override {} | |
| 111 | |
| 112 void BookmarkNodeRemoved(bookmarks::BookmarkModel* model, | |
| 113 const bookmarks::BookmarkNode* parent, | |
| 114 int old_index, const bookmarks::BookmarkNode* node, | |
| 115 const std::set<GURL>& no_longer_bookmarked) override {} | |
| 116 | |
| 117 void BookmarkNodeChanged(bookmarks::BookmarkModel* model, | |
| 118 const bookmarks::BookmarkNode* node) override {} | |
| 119 | |
| 120 void BookmarkNodeFaviconChanged(bookmarks::BookmarkModel* model, | |
| 121 const bookmarks::BookmarkNode* node) override {} | |
| 122 | |
| 123 void BookmarkNodeChildrenReordered(bookmarks::BookmarkModel* model, | |
| 124 const bookmarks::BookmarkNode* node) override {} | |
| 125 | |
| 126 void BookmarkAllUserNodesRemoved(bookmarks::BookmarkModel* model, | |
| 127 const std::set<GURL>& removed_urls) override {} | |
| 128 | |
| 129 private: | |
| 130 ProfileStatisticsAggregator* parent_ = nullptr; | |
| 131 }; | |
| 132 | |
| 133 // Password counting | |
| 134 class PasswordStoreConsumerHelper | |
| 135 : public password_manager::PasswordStoreConsumer { | |
| 136 public: | |
| 137 explicit PasswordStoreConsumerHelper(ProfileStatisticsAggregator* parent) | |
| 138 : parent_(parent) {} | |
| 139 | |
| 140 void OnGetPasswordStoreResults( | |
| 141 ScopedVector<autofill::PasswordForm> results) override { | |
| 142 parent_->StatisticsCallbackSuccess(profiles::kProfileStatisticsPasswords, | |
| 143 results.size()); | |
| 144 } | |
| 145 | |
| 146 private: | |
| 147 ProfileStatisticsAggregator* parent_ = nullptr; | |
| 148 | |
| 149 DISALLOW_COPY_AND_ASSIGN(PasswordStoreConsumerHelper); | |
| 150 }; | |
| 151 | |
| 152 // Preference counting. | |
| 153 ProfileStatValue CountPrefs() const; | |
| 154 | |
| 155 Profile* profile_; | |
| 156 profiles::ProfileCategoryStats profile_category_stats_; | |
| 157 | |
| 158 // Callback function to be called when results arrive. Will be called | |
| 159 // multiple times (once for each statistics). | |
| 160 const profiles::ProfileStatisticsCallback callback_; | |
| 161 | |
| 162 base::CancelableTaskTracker* tracker_; | |
| 163 scoped_ptr<base::CancelableTaskTracker> default_tracker_; | |
| 164 | |
| 165 // Bookmark counting | |
| 166 scoped_ptr<BookmarkModelHelper> bookmark_model_helper_; | |
| 167 | |
| 168 // Password counting. | |
| 169 PasswordStoreConsumerHelper password_store_consumer_helper_; | |
| 170 | |
| 171 DISALLOW_COPY_AND_ASSIGN(ProfileStatisticsAggregator); | |
| 172 }; | |
| 173 | |
| 174 ProfileStatisticsAggregator::ProfileStatisticsAggregator( | |
| 175 Profile* profile, | |
| 176 const profiles::ProfileStatisticsCallback& callback, | |
| 177 base::CancelableTaskTracker* tracker) | |
| 178 : profile_(profile), | |
| 179 callback_(callback), | |
| 180 tracker_(tracker), | |
| 181 password_store_consumer_helper_(this) { | |
| 182 if (!tracker_) { | |
| 183 default_tracker_.reset(new base::CancelableTaskTracker); | |
| 184 tracker_ = default_tracker_.get(); | |
| 185 } | |
| 186 Init(); | |
| 187 } | 21 } |
| 188 | 22 |
| 189 void ProfileStatisticsAggregator::Init() { | 23 void ProfileStatistics::GatherStatistics( |
| 190 DCHECK(profile_); | 24 const profiles::ProfileStatisticsCallback& callback) { |
| 25 // IsValidProfile() can be false in unit tests. |
| 26 if (!g_browser_process->profile_manager()->IsValidProfile(profile_)) |
| 27 return; |
| 28 DCHECK(!profile_->IsOffTheRecord() && !profile_->IsSystemProfile()); |
| 191 | 29 |
| 192 // Initiate bookmark counting (async). Post to UI thread. | 30 if (HasAggregator()) { |
| 193 tracker_->PostTask( | 31 GetAggregator()->AddCallbackAndStartAggregator(callback); |
| 194 content::BrowserThread::GetMessageLoopProxyForThread( | |
| 195 content::BrowserThread::UI).get(), | |
| 196 FROM_HERE, | |
| 197 base::Bind(&ProfileStatisticsAggregator::WaitOrCountBookmarks, this)); | |
| 198 | |
| 199 // Initiate history counting (async). | |
| 200 history::HistoryService* history_service = | |
| 201 HistoryServiceFactory::GetForProfileWithoutCreating(profile_); | |
| 202 | |
| 203 if (history_service) { | |
| 204 history_service->GetHistoryCount( | |
| 205 base::Time(), | |
| 206 base::Time::Max(), | |
| 207 base::Bind(&ProfileStatisticsAggregator::StatisticsCallbackHistory, | |
| 208 this), | |
| 209 tracker_); | |
| 210 } else { | 32 } else { |
| 211 StatisticsCallbackFailure(profiles::kProfileStatisticsBrowsingHistory); | 33 // The statistics task may outlive ProfileStatistics in unit tests, so a |
| 212 } | 34 // weak pointer is used for the callback. |
| 213 | 35 scoped_refptr<ProfileStatisticsAggregator> aggregator = |
| 214 // Initiate stored password counting (async). | 36 new ProfileStatisticsAggregator( |
| 215 // TODO(anthonyvd): make password task cancellable. | 37 profile_, |
| 216 scoped_refptr<password_manager::PasswordStore> password_store = | 38 callback, |
| 217 PasswordStoreFactory::GetForProfile( | 39 base::Bind(&ProfileStatistics::DeregisterAggregator, |
| 218 profile_, ServiceAccessType::EXPLICIT_ACCESS); | 40 weak_ptr_factory_.GetWeakPtr())); |
| 219 if (password_store) { | 41 RegisterAggregator(aggregator.get()); |
| 220 password_store->GetAutofillableLogins(&password_store_consumer_helper_); | |
| 221 } else { | |
| 222 StatisticsCallbackFailure(profiles::kProfileStatisticsPasswords); | |
| 223 } | |
| 224 | |
| 225 // Initiate preference counting (async). Post to UI thread. | |
| 226 tracker_->PostTaskAndReplyWithResult( | |
| 227 content::BrowserThread::GetMessageLoopProxyForThread( | |
| 228 content::BrowserThread::UI).get(), | |
| 229 FROM_HERE, | |
| 230 base::Bind(&ProfileStatisticsAggregator::CountPrefs, this), | |
| 231 base::Bind(&ProfileStatisticsAggregator::StatisticsCallback, | |
| 232 this, profiles::kProfileStatisticsSettings)); | |
| 233 } | |
| 234 | |
| 235 void ProfileStatisticsAggregator::StatisticsCallback( | |
| 236 const char* category, ProfileStatValue result) { | |
| 237 profiles::ProfileCategoryStat datum; | |
| 238 datum.category = category; | |
| 239 datum.count = result.count; | |
| 240 datum.success = result.success; | |
| 241 profile_category_stats_.push_back(datum); | |
| 242 if (!callback_.is_null()) | |
| 243 callback_.Run(profile_category_stats_); | |
| 244 | |
| 245 if (result.success) { | |
| 246 profiles::SetProfileStatisticsInCache(profile_->GetPath(), datum.category, | |
| 247 result.count); | |
| 248 } | 42 } |
| 249 } | 43 } |
| 250 | 44 |
| 251 void ProfileStatisticsAggregator::StatisticsCallbackSuccess( | 45 bool ProfileStatistics::HasAggregator() const { |
| 252 const char* category, int count) { | 46 return aggregator_ != nullptr; |
| 253 ProfileStatValue result; | |
| 254 result.count = count; | |
| 255 result.success = true; | |
| 256 StatisticsCallback(category, result); | |
| 257 } | 47 } |
| 258 | 48 |
| 259 void ProfileStatisticsAggregator::StatisticsCallbackFailure( | 49 ProfileStatisticsAggregator* ProfileStatistics::GetAggregator() const { |
| 260 const char* category) { | 50 return aggregator_; |
| 261 ProfileStatValue result; | |
| 262 result.count = 0; | |
| 263 result.success = false; | |
| 264 StatisticsCallback(category, result); | |
| 265 } | 51 } |
| 266 | 52 |
| 267 void ProfileStatisticsAggregator::StatisticsCallbackHistory( | 53 void ProfileStatistics::RegisterAggregator( |
| 268 history::HistoryCountResult result) { | 54 ProfileStatisticsAggregator* aggregator) { |
| 269 ProfileStatValue result_converted; | 55 aggregator_ = aggregator; |
| 270 result_converted.count = result.count; | |
| 271 result_converted.success = result.success; | |
| 272 StatisticsCallback(profiles::kProfileStatisticsBrowsingHistory, | |
| 273 result_converted); | |
| 274 } | 56 } |
| 275 | 57 |
| 276 void ProfileStatisticsAggregator::CountBookmarks( | 58 void ProfileStatistics::DeregisterAggregator() { |
| 277 bookmarks::BookmarkModel* bookmark_model) { | 59 aggregator_ = nullptr; |
| 278 int count = CountBookmarksFromNode(bookmark_model->bookmark_bar_node()) + | |
| 279 CountBookmarksFromNode(bookmark_model->other_node()) + | |
| 280 CountBookmarksFromNode(bookmark_model->mobile_node()); | |
| 281 | |
| 282 StatisticsCallbackSuccess(profiles::kProfileStatisticsBookmarks, count); | |
| 283 } | 60 } |
| 284 | 61 |
| 285 void ProfileStatisticsAggregator::WaitOrCountBookmarks() { | 62 // static |
| 286 bookmarks::BookmarkModel* bookmark_model = | 63 profiles::ProfileCategoryStats |
| 287 BookmarkModelFactory::GetForProfileIfExists(profile_); | 64 ProfileStatistics::GetProfileStatisticsFromAttributesStorage( |
| 288 | 65 const base::FilePath& profile_path) { |
| 289 if (bookmark_model) { | |
| 290 if (bookmark_model->loaded()) { | |
| 291 CountBookmarks(bookmark_model); | |
| 292 } else { | |
| 293 AddRef(); | |
| 294 bookmark_model_helper_.reset(new BookmarkModelHelper(this)); | |
| 295 bookmark_model->AddObserver(bookmark_model_helper_.get()); | |
| 296 } | |
| 297 } else { | |
| 298 StatisticsCallbackFailure(profiles::kProfileStatisticsBookmarks); | |
| 299 } | |
| 300 } | |
| 301 | |
| 302 ProfileStatValue ProfileStatisticsAggregator::CountPrefs() const { | |
| 303 const PrefService* pref_service = profile_->GetPrefs(); | |
| 304 | |
| 305 ProfileStatValue result; | |
| 306 if (pref_service) { | |
| 307 scoped_ptr<base::DictionaryValue> prefs = | |
| 308 pref_service->GetPreferenceValuesWithoutPathExpansion(); | |
| 309 | |
| 310 int count = 0; | |
| 311 for (base::DictionaryValue::Iterator it(*(prefs.get())); | |
| 312 !it.IsAtEnd(); it.Advance()) { | |
| 313 const PrefService::Preference* pref = pref_service-> | |
| 314 FindPreference(it.key()); | |
| 315 // Skip all dictionaries (which must be empty by the function call above). | |
| 316 if (it.value().GetType() != base::Value::TYPE_DICTIONARY && | |
| 317 pref && pref->IsUserControlled() && !pref->IsDefaultValue()) { | |
| 318 ++count; | |
| 319 } | |
| 320 } | |
| 321 | |
| 322 result.count = count; | |
| 323 result.success = true; | |
| 324 } else { | |
| 325 result.count = 0; | |
| 326 result.success = false; | |
| 327 } | |
| 328 return result; | |
| 329 } | |
| 330 | |
| 331 } // namespace | |
| 332 | |
| 333 namespace profiles { | |
| 334 | |
| 335 // Constants for the categories in ProfileCategoryStats | |
| 336 const char kProfileStatisticsBrowsingHistory[] = "BrowsingHistory"; | |
| 337 const char kProfileStatisticsPasswords[] = "Passwords"; | |
| 338 const char kProfileStatisticsBookmarks[] = "Bookmarks"; | |
| 339 const char kProfileStatisticsSettings[] = "Settings"; | |
| 340 | |
| 341 void GatherProfileStatistics(Profile* profile, | |
| 342 const ProfileStatisticsCallback& callback, | |
| 343 base::CancelableTaskTracker* tracker) { | |
| 344 DCHECK(profile); | |
| 345 if (profile->IsOffTheRecord() || profile->IsSystemProfile()) { | |
| 346 NOTREACHED(); | |
| 347 return; | |
| 348 } | |
| 349 | |
| 350 scoped_refptr<ProfileStatisticsAggregator> aggregator = | |
| 351 new ProfileStatisticsAggregator(profile, callback, tracker); | |
| 352 } | |
| 353 | |
| 354 ProfileCategoryStats GetProfileStatisticsFromCache( | |
| 355 const base::FilePath& profile_path) { | |
| 356 ProfileAttributesEntry* entry = nullptr; | 66 ProfileAttributesEntry* entry = nullptr; |
| 357 bool has_entry = g_browser_process->profile_manager()-> | 67 bool has_entry = g_browser_process->profile_manager()-> |
| 358 GetProfileAttributesStorage(). | 68 GetProfileAttributesStorage(). |
| 359 GetProfileAttributesWithPath(profile_path, &entry); | 69 GetProfileAttributesWithPath(profile_path, &entry); |
| 360 | 70 |
| 361 ProfileCategoryStats stats; | 71 profiles::ProfileCategoryStats stats; |
| 362 ProfileCategoryStat stat; | 72 profiles::ProfileCategoryStat stat; |
| 363 | 73 |
| 364 stat.category = kProfileStatisticsBrowsingHistory; | 74 stat.category = profiles::kProfileStatisticsBrowsingHistory; |
| 365 stat.success = has_entry ? entry->HasStatsBrowsingHistory() : false; | 75 stat.success = has_entry ? entry->HasStatsBrowsingHistory() : false; |
| 366 stat.count = stat.success ? entry->GetStatsBrowsingHistory() : 0; | 76 stat.count = stat.success ? entry->GetStatsBrowsingHistory() : 0; |
| 367 stats.push_back(stat); | 77 stats.push_back(stat); |
| 368 | 78 |
| 369 stat.category = kProfileStatisticsPasswords; | 79 stat.category = profiles::kProfileStatisticsPasswords; |
| 370 stat.success = has_entry ? entry->HasStatsPasswords() : false; | 80 stat.success = has_entry ? entry->HasStatsPasswords() : false; |
| 371 stat.count = stat.success ? entry->GetStatsPasswords() : 0; | 81 stat.count = stat.success ? entry->GetStatsPasswords() : 0; |
| 372 stats.push_back(stat); | 82 stats.push_back(stat); |
| 373 | 83 |
| 374 stat.category = kProfileStatisticsBookmarks; | 84 stat.category = profiles::kProfileStatisticsBookmarks; |
| 375 stat.success = has_entry ? entry->HasStatsBookmarks() : false; | 85 stat.success = has_entry ? entry->HasStatsBookmarks() : false; |
| 376 stat.count = stat.success ? entry->GetStatsBookmarks() : 0; | 86 stat.count = stat.success ? entry->GetStatsBookmarks() : 0; |
| 377 stats.push_back(stat); | 87 stats.push_back(stat); |
| 378 | 88 |
| 379 stat.category = kProfileStatisticsSettings; | 89 stat.category = profiles::kProfileStatisticsSettings; |
| 380 stat.success = has_entry ? entry->HasStatsSettings() : false; | 90 stat.success = has_entry ? entry->HasStatsSettings() : false; |
| 381 stat.count = stat.success ? entry->GetStatsSettings() : 0; | 91 stat.count = stat.success ? entry->GetStatsSettings() : 0; |
| 382 stats.push_back(stat); | 92 stats.push_back(stat); |
| 383 | 93 |
| 384 return stats; | 94 return stats; |
| 385 } | 95 } |
| 386 | 96 |
| 387 void SetProfileStatisticsInCache(const base::FilePath& profile_path, | 97 // static |
| 388 const std::string& category, int count) { | 98 void ProfileStatistics::SetProfileStatisticsToAttributesStorage( |
| 389 // If local_state() is null, profile_manager() will seg-fault. | 99 const base::FilePath& profile_path, |
| 390 if (!g_browser_process || !g_browser_process->local_state()) | 100 const std::string& category, |
| 391 return; | 101 int count) { |
| 392 | 102 // |profile_manager()| may return a null pointer. |
| 393 // profile_manager() may return a null pointer. | |
| 394 ProfileManager* profile_manager = g_browser_process->profile_manager(); | 103 ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| 395 if (!profile_manager) | 104 if (!profile_manager) |
| 396 return; | 105 return; |
| 397 | 106 |
| 398 ProfileAttributesEntry* entry = nullptr; | 107 ProfileAttributesEntry* entry = nullptr; |
| 399 if (!profile_manager->GetProfileAttributesStorage(). | 108 if (!profile_manager->GetProfileAttributesStorage(). |
| 400 GetProfileAttributesWithPath(profile_path, &entry)) | 109 GetProfileAttributesWithPath(profile_path, &entry)) { |
| 110 // It is possible to have the profile attributes entry absent, e.g. the |
| 111 // profile is scheduled for deletion during the async statistics task. |
| 401 return; | 112 return; |
| 113 } |
| 402 | 114 |
| 403 if (category == kProfileStatisticsBrowsingHistory) { | 115 if (category == profiles::kProfileStatisticsBrowsingHistory) { |
| 404 entry->SetStatsBrowsingHistory(count); | 116 entry->SetStatsBrowsingHistory(count); |
| 405 } else if (category == kProfileStatisticsPasswords) { | 117 } else if (category == profiles::kProfileStatisticsPasswords) { |
| 406 entry->SetStatsPasswords(count); | 118 entry->SetStatsPasswords(count); |
| 407 } else if (category == kProfileStatisticsBookmarks) { | 119 } else if (category == profiles::kProfileStatisticsBookmarks) { |
| 408 entry->SetStatsBookmarks(count); | 120 entry->SetStatsBookmarks(count); |
| 409 } else if (category == kProfileStatisticsSettings) { | 121 } else if (category == profiles::kProfileStatisticsSettings) { |
| 410 entry->SetStatsSettings(count); | 122 entry->SetStatsSettings(count); |
| 411 } else { | 123 } else { |
| 412 NOTREACHED(); | 124 NOTREACHED(); |
| 413 } | 125 } |
| 414 } | 126 } |
| 415 | |
| 416 } // namespace profiles | |
| OLD | NEW |