InjectedTab = function(extension, tab, pageStatus, pageOptions, port) {
  /**
   * Hosting extension.
   * @type {!Extension}
   * @private
   */
  this.extension_ = extension;

  /**
   * Target tab ID.
   * @type {number}
   * @private
   */
  this.tabId_ = tab.id;

  /**
   * Page URL.
   * @type {string}
   * @private
   */
  this.pageUrl_ = URI.canonicalize(tab.url);

  /**
   * Page options.
   * @type {!Object}
   * @private
   */
  this.pageOptions_ = pageOptions;

  /**
   * Message port connected to the content script.
   * @type {!Port}
   * @private
   */
  this.port_ = port;

  /**
   * Debugger source, if enabled.
   * @type {Debugger}
   * @private
   */
  this.debugger_ = null;

  if (pageStatus == PageStatus.WHITELISTED &&
      pageOptions['wtf.trace.provider.chromeDebug'] !== false) {
    var timelineEnabled =
        pageOptions['wtf.trace.provider.chromeDebug.timeline'] !== false;
    var memoryInfoEnabled =
        pageOptions['wtf.trace.provider.chromeDebug.memoryInfo'];
    var tracingEnabled =
        pageOptions['wtf.trace.provider.chromeDebug.tracing'];
    if (timelineEnabled || memoryInfoEnabled || tracingEnabled) {
      this.debugger_ = new Debugger(this.tabId_, this.pageOptions_);
    }
  }

  /**
   * Registered event handlers.
   * @type {!Object}
   * @private
   */
  this.eventHandlers_ = {
    onMessage: this.messageReceived_.bind(this),
    onDisconnect: this.disconnected_.bind(this)
  };

  this.port_.onMessage.addListener(this.eventHandlers_.onMessage);
  this.port_.onDisconnect.addListener(this.eventHandlers_.onDisconnect);

  /**
   * Periodic timer to transmit debugger data.
   * @type {number}
   * @private
   */
  this.debuggerTransmitId_ = -1;

  if (this.debugger_) {
    this.debuggerTransmitId_ = window.setInterval((function() {
      var records = this.debugger_.getRecords();
      if (records.length) {
        this.port_.postMessage(JSON.stringify({
          'command': 'debugger_data',
          'records': records
        }));
        this.debugger_.clearRecords();
      }
    }).bind(this), 1000);
  }
}
Channel to an injected tab.
This is created once for each tab when the content script is connected.
It handles message dispatch from the content script and sending data to the
content script based on enabled features (like debugging).

@param {!Extension} extension Hosting extension.
@param {!Tab} tab Injected tab.
@param {!Object} pageOptions Page options.
@param {!Port} port Message port to the content script.
@param {PageStatus} pageStatus Page status.
@constructor