1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/ReportingObserver.h"
#include "mozilla/dom/Report.h"
#include "mozilla/dom/ReportingBinding.h"
#include "nsContentUtils.h"
#include "nsIGlobalObject.h"
#include "nsThreadUtils.h"
namespace mozilla::dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(ReportingObserver)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ReportingObserver)
tmp->Disconnect();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mReports)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallback)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ReportingObserver)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReports)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
/* static */
already_AddRefed<ReportingObserver> ReportingObserver::Constructor(
const GlobalObject& aGlobal, ReportingObserverCallback& aCallback,
const ReportingObserverOptions& aOptions, ErrorResult& aRv) {
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
MOZ_ASSERT(global);
nsTArray<nsString> types;
if (aOptions.mTypes.WasPassed()) {
types = aOptions.mTypes.Value();
}
RefPtr<ReportingObserver> ro =
new ReportingObserver(global, aCallback, types, aOptions.mBuffered);
return ro.forget();
}
ReportingObserver::ReportingObserver(nsIGlobalObject* aGlobal,
ReportingObserverCallback& aCallback,
const nsTArray<nsString>& aTypes,
bool aBuffered)
: mGlobal(aGlobal),
mCallback(&aCallback),
mTypes(aTypes.Clone()),
mBuffered(aBuffered) {
MOZ_ASSERT(aGlobal);
}
ReportingObserver::~ReportingObserver() { Disconnect(); }
JSObject* ReportingObserver::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) {
return ReportingObserver_Binding::Wrap(aCx, this, aGivenProto);
}
void ReportingObserver::Observe() {
mGlobal->RegisterReportingObserver(this, mBuffered);
}
void ReportingObserver::Disconnect() {
if (mGlobal) {
mGlobal->UnregisterReportingObserver(this);
}
}
void ReportingObserver::TakeRecords(nsTArray<RefPtr<Report>>& aRecords) {
mReports.SwapElements(aRecords);
}
namespace {
class ReportRunnable final : public DiscardableRunnable {
public:
explicit ReportRunnable(nsIGlobalObject* aGlobal)
: DiscardableRunnable("ReportRunnable"), mGlobal(aGlobal) {}
// MOZ_CAN_RUN_SCRIPT_BOUNDARY until Runnable::Run is MOZ_CAN_RUN_SCRIPT. See
// bug 1535398.
MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override {
MOZ_KnownLive(mGlobal)->NotifyReportingObservers();
return NS_OK;
}
private:
const nsCOMPtr<nsIGlobalObject> mGlobal;
};
} // namespace
void ReportingObserver::MaybeReport(Report* aReport) {
MOZ_ASSERT(aReport);
if (!mTypes.IsEmpty()) {
nsAutoString type;
aReport->GetType(type);
if (!mTypes.Contains(type)) {
return;
}
}
bool wasEmpty = mReports.IsEmpty();
RefPtr<Report> report = aReport->Clone();
MOZ_ASSERT(report);
if (NS_WARN_IF(!mReports.AppendElement(report, fallible))) {
return;
}
if (!wasEmpty) {
return;
}
RefPtr<ReportRunnable> r = new ReportRunnable(mGlobal);
NS_DispatchToCurrentThread(r);
}
void ReportingObserver::MaybeNotify() {
if (mReports.IsEmpty()) {
return;
}
// Let's take the ownership of the reports.
nsTArray<RefPtr<Report>> list = std::move(mReports);
Sequence<OwningNonNull<Report>> reports;
for (Report* report : list) {
if (NS_WARN_IF(!reports.AppendElement(*report, fallible))) {
return;
}
}
// We should report if this throws exception. But where?
RefPtr<ReportingObserverCallback> callback(mCallback);
callback->Call(reports, *this);
}
void ReportingObserver::ForgetReports() { mReports.Clear(); }
} // namespace mozilla::dom
|