1// Copyright 2013 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#ifndef EXTENSIONS_BROWSER_LAZY_BACKGROUND_TASK_QUEUE_H_
6#define EXTENSIONS_BROWSER_LAZY_BACKGROUND_TASK_QUEUE_H_
7
8#include <map>
9#include <string>
10
11#include "base/callback_forward.h"
12#include "base/compiler_specific.h"
13#include "base/gtest_prod_util.h"
14#include "base/memory/linked_ptr.h"
15#include "base/scoped_observer.h"
16#include "content/public/browser/notification_observer.h"
17#include "content/public/browser/notification_registrar.h"
18#include "extensions/browser/extension_registry_observer.h"
19
20namespace content {
21class BrowserContext;
22}
23
24namespace extensions {
25class Extension;
26class ExtensionHost;
27class ExtensionRegistry;
28
29// This class maintains a queue of tasks that should execute when an
30// extension's lazy background page is loaded. It is also in charge of loading
31// the page when the first task is queued.
32//
33// It is the consumer's responsibility to use this class when appropriate, i.e.
34// only with extensions that have not-yet-loaded lazy background pages.
35class LazyBackgroundTaskQueue : public content::NotificationObserver,
36                                public ExtensionRegistryObserver {
37 public:
38  typedef base::Callback<void(ExtensionHost*)> PendingTask;
39
40  explicit LazyBackgroundTaskQueue(content::BrowserContext* browser_context);
41  virtual ~LazyBackgroundTaskQueue();
42
43  // Returns the number of extensions having pending tasks.
44  size_t extensions_with_pending_tasks() { return pending_tasks_.size(); }
45
46  // Returns true if the task should be added to the queue (that is, if the
47  // extension has a lazy background page that isn't ready yet). If the
48  // extension has a lazy background page that is being suspended this method
49  // cancels that suspension.
50  bool ShouldEnqueueTask(content::BrowserContext* context,
51                         const Extension* extension);
52
53  // Adds a task to the queue for a given extension. If this is the first
54  // task added for the extension, its lazy background page will be loaded.
55  // The task will be called either when the page is loaded, or when the
56  // page fails to load for some reason (e.g. a crash or browser
57  // shutdown). In the latter case, the ExtensionHost parameter is NULL.
58  void AddPendingTask(
59      content::BrowserContext* context,
60      const std::string& extension_id,
61      const PendingTask& task);
62
63 private:
64  FRIEND_TEST_ALL_PREFIXES(LazyBackgroundTaskQueueTest, ProcessPendingTasks);
65
66  // A map between a BrowserContext/extension_id pair and the queue of tasks
67  // pending the load of its background page.
68  typedef std::string ExtensionID;
69  typedef std::pair<content::BrowserContext*, ExtensionID> PendingTasksKey;
70  typedef std::vector<PendingTask> PendingTasksList;
71  typedef std::map<PendingTasksKey,
72                   linked_ptr<PendingTasksList> > PendingTasksMap;
73
74  // content::NotificationObserver interface.
75  virtual void Observe(int type,
76                       const content::NotificationSource& source,
77                       const content::NotificationDetails& details) OVERRIDE;
78
79  // ExtensionRegistryObserver interface.
80  virtual void OnExtensionUnloaded(
81      content::BrowserContext* browser_context,
82      const Extension* extension,
83      UnloadedExtensionInfo::Reason reason) OVERRIDE;
84
85  // Called when a lazy background page has finished loading, or has failed to
86  // load (host is NULL in that case). All enqueued tasks are run in order.
87  void ProcessPendingTasks(
88      ExtensionHost* host,
89      content::BrowserContext* context,
90      const Extension* extension);
91
92  content::BrowserContext* browser_context_;
93  content::NotificationRegistrar registrar_;
94  PendingTasksMap pending_tasks_;
95
96  ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
97      extension_registry_observer_;
98};
99
100}  // namespace extensions
101
102#endif  // EXTENSIONS_BROWSER_LAZY_BACKGROUND_TASK_QUEUE_H_
103