Chromium Code Reviews| 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 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 212 * to the original callback provided by the extension. | 212 * to the original callback provided by the extension. |
| 213 * | 213 * |
| 214 * @typedef {{ | 214 * @typedef {{ |
| 215 * prologue: function (), | 215 * prologue: function (), |
| 216 * epilogue: function () | 216 * epilogue: function () |
| 217 * }} | 217 * }} |
| 218 */ | 218 */ |
| 219 var WrapperPlugin; | 219 var WrapperPlugin; |
| 220 | 220 |
| 221 /** | 221 /** |
| 222 * Promise Metadata. Holds fields that are used in identifying a promise during | |
| 223 * task processing. | |
| 224 * | |
| 225 * @typedef {{ | |
| 226 * id: number, | |
| 227 * isCatch: boolean | |
| 228 * }} | |
| 229 */ | |
| 230 var PromiseMetadata; | |
| 231 | |
| 232 /** | |
| 222 * Wrapper for callbacks. Used to add error handling and other services to | 233 * Wrapper for callbacks. Used to add error handling and other services to |
| 223 * callbacks for HTML and Chrome functions and events. | 234 * callbacks for HTML and Chrome functions and events. |
| 224 */ | 235 */ |
| 225 var wrapper = (function() { | 236 var wrapper = (function() { |
| 226 /** | 237 /** |
| 227 * Factory for wrapper plugins. If specified, it's used to generate an | 238 * Factory for wrapper plugins. If specified, it's used to generate an |
| 228 * instance of WrapperPlugin each time we wrap a callback (which corresponds | 239 * instance of WrapperPlugin each time we wrap a callback (which corresponds |
| 229 * to addListener call for Chrome events, and to every API call that specifies | 240 * to addListener call for Chrome events, and to every API call that specifies |
| 230 * a callback). WrapperPlugin's lifetime ends when the callback for which it | 241 * a callback). WrapperPlugin's lifetime ends when the callback for which it |
| 231 * was generated, exits. It's possible to have several instances of | 242 * was generated, exits. It's possible to have several instances of |
| 232 * WrapperPlugin at the same time. | 243 * WrapperPlugin at the same time. |
| 233 * An instance of WrapperPlugin can have state that can be shared by its | 244 * An instance of WrapperPlugin can have state that can be shared by its |
| 234 * constructor, prologue() and epilogue(). Also WrapperPlugins can change | 245 * constructor, prologue() and epilogue(). Also WrapperPlugins can change |
| 235 * state of other objects, for example, to do refcounting. | 246 * state of other objects, for example, to do refcounting. |
| 236 * @type {?function(): WrapperPlugin} | 247 * @type {?function(PromiseMetadata): WrapperPlugin} |
| 237 */ | 248 */ |
| 238 var wrapperPluginFactory = null; | 249 var wrapperPluginFactory = null; |
| 239 | 250 |
| 240 /** | 251 /** |
| 241 * Registers a wrapper plugin factory. | 252 * Registers a wrapper plugin factory. |
| 242 * @param {function(): WrapperPlugin} factory Wrapper plugin factory. | 253 * @param {function(PromiseMetadata): WrapperPlugin} factory |
| 254 * Wrapper plugin factory. | |
| 243 */ | 255 */ |
| 244 function registerWrapperPluginFactory(factory) { | 256 function registerWrapperPluginFactory(factory) { |
| 245 if (wrapperPluginFactory) { | 257 if (wrapperPluginFactory) { |
| 246 reportError(buildErrorWithMessageForServer( | 258 reportError(buildErrorWithMessageForServer( |
| 247 'registerWrapperPluginFactory: factory is already registered.')); | 259 'registerWrapperPluginFactory: factory is already registered.')); |
| 248 } | 260 } |
| 249 | 261 |
| 250 wrapperPluginFactory = factory; | 262 wrapperPluginFactory = factory; |
| 251 } | 263 } |
| 252 | 264 |
| 253 /** | 265 /** |
| 254 * True if currently executed code runs in a callback or event handler that | 266 * True if currently executed code runs in a callback or event handler that |
| 255 * was instrumented by wrapper.wrapCallback() call. | 267 * was instrumented by wrapper.wrapCallback() call. |
| 256 * @type {boolean} | 268 * @type {boolean} |
| 257 */ | 269 */ |
| 258 var isInWrappedCallback = false; | 270 var isInWrappedCallback = false; |
| 259 | 271 |
| 260 /** | 272 /** |
| 261 * Required callbacks that are not yet called. Includes both task and non-task | 273 * Required callbacks that are not yet called. Includes both task and non-task |
| 262 * callbacks. This is a map from unique callback id to the stack at the moment | 274 * callbacks. This is a map from unique callback id to the stack at the moment |
| 263 * when the callback was wrapped. This stack identifies the callback. | 275 * when the callback was wrapped. This stack identifies the callback. |
| 264 * Used only for diagnostics. | 276 * Used only for diagnostics. |
| 265 * @type {Object.<number, string>} | 277 * @type {Object.<number, string>} |
| 266 */ | 278 */ |
| 267 var pendingCallbacks = {}; | 279 var pendingCallbacks = {}; |
| 268 | 280 |
| 269 /** | 281 /** |
| 282 * A map of promise IDs to an array of "then" callback IDs. | |
| 283 * @type {Object.<number, array.<number>>} | |
| 284 */ | |
| 285 var pendingThenCallbacks = {}; | |
| 286 | |
| 287 /** | |
| 288 * A map of promise IDs to an array of "catch" callback IDs. | |
| 289 * @type {Object.<number, array.<number>>} | |
| 290 */ | |
| 291 var pendingCatchCallbacks = {}; | |
| 292 | |
| 293 /** | |
| 270 * Unique ID of the next callback. | 294 * Unique ID of the next callback. |
| 271 * @type {number} | 295 * @type {number} |
| 272 */ | 296 */ |
| 273 var nextCallbackId = 0; | 297 var nextCallbackId = 0; |
| 274 | 298 |
| 275 /** | 299 /** |
| 276 * Gets diagnostic string with the status of the wrapper. | 300 * Gets diagnostic string with the status of the wrapper. |
| 277 * @return {string} Diagnostic string. | 301 * @return {string} Diagnostic string. |
| 278 */ | 302 */ |
| 279 function debugGetStateString() { | 303 function debugGetStateString() { |
| 280 return 'pendingCallbacks @' + Date.now() + ' = ' + | 304 return 'pendingCallbacks @' + Date.now() + ' = ' + |
| 281 JSON.stringify(pendingCallbacks); | 305 JSON.stringify(pendingCallbacks); |
| 282 } | 306 } |
| 283 | 307 |
| 284 /** | 308 /** |
| 285 * Checks that we run in a wrapped callback. | 309 * Checks that we run in a wrapped callback. |
| 286 */ | 310 */ |
| 287 function checkInWrappedCallback() { | 311 function checkInWrappedCallback() { |
| 288 if (!isInWrappedCallback) { | 312 if (!isInWrappedCallback) { |
| 289 reportError(buildErrorWithMessageForServer( | 313 reportError(buildErrorWithMessageForServer( |
| 290 'Not in instrumented callback')); | 314 'Not in instrumented callback')); |
| 291 } | 315 } |
| 292 } | 316 } |
| 293 | 317 |
| 294 /** | 318 /** |
| 295 * Adds error processing to an API callback. | 319 * Adds error processing to an API callback. |
| 296 * @param {Function} callback Callback to instrument. | 320 * @param {Function} callback Callback to instrument. |
| 297 * @param {boolean=} opt_isEventListener True if the callback is a listener to | 321 * @param {boolean=} opt_isEventListener True if the callback is a listener to |
| 298 * a Chrome API event. | 322 * a Chrome API event. |
| 323 * @param {PromiseMetadata=} opt_promiseMetadata Set if wrapped from a | |
| 324 * promise. | |
| 299 * @return {Function} Instrumented callback. | 325 * @return {Function} Instrumented callback. |
| 300 */ | 326 */ |
| 301 function wrapCallback(callback, opt_isEventListener) { | 327 function wrapCallback(callback, opt_isEventListener, opt_promiseMetadata) { |
| 302 var callbackId = nextCallbackId++; | 328 var callbackId = nextCallbackId++; |
| 303 | 329 |
| 304 if (!opt_isEventListener) { | 330 if (!opt_isEventListener) { |
| 305 checkInWrappedCallback(); | 331 checkInWrappedCallback(); |
| 306 pendingCallbacks[callbackId] = new Error().stack + ' @' + Date.now(); | 332 pendingCallbacks[callbackId] = new Error().stack + ' @' + Date.now(); |
| 333 if (opt_promiseMetadata) { | |
| 334 var callbackIdMap = opt_promiseMetadata.isCatch ? | |
| 335 pendingCatchCallbacks : | |
| 336 pendingThenCallbacks; | |
| 337 callbackIdMap[opt_promiseMetadata.id] = | |
| 338 callbackIdMap[opt_promiseMetadata.id] || []; | |
| 339 callbackIdMap[opt_promiseMetadata.id].push(callbackId); | |
| 340 } | |
| 307 } | 341 } |
| 308 | |
| 309 // wrapperPluginFactory may be null before task manager is built, and in | 342 // wrapperPluginFactory may be null before task manager is built, and in |
| 310 // tests. | 343 // tests. |
| 311 var wrapperPluginInstance = wrapperPluginFactory && wrapperPluginFactory(); | 344 var wrapperPluginInstance = |
| 345 wrapperPluginFactory && wrapperPluginFactory(opt_promiseMetadata); | |
| 312 | 346 |
| 313 return function() { | 347 return function() { |
| 314 // This is the wrapper for the callback. | 348 // This is the wrapper for the callback. |
| 315 try { | 349 try { |
| 316 verify(!isInWrappedCallback, 'Re-entering instrumented callback'); | 350 verify(!isInWrappedCallback, 'Re-entering instrumented callback'); |
| 317 isInWrappedCallback = true; | 351 isInWrappedCallback = true; |
| 318 | 352 |
| 319 if (!opt_isEventListener) | 353 if (!opt_isEventListener) { |
| 320 delete pendingCallbacks[callbackId]; | 354 delete pendingCallbacks[callbackId]; |
| 355 if (opt_promiseMetadata) { | |
| 356 var callbackIdsToRemove = opt_promiseMetadata.isCatch ? | |
| 357 pendingThenCallbacks[opt_promiseMetadata.id] : | |
| 358 pendingCatchCallbacks[opt_promiseMetadata.id]; | |
| 359 if (callbackIdsToRemove !== undefined) { | |
| 360 callbackIdsToRemove.forEach(function(idToRemove) { | |
| 361 delete pendingCallbacks[idToRemove]; | |
| 362 }); | |
| 363 } | |
| 364 } | |
| 365 } | |
| 321 | 366 |
| 322 if (wrapperPluginInstance) | 367 if (wrapperPluginInstance) |
| 323 wrapperPluginInstance.prologue(); | 368 wrapperPluginInstance.prologue(); |
| 324 | 369 |
| 325 // Call the original callback. | 370 // Call the original callback. |
| 326 callback.apply(null, arguments); | 371 callback.apply(null, arguments); |
| 327 | 372 |
| 328 if (wrapperPluginInstance) | 373 if (wrapperPluginInstance) |
| 329 wrapperPluginInstance.epilogue(); | 374 wrapperPluginInstance.epilogue(); |
| 330 | 375 |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 430 })(); | 475 })(); |
| 431 | 476 |
| 432 wrapper.instrumentChromeApiFunction('alarms.get', 1); | 477 wrapper.instrumentChromeApiFunction('alarms.get', 1); |
| 433 wrapper.instrumentChromeApiFunction('alarms.onAlarm.addListener', 0); | 478 wrapper.instrumentChromeApiFunction('alarms.onAlarm.addListener', 0); |
| 434 wrapper.instrumentChromeApiFunction('identity.getAuthToken', 1); | 479 wrapper.instrumentChromeApiFunction('identity.getAuthToken', 1); |
| 435 wrapper.instrumentChromeApiFunction('identity.onSignInChanged.addListener', 0); | 480 wrapper.instrumentChromeApiFunction('identity.onSignInChanged.addListener', 0); |
| 436 wrapper.instrumentChromeApiFunction('identity.removeCachedAuthToken', 1); | 481 wrapper.instrumentChromeApiFunction('identity.removeCachedAuthToken', 1); |
| 437 wrapper.instrumentChromeApiFunction('webstorePrivate.getBrowserLogin', 0); | 482 wrapper.instrumentChromeApiFunction('webstorePrivate.getBrowserLogin', 0); |
| 438 | 483 |
| 439 /** | 484 /** |
| 485 * Unique ID of the next promise. | |
| 486 * @type {number} | |
| 487 */ | |
| 488 var nextPromiseId = 0; | |
| 489 | |
| 490 /** | |
| 440 * Add task tracking support to Promise.then. | 491 * Add task tracking support to Promise.then. |
| 441 * @override | 492 * @override |
| 442 */ | 493 */ |
| 443 Promise.prototype.then = function() { | 494 Promise.prototype.then = function() { |
| 444 var originalThen = Promise.prototype.then; | 495 var originalThen = Promise.prototype.then; |
| 445 return function(callback) { | 496 return function(callback) { |
| 446 return originalThen.call(this, wrapper.wrapCallback(callback, false)); | 497 var promiseId = this.__promiseId; |
| 498 if (promiseId === undefined) { | |
| 499 promiseId = nextPromiseId; | |
| 500 nextPromiseId++; | |
| 501 } | |
| 502 // "then" may return a new promise, getting rid of the ID! | |
| 503 // Set it before and after the call to keep the value. | |
| 504 this.__promiseId = promiseId; | |
|
rgustafson
2014/02/24 21:55:12
Still kinda confused in general by setting the sam
robliao
2014/02/24 22:31:13
You're right in the general case (and we'll need t
robliao
2014/02/24 23:11:56
Added a comment about this limitation.
On 2014/02/
| |
| 505 var promise = originalThen.call( | |
| 506 this, wrapper.wrapCallback(callback, false, | |
| 507 {id: this.__promiseId, isCatch: false})); | |
| 508 promise.__promiseId = promiseId; | |
| 509 return promise; | |
| 447 } | 510 } |
| 448 }(); | 511 }(); |
| 449 | 512 |
| 450 /** | 513 /** |
| 451 * Add task tracking support to Promise.catch. | 514 * Add task tracking support to Promise.catch. |
| 452 * @override | 515 * @override |
| 453 */ | 516 */ |
| 454 Promise.prototype.catch = function() { | 517 Promise.prototype.catch = function() { |
| 455 var originalCatch = Promise.prototype.catch; | 518 var originalCatch = Promise.prototype.catch; |
| 456 return function(callback) { | 519 return function(callback) { |
| 457 return originalCatch.call(this, wrapper.wrapCallback(callback, false)); | 520 var promiseId = this.__promiseId; |
| 521 if (promiseId === undefined) { | |
| 522 promiseId = nextPromiseId; | |
| 523 nextPromiseId++; | |
| 524 } | |
| 525 // "catch" may return a new promise, getting rid of the ID! | |
| 526 // Set it before and after the call to keep the value. | |
| 527 this.__promiseId = promiseId; | |
| 528 var promise = originalCatch.call( | |
| 529 this, wrapper.wrapCallback(callback, false, | |
| 530 {id: this.__promiseId, isCatch: true})); | |
| 531 promise.__promiseId = promiseId; | |
| 532 return promise; | |
| 458 } | 533 } |
| 459 }(); | 534 }(); |
| 460 | 535 |
| 461 /** | 536 /** |
| 537 * Promise Pending Callback Data. Counts outstanding "then" and "catch" | |
| 538 * callbacks; | |
| 539 * | |
| 540 * @typedef {{ | |
| 541 * thenCount: number, | |
| 542 * catchCount: number | |
| 543 * }} | |
| 544 */ | |
| 545 var PromisePendingCallbackData; | |
| 546 | |
| 547 /** | |
| 462 * Builds the object to manage tasks (mutually exclusive chains of events). | 548 * Builds the object to manage tasks (mutually exclusive chains of events). |
| 463 * @param {function(string, string): boolean} areConflicting Function that | 549 * @param {function(string, string): boolean} areConflicting Function that |
| 464 * checks if a new task can't be added to a task queue that contains an | 550 * checks if a new task can't be added to a task queue that contains an |
| 465 * existing task. | 551 * existing task. |
| 466 * @return {Object} Task manager interface. | 552 * @return {Object} Task manager interface. |
| 467 */ | 553 */ |
| 468 function buildTaskManager(areConflicting) { | 554 function buildTaskManager(areConflicting) { |
| 469 /** | 555 /** |
| 470 * Queue of scheduled tasks. The first element, if present, corresponds to the | 556 * Queue of scheduled tasks. The first element, if present, corresponds to the |
| 471 * currently running task. | 557 * currently running task. |
| 472 * @type {Array.<Object.<string, function()>>} | 558 * @type {Array.<Object.<string, function()>>} |
| 473 */ | 559 */ |
| 474 var queue = []; | 560 var queue = []; |
| 475 | 561 |
| 476 /** | 562 /** |
| 477 * Count of unfinished callbacks of the current task. | 563 * Count of unfinished callbacks of the current task. |
| 478 * @type {number} | 564 * @type {number} |
| 479 */ | 565 */ |
| 480 var taskPendingCallbackCount = 0; | 566 var taskPendingCallbackCount = 0; |
| 481 | 567 |
| 482 /** | 568 /** |
| 569 * Map of Promise ID to PromisePendingCallbackData to count the number of | |
| 570 * outstanding "then" and "catch" callbacks. | |
| 571 * @type {object.<number, PromisePendingCallbackData>} | |
| 572 */ | |
| 573 var taskPromisePendingCallbackData = {}; | |
| 574 | |
| 575 /** | |
| 483 * True if currently executed code is a part of a task. | 576 * True if currently executed code is a part of a task. |
| 484 * @type {boolean} | 577 * @type {boolean} |
| 485 */ | 578 */ |
| 486 var isInTask = false; | 579 var isInTask = false; |
| 487 | 580 |
| 488 /** | 581 /** |
| 489 * Starts the first queued task. | 582 * Starts the first queued task. |
| 490 */ | 583 */ |
| 491 function startFirst() { | 584 function startFirst() { |
| 492 verify(queue.length >= 1, 'startFirst: queue is empty'); | 585 verify(queue.length >= 1, 'startFirst: queue is empty'); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 566 queue.length == 0, | 659 queue.length == 0, |
| 567 'Incomplete task when unloading event page,' + | 660 'Incomplete task when unloading event page,' + |
| 568 ' queue = ' + JSON.stringify(queue) + ', ' + | 661 ' queue = ' + JSON.stringify(queue) + ', ' + |
| 569 wrapper.debugGetStateString()); | 662 wrapper.debugGetStateString()); |
| 570 }); | 663 }); |
| 571 | 664 |
| 572 | 665 |
| 573 /** | 666 /** |
| 574 * Wrapper plugin for tasks. | 667 * Wrapper plugin for tasks. |
| 575 * @constructor | 668 * @constructor |
| 669 * @param {PromiseMetadata=} opt_promiseMetadata Set if wrapped from a | |
| 670 * promise. | |
| 576 */ | 671 */ |
| 577 function TasksWrapperPlugin() { | 672 function TasksWrapperPlugin(opt_promiseMetadata) { |
| 578 this.isTaskCallback = isInTask; | 673 this.isTaskCallback = isInTask; |
| 579 if (this.isTaskCallback) | 674 if (this.isTaskCallback) { |
| 580 ++taskPendingCallbackCount; | 675 ++taskPendingCallbackCount; |
| 676 if (opt_promiseMetadata !== undefined) { | |
| 677 this.promiseId = opt_promiseMetadata.id; | |
| 678 if (!taskPromisePendingCallbackData[this.promiseId]) { | |
| 679 taskPromisePendingCallbackData[this.promiseId] = | |
| 680 {thenCount: 0, catchCount: 0}; | |
| 681 } | |
| 682 if (opt_promiseMetadata.isCatch) { | |
| 683 taskPromisePendingCallbackData[this.promiseId].catchCount++; | |
| 684 this.isCatch = true; | |
| 685 } else { | |
| 686 taskPromisePendingCallbackData[this.promiseId].thenCount++; | |
| 687 this.isCatch = false; | |
| 688 } | |
| 689 } | |
| 690 } | |
| 581 } | 691 } |
| 582 | 692 |
| 583 TasksWrapperPlugin.prototype = { | 693 TasksWrapperPlugin.prototype = { |
| 584 /** | 694 /** |
| 585 * Plugin code to be executed before invoking the original callback. | 695 * Plugin code to be executed before invoking the original callback. |
| 586 */ | 696 */ |
| 587 prologue: function() { | 697 prologue: function() { |
| 588 if (this.isTaskCallback) { | 698 if (this.isTaskCallback) { |
| 589 verify(!isInTask, 'TasksWrapperPlugin.prologue: already in task'); | 699 verify(!isInTask, 'TasksWrapperPlugin.prologue: already in task'); |
| 590 isInTask = true; | 700 isInTask = true; |
| 591 } | 701 } |
| 592 }, | 702 }, |
| 593 | 703 |
| 594 /** | 704 /** |
| 595 * Plugin code to be executed after invoking the original callback. | 705 * Plugin code to be executed after invoking the original callback. |
| 596 */ | 706 */ |
| 597 epilogue: function() { | 707 epilogue: function() { |
| 598 if (this.isTaskCallback) { | 708 if (this.isTaskCallback) { |
| 599 verify(isInTask, 'TasksWrapperPlugin.epilogue: not in task at exit'); | 709 verify(isInTask, 'TasksWrapperPlugin.epilogue: not in task at exit'); |
| 600 isInTask = false; | 710 isInTask = false; |
| 711 if (this.promiseId !== undefined) { | |
| 712 // Finishing up a promise callback. If a "then" calls back, then | |
| 713 // all "catch" callbacks will not call back and vice versa. | |
| 714 // Subtract the callbacks that will not call back. | |
| 715 if (this.isCatch) { | |
| 716 taskPendingCallbackCount -= | |
| 717 taskPromisePendingCallbackData[this.promiseId].thenCount; | |
| 718 taskPromisePendingCallbackData[this.promiseId].thenCount = 0; | |
| 719 } else { | |
| 720 taskPendingCallbackCount -= | |
| 721 taskPromisePendingCallbackData[this.promiseId].catchCount; | |
| 722 taskPromisePendingCallbackData[this.promiseId].catchCount = 0; | |
| 723 } | |
| 724 } | |
| 601 if (--taskPendingCallbackCount == 0) | 725 if (--taskPendingCallbackCount == 0) |
| 602 finish(); | 726 finish(); |
| 603 } | 727 } |
| 604 } | 728 } |
| 605 }; | 729 }; |
| 606 | 730 |
| 607 wrapper.registerWrapperPluginFactory(function() { | 731 wrapper.registerWrapperPluginFactory( |
| 608 return new TasksWrapperPlugin(); | 732 function(opt_promiseMetadata) { |
| 609 }); | 733 return new TasksWrapperPlugin(opt_promiseMetadata); |
| 734 }); | |
| 610 | 735 |
| 611 return { | 736 return { |
| 612 add: add | 737 add: add |
| 613 }; | 738 }; |
| 614 } | 739 } |
| 615 | 740 |
| 616 /** | 741 /** |
| 617 * Builds an object to manage retrying activities with exponential backoff. | 742 * Builds an object to manage retrying activities with exponential backoff. |
| 618 * @param {string} name Name of this attempt manager. | 743 * @param {string} name Name of this attempt manager. |
| 619 * @param {function()} attempt Activity that the manager retries until it | 744 * @param {function()} attempt Activity that the manager retries until it |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 823 // One hour is just an arbitrary amount of time chosen. | 948 // One hour is just an arbitrary amount of time chosen. |
| 824 chrome.alarms.create(alarmName, {periodInMinutes: 60}); | 949 chrome.alarms.create(alarmName, {periodInMinutes: 60}); |
| 825 | 950 |
| 826 return { | 951 return { |
| 827 addListener: addListener, | 952 addListener: addListener, |
| 828 getAuthToken: getAuthToken, | 953 getAuthToken: getAuthToken, |
| 829 isSignedIn: isSignedIn, | 954 isSignedIn: isSignedIn, |
| 830 removeToken: removeToken | 955 removeToken: removeToken |
| 831 }; | 956 }; |
| 832 } | 957 } |
| OLD | NEW |