NS_IMETHODIMP
nsStatusReporterManager::DumpReports()
{
  static unsigned number = 1;
  nsresult rv;
  int thispid = 181818;

  thispid = getpid();
  nsCString filename("status-reports-");
  filename.AppendInt(thispid);
  filename.Append('-');
  filename.AppendInt(number++);
  filename.AppendLiteral(".json");

  // Open a file in NS_OS_TEMP_DIR for writing.
  // The file is initialized as "incomplete-status-reports-pid-number.json" in the
  // begining, it will be rename as "status-reports-pid-number.json" in the end.
  nsCOMPtr<nsIFile> tmpFile;
  rv = nsDumpUtils::OpenTempFile(NS_LITERAL_CSTRING("incomplete-") +
                                 filename,
                                 getter_AddRefs(tmpFile),
                                 NS_LITERAL_CSTRING("status-reports"));
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  nsCOMPtr<nsIFileOutputStream> ostream =
    do_CreateInstance("@mozilla.org/network/file-output-stream;1");
  rv = ostream->Init(tmpFile, -1, -1, 0);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  //Write the reports to the file

  DUMP(ostream, "{\n\"subject\":\"about:service reports\",\n");
  DUMP(ostream, "\"reporters\": [ ");

  nsCOMPtr<nsISimpleEnumerator> e;
  bool more, first = true;
  EnumerateReporters(getter_AddRefs(e));
  while (NS_SUCCEEDED(e->HasMoreElements(&more)) && more) {
    nsCOMPtr<nsISupports> supports;
    e->GetNext(getter_AddRefs(supports));
    nsCOMPtr<nsIStatusReporter> r = do_QueryInterface(supports);

    nsCString process;
    rv = r->GetProcess(process);
    if (NS_WARN_IF(NS_FAILED(rv))) {
      return rv;
    }

    nsCString name;
    rv = r->GetName(name);
    if (NS_WARN_IF(NS_FAILED(rv))) {
      return rv;
    }

    nsCString description;
    rv = r->GetDescription(description);
    if (NS_WARN_IF(NS_FAILED(rv))) {
      return rv;
    }

    if (first) {
      first = false;
    } else {
      DUMP(ostream, ",");
    }

    rv = DumpReport(ostream, process, name, description);
    if (NS_WARN_IF(NS_FAILED(rv))) {
      return rv;
    }
  }
  DUMP(ostream, "\n]\n}\n");

  rv = ostream->Close();
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  // Rename the status reports file
  nsCOMPtr<nsIFile> srFinalFile;
  rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(srFinalFile));
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

#ifdef ANDROID
  rv = srFinalFile->AppendNative(NS_LITERAL_CSTRING("status-reports"));
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }
#endif

  rv = srFinalFile->AppendNative(filename);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  rv = srFinalFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  nsAutoString srActualFinalFilename;
  rv = srFinalFile->GetLeafName(srActualFinalFilename);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  rv = tmpFile->MoveTo(/* directory */ nullptr, srActualFinalFilename);

  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  return NS_OK;
}
NS_IMETHODIMP
nsMemoryReporterManager::GetExplicit(PRInt64 *aExplicit)
{
    InfallibleTArray<MemoryReport> nonheap;
    PRInt64 heapUsed = PRInt64(-1);

    // Get "heap-allocated" and all the KIND_NONHEAP measurements from vanilla
    // reporters.
    nsCOMPtr<nsISimpleEnumerator> e;
    EnumerateReporters(getter_AddRefs(e));

    PRBool more;
    while (NS_SUCCEEDED(e->HasMoreElements(&more)) && more) {
        nsCOMPtr<nsIMemoryReporter> r;
        e->GetNext(getter_AddRefs(r));

        PRInt32 kind;
        nsresult rv = r->GetKind(&kind);
        NS_ENSURE_SUCCESS(rv, rv);

        if (kind == nsIMemoryReporter::KIND_NONHEAP) {
            nsCString path;
            rv = r->GetPath(path);
            NS_ENSURE_SUCCESS(rv, rv);

            PRInt64 amount;
            rv = r->GetAmount(&amount);
            NS_ENSURE_SUCCESS(rv, rv);

            // Just skip any NONHEAP reporters that fail, because
            // "heap-allocated" is the most important one.
            if (amount != PRInt64(-1)) {
                MemoryReport mr(path, amount);
                nonheap.AppendElement(mr);
            }
        } else {
            nsCString path;
            rv = r->GetPath(path);
            NS_ENSURE_SUCCESS(rv, rv);

            if (path.Equals("heap-allocated")) {
                rv = r->GetAmount(&heapUsed);
                NS_ENSURE_SUCCESS(rv, rv);
                // If "heap-allocated" fails, we give up, because the result
                // would be horribly inaccurate.
                if (heapUsed == PRInt64(-1)) {
                    *aExplicit = PRInt64(-1);
                    return NS_OK;
                }
            }
        }
    }

    // Get KIND_NONHEAP measurements from multi-reporters, too.
    nsCOMPtr<nsISimpleEnumerator> e2;
    EnumerateMultiReporters(getter_AddRefs(e2));
    nsRefPtr<MemoryReportsWrapper> wrappedMRs =
        new MemoryReportsWrapper(&nonheap);
    nsRefPtr<MemoryReportCallback> cb = new MemoryReportCallback();

    while (NS_SUCCEEDED(e2->HasMoreElements(&more)) && more) {
      nsCOMPtr<nsIMemoryMultiReporter> r;
      e2->GetNext(getter_AddRefs(r));
      r->CollectReports(cb, wrappedMRs);
    }

    // Ignore (by zeroing its amount) any reporter that is a child of another
    // reporter.  Eg. if we have "explicit/a" and "explicit/a/b", zero the
    // latter.  This is quadratic in the number of NONHEAP reporters, but there
    // shouldn't be many.
    for (PRUint32 i = 0; i < nonheap.Length(); i++) {
        const nsCString &iPath = nonheap[i].path;
        for (PRUint32 j = i + 1; j < nonheap.Length(); j++) {
            const nsCString &jPath = nonheap[j].path;
            if (isParent(iPath, jPath)) {
                nonheap[j].amount = 0;
            } else if (isParent(jPath, iPath)) {
                nonheap[i].amount = 0;
            }
        }
    }

    // Sum all the nonheap reporters and heapUsed.
    *aExplicit = heapUsed;
    for (PRUint32 i = 0; i < nonheap.Length(); i++) {
        *aExplicit += nonheap[i].amount;
    }

    return NS_OK;
}