• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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 CHROME_BROWSER_BACKGROUND_BACKGROUND_MODE_MANAGER_H_
6 #define CHROME_BROWSER_BACKGROUND_BACKGROUND_MODE_MANAGER_H_
7 
8 #include <map>
9 
10 #include "base/gtest_prod_util.h"
11 #include "base/memory/scoped_vector.h"
12 #include "base/prefs/pref_change_registrar.h"
13 #include "chrome/browser/background/background_application_list_model.h"
14 #include "chrome/browser/profiles/profile_info_cache_observer.h"
15 #include "chrome/browser/status_icons/status_icon.h"
16 #include "chrome/browser/status_icons/status_icon_menu_model.h"
17 #include "chrome/browser/ui/browser_list_observer.h"
18 #include "components/keyed_service/core/keyed_service.h"
19 #include "content/public/browser/notification_observer.h"
20 #include "content/public/browser/notification_registrar.h"
21 #include "extensions/common/extension.h"
22 
23 class Browser;
24 class PrefRegistrySimple;
25 class Profile;
26 class ProfileInfoCache;
27 class StatusIcon;
28 class StatusTray;
29 
30 namespace base {
31 class CommandLine;
32 }
33 
34 typedef std::vector<int> CommandIdExtensionVector;
35 
36 // BackgroundModeManager is responsible for switching Chrome into and out of
37 // "background mode" and for providing UI for the user to exit Chrome when there
38 // are no open browser windows.
39 //
40 // Chrome enters background mode whenever there is an application with the
41 // "background" permission installed. This class monitors the set of
42 // installed/loaded extensions to ensure that Chrome enters/exits background
43 // mode at the appropriate time.
44 //
45 // When Chrome is in background mode, it will continue running even after the
46 // last browser window is closed, until the user explicitly exits the app.
47 // Additionally, when in background mode, Chrome will launch on OS login with
48 // no open windows to allow apps with the "background" permission to run in the
49 // background.
50 class BackgroundModeManager
51     : public content::NotificationObserver,
52       public chrome::BrowserListObserver,
53       public BackgroundApplicationListModel::Observer,
54       public ProfileInfoCacheObserver,
55       public StatusIconMenuModel::Delegate {
56  public:
57   BackgroundModeManager(base::CommandLine* command_line,
58                         ProfileInfoCache* profile_cache);
59   virtual ~BackgroundModeManager();
60 
61   static void RegisterPrefs(PrefRegistrySimple* registry);
62 
63   virtual void RegisterProfile(Profile* profile);
64 
65   static void LaunchBackgroundApplication(Profile* profile,
66       const extensions::Extension* extension);
67 
68   // Returns true if background mode is active.
69   virtual bool IsBackgroundModeActive();
70 
71   // Suspends background mode until either ResumeBackgroundMode is called or
72   // Chrome is restarted. This has the same effect as ending background mode
73   // for the current browser session.
74   virtual void SuspendBackgroundMode();
75 
76   // Resumes background mode. This ends a suspension of background mode, but
77   // will not start it if it is not enabled.
78   virtual void ResumeBackgroundMode();
79 
80   // For testing purposes.
81   int NumberOfBackgroundModeData();
82 
83  private:
84   friend class AppBackgroundPageApiTest;
85   friend class BackgroundModeManagerTest;
86   friend class BackgroundModeManagerWithExtensionsTest;
87   friend class TestBackgroundModeManager;
88   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
89                            BackgroundAppLoadUnload);
90   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
91                            BackgroundLaunchOnStartup);
92   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
93                            BackgroundAppInstallUninstallWhileDisabled);
94   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
95                            BackgroundModeDisabledPreventsKeepAliveOnStartup);
96   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
97                            DisableBackgroundModeUnderTestFlag);
98   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
99                            EnableAfterBackgroundAppInstall);
100   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
101                            MultiProfile);
102   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
103                            ProfileInfoCacheStorage);
104   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
105                            ProfileInfoCacheObserver);
106   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
107                            DeleteBackgroundProfile);
108   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerWithExtensionsTest,
109                            BackgroundMenuGeneration);
110   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerWithExtensionsTest,
111                            BackgroundMenuGenerationMultipleProfile);
112   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerWithExtensionsTest,
113                            BalloonDisplay);
114   FRIEND_TEST_ALL_PREFIXES(BackgroundAppBrowserTest,
115                            ReloadBackgroundApp);
116 
117   class BackgroundModeData : public StatusIconMenuModel::Delegate {
118    public:
119     explicit BackgroundModeData(
120         Profile* profile,
121         CommandIdExtensionVector* command_id_extension_vector);
122     virtual ~BackgroundModeData();
123 
124     // The cached list of BackgroundApplications.
125     scoped_ptr<BackgroundApplicationListModel> applications_;
126 
127     // Overrides from StatusIconMenuModel::Delegate implementation.
128     virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
129 
130     // Returns a browser window, or creates one if none are open. Used by
131     // operations (like displaying the preferences dialog) that require a
132     // Browser window.
133     Browser* GetBrowserWindow();
134 
135     // Returns the number of background apps for this profile.
136     int GetBackgroundAppCount() const;
137 
138     // Builds the profile specific parts of the menu. The menu passed in may
139     // be a submenu in the case of multi-profiles or the main menu in the case
140     // of the single profile case. If containing_menu is valid, we will add
141     // menu as a submenu to it.
142     void BuildProfileMenu(StatusIconMenuModel* menu,
143                           StatusIconMenuModel* containing_menu);
144 
145     // Set the name associated with this background mode data for displaying in
146     // the status tray.
147     void SetName(const base::string16& new_profile_name);
148 
149     // The name associated with this background mode data. This should match
150     // the name in the ProfileInfoCache for this profile.
151     base::string16 name();
152 
153     // Used for sorting BackgroundModeData*s.
154     static bool BackgroundModeDataCompare(const BackgroundModeData* bmd1,
155                                           const BackgroundModeData* bmd2);
156 
157     // Returns the set of new background apps (apps that have been loaded since
158     // the last call to GetNewBackgroundApps()).
159     std::set<const extensions::Extension*> GetNewBackgroundApps();
160 
161    private:
162     // Name associated with this profile which is used to label its submenu.
163     base::string16 name_;
164 
165     // The profile associated with this background app data.
166     Profile* profile_;
167 
168     // Weak ref vector owned by BackgroundModeManager where the
169     // indices correspond to Command IDs and values correspond to
170     // extension indices. A value of -1 indicates no extension is associated
171     // with the index.
172     CommandIdExtensionVector* command_id_extension_vector_;
173 
174     // The list of notified extensions for this profile. We track this to ensure
175     // that we never notify the user about the same extension twice in a single
176     // browsing session - this is done because the extension subsystem is not
177     // good about tracking changes to the background permission around
178     // extension reloads, and will sometimes report spurious permission changes.
179     std::set<extensions::ExtensionId> current_extensions_;
180   };
181 
182   // Ideally we would want our BackgroundModeData to be scoped_ptrs,
183   // but since maps copy their entries, we can't used scoped_ptrs.
184   // Similarly, we can't just have a map of BackgroundModeData objects,
185   // since BackgroundModeData contains a scoped_ptr which once again
186   // can't be copied. So rather than using BackgroundModeData* which
187   // we'd have to remember to delete, we use the ref-counted linked_ptr
188   // which is similar to a shared_ptr.
189   typedef linked_ptr<BackgroundModeData> BackgroundModeInfo;
190 
191   typedef std::map<Profile*, BackgroundModeInfo> BackgroundModeInfoMap;
192 
193   // content::NotificationObserver implementation.
194   virtual void Observe(int type,
195                        const content::NotificationSource& source,
196                        const content::NotificationDetails& details) OVERRIDE;
197 
198   // Called when the kBackgroundModeEnabled preference changes.
199   void OnBackgroundModeEnabledPrefChanged();
200 
201   // BackgroundApplicationListModel::Observer implementation.
202   virtual void OnApplicationDataChanged(const extensions::Extension* extension,
203                                         Profile* profile) OVERRIDE;
204   virtual void OnApplicationListChanged(Profile* profile) OVERRIDE;
205 
206   // Overrides from ProfileInfoCacheObserver
207   virtual void OnProfileAdded(const base::FilePath& profile_path) OVERRIDE;
208   virtual void OnProfileWillBeRemoved(
209       const base::FilePath& profile_path) OVERRIDE;
210   virtual void OnProfileNameChanged(
211       const base::FilePath& profile_path,
212       const base::string16& old_profile_name) OVERRIDE;
213 
214   // Overrides from StatusIconMenuModel::Delegate implementation.
215   virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
216 
217   // chrome::BrowserListObserver implementation.
218   virtual void OnBrowserAdded(Browser* browser) OVERRIDE;
219 
220   // Invoked when an extension is installed so we can ensure that
221   // launch-on-startup is enabled if appropriate. |extension| can be NULL when
222   // called from unit tests.
223   void OnBackgroundAppInstalled(
224       const extensions::Extension* extension);
225 
226   // Walk the list of profiles and see if an extension or app is being
227   // currently upgraded or reloaded by any profile.  If so, update the
228   // output variables appropriately.
229   void CheckReloadStatus(
230       const extensions::Extension* extension,
231       bool* is_being_reloaded);
232 
233   // Called to make sure that our launch-on-startup mode is properly set.
234   // (virtual so we can override for tests).
235   virtual void EnableLaunchOnStartup(bool should_launch);
236 
237   // Invoked when a background app is installed so we can display a
238   // platform-specific notification to the user.
239   virtual void DisplayAppInstalledNotification(
240       const extensions::Extension* extension);
241 
242   // Invoked to put Chrome in KeepAlive mode - chrome runs in the background
243   // and has a status bar icon.
244   void StartBackgroundMode();
245 
246   // Invoked to take Chrome out of KeepAlive mode - chrome stops running in
247   // the background and removes its status bar icon.
248   void EndBackgroundMode();
249 
250   // Enables keep alive and the status tray icon if and only if background mode
251   // is active and not suspended.
252   virtual void UpdateKeepAliveAndTrayIcon();
253 
254   // If --no-startup-window is passed, BackgroundModeManager will manually keep
255   // chrome running while waiting for apps to load. This is called when we no
256   // longer need to do this (either because the user has chosen to exit chrome
257   // manually, or all apps have been loaded).
258   void DecrementKeepAliveCountForStartup();
259 
260   // Return an appropriate name for a Preferences menu entry.  Preferences is
261   // sometimes called Options or Settings.
262   base::string16 GetPreferencesMenuLabel();
263 
264   // Create a status tray icon to allow the user to shutdown Chrome when running
265   // in background mode. Virtual to enable testing.
266   virtual void CreateStatusTrayIcon();
267 
268   // Removes the status tray icon because we are exiting background mode.
269   // Virtual to enable testing.
270   virtual void RemoveStatusTrayIcon();
271 
272   // Create a context menu, or replace/update an existing context menu, for the
273   // status tray icon which, among other things, allows the user to shutdown
274   // Chrome when running in background mode. All profiles are listed under
275   // the one context menu.
276   virtual void UpdateStatusTrayIconContextMenu();
277 
278   // Returns the BackgroundModeData associated with this profile. If it does
279   // not exist, returns NULL.
280   BackgroundModeManager::BackgroundModeData* GetBackgroundModeData(
281       Profile* const profile) const;
282 
283   // Returns the iterator associated with a particular profile name.
284   // This should not be used to iterate over the background mode data. It is
285   // used to efficiently delete an item from the background mode data map.
286   BackgroundModeInfoMap::iterator GetBackgroundModeIterator(
287       const base::string16& profile_name);
288 
289   // Returns true if the "Let chrome run in the background" pref is checked.
290   // (virtual to allow overriding in tests).
291   virtual bool IsBackgroundModePrefEnabled() const;
292 
293   // Turns off background mode if it's currently enabled.
294   void DisableBackgroundMode();
295 
296   // Turns on background mode if it's currently disabled.
297   void EnableBackgroundMode();
298 
299   // Returns the number of background apps in the system (virtual to allow
300   // overriding in unit tests).
301   virtual int GetBackgroundAppCount() const;
302 
303   // Returns the number of background apps for a profile.
304   virtual int GetBackgroundAppCountForProfile(Profile* const profile) const;
305 
306   // Returns true if we should be in background mode.
307   bool ShouldBeInBackgroundMode() const;
308 
309   // Finds the BackgroundModeData associated with the last active profile,
310   // if the profile isn't locked. Returns NULL otherwise.
311   BackgroundModeManager::BackgroundModeData*
312       GetBackgroundModeDataForLastProfile() const;
313 
314   // Reference to the profile info cache. It is used to update the background
315   // app status of profiles when they open/close background apps.
316   ProfileInfoCache* profile_cache_;
317 
318   // Registrars for managing our change observers.
319   content::NotificationRegistrar registrar_;
320   PrefChangeRegistrar pref_registrar_;
321 
322   // The profile-keyed data for this background mode manager. Keyed on profile.
323   BackgroundModeInfoMap background_mode_data_;
324 
325   // Contains the dynamic Command IDs for the entire background menu.
326   CommandIdExtensionVector command_id_extension_vector_;
327 
328   // Maintains submenu lifetime for the multiple profile context menu.
329   ScopedVector<StatusIconMenuModel> submenus;
330 
331   // Reference to our status tray. If null, the platform doesn't support status
332   // icons.
333   StatusTray* status_tray_;
334 
335   // Reference to our status icon (if any) - owned by the StatusTray.
336   StatusIcon* status_icon_;
337 
338   // Reference to our status icon's context menu (if any) - owned by the
339   // status_icon_.
340   StatusIconMenuModel* context_menu_;
341 
342   // Set to true when we are running in background mode. Allows us to track our
343   // current background state so we can take the appropriate action when the
344   // user disables/enables background mode via preferences.
345   bool in_background_mode_;
346 
347   // Set when we are keeping chrome running during the startup process - this
348   // is required when running with the --no-startup-window flag, as otherwise
349   // chrome would immediately exit due to having no open windows.
350   bool keep_alive_for_startup_;
351 
352   // Set to true when Chrome is running with the --keep-alive-for-test flag
353   // (used for testing background mode without having to install a background
354   // app).
355   bool keep_alive_for_test_;
356 
357   // Set to true when background mode is suspended.
358   bool background_mode_suspended_;
359 
360   // Set to true when background mode is keeping Chrome alive.
361   bool keeping_alive_;
362 
363   DISALLOW_COPY_AND_ASSIGN(BackgroundModeManager);
364 };
365 
366 #endif  // CHROME_BROWSER_BACKGROUND_BACKGROUND_MODE_MANAGER_H_
367