| Index: chrome/renderer/resources/extensions/app_custom_bindings.js | 
| diff --git a/chrome/renderer/resources/extensions/app_custom_bindings.js b/chrome/renderer/resources/extensions/app_custom_bindings.js | 
| index 303bea6932d1fc09c8ee3fe0b536a7013d339a9a..0c2011d18737f436a103952dbd48182d2fce42a1 100644 | 
| --- a/chrome/renderer/resources/extensions/app_custom_bindings.js | 
| +++ b/chrome/renderer/resources/extensions/app_custom_bindings.js | 
| @@ -13,15 +13,40 @@ if (!GetAvailability('app').is_available) { | 
|  | 
| var appNatives = requireNative('app'); | 
| var chrome = requireNative('chrome').GetChrome(); | 
| +var process = requireNative('process'); | 
| +var extensionId = process.GetExtensionId(); | 
| +var logActivity = requireNative('activityLogger'); | 
| + | 
| +function wrapForLogging(fun) { | 
| +  var id = extensionId; | 
| +  return (function() { | 
| +    // TODO(ataly): We need to make sure we use the right prototype for | 
| +    // fun.apply. Array slice can either be rewritten or similarly defined. | 
| +    logActivity.LogAPICall(id, "app." + fun.name, | 
| +        Array.prototype.slice.call(arguments)); | 
| +    return fun.apply(this, arguments); | 
| +  }); | 
| +} | 
|  | 
| // This becomes chrome.app | 
| -var app = { | 
| -  getIsInstalled: appNatives.GetIsInstalled, | 
| -  install: appNatives.Install, | 
| -  getDetails: appNatives.GetDetails, | 
| -  getDetailsForFrame: appNatives.GetDetailsForFrame, | 
| -  runningState: appNatives.GetRunningState | 
| -}; | 
| +var app; | 
| +if (!extensionId) { | 
| +  app = { | 
| +    getIsInstalled: appNatives.GetIsInstalled, | 
| +    install: appNatives.Install, | 
| +    getDetails: appNatives.GetDetails, | 
| +    getDetailsForFrame: appNatives.GetDetailsForFrame, | 
| +    runningState: appNatives.GetRunningState | 
| +  }; | 
| +} else { | 
| +  app = { | 
| +    getIsInstalled: wrapForLogging(appNatives.GetIsInstalled), | 
| +    install: wrapForLogging(appNatives.Install), | 
| +    getDetails: wrapForLogging(appNatives.GetDetails), | 
| +    getDetailsForFrame: wrapForLogging(appNatives.GetDetailsForFrame), | 
| +    runningState: wrapForLogging(appNatives.GetRunningState) | 
| +  }; | 
| +} | 
|  | 
| // Tricky; "getIsInstalled" is actually exposed as the getter "isInstalled", | 
| // but we don't have a way to express this in the schema JSON (nor is it | 
| @@ -29,7 +54,11 @@ var app = { | 
| // | 
| // So, define it manually, and let the getIsInstalled function act as its | 
| // documentation. | 
| -app.__defineGetter__('isInstalled', appNatives.GetIsInstalled); | 
| +if (!extensionId) | 
| +  app.__defineGetter__('isInstalled', appNatives.GetIsInstalled); | 
| +else | 
| +  app.__defineGetter__('isInstalled', | 
| +                       wrapForLogging(appNatives.GetIsInstalled)); | 
|  | 
| // Called by app_bindings.cc. | 
| // This becomes chromeHidden.app | 
| @@ -51,6 +80,8 @@ app.installState = function getInstallState(callback) { | 
| callbacks[callbackId] = callback; | 
| appNatives.GetInstallState(callbackId); | 
| }; | 
| +if (extensionId) | 
| +  app.installState = wrapForLogging(app.installState); | 
|  | 
| // These must match the names in InstallAppbinding() in | 
| // chrome/renderer/extensions/dispatcher.cc. | 
|  |