OLD | NEW |
---|---|
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 'use strict'; | 5 'use strict'; |
6 | 6 |
7 /** | 7 /** |
8 * @fileoverview Utility objects and functions for Google Now extension. | 8 * @fileoverview Utility objects and functions for Google Now extension. |
9 * Most important entities here: | 9 * Most important entities here: |
10 * (1) 'wrapper' is a module used to add error handling and other services to | 10 * (1) 'wrapper' is a module used to add error handling and other services to |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
186 | 186 |
187 // Limiting 1 error report per background page load. | 187 // Limiting 1 error report per background page load. |
188 var errorReported = false; | 188 var errorReported = false; |
189 | 189 |
190 /** | 190 /** |
191 * Reports an error to the server and the user, as appropriate. | 191 * Reports an error to the server and the user, as appropriate. |
192 * @param {Error} error Error to report. | 192 * @param {Error} error Error to report. |
193 */ | 193 */ |
194 function reportError(error) { | 194 function reportError(error) { |
195 var message = 'Critical error:\n' + error.stack; | 195 var message = 'Critical error:\n' + error.stack; |
196 if (isInDebugMode()) | 196 if (isInDebugMode()) |
robliao
2014/05/05 17:24:30
This is a codesync artifact.
| |
197 console.error(message); | 197 console.error(message); |
198 | 198 |
199 if (!errorReported) { | 199 if (!errorReported) { |
200 errorReported = true; | 200 errorReported = true; |
201 chrome.metricsPrivate.getIsCrashReportingEnabled(function(isEnabled) { | 201 chrome.metricsPrivate.getIsCrashReportingEnabled(function(isEnabled) { |
202 if (isEnabled) | 202 if (isEnabled) |
203 sendErrorReport(error); | 203 sendErrorReport(error); |
204 if (isInDebugMode()) | 204 if (isInDebugMode()) |
205 alert(message); | 205 alert(message); |
206 }); | 206 }); |
(...skipping 665 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
872 * @param {function(boolean)} callback The function's boolean parameter is | 872 * @param {function(boolean)} callback The function's boolean parameter is |
873 * true if the attempt manager has started, false otherwise. | 873 * true if the attempt manager has started, false otherwise. |
874 */ | 874 */ |
875 function isRunning(callback) { | 875 function isRunning(callback) { |
876 instrumented.alarms.get(alarmName, function(alarmInfo) { | 876 instrumented.alarms.get(alarmName, function(alarmInfo) { |
877 callback(!!alarmInfo); | 877 callback(!!alarmInfo); |
878 }); | 878 }); |
879 } | 879 } |
880 | 880 |
881 /** | 881 /** |
882 * Schedules next attempt. | 882 * Schedules the alarm with a random factor to reduce the chance that all |
883 * @param {number=} opt_previousDelaySeconds Previous delay in a sequence of | 883 * clients will fire their timers at the same time. |
884 * retry attempts, if specified. Not specified for scheduling first retry | 884 * @param {number} durationSeconds Number of seconds before firing the alarm. |
885 * in the exponential sequence. | |
886 */ | 885 */ |
887 function scheduleNextAttempt(opt_previousDelaySeconds) { | 886 function scheduleAlarm(durationSeconds) { |
888 var base = opt_previousDelaySeconds ? opt_previousDelaySeconds * 2 : | 887 var randomizedRetryDuration = |
889 initialDelaySeconds; | 888 Math.min(durationSeconds * (1 + 0.2 * Math.random()), |
890 var newRetryDelaySeconds = | 889 maximumDelaySeconds); |
891 Math.min(base * (1 + 0.2 * Math.random()), maximumDelaySeconds); | |
892 | 890 |
893 createAlarm(newRetryDelaySeconds); | 891 createAlarm(randomizedRetryDuration); |
894 | 892 |
895 var items = {}; | 893 var items = {}; |
896 items[currentDelayStorageKey] = newRetryDelaySeconds; | 894 items[currentDelayStorageKey] = randomizedRetryDuration; |
897 chrome.storage.local.set(items); | 895 chrome.storage.local.set(items); |
898 } | 896 } |
899 | 897 |
900 /** | 898 /** |
901 * Starts repeated attempts. | 899 * Starts repeated attempts. |
902 * @param {number=} opt_firstDelaySeconds Time until the first attempt, if | 900 * @param {number=} opt_firstDelaySeconds Time until the first attempt, if |
903 * specified. Otherwise, initialDelaySeconds will be used for the first | 901 * specified. Otherwise, initialDelaySeconds will be used for the first |
904 * attempt. | 902 * attempt. |
905 */ | 903 */ |
906 function start(opt_firstDelaySeconds) { | 904 function start(opt_firstDelaySeconds) { |
907 if (opt_firstDelaySeconds) { | 905 if (opt_firstDelaySeconds) { |
908 createAlarm(opt_firstDelaySeconds); | 906 createAlarm(opt_firstDelaySeconds); |
909 chrome.storage.local.remove(currentDelayStorageKey); | 907 chrome.storage.local.remove(currentDelayStorageKey); |
910 } else { | 908 } else { |
911 scheduleNextAttempt(); | 909 scheduleAlarm(initialDelaySeconds); |
912 } | 910 } |
913 } | 911 } |
914 | 912 |
915 /** | 913 /** |
916 * Stops repeated attempts. | 914 * Stops repeated attempts. |
917 */ | 915 */ |
918 function stop() { | 916 function stop() { |
919 chrome.alarms.clear(alarmName); | 917 chrome.alarms.clear(alarmName); |
920 chrome.storage.local.remove(currentDelayStorageKey); | 918 chrome.storage.local.remove(currentDelayStorageKey); |
921 } | 919 } |
922 | 920 |
923 /** | 921 /** |
924 * Plans for the next attempt. | 922 * Schedules an exponential backoff retry. |
925 * @param {function()} callback Completion callback. It will be invoked after | 923 * @return {Promise} A promise to schedule the retry. |
926 * the planning is done. | |
927 */ | 924 */ |
928 function planForNext(callback) { | 925 function scheduleRetry() { |
929 var request = {}; | 926 var request = {}; |
930 request[currentDelayStorageKey] = undefined; | 927 request[currentDelayStorageKey] = undefined; |
931 fillFromChromeLocalStorage(request, PromiseRejection.ALLOW) | 928 return fillFromChromeLocalStorage(request, PromiseRejection.ALLOW) |
932 .catch(function() { | 929 .catch(function() { |
933 request[currentDelayStorageKey] = maximumDelaySeconds; | 930 request[currentDelayStorageKey] = maximumDelaySeconds; |
934 return Promise.resolve(request); | 931 return Promise.resolve(request); |
935 }).then(function(items) { | 932 }) |
936 console.log('planForNext-get-storage ' + JSON.stringify(items)); | 933 .then(function(items) { |
937 scheduleNextAttempt(items[currentDelayStorageKey]); | 934 console.log('scheduleRetry-get-storage ' + JSON.stringify(items)); |
938 callback(); | 935 var retrySeconds = initialDelaySeconds; |
936 if (items[currentDelayStorageKey]) { | |
937 retrySeconds = items[currentDelayStorageKey] * 2; | |
938 } | |
939 scheduleAlarm(retrySeconds); | |
939 }); | 940 }); |
940 } | 941 } |
941 | 942 |
942 instrumented.alarms.onAlarm.addListener(function(alarm) { | 943 instrumented.alarms.onAlarm.addListener(function(alarm) { |
943 if (alarm.name == alarmName) | 944 if (alarm.name == alarmName) |
944 isRunning(function(running) { | 945 isRunning(function(running) { |
945 if (running) | 946 if (running) |
946 attempt(); | 947 attempt(); |
947 }); | 948 }); |
948 }); | 949 }); |
949 | 950 |
950 return { | 951 return { |
951 start: start, | 952 start: start, |
952 planForNext: planForNext, | 953 scheduleRetry: scheduleRetry, |
953 stop: stop, | 954 stop: stop, |
954 isRunning: isRunning | 955 isRunning: isRunning |
955 }; | 956 }; |
956 } | 957 } |
957 | 958 |
958 // TODO(robliao): Use signed-in state change watch API when it's available. | 959 // TODO(robliao): Use signed-in state change watch API when it's available. |
959 /** | 960 /** |
960 * Wraps chrome.identity to provide limited listening support for | 961 * Wraps chrome.identity to provide limited listening support for |
961 * the sign in state by polling periodically for the auth token. | 962 * the sign in state by polling periodically for the auth token. |
962 * @return {Object} The Authentication Manager interface. | 963 * @return {Object} The Authentication Manager interface. |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1052 // One hour is just an arbitrary amount of time chosen. | 1053 // One hour is just an arbitrary amount of time chosen. |
1053 chrome.alarms.create(alarmName, {periodInMinutes: 60}); | 1054 chrome.alarms.create(alarmName, {periodInMinutes: 60}); |
1054 | 1055 |
1055 return { | 1056 return { |
1056 addListener: addListener, | 1057 addListener: addListener, |
1057 getAuthToken: getAuthToken, | 1058 getAuthToken: getAuthToken, |
1058 isSignedIn: isSignedIn, | 1059 isSignedIn: isSignedIn, |
1059 removeToken: removeToken | 1060 removeToken: removeToken |
1060 }; | 1061 }; |
1061 } | 1062 } |
OLD | NEW |