bool
PluginModuleParent::ShouldContinueFromReplyTimeout()
{
#ifdef MOZ_CRASHREPORTER
    CrashReporterParent* crashReporter = CrashReporter();
    if (crashReporter->GeneratePairedMinidump(this)) {
        mBrowserDumpID = crashReporter->ParentDumpID();
        mPluginDumpID = crashReporter->ChildDumpID();
        PLUGIN_LOG_DEBUG(
                ("generated paired browser/plugin minidumps: %s/%s (ID=%s)",
                 NS_ConvertUTF16toUTF8(mBrowserDumpID).get(),
                 NS_ConvertUTF16toUTF8(mPluginDumpID).get(),
                 NS_ConvertUTF16toUTF8(crashReporter->HangID()).get()));
    } else {
        NS_WARNING("failed to capture paired minidumps from hang");
    }
#endif

    // this must run before the error notification from the channel,
    // or not at all
    MessageLoop::current()->PostTask(
        FROM_HERE,
        mTaskFactory.NewRunnableMethod(
            &PluginModuleParent::CleanupFromTimeout));

    if (!KillProcess(OtherProcess(), 1, false))
        NS_WARNING("failed to kill subprocess!");

    return false;
}
bool
PluginModuleParent::ShouldContinueFromReplyTimeout()
{
#ifdef MOZ_CRASHREPORTER
    CrashReporterParent* crashReporter = CrashReporter();
    crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("PluginHang"),
                                       NS_LITERAL_CSTRING("1"));
    if (crashReporter->GeneratePairedMinidump(this)) {
        mPluginDumpID = crashReporter->ChildDumpID();
        PLUGIN_LOG_DEBUG(
                ("generated paired browser/plugin minidumps: %s)",
                 NS_ConvertUTF16toUTF8(mPluginDumpID).get()));

        crashReporter->AnnotateCrashReport(
            NS_LITERAL_CSTRING("additional_minidumps"),
            NS_LITERAL_CSTRING("browser"));

        // TODO: collect Flash minidumps here
    } else {
        NS_WARNING("failed to capture paired minidumps from hang");
    }
#endif

#ifdef XP_WIN
    // collect cpu usage for plugin processes

    InfallibleTArray<base::ProcessHandle> processHandles;
    base::ProcessHandle handle;

    processHandles.AppendElement(OtherProcess());
#ifdef MOZ_CRASHREPORTER_INJECTOR
    if (mFlashProcess1 && base::OpenProcessHandle(mFlashProcess1, &handle)) {
      processHandles.AppendElement(handle);
    }
    if (mFlashProcess2 && base::OpenProcessHandle(mFlashProcess2, &handle)) {
      processHandles.AppendElement(handle);
    }
#endif

    if (!GetProcessCpuUsage(processHandles, mPluginCpuUsageOnHang)) {
      mPluginCpuUsageOnHang.Clear();
    }
