LCOV - code coverage report
Current view: top level - ipc/glue - CrashReporterHost.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 5 139 3.6 %
Date: 2017-07-14 16:53:18 Functions: 1 25 4.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "CrashReporterHost.h"
       8             : #include "CrashReporterMetadataShmem.h"
       9             : #include "mozilla/ipc/GeckoChildProcessHost.h"
      10             : #include "mozilla/Sprintf.h"
      11             : #include "mozilla/SyncRunnable.h"
      12             : #include "mozilla/Telemetry.h"
      13             : #ifdef MOZ_CRASHREPORTER
      14             : # include "nsExceptionHandler.h"
      15             : # include "nsIAsyncShutdown.h"
      16             : # include "nsICrashService.h"
      17             : #endif
      18             : 
      19             : namespace mozilla {
      20             : namespace ipc {
      21             : 
      22           1 : CrashReporterHost::CrashReporterHost(GeckoProcessType aProcessType,
      23             :                                      const Shmem& aShmem,
      24           1 :                                      ThreadId aThreadId)
      25             :  : mProcessType(aProcessType),
      26             :    mShmem(aShmem),
      27             :    mThreadId(aThreadId),
      28           1 :    mStartTime(::time(nullptr)),
      29           2 :    mFinalized(false)
      30             : {
      31           1 : }
      32             : 
      33             : #ifdef MOZ_CRASHREPORTER
      34             : bool
      35           0 : CrashReporterHost::GenerateCrashReport(base::ProcessId aPid)
      36             : {
      37           0 :   if (!TakeCrashedChildMinidump(aPid, nullptr)) {
      38           0 :     return false;
      39             :   }
      40           0 :   return FinalizeCrashReport();
      41             : }
      42             : 
      43             : RefPtr<nsIFile>
      44           0 : CrashReporterHost::TakeCrashedChildMinidump(base::ProcessId aPid, uint32_t* aOutSequence)
      45             : {
      46           0 :   MOZ_ASSERT(!HasMinidump());
      47             : 
      48           0 :   RefPtr<nsIFile> crashDump;
      49           0 :   if (!XRE_TakeMinidumpForChild(aPid, getter_AddRefs(crashDump), aOutSequence)) {
      50           0 :     return nullptr;
      51             :   }
      52           0 :   if (!AdoptMinidump(crashDump)) {
      53           0 :     return nullptr;
      54             :   }
      55           0 :   return crashDump.get();
      56             : }
      57             : 
      58             : bool
      59           0 : CrashReporterHost::AdoptMinidump(nsIFile* aFile)
      60             : {
      61           0 :   return CrashReporter::GetIDFromMinidump(aFile, mDumpID);
      62             : }
      63             : 
      64             : bool
      65           0 : CrashReporterHost::FinalizeCrashReport()
      66             : {
      67           0 :   MOZ_ASSERT(!mFinalized);
      68           0 :   MOZ_ASSERT(HasMinidump());
      69             : 
      70           0 :   CrashReporter::AnnotationTable notes;
      71             : 
      72           0 :   nsAutoCString type;
      73           0 :   switch (mProcessType) {
      74             :     case GeckoProcessType_Content:
      75           0 :       type = NS_LITERAL_CSTRING("content");
      76           0 :       break;
      77             :     case GeckoProcessType_Plugin:
      78             :     case GeckoProcessType_GMPlugin:
      79           0 :       type = NS_LITERAL_CSTRING("plugin");
      80           0 :       break;
      81             :     case GeckoProcessType_GPU:
      82           0 :       type = NS_LITERAL_CSTRING("gpu");
      83           0 :       break;
      84             :     default:
      85           0 :       NS_ERROR("unknown process type");
      86           0 :       break;
      87             :   }
      88           0 :   notes.Put(NS_LITERAL_CSTRING("ProcessType"), type);
      89             : 
      90             :   char startTime[32];
      91           0 :   SprintfLiteral(startTime, "%lld", static_cast<long long>(mStartTime));
      92           0 :   notes.Put(NS_LITERAL_CSTRING("StartupTime"), nsDependentCString(startTime));
      93             : 
      94             :   // We might not have shmem (for example, when running crashreporter tests).
      95           0 :   if (mShmem.IsReadable()) {
      96           0 :     CrashReporterMetadataShmem::ReadAppNotes(mShmem, &notes);
      97             :   }
      98           0 :   CrashReporter::AppendExtraData(mDumpID, mExtraNotes);
      99           0 :   CrashReporter::AppendExtraData(mDumpID, notes);
     100             : 
     101             :   // Use mExtraNotes, since NotifyCrashService looks for "PluginHang" which is
     102             :   // set in the parent process.
     103           0 :   NotifyCrashService(mProcessType, mDumpID, &mExtraNotes);
     104             : 
     105           0 :   mFinalized = true;
     106           0 :   return true;
     107             : }
     108             : 
     109             : namespace {
     110             : class GenerateMinidumpShutdownBlocker : public nsIAsyncShutdownBlocker {
     111             : public:
     112           0 :   GenerateMinidumpShutdownBlocker() = default;
     113             : 
     114           0 :   NS_IMETHOD BlockShutdown(nsIAsyncShutdownClient* aBarrierClient) override
     115             :   {
     116           0 :     return NS_OK;
     117             :   }
     118             : 
     119           0 :   NS_IMETHOD GetName(nsAString& aName) override
     120             :   {
     121           0 :     aName = NS_LITERAL_STRING("Crash Reporter: blocking on minidump"
     122           0 :                               "generation.");
     123           0 :     return NS_OK;
     124             :   }
     125             : 
     126           0 :   NS_IMETHOD GetState(nsIPropertyBag**) override
     127             :   {
     128           0 :     return NS_OK;
     129             :   }
     130             : 
     131             :   NS_DECL_THREADSAFE_ISUPPORTS
     132             : 
     133             : private:
     134           0 :   virtual ~GenerateMinidumpShutdownBlocker() = default;
     135             : };
     136             : 
     137           0 : NS_IMPL_ISUPPORTS(GenerateMinidumpShutdownBlocker, nsIAsyncShutdownBlocker)
     138             : }
     139             : 
     140           0 : static nsCOMPtr<nsIAsyncShutdownClient> GetShutdownBarrier()
     141             : {
     142           0 :   MOZ_ASSERT(NS_IsMainThread());
     143             : 
     144           0 :   nsCOMPtr<nsIAsyncShutdownService> svc = services::GetAsyncShutdown();
     145           0 :   nsCOMPtr<nsIAsyncShutdownClient> barrier;
     146           0 :   nsresult rv = svc->GetProfileBeforeChange(getter_AddRefs(barrier));
     147             : 
     148           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     149           0 :     return nullptr;
     150             :   }
     151             : 
     152           0 :   return barrier.forget();
     153             : }
     154             : 
     155             : void
     156           0 : CrashReporterHost::GenerateMinidumpAndPair(GeckoChildProcessHost* aChildProcess,
     157             :                                            nsIFile* aMinidumpToPair,
     158             :                                            const nsACString& aPairName,
     159             :                                            std::function<void(bool)>&& aCallback,
     160             :                                            bool aAsync)
     161             : {
     162             :   base::ProcessHandle childHandle;
     163             : #ifdef XP_MACOSX
     164             :   childHandle = aChildProcess->GetChildTask();
     165             : #else
     166           0 :   childHandle = aChildProcess->GetChildProcessHandle();
     167             : #endif
     168             : 
     169           0 :   if (!mCreateMinidumpCallback.IsEmpty()) {
     170           0 :     aCallback(false);
     171           0 :     return;
     172             :   }
     173           0 :   mCreateMinidumpCallback.Init(Move(aCallback), aAsync);
     174             : 
     175           0 :   if (!childHandle) {
     176           0 :     NS_WARNING("Failed to get child process handle.");
     177           0 :     mCreateMinidumpCallback.Invoke(false);
     178           0 :     return;
     179             :   }
     180             : 
     181           0 :   nsCOMPtr<nsIAsyncShutdownBlocker> shutdownBlocker;
     182           0 :   if (aAsync && NS_IsMainThread()) {
     183           0 :     nsCOMPtr<nsIAsyncShutdownClient> barrier = GetShutdownBarrier();
     184           0 :     if (!barrier) {
     185           0 :       mCreateMinidumpCallback.Invoke(false);
     186           0 :       return;
     187             :     }
     188             : 
     189           0 :     shutdownBlocker = new GenerateMinidumpShutdownBlocker();
     190             : 
     191           0 :     nsresult rv = barrier->AddBlocker(shutdownBlocker,
     192           0 :                                       NS_LITERAL_STRING(__FILE__), __LINE__,
     193           0 :                                       NS_LITERAL_STRING("Minidump generation"));
     194           0 :     Unused << NS_WARN_IF(NS_FAILED(rv));
     195             :   }
     196             : 
     197             :   std::function<void(bool)> callback =
     198           0 :     [this, shutdownBlocker](bool aResult) {
     199           0 :       if (aResult &&
     200           0 :           CrashReporter::GetIDFromMinidump(this->mTargetDump, this->mDumpID)) {
     201           0 :         this->mCreateMinidumpCallback.Invoke(true);
     202             :       } else {
     203           0 :         this->mCreateMinidumpCallback.Invoke(false);
     204             :        }
     205             : 
     206           0 :        if (shutdownBlocker) {
     207           0 :          nsCOMPtr<nsIAsyncShutdownClient> barrier = GetShutdownBarrier();
     208           0 :          if (barrier) {
     209           0 :            barrier->RemoveBlocker(shutdownBlocker);
     210             :          }
     211             :       }
     212           0 :     };
     213             : 
     214           0 :   CrashReporter::CreateMinidumpsAndPair(childHandle,
     215             :                                         mThreadId,
     216             :                                         aPairName,
     217             :                                         aMinidumpToPair,
     218           0 :                                         getter_AddRefs(mTargetDump),
     219           0 :                                         Move(callback),
     220           0 :                                         aAsync);
     221             : }
     222             : 
     223             : /* static */ void
     224           0 : CrashReporterHost::NotifyCrashService(GeckoProcessType aProcessType,
     225             :                                       const nsString& aChildDumpID,
     226             :                                       const AnnotationTable* aNotes)
     227             : {
     228           0 :   if (!NS_IsMainThread()) {
     229           0 :     RefPtr<Runnable> runnable = NS_NewRunnableFunction(
     230           0 :       "ipc::CrashReporterHost::NotifyCrashService", [=]() -> void {
     231           0 :         CrashReporterHost::NotifyCrashService(
     232           0 :           aProcessType, aChildDumpID, aNotes);
     233           0 :       });
     234           0 :     RefPtr<nsIThread> mainThread = do_GetMainThread();
     235           0 :     SyncRunnable::DispatchToThread(mainThread, runnable);
     236           0 :     return;
     237             :   }
     238             : 
     239           0 :   MOZ_ASSERT(!aChildDumpID.IsEmpty());
     240             : 
     241             :   nsCOMPtr<nsICrashService> crashService =
     242           0 :     do_GetService("@mozilla.org/crashservice;1");
     243           0 :   if (!crashService) {
     244           0 :     return;
     245             :   }
     246             : 
     247             :   int32_t processType;
     248           0 :   int32_t crashType = nsICrashService::CRASH_TYPE_CRASH;
     249             : 
     250           0 :   nsCString telemetryKey;
     251             : 
     252           0 :   switch (aProcessType) {
     253             :     case GeckoProcessType_Content:
     254           0 :       processType = nsICrashService::PROCESS_TYPE_CONTENT;
     255           0 :       telemetryKey.AssignLiteral("content");
     256           0 :       break;
     257             :     case GeckoProcessType_Plugin: {
     258           0 :       processType = nsICrashService::PROCESS_TYPE_PLUGIN;
     259           0 :       telemetryKey.AssignLiteral("plugin");
     260           0 :       nsAutoCString val;
     261           0 :       if (aNotes->Get(NS_LITERAL_CSTRING("PluginHang"), &val) &&
     262           0 :         val.Equals(NS_LITERAL_CSTRING("1"))) {
     263           0 :         crashType = nsICrashService::CRASH_TYPE_HANG;
     264           0 :         telemetryKey.AssignLiteral("pluginhang");
     265             :       }
     266           0 :       break;
     267             :     }
     268             :     case GeckoProcessType_GMPlugin:
     269           0 :       processType = nsICrashService::PROCESS_TYPE_GMPLUGIN;
     270           0 :       telemetryKey.AssignLiteral("gmplugin");
     271           0 :       break;
     272             :     case GeckoProcessType_GPU:
     273           0 :       processType = nsICrashService::PROCESS_TYPE_GPU;
     274           0 :       telemetryKey.AssignLiteral("gpu");
     275           0 :       break;
     276             :     default:
     277           0 :       NS_ERROR("unknown process type");
     278           0 :       return;
     279             :   }
     280             : 
     281           0 :   nsCOMPtr<nsISupports> promise;
     282           0 :   crashService->AddCrash(processType, crashType, aChildDumpID, getter_AddRefs(promise));
     283           0 :   Telemetry::Accumulate(Telemetry::SUBPROCESS_CRASHES_WITH_DUMP, telemetryKey, 1);
     284             : }
     285             : 
     286             : void
     287           0 : CrashReporterHost::AddNote(const nsCString& aKey, const nsCString& aValue)
     288             : {
     289           0 :   mExtraNotes.Put(aKey, aValue);
     290           0 : }
     291             : #endif
     292             : 
     293             : } // namespace ipc
     294             : } // namespace mozilla

Generated by: LCOV version 1.13