summaryrefslogtreecommitdiffstats
path: root/remoting
diff options
context:
space:
mode:
authorkelvinp <kelvinp@chromium.org>2015-05-26 17:54:01 -0700
committerCommit bot <commit-bot@chromium.org>2015-05-27 00:54:24 +0000
commit2a8128fc0c63c3e38ba25ddd82e09c586a8bd10d (patch)
tree91921ffad84f70b5ddbf7e84e2c17ef22a3caf8f /remoting
parentd879a2e3c4c65ae67a360784099f0690af523f72 (diff)
downloadchromium_src-2a8128fc0c63c3e38ba25ddd82e09c586a8bd10d.zip
chromium_src-2a8128fc0c63c3e38ba25ddd82e09c586a8bd10d.tar.gz
chromium_src-2a8128fc0c63c3e38ba25ddd82e09c586a8bd10d.tar.bz2
[AppRemoting] Drop the connection after resuming from a sleep > 30s.
Summary of changes: 1. Implements a resume detector by detecting differences in the time elapsed between ticks in setInterval(). 2. Drops the connection if the client with ERROR_CLIENT_SUSPENDED if the webapp resumes from a sleep longer than 30s. 3. A follow up CL will be done to update the error code on the directory service. BUG=486888 Review URL: https://codereview.chromium.org/1148993003 Cr-Commit-Position: refs/heads/master@{#331493}
Diffstat (limited to 'remoting')
-rw-r--r--remoting/remoting_webapp_files.gypi1
-rw-r--r--remoting/webapp/app_remoting/js/app_remoting_activity.js25
-rw-r--r--remoting/webapp/base/js/client_session.js28
-rw-r--r--remoting/webapp/base/js/error.js42
-rw-r--r--remoting/webapp/base/js/server_log_entry.js2
-rw-r--r--remoting/webapp/base/js/suspend_detector.js73
-rw-r--r--remoting/webapp/files.gni1
7 files changed, 145 insertions, 27 deletions
diff --git a/remoting/remoting_webapp_files.gypi b/remoting/remoting_webapp_files.gypi
index 565a260..1310232 100644
--- a/remoting/remoting_webapp_files.gypi
+++ b/remoting/remoting_webapp_files.gypi
@@ -179,6 +179,7 @@
'webapp/base/js/protocol_extension.js',
'webapp/base/js/error.js',
'webapp/base/js/plugin_settings.js',
+ 'webapp/base/js/suspend_detector.js',
'webapp/base/js/typecheck.js',
'webapp/base/js/xhr.js',
],
diff --git a/remoting/webapp/app_remoting/js/app_remoting_activity.js b/remoting/webapp/app_remoting/js/app_remoting_activity.js
index 2697bbbd..ff4fb98 100644
--- a/remoting/webapp/app_remoting/js/app_remoting_activity.js
+++ b/remoting/webapp/app_remoting/js/app_remoting_activity.js
@@ -31,9 +31,6 @@ remoting.AppHostResponse;
* @implements {remoting.Activity}
*/
remoting.AppRemotingActivity = function(appCapabilities) {
- /** @private {remoting.AppConnectedView} */
- this.connectedView_ = null;
-
/** @private */
this.sessionFactory_ = new remoting.ClientSessionFactory(
document.querySelector('#client-container .client-plugin-container'),
@@ -41,11 +38,13 @@ remoting.AppRemotingActivity = function(appCapabilities) {
/** @private {remoting.ClientSession} */
this.session_ = null;
+
+ /** @private {base.Disposables} */
+ this.connectedDisposables_ = null;
};
remoting.AppRemotingActivity.prototype.dispose = function() {
- base.dispose(this.connectedView_);
- this.connectedView_ = null;
+ this.cleanup_();
remoting.LoadingWindow.close();
};
@@ -67,8 +66,8 @@ remoting.AppRemotingActivity.prototype.stop = function() {
/** @private */
remoting.AppRemotingActivity.prototype.cleanup_ = function() {
- base.dispose(this.connectedView_);
- this.connectedView_ = null;
+ base.dispose(this.connectedDisposables_);
+ this.connectedDisposables_ = null;
base.dispose(this.session_);
this.session_ = null;
};
@@ -160,7 +159,7 @@ remoting.AppRemotingActivity.prototype.onAppHostResponse_ =
* @param {remoting.ConnectionInfo} connectionInfo
*/
remoting.AppRemotingActivity.prototype.onConnected = function(connectionInfo) {
- this.connectedView_ = new remoting.AppConnectedView(
+ var connectedView = new remoting.AppConnectedView(
document.getElementById('client-container'), connectionInfo);
var idleDetector = new remoting.IdleDetector(
@@ -171,6 +170,11 @@ remoting.AppRemotingActivity.prototype.onConnected = function(connectionInfo) {
if (remoting.platformIsMac()) {
connectionInfo.plugin().setRemapKeys('0x0700e3>0x0700e0,0x0700e7>0x0700e4');
}
+
+ // Drop the session after 30s of suspension as we cannot recover from a
+ // connectivity loss longer than 30s anyways.
+ this.session_.dropSessionOnSuspend(30 * 1000);
+ this.connectedDisposables_ = new base.Disposables(connectedView);
};
/**
@@ -195,6 +199,11 @@ remoting.AppRemotingActivity.prototype.onConnectionFailed = function(error) {
/** @private */
remoting.AppRemotingActivity.prototype.onConnectionDropped_ = function() {
+ // Don't dispose the session here to keep the plugin alive so that we can show
+ // the last frame of the remote application window.
+ base.dispose(this.connectedDisposables_);
+ this.connectedDisposables_ = null;
+
var rootElement = /** @type {HTMLDialogElement} */ (
document.getElementById('connection-dropped-dialog'));
diff --git a/remoting/webapp/base/js/client_session.js b/remoting/webapp/base/js/client_session.js
index ff4c737..4ed7264 100644
--- a/remoting/webapp/base/js/client_session.js
+++ b/remoting/webapp/base/js/client_session.js
@@ -329,6 +329,29 @@ remoting.ClientSession.prototype.getError = function() {
};
/**
+ * Drop the session when the computer is suspended for more than
+ * |suspendDurationInMS|.
+ *
+ * @param {number} suspendDurationInMS maximum duration of suspension allowed
+ * before the session will be dropped.
+ */
+remoting.ClientSession.prototype.dropSessionOnSuspend = function(
+ suspendDurationInMS) {
+ if (this.state_ !== remoting.ClientSession.State.CONNECTED) {
+ console.error('The session is not connected.');
+ return;
+ }
+
+ var suspendDetector = new remoting.SuspendDetector(suspendDurationInMS);
+ this.connectedDisposables_.add(
+ suspendDetector,
+ new base.EventHook(
+ suspendDetector, remoting.SuspendDetector.Events.resume,
+ this.disconnect.bind(
+ this, new remoting.Error(remoting.Error.Tag.CLIENT_SUSPENDED))));
+};
+
+/**
* Called when the client receives its first frame.
*
* @return {void} Nothing.
@@ -492,6 +515,11 @@ remoting.ClientSession.prototype.isFinished = function() {
* @private
*/
remoting.ClientSession.prototype.setState_ = function(newState) {
+ // If we are at a finished state, ignore further state changes.
+ if (this.isFinished()) {
+ return;
+ }
+
var oldState = this.state_;
this.state_ = this.translateState_(oldState, newState);
diff --git a/remoting/webapp/base/js/error.js b/remoting/webapp/base/js/error.js
index d1dbbe24..b33115f 100644
--- a/remoting/webapp/base/js/error.js
+++ b/remoting/webapp/base/js/error.js
@@ -99,26 +99,30 @@ remoting.Error.Tag = {
// not normally cause the error text to be shown to the user, so the
// i18n-content prefix is not needed in this case.
CANCELLED: '__CANCELLED__',
-
- INVALID_ACCESS_CODE: /*i18n-content*/'ERROR_INVALID_ACCESS_CODE',
- MISSING_PLUGIN: /*i18n-content*/'ERROR_MISSING_PLUGIN',
- AUTHENTICATION_FAILED: /*i18n-content*/'ERROR_AUTHENTICATION_FAILED',
- HOST_IS_OFFLINE: /*i18n-content*/'ERROR_HOST_IS_OFFLINE',
- INCOMPATIBLE_PROTOCOL: /*i18n-content*/'ERROR_INCOMPATIBLE_PROTOCOL',
- BAD_PLUGIN_VERSION: /*i18n-content*/'ERROR_BAD_PLUGIN_VERSION',
- NETWORK_FAILURE: /*i18n-content*/'ERROR_NETWORK_FAILURE',
- HOST_OVERLOAD: /*i18n-content*/'ERROR_HOST_OVERLOAD',
- UNEXPECTED: /*i18n-content*/'ERROR_UNEXPECTED',
- SERVICE_UNAVAILABLE: /*i18n-content*/'ERROR_SERVICE_UNAVAILABLE',
- NOT_AUTHENTICATED: /*i18n-content*/'ERROR_NOT_AUTHENTICATED',
- NOT_FOUND: /*i18n-content*/'ERROR_NOT_FOUND',
- INVALID_HOST_DOMAIN: /*i18n-content*/'ERROR_INVALID_HOST_DOMAIN',
- P2P_FAILURE: /*i18n-content*/'ERROR_P2P_FAILURE',
- REGISTRATION_FAILED: /*i18n-content*/'ERROR_HOST_REGISTRATION_FAILED',
- NOT_AUTHORIZED: /*i18n-content*/'ERROR_NOT_AUTHORIZED',
-
+ // Used to signify that the local computer was suspended for long enough that
+ // the connection is expected to drop, allowing a reconnect attempt to be
+ // scheduled sooner. This is not shownThis is not shown to the user so
+ // i18n-content prefix is not needed in this case.
+ CLIENT_SUSPENDED: '__CLIENT_SUSPENDED__',
+
+ INVALID_ACCESS_CODE: /*i18n-content*/ 'ERROR_INVALID_ACCESS_CODE',
+ MISSING_PLUGIN: /*i18n-content*/ 'ERROR_MISSING_PLUGIN',
+ AUTHENTICATION_FAILED: /*i18n-content*/ 'ERROR_AUTHENTICATION_FAILED',
+ HOST_IS_OFFLINE: /*i18n-content*/ 'ERROR_HOST_IS_OFFLINE',
+ INCOMPATIBLE_PROTOCOL: /*i18n-content*/ 'ERROR_INCOMPATIBLE_PROTOCOL',
+ BAD_PLUGIN_VERSION: /*i18n-content*/ 'ERROR_BAD_PLUGIN_VERSION',
+ NETWORK_FAILURE: /*i18n-content*/ 'ERROR_NETWORK_FAILURE',
+ HOST_OVERLOAD: /*i18n-content*/ 'ERROR_HOST_OVERLOAD',
+ UNEXPECTED: /*i18n-content*/ 'ERROR_UNEXPECTED',
+ SERVICE_UNAVAILABLE: /*i18n-content*/ 'ERROR_SERVICE_UNAVAILABLE',
+ NOT_AUTHENTICATED: /*i18n-content*/ 'ERROR_NOT_AUTHENTICATED',
+ NOT_FOUND: /*i18n-content*/ 'ERROR_NOT_FOUND',
+ INVALID_HOST_DOMAIN: /*i18n-content*/ 'ERROR_INVALID_HOST_DOMAIN',
+ P2P_FAILURE: /*i18n-content*/ 'ERROR_P2P_FAILURE',
+ REGISTRATION_FAILED: /*i18n-content*/ 'ERROR_HOST_REGISTRATION_FAILED',
+ NOT_AUTHORIZED: /*i18n-content*/ 'ERROR_NOT_AUTHORIZED',
// TODO(garykac): Move app-specific errors into separate location.
- APP_NOT_AUTHORIZED: /*i18n-content*/'ERROR_APP_NOT_AUTHORIZED'
+ APP_NOT_AUTHORIZED: /*i18n-content*/ 'ERROR_APP_NOT_AUTHORIZED'
};
// A whole bunch of semi-redundant constants, mostly to reduce to size
diff --git a/remoting/webapp/base/js/server_log_entry.js b/remoting/webapp/base/js/server_log_entry.js
index ec771a8..50bb11a 100644
--- a/remoting/webapp/base/js/server_log_entry.js
+++ b/remoting/webapp/base/js/server_log_entry.js
@@ -112,6 +112,8 @@ remoting.ServerLogEntry.getValueForError_ = function(connectionError) {
return 'host-overload';
case remoting.Error.Tag.P2P_FAILURE:
return 'p2p-failure';
+ case remoting.Error.Tag.CLIENT_SUSPENDED:
+ return 'client-suspended';
case remoting.Error.Tag.UNEXPECTED:
return 'unexpected';
default:
diff --git a/remoting/webapp/base/js/suspend_detector.js b/remoting/webapp/base/js/suspend_detector.js
new file mode 100644
index 0000000..241da49
--- /dev/null
+++ b/remoting/webapp/base/js/suspend_detector.js
@@ -0,0 +1,73 @@
+// Copyright 2015 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.
+
+/** @suppress {duplicate} */
+var remoting = remoting || {};
+
+(function () {
+
+'use strict';
+
+var INTERVAL_IN_MS = 500;
+
+var TIMER_INACCURACY_IN_MS = 10;
+
+/**
+ * @constructor
+ * @param {number=} opt_maxSuspendInMs The maximum permitted suspend duration
+ * to raise the resume event.
+ * @extends {base.EventSourceImpl}
+ * @implements {base.Disposable}
+ */
+remoting.SuspendDetector = function(opt_maxSuspendInMs) {
+ base.inherits(this, base.EventSourceImpl);
+ this.defineEvents(base.values(remoting.SuspendDetector.Events));
+
+ if (!Number.isInteger(opt_maxSuspendInMs)) {
+ opt_maxSuspendInMs = TIMER_INACCURACY_IN_MS;
+ }
+
+ /** @private */
+ this.maxSuspendInMs_ = Math.max(opt_maxSuspendInMs, TIMER_INACCURACY_IN_MS);
+
+ /**
+ * JavaScript timer is paused while the computer is suspended, we need to use
+ * a higher resolution timer instead of |this.maxSuspendInMs_| to ensure the
+ * resume event fires promptly after the system wakes up from sleep.
+ * @private
+ */
+ this.timer_ =
+ new base.RepeatingTimer(this.onTick_.bind(this), INTERVAL_IN_MS);
+
+ /** @private */
+ this.lastTick_ = new Date();
+};
+
+remoting.SuspendDetector.prototype.dispose = function() {
+ base.dispose(this.timer_);
+ this.timer = null;
+};
+
+/** @private */
+remoting.SuspendDetector.prototype.onTick_ = function() {
+ var now = new Date();
+ // If the computer has just resumed from sleep, the sleep duration will
+ // roughly equal the |delta| between the ticks.
+ var delta = now - this.lastTick_;
+ this.lastTick_ = now;
+ if (delta > this.maxSuspendInMs_) {
+ this.raiseEvent(remoting.SuspendDetector.Events.resume, delta);
+ }
+};
+
+})();
+
+/** @enum {string} */
+remoting.SuspendDetector.Events = {
+ // Fired when the computer resumes up from sleep with the approximate sleep
+ // duration in milliseconds. The sleep duration is only an approximation with
+ // and an uncertainty of |INTERVAL_IN_MS|.
+ // {number} sleepDuration
+ resume: 'resume'
+};
diff --git a/remoting/webapp/files.gni b/remoting/webapp/files.gni
index dde5fa6..48b61da 100644
--- a/remoting/webapp/files.gni
+++ b/remoting/webapp/files.gni
@@ -174,6 +174,7 @@ remoting_webapp_shared_js_core_files = [
"base/js/protocol_extension.js",
"base/js/error.js",
"base/js/plugin_settings.js",
+ "base/js/suspend_detector.js",
"base/js/typecheck.js",
"base/js/xhr.js",
]