Bug 1350435 - Compute snapshot ID in the parent process. r=fitzgen draft
authorAndrew McCreight <continuation@gmail.com>
Fri, 24 Mar 2017 10:34:44 -0700
changeset 551470 bcc6cc48b86af44b0adddfcdcba89d134f9426ae
parent 551469 acd216bf727c8035403c6f22fd76ac8b9684dbd4
child 551474 00c0b47e3c88b464855c5cb70970462fd5a3d635
child 551804 209e5bbe904712132910658c4589d299a7787708
push id51055
push userbmo:continuation@gmail.com
push dateSun, 26 Mar 2017 12:53:29 +0000
reviewersfitzgen
bugs1350435
milestone55.0a1
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
devtools/server/performance/memory.js
devtools/shared/heapsnapshot/HeapSnapshot.cpp
devtools/shared/heapsnapshot/HeapSnapshot.h
devtools/shared/heapsnapshot/HeapSnapshotFileUtils.js
devtools/shared/heapsnapshot/HeapSnapshotTempFileHelperParent.cpp
devtools/shared/heapsnapshot/PHeapSnapshotTempFileHelper.ipdl
dom/base/ChromeUtils.h
dom/webidl/ThreadSafeChromeUtils.webidl
--- 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);
 
   /**