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

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: 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
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)
21 // The code to remove a login item has a potential race (because the code to
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() { 20 void SetUserRemovedLoginItemPrefCallback() {
30 PrefService* service = g_browser_process->local_state(); 21 PrefService* service = g_browser_process->local_state();
31 service->SetBoolean(prefs::kUserRemovedLoginItem, true); 22 service->SetBoolean(prefs::kUserRemovedLoginItem, true);
32 } 23 }
33 24
25 void SetCreatedLoginItemPrefCallback() {
26 PrefService* service = g_browser_process->local_state();
27 service->SetBoolean(prefs::kChromeCreatedLoginItem, true);
28 }
29
34 void DisableLaunchOnStartupCallback() { 30 void DisableLaunchOnStartupCallback() {
35 // Check if Chrome is not a login Item, or is a Login Item but w/o 'hidden' 31 // If the LoginItem is not hidden, it means it's user created, so don't
36 // flag - most likely user has modified the setting, don't override it. 32 // delete it.
37 bool is_hidden = false; 33 bool is_hidden = false;
38 if (!base::mac::CheckLoginItemStatus(&is_hidden)) { 34 if (base::mac::CheckLoginItemStatus(&is_hidden) && is_hidden)
39 // No login item - this means the user must have already removed it, so 35 base::mac::RemoveFromLoginItems();
40 // call back to the UI thread to set a preference so we don't try to 36 }
41 // recreate it the next time they enable/install a background app. 37
42 #if !defined(NDEBUG) 38 void CheckForUserRemovedLoginItem() {
43 login_item_removed = true; 39 if (!base::mac::CheckLoginItemStatus(NULL)) {
44 #endif 40 // There's no LoginItem, so set the kUserRemovedLoginItem pref.
45 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 41 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
46 base::Bind(SetUserRemovedLoginItemPrefCallback)); 42 base::Bind(SetUserRemovedLoginItemPrefCallback));
47 return; 43 }
44 }
45
46 void EnableLaunchOnStartupCallback(bool need_migration) {
47 if (need_migration) {
48 DLOG(ERROR) << "MIGRATING";
49 // This is the first time running Chrome since the kChromeCreatedLoginItem
50 // pref was added. Initialize the status of this pref based on whether
51 // there is already a hidden login item.
52 bool is_hidden = false;
53 if (base::mac::CheckLoginItemStatus(&is_hidden)) {
54 DLOG(ERROR) << "FOUND LOGIN ITEM - hidden = " << is_hidden;
55 if (is_hidden) {
56 // We already have a hidden login item, so set the kChromeCreatedLoginItem
57 // flag.
58 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
59 base::Bind(SetCreatedLoginItemPrefCallback));
60 }
61 // LoginItem already exists - just exit.
62 return;
63 }
48 } 64 }
49 65
50 // If the login item does not have the "hidden" flag set, just leave it there 66 // Check if Chrome is already a Login Item - if not, create one.
51 // since it means the user must have created it. 67 if (!base::mac::CheckLoginItemStatus(NULL)) {
52 if (!is_hidden) 68 // Call back to the UI thread to set our preference so we know that Chrome
53 return; 69 // created the login item (which means we are allowed to delete it later).
54 70 // There's a race condition here if the user disables launch on startup
55 // Remove the login item we created. 71 // before our callback is run, but the user can manually disable
56 base::mac::RemoveFromLoginItems(); 72 // "Open At Login" via the dock if this happens.
57 } 73 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, 74 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
73 base::Bind(SetUserCreatedLoginItemPrefCallback)); 75 base::Bind(SetCreatedLoginItemPrefCallback));
74 return;
75 } 76 }
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 } 77 }
84 78
85 } // namespace 79 } // namespace
86 80
87 void BackgroundModeManager::EnableLaunchOnStartup(bool should_launch) { 81 void BackgroundModeManager::EnableLaunchOnStartup(bool should_launch) {
88 // This functionality is only defined for default profile, currently. 82 // This functionality is only defined for default profile, currently.
89 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUserDataDir)) 83 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUserDataDir))
sail 2013/04/11 16:12:29 The user data directory has nothing to do with def
Andrew T Wilson (Slow) 2013/04/12 09:52:21 Yeah, the comment was wrong (predated multi-profil
90 return; 84 return;
91 85
86 // There are a few cases we need to handle:
87 //
88 // 1) Chrome is transitioning to "launch on startup" state, and there's no
89 // login item currently. We create a new item if the kUserRemovedLoginItem
90 // and kChromeCreatedLoginItem flags are already false, and set the
91 // kChromeCreatedLoginItem flag to true. If kChromeCreatedLoginItem is
92 // already set (meaning that we created a login item that has since been
93 // deleted) then we will set the kUserRemovedLoginItem so we do not create
94 // login items in the future.
95 //
96 // 2) Chrome is transitioning to the "do not launch on startup" state. If
97 // the kChromeCreatedLoginItem flag is false, we do nothing. Otherwise, we
98 // will delete the login item if it's present, and not we will set
99 // kUserRemovedLoginItem to true to prevent future login items from being
100 // created.
92 if (should_launch) { 101 if (should_launch) {
93 PrefService* service = g_browser_process->local_state(); 102 PrefService* service = g_browser_process->local_state();
94 // Create a login item if the user did not remove our login item 103 // 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 104 if (service->GetBoolean(prefs::kUserRemovedLoginItem))
96 // want to check for a user-created login item. 105 return;
97 bool should_add_login_item = 106
98 !service->GetBoolean(prefs::kUserRemovedLoginItem); 107 if (service->GetBoolean(prefs::kChromeCreatedLoginItem)) {
99 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 108 DCHECK(service->GetBoolean(prefs::kMigratedLoginItemPref));
100 base::Bind(EnableLaunchOnStartupCallback, 109 // If we previously created a login item, we don't need to create
101 should_add_login_item)); 110 // a new one - just check to see if the user removed it so we don't
111 // every create another one.
sail 2013/04/11 16:12:29 typo? "don't every"
Andrew T Wilson (Slow) 2013/04/12 09:52:21 Done.
112 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
113 base::Bind(CheckForUserRemovedLoginItem));
114 } else {
115 bool need_migration = !service->GetBoolean(
116 prefs::kMigratedLoginItemPref);
117 service->SetBoolean(prefs::kMigratedLoginItemPref, true);
118 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
119 base::Bind(EnableLaunchOnStartupCallback,
120 need_migration));
121 }
102 } else { 122 } else {
103 PrefService* service = g_browser_process->local_state(); 123 PrefService* service = g_browser_process->local_state();
104 if (service->GetBoolean(prefs::kUserCreatedLoginItem)) { 124 // We didn't create any login items, so just exit.
105 // We didn't create the login item, so nothing to do here. Clear our 125 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; 126 return;
114 } 127
128 // Clear the pref now that we're removing the login item.
129 service->ClearPref(prefs::kChromeCreatedLoginItem);
130
131 // If the user removed our login item, note this so we don't ever create
132 // another one.
133 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
134 base::Bind(CheckForUserRemovedLoginItem));
135
115 // Call to the File thread to remove the login item since it requires 136 // Call to the File thread to remove the login item since it requires
116 // accessing the disk. 137 // accessing the disk.
117 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 138 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
118 base::Bind(DisableLaunchOnStartupCallback)); 139 base::Bind(DisableLaunchOnStartupCallback));
119 } 140 }
120 } 141 }
121 142
122 void BackgroundModeManager::DisplayAppInstalledNotification( 143 void BackgroundModeManager::DisplayAppInstalledNotification(
123 const extensions::Extension* extension) { 144 const extensions::Extension* extension) {
124 // TODO(atwilson): Display a platform-appropriate notification here. 145 // TODO(atwilson): Display a platform-appropriate notification here.
125 // http://crbug.com/74970 146 // http://crbug.com/74970
126 } 147 }
127 148
128 string16 BackgroundModeManager::GetPreferencesMenuLabel() { 149 string16 BackgroundModeManager::GetPreferencesMenuLabel() {
129 return l10n_util::GetStringUTF16(IDS_OPTIONS); 150 return l10n_util::GetStringUTF16(IDS_OPTIONS);
130 } 151 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698