Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(28)

Side by Side Diff: chrome/browser/background/background_mode_manager_mac.mm

Issue 13982009: Fix issue with login items getting recreated. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Updated comments/review feedback. Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/background/background_mode_manager.cc ('k') | chrome/common/pref_names.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/bind.h" 5 #include "base/bind.h"
6 #include "base/command_line.h" 6 #include "base/command_line.h"
7 #include "base/mac/mac_util.h" 7 #include "base/mac/mac_util.h"
8 #include "base/prefs/pref_service.h" 8 #include "base/prefs/pref_service.h"
9 #include "chrome/browser/background/background_mode_manager.h" 9 #include "chrome/browser/background/background_mode_manager.h"
10 #include "chrome/browser/browser_process.h" 10 #include "chrome/browser/browser_process.h"
11 #include "chrome/common/chrome_switches.h" 11 #include "chrome/common/chrome_switches.h"
12 #include "chrome/common/pref_names.h" 12 #include "chrome/common/pref_names.h"
13 #include "content/public/browser/browser_thread.h" 13 #include "content/public/browser/browser_thread.h"
14 #include "grit/generated_resources.h" 14 #include "grit/generated_resources.h"
15 #include "ui/base/l10n/l10n_util.h" 15 #include "ui/base/l10n/l10n_util.h"
16 16
17 using content::BrowserThread; 17 using content::BrowserThread;
18 18
19 namespace { 19 namespace {
20 #if !defined(NDEBUG) 20 void SetUserRemovedLoginItemPrefOnUIThread() {
21 // The code to remove a login item has a potential race (because the code to 21 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
22 // set and check the kUserRemovedLoginItem pref runs on the UI thread, while
23 // the code that checks for a login item runs on the IO thread). We add this
24 // flag which should always match the value of the pref to see if we ever hit
25 // this race in practice.
26 static bool login_item_removed = false;
27 #endif
28
29 void SetUserRemovedLoginItemPrefCallback() {
30 PrefService* service = g_browser_process->local_state(); 22 PrefService* service = g_browser_process->local_state();
31 service->SetBoolean(prefs::kUserRemovedLoginItem, true); 23 service->SetBoolean(prefs::kUserRemovedLoginItem, true);
32 } 24 }
33 25
34 void DisableLaunchOnStartupCallback() { 26 void SetCreatedLoginItemPrefOnUIThread() {
35 // Check if Chrome is not a login Item, or is a Login Item but w/o 'hidden' 27 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
36 // flag - most likely user has modified the setting, don't override it. 28 PrefService* service = g_browser_process->local_state();
29 service->SetBoolean(prefs::kChromeCreatedLoginItem, true);
30 }
31
32 void DisableLaunchOnStartupOnFileThread() {
33 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
34 // If the LoginItem is not hidden, it means it's user created, so don't
35 // delete it.
37 bool is_hidden = false; 36 bool is_hidden = false;
38 if (!base::mac::CheckLoginItemStatus(&is_hidden)) { 37 if (base::mac::CheckLoginItemStatus(&is_hidden) && is_hidden)
39 // No login item - this means the user must have already removed it, so 38 base::mac::RemoveFromLoginItems();
40 // call back to the UI thread to set a preference so we don't try to 39 }
41 // recreate it the next time they enable/install a background app. 40
42 #if !defined(NDEBUG) 41 void CheckForUserRemovedLoginItemOnFileThread() {
43 login_item_removed = true; 42 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
44 #endif 43 if (!base::mac::CheckLoginItemStatus(NULL)) {
44 // There's no LoginItem, so set the kUserRemovedLoginItem pref.
45 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 45 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
46 base::Bind(SetUserRemovedLoginItemPrefCallback)); 46 base::Bind(SetUserRemovedLoginItemPrefOnUIThread));
47 return; 47 }
48 }
49
50 void EnableLaunchOnStartupOnFileThread(bool need_migration) {
51 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
52 if (need_migration) {
53 // This is the first time running Chrome since the kChromeCreatedLoginItem
54 // pref was added. Initialize the status of this pref based on whether
55 // there is already a hidden login item.
56 bool is_hidden = false;
57 if (base::mac::CheckLoginItemStatus(&is_hidden)) {
58 if (is_hidden) {
59 // We already have a hidden login item, so set the kChromeCreatedLoginItem
60 // flag.
61 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
62 base::Bind(SetCreatedLoginItemPrefOnUIThread));
63 }
64 // LoginItem already exists - just exit.
65 return;
66 }
48 } 67 }
49 68
50 // If the login item does not have the "hidden" flag set, just leave it there 69 // Check if Chrome is already a Login Item - if not, create one.
51 // since it means the user must have created it. 70 if (!base::mac::CheckLoginItemStatus(NULL)) {
52 if (!is_hidden) 71 // Call back to the UI thread to set our preference so we know that Chrome
53 return; 72 // created the login item (which means we are allowed to delete it later).
54 73 // There's a race condition here if the user disables launch on startup
55 // Remove the login item we created. 74 // before our callback is run, but the user can manually disable
56 base::mac::RemoveFromLoginItems(); 75 // "Open At Login" via the dock if this happens.
57 } 76 base::mac::AddToLoginItems(true); // Hide on startup.
58
59 void SetUserCreatedLoginItemPrefCallback() {
60 PrefService* service = g_browser_process->local_state();
61 service->SetBoolean(prefs::kUserCreatedLoginItem, true);
62 }
63
64 void EnableLaunchOnStartupCallback(bool should_add_login_item) {
65 // Check if Chrome is already a Login Item (avoid overriding user choice).
66 if (base::mac::CheckLoginItemStatus(NULL)) {
67 // Call back to the UI thread to set our preference so we don't delete the
68 // user's login item when we disable launch on startup. There's a race
69 // condition here if the user disables launch on startup before our callback
70 // is run, but the user can manually disable "Open At Login" via the dock if
71 // this happens.
72 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 77 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
73 base::Bind(SetUserCreatedLoginItemPrefCallback)); 78 base::Bind(SetCreatedLoginItemPrefOnUIThread));
74 return;
75 } 79 }
76
77 if (should_add_login_item)
78 base::mac::AddToLoginItems(true); // Hide on startup.
79 #if !defined(NDEBUG)
80 else
81 DCHECK(!login_item_removed); // Check for race condition (see above).
82 #endif
83 } 80 }
84 81
85 } // namespace 82 } // namespace
86 83
87 void BackgroundModeManager::EnableLaunchOnStartup(bool should_launch) { 84 void BackgroundModeManager::EnableLaunchOnStartup(bool should_launch) {
88 // This functionality is only defined for default profile, currently. 85 // LoginItems are associated with an executable, not with a specific
86 // user-data-dir, so only mess with the LoginItem when running with the
87 // default user-data-dir. So if a user is running multiple instances of
88 // Chrome with different user-data-dirs, they won't conflict in their
89 // use of LoginItems.
89 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUserDataDir)) 90 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUserDataDir))
90 return; 91 return;
91 92
93 // There are a few cases we need to handle:
94 //
95 // 1) Chrome is transitioning to "launch on startup" state, and there's no
96 // login item currently. We create a new item if the kUserRemovedLoginItem
97 // and kChromeCreatedLoginItem flags are already false, and set the
98 // kChromeCreatedLoginItem flag to true. If kChromeCreatedLoginItem is
99 // already set (meaning that we created a login item that has since been
100 // deleted) then we will set the kUserRemovedLoginItem so we do not create
101 // login items in the future.
102 //
103 // 2) Chrome is transitioning to the "do not launch on startup" state. If
104 // the kChromeCreatedLoginItem flag is false, we do nothing. Otherwise, we
105 // will delete the login item if it's present, and not we will set
106 // kUserRemovedLoginItem to true to prevent future login items from being
107 // created.
92 if (should_launch) { 108 if (should_launch) {
93 PrefService* service = g_browser_process->local_state(); 109 PrefService* service = g_browser_process->local_state();
94 // Create a login item if the user did not remove our login item 110 // If the user removed the login item, don't ever create another one.
95 // previously. We call out to the FILE thread either way since we 111 if (service->GetBoolean(prefs::kUserRemovedLoginItem))
96 // want to check for a user-created login item. 112 return;
97 bool should_add_login_item = 113
98 !service->GetBoolean(prefs::kUserRemovedLoginItem); 114 if (service->GetBoolean(prefs::kChromeCreatedLoginItem)) {
99 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 115 DCHECK(service->GetBoolean(prefs::kMigratedLoginItemPref));
100 base::Bind(EnableLaunchOnStartupCallback, 116 // If we previously created a login item, we don't need to create
101 should_add_login_item)); 117 // a new one - just check to see if the user removed it so we don't
118 // ever create another one.
119 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
120 base::Bind(
121 CheckForUserRemovedLoginItemOnFileThread));
122 } else {
123 bool need_migration = !service->GetBoolean(
124 prefs::kMigratedLoginItemPref);
125 service->SetBoolean(prefs::kMigratedLoginItemPref, true);
126 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
127 base::Bind(EnableLaunchOnStartupOnFileThread,
128 need_migration));
129 }
102 } else { 130 } else {
103 PrefService* service = g_browser_process->local_state(); 131 PrefService* service = g_browser_process->local_state();
104 if (service->GetBoolean(prefs::kUserCreatedLoginItem)) { 132 // If Chrome didn't create any login items, just exit.
105 // We didn't create the login item, so nothing to do here. Clear our 133 if (!service->GetBoolean(prefs::kChromeCreatedLoginItem))
106 // prefs so if the user removes the login item before installing a
107 // background app, we will revert to the default behavior.
108 service->ClearPref(prefs::kUserCreatedLoginItem);
109 service->ClearPref(prefs::kUserRemovedLoginItem);
110 #if !defined(NDEBUG)
111 login_item_removed = false;
112 #endif
113 return; 134 return;
114 } 135
136 // Clear the pref now that we're removing the login item.
137 service->ClearPref(prefs::kChromeCreatedLoginItem);
138
139 // If the user removed our login item, note this so we don't ever create
140 // another one.
141 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
142 base::Bind(
143 CheckForUserRemovedLoginItemOnFileThread));
144
115 // Call to the File thread to remove the login item since it requires 145 // Call to the File thread to remove the login item since it requires
116 // accessing the disk. 146 // accessing the disk.
117 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 147 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
118 base::Bind(DisableLaunchOnStartupCallback)); 148 base::Bind(DisableLaunchOnStartupOnFileThread));
119 } 149 }
120 } 150 }
121 151
122 void BackgroundModeManager::DisplayAppInstalledNotification( 152 void BackgroundModeManager::DisplayAppInstalledNotification(
123 const extensions::Extension* extension) { 153 const extensions::Extension* extension) {
124 // TODO(atwilson): Display a platform-appropriate notification here. 154 // TODO(atwilson): Display a platform-appropriate notification here.
125 // http://crbug.com/74970 155 // http://crbug.com/74970
126 } 156 }
127 157
128 string16 BackgroundModeManager::GetPreferencesMenuLabel() { 158 string16 BackgroundModeManager::GetPreferencesMenuLabel() {
129 return l10n_util::GetStringUTF16(IDS_OPTIONS); 159 return l10n_util::GetStringUTF16(IDS_OPTIONS);
130 } 160 }
OLDNEW
« no previous file with comments | « chrome/browser/background/background_mode_manager.cc ('k') | chrome/common/pref_names.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698