summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/browser_main.cc5
-rw-r--r--chrome/browser/chromeos/login/login_browsertest.cc6
-rw-r--r--chrome/browser/chromeos/login/screen_locker.cc81
3 files changed, 74 insertions, 18 deletions
diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc
index 34e945d..2d47ccf4 100644
--- a/chrome/browser/browser_main.cc
+++ b/chrome/browser/browser_main.cc
@@ -615,7 +615,6 @@ void OptionallyRunChromeOSLoginManager(const CommandLine& parsed_command_line) {
}
browser::ShowLoginWizard(first_screen, size);
}
- chromeos::ScreenLocker::InitClass();
}
#else
void OptionallyRunChromeOSLoginManager(const CommandLine& parsed_command_line) {
@@ -1041,6 +1040,10 @@ int BrowserMain(const MainFunctionParams& parameters) {
// Profile creation ----------------------------------------------------------
#if defined(OS_CHROMEOS)
+ // Initialize the screen locker now so that it can receive
+ // LOGIN_USER_CHANGED notification from UserManager.
+ chromeos::ScreenLocker::InitClass();
+
// This forces the ProfileManager to be created and register for the
// notification it needs to track the logged in user.
g_browser_process->profile_manager()->GetDefaultProfile();
diff --git a/chrome/browser/chromeos/login/login_browsertest.cc b/chrome/browser/chromeos/login/login_browsertest.cc
index da51a39..4c1800f 100644
--- a/chrome/browser/chromeos/login/login_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_browsertest.cc
@@ -12,6 +12,7 @@
#include "chrome/browser/chromeos/cros/mock_library_loader.h"
#include "chrome/browser/chromeos/cros/mock_network_library.h"
#include "chrome/browser/chromeos/cros/mock_power_library.h"
+#include "chrome/browser/chromeos/cros/mock_screen_lock_library.h"
#include "chrome/browser/chromeos/cros/mock_synaptics_library.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/in_process_browser_test.h"
@@ -47,6 +48,7 @@ class LoginTestBase : public InProcessBrowserTest {
testApi_->SetSynapticsLibrary(&mock_synaptics_library_, false);
testApi_->SetCryptohomeLibrary(&mock_cryptohome_library_, false);
+ testApi_->SetScreenLockLibrary(&mock_screen_lock_library_, false);
}
protected:
@@ -55,6 +57,7 @@ class LoginTestBase : public InProcessBrowserTest {
NiceMock<MockLanguageLibrary> mock_language_library_;
NiceMock<MockNetworkLibrary> mock_network_library_;
NiceMock<MockPowerLibrary> mock_power_library_;
+ NiceMock<MockScreenLockLibrary> mock_screen_lock_library_;
NiceMock<MockSynapticsLibrary> mock_synaptics_library_;
ImePropertyList ime_properties_;
chromeos::CrosLibrary::TestApi* testApi_;
@@ -65,6 +68,8 @@ class LoginUserTest : public LoginTestBase {
LoginUserTest() {
EXPECT_CALL(mock_cryptohome_library_, IsMounted())
.WillRepeatedly(Return(true));
+ EXPECT_CALL(mock_screen_lock_library_, AddObserver(_))
+ .WillOnce(Return());
}
virtual void SetUpCommandLine(CommandLine* command_line) {
@@ -107,4 +112,3 @@ IN_PROC_BROWSER_TEST_F(LoginProfileTest, UserNotPassed) {
}
} // namespace chromeos
-
diff --git a/chrome/browser/chromeos/login/screen_locker.cc b/chrome/browser/chromeos/login/screen_locker.cc
index 23b4a76..507f0fe 100644
--- a/chrome/browser/chromeos/login/screen_locker.cc
+++ b/chrome/browser/chromeos/login/screen_locker.cc
@@ -18,6 +18,11 @@
#include "views/widget/widget_gtk.h"
namespace {
+// The maxium times that the screen locker should try to grab input,
+// and its interval. It has to be able to grab all inputs in 30 seconds,
+// otherwise chromium process fails and the session is terminated.
+const int64 kRetryGrabIntervalMs = 1000;
+const int kGrabFailureLimit = 30;
// Observer to start ScreenLocker when the screen lock
class ScreenLockObserver : public chromeos::ScreenLockLibrary::Observer,
@@ -69,7 +74,12 @@ ScreenLocker* ScreenLocker::screen_locker_ = NULL;
// TODO(oshima): catch grab-broke event and quit if it ever happenes.
class GrabWidget : public views::WidgetGtk {
public:
- GrabWidget() : views::WidgetGtk(views::WidgetGtk::TYPE_CHILD) {
+ GrabWidget()
+ : views::WidgetGtk(views::WidgetGtk::TYPE_CHILD),
+ ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
+ grab_failure_count_(0),
+ kbd_grab_status_(GDK_GRAB_INVALID_TIME),
+ mouse_grab_status_(GDK_GRAB_INVALID_TIME) {
}
virtual void Show() {
@@ -79,11 +89,34 @@ class GrabWidget : public views::WidgetGtk {
gtk_grab_remove(current_grab_window);
DoGrab();
- GdkGrabStatus kbd_status =
- gdk_keyboard_grab(window_contents()->window, FALSE,
- GDK_CURRENT_TIME);
- CHECK_EQ(GDK_GRAB_SUCCESS, kbd_status) << "Failed to grab keyboard input";
- GdkGrabStatus ptr_status =
+
+ // Now steal all inputs.
+ TryGrabAllInputs();
+ }
+
+ // Try to grab all inputs. It initiates another try if it fails to
+ // grab and the retry count is within a limit, or fails with CHECK.
+ void TryGrabAllInputs();
+
+ private:
+ ScopedRunnableMethodFactory<GrabWidget> task_factory_;
+
+ // The number times the widget tried to grab all focus.
+ int grab_failure_count_;
+ // Status of keyboard and mouse grab.
+ GdkGrabStatus kbd_grab_status_;
+ GdkGrabStatus mouse_grab_status_;
+
+ DISALLOW_COPY_AND_ASSIGN(GrabWidget);
+};
+
+
+void GrabWidget::TryGrabAllInputs() {
+ if (kbd_grab_status_ != GDK_GRAB_SUCCESS)
+ kbd_grab_status_ = gdk_keyboard_grab(window_contents()->window, FALSE,
+ GDK_CURRENT_TIME);
+ if (mouse_grab_status_ != GDK_GRAB_SUCCESS) {
+ mouse_grab_status_ =
gdk_pointer_grab(window_contents()->window,
FALSE,
static_cast<GdkEventMask>(
@@ -92,12 +125,23 @@ class GrabWidget : public views::WidgetGtk {
NULL,
NULL,
GDK_CURRENT_TIME);
- CHECK_EQ(GDK_GRAB_SUCCESS, ptr_status) << "Failed to grab pointer input";
}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(GrabWidget);
-};
+ if ((kbd_grab_status_ != GDK_GRAB_SUCCESS ||
+ kbd_grab_status_ != GDK_GRAB_SUCCESS) &&
+ grab_failure_count_++ < kGrabFailureLimit) {
+ DLOG(WARNING) << "Failed to grab inputs. Trying again in 1 second: kbd="
+ << kbd_grab_status_ << ", mouse=" << mouse_grab_status_;
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ task_factory_.NewRunnableMethod(&GrabWidget::TryGrabAllInputs),
+ kRetryGrabIntervalMs);
+ } else {
+ CHECK_EQ(GDK_GRAB_SUCCESS, kbd_grab_status_)
+ << "Failed to grab keyboard input:" << kbd_grab_status_;
+ CHECK_EQ(GDK_GRAB_SUCCESS, mouse_grab_status_)
+ << "Failed to grab pointer input:" << mouse_grab_status_;
+ }
+}
} // namespace
@@ -182,11 +226,16 @@ void ScreenLocker::EnableInput() {
// static
void ScreenLocker::Show() {
DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI);
- DCHECK(!screen_locker_);
- gfx::Rect bounds(views::Screen::GetMonitorWorkAreaNearestWindow(NULL));
- ScreenLocker* locker =
- new ScreenLocker(UserManager::Get()->logged_in_user());
- locker->Init(bounds);
+ // TODO(oshima): Currently, PowerManager may send a lock screen event
+ // even if a screen is locked. Investigate & solve the issue and
+ // enable this again if it's possible.
+ // DCHECK(!screen_locker_);
+ if (!screen_locker_) {
+ gfx::Rect bounds(views::Screen::GetMonitorWorkAreaNearestWindow(NULL));
+ ScreenLocker* locker =
+ new ScreenLocker(UserManager::Get()->logged_in_user());
+ locker->Init(bounds);
+ }
// TODO(oshima): Wait for a message from WM to complete the process.
if (CrosLibrary::Get()->EnsureLoaded())
CrosLibrary::Get()->GetScreenLockLibrary()->NotifyScreenLockCompleted();