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