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

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: Quick Spacing Fix 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 * Returns an instrumented function.
303 * @param {array} functionIdentifierParts Path to the chrome.* function.
304 * @param {string} functionName Name of the chrome API function.
305 * @param {number} callbackParameter Index of the callback parameter to this
306 * API function.
307 * @return {function} An instrumented function.
308 */
309 function createInstrumentedFunction(
310 functionIdentifierParts,
311 functionName,
312 callbackParameter) {
313 return function() {
314 // This is the wrapper for the API function. Pass the wrapped callback to
315 // the original function.
316 var callback = arguments[callbackParameter];
317 if (typeof callback != 'function') {
318 debugAlert('Argument ' + callbackParameter + ' of ' +
319 functionIdentifierParts.join('.') + '.' + functionName +
320 ' is not a function');
321 }
322 arguments[callbackParameter] = wrapCallback(
323 callback, functionName == 'addListener');
324
325 var chromeContainer = chrome;
326 functionIdentifierParts.map(function(fragment) {
327 chromeContainer = chromeContainer[fragment];
328 });
329 return chromeContainer[functionName].
330 apply(chromeContainer, arguments);
331 };
332 }
333
334 /**
299 * Instruments an API function to add error processing to its user 335 * Instruments an API function to add error processing to its user
300 * code-provided callback. 336 * code-provided callback.
301 * @param {Object} namespace Namespace of the API function. 337 * @param {string} functionIdentifier Full identifier of the function without
302 * @param {string} functionName Name of the API function. 338 * the 'chrome.' portion.
303 * @param {number} callbackParameter Index of the callback parameter to this 339 * @param {number} callbackParameter Index of the callback parameter to this
304 * API function. 340 * API function.
305 */ 341 */
306 function instrumentApiFunction(namespace, functionName, callbackParameter) { 342 function instrumentChromeApiFunction(functionIdentifier, callbackParameter) {
307 var originalFunction = namespace[functionName]; 343 var functionIdentifierParts = functionIdentifier.split('.');
344 var functionName = functionIdentifierParts.pop();
345 var chromeContainer = chrome;
346 var instrumentedContainer = instrumented;
347 functionIdentifierParts.map(function(fragment) {
348 chromeContainer = chromeContainer[fragment];
349 if (!(fragment in instrumentedContainer))
350 instrumentedContainer[fragment] = {};
308 351
309 if (!originalFunction) 352 instrumentedContainer = instrumentedContainer[fragment];
353 });
354
355 var targetFunction = chromeContainer[functionName];
356
357 if (!targetFunction)
310 debugAlert('Cannot instrument ' + functionName); 358 debugAlert('Cannot instrument ' + functionName);
311 359
312 namespace[functionName] = function() { 360 instrumentedContainer[functionName] = createInstrumentedFunction(
313 // This is the wrapper for the API function. Pass the wrapped callback to 361 functionIdentifierParts,
314 // the original function. 362 functionName,
315 var callback = arguments[callbackParameter]; 363 callbackParameter);
316 if (typeof callback != 'function') {
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 } 364 }
325 365
326 instrumentApiFunction(chrome.alarms, 'get', 1); 366 instrumentChromeApiFunction('alarms.get', 1);
327 instrumentApiFunction(chrome.alarms.onAlarm, 'addListener', 0); 367 instrumentChromeApiFunction('alarms.onAlarm.addListener', 0);
328 instrumentApiFunction(chrome.identity, 'getAuthToken', 1); 368 instrumentChromeApiFunction('identity.getAuthToken', 1);
329 instrumentApiFunction(chrome.runtime.onSuspend, 'addListener', 0); 369 instrumentChromeApiFunction('identity.removeCachedAuthToken', 1);
370 instrumentChromeApiFunction('runtime.onSuspend.addListener', 0);
330 371
331 chrome.runtime.onSuspend.addListener(function() { 372 chrome.runtime.onSuspend.addListener(function() {
332 var stringifiedPendingCallbacks = JSON.stringify(pendingCallbacks); 373 var stringifiedPendingCallbacks = JSON.stringify(pendingCallbacks);
333 verify( 374 verify(
334 queue.length == 0 && stringifiedPendingCallbacks == '{}', 375 queue.length == 0 && stringifiedPendingCallbacks == '{}',
335 'Incomplete task or pending callbacks when unloading event page,' + 376 'Incomplete task or pending callbacks when unloading event page,' +
336 ' queue = ' + JSON.stringify(queue) + 377 ' queue = ' + JSON.stringify(queue) +
337 ', pendingCallbacks = ' + stringifiedPendingCallbacks); 378 ', pendingCallbacks = ' + stringifiedPendingCallbacks);
338 }); 379 });
339 380
340 return { 381 return {
341 add: add, 382 add: add,
342 debugSetStepName: function() {}, // TODO(vadimt): remove 383 debugSetStepName: function() {}, // TODO(vadimt): remove
343 instrumentApiFunction: instrumentApiFunction, 384 instrumentChromeApiFunction: instrumentChromeApiFunction,
344 wrapCallback: wrapCallback 385 wrapCallback: wrapCallback
345 }; 386 };
346 } 387 }
347 388
348 var storage = chrome.storage.local;
349
350 /** 389 /**
351 * Builds an object to manage retrying activities with exponential backoff. 390 * Builds an object to manage retrying activities with exponential backoff.
352 * @param {string} name Name of this attempt manager. 391 * @param {string} name Name of this attempt manager.
353 * @param {function()} attempt Activity that the manager retries until it 392 * @param {function()} attempt Activity that the manager retries until it
354 * calls 'stop' method. 393 * calls 'stop' method.
355 * @param {number} initialDelaySeconds Default first delay until first retry. 394 * @param {number} initialDelaySeconds Default first delay until first retry.
356 * @param {number} maximumDelaySeconds Maximum delay between retries. 395 * @param {number} maximumDelaySeconds Maximum delay between retries.
357 * @return {Object} Attempt manager interface. 396 * @return {Object} Attempt manager interface.
358 */ 397 */
359 function buildAttemptManager( 398 function buildAttemptManager(
(...skipping 13 matching lines...) Expand all
373 }; 412 };
374 chrome.alarms.create(alarmName, alarmInfo); 413 chrome.alarms.create(alarmName, alarmInfo);
375 } 414 }
376 415
377 /** 416 /**
378 * Indicates if this attempt manager has started. 417 * Indicates if this attempt manager has started.
379 * @param {function(boolean)} callback The function's boolean parameter is 418 * @param {function(boolean)} callback The function's boolean parameter is
380 * true if the attempt manager has started, false otherwise. 419 * true if the attempt manager has started, false otherwise.
381 */ 420 */
382 function isRunning(callback) { 421 function isRunning(callback) {
383 chrome.alarms.get(alarmName, function(alarmInfo) { 422 instrumented.alarms.get(alarmName, function(alarmInfo) {
384 callback(!!alarmInfo); 423 callback(!!alarmInfo);
385 }); 424 });
386 } 425 }
387 426
388 /** 427 /**
389 * Schedules next attempt. 428 * Schedules next attempt.
390 * @param {number=} opt_previousDelaySeconds Previous delay in a sequence of 429 * @param {number=} opt_previousDelaySeconds Previous delay in a sequence of
391 * retry attempts, if specified. Not specified for scheduling first retry 430 * retry attempts, if specified. Not specified for scheduling first retry
392 * in the exponential sequence. 431 * in the exponential sequence.
393 */ 432 */
394 function scheduleNextAttempt(opt_previousDelaySeconds) { 433 function scheduleNextAttempt(opt_previousDelaySeconds) {
395 var base = opt_previousDelaySeconds ? opt_previousDelaySeconds * 2 : 434 var base = opt_previousDelaySeconds ? opt_previousDelaySeconds * 2 :
396 initialDelaySeconds; 435 initialDelaySeconds;
397 var newRetryDelaySeconds = 436 var newRetryDelaySeconds =
398 Math.min(base * (1 + 0.2 * Math.random()), maximumDelaySeconds); 437 Math.min(base * (1 + 0.2 * Math.random()), maximumDelaySeconds);
399 438
400 createAlarm(newRetryDelaySeconds); 439 createAlarm(newRetryDelaySeconds);
401 440
402 var items = {}; 441 var items = {};
403 items[currentDelayStorageKey] = newRetryDelaySeconds; 442 items[currentDelayStorageKey] = newRetryDelaySeconds;
404 storage.set(items); 443 chrome.storage.local.set(items);
405 } 444 }
406 445
407 /** 446 /**
408 * Starts repeated attempts. 447 * Starts repeated attempts.
409 * @param {number=} opt_firstDelaySeconds Time until the first attempt, if 448 * @param {number=} opt_firstDelaySeconds Time until the first attempt, if
410 * specified. Otherwise, initialDelaySeconds will be used for the first 449 * specified. Otherwise, initialDelaySeconds will be used for the first
411 * attempt. 450 * attempt.
412 */ 451 */
413 function start(opt_firstDelaySeconds) { 452 function start(opt_firstDelaySeconds) {
414 if (opt_firstDelaySeconds) { 453 if (opt_firstDelaySeconds) {
415 createAlarm(opt_firstDelaySeconds); 454 createAlarm(opt_firstDelaySeconds);
416 storage.remove(currentDelayStorageKey); 455 chrome.storage.local.remove(currentDelayStorageKey);
417 } else { 456 } else {
418 scheduleNextAttempt(); 457 scheduleNextAttempt();
419 } 458 }
420 } 459 }
421 460
422 /** 461 /**
423 * Stops repeated attempts. 462 * Stops repeated attempts.
424 */ 463 */
425 function stop() { 464 function stop() {
426 chrome.alarms.clear(alarmName); 465 chrome.alarms.clear(alarmName);
427 storage.remove(currentDelayStorageKey); 466 chrome.storage.local.remove(currentDelayStorageKey);
428 } 467 }
429 468
430 /** 469 /**
431 * Plans for the next attempt. 470 * Plans for the next attempt.
432 * @param {function()} callback Completion callback. It will be invoked after 471 * @param {function()} callback Completion callback. It will be invoked after
433 * the planning is done. 472 * the planning is done.
434 */ 473 */
435 function planForNext(callback) { 474 function planForNext(callback) {
436 storage.get(currentDelayStorageKey, function(items) { 475 instrumented.storage.local.get(currentDelayStorageKey, function(items) {
437 console.log('planForNext-get-storage ' + JSON.stringify(items)); 476 console.log('planForNext-get-storage ' + JSON.stringify(items));
438 scheduleNextAttempt(items[currentDelayStorageKey]); 477 scheduleNextAttempt(items[currentDelayStorageKey]);
439 callback(); 478 callback();
440 }); 479 });
441 } 480 }
442 481
443 chrome.alarms.onAlarm.addListener(function(alarm) { 482 instrumented.alarms.onAlarm.addListener(function(alarm) {
444 if (alarm.name == alarmName) 483 if (alarm.name == alarmName)
445 isRunning(function(running) { 484 isRunning(function(running) {
446 if (running) 485 if (running)
447 attempt(); 486 attempt();
448 }); 487 });
449 }); 488 });
450 489
451 return { 490 return {
452 start: start, 491 start: start,
453 planForNext: planForNext, 492 planForNext: planForNext,
(...skipping 13 matching lines...) Expand all
467 */ 506 */
468 function buildAuthenticationManager() { 507 function buildAuthenticationManager() {
469 var alarmName = 'sign-in-alarm'; 508 var alarmName = 'sign-in-alarm';
470 509
471 /** 510 /**
472 * Determines if the user is signed in and provides a token if signed in. 511 * Determines if the user is signed in and provides a token if signed in.
473 * @param {function(string=)} callback Called on completion. 512 * @param {function(string=)} callback Called on completion.
474 * If the user is signed in, the string contains the token. 513 * If the user is signed in, the string contains the token.
475 */ 514 */
476 function isSignedIn(callback) { 515 function isSignedIn(callback) {
477 chrome.identity.getAuthToken({interactive: false}, function(token) { 516 instrumented.identity.getAuthToken({interactive: false}, function(token) {
478 token = chrome.runtime.lastError ? undefined : token; 517 token = chrome.runtime.lastError ? undefined : token;
479 callback(token); 518 callback(token);
480 checkAndNotifyListeners(!!token); 519 checkAndNotifyListeners(!!token);
481 }); 520 });
482 } 521 }
483 522
484 /** 523 /**
485 * Removes the specified cached token. 524 * Removes the specified cached token.
486 * @param {string} token Authentication Token to remove from the cache. 525 * @param {string} token Authentication Token to remove from the cache.
487 * @param {function} onSuccess Called on completion. 526 * @param {function} onSuccess Called on completion.
488 */ 527 */
489 function removeToken(token, onSuccess) { 528 function removeToken(token, onSuccess) {
490 chrome.identity.removeCachedAuthToken({token: token}, function() { 529 instrumented.identity.removeCachedAuthToken({token: token}, function() {
491 // Removing the token from the cache will change the sign in state. 530 // Removing the token from the cache will change the sign in state.
492 // Repoll now to check the state and notify listeners. 531 // Repoll now to check the state and notify listeners.
493 // This also lets Chrome now about a possible problem with the token. 532 // This also lets Chrome now about a possible problem with the token.
494 isSignedIn(function() {}); 533 isSignedIn(function() {});
495 onSuccess(); 534 onSuccess();
496 }); 535 });
497 } 536 }
498 537
499 var listeners = []; 538 var listeners = [];
500 539
(...skipping 14 matching lines...) Expand all
515 function checkAndNotifyListeners(currentSignedInState) { 554 function checkAndNotifyListeners(currentSignedInState) {
516 if ((lastReturnedSignedInState !== currentSignedInState) && 555 if ((lastReturnedSignedInState !== currentSignedInState) &&
517 (lastReturnedSignedInState !== null)) { 556 (lastReturnedSignedInState !== null)) {
518 for (var listenerIndex in listeners) { 557 for (var listenerIndex in listeners) {
519 listeners[listenerIndex](); 558 listeners[listenerIndex]();
520 } 559 }
521 } 560 }
522 lastReturnedSignedInState = currentSignedInState; 561 lastReturnedSignedInState = currentSignedInState;
523 } 562 }
524 563
525 chrome.alarms.onAlarm.addListener(function(alarm) { 564 instrumented.alarms.onAlarm.addListener(function(alarm) {
526 if (alarm.name == alarmName) 565 if (alarm.name == alarmName)
527 isSignedIn(function() {}); 566 isSignedIn(function() {});
528 }); 567 });
529 568
530 // Poll for the sign in state every hour. 569 // Poll for the sign in state every hour.
531 // One hour is just an arbitrary amount of time chosen. 570 // One hour is just an arbitrary amount of time chosen.
532 chrome.alarms.create(alarmName, {periodInMinutes: 60}); 571 chrome.alarms.create(alarmName, {periodInMinutes: 60});
533 572
534 return { 573 return {
535 addListener: addListener, 574 addListener: addListener,
536 isSignedIn: isSignedIn, 575 isSignedIn: isSignedIn,
537 removeToken: removeToken 576 removeToken: removeToken
538 }; 577 };
539 } 578 }
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