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 23class Browser; 24class PrefRegistrySimple; 25class Profile; 26class ProfileInfoCache; 27class StatusIcon; 28class StatusTray; 29 30namespace base { 31class CommandLine; 32} 33 34typedef 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. 50class 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