summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbauerb@chromium.org <bauerb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-18 18:18:10 +0000
committerbauerb@chromium.org <bauerb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-18 18:18:10 +0000
commit9cc821655bc828170c9a049697d6f2ffcf5a3488 (patch)
tree3d1dfccccd7b3227ca59b677831f8a6f99c8a4e5
parentcda668384d63be9fddaebf01d82cd55105a2f8ac (diff)
downloadchromium_src-9cc821655bc828170c9a049697d6f2ffcf5a3488.zip
chromium_src-9cc821655bc828170c9a049697d6f2ffcf5a3488.tar.gz
chromium_src-9cc821655bc828170c9a049697d6f2ffcf5a3488.tar.bz2
Wait for other browser windows to close when entering managed mode and cancel on failure.
To do this, we need to make the interface for ManagedMode::EnterManagedMode() asynchronous and change ManagedMode into a singleton. BUG=119284 TEST=unit_tests --gtest_filter=ManagedModeTest.* Review URL: http://codereview.chromium.org/9903018 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@132824 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/extensions/extension_managed_mode_api.cc18
-rw-r--r--chrome/browser/extensions/extension_managed_mode_api.h6
-rw-r--r--chrome/browser/managed_mode.cc165
-rw-r--r--chrome/browser/managed_mode.h62
-rw-r--r--chrome/browser/managed_mode_unittest.cc226
-rw-r--r--chrome/browser/ui/browser.cc5
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/common/chrome_notification_types.h8
-rw-r--r--chrome/common/chrome_switches.cc3
-rw-r--r--chrome/common/chrome_switches.h1
10 files changed, 457 insertions, 38 deletions
diff --git a/chrome/browser/extensions/extension_managed_mode_api.cc b/chrome/browser/extensions/extension_managed_mode_api.cc
index 1471743..2cd834b2 100644
--- a/chrome/browser/extensions/extension_managed_mode_api.cc
+++ b/chrome/browser/extensions/extension_managed_mode_api.cc
@@ -8,6 +8,7 @@
#include <string>
+#include "base/bind.h"
#include "chrome/browser/managed_mode.h"
#include "chrome/browser/extensions/extension_preference_api_constants.h"
@@ -34,16 +35,15 @@ bool GetManagedModeFunction::RunImpl() {
EnterManagedModeFunction::~EnterManagedModeFunction() { }
bool EnterManagedModeFunction::RunImpl() {
- bool confirmed = true;
- if (!ManagedMode::IsInManagedMode()) {
- // TODO(pamg): WIP. Show modal password dialog and save hashed password. Set
- // |confirmed| to false if user cancels dialog.
-
- confirmed = ManagedMode::EnterManagedMode(profile());
- }
+ ManagedMode::EnterManagedMode(
+ profile(),
+ base::Bind(&EnterManagedModeFunction::SendResult, this));
+ return true;
+}
+void EnterManagedModeFunction::SendResult(bool success) {
scoped_ptr<DictionaryValue> result(new DictionaryValue);
- result->SetBoolean(kEnterSuccessKey, confirmed);
+ result->SetBoolean(kEnterSuccessKey, success);
result_.reset(result.release());
- return true;
+ SendResponse(true);
}
diff --git a/chrome/browser/extensions/extension_managed_mode_api.h b/chrome/browser/extensions/extension_managed_mode_api.h
index 0c1ef49..07b9e25 100644
--- a/chrome/browser/extensions/extension_managed_mode_api.h
+++ b/chrome/browser/extensions/extension_managed_mode_api.h
@@ -18,11 +18,15 @@ class GetManagedModeFunction : public SyncExtensionFunction {
DECLARE_EXTENSION_FUNCTION_NAME("experimental.managedMode.get")
};
-class EnterManagedModeFunction : public SyncExtensionFunction {
+class EnterManagedModeFunction : public AsyncExtensionFunction {
public:
virtual ~EnterManagedModeFunction();
virtual bool RunImpl() OVERRIDE;
DECLARE_EXTENSION_FUNCTION_NAME("experimental.managedMode.enter")
+
+ private:
+ // Called when we have either successfully entered managed mode or failed.
+ void SendResult(bool success);
};
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_MANAGED_MODE_API_H_
diff --git a/chrome/browser/managed_mode.cc b/chrome/browser/managed_mode.cc
index cef0d9e..15706a8 100644
--- a/chrome/browser/managed_mode.cc
+++ b/chrome/browser/managed_mode.cc
@@ -7,24 +7,37 @@
#include "base/command_line.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
+#include "chrome/browser/ui/app_modal_dialogs/js_modal_dialog.h"
+#include "chrome/browser/ui/browser_window.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/notification_service.h"
// static
+ManagedMode* ManagedMode::GetInstance() {
+ return Singleton<ManagedMode>::get();
+}
+
+// static
void ManagedMode::RegisterPrefs(PrefService* prefs) {
prefs->RegisterBooleanPref(prefs::kInManagedMode, false);
// Set the value directly in the PrefService instead of using
// CommandLinePrefStore so we can change it at runtime.
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kManaged))
- SetInManagedMode(true);
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoManaged))
+ GetInstance()->SetInManagedMode(false);
+ else if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kManaged))
+ GetInstance()->SetInManagedMode(true);
}
// static
bool ManagedMode::IsInManagedMode() {
+ return GetInstance()->IsInManagedModeImpl();
+}
+
+bool ManagedMode::IsInManagedModeImpl() {
// |g_browser_process| can be NULL during startup.
if (!g_browser_process)
return false;
@@ -32,46 +45,154 @@ bool ManagedMode::IsInManagedMode() {
}
// static
-bool ManagedMode::EnterManagedMode(Profile* profile) {
- bool confirmed = PlatformConfirmEnter();
- if (confirmed) {
- // Close all other profiles.
- // TODO(bauerb): This may not close all windows, for example if there is an
- // onbeforeunload handler. We should cancel entering managed mode in that
- // case.
- std::vector<Profile*> profiles =
- g_browser_process->profile_manager()->GetLoadedProfiles();
- for (std::vector<Profile*>::iterator it = profiles.begin();
- it != profiles.end(); ++it) {
- if (*it != profile)
- BrowserList::CloseAllBrowsersWithProfile(*it);
- }
+void ManagedMode::EnterManagedMode(Profile* profile,
+ const EnterCallback& callback) {
+ GetInstance()->EnterManagedModeImpl(profile, callback);
+}
+
+void ManagedMode::EnterManagedModeImpl(Profile* profile,
+ const EnterCallback& callback) {
+ if (IsInManagedModeImpl()) {
+ callback.Run(true);
+ return;
+ }
+ Profile* original_profile = profile->GetOriginalProfile();
+ if (!callbacks_.empty()) {
+ // We are already in the process of entering managed mode, waiting for
+ // browsers to close. Don't allow entering managed mode again for a
+ // different profile, and queue the callback for the same profile.
+ if (original_profile != managed_profile_)
+ callback.Run(false);
+ else
+ callbacks_.push_back(callback);
+ return;
+ }
+ if (!PlatformConfirmEnter()) {
+ callback.Run(false);
+ return;
+ }
+ managed_profile_ = original_profile;
+ // Close all other profiles.
+ // At this point, we shouldn't be waiting for other browsers to close (yet).
+ DCHECK_EQ(0u, browsers_to_close_.size());
+ for (BrowserList::const_iterator i = BrowserList::begin();
+ i != BrowserList::end(); ++i) {
+ if ((*i)->profile()->GetOriginalProfile() != managed_profile_)
+ browsers_to_close_.insert(*i);
+ }
+
+ if (browsers_to_close_.empty()) {
SetInManagedMode(true);
+ managed_profile_ = NULL;
+ callback.Run(true);
+ return;
+ }
+ callbacks_.push_back(callback);
+ registrar_.Add(this, content::NOTIFICATION_APP_EXITING,
+ content::NotificationService::AllSources());
+ registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED,
+ content::NotificationService::AllSources());
+ for (std::set<const Browser*>::const_iterator i = browsers_to_close_.begin();
+ i != browsers_to_close_.end(); ++i) {
+ (*i)->window()->Close();
}
- return confirmed;
}
// static
void ManagedMode::LeaveManagedMode() {
+ GetInstance()->LeaveManagedModeImpl();
+}
+
+void ManagedMode::LeaveManagedModeImpl() {
bool confirmed = PlatformConfirmLeave();
if (confirmed)
SetInManagedMode(false);
}
-// static
+void ManagedMode::OnBrowserAdded(const Browser* browser) {
+ // Return early if we don't have any queued callbacks.
+ if (callbacks_.empty())
+ return;
+
+ if (browser->profile()->GetOriginalProfile() != managed_profile_)
+ FinalizeEnter(false);
+}
+
+void ManagedMode::OnBrowserRemoved(const Browser* browser) {
+ // Return early if we don't have any queued callbacks.
+ if (callbacks_.empty())
+ return;
+
+ if (browser->profile()->GetOriginalProfile() == managed_profile_) {
+ // Ignore closing browser windows that are in managed mode.
+ return;
+ }
+ size_t count = browsers_to_close_.erase(browser);
+ DCHECK_EQ(1u, count);
+ if (browsers_to_close_.empty())
+ FinalizeEnter(true);
+}
+
+ManagedMode::ManagedMode() : managed_profile_(NULL) {
+ BrowserList::AddObserver(this);
+}
+
+ManagedMode::~ManagedMode() {
+ BrowserList::RemoveObserver(this);
+ DCHECK(!managed_profile_);
+ DCHECK_EQ(0u, callbacks_.size());
+ DCHECK_EQ(0u, browsers_to_close_.size());
+}
+
+void ManagedMode::Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ // Return early if we don't have any queued callbacks.
+ if (callbacks_.empty())
+ return;
+
+ switch (type) {
+ case content::NOTIFICATION_APP_EXITING: {
+ FinalizeEnter(false);
+ return;
+ }
+ case chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED: {
+ Browser* browser = content::Source<Browser>(source).ptr();
+ if (browsers_to_close_.find(browser) != browsers_to_close_.end())
+ FinalizeEnter(false);
+ return;
+ }
+ default: {
+ NOTREACHED();
+ break;
+ }
+ }
+}
+
+void ManagedMode::FinalizeEnter(bool result) {
+ if (result)
+ SetInManagedMode(true);
+ for (std::vector<EnterCallback>::iterator it = callbacks_.begin();
+ it != callbacks_.end(); ++it) {
+ it->Run(result);
+ }
+ managed_profile_ = NULL;
+ callbacks_.clear();
+ browsers_to_close_.clear();
+ registrar_.RemoveAll();
+}
+
bool ManagedMode::PlatformConfirmEnter() {
// TODO(bauerb): Show platform-specific confirmation dialog.
return true;
}
-// static
bool ManagedMode::PlatformConfirmLeave() {
// TODO(bauerb): Show platform-specific confirmation dialog.
return true;
}
-// static
void ManagedMode::SetInManagedMode(bool in_managed_mode) {
g_browser_process->local_state()->SetBoolean(prefs::kInManagedMode,
in_managed_mode);
diff --git a/chrome/browser/managed_mode.h b/chrome/browser/managed_mode.h
index 11466bf..b3edef0 100644
--- a/chrome/browser/managed_mode.h
+++ b/chrome/browser/managed_mode.h
@@ -5,25 +5,75 @@
#ifndef CHROME_BROWSER_MANAGED_MODE_H_
#define CHROME_BROWSER_MANAGED_MODE_H_
+#include <set>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+
+class Browser;
+template<typename T>
+struct DefaultSingletonTraits;
class PrefService;
class Profile;
-class ManagedMode {
+class ManagedMode : public BrowserList::Observer,
+ public content::NotificationObserver {
public:
+ typedef base::Callback<void(bool)> EnterCallback;
+
static void RegisterPrefs(PrefService* prefs);
static bool IsInManagedMode();
- // Returns true iff managed mode was entered sucessfully.
- static bool EnterManagedMode(Profile* profile);
+ // Calls |callback| with the argument true iff managed mode was entered
+ // sucessfully.
+ static void EnterManagedMode(Profile* profile, const EnterCallback& callback);
static void LeaveManagedMode();
+ // BrowserList::Observer implementation:
+ virtual void OnBrowserAdded(const Browser* browser) OVERRIDE;
+ virtual void OnBrowserRemoved(const Browser* browser) OVERRIDE;
+
+ // content::NotificationObserver implementation:
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE;
+
+ protected:
+ ManagedMode();
+ virtual ~ManagedMode();
+ void EnterManagedModeImpl(Profile* profile, const EnterCallback& callback);
+
private:
+ friend struct DefaultSingletonTraits<ManagedMode>;
+ friend class Singleton<ManagedMode>;
+
+ static ManagedMode* GetInstance();
+
+ void LeaveManagedModeImpl();
+
+ void FinalizeEnter(bool result);
+
// Platform-specific methods that confirm whether we can enter or leave
// managed mode.
- static bool PlatformConfirmEnter();
- static bool PlatformConfirmLeave();
+ virtual bool PlatformConfirmEnter();
+ virtual bool PlatformConfirmLeave();
- static void SetInManagedMode(bool in_managed_mode);
+ virtual bool IsInManagedModeImpl();
+ virtual void SetInManagedMode(bool in_managed_mode);
+
+ content::NotificationRegistrar registrar_;
+
+ // The managed profile. This is non-NULL only while we're entering
+ // managed mode.
+ const Profile* managed_profile_;
+ std::set<const Browser*> browsers_to_close_;
+ std::vector<EnterCallback> callbacks_;
};
#endif // CHROME_BROWSER_MANAGED_MODE_H_
diff --git a/chrome/browser/managed_mode_unittest.cc b/chrome/browser/managed_mode_unittest.cc
new file mode 100644
index 0000000..712dcc7
--- /dev/null
+++ b/chrome/browser/managed_mode_unittest.cc
@@ -0,0 +1,226 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/managed_mode.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/message_loop.h"
+#include "chrome/browser/managed_mode.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/test_browser_window.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/test/test_browser_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using ::testing::StrictMock;
+
+namespace {
+
+class FakeManagedMode : public ManagedMode {
+ public:
+ FakeManagedMode() : in_managed_mode_(false), should_cancel_enter_(false) {
+ }
+
+ void set_should_cancel_enter(bool should_cancel_enter) {
+ should_cancel_enter_ = should_cancel_enter;
+ }
+
+ void EnterManagedModeForTesting(Profile* profile,
+ const base::Callback<void(bool)>& callback) {
+ EnterManagedModeImpl(profile, callback);
+ }
+
+ // ManagedMode overrides:
+ virtual bool IsInManagedModeImpl() OVERRIDE {
+ return in_managed_mode_;
+ }
+
+ virtual void SetInManagedMode(bool in_managed_mode) OVERRIDE {
+ in_managed_mode_ = in_managed_mode;
+ }
+
+ virtual bool PlatformConfirmEnter() OVERRIDE {
+ return !should_cancel_enter_;
+ }
+
+ virtual bool PlatformConfirmLeave() OVERRIDE {
+ return true;
+ }
+
+ private:
+ bool in_managed_mode_;
+ bool should_cancel_enter_;
+};
+
+class MockBrowserWindow : public TestBrowserWindow {
+ public:
+ explicit MockBrowserWindow(Browser* browser) : TestBrowserWindow(browser) {
+ }
+
+ MOCK_METHOD0(Close, void());
+};
+
+class BrowserFixture {
+ public:
+ BrowserFixture(FakeManagedMode* managed_mode,
+ TestingProfile* profile)
+ : browser_(Browser::TYPE_TABBED, profile),
+ window_(&browser_),
+ managed_mode_(managed_mode) {
+ browser_.SetWindowForTesting(&window_);
+ }
+
+ ~BrowserFixture() {
+ }
+
+ MockBrowserWindow* window() {
+ return &window_;
+ }
+
+ private:
+ Browser browser_;
+ StrictMock<MockBrowserWindow> window_;
+ FakeManagedMode* managed_mode_;
+};
+
+class MockCallback : public base::RefCountedThreadSafe<MockCallback> {
+ public:
+ explicit MockCallback(FakeManagedMode* managed_mode)
+ : managed_mode_(managed_mode) {
+ }
+ virtual ~MockCallback() {}
+
+ void CheckManagedMode(bool success) {
+ EXPECT_EQ(managed_mode_->IsInManagedModeImpl(), success);
+ DidEnterManagedMode(success);
+ }
+
+ MOCK_METHOD1(DidEnterManagedMode, void(bool));
+
+ private:
+ FakeManagedMode* managed_mode_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+} // namespace
+
+class ManagedModeTest : public ::testing::Test {
+ public:
+ ManagedModeTest() : ui_thread_(content::BrowserThread::UI, &message_loop_) {
+ }
+
+ scoped_refptr<MockCallback> CreateCallback() {
+ return new StrictMock<MockCallback>(&managed_mode_);
+ }
+
+ base::Callback<void(bool)> CreateExpectedCallback(bool success) {
+ scoped_refptr<MockCallback> callback = CreateCallback();
+ EXPECT_CALL(*callback, DidEnterManagedMode(success));
+ return base::Bind(&MockCallback::CheckManagedMode, callback);
+ }
+
+ protected:
+ MessageLoop message_loop_;
+ content::TestBrowserThread ui_thread_;
+ TestingProfile managed_mode_profile_;
+ TestingProfile other_profile_;
+ FakeManagedMode managed_mode_;
+};
+
+TEST_F(ManagedModeTest, SingleBrowser) {
+ BrowserFixture managed_mode_browser(&managed_mode_, &managed_mode_profile_);
+
+ // If there are no browsers belonging to a different profile, entering should
+ // immediately succeed.
+ managed_mode_.EnterManagedModeForTesting(&managed_mode_profile_,
+ CreateExpectedCallback(true));
+}
+
+TEST_F(ManagedModeTest, AlreadyInManagedMode) {
+ BrowserFixture managed_mode_browser(&managed_mode_, &managed_mode_profile_);
+ BrowserFixture other_browser(&managed_mode_, &other_profile_);
+
+ // If we're already in managed mode, entering should immediately succeed.
+ managed_mode_.SetInManagedMode(true);
+ managed_mode_.EnterManagedModeForTesting(&managed_mode_profile_,
+ CreateExpectedCallback(true));
+}
+
+TEST_F(ManagedModeTest, QueueRequests) {
+ BrowserFixture managed_mode_browser(&managed_mode_, &managed_mode_profile_);
+
+ // Keep this before the other browser is constructed, so we verify its
+ // expectations after the browser is destroyed.
+ scoped_refptr<MockCallback> callback = CreateCallback();
+ BrowserFixture other_browser(&managed_mode_, &other_profile_);
+
+ EXPECT_CALL(*other_browser.window(), Close());
+ managed_mode_.EnterManagedModeForTesting(
+ &managed_mode_profile_,
+ base::Bind(&MockCallback::CheckManagedMode, callback));
+ managed_mode_.EnterManagedModeForTesting(
+ &managed_mode_profile_,
+ base::Bind(&MockCallback::CheckManagedMode, callback));
+ // The callbacks should run as soon as |other_browser| is closed.
+ EXPECT_CALL(*callback, DidEnterManagedMode(true)).Times(2);
+}
+
+TEST_F(ManagedModeTest, OpenNewBrowser) {
+ BrowserFixture managed_mode_browser(&managed_mode_, &managed_mode_profile_);
+ BrowserFixture other_browser(&managed_mode_, &other_profile_);
+
+ scoped_refptr<MockCallback> callback = CreateCallback();
+ EXPECT_CALL(*other_browser.window(), Close());
+ managed_mode_.EnterManagedModeForTesting(
+ &managed_mode_profile_,
+ base::Bind(&MockCallback::CheckManagedMode, callback));
+
+ // Opening another browser with the managed profile should not cancel entering
+ // managed mode.
+ BrowserFixture other_managed_mode_browser(&managed_mode_,
+ &managed_mode_profile_);
+
+ // Opening another browser should cancel entering managed mode.
+ EXPECT_CALL(*callback, DidEnterManagedMode(false));
+ BrowserFixture yet_another_browser(&managed_mode_, &other_profile_);
+}
+
+TEST_F(ManagedModeTest, DifferentProfile) {
+ BrowserFixture managed_mode_browser(&managed_mode_, &managed_mode_profile_);
+
+ // Keep this before the other browser is constructed, so we verify its
+ // expectations after the browser is destroyed.
+ scoped_refptr<MockCallback> callback = CreateCallback();
+ BrowserFixture other_browser(&managed_mode_, &other_profile_);
+
+ EXPECT_CALL(*other_browser.window(), Close());
+ managed_mode_.EnterManagedModeForTesting(
+ &managed_mode_profile_,
+ base::Bind(&MockCallback::CheckManagedMode, callback));
+
+ // Trying to enter managed mode with a different profile should fail
+ // immediately.
+ managed_mode_.EnterManagedModeForTesting(&other_profile_,
+ CreateExpectedCallback(false));
+
+ // The first request should still succeed as soon as the other browser is
+ // closed.
+ EXPECT_CALL(*callback, DidEnterManagedMode(true));
+}
+
+TEST_F(ManagedModeTest, Cancelled) {
+ BrowserFixture managed_mode_browser(&managed_mode_, &managed_mode_profile_);
+ BrowserFixture other_browser(&managed_mode_, &other_profile_);
+
+ // If the user cancelled entering managed mode, it should fail immediately.
+ managed_mode_.set_should_cancel_enter(true);
+ managed_mode_.EnterManagedModeForTesting(&managed_mode_profile_,
+ CreateExpectedCallback(false));
+}
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 66744f5..316e399 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -5307,6 +5307,11 @@ void Browser::CancelWindowClose() {
tabs_needing_unload_fired_.clear();
is_attempting_to_close_browser_ = false;
+ content::NotificationService::current()->Notify(
+ chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED,
+ content::Source<Browser>(this),
+ content::NotificationService::NoDetails());
+
// Inform TabCloseableStateWatcher that closing of window has been canceled.
TabCloseableStateWatcher* watcher =
g_browser_process->tab_closeable_state_watcher();
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index fe30e87..39aaf80 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1500,6 +1500,7 @@
'browser/internal_auth_unittest.cc',
'browser/language_usage_metrics_unittest.cc',
'browser/mac/keystone_glue_unittest.mm',
+ 'browser/managed_mode_unittest.cc',
'browser/media/media_internals_unittest.cc',
'browser/media_gallery/media_device_notifications_linux_unittest.cc',
'browser/media_gallery/media_gallery_database_unittest.cc',
diff --git a/chrome/common/chrome_notification_types.h b/chrome/common/chrome_notification_types.h
index 1e67e8b..3781814 100644
--- a/chrome/common/chrome_notification_types.h
+++ b/chrome/common/chrome_notification_types.h
@@ -42,6 +42,14 @@ enum NotificationType {
// valid for the duration of this call.
NOTIFICATION_BROWSER_CLOSED,
+ // This message is sent when closing a browser has been cancelled, either by
+ // the user cancelling a beforeunload dialog, or IsClosingPermitted()
+ // disallowing closing. This notification implies that no BROWSER_CLOSING or
+ // BROWSER_CLOSED notification will be sent.
+ // The source is a Source<Browser> containing the affected browser. No details
+ // are expected.
+ NOTIFICATION_BROWSER_CLOSE_CANCELLED,
+
// Indicates that a top window has been closed. The source is the HWND
// that was closed, no details are expected.
NOTIFICATION_WINDOW_CLOSED,
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 80e26d1..51b273b 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -854,6 +854,9 @@ const char kNoExperiments[] = "no-experiments";
// you're for some reason tempted to pass them both.
const char kNoFirstRun[] = "no-first-run";
+// Starts the browser outside of managed mode.
+const char kNoManaged[] = "no-managed";
+
// Don't send hyperlink auditing pings
const char kNoPings[] = "no-pings";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 4afed1a..abe4977 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -232,6 +232,7 @@ extern const char kNoDisplayingInsecureContent[];
extern const char kNoEvents[];
extern const char kNoExperiments[];
extern const char kNoFirstRun[];
+extern const char kNoManaged[];
extern const char kNoProxyServer[];
extern const char kNoPings[];
extern const char kNoProtector[];