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

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

Powered by Google App Engine
This is Rietveld 408576698