Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(493)

Side by Side Diff: chrome/browser/resources/google_now/utility.js

Issue 22647003: Remove chrome.* Function Instrumentation Inlining and Use a Separate Instrumented Object (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@SMLog
Patch Set: CR Feedback Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/resources/google_now/cards_unittest.gtestjs ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 */ 9 */
10 10
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
48 function buildServerRequest(handlerName, contentType) { 48 function buildServerRequest(handlerName, contentType) {
49 var request = new XMLHttpRequest(); 49 var request = new XMLHttpRequest();
50 50
51 request.responseType = 'text'; 51 request.responseType = 'text';
52 request.open('POST', NOTIFICATION_CARDS_URL + '/' + handlerName, true); 52 request.open('POST', NOTIFICATION_CARDS_URL + '/' + handlerName, true);
53 request.setRequestHeader('Content-type', contentType); 53 request.setRequestHeader('Content-type', contentType);
54 54
55 return request; 55 return request;
56 } 56 }
57 57
58 // Partial mirror of chrome.* for all instrumented functions.
59 var instrumented = {};
60
58 /** 61 /**
59 * Builds the object to manage tasks (mutually exclusive chains of events). 62 * Builds the object to manage tasks (mutually exclusive chains of events).
60 * @param {function(string, string): boolean} areConflicting Function that 63 * @param {function(string, string): boolean} areConflicting Function that
61 * checks if a new task can't be added to a task queue that contains an 64 * checks if a new task can't be added to a task queue that contains an
62 * existing task. 65 * existing task.
63 * @return {Object} Task manager interface. 66 * @return {Object} Task manager interface.
64 */ 67 */
65 function buildTaskManager(areConflicting) { 68 function buildTaskManager(areConflicting) {
66 /** 69 /**
67 * Queue of scheduled tasks. The first element, if present, corresponds to the 70 * Queue of scheduled tasks. The first element, if present, corresponds to the
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after
289 if (isEnabled) 292 if (isEnabled)
290 sendErrorReport(error); 293 sendErrorReport(error);
291 }); 294 });
292 debugAlert(message); 295 debugAlert(message);
293 } 296 }
294 } 297 }
295 }; 298 };
296 } 299 }
297 300
298 /** 301 /**
302 * Adds an instrumented function to instrumented.* that forwards
303 * to the equivalent chrome.* function.
304 * @param {object} instrumentedContainer Instrumented container object
305 * for the function in the 'chrome.' portion.
306 * @param {array} functionIdentifierParts Path to the chrome.* function.
307 * @param {string} functionName Name of the chrome API function.
308 * @param {number} callbackParameter Index of the callback parameter to this
309 * API function.
310 */
311 function addInstrumentedFunction(
312 instrumentedContainer,
313 functionIdentifierParts,
314 functionName,
315 callbackParameter) {
316 instrumentedContainer[functionName] = function() {
vadimt 2013/08/08 18:19:25 Alternatively, you could simply return the new fun
robliao 2013/08/08 21:35:35 Sounds better. On 2013/08/08 18:19:25, vadimt wrot
317 // This is the wrapper for the API function. Pass the wrapped callback to
318 // the original function.
319 var callback = arguments[callbackParameter];
320 if (typeof callback != 'function') {
321 debugAlert('Argument ' + callbackParameter + ' of ' +
322 functionIdentifierParts.join('.') + '.' + functionName +
323 ' is not a function');
324 }
325 arguments[callbackParameter] = wrapCallback(
326 callback, functionName == 'addListener');
327
328 var chromeContainer = chrome;
329 functionIdentifierParts.map(function(fragment) {
330 chromeContainer = chromeContainer[fragment];
331 });
332 return chromeContainer[functionName].
333 apply(chromeContainer, arguments);
334 };
335 }
336
337 /**
299 * Instruments an API function to add error processing to its user 338 * Instruments an API function to add error processing to its user
300 * code-provided callback. 339 * code-provided callback.
301 * @param {Object} namespace Namespace of the API function. 340 * @param {string} functionIdentifier Full identifier of the function without
302 * @param {string} functionName Name of the API function. 341 * the 'chrome.' portion.
303 * @param {number} callbackParameter Index of the callback parameter to this 342 * @param {number} callbackParameter Index of the callback parameter to this
304 * API function. 343 * API function.
305 */ 344 */
306 function instrumentApiFunction(namespace, functionName, callbackParameter) { 345 function instrumentChromeApiFunction(functionIdentifier, callbackParameter) {
307 var originalFunction = namespace[functionName]; 346 var functionIdentifierParts = functionIdentifier.split('.');
347 var functionName = functionIdentifierParts.pop();
348 var chromeContainer = chrome;
349 var instrumentedContainer = instrumented;
350 functionIdentifierParts.map(function(fragment) {
351 chromeContainer = chromeContainer[fragment];
352 if (!(fragment in instrumentedContainer))
353 instrumentedContainer[fragment] = {};
308 354
309 if (!originalFunction) 355 instrumentedContainer = instrumentedContainer[fragment];
vadimt 2013/08/08 18:19:25 Or, if you prefer: instrumentedContainer = instrum
robliao 2013/08/08 21:35:35 Keeping current for explicitness. On 2013/08/08 18
356 });
357
358 var targetFunction = chromeContainer[functionName];
359
360 if (!targetFunction)
310 debugAlert('Cannot instrument ' + functionName); 361 debugAlert('Cannot instrument ' + functionName);
311 362
312 namespace[functionName] = function() { 363 addInstrumentedFunction(
313 // This is the wrapper for the API function. Pass the wrapped callback to 364 instrumentedContainer,
314 // the original function. 365 functionIdentifierParts,
315 var callback = arguments[callbackParameter]; 366 functionName,
316 if (typeof callback != 'function') { 367 callbackParameter);
317 debugAlert('Argument ' + callbackParameter + ' of ' + functionName +
318 ' is not a function');
319 }
320 arguments[callbackParameter] = wrapCallback(
321 callback, functionName == 'addListener');
322 return originalFunction.apply(namespace, arguments);
323 };
324 } 368 }
325 369
326 instrumentApiFunction(chrome.alarms, 'get', 1); 370 instrumentChromeApiFunction('alarms.get', 1);
327 instrumentApiFunction(chrome.alarms.onAlarm, 'addListener', 0); 371 instrumentChromeApiFunction('alarms.onAlarm.addListener', 0);
328 instrumentApiFunction(chrome.identity, 'getAuthToken', 1); 372 instrumentChromeApiFunction('identity.getAuthToken', 1);
329 instrumentApiFunction(chrome.runtime.onSuspend, 'addListener', 0); 373 instrumentChromeApiFunction('identity.removeCachedAuthToken', 1);
374 instrumentChromeApiFunction('runtime.onSuspend.addListener', 0);
330 375
331 chrome.runtime.onSuspend.addListener(function() { 376 chrome.runtime.onSuspend.addListener(function() {
332 var stringifiedPendingCallbacks = JSON.stringify(pendingCallbacks); 377 var stringifiedPendingCallbacks = JSON.stringify(pendingCallbacks);
333 verify( 378 verify(
334 queue.length == 0 && stringifiedPendingCallbacks == '{}', 379 queue.length == 0 && stringifiedPendingCallbacks == '{}',
335 'Incomplete task or pending callbacks when unloading event page,' + 380 'Incomplete task or pending callbacks when unloading event page,' +
336 ' queue = ' + JSON.stringify(queue) + 381 ' queue = ' + JSON.stringify(queue) +
337 ', pendingCallbacks = ' + stringifiedPendingCallbacks); 382 ', pendingCallbacks = ' + stringifiedPendingCallbacks);
338 }); 383 });
339 384
340 return { 385 return {
341 add: add, 386 add: add,
342 debugSetStepName: function() {}, // TODO(vadimt): remove 387 debugSetStepName: function() {}, // TODO(vadimt): remove
343 instrumentApiFunction: instrumentApiFunction, 388 instrumentChromeApiFunction: instrumentChromeApiFunction,
344 wrapCallback: wrapCallback 389 wrapCallback: wrapCallback
345 }; 390 };
346 } 391 }
347 392
348 var storage = chrome.storage.local;
349
350 /** 393 /**
351 * Builds an object to manage retrying activities with exponential backoff. 394 * Builds an object to manage retrying activities with exponential backoff.
352 * @param {string} name Name of this attempt manager. 395 * @param {string} name Name of this attempt manager.
353 * @param {function()} attempt Activity that the manager retries until it 396 * @param {function()} attempt Activity that the manager retries until it
354 * calls 'stop' method. 397 * calls 'stop' method.
355 * @param {number} initialDelaySeconds Default first delay until first retry. 398 * @param {number} initialDelaySeconds Default first delay until first retry.
356 * @param {number} maximumDelaySeconds Maximum delay between retries. 399 * @param {number} maximumDelaySeconds Maximum delay between retries.
357 * @return {Object} Attempt manager interface. 400 * @return {Object} Attempt manager interface.
358 */ 401 */
359 function buildAttemptManager( 402 function buildAttemptManager(
(...skipping 13 matching lines...) Expand all
373 }; 416 };
374 chrome.alarms.create(alarmName, alarmInfo); 417 chrome.alarms.create(alarmName, alarmInfo);
375 } 418 }
376 419
377 /** 420 /**
378 * Indicates if this attempt manager has started. 421 * Indicates if this attempt manager has started.
379 * @param {function(boolean)} callback The function's boolean parameter is 422 * @param {function(boolean)} callback The function's boolean parameter is
380 * true if the attempt manager has started, false otherwise. 423 * true if the attempt manager has started, false otherwise.
381 */ 424 */
382 function isRunning(callback) { 425 function isRunning(callback) {
383 chrome.alarms.get(alarmName, function(alarmInfo) { 426 instrumented.alarms.get(alarmName, function(alarmInfo) {
384 callback(!!alarmInfo); 427 callback(!!alarmInfo);
385 }); 428 });
386 } 429 }
387 430
388 /** 431 /**
389 * Schedules next attempt. 432 * Schedules next attempt.
390 * @param {number=} opt_previousDelaySeconds Previous delay in a sequence of 433 * @param {number=} opt_previousDelaySeconds Previous delay in a sequence of
391 * retry attempts, if specified. Not specified for scheduling first retry 434 * retry attempts, if specified. Not specified for scheduling first retry
392 * in the exponential sequence. 435 * in the exponential sequence.
393 */ 436 */
394 function scheduleNextAttempt(opt_previousDelaySeconds) { 437 function scheduleNextAttempt(opt_previousDelaySeconds) {
395 var base = opt_previousDelaySeconds ? opt_previousDelaySeconds * 2 : 438 var base = opt_previousDelaySeconds ? opt_previousDelaySeconds * 2 :
396 initialDelaySeconds; 439 initialDelaySeconds;
397 var newRetryDelaySeconds = 440 var newRetryDelaySeconds =
398 Math.min(base * (1 + 0.2 * Math.random()), maximumDelaySeconds); 441 Math.min(base * (1 + 0.2 * Math.random()), maximumDelaySeconds);
399 442
400 createAlarm(newRetryDelaySeconds); 443 createAlarm(newRetryDelaySeconds);
401 444
402 var items = {}; 445 var items = {};
403 items[currentDelayStorageKey] = newRetryDelaySeconds; 446 items[currentDelayStorageKey] = newRetryDelaySeconds;
404 storage.set(items); 447 chrome.storage.local.set(items);
405 } 448 }
406 449
407 /** 450 /**
408 * Starts repeated attempts. 451 * Starts repeated attempts.
409 * @param {number=} opt_firstDelaySeconds Time until the first attempt, if 452 * @param {number=} opt_firstDelaySeconds Time until the first attempt, if
410 * specified. Otherwise, initialDelaySeconds will be used for the first 453 * specified. Otherwise, initialDelaySeconds will be used for the first
411 * attempt. 454 * attempt.
412 */ 455 */
413 function start(opt_firstDelaySeconds) { 456 function start(opt_firstDelaySeconds) {
414 if (opt_firstDelaySeconds) { 457 if (opt_firstDelaySeconds) {
415 createAlarm(opt_firstDelaySeconds); 458 createAlarm(opt_firstDelaySeconds);
416 storage.remove(currentDelayStorageKey); 459 chrome.storage.local.remove(currentDelayStorageKey);
417 } else { 460 } else {
418 scheduleNextAttempt(); 461 scheduleNextAttempt();
419 } 462 }
420 } 463 }
421 464
422 /** 465 /**
423 * Stops repeated attempts. 466 * Stops repeated attempts.
424 */ 467 */
425 function stop() { 468 function stop() {
426 chrome.alarms.clear(alarmName); 469 chrome.alarms.clear(alarmName);
427 storage.remove(currentDelayStorageKey); 470 chrome.storage.local.remove(currentDelayStorageKey);
428 } 471 }
429 472
430 /** 473 /**
431 * Plans for the next attempt. 474 * Plans for the next attempt.
432 * @param {function()} callback Completion callback. It will be invoked after 475 * @param {function()} callback Completion callback. It will be invoked after
433 * the planning is done. 476 * the planning is done.
434 */ 477 */
435 function planForNext(callback) { 478 function planForNext(callback) {
436 storage.get(currentDelayStorageKey, function(items) { 479 instrumented.storage.local.get(currentDelayStorageKey, function(items) {
437 console.log('planForNext-get-storage ' + JSON.stringify(items)); 480 console.log('planForNext-get-storage ' + JSON.stringify(items));
438 scheduleNextAttempt(items[currentDelayStorageKey]); 481 scheduleNextAttempt(items[currentDelayStorageKey]);
439 callback(); 482 callback();
440 }); 483 });
441 } 484 }
442 485
443 chrome.alarms.onAlarm.addListener(function(alarm) { 486 instrumented.alarms.onAlarm.addListener(function(alarm) {
444 if (alarm.name == alarmName) 487 if (alarm.name == alarmName)
445 isRunning(function(running) { 488 isRunning(function(running) {
446 if (running) 489 if (running)
447 attempt(); 490 attempt();
448 }); 491 });
449 }); 492 });
450 493
451 return { 494 return {
452 start: start, 495 start: start,
453 planForNext: planForNext, 496 planForNext: planForNext,
(...skipping 13 matching lines...) Expand all
467 */ 510 */
468 function buildAuthenticationManager() { 511 function buildAuthenticationManager() {
469 var alarmName = 'sign-in-alarm'; 512 var alarmName = 'sign-in-alarm';
470 513
471 /** 514 /**
472 * Determines if the user is signed in and provides a token if signed in. 515 * Determines if the user is signed in and provides a token if signed in.
473 * @param {function(string=)} callback Called on completion. 516 * @param {function(string=)} callback Called on completion.
474 * If the user is signed in, the string contains the token. 517 * If the user is signed in, the string contains the token.
475 */ 518 */
476 function isSignedIn(callback) { 519 function isSignedIn(callback) {
477 chrome.identity.getAuthToken({interactive: false}, function(token) { 520 instrumented.identity.getAuthToken({interactive: false}, function(token) {
478 token = chrome.runtime.lastError ? undefined : token; 521 token = chrome.runtime.lastError ? undefined : token;
479 callback(token); 522 callback(token);
480 checkAndNotifyListeners(!!token); 523 checkAndNotifyListeners(!!token);
481 }); 524 });
482 } 525 }
483 526
484 /** 527 /**
485 * Removes the specified cached token. 528 * Removes the specified cached token.
486 * @param {string} token Authentication Token to remove from the cache. 529 * @param {string} token Authentication Token to remove from the cache.
487 * @param {function} onSuccess Called on completion. 530 * @param {function} onSuccess Called on completion.
488 */ 531 */
489 function removeToken(token, onSuccess) { 532 function removeToken(token, onSuccess) {
490 chrome.identity.removeCachedAuthToken({token: token}, function() { 533 instrumented.identity.removeCachedAuthToken({token: token}, function() {
491 // Removing the token from the cache will change the sign in state. 534 // Removing the token from the cache will change the sign in state.
492 // Repoll now to check the state and notify listeners. 535 // Repoll now to check the state and notify listeners.
493 // This also lets Chrome now about a possible problem with the token. 536 // This also lets Chrome now about a possible problem with the token.
494 isSignedIn(function() {}); 537 isSignedIn(function() {});
495 onSuccess(); 538 onSuccess();
496 }); 539 });
497 } 540 }
498 541
499 var listeners = []; 542 var listeners = [];
500 543
(...skipping 14 matching lines...) Expand all
515 function checkAndNotifyListeners(currentSignedInState) { 558 function checkAndNotifyListeners(currentSignedInState) {
516 if ((lastReturnedSignedInState !== currentSignedInState) && 559 if ((lastReturnedSignedInState !== currentSignedInState) &&
517 (lastReturnedSignedInState !== null)) { 560 (lastReturnedSignedInState !== null)) {
518 for (var listenerIndex in listeners) { 561 for (var listenerIndex in listeners) {
519 listeners[listenerIndex](); 562 listeners[listenerIndex]();
520 } 563 }
521 } 564 }
522 lastReturnedSignedInState = currentSignedInState; 565 lastReturnedSignedInState = currentSignedInState;
523 } 566 }
524 567
525 chrome.alarms.onAlarm.addListener(function(alarm) { 568 instrumented.alarms.onAlarm.addListener(function(alarm) {
526 if (alarm.name == alarmName) 569 if (alarm.name == alarmName)
527 isSignedIn(function() {}); 570 isSignedIn(function() {});
528 }); 571 });
529 572
530 // Poll for the sign in state every hour. 573 // Poll for the sign in state every hour.
531 // One hour is just an arbitrary amount of time chosen. 574 // One hour is just an arbitrary amount of time chosen.
532 chrome.alarms.create(alarmName, {periodInMinutes: 60}); 575 chrome.alarms.create(alarmName, {periodInMinutes: 60});
533 576
534 return { 577 return {
535 addListener: addListener, 578 addListener: addListener,
536 isSignedIn: isSignedIn, 579 isSignedIn: isSignedIn,
537 removeToken: removeToken 580 removeToken: removeToken
538 }; 581 };
539 } 582 }
OLDNEW
« no previous file with comments | « chrome/browser/resources/google_now/cards_unittest.gtestjs ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698