Home | History | Annotate | Download | only in background
      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/browser_context_keyed_service/browser_context_keyed_service.h"
     19 #include "content/public/browser/notification_observer.h"
     20 #include "content/public/browser/notification_registrar.h"
     21 
     22 class Browser;
     23 class CommandLine;
     24 class PrefRegistrySimple;
     25 class Profile;
     26 class ProfileInfoCache;
     27 class StatusIcon;
     28 class StatusTray;
     29 
     30 namespace extensions {
     31 class Extension;
     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(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 TestBackgroundModeManager;
     87   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
     88                            BackgroundAppLoadUnload);
     89   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
     90                            BackgroundLaunchOnStartup);
     91   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
     92                            BackgroundAppInstallUninstallWhileDisabled);
     93   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
     94                            BackgroundModeDisabledPreventsKeepAliveOnStartup);
     95   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
     96                            DisableBackgroundModeUnderTestFlag);
     97   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
     98                            EnableAfterBackgroundAppInstall);
     99   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
    100                            MultiProfile);
    101   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
    102                            ProfileInfoCacheStorage);
    103   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
    104                            ProfileInfoCacheObserver);
    105   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
    106                            BackgroundMenuGeneration);
    107   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
    108                            BackgroundMenuGenerationMultipleProfile);
    109   FRIEND_TEST_ALL_PREFIXES(BackgroundAppBrowserTest,
    110                            ReloadBackgroundApp);
    111 
    112   class BackgroundModeData : public StatusIconMenuModel::Delegate {
    113    public:
    114     explicit BackgroundModeData(
    115         Profile* profile,
    116         CommandIdExtensionVector* command_id_extension_vector);
    117     virtual ~BackgroundModeData();
    118 
    119     // The cached list of BackgroundApplications.
    120     scoped_ptr<BackgroundApplicationListModel> applications_;
    121 
    122     // Overrides from StatusIconMenuModel::Delegate implementation.
    123     virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
    124 
    125     // Returns a browser window, or creates one if none are open. Used by
    126     // operations (like displaying the preferences dialog) that require a
    127     // Browser window.
    128     Browser* GetBrowserWindow();
    129 
    130     // Returns the number of background apps for this profile.
    131     int GetBackgroundAppCount() const;
    132 
    133     // Builds the profile specific parts of the menu. The menu passed in may
    134     // be a submenu in the case of multi-profiles or the main menu in the case
    135     // of the single profile case. If containing_menu is valid, we will add
    136     // menu as a submenu to it.
    137     void BuildProfileMenu(StatusIconMenuModel* menu,
    138                           StatusIconMenuModel* containing_menu);
    139 
    140     // Set the name associated with this background mode data for displaying in
    141     // the status tray.
    142     void SetName(const base::string16& new_profile_name);
    143 
    144     // The name associated with this background mode data. This should match
    145     // the name in the ProfileInfoCache for this profile.
    146     base::string16 name();
    147 
    148     // Used for sorting BackgroundModeData*s.
    149     static bool BackgroundModeDataCompare(const BackgroundModeData* bmd1,
    150                                           const BackgroundModeData* bmd2);
    151 
    152    private:
    153     // Name associated with this profile which is used to label its submenu.
    154     base::string16 name_;
    155 
    156     // The profile associated with this background app data.
    157     Profile* profile_;
    158 
    159     // Weak ref vector owned by BackgroundModeManager where the
    160     // indices correspond to Command IDs and values correspond to
    161     // extension indices. A value of -1 indicates no extension is associated
    162     // with the index.
    163     CommandIdExtensionVector* command_id_extension_vector_;
    164   };
    165 
    166   // Ideally we would want our BackgroundModeData to be scoped_ptrs,
    167   // but since maps copy their entries, we can't used scoped_ptrs.
    168   // Similarly, we can't just have a map of BackgroundModeData objects,
    169   // since BackgroundModeData contains a scoped_ptr which once again
    170   // can't be copied. So rather than using BackgroundModeData* which
    171   // we'd have to remember to delete, we use the ref-counted linked_ptr
    172   // which is similar to a shared_ptr.
    173   typedef linked_ptr<BackgroundModeData> BackgroundModeInfo;
    174 
    175   typedef std::map<Profile*, BackgroundModeInfo> BackgroundModeInfoMap;
    176 
    177   // content::NotificationObserver implementation.
    178   virtual void Observe(int type,
    179                        const content::NotificationSource& source,
    180                        const content::NotificationDetails& details) OVERRIDE;
    181 
    182   // Called when the kBackgroundModeEnabled preference changes.
    183   void OnBackgroundModeEnabledPrefChanged();
    184 
    185   // BackgroundApplicationListModel::Observer implementation.
    186   virtual void OnApplicationDataChanged(const extensions::Extension* extension,
    187                                         Profile* profile) OVERRIDE;
    188   virtual void OnApplicationListChanged(Profile* profile) OVERRIDE;
    189 
    190   // Overrides from ProfileInfoCacheObserver
    191   virtual void OnProfileAdded(const base::FilePath& profile_path) OVERRIDE;
    192   virtual void OnProfileWillBeRemoved(
    193       const base::FilePath& profile_path) OVERRIDE;
    194   virtual void OnProfileNameChanged(
    195       const base::FilePath& profile_path,
    196       const base::string16& old_profile_name) OVERRIDE;
    197 
    198   // Overrides from StatusIconMenuModel::Delegate implementation.
    199   virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
    200 
    201   // chrome::BrowserListObserver implementation.
    202   virtual void OnBrowserAdded(Browser* browser) OVERRIDE;
    203 
    204   // Invoked when an extension is installed so we can ensure that
    205   // launch-on-startup is enabled if appropriate. |extension| can be NULL when
    206   // called from unit tests.
    207   void OnBackgroundAppInstalled(
    208       const extensions::Extension* extension);
    209 
    210   // Walk the list of profiles and see if an extension or app is being
    211   // currently upgraded or reloaded by any profile.  If so, update the
    212   // output variables appropriately.
    213   void CheckReloadStatus(
    214       const extensions::Extension* extension,
    215       bool* is_being_reloaded);
    216 
    217   // Called to make sure that our launch-on-startup mode is properly set.
    218   // (virtual so we can override for tests).
    219   virtual void EnableLaunchOnStartup(bool should_launch);
    220 
    221   // Invoked when a background app is installed so we can display a
    222   // platform-specific notification to the user.
    223   virtual void DisplayAppInstalledNotification(
    224       const extensions::Extension* extension);
    225 
    226   // Invoked to put Chrome in KeepAlive mode - chrome runs in the background
    227   // and has a status bar icon.
    228   void StartBackgroundMode();
    229 
    230   // Invoked to take Chrome out of KeepAlive mode - chrome stops running in
    231   // the background and removes its status bar icon.
    232   void EndBackgroundMode();
    233 
    234   // Enables keep alive and the status tray icon if and only if background mode
    235   // is active and not suspended.
    236   virtual void UpdateKeepAliveAndTrayIcon();
    237 
    238   // If --no-startup-window is passed, BackgroundModeManager will manually keep
    239   // chrome running while waiting for apps to load. This is called when we no
    240   // longer need to do this (either because the user has chosen to exit chrome
    241   // manually, or all apps have been loaded).
    242   void EndKeepAliveForStartup();
    243 
    244   // Return an appropriate name for a Preferences menu entry.  Preferences is
    245   // sometimes called Options or Settings.
    246   base::string16 GetPreferencesMenuLabel();
    247 
    248   // Create a status tray icon to allow the user to shutdown Chrome when running
    249   // in background mode. Virtual to enable testing.
    250   virtual void CreateStatusTrayIcon();
    251 
    252   // Removes the status tray icon because we are exiting background mode.
    253   // Virtual to enable testing.
    254   virtual void RemoveStatusTrayIcon();
    255 
    256   // Create a context menu, or replace/update an existing context menu, for the
    257   // status tray icon which, among other things, allows the user to shutdown
    258   // Chrome when running in background mode. All profiles are listed under
    259   // the one context menu.
    260   virtual void UpdateStatusTrayIconContextMenu();
    261 
    262   // Returns the BackgroundModeData associated with this profile. If it does
    263   // not exist, returns NULL.
    264   BackgroundModeManager::BackgroundModeData* GetBackgroundModeData(
    265       Profile* const profile) const;
    266 
    267   // Returns the iterator associated with a particular profile name.
    268   // This should not be used to iterate over the background mode data. It is
    269   // used to efficiently delete an item from the background mode data map.
    270   BackgroundModeInfoMap::iterator GetBackgroundModeIterator(
    271       const base::string16& profile_name);
    272 
    273   // Returns true if the "Let chrome run in the background" pref is checked.
    274   // (virtual to allow overriding in tests).
    275   virtual bool IsBackgroundModePrefEnabled() const;
    276 
    277   // Turns off background mode if it's currently enabled.
    278   void DisableBackgroundMode();
    279 
    280   // Turns on background mode if it's currently disabled.
    281   void EnableBackgroundMode();
    282 
    283   // Returns the number of background apps in the system (virtual to allow
    284   // overriding in unit tests).
    285   virtual int GetBackgroundAppCount() const;
    286 
    287   // Returns the number of background apps for a profile.
    288   virtual int GetBackgroundAppCountForProfile(Profile* const profile) const;
    289 
    290   // Returns true if we should be in background mode.
    291   bool ShouldBeInBackgroundMode() const;
    292 
    293   // Reference to the profile info cache. It is used to update the background
    294   // app status of profiles when they open/close background apps.
    295   ProfileInfoCache* profile_cache_;
    296 
    297   // Registrars for managing our change observers.
    298   content::NotificationRegistrar registrar_;
    299   PrefChangeRegistrar pref_registrar_;
    300 
    301   // The profile-keyed data for this background mode manager. Keyed on profile.
    302   BackgroundModeInfoMap background_mode_data_;
    303 
    304   // Contains the dynamic Command IDs for the entire background menu.
    305   CommandIdExtensionVector command_id_extension_vector_;
    306 
    307   // Maintains submenu lifetime for the multiple profile context menu.
    308   ScopedVector<StatusIconMenuModel> submenus;
    309 
    310   // Reference to our status tray. If null, the platform doesn't support status
    311   // icons.
    312   StatusTray* status_tray_;
    313 
    314   // Reference to our status icon (if any) - owned by the StatusTray.
    315   StatusIcon* status_icon_;
    316 
    317   // Reference to our status icon's context menu (if any) - owned by the
    318   // status_icon_.
    319   StatusIconMenuModel* context_menu_;
    320 
    321   // Set to true when we are running in background mode. Allows us to track our
    322   // current background state so we can take the appropriate action when the
    323   // user disables/enables background mode via preferences.
    324   bool in_background_mode_;
    325 
    326   // Set when we are keeping chrome running during the startup process - this
    327   // is required when running with the --no-startup-window flag, as otherwise
    328   // chrome would immediately exit due to having no open windows.
    329   bool keep_alive_for_startup_;
    330 
    331   // Set to true when Chrome is running with the --keep-alive-for-test flag
    332   // (used for testing background mode without having to install a background
    333   // app).
    334   bool keep_alive_for_test_;
    335 
    336   // Set to true when background mode is suspended.
    337   bool background_mode_suspended_;
    338 
    339   // Set to true when background mode is keeping Chrome alive.
    340   bool keeping_alive_;
    341 
    342   DISALLOW_COPY_AND_ASSIGN(BackgroundModeManager);
    343 };
    344 
    345 #endif  // CHROME_BROWSER_BACKGROUND_BACKGROUND_MODE_MANAGER_H_
    346