Bug 1362800 - Expose geckoProfiler.getProfileAsArrayBuffer. r?kmag draft
authorMarkus Stange <mstange@themasta.com>
Thu, 11 May 2017 00:32:46 -0400
changeset 575980 dcc76faa07776e893ce8c02ac849c2ed2288a192
parent 575783 63295ae352ae7b918fe1703c3140774b16034587
child 628067 2326fac14c5a3ebc35f50c3ca7ddb46bfcdc3fd6
push id58221
push userbmo:mstange@themasta.com
push dateThu, 11 May 2017 04:33:48 +0000
reviewerskmag
bugs1362800
milestone55.0a1
Bug 1362800 - Expose geckoProfiler.getProfileAsArrayBuffer. r?kmag MozReview-Commit-ID: 7uFPWAhh25L
browser/components/extensions/ext-geckoProfiler.js
browser/components/extensions/schemas/geckoProfiler.json
browser/components/extensions/test/xpcshell/test_ext_geckoProfiler_control.js
--- a/browser/components/extensions/ext-geckoProfiler.js
+++ b/browser/components/extensions/ext-geckoProfiler.js
@@ -10,16 +10,20 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "Subprocess", "resource://gre/modules/Subprocess.jsm");
 
 const PREF_ASYNC_STACK = "javascript.options.asyncstack";
 const PREF_SYMBOLS_URL = "extensions.geckoProfiler.symbols.url";
 const PREF_GET_SYMBOL_RULES = "extensions.geckoProfiler.getSymbolRules";
 
 const ASYNC_STACKS_ENABLED = Services.prefs.getBoolPref(PREF_ASYNC_STACK, false);
 
+var {
+  ExtensionError,
+} = ExtensionUtils;
+
 function parseSym(data) {
   const worker = new ChromeWorker("resource://app/modules/ParseSymbols-worker.js");
   const promise = new Promise((resolve, reject) => {
     worker.onmessage = (e) => {
       if (e.data.error) {
         reject(e.data.error);
       } else {
         resolve(e.data.result);
@@ -290,23 +294,32 @@ this.geckoProfiler = class extends Exten
         },
 
         async resume() {
           Services.profiler.ResumeSampling();
         },
 
         async getProfile() {
           if (!Services.profiler.IsActive()) {
-            throw new Error("The profiler is stopped. " +
+            throw new ExtensionError("The profiler is stopped. " +
               "You need to start the profiler before you can capture a profile.");
           }
 
           return Services.profiler.getProfileDataAsync();
         },
 
+        async getProfileAsArrayBuffer() {
+          if (!Services.profiler.IsActive()) {
+            throw new ExtensionError("The profiler is stopped. " +
+              "You need to start the profiler before you can capture a profile.");
+          }
+
+          return Services.profiler.getProfileDataAsArrayBuffer();
+        },
+
         async getSymbols(debugName, breakpadId) {
           if (symbolCache.size === 0) {
             primeSymbolStore(Services.profiler.sharedLibraries);
           }
 
           const cachedLibInfo = symbolCache.get(urlForSymFile(debugName, breakpadId));
 
           const symbolRules = Services.prefs.getCharPref(PREF_GET_SYMBOL_RULES, "localBreakpad,remoteBreakpad");
--- a/browser/components/extensions/schemas/geckoProfiler.json
+++ b/browser/components/extensions/schemas/geckoProfiler.json
@@ -88,16 +88,23 @@
       {
         "name": "getProfile",
         "type": "function",
         "description": "Gathers the profile data from the current profiling session.",
         "async": true,
         "parameters": []
       },
       {
+        "name": "getProfileAsArrayBuffer",
+        "type": "function",
+        "description": "Gathers the profile data from the current profiling session. The returned promise resolves to an array buffer that contains a JSON string.",
+        "async": true,
+        "parameters": []
+      },
+      {
         "name": "getSymbols",
         "type": "function",
         "description": "Gets the debug symbols for a particular library.",
         "async": true,
         "parameters": [
           {
             "type": "string",
             "name": "debugName",
--- a/browser/components/extensions/test/xpcshell/test_ext_geckoProfiler_control.js
+++ b/browser/components/extensions/test/xpcshell/test_ext_geckoProfiler_control.js
@@ -43,16 +43,28 @@ let getExtension = () => {
             result = await browser.geckoProfiler.getProfile();
             browser.test.assertTrue("libs" in result, "The profile contains libs.");
             browser.test.assertTrue("meta" in result, "The profile contains meta.");
             browser.test.assertTrue("threads" in result, "The profile contains threads.");
             browser.test.assertTrue(result.threads.some(t => t.name == "GeckoMain"),
                                     "The profile contains a GeckoMain thread.");
             browser.test.sendMessage("tested profile");
             break;
+          case "test profile as array buffer":
+            let arrayBuffer = await browser.geckoProfiler.getProfileAsArrayBuffer();
+            browser.test.assertTrue(arrayBuffer.byteLength >= 2, "The profile array buffer contains data.");
+            let textDecoder = new TextDecoder();
+            let profile = JSON.parse(textDecoder.decode(arrayBuffer));
+            browser.test.assertTrue("libs" in profile, "The profile contains libs.");
+            browser.test.assertTrue("meta" in profile, "The profile contains meta.");
+            browser.test.assertTrue("threads" in profile, "The profile contains threads.");
+            browser.test.assertTrue(profile.threads.some(t => t.name == "GeckoMain"),
+                                    "The profile contains a GeckoMain thread.");
+            browser.test.sendMessage("tested profile as array buffer");
+            break;
           case "remove runningListener":
             browser.geckoProfiler.onRunning.removeListener(runningListener);
             browser.test.sendMessage("removed runningListener");
             break;
         }
       });
 
       browser.test.sendMessage("ready");
@@ -81,16 +93,19 @@ add_task(async function testProfilerCont
   await extension.awaitMessage("stopped");
 
   extension.sendMessage("start");
   await extension.awaitMessage("started");
 
   extension.sendMessage("test profile");
   await extension.awaitMessage("tested profile");
 
+  extension.sendMessage("test profile as array buffer");
+  await extension.awaitMessage("tested profile as array buffer");
+
   extension.sendMessage("pause");
   await extension.awaitMessage("paused");
 
   extension.sendMessage("resume");
   await extension.awaitMessage("resumed");
 
   extension.sendMessage("stop");
   await extension.awaitMessage("stopped");