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