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 // TODO(vadimt): Remove alerts. | 7 // TODO(vadimt): Remove alerts. |
8 | 8 |
9 /** | 9 /** |
10 * @fileoverview Utility objects and functions for Google Now extension. | 10 * @fileoverview Utility objects and functions for Google Now extension. |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
75 */ | 75 */ |
76 var pendingCallbacks = {}; | 76 var pendingCallbacks = {}; |
77 | 77 |
78 /** | 78 /** |
79 * True if currently executed code is a part of a task. | 79 * True if currently executed code is a part of a task. |
80 * @type {boolean} | 80 * @type {boolean} |
81 */ | 81 */ |
82 var isInTask = false; | 82 var isInTask = false; |
83 | 83 |
84 /** | 84 /** |
85 * True if currently executed code runs in an instrumented callback. | |
86 * @type {boolean} | |
87 */ | |
88 var isInInstrumentedCallback = false; | |
89 | |
90 /** | |
91 * Checks that we run in an instrumented callback. | |
92 */ | |
93 function checkInstrumentedCallback() { | |
rgustafson
2013/08/02 18:43:38
checkInInstrumentedCallback
vadimt
2013/08/02 19:19:25
Done.
| |
94 if (!isInInstrumentedCallback) { | |
95 // Cannot use verify() since no one will catch the exception. | |
96 // This alert will detect bugs at the development stage, and is very | |
97 // unlikely to be seen by users. | |
98 var error = 'Not in instrumented callback: ' + new Error().stack; | |
99 console.error(error); | |
100 alert(error); | |
rgustafson
2013/08/02 18:43:38
This alert is included in the file wide "remove al
| |
101 } | |
102 } | |
103 | |
104 /** | |
85 * Starts the first queued task. | 105 * Starts the first queued task. |
86 */ | 106 */ |
87 function startFirst() { | 107 function startFirst() { |
88 verify(queue.length >= 1, 'startFirst: queue is empty'); | 108 verify(queue.length >= 1, 'startFirst: queue is empty'); |
89 verify(!isInTask, 'startFirst: already in task'); | 109 verify(!isInTask, 'startFirst: already in task'); |
90 isInTask = true; | 110 isInTask = true; |
91 | 111 |
92 // Start the oldest queued task, but don't remove it from the queue. | 112 // Start the oldest queued task, but don't remove it from the queue. |
93 verify( | 113 verify( |
94 taskPendingCallbackCount == 0, | 114 taskPendingCallbackCount == 0, |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
126 | 146 |
127 /** | 147 /** |
128 * Adds a new task. If another task is not running, runs the task immediately. | 148 * Adds a new task. If another task is not running, runs the task immediately. |
129 * If any task in the queue is not compatible with the task, ignores the new | 149 * If any task in the queue is not compatible with the task, ignores the new |
130 * task. Otherwise, stores the task for future execution. | 150 * task. Otherwise, stores the task for future execution. |
131 * @param {string} taskName Name of the task. | 151 * @param {string} taskName Name of the task. |
132 * @param {function(function())} task Function to run. Takes a callback | 152 * @param {function(function())} task Function to run. Takes a callback |
133 * parameter. Call this callback on completion. | 153 * parameter. Call this callback on completion. |
134 */ | 154 */ |
135 function add(taskName, task) { | 155 function add(taskName, task) { |
156 checkInstrumentedCallback(); | |
136 console.log('Adding task ' + taskName); | 157 console.log('Adding task ' + taskName); |
137 if (!canQueue(taskName)) | 158 if (!canQueue(taskName)) |
138 return; | 159 return; |
139 | 160 |
140 queue.push({name: taskName, task: task}); | 161 queue.push({name: taskName, task: task}); |
141 | 162 |
142 if (queue.length == 1) { | 163 if (queue.length == 1) { |
143 startFirst(); | 164 startFirst(); |
144 } | 165 } |
145 } | 166 } |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
200 | 221 |
201 /** | 222 /** |
202 * Unique ID of the next callback. | 223 * Unique ID of the next callback. |
203 * @type {number} | 224 * @type {number} |
204 */ | 225 */ |
205 var nextCallbackId = 0; | 226 var nextCallbackId = 0; |
206 | 227 |
207 /** | 228 /** |
208 * Adds error processing to an API callback. | 229 * Adds error processing to an API callback. |
209 * @param {Function} callback Callback to instrument. | 230 * @param {Function} callback Callback to instrument. |
210 * @param {boolean=} opt_dontRequire True if the callback is not required to | 231 * @param {boolean=} opt_isEventListener True if the callback is an event |
211 * be invoked. | 232 * listener. |
212 * @return {Function} Instrumented callback. | 233 * @return {Function} Instrumented callback. |
213 */ | 234 */ |
214 function wrapCallback(callback, opt_dontRequire) { | 235 function wrapCallback(callback, opt_isEventListener) { |
215 verify(!(opt_dontRequire && isInTask), 'Unrequired callback in a task.'); | 236 verify(!(opt_isEventListener && isInTask), |
237 'Unrequired callback in a task.'); | |
216 var callbackId = nextCallbackId++; | 238 var callbackId = nextCallbackId++; |
217 var isTaskCallback = isInTask; | 239 var isTaskCallback = isInTask; |
218 if (isTaskCallback) | 240 if (isTaskCallback) |
219 ++taskPendingCallbackCount; | 241 ++taskPendingCallbackCount; |
220 if (!opt_dontRequire) | 242 if (!opt_isEventListener) { |
243 checkInstrumentedCallback(); | |
221 pendingCallbacks[callbackId] = new Error().stack; | 244 pendingCallbacks[callbackId] = new Error().stack; |
245 } | |
222 | 246 |
223 return function() { | 247 return function() { |
224 // This is the wrapper for the callback. | 248 // This is the wrapper for the callback. |
225 try { | 249 try { |
226 if (isTaskCallback) { | 250 if (isTaskCallback) { |
227 verify(!isInTask, 'wrapCallback: already in task'); | 251 verify(!isInTask, 'wrapCallback: already in task'); |
228 isInTask = true; | 252 isInTask = true; |
229 } | 253 } |
230 if (!opt_dontRequire) | 254 if (!opt_isEventListener) |
231 delete pendingCallbacks[callbackId]; | 255 delete pendingCallbacks[callbackId]; |
232 | 256 |
233 // Call the original callback. | 257 // Call the original callback. |
258 verify(!isInInstrumentedCallback, 'Re-entering instrumented callback'); | |
259 isInInstrumentedCallback = true; | |
234 callback.apply(null, arguments); | 260 callback.apply(null, arguments); |
261 verify(isInInstrumentedCallback, | |
262 'Instrumented callback in not instrumented upon exit'); | |
rgustafson
2013/08/02 18:43:38
in -> is
vadimt
2013/08/02 19:19:25
Done.
| |
263 isInInstrumentedCallback = false; | |
235 | 264 |
236 if (isTaskCallback) { | 265 if (isTaskCallback) { |
237 verify(isInTask, 'wrapCallback: not in task at exit'); | 266 verify(isInTask, 'wrapCallback: not in task at exit'); |
238 isInTask = false; | 267 isInTask = false; |
239 if (--taskPendingCallbackCount == 0) | 268 if (--taskPendingCallbackCount == 0) |
240 finish(); | 269 finish(); |
241 } | 270 } |
242 } catch (error) { | 271 } catch (error) { |
243 var message = 'Uncaught exception:\n' + error.stack; | 272 var message = 'Uncaught exception:\n' + error.stack; |
244 console.error(message); | 273 console.error(message); |
(...skipping 30 matching lines...) Expand all Loading... | |
275 if (typeof callback != 'function') { | 304 if (typeof callback != 'function') { |
276 alert('Argument ' + callbackParameter + ' of ' + functionName + | 305 alert('Argument ' + callbackParameter + ' of ' + functionName + |
277 ' is not a function'); | 306 ' is not a function'); |
278 } | 307 } |
279 arguments[callbackParameter] = wrapCallback( | 308 arguments[callbackParameter] = wrapCallback( |
280 callback, functionName == 'addListener'); | 309 callback, functionName == 'addListener'); |
281 return originalFunction.apply(namespace, arguments); | 310 return originalFunction.apply(namespace, arguments); |
282 }; | 311 }; |
283 } | 312 } |
284 | 313 |
314 instrumentApiFunction(chrome.alarms, 'get', 1); | |
285 instrumentApiFunction(chrome.alarms.onAlarm, 'addListener', 0); | 315 instrumentApiFunction(chrome.alarms.onAlarm, 'addListener', 0); |
316 instrumentApiFunction(chrome.identity, 'getAuthToken', 1); | |
286 instrumentApiFunction(chrome.runtime.onSuspend, 'addListener', 0); | 317 instrumentApiFunction(chrome.runtime.onSuspend, 'addListener', 0); |
287 | 318 |
288 chrome.runtime.onSuspend.addListener(function() { | 319 chrome.runtime.onSuspend.addListener(function() { |
289 var stringifiedPendingCallbacks = JSON.stringify(pendingCallbacks); | 320 var stringifiedPendingCallbacks = JSON.stringify(pendingCallbacks); |
290 verify( | 321 verify( |
291 queue.length == 0 && stringifiedPendingCallbacks == '{}', | 322 queue.length == 0 && stringifiedPendingCallbacks == '{}', |
292 'Incomplete task or pending callbacks when unloading event page,' + | 323 'Incomplete task or pending callbacks when unloading event page,' + |
293 ' queue = ' + JSON.stringify(queue) + | 324 ' queue = ' + JSON.stringify(queue) + |
294 ', pendingCallbacks = ' + stringifiedPendingCallbacks); | 325 ', pendingCallbacks = ' + stringifiedPendingCallbacks); |
295 }); | 326 }); |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
487 // Poll for the sign in state every hour. | 518 // Poll for the sign in state every hour. |
488 // One hour is just an arbitrary amount of time chosen. | 519 // One hour is just an arbitrary amount of time chosen. |
489 chrome.alarms.create(alarmName, {periodInMinutes: 60}); | 520 chrome.alarms.create(alarmName, {periodInMinutes: 60}); |
490 | 521 |
491 return { | 522 return { |
492 addListener: addListener, | 523 addListener: addListener, |
493 isSignedIn: isSignedIn, | 524 isSignedIn: isSignedIn, |
494 removeToken: removeToken | 525 removeToken: removeToken |
495 }; | 526 }; |
496 } | 527 } |
OLD | NEW |