Bug 1768722 - Use std::ofstream in nsProfiler::DumpProfileToFileAsync, and reject promise in case of failure - r=florian,mixedpuppy

The geckoProfiler.dumpProfileToFile (extension API) needed to be updated, to create the target directory if necessary. Some xpcshell tests would fail otherwise.

Also improved nsIProfiler.idl docs of dumpProfileToFile{,Async}.

***
Use ofstream, fixed xpcshell tests.

Differential Revision: https://phabricator.services.mozilla.com/D148610
This commit is contained in:
Gerald Squelart 2022-06-15 06:12:08 +00:00
parent c1313ef8d6
commit 48364b519f
3 changed files with 42 additions and 21 deletions

View File

@ -8,6 +8,9 @@
ChromeUtils.defineModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
// eslint-disable-next-line mozilla/reject-importGlobalProperties
Cu.importGlobalProperties(["IOUtils", "PathUtils"]);
const PREF_ASYNC_STACK = "javascript.options.asyncstack";
const ASYNC_STACKS_ENABLED = Services.prefs.getBoolPref(
@ -133,10 +136,14 @@ this.geckoProfiler = class extends ExtensionAPI {
throw new ExtensionError("Path cannot contain a subdirectory.");
}
let fragments = [OS.Constants.Path.profileDir, "profiler", fileName];
let filePath = OS.Path.join(...fragments);
let dirPath = PathUtils.join(
OS.Constants.Path.profileDir,
"profiler"
);
let filePath = PathUtils.join(dirPath, fileName);
try {
await IOUtils.makeDirectory(dirPath);
await Services.profiler.dumpProfileToFileAsync(filePath);
} catch (e) {
Cu.reportError(e);

View File

@ -93,12 +93,28 @@ interface nsIProfiler : nsISupports
Promise getProfileDataAsGzippedArrayBuffer([optional] in double aSinceTime);
/**
* Returns a promise that resolves once the file has been written.
* Asynchronously dump the profile collected so far to a file.
* Returns a promise that resolves once the file has been written, with data
* from all responsive Firefox processes. Note: This blocks the parent process
* while collecting its own data, then unblocks while child processes data is
* being collected.
* `aFilename` may be a full path, or a path relative to where Firefox was
* launched. The target directory must already exist.
*/
[implicit_jscontext]
Promise dumpProfileToFileAsync(in ACString aFilename,
[optional] in double aSinceTime);
/**
* Synchronously dump the profile collected so far in this process to a file.
* This profile will only contain data from the parent process, and from child
* processes that have ended during the session; other currently-live
* processes are ignored.
* `aFilename` may be a full path, or a path relative to where Firefox was
* launched. The target directory must already exist.
*/
void dumpProfileToFile(in string aFilename);
boolean IsActive();
/**
@ -187,11 +203,6 @@ interface nsIProfiler : nsISupports
[implicit_jscontext]
Promise getSymbolTable(in ACString aDebugPath, in ACString aBreakpadID);
/**
* Dump the collected profile to a file.
*/
void dumpProfileToFile(in string aFilename);
%{C++
virtual RefPtr<mozilla::MozPromise<FallibleTArray<uint8_t>, nsresult, true>> GetProfileDataAsGzippedArrayBufferAndroid(double aSinceTime) = 0;
%}

View File

@ -6,6 +6,8 @@
#include "nsProfiler.h"
#include <fstream>
#include <limits>
#include <sstream>
#include <string>
#include <utility>
@ -24,12 +26,10 @@
#include "mozilla/dom/TypedArray.h"
#include "mozilla/Preferences.h"
#include "nsComponentManagerUtils.h"
#include "nsIFileStreams.h"
#include "nsIInterfaceRequestor.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsILoadContext.h"
#include "nsIWebNavigation.h"
#include "nsLocalFile.h"
#include "nsMemory.h"
#include "nsProfilerStartParams.h"
#include "nsProxyRelease.h"
@ -596,18 +596,21 @@ nsProfiler::DumpProfileToFileAsync(const nsACString& aFilename,
->Then(
GetMainThreadSerialEventTarget(), __func__,
[filename, promise](const nsCString& aResult) {
nsCOMPtr<nsIFile> file =
do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
nsresult rv = file->InitWithNativePath(filename);
if (NS_FAILED(rv)) {
MOZ_CRASH();
if (aResult.Length() >=
size_t(std::numeric_limits<std::streamsize>::max())) {
promise->MaybeReject(NS_ERROR_FILE_TOO_BIG);
return;
}
nsCOMPtr<nsIFileOutputStream> of =
do_CreateInstance("@mozilla.org/network/file-output-stream;1");
of->Init(file, -1, -1, 0);
uint32_t sz;
of->Write(aResult.get(), aResult.Length(), &sz);
of->Close();
std::ofstream stream;
stream.open(filename.get());
if (!stream.is_open()) {
promise->MaybeReject(NS_ERROR_FILE_UNRECOGNIZED_PATH);
return;
}
stream.write(aResult.get(), std::streamsize(aResult.Length()));
stream.close();
promise->MaybeResolveWithUndefined();
},