Bug 1350435 - Compute snapshot ID in the parent process. r=fitzgen
The parent and content processes can have different temp directories
when sandboxing is enabled, so the process that creates the file for a
heap snapshot must also determine the snapshot ID.
MozReview-Commit-ID: 2UuncT54NXc
--- a/devtools/server/performance/memory.js
+++ b/devtools/server/performance/memory.js
@@ -150,18 +150,17 @@ exports.Memory = Class({
if (!boundaries) {
if (this.parent instanceof ChromeActor ||
this.parent instanceof ChildProcessActor) {
boundaries = { runtime: true };
} else {
boundaries = { debugger: this.dbg };
}
}
- const path = ThreadSafeChromeUtils.saveHeapSnapshot(boundaries);
- return HeapSnapshotFileUtils.getSnapshotIdFromPath(path);
+ return ThreadSafeChromeUtils.saveHeapSnapshotGetId(boundaries);
}, "saveHeapSnapshot"),
/**
* Take a census of the heap. See js/src/doc/Debugger/Debugger.Memory.md for
* more information.
*/
takeCensus: expectState("attached", function () {
return this.dbg.memory.takeCensus();
--- a/devtools/shared/heapsnapshot/HeapSnapshot.cpp
+++ b/devtools/shared/heapsnapshot/HeapSnapshot.cpp
@@ -1439,35 +1439,46 @@ msSinceProcessCreation(const TimeStamp&
bool ignored;
auto duration = now - TimeStamp::ProcessCreation(ignored);
return (unsigned long) duration.ToMilliseconds();
}
/* static */ already_AddRefed<nsIFile>
HeapSnapshot::CreateUniqueCoreDumpFile(ErrorResult& rv,
const TimeStamp& now,
- nsAString& outFilePath)
+ nsAString& outFilePath,
+ nsAString& outSnapshotId)
{
nsCOMPtr<nsIFile> file;
rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(file));
if (NS_WARN_IF(rv.Failed()))
return nullptr;
+ nsAutoString tempPath;
+ rv = file->GetPath(tempPath);
+ if (NS_WARN_IF(rv.Failed()))
+ return nullptr;
+
auto ms = msSinceProcessCreation(now);
rv = file->AppendNative(nsPrintfCString("%lu.fxsnapshot", ms));
if (NS_WARN_IF(rv.Failed()))
return nullptr;
rv = file->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0666);
if (NS_WARN_IF(rv.Failed()))
return nullptr;
rv = file->GetPath(outFilePath);
if (NS_WARN_IF(rv.Failed()))
- return nullptr;
+ return nullptr;
+
+ // The snapshot ID must be computed in the process that created the
+ // temp file, because TmpD may not be the same in all processes.
+ outSnapshotId.Assign(Substring(outFilePath, tempPath.Length() + 1,
+ outFilePath.Length() - tempPath.Length() - sizeof(".fxsnapshot")));
return file.forget();
}
// Deletion policy for cleaning up PHeapSnapshotTempFileHelperChild pointers.
class DeleteHeapSnapshotTempFileHelperChild
{
public:
@@ -1484,24 +1495,28 @@ using UniqueHeapSnapshotTempFileHelperCh
DeleteHeapSnapshotTempFileHelperChild>;
// Get an nsIOutputStream that we can write the heap snapshot to. In non-e10s
// and in the e10s parent process, open a file directly and create an output
// stream for it. In e10s child processes, we are sandboxed without access to
// the filesystem. Use IPDL to request a file descriptor from the parent
// process.
static already_AddRefed<nsIOutputStream>
-getCoreDumpOutputStream(ErrorResult& rv, TimeStamp& start, nsAString& outFilePath)
+getCoreDumpOutputStream(ErrorResult& rv,
+ TimeStamp& start,
+ nsAString& outFilePath,
+ nsAString& outSnapshotId)
{
if (XRE_IsParentProcess()) {
// Create the file and open the output stream directly.
nsCOMPtr<nsIFile> file = HeapSnapshot::CreateUniqueCoreDumpFile(rv,
start,
- outFilePath);
+ outFilePath,
+ outSnapshotId);
if (NS_WARN_IF(rv.Failed()))
return nullptr;
nsCOMPtr<nsIOutputStream> outputStream;
rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), file,
PR_WRONLY, -1, 0);
if (NS_WARN_IF(rv.Failed()))
return nullptr;
@@ -1530,16 +1545,17 @@ getCoreDumpOutputStream(ErrorResult& rv,
}
if (response.type() == OpenHeapSnapshotTempFileResponse::Tnsresult) {
rv.Throw(response.get_nsresult());
return nullptr;
}
auto opened = response.get_OpenedFile();
outFilePath = opened.path();
+ outSnapshotId = opened.snapshotId();
nsCOMPtr<nsIOutputStream> outputStream =
FileDescriptorOutputStream::Create(opened.descriptor());
if (NS_WARN_IF(!outputStream)) {
rv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
return outputStream.forget();
@@ -1548,29 +1564,32 @@ getCoreDumpOutputStream(ErrorResult& rv,
} // namespace devtools
namespace dom {
using namespace JS;
using namespace devtools;
/* static */ void
-ThreadSafeChromeUtils::SaveHeapSnapshot(GlobalObject& global,
- const HeapSnapshotBoundaries& boundaries,
- nsAString& outFilePath,
- ErrorResult& rv)
+ThreadSafeChromeUtils::SaveHeapSnapshotShared(GlobalObject& global,
+ const HeapSnapshotBoundaries& boundaries,
+ nsAString& outFilePath,
+ nsAString& outSnapshotId,
+ ErrorResult& rv)
{
auto start = TimeStamp::Now();
bool wantNames = true;
CompartmentSet compartments;
uint32_t nodeCount = 0;
uint32_t edgeCount = 0;
- nsCOMPtr<nsIOutputStream> outputStream = getCoreDumpOutputStream(rv, start, outFilePath);
+ nsCOMPtr<nsIOutputStream> outputStream = getCoreDumpOutputStream(rv, start,
+ outFilePath,
+ outSnapshotId);
if (NS_WARN_IF(rv.Failed()))
return;
ZeroCopyNSIOutputStream zeroCopyStream(outputStream);
::google::protobuf::io::GzipOutputStream gzipStream(&zeroCopyStream);
JSContext* cx = global.Context();
@@ -1613,16 +1632,36 @@ ThreadSafeChromeUtils::SaveHeapSnapshot(
Telemetry::AccumulateTimeDelta(Telemetry::DEVTOOLS_SAVE_HEAP_SNAPSHOT_MS,
start);
Telemetry::Accumulate(Telemetry::DEVTOOLS_HEAP_SNAPSHOT_NODE_COUNT,
nodeCount);
Telemetry::Accumulate(Telemetry::DEVTOOLS_HEAP_SNAPSHOT_EDGE_COUNT,
edgeCount);
}
+/* static */ void
+ThreadSafeChromeUtils::SaveHeapSnapshot(GlobalObject& global,
+ const HeapSnapshotBoundaries& boundaries,
+ nsAString& outFilePath,
+ ErrorResult& rv)
+{
+ nsAutoString snapshotId;
+ SaveHeapSnapshotShared(global, boundaries, outFilePath, snapshotId, rv);
+}
+
+/* static */ void
+ThreadSafeChromeUtils::SaveHeapSnapshotGetId(GlobalObject& global,
+ const HeapSnapshotBoundaries& boundaries,
+ nsAString& outSnapshotId,
+ ErrorResult& rv)
+{
+ nsAutoString filePath;
+ SaveHeapSnapshotShared(global, boundaries, filePath, outSnapshotId, rv);
+}
+
/* static */ already_AddRefed<HeapSnapshot>
ThreadSafeChromeUtils::ReadHeapSnapshot(GlobalObject& global,
const nsAString& filePath,
ErrorResult& rv)
{
auto start = TimeStamp::Now();
UniquePtr<char[]> path(ToNewCString(filePath));
--- a/devtools/shared/heapsnapshot/HeapSnapshot.h
+++ b/devtools/shared/heapsnapshot/HeapSnapshot.h
@@ -121,17 +121,18 @@ public:
const uint8_t* buffer,
uint32_t size,
ErrorResult& rv);
// Creates the `$TEMP_DIR/XXXXXX-XXX.fxsnapshot` core dump file that heap
// snapshots are serialized into.
static already_AddRefed<nsIFile> CreateUniqueCoreDumpFile(ErrorResult& rv,
const TimeStamp& now,
- nsAString& outFilePath);
+ nsAString& outFilePath,
+ nsAString& outSnapshotId);
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(HeapSnapshot)
MOZ_DECLARE_REFCOUNTED_TYPENAME(HeapSnapshot)
nsISupports* GetParentObject() const { return mParent; }
virtual JSObject* WrapObject(JSContext* aCx,
--- a/devtools/shared/heapsnapshot/HeapSnapshotFileUtils.js
+++ b/devtools/shared/heapsnapshot/HeapSnapshotFileUtils.js
@@ -76,20 +76,8 @@ exports.haveHeapSnapshotTempFile = funct
const path = exports.getHeapSnapshotTempFilePath(snapshotId);
if (!path) {
return Promise.resolve(false);
}
return OS.File.stat(path).then(() => true,
() => false);
};
-
-/**
- * Given a heap snapshot's file path, extricate the snapshot id.
- *
- * @param {String} path
- *
- * @returns String
- */
-exports.getSnapshotIdFromPath = function (path) {
- return path.slice(OS.Constants.Path.tmpDir.length + 1,
- path.length - ".fxsnapshot".length);
-};
--- a/devtools/shared/heapsnapshot/HeapSnapshotTempFileHelperParent.cpp
+++ b/devtools/shared/heapsnapshot/HeapSnapshotTempFileHelperParent.cpp
@@ -26,19 +26,21 @@ openFileFailure(ErrorResult& rv,
mozilla::ipc::IPCResult
HeapSnapshotTempFileHelperParent::RecvOpenHeapSnapshotTempFile(
OpenHeapSnapshotTempFileResponse* outResponse)
{
auto start = TimeStamp::Now();
ErrorResult rv;
nsAutoString filePath;
+ nsAutoString snapshotId;
nsCOMPtr<nsIFile> file = HeapSnapshot::CreateUniqueCoreDumpFile(rv,
start,
- filePath);
+ filePath,
+ snapshotId);
if (NS_WARN_IF(rv.Failed())) {
if (!openFileFailure(rv, outResponse)) {
return IPC_FAIL_NO_REASON(this);
}
return IPC_OK();
}
PRFileDesc* prfd;
@@ -48,14 +50,14 @@ HeapSnapshotTempFileHelperParent::RecvOp
return IPC_FAIL_NO_REASON(this);
}
return IPC_OK();
}
FileDescriptor::PlatformHandleType handle =
FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(prfd));
FileDescriptor fd(handle);
- *outResponse = OpenedFile(filePath, fd);
+ *outResponse = OpenedFile(filePath, snapshotId, fd);
return IPC_OK();
}
} // namespace devtools
} // namespace mozilla
--- a/devtools/shared/heapsnapshot/PHeapSnapshotTempFileHelper.ipdl
+++ b/devtools/shared/heapsnapshot/PHeapSnapshotTempFileHelper.ipdl
@@ -7,16 +7,17 @@
include protocol PContent;
namespace mozilla {
namespace devtools {
struct OpenedFile
{
nsString path;
+ nsString snapshotId;
FileDescriptor descriptor;
};
union OpenHeapSnapshotTempFileResponse
{
nsresult;
OpenedFile;
};
--- a/dom/base/ChromeUtils.h
+++ b/dom/base/ChromeUtils.h
@@ -21,24 +21,38 @@ class HeapSnapshot;
namespace dom {
class ArrayBufferViewOrArrayBuffer;
class PrecompiledScript;
class Promise;
class ThreadSafeChromeUtils
{
+private:
+ // Implemented in devtools/shared/heapsnapshot/HeapSnapshot.cpp
+ static void SaveHeapSnapshotShared(GlobalObject& global,
+ const HeapSnapshotBoundaries& boundaries,
+ nsAString& filePath,
+ nsAString& snapshotId,
+ ErrorResult& rv);
+
public:
// Implemented in devtools/shared/heapsnapshot/HeapSnapshot.cpp
static void SaveHeapSnapshot(GlobalObject& global,
const HeapSnapshotBoundaries& boundaries,
nsAString& filePath,
ErrorResult& rv);
// Implemented in devtools/shared/heapsnapshot/HeapSnapshot.cpp
+ static void SaveHeapSnapshotGetId(GlobalObject& global,
+ const HeapSnapshotBoundaries& boundaries,
+ nsAString& snapshotId,
+ ErrorResult& rv);
+
+ // Implemented in devtools/shared/heapsnapshot/HeapSnapshot.cpp
static already_AddRefed<devtools::HeapSnapshot> ReadHeapSnapshot(GlobalObject& global,
const nsAString& filePath,
ErrorResult& rv);
static void NondeterministicGetWeakMapKeys(GlobalObject& aGlobal,
JS::Handle<JS::Value> aMap,
JS::MutableHandle<JS::Value> aRetval,
ErrorResult& aRv);
--- a/dom/webidl/ThreadSafeChromeUtils.webidl
+++ b/dom/webidl/ThreadSafeChromeUtils.webidl
@@ -20,16 +20,26 @@ interface ThreadSafeChromeUtils {
* to. This is guaranteed to be within the temp
* directory and its file name will match the regexp
* `\d+(\-\d+)?\.fxsnapshot`.
*/
[Throws]
static DOMString saveHeapSnapshot(optional HeapSnapshotBoundaries boundaries);
/**
+ * This is the same as saveHeapSnapshot, but with a different return value.
+ *
+ * @returns The snapshot ID of the file. This is the file name
+ * without the temp directory or the trailing
+ * `.fxsnapshot`.
+ */
+ [Throws]
+ static DOMString saveHeapSnapshotGetId(optional HeapSnapshotBoundaries boundaries);
+
+ /**
* Deserialize a core dump into a HeapSnapshot.
*
* @param filePath The file path to read the heap snapshot from.
*/
[Throws, NewObject]
static HeapSnapshot readHeapSnapshot(DOMString filePath);
/**