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/sync/util/extensions_activity_monitor.h" 6 7 #include "base/task.h" 8 #include "chrome/browser/extensions/extension_bookmarks_module.h" 9 #include "chrome/common/extensions/extension.h" 10 #include "content/browser/browser_thread.h" 11 #include "content/common/notification_service.h" 12 13 namespace browser_sync { 14 15 namespace { 16 // A helper task to register an ExtensionsActivityMonitor as an observer of 17 // events on the UI thread (even though the monitor may live on another thread). 18 // This liberates ExtensionsActivityMonitor from having to be ref counted. 19 class RegistrationTask : public Task { 20 public: 21 RegistrationTask(ExtensionsActivityMonitor* monitor, 22 NotificationRegistrar* registrar) 23 : monitor_(monitor), registrar_(registrar) {} 24 virtual ~RegistrationTask() {} 25 26 virtual void Run() { 27 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 28 29 // It would be nice if we could specify a Source for each specific function 30 // we wanted to observe, but the actual function objects are allocated on 31 // the fly so there is no reliable object to point to (same problem if we 32 // wanted to use the string name). Thus, we use all sources and filter in 33 // Observe. 34 registrar_->Add(monitor_, NotificationType::EXTENSION_BOOKMARKS_API_INVOKED, 35 NotificationService::AllSources()); 36 } 37 38 private: 39 ExtensionsActivityMonitor* monitor_; 40 NotificationRegistrar* registrar_; 41 DISALLOW_COPY_AND_ASSIGN(RegistrationTask); 42 }; 43 } // namespace 44 45 ExtensionsActivityMonitor::ExtensionsActivityMonitor() { 46 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 47 new RegistrationTask(this, ®istrar_)); 48 } 49 50 ExtensionsActivityMonitor::~ExtensionsActivityMonitor() { 51 // In some unrelated unit tests, there is no running UI loop. In this case, 52 // the PostTask in our ctor will not result in anything running, so |this| 53 // won't be used for anything. In this case (or whenever no registration took 54 // place) and only this case we allow destruction on another loop, but this 55 // isn't something a client of this class can control; it happens implicitly 56 // by not having a running UI thread. 57 if (!registrar_.IsEmpty()) { 58 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 59 60 // The registrar calls RemoveAll in its dtor (which would happen in a 61 // moment but explicitly call this so it is clear why we need to be on the 62 // ui_loop_. 63 registrar_.RemoveAll(); 64 } 65 } 66 67 void ExtensionsActivityMonitor::GetAndClearRecords(Records* buffer) { 68 base::AutoLock lock(records_lock_); 69 buffer->clear(); 70 buffer->swap(records_); 71 } 72 73 void ExtensionsActivityMonitor::PutRecords(const Records& records) { 74 base::AutoLock lock(records_lock_); 75 for (Records::const_iterator i = records.begin(); i != records.end(); ++i) { 76 records_[i->first].extension_id = i->second.extension_id; 77 records_[i->first].bookmark_write_count += i->second.bookmark_write_count; 78 } 79 } 80 81 void ExtensionsActivityMonitor::Observe(NotificationType type, 82 const NotificationSource& source, 83 const NotificationDetails& details) { 84 base::AutoLock lock(records_lock_); 85 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 86 const Extension* extension = Source<const Extension>(source).ptr(); 87 const BookmarksFunction* f = Details<const BookmarksFunction>(details).ptr(); 88 if (f->name() == "bookmarks.update" || 89 f->name() == "bookmarks.move" || 90 f->name() == "bookmarks.create" || 91 f->name() == "bookmarks.removeTree" || 92 f->name() == "bookmarks.remove") { 93 Record& record = records_[extension->id()]; 94 record.extension_id = extension->id(); 95 record.bookmark_write_count++; 96 } 97 } 98 99 } // namespace browser_sync 100