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