#endif

    // this must run before the error notification from the channel,
    // or not at all
    MessageLoop::current()->PostTask(
        FROM_HERE,
        mTaskFactory.NewRunnableMethod(
            &PluginModuleParent::CleanupFromTimeout));

    if (!KillProcess(OtherProcess(), 1, false))
        NS_WARNING("failed to kill subprocess!");

    return false;
}
void
PluginModuleParent::ActorDestroy(ActorDestroyReason why)
{
    switch (why) {
    case AbnormalShutdown: {
#ifdef MOZ_CRASHREPORTER
        CrashReporterParent* crashReporter = CrashReporter();

        CrashReporter::AnnotationTable notes;
        notes.Init(4);
        WriteExtraDataForMinidump(notes);
        
        if (!mPluginDumpID.IsEmpty() && !mBrowserDumpID.IsEmpty()) {
            crashReporter->GenerateHangCrashReport(&notes);
        }
        else if (!mPluginDumpID.IsEmpty()) {
            // Nothing to do, we've already written this minidump in
            // PluginModuleParent::OnCrash
        }
        else if (crashReporter->GenerateCrashReport(this, &notes)) {
            mPluginDumpID = crashReporter->ChildDumpID();
            PLUGIN_LOG_DEBUG(("got child minidump: %s",
                              NS_ConvertUTF16toUTF8(mPluginDumpID).get()));
        }
        else {
            NS_WARNING("[PluginModuleParent::ActorDestroy] abnormal shutdown without minidump!");
        }
#endif

        mShutdown = true;
        // Defer the PluginCrashed method so that we don't re-enter
        // and potentially modify the actor child list while enumerating it.
        if (mPlugin)
            MessageLoop::current()->PostTask(
                FROM_HERE,
                mTaskFactory.NewRunnableMethod(
                    &PluginModuleParent::NotifyPluginCrashed));
        break;
    }
    case NormalShutdown:
        mShutdown = true;
        break;

    default:
        NS_ERROR("Unexpected shutdown reason for toplevel actor.");
    }
}
void
ContentParent::ActorDestroy(ActorDestroyReason why)
{
    nsCOMPtr<nsIThreadObserver>
        kungFuDeathGrip(static_cast<nsIThreadObserver*>(this));
    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
    if (obs) {
        obs->RemoveObserver(static_cast<nsIObserver*>(this), "xpcom-shutdown");
        obs->RemoveObserver(static_cast<nsIObserver*>(this), "memory-pressure");
        obs->RemoveObserver(static_cast<nsIObserver*>(this), "child-memory-reporter-request");
        obs->RemoveObserver(static_cast<nsIObserver*>(this), NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC);
        obs->RemoveObserver(static_cast<nsIObserver*>(this), "child-gc-request");
        obs->RemoveObserver(static_cast<nsIObserver*>(this), "child-cc-request");
#ifdef ACCESSIBILITY
        obs->RemoveObserver(static_cast<nsIObserver*>(this), "a11y-init-or-shutdown");
#endif
    }

    mMessageManager->Disconnect();

    // clear the child memory reporters
    InfallibleTArray<MemoryReport> empty;
    SetChildMemoryReporters(empty);

    // remove the global remote preferences observers
    nsCOMPtr<nsIPrefBranch2> prefs 
            (do_GetService(NS_PREFSERVICE_CONTRACTID));
    if (prefs) { 
        prefs->RemoveObserver("", this);
    }

    RecvRemoveGeolocationListener();
    RecvRemoveDeviceMotionListener();

    nsCOMPtr<nsIThreadInternal>
        threadInt(do_QueryInterface(NS_GetCurrentThread()));
    if (threadInt)
        threadInt->RemoveObserver(this);
    if (mRunToCompletionDepth)
        mRunToCompletionDepth = 0;

    if (gContentParents) {
        gContentParents->RemoveElement(this);
        if (!gContentParents->Length()) {
            delete gContentParents;
            gContentParents = NULL;
        }
    }

    mIsAlive = false;

    if (obs) {
        nsRefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
        props->Init();

        if (AbnormalShutdown == why) {
            props->SetPropertyAsBool(NS_LITERAL_STRING("abnormal"), true);

#ifdef MOZ_CRASHREPORTER
            MOZ_ASSERT(ManagedPCrashReporterParent().Length() > 0);
            CrashReporterParent* crashReporter =
                    static_cast<CrashReporterParent*>(ManagedPCrashReporterParent()[0]);

            crashReporter->GenerateCrashReport(this, NULL);
 
            nsAutoString dumpID(crashReporter->ChildDumpID());
            props->SetPropertyAsAString(NS_LITERAL_STRING("dumpID"), dumpID);
#endif

            obs->NotifyObservers((nsIPropertyBag2*) props, "ipc:content-shutdown", nsnull);
        }
    }

    MessageLoop::current()->
        PostTask(FROM_HERE,
                 NewRunnableFunction(DelayedDeleteSubprocess, mSubprocess));
    mSubprocess = NULL;

    // IPDL rules require actors to live on past ActorDestroy, but it
    // may be that the kungFuDeathGrip above is the last reference to
    // |this|.  If so, when we go out of scope here, we're deleted and
    // all hell breaks loose.
    //
    // This runnable ensures that a reference to |this| lives on at
    // least until after the current task finishes running.
    NS_DispatchToCurrentThread(new DelayedDeleteContentParentTask(this));
}