summaryrefslogtreecommitdiffstats
path: root/devtools/server/actors/resources/jstracer-state.js
blob: 1bb4723b5528215028630e8d7c95895e1000b754 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

const {
  TYPES: { JSTRACER_STATE },
} = require("resource://devtools/server/actors/resources/index.js");

const { JSTracer } = ChromeUtils.importESModule(
  "resource://devtools/server/tracer/tracer.sys.mjs",
  { global: "contextual" }
);

const { LOG_METHODS } = require("resource://devtools/server/actors/tracer.js");
const Targets = require("resource://devtools/server/actors/targets/index.js");

class TracingStateWatcher {
  /**
   * Start watching for tracing state changes for a given target actor.
   *
   * @param TargetActor targetActor
   *        The target actor from which we should observe
   * @param Object options
   *        Dictionary object with following attributes:
   *        - onAvailable: mandatory function
   *          This will be called for each resource.
   */
  async watch(targetActor, { onAvailable }) {
    // Bug 1874204: tracer doesn't support tracing content process from the browser toolbox just yet
    if (targetActor.targetType == Targets.TYPES.PROCESS) {
      return;
    }

    this.targetActor = targetActor;
    this.onAvailable = onAvailable;

    this.tracingListener = {
      onTracingToggled: this.onTracingToggled.bind(this),
    };
    JSTracer.addTracingListener(this.tracingListener);
  }

  /**
   * Stop watching for tracing state
   */
  destroy() {
    if (!this.tracingListener) {
      return;
    }
    JSTracer.removeTracingListener(this.tracingListener);
  }

  /**
   * Be notified by the underlying JavaScriptTracer class
   * in case it stops by itself, instead of being stopped when the Actor's stopTracing
   * method is called by the user.
   *
   * @param {Boolean} enabled
   *        True if the tracer starts tracing, false it it stops.
   * @param {String} reason
   *        Optional string to justify why the tracer stopped.
   */
  onTracingToggled(enabled, reason) {
    const tracerActor = this.targetActor.getTargetScopedActor("tracer");
    const logMethod = tracerActor?.getLogMethod();

    // JavascriptTracer only supports recording once in the same process/thread.
    // If we open another DevTools, on the same process, we would receive notification
    // about a JavascriptTracer controlled by another toolbox's tracer actor.
    // Ignore them as our current tracer actor didn't start tracing.
    if (!logMethod) {
      return;
    }

    this.onAvailable([
      {
        resourceType: JSTRACER_STATE,
        enabled,
        logMethod,
        profile:
          logMethod == LOG_METHODS.PROFILER && !enabled
            ? tracerActor.getProfile()
            : undefined,
        timeStamp: ChromeUtils.dateNow(),
        reason,
      },
    ]);
  }
}

module.exports = TracingStateWatcher;