2017-10-26 22:08:41 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2015-06-17 18:12:23 +00:00
|
|
|
/* 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 "ChromeUtils.h"
|
|
|
|
|
2018-09-05 09:25:42 +00:00
|
|
|
#include "js/CharacterEncoding.h"
|
2018-08-20 14:45:44 +00:00
|
|
|
#include "js/SavedFrameAPI.h"
|
2017-08-18 18:10:10 +00:00
|
|
|
#include "jsfriendapi.h"
|
|
|
|
#include "WrapperFactory.h"
|
|
|
|
|
2016-03-22 19:09:04 +00:00
|
|
|
#include "mozilla/Base64.h"
|
2015-06-17 18:12:23 +00:00
|
|
|
#include "mozilla/BasePrincipal.h"
|
2017-11-16 09:48:45 +00:00
|
|
|
#include "mozilla/CycleCollectedJSRuntime.h"
|
2019-08-15 19:28:16 +00:00
|
|
|
#include "mozilla/IntentionalCrash.h"
|
2018-07-05 14:32:03 +00:00
|
|
|
#include "mozilla/PerformanceMetricsCollector.h"
|
2019-05-21 19:01:31 +00:00
|
|
|
#include "mozilla/PerfStats.h"
|
2018-06-26 08:43:16 +00:00
|
|
|
#include "mozilla/Preferences.h"
|
2019-02-23 18:07:59 +00:00
|
|
|
#include "mozilla/ProcInfo.h"
|
|
|
|
#include "mozilla/RDDProcessManager.h"
|
2019-01-17 18:18:31 +00:00
|
|
|
#include "mozilla/ResultExtensions.h"
|
2017-09-24 05:12:32 +00:00
|
|
|
#include "mozilla/TimeStamp.h"
|
2018-08-29 02:00:00 +00:00
|
|
|
#include "mozilla/dom/BrowsingContext.h"
|
2020-03-20 09:11:32 +00:00
|
|
|
#include "mozilla/dom/ContentChild.h"
|
2019-02-23 18:07:59 +00:00
|
|
|
#include "mozilla/dom/ContentParent.h"
|
2017-09-24 05:12:32 +00:00
|
|
|
#include "mozilla/dom/IdleDeadline.h"
|
2020-06-25 20:35:18 +00:00
|
|
|
#include "mozilla/dom/InProcessChild.h"
|
2020-04-30 16:42:53 +00:00
|
|
|
#include "mozilla/dom/JSActorService.h"
|
2019-12-21 00:10:13 +00:00
|
|
|
#include "mozilla/dom/MediaControlUtils.h"
|
|
|
|
#include "mozilla/dom/MediaControlService.h"
|
2020-03-05 19:43:50 +00:00
|
|
|
#include "mozilla/dom/MediaMetadata.h"
|
|
|
|
#include "mozilla/dom/MediaSessionBinding.h"
|
2020-04-04 14:48:35 +00:00
|
|
|
#include "mozilla/dom/Performance.h"
|
2019-01-17 18:18:31 +00:00
|
|
|
#include "mozilla/dom/Promise.h"
|
2018-12-01 20:26:10 +00:00
|
|
|
#include "mozilla/dom/ReportingHeader.h"
|
2017-10-12 12:50:23 +00:00
|
|
|
#include "mozilla/dom/UnionTypes.h"
|
2017-09-24 05:12:32 +00:00
|
|
|
#include "mozilla/dom/WindowBinding.h" // For IdleRequestCallback/Options
|
2020-04-29 09:02:05 +00:00
|
|
|
#include "mozilla/dom/WorkerPrivate.h"
|
2019-02-23 18:07:59 +00:00
|
|
|
#include "mozilla/gfx/GPUProcessManager.h"
|
2019-06-21 01:33:47 +00:00
|
|
|
#include "mozilla/ipc/GeckoChildProcessHost.h"
|
2019-01-30 12:43:34 +00:00
|
|
|
#include "mozilla/net/UrlClassifierFeatureFactory.h"
|
2019-06-07 19:56:51 +00:00
|
|
|
#include "mozilla/net/SocketProcessHost.h"
|
2018-06-26 08:43:16 +00:00
|
|
|
#include "IOActivityMonitor.h"
|
2019-02-23 18:07:59 +00:00
|
|
|
#include "nsIOService.h"
|
2017-09-24 05:12:32 +00:00
|
|
|
#include "nsThreadUtils.h"
|
2017-12-16 05:30:25 +00:00
|
|
|
#include "mozJSComponentLoader.h"
|
|
|
|
#include "GeckoProfiler.h"
|
2020-04-04 14:48:35 +00:00
|
|
|
#ifdef MOZ_GECKO_PROFILER
|
|
|
|
# include "ProfilerMarkerPayload.h"
|
|
|
|
#endif
|
2019-01-03 15:43:06 +00:00
|
|
|
#include "nsIException.h"
|
2015-06-17 18:12:23 +00:00
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
namespace dom {
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::NondeterministicGetWeakMapKeys(
|
2017-11-08 05:25:33 +00:00
|
|
|
GlobalObject& aGlobal, JS::Handle<JS::Value> aMap,
|
|
|
|
JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv) {
|
2015-11-11 11:55:00 +00:00
|
|
|
if (!aMap.isObject()) {
|
|
|
|
aRetval.setUndefined();
|
|
|
|
} else {
|
|
|
|
JSContext* cx = aGlobal.Context();
|
|
|
|
JS::Rooted<JSObject*> objRet(cx);
|
|
|
|
JS::Rooted<JSObject*> mapObj(cx, &aMap.toObject());
|
|
|
|
if (!JS_NondeterministicGetWeakMapKeys(cx, mapObj, &objRet)) {
|
|
|
|
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
} else {
|
|
|
|
aRetval.set(objRet ? JS::ObjectValue(*objRet) : JS::UndefinedValue());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::NondeterministicGetWeakSetKeys(
|
2017-11-08 05:25:33 +00:00
|
|
|
GlobalObject& aGlobal, JS::Handle<JS::Value> aSet,
|
|
|
|
JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv) {
|
2015-11-16 14:50:00 +00:00
|
|
|
if (!aSet.isObject()) {
|
|
|
|
aRetval.setUndefined();
|
|
|
|
} else {
|
|
|
|
JSContext* cx = aGlobal.Context();
|
|
|
|
JS::Rooted<JSObject*> objRet(cx);
|
|
|
|
JS::Rooted<JSObject*> setObj(cx, &aSet.toObject());
|
|
|
|
if (!JS_NondeterministicGetWeakSetKeys(cx, setObj, &objRet)) {
|
|
|
|
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
} else {
|
|
|
|
aRetval.set(objRet ? JS::ObjectValue(*objRet) : JS::UndefinedValue());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::Base64URLEncode(GlobalObject& aGlobal,
|
|
|
|
const ArrayBufferViewOrArrayBuffer& aSource,
|
|
|
|
const Base64URLEncodeOptions& aOptions,
|
|
|
|
nsACString& aResult, ErrorResult& aRv) {
|
2016-03-22 19:09:04 +00:00
|
|
|
size_t length = 0;
|
|
|
|
uint8_t* data = nullptr;
|
|
|
|
if (aSource.IsArrayBuffer()) {
|
|
|
|
const ArrayBuffer& buffer = aSource.GetAsArrayBuffer();
|
2020-01-23 03:22:06 +00:00
|
|
|
buffer.ComputeState();
|
2016-03-22 19:09:04 +00:00
|
|
|
length = buffer.Length();
|
|
|
|
data = buffer.Data();
|
|
|
|
} else if (aSource.IsArrayBufferView()) {
|
|
|
|
const ArrayBufferView& view = aSource.GetAsArrayBufferView();
|
2020-01-23 03:22:06 +00:00
|
|
|
view.ComputeState();
|
2016-03-22 19:09:04 +00:00
|
|
|
length = view.Length();
|
|
|
|
data = view.Data();
|
|
|
|
} else {
|
|
|
|
MOZ_CRASH("Uninitialized union: expected buffer or view");
|
|
|
|
}
|
|
|
|
|
2016-04-22 14:41:58 +00:00
|
|
|
auto paddingPolicy = aOptions.mPad ? Base64URLEncodePaddingPolicy::Include
|
|
|
|
: Base64URLEncodePaddingPolicy::Omit;
|
|
|
|
nsresult rv = mozilla::Base64URLEncode(length, data, paddingPolicy, aResult);
|
2016-03-22 19:09:04 +00:00
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
aResult.Truncate();
|
|
|
|
aRv.Throw(rv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::Base64URLDecode(GlobalObject& aGlobal,
|
|
|
|
const nsACString& aString,
|
|
|
|
const Base64URLDecodeOptions& aOptions,
|
|
|
|
JS::MutableHandle<JSObject*> aRetval,
|
|
|
|
ErrorResult& aRv) {
|
2016-04-22 14:41:58 +00:00
|
|
|
Base64URLDecodePaddingPolicy paddingPolicy;
|
|
|
|
switch (aOptions.mPadding) {
|
|
|
|
case Base64URLDecodePadding::Require:
|
|
|
|
paddingPolicy = Base64URLDecodePaddingPolicy::Require;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Base64URLDecodePadding::Ignore:
|
|
|
|
paddingPolicy = Base64URLDecodePaddingPolicy::Ignore;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Base64URLDecodePadding::Reject:
|
|
|
|
paddingPolicy = Base64URLDecodePaddingPolicy::Reject;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
aRv.Throw(NS_ERROR_INVALID_ARG);
|
|
|
|
return;
|
|
|
|
}
|
2016-03-22 19:09:04 +00:00
|
|
|
FallibleTArray<uint8_t> data;
|
2016-04-22 14:41:58 +00:00
|
|
|
nsresult rv = mozilla::Base64URLDecode(aString, paddingPolicy, data);
|
2016-03-22 19:09:04 +00:00
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
aRv.Throw(rv);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::Rooted<JSObject*> buffer(
|
|
|
|
aGlobal.Context(),
|
|
|
|
ArrayBuffer::Create(aGlobal.Context(), data.Length(), data.Elements()));
|
|
|
|
if (NS_WARN_IF(!buffer)) {
|
|
|
|
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
aRetval.set(buffer);
|
|
|
|
}
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::ReleaseAssert(GlobalObject& aGlobal, bool aCondition,
|
|
|
|
const nsAString& aMessage) {
|
2019-01-03 15:43:06 +00:00
|
|
|
// If the condition didn't fail, which is the likely case, immediately return.
|
|
|
|
if (MOZ_LIKELY(aCondition)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Extract the current stack from the JS runtime to embed in the crash reason.
|
|
|
|
nsAutoString filename;
|
|
|
|
uint32_t lineNo = 0;
|
|
|
|
|
|
|
|
if (nsCOMPtr<nsIStackFrame> location = GetCurrentJSStack(1)) {
|
|
|
|
location->GetFilename(aGlobal.Context(), filename);
|
|
|
|
lineNo = location->GetLineNumber(aGlobal.Context());
|
|
|
|
} else {
|
2020-07-01 08:29:29 +00:00
|
|
|
filename.Assign(u"<unknown>"_ns);
|
2019-01-03 15:43:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Convert to utf-8 for adding as the MozCrashReason.
|
|
|
|
NS_ConvertUTF16toUTF8 filenameUtf8(filename);
|
|
|
|
NS_ConvertUTF16toUTF8 messageUtf8(aMessage);
|
|
|
|
|
|
|
|
// Actually crash.
|
|
|
|
MOZ_CRASH_UNSAFE_PRINTF("Failed ChromeUtils.releaseAssert(\"%s\") @ %s:%u",
|
|
|
|
messageUtf8.get(), filenameUtf8.get(), lineNo);
|
|
|
|
}
|
|
|
|
|
2020-04-04 14:48:35 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::AddProfilerMarker(
|
|
|
|
GlobalObject& aGlobal, const nsACString& aName,
|
|
|
|
const Optional<DOMHighResTimeStamp>& aStartTime,
|
|
|
|
const Optional<nsACString>& aText) {
|
|
|
|
#ifdef MOZ_GECKO_PROFILER
|
|
|
|
const nsCString& name = PromiseFlatCString(aName);
|
|
|
|
|
|
|
|
if (!aText.WasPassed() && !aStartTime.WasPassed()) {
|
|
|
|
profiler_add_js_marker(name.get());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TimeStamp now = mozilla::TimeStamp::NowUnfuzzed();
|
|
|
|
TimeStamp startTime = now;
|
|
|
|
if (aStartTime.WasPassed()) {
|
|
|
|
RefPtr<Performance> performance;
|
|
|
|
|
|
|
|
if (NS_IsMainThread()) {
|
|
|
|
nsCOMPtr<nsPIDOMWindowInner> ownerWindow =
|
|
|
|
do_QueryInterface(aGlobal.GetAsSupports());
|
|
|
|
if (ownerWindow) {
|
|
|
|
performance = ownerWindow->GetPerformance();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
JSContext* cx = aGlobal.Context();
|
|
|
|
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
|
|
|
|
if (workerPrivate) {
|
|
|
|
performance = workerPrivate->GlobalScope()->GetPerformance();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (performance) {
|
|
|
|
startTime = performance->CreationTimeStamp() +
|
|
|
|
TimeDuration::FromMilliseconds(aStartTime.Value());
|
|
|
|
} else {
|
|
|
|
startTime = TimeStamp::ProcessCreation() +
|
|
|
|
TimeDuration::FromMilliseconds(aStartTime.Value());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aText.WasPassed()) {
|
|
|
|
profiler_add_text_marker(name.get(), aText.Value(),
|
|
|
|
JS::ProfilingCategoryPair::JS, startTime, now);
|
|
|
|
} else {
|
|
|
|
profiler_add_marker(name.get(), JS::ProfilingCategoryPair::JS,
|
|
|
|
TimingMarkerPayload(startTime, now));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::WaiveXrays(GlobalObject& aGlobal, JS::HandleValue aVal,
|
|
|
|
JS::MutableHandleValue aRetval, ErrorResult& aRv) {
|
2017-08-18 18:10:10 +00:00
|
|
|
JS::RootedValue value(aGlobal.Context(), aVal);
|
|
|
|
if (!xpc::WrapperFactory::WaiveXrayAndWrap(aGlobal.Context(), &value)) {
|
|
|
|
aRv.NoteJSContextException(aGlobal.Context());
|
|
|
|
} else {
|
|
|
|
aRetval.set(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::UnwaiveXrays(GlobalObject& aGlobal, JS::HandleValue aVal,
|
|
|
|
JS::MutableHandleValue aRetval,
|
|
|
|
ErrorResult& aRv) {
|
2017-08-18 18:10:10 +00:00
|
|
|
if (!aVal.isObject()) {
|
|
|
|
aRetval.set(aVal);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::RootedObject obj(aGlobal.Context(),
|
|
|
|
js::UncheckedUnwrap(&aVal.toObject()));
|
|
|
|
if (!JS_WrapObject(aGlobal.Context(), &obj)) {
|
|
|
|
aRv.NoteJSContextException(aGlobal.Context());
|
|
|
|
} else {
|
|
|
|
aRetval.setObject(*obj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::GetClassName(GlobalObject& aGlobal, JS::HandleObject aObj,
|
|
|
|
bool aUnwrap, nsAString& aRetval) {
|
2017-08-18 18:10:10 +00:00
|
|
|
JS::RootedObject obj(aGlobal.Context(), aObj);
|
|
|
|
if (aUnwrap) {
|
|
|
|
obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
|
|
|
|
}
|
|
|
|
|
|
|
|
aRetval =
|
|
|
|
NS_ConvertUTF8toUTF16(nsDependentCString(js::GetObjectClass(obj)->name));
|
|
|
|
}
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::ShallowClone(GlobalObject& aGlobal, JS::HandleObject aObj,
|
|
|
|
JS::HandleObject aTarget,
|
|
|
|
JS::MutableHandleObject aRetval,
|
|
|
|
ErrorResult& aRv) {
|
2017-08-24 20:33:40 +00:00
|
|
|
JSContext* cx = aGlobal.Context();
|
|
|
|
|
|
|
|
auto cleanup = MakeScopeExit([&]() { aRv.NoteJSContextException(cx); });
|
|
|
|
|
|
|
|
JS::Rooted<JS::IdVector> ids(cx, JS::IdVector(cx));
|
2019-03-26 13:58:20 +00:00
|
|
|
JS::RootedVector<JS::Value> values(cx);
|
2019-03-13 12:33:15 +00:00
|
|
|
JS::RootedVector<jsid> valuesIds(cx);
|
2017-08-24 20:33:40 +00:00
|
|
|
|
|
|
|
{
|
2019-02-02 03:24:22 +00:00
|
|
|
// cx represents our current Realm, so it makes sense to use it for the
|
|
|
|
// CheckedUnwrapDynamic call. We do want CheckedUnwrapDynamic, in case
|
|
|
|
// someone is shallow-cloning a Window.
|
|
|
|
JS::RootedObject obj(cx, js::CheckedUnwrapDynamic(aObj, cx));
|
2017-08-24 20:33:40 +00:00
|
|
|
if (!obj) {
|
|
|
|
js::ReportAccessDenied(cx);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (js::IsScriptedProxy(obj)) {
|
|
|
|
JS_ReportErrorASCII(cx, "Shallow cloning a proxy object is not allowed");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-08-02 06:48:40 +00:00
|
|
|
JSAutoRealm ar(cx, obj);
|
2017-08-24 20:33:40 +00:00
|
|
|
|
2018-12-17 15:19:27 +00:00
|
|
|
if (!JS_Enumerate(cx, obj, &ids) || !values.reserve(ids.length()) ||
|
|
|
|
!valuesIds.reserve(ids.length())) {
|
2017-08-24 20:33:40 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::Rooted<JS::PropertyDescriptor> desc(cx);
|
|
|
|
JS::RootedId id(cx);
|
|
|
|
for (jsid idVal : ids) {
|
|
|
|
id = idVal;
|
|
|
|
if (!JS_GetOwnPropertyDescriptorById(cx, obj, id, &desc)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (desc.setter() || desc.getter()) {
|
|
|
|
continue;
|
|
|
|
}
|
2018-12-17 15:19:27 +00:00
|
|
|
valuesIds.infallibleAppend(id);
|
2017-08-24 20:33:40 +00:00
|
|
|
values.infallibleAppend(desc.value());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::RootedObject obj(cx);
|
|
|
|
{
|
2018-08-02 06:48:40 +00:00
|
|
|
Maybe<JSAutoRealm> ar;
|
2017-08-24 20:33:40 +00:00
|
|
|
if (aTarget) {
|
2019-02-02 03:24:22 +00:00
|
|
|
// Our target could be anything, so we want CheckedUnwrapDynamic here.
|
|
|
|
// "cx" represents the current Realm when we were called from bindings, so
|
|
|
|
// we can just use that.
|
|
|
|
JS::RootedObject target(cx, js::CheckedUnwrapDynamic(aTarget, cx));
|
2017-08-24 20:33:40 +00:00
|
|
|
if (!target) {
|
|
|
|
js::ReportAccessDenied(cx);
|
|
|
|
return;
|
|
|
|
}
|
2018-05-16 08:53:16 +00:00
|
|
|
ar.emplace(cx, target);
|
2017-08-24 20:33:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
obj = JS_NewPlainObject(cx);
|
|
|
|
if (!obj) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::RootedValue value(cx);
|
|
|
|
JS::RootedId id(cx);
|
2018-12-17 15:19:27 +00:00
|
|
|
for (uint32_t i = 0; i < valuesIds.length(); i++) {
|
|
|
|
id = valuesIds[i];
|
2017-08-24 20:33:40 +00:00
|
|
|
value = values[i];
|
|
|
|
|
|
|
|
JS_MarkCrossZoneId(cx, id);
|
|
|
|
if (!JS_WrapValue(cx, &value) ||
|
|
|
|
!JS_SetPropertyById(cx, obj, id, value)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aTarget && !JS_WrapObject(cx, &obj)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup.release();
|
|
|
|
aRetval.set(obj);
|
|
|
|
}
|
|
|
|
|
2017-09-24 05:12:32 +00:00
|
|
|
namespace {
|
|
|
|
class IdleDispatchRunnable final : public IdleRunnable,
|
|
|
|
public nsITimerCallback {
|
|
|
|
public:
|
|
|
|
NS_DECL_ISUPPORTS_INHERITED
|
2018-11-30 10:46:48 +00:00
|
|
|
|
2017-09-24 05:12:32 +00:00
|
|
|
IdleDispatchRunnable(nsIGlobalObject* aParent, IdleRequestCallback& aCallback)
|
|
|
|
: IdleRunnable("ChromeUtils::IdleDispatch"),
|
|
|
|
mCallback(&aCallback),
|
|
|
|
mParent(aParent) {}
|
2018-11-30 10:46:48 +00:00
|
|
|
|
2019-03-19 07:22:05 +00:00
|
|
|
// 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 {
|
2017-09-24 05:12:32 +00:00
|
|
|
if (mCallback) {
|
|
|
|
CancelTimer();
|
|
|
|
|
|
|
|
auto deadline = mDeadline - TimeStamp::ProcessCreation();
|
|
|
|
|
|
|
|
ErrorResult rv;
|
|
|
|
RefPtr<IdleDeadline> idleDeadline =
|
|
|
|
new IdleDeadline(mParent, mTimedOut, deadline.ToMilliseconds());
|
|
|
|
|
2020-02-13 14:38:48 +00:00
|
|
|
RefPtr<IdleRequestCallback> callback(std::move(mCallback));
|
2019-03-19 07:22:05 +00:00
|
|
|
MOZ_ASSERT(!mCallback);
|
|
|
|
callback->Call(*idleDeadline, "ChromeUtils::IdleDispatch handler");
|
2017-09-24 05:12:32 +00:00
|
|
|
mParent = nullptr;
|
|
|
|
}
|
|
|
|
return NS_OK;
|
2018-11-30 10:46:48 +00:00
|
|
|
}
|
2017-09-24 05:12:32 +00:00
|
|
|
|
|
|
|
void SetDeadline(TimeStamp aDeadline) override { mDeadline = aDeadline; }
|
|
|
|
|
|
|
|
NS_IMETHOD Notify(nsITimer* aTimer) override {
|
|
|
|
mTimedOut = true;
|
|
|
|
SetDeadline(TimeStamp::Now());
|
|
|
|
return Run();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetTimer(uint32_t aDelay, nsIEventTarget* aTarget) override {
|
|
|
|
MOZ_ASSERT(aTarget);
|
|
|
|
MOZ_ASSERT(!mTimer);
|
2017-10-16 06:15:40 +00:00
|
|
|
NS_NewTimerWithCallback(getter_AddRefs(mTimer), this, aDelay,
|
|
|
|
nsITimer::TYPE_ONE_SHOT, aTarget);
|
2017-09-24 05:12:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual ~IdleDispatchRunnable() { CancelTimer(); }
|
|
|
|
|
|
|
|
private:
|
|
|
|
void CancelTimer() {
|
|
|
|
if (mTimer) {
|
|
|
|
mTimer->Cancel();
|
|
|
|
mTimer = nullptr;
|
|
|
|
}
|
2018-11-30 10:46:48 +00:00
|
|
|
}
|
2017-09-24 05:12:32 +00:00
|
|
|
|
|
|
|
RefPtr<IdleRequestCallback> mCallback;
|
|
|
|
nsCOMPtr<nsIGlobalObject> mParent;
|
|
|
|
|
|
|
|
nsCOMPtr<nsITimer> mTimer;
|
|
|
|
|
|
|
|
TimeStamp mDeadline{};
|
|
|
|
bool mTimedOut = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS_INHERITED(IdleDispatchRunnable, IdleRunnable,
|
|
|
|
nsITimerCallback)
|
|
|
|
} // anonymous namespace
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::IdleDispatch(const GlobalObject& aGlobal,
|
|
|
|
IdleRequestCallback& aCallback,
|
|
|
|
const IdleRequestOptions& aOptions,
|
|
|
|
ErrorResult& aRv) {
|
2017-09-24 05:12:32 +00:00
|
|
|
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
|
|
|
MOZ_ASSERT(global);
|
|
|
|
|
|
|
|
auto runnable = MakeRefPtr<IdleDispatchRunnable>(global, aCallback);
|
|
|
|
|
|
|
|
if (aOptions.mTimeout.WasPassed()) {
|
2019-01-26 17:18:05 +00:00
|
|
|
aRv = NS_DispatchToCurrentThreadQueue(
|
|
|
|
runnable.forget(), aOptions.mTimeout.Value(), EventQueuePriority::Idle);
|
2017-09-24 05:12:32 +00:00
|
|
|
} else {
|
2019-01-26 17:18:05 +00:00
|
|
|
aRv = NS_DispatchToCurrentThreadQueue(runnable.forget(),
|
|
|
|
EventQueuePriority::Idle);
|
2017-09-24 05:12:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::Import(const GlobalObject& aGlobal,
|
|
|
|
const nsAString& aResourceURI,
|
|
|
|
const Optional<JS::Handle<JSObject*>>& aTargetObj,
|
|
|
|
JS::MutableHandle<JSObject*> aRetval,
|
|
|
|
ErrorResult& aRv) {
|
2017-12-16 05:30:25 +00:00
|
|
|
RefPtr<mozJSComponentLoader> moduleloader = mozJSComponentLoader::Get();
|
|
|
|
MOZ_ASSERT(moduleloader);
|
|
|
|
|
|
|
|
NS_ConvertUTF16toUTF8 registryLocation(aResourceURI);
|
|
|
|
|
2019-11-11 20:27:44 +00:00
|
|
|
AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING_NONSENSITIVE("ChromeUtils::Import",
|
|
|
|
OTHER, registryLocation);
|
2017-12-16 05:30:25 +00:00
|
|
|
|
|
|
|
JSContext* cx = aGlobal.Context();
|
|
|
|
|
2019-01-17 18:18:31 +00:00
|
|
|
bool ignoreExports = aTargetObj.WasPassed() && !aTargetObj.Value();
|
|
|
|
|
|
|
|
JS::RootedObject global(cx);
|
|
|
|
JS::RootedObject exports(cx);
|
|
|
|
nsresult rv = moduleloader->Import(cx, registryLocation, &global, &exports,
|
|
|
|
ignoreExports);
|
2017-12-16 05:30:25 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
aRv.Throw(rv);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Import() on the component loader can return NS_OK while leaving an
|
|
|
|
// exception on the JSContext. Check for that case.
|
|
|
|
if (JS_IsExceptionPending(cx)) {
|
|
|
|
aRv.NoteJSContextException(cx);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-01-17 18:18:31 +00:00
|
|
|
if (ignoreExports) {
|
|
|
|
// Since we're ignoring exported symbols, return the module global rather
|
|
|
|
// than an exports object.
|
|
|
|
//
|
|
|
|
// Note: This behavior is deprecated, since it is incompatible with ES6
|
|
|
|
// module semantics, which don't include any such global object.
|
|
|
|
if (!JS_WrapObject(cx, &global)) {
|
|
|
|
aRv.Throw(NS_ERROR_FAILURE);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
aRetval.set(global);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aTargetObj.WasPassed()) {
|
|
|
|
if (!JS_AssignObject(cx, aTargetObj.Value(), exports)) {
|
|
|
|
aRv.Throw(NS_ERROR_FAILURE);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!JS_WrapObject(cx, &exports)) {
|
|
|
|
aRv.Throw(NS_ERROR_FAILURE);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
aRetval.set(exports);
|
2017-12-16 05:30:25 +00:00
|
|
|
}
|
|
|
|
|
2018-01-18 03:20:16 +00:00
|
|
|
namespace module_getter {
|
|
|
|
static const size_t SLOT_ID = 0;
|
|
|
|
static const size_t SLOT_URI = 1;
|
2018-11-30 10:46:48 +00:00
|
|
|
|
2018-01-18 03:20:16 +00:00
|
|
|
static bool ExtractArgs(JSContext* aCx, JS::CallArgs& aArgs,
|
|
|
|
JS::MutableHandle<JSObject*> aCallee,
|
|
|
|
JS::MutableHandle<JSObject*> aThisObj,
|
|
|
|
JS::MutableHandle<jsid> aId) {
|
|
|
|
aCallee.set(&aArgs.callee());
|
2018-11-30 10:46:48 +00:00
|
|
|
|
2018-01-18 03:20:16 +00:00
|
|
|
JS::Handle<JS::Value> thisv = aArgs.thisv();
|
|
|
|
if (!thisv.isObject()) {
|
|
|
|
JS_ReportErrorASCII(aCx, "Invalid target object");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
aThisObj.set(&thisv.toObject());
|
|
|
|
|
|
|
|
JS::Rooted<JS::Value> id(aCx,
|
|
|
|
js::GetFunctionNativeReserved(aCallee, SLOT_ID));
|
|
|
|
MOZ_ALWAYS_TRUE(JS_ValueToId(aCx, id, aId));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool ModuleGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
|
|
|
|
JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
|
|
|
|
|
|
|
|
JS::Rooted<JSObject*> callee(aCx);
|
|
|
|
JS::Rooted<JSObject*> thisObj(aCx);
|
|
|
|
JS::Rooted<jsid> id(aCx);
|
|
|
|
if (!ExtractArgs(aCx, args, &callee, &thisObj, &id)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::Rooted<JSString*> moduleURI(
|
|
|
|
aCx, js::GetFunctionNativeReserved(callee, SLOT_URI).toString());
|
2018-09-05 09:25:42 +00:00
|
|
|
JS::UniqueChars bytes = JS_EncodeStringToUTF8(aCx, moduleURI);
|
|
|
|
if (!bytes) {
|
2018-01-18 03:20:16 +00:00
|
|
|
return false;
|
|
|
|
}
|
2018-09-05 09:25:42 +00:00
|
|
|
nsDependentCString uri(bytes.get());
|
2018-01-18 03:20:16 +00:00
|
|
|
|
|
|
|
RefPtr<mozJSComponentLoader> moduleloader = mozJSComponentLoader::Get();
|
|
|
|
MOZ_ASSERT(moduleloader);
|
|
|
|
|
|
|
|
JS::Rooted<JSObject*> moduleGlobal(aCx);
|
2018-08-04 13:30:39 +00:00
|
|
|
JS::Rooted<JSObject*> moduleExports(aCx);
|
|
|
|
nsresult rv = moduleloader->Import(aCx, uri, &moduleGlobal, &moduleExports);
|
|
|
|
if (NS_FAILED(rv)) {
|
2018-01-18 03:20:16 +00:00
|
|
|
Throw(aCx, rv);
|
2018-08-04 13:30:39 +00:00
|
|
|
return false;
|
2018-01-18 03:20:16 +00:00
|
|
|
}
|
|
|
|
|
2018-08-04 13:30:39 +00:00
|
|
|
JS::RootedValue value(aCx);
|
|
|
|
if (!JS_GetPropertyById(aCx, moduleExports, id, &value)) {
|
2018-01-18 03:20:16 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!JS_DefinePropertyById(aCx, thisObj, id, value, JSPROP_ENUMERATE)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
args.rval().set(value);
|
|
|
|
return true;
|
2018-11-30 10:46:48 +00:00
|
|
|
}
|
2018-01-18 03:20:16 +00:00
|
|
|
|
|
|
|
static bool ModuleSetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
|
|
|
|
JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
|
|
|
|
|
|
|
|
JS::Rooted<JSObject*> callee(aCx);
|
|
|
|
JS::Rooted<JSObject*> thisObj(aCx);
|
|
|
|
JS::Rooted<jsid> id(aCx);
|
|
|
|
if (!ExtractArgs(aCx, args, &callee, &thisObj, &id)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return JS_DefinePropertyById(aCx, thisObj, id, args.get(0), JSPROP_ENUMERATE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool DefineGetter(JSContext* aCx, JS::Handle<JSObject*> aTarget,
|
|
|
|
const nsAString& aId, const nsAString& aResourceURI) {
|
|
|
|
JS::RootedValue uri(aCx);
|
|
|
|
JS::RootedValue idValue(aCx);
|
|
|
|
JS::Rooted<jsid> id(aCx);
|
|
|
|
if (!xpc::NonVoidStringToJsval(aCx, aResourceURI, &uri) ||
|
|
|
|
!xpc::NonVoidStringToJsval(aCx, aId, &idValue) ||
|
|
|
|
!JS_ValueToId(aCx, idValue, &id)) {
|
|
|
|
return false;
|
2018-11-30 10:46:48 +00:00
|
|
|
}
|
2018-01-18 03:20:16 +00:00
|
|
|
idValue = js::IdToValue(id);
|
|
|
|
|
|
|
|
JS::Rooted<JSObject*> getter(
|
|
|
|
aCx, JS_GetFunctionObject(
|
|
|
|
js::NewFunctionByIdWithReserved(aCx, ModuleGetter, 0, 0, id)));
|
|
|
|
|
|
|
|
JS::Rooted<JSObject*> setter(
|
|
|
|
aCx, JS_GetFunctionObject(
|
|
|
|
js::NewFunctionByIdWithReserved(aCx, ModuleSetter, 0, 0, id)));
|
|
|
|
|
|
|
|
if (!getter || !setter) {
|
|
|
|
JS_ReportOutOfMemory(aCx);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
js::SetFunctionNativeReserved(getter, SLOT_ID, idValue);
|
|
|
|
js::SetFunctionNativeReserved(setter, SLOT_ID, idValue);
|
|
|
|
|
|
|
|
js::SetFunctionNativeReserved(getter, SLOT_URI, uri);
|
|
|
|
|
2018-06-21 09:05:42 +00:00
|
|
|
return JS_DefinePropertyById(
|
|
|
|
aCx, aTarget, id, getter, setter,
|
2018-01-18 03:20:16 +00:00
|
|
|
JSPROP_GETTER | JSPROP_SETTER | JSPROP_ENUMERATE);
|
|
|
|
}
|
|
|
|
} // namespace module_getter
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::DefineModuleGetter(const GlobalObject& global,
|
|
|
|
JS::Handle<JSObject*> target,
|
|
|
|
const nsAString& id,
|
|
|
|
const nsAString& resourceURI,
|
|
|
|
ErrorResult& aRv) {
|
2018-01-18 03:20:16 +00:00
|
|
|
if (!module_getter::DefineGetter(global.Context(), target, id, resourceURI)) {
|
|
|
|
aRv.NoteJSContextException(global.Context());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::OriginAttributesToSuffix(
|
2015-06-24 20:34:54 +00:00
|
|
|
dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs,
|
|
|
|
nsCString& aSuffix)
|
|
|
|
|
|
|
|
{
|
2017-01-12 16:38:48 +00:00
|
|
|
OriginAttributes attrs(aAttrs);
|
2015-06-24 20:34:54 +00:00
|
|
|
attrs.CreateSuffix(aSuffix);
|
|
|
|
}
|
2015-07-13 15:25:42 +00:00
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
bool ChromeUtils::OriginAttributesMatchPattern(
|
2015-07-09 18:36:35 +00:00
|
|
|
dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs,
|
|
|
|
const dom::OriginAttributesPatternDictionary& aPattern) {
|
2017-01-12 16:38:48 +00:00
|
|
|
OriginAttributes attrs(aAttrs);
|
2015-07-09 18:36:35 +00:00
|
|
|
OriginAttributesPattern pattern(aPattern);
|
|
|
|
return pattern.Matches(attrs);
|
|
|
|
}
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::CreateOriginAttributesFromOrigin(
|
2016-02-29 11:26:00 +00:00
|
|
|
dom::GlobalObject& aGlobal, const nsAString& aOrigin,
|
|
|
|
dom::OriginAttributesDictionary& aAttrs, ErrorResult& aRv) {
|
2017-01-12 16:38:48 +00:00
|
|
|
OriginAttributes attrs;
|
2016-01-06 10:08:30 +00:00
|
|
|
nsAutoCString suffix;
|
|
|
|
if (!attrs.PopulateFromOrigin(NS_ConvertUTF16toUTF8(aOrigin), suffix)) {
|
|
|
|
aRv.Throw(NS_ERROR_FAILURE);
|
|
|
|
return;
|
|
|
|
}
|
2016-02-19 14:55:25 +00:00
|
|
|
aAttrs = attrs;
|
2016-02-18 12:42:00 +00:00
|
|
|
}
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::FillNonDefaultOriginAttributes(
|
2016-02-29 11:26:00 +00:00
|
|
|
dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs,
|
|
|
|
dom::OriginAttributesDictionary& aNewAttrs) {
|
|
|
|
aNewAttrs = aAttrs;
|
|
|
|
}
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
bool ChromeUtils::IsOriginAttributesEqual(
|
2016-02-25 15:41:13 +00:00
|
|
|
dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aA,
|
|
|
|
const dom::OriginAttributesDictionary& aB) {
|
2016-11-17 13:52:16 +00:00
|
|
|
return IsOriginAttributesEqual(aA, aB);
|
|
|
|
}
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
bool ChromeUtils::IsOriginAttributesEqual(
|
2016-11-17 13:52:16 +00:00
|
|
|
const dom::OriginAttributesDictionary& aA,
|
|
|
|
const dom::OriginAttributesDictionary& aB) {
|
2018-11-29 22:07:30 +00:00
|
|
|
return aA == aB;
|
2016-02-25 15:41:13 +00:00
|
|
|
}
|
|
|
|
|
2017-11-16 09:48:45 +00:00
|
|
|
#ifdef NIGHTLY_BUILD
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::GetRecentJSDevError(GlobalObject& aGlobal,
|
|
|
|
JS::MutableHandleValue aRetval,
|
|
|
|
ErrorResult& aRv) {
|
2017-11-16 09:48:45 +00:00
|
|
|
aRetval.setUndefined();
|
|
|
|
auto runtime = CycleCollectedJSRuntime::Get();
|
|
|
|
MOZ_ASSERT(runtime);
|
|
|
|
|
|
|
|
auto cx = aGlobal.Context();
|
|
|
|
if (!runtime->GetRecentDevError(cx, aRetval)) {
|
|
|
|
aRv.NoteJSContextException(cx);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::ClearRecentJSDevError(GlobalObject&) {
|
2017-11-16 09:48:45 +00:00
|
|
|
auto runtime = CycleCollectedJSRuntime::Get();
|
|
|
|
MOZ_ASSERT(runtime);
|
|
|
|
|
|
|
|
runtime->ClearRecentDevError();
|
|
|
|
}
|
|
|
|
#endif // NIGHTLY_BUILD
|
|
|
|
|
2019-08-30 21:55:42 +00:00
|
|
|
#define PROCTYPE_TO_WEBIDL_CASE(_procType, _webidl) \
|
|
|
|
case mozilla::ProcType::_procType: \
|
|
|
|
return WebIDLProcType::_webidl
|
|
|
|
|
|
|
|
static WebIDLProcType ProcTypeToWebIDL(mozilla::ProcType aType) {
|
|
|
|
// Max is the value of the last enum, not the length, so add one.
|
2019-10-23 03:54:39 +00:00
|
|
|
static_assert(
|
|
|
|
WebIDLProcTypeValues::Count == static_cast<size_t>(ProcType::Max) + 1,
|
|
|
|
"In order for this static cast to be okay, "
|
|
|
|
"WebIDLProcType must match ProcType exactly");
|
2019-08-30 21:55:42 +00:00
|
|
|
|
|
|
|
switch (aType) {
|
|
|
|
PROCTYPE_TO_WEBIDL_CASE(Web, Web);
|
2020-05-06 20:11:55 +00:00
|
|
|
PROCTYPE_TO_WEBIDL_CASE(WebIsolated, WebIsolated);
|
2019-08-30 21:55:42 +00:00
|
|
|
PROCTYPE_TO_WEBIDL_CASE(File, File);
|
|
|
|
PROCTYPE_TO_WEBIDL_CASE(Extension, Extension);
|
|
|
|
PROCTYPE_TO_WEBIDL_CASE(PrivilegedAbout, Privilegedabout);
|
2020-05-06 20:11:55 +00:00
|
|
|
PROCTYPE_TO_WEBIDL_CASE(PrivilegedMozilla, Privilegedmozilla);
|
|
|
|
PROCTYPE_TO_WEBIDL_CASE(WebCOOPCOEP, WithCoopCoep);
|
2019-08-30 21:55:42 +00:00
|
|
|
PROCTYPE_TO_WEBIDL_CASE(WebLargeAllocation, WebLargeAllocation);
|
|
|
|
PROCTYPE_TO_WEBIDL_CASE(Browser, Browser);
|
|
|
|
PROCTYPE_TO_WEBIDL_CASE(Plugin, Plugin);
|
|
|
|
PROCTYPE_TO_WEBIDL_CASE(IPDLUnitTest, IpdlUnitTest);
|
|
|
|
PROCTYPE_TO_WEBIDL_CASE(GMPlugin, GmpPlugin);
|
|
|
|
PROCTYPE_TO_WEBIDL_CASE(GPU, Gpu);
|
|
|
|
PROCTYPE_TO_WEBIDL_CASE(VR, Vr);
|
|
|
|
PROCTYPE_TO_WEBIDL_CASE(RDD, Rdd);
|
|
|
|
PROCTYPE_TO_WEBIDL_CASE(Socket, Socket);
|
|
|
|
PROCTYPE_TO_WEBIDL_CASE(RemoteSandboxBroker, RemoteSandboxBroker);
|
2019-12-19 15:50:03 +00:00
|
|
|
#ifdef MOZ_ENABLE_FORKSERVER
|
|
|
|
PROCTYPE_TO_WEBIDL_CASE(ForkServer, ForkServer);
|
|
|
|
#endif
|
2020-05-30 14:38:30 +00:00
|
|
|
PROCTYPE_TO_WEBIDL_CASE(Preallocated, Preallocated);
|
2019-08-30 21:55:42 +00:00
|
|
|
PROCTYPE_TO_WEBIDL_CASE(Unknown, Unknown);
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(false, "Unhandled case in ProcTypeToWebIDL");
|
|
|
|
return WebIDLProcType::Unknown;
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef PROCTYPE_TO_WEBIDL_CASE
|
|
|
|
|
2019-02-23 18:07:59 +00:00
|
|
|
/* static */
|
|
|
|
already_AddRefed<Promise> ChromeUtils::RequestProcInfo(GlobalObject& aGlobal,
|
|
|
|
ErrorResult& aRv) {
|
|
|
|
// This function will use IPDL to enable threads info on macOS
|
|
|
|
// see https://bugzilla.mozilla.org/show_bug.cgi?id=1529023
|
|
|
|
if (!XRE_IsParentProcess()) {
|
|
|
|
aRv.Throw(NS_ERROR_FAILURE);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
// Creating a JS promise
|
|
|
|
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
|
|
|
MOZ_ASSERT(global);
|
|
|
|
RefPtr<Promise> domPromise = Promise::Create(global, aRv);
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
MOZ_ASSERT(domPromise);
|
|
|
|
|
|
|
|
base::ProcessId parentPid = base::GetCurrentProcId();
|
|
|
|
RefPtr<nsISerialEventTarget> target =
|
|
|
|
global->EventTargetFor(TaskCategory::Performance);
|
|
|
|
|
|
|
|
// Getting the parent proc info
|
2020-07-01 08:29:29 +00:00
|
|
|
mozilla::GetProcInfo(parentPid, 0, mozilla::ProcType::Browser, u""_ns)
|
2019-02-23 18:07:59 +00:00
|
|
|
->Then(
|
|
|
|
target, __func__,
|
|
|
|
[target, domPromise, parentPid](ProcInfo aParentInfo) {
|
2019-06-21 01:33:47 +00:00
|
|
|
// Get a list of ContentParent
|
|
|
|
nsTArray<ContentParent*> contentParents;
|
|
|
|
ContentParent::GetAll(contentParents);
|
2019-02-23 18:07:59 +00:00
|
|
|
nsTArray<RefPtr<ProcInfoPromise>> promises;
|
2019-06-21 01:33:47 +00:00
|
|
|
mozilla::ipc::GeckoChildProcessHost::GetAll(
|
2020-05-05 10:08:02 +00:00
|
|
|
[&promises, &contentParents](
|
2019-06-21 01:33:47 +00:00
|
|
|
mozilla::ipc::GeckoChildProcessHost* aGeckoProcess) {
|
|
|
|
if (!aGeckoProcess->GetChildProcessHandle()) {
|
|
|
|
return;
|
|
|
|
}
|
2020-05-06 20:11:55 +00:00
|
|
|
nsAutoString origin;
|
2019-06-21 01:33:47 +00:00
|
|
|
base::ProcessId childPid =
|
|
|
|
base::GetProcId(aGeckoProcess->GetChildProcessHandle());
|
|
|
|
int32_t childId = 0;
|
2019-08-30 21:52:40 +00:00
|
|
|
mozilla::ProcType type = mozilla::ProcType::Unknown;
|
2019-06-21 01:33:47 +00:00
|
|
|
switch (aGeckoProcess->GetProcessType()) {
|
|
|
|
case GeckoProcessType::GeckoProcessType_Content: {
|
|
|
|
ContentParent* contentParent = nullptr;
|
|
|
|
// This loop can become slow as we get more processes in
|
|
|
|
// Fission, so might need some refactoring in the future.
|
|
|
|
for (ContentParent* parent : contentParents) {
|
|
|
|
// find the match
|
|
|
|
if (parent->Process() == aGeckoProcess) {
|
|
|
|
contentParent = parent;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!contentParent) {
|
|
|
|
return;
|
|
|
|
}
|
2020-05-06 20:11:55 +00:00
|
|
|
// Converting the remoteType into a ProcType.
|
|
|
|
// Ideally, the remoteType should be strongly typed
|
|
|
|
// upstream, this would make the conversion less brittle.
|
|
|
|
nsAutoString remoteType(contentParent->GetRemoteType());
|
2020-07-01 08:34:12 +00:00
|
|
|
if (StringBeginsWith(remoteType,
|
|
|
|
NS_LITERAL_STRING_FROM_CSTRING(
|
|
|
|
FISSION_WEB_REMOTE_TYPE))) {
|
2020-05-06 20:11:55 +00:00
|
|
|
// WARNING: Do not change the order, as
|
|
|
|
// `DEFAULT_REMOTE_TYPE` is a prefix of
|
|
|
|
// `FISSION_WEB_REMOTE_TYPE`.
|
|
|
|
type = mozilla::ProcType::WebIsolated;
|
|
|
|
} else if (StringBeginsWith(
|
2020-07-01 08:34:12 +00:00
|
|
|
remoteType, NS_LITERAL_STRING_FROM_CSTRING(
|
|
|
|
DEFAULT_REMOTE_TYPE))) {
|
2019-06-21 01:33:47 +00:00
|
|
|
type = mozilla::ProcType::Web;
|
2020-05-06 20:11:55 +00:00
|
|
|
} else if (remoteType.EqualsLiteral(FILE_REMOTE_TYPE)) {
|
2019-06-21 01:33:47 +00:00
|
|
|
type = mozilla::ProcType::File;
|
2020-05-06 20:11:55 +00:00
|
|
|
} else if (remoteType.EqualsLiteral(
|
2019-06-21 01:33:47 +00:00
|
|
|
EXTENSION_REMOTE_TYPE)) {
|
|
|
|
type = mozilla::ProcType::Extension;
|
2020-05-06 20:11:55 +00:00
|
|
|
} else if (remoteType.EqualsLiteral(
|
2019-06-21 01:33:47 +00:00
|
|
|
PRIVILEGEDABOUT_REMOTE_TYPE)) {
|
|
|
|
type = mozilla::ProcType::PrivilegedAbout;
|
2020-05-06 20:11:55 +00:00
|
|
|
} else if (remoteType.EqualsLiteral(
|
|
|
|
PRIVILEGEDMOZILLA_REMOTE_TYPE)) {
|
|
|
|
type = mozilla::ProcType::PrivilegedMozilla;
|
|
|
|
} else if (StringBeginsWith(
|
|
|
|
remoteType,
|
2020-07-01 08:34:12 +00:00
|
|
|
NS_LITERAL_STRING_FROM_CSTRING(
|
2020-05-06 20:11:55 +00:00
|
|
|
WITH_COOP_COEP_REMOTE_TYPE_PREFIX))) {
|
|
|
|
type = mozilla::ProcType::WebCOOPCOEP;
|
|
|
|
} else if (remoteType.EqualsLiteral(
|
2019-06-21 01:33:47 +00:00
|
|
|
LARGE_ALLOCATION_REMOTE_TYPE)) {
|
|
|
|
type = mozilla::ProcType::WebLargeAllocation;
|
2020-05-30 14:38:30 +00:00
|
|
|
} else if (remoteType.EqualsLiteral(
|
|
|
|
PREALLOC_REMOTE_TYPE)) {
|
|
|
|
type = mozilla::ProcType::Preallocated;
|
2020-05-06 20:11:55 +00:00
|
|
|
} else {
|
|
|
|
MOZ_CRASH("Unknown remoteType");
|
|
|
|
}
|
|
|
|
|
|
|
|
// By convention, everything after '=' is the origin.
|
|
|
|
nsAString::const_iterator cursor;
|
|
|
|
nsAString::const_iterator end;
|
|
|
|
remoteType.BeginReading(cursor);
|
|
|
|
remoteType.EndReading(end);
|
|
|
|
if (FindCharInReadable(u'=', cursor, end)) {
|
|
|
|
origin = Substring(++cursor, end);
|
2019-06-21 01:33:47 +00:00
|
|
|
}
|
|
|
|
childId = contentParent->ChildID();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case GeckoProcessType::GeckoProcessType_Default:
|
|
|
|
type = mozilla::ProcType::Browser;
|
|
|
|
break;
|
|
|
|
case GeckoProcessType::GeckoProcessType_Plugin:
|
|
|
|
type = mozilla::ProcType::Plugin;
|
|
|
|
break;
|
|
|
|
case GeckoProcessType::GeckoProcessType_GMPlugin:
|
|
|
|
type = mozilla::ProcType::GMPlugin;
|
|
|
|
break;
|
|
|
|
case GeckoProcessType::GeckoProcessType_GPU:
|
|
|
|
type = mozilla::ProcType::GPU;
|
|
|
|
break;
|
|
|
|
case GeckoProcessType::GeckoProcessType_VR:
|
|
|
|
type = mozilla::ProcType::VR;
|
|
|
|
break;
|
|
|
|
case GeckoProcessType::GeckoProcessType_RDD:
|
|
|
|
type = mozilla::ProcType::RDD;
|
|
|
|
break;
|
|
|
|
case GeckoProcessType::GeckoProcessType_Socket:
|
|
|
|
type = mozilla::ProcType::Socket;
|
|
|
|
break;
|
|
|
|
case GeckoProcessType::GeckoProcessType_RemoteSandboxBroker:
|
|
|
|
type = mozilla::ProcType::RemoteSandboxBroker;
|
|
|
|
break;
|
2019-12-19 15:50:03 +00:00
|
|
|
#ifdef MOZ_ENABLE_FORKSERVER
|
|
|
|
case GeckoProcessType::GeckoProcessType_ForkServer:
|
|
|
|
type = mozilla::ProcType::ForkServer;
|
|
|
|
break;
|
|
|
|
#endif
|
2019-06-21 01:33:47 +00:00
|
|
|
default:
|
2019-08-30 21:52:40 +00:00
|
|
|
// Leave the default Unknown value in |type|.
|
|
|
|
break;
|
2019-06-21 01:33:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
promises.AppendElement(
|
|
|
|
#ifdef XP_MACOSX
|
2020-05-06 20:11:55 +00:00
|
|
|
mozilla::GetProcInfo(childPid, childId, type, origin,
|
2019-06-21 01:33:47 +00:00
|
|
|
aGeckoProcess->GetChildTask())
|
|
|
|
#else
|
2020-05-06 20:11:55 +00:00
|
|
|
mozilla::GetProcInfo(childPid, childId, type, origin)
|
2019-06-21 01:33:47 +00:00
|
|
|
#endif
|
|
|
|
);
|
|
|
|
});
|
2019-02-23 18:07:59 +00:00
|
|
|
|
|
|
|
auto ProcInfoResolver =
|
|
|
|
[domPromise, parentPid, parentInfo = aParentInfo](
|
|
|
|
const nsTArray<ProcInfo>& aChildrenInfo) {
|
|
|
|
mozilla::dom::ParentProcInfoDictionary procInfo;
|
|
|
|
// parent, basic info.
|
|
|
|
procInfo.mPid = parentPid;
|
|
|
|
procInfo.mFilename.Assign(parentInfo.filename);
|
2019-08-30 21:52:36 +00:00
|
|
|
procInfo.mType = mozilla::dom::WebIDLProcType::Browser;
|
2019-02-23 18:07:59 +00:00
|
|
|
procInfo.mVirtualMemorySize = parentInfo.virtualMemorySize;
|
|
|
|
procInfo.mResidentSetSize = parentInfo.residentSetSize;
|
|
|
|
procInfo.mCpuUser = parentInfo.cpuUser;
|
|
|
|
procInfo.mCpuKernel = parentInfo.cpuKernel;
|
|
|
|
|
|
|
|
// parent, threads info.
|
|
|
|
mozilla::dom::Sequence<mozilla::dom::ThreadInfoDictionary>
|
|
|
|
threads;
|
|
|
|
for (const ThreadInfo& entry : parentInfo.threads) {
|
|
|
|
ThreadInfoDictionary* thread =
|
|
|
|
threads.AppendElement(fallible);
|
|
|
|
if (NS_WARN_IF(!thread)) {
|
|
|
|
domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
thread->mCpuUser = entry.cpuUser;
|
|
|
|
thread->mCpuKernel = entry.cpuKernel;
|
|
|
|
thread->mTid = entry.tid;
|
2020-05-15 20:19:25 +00:00
|
|
|
thread->mName.Assign(entry.name);
|
2019-02-23 18:07:59 +00:00
|
|
|
}
|
2020-04-29 08:42:37 +00:00
|
|
|
procInfo.mThreads = std::move(threads);
|
2019-02-23 18:07:59 +00:00
|
|
|
|
|
|
|
mozilla::dom::Sequence<mozilla::dom::ChildProcInfoDictionary>
|
|
|
|
children;
|
|
|
|
for (const ProcInfo& info : aChildrenInfo) {
|
|
|
|
ChildProcInfoDictionary* childProcInfo =
|
|
|
|
children.AppendElement(fallible);
|
|
|
|
if (NS_WARN_IF(!childProcInfo)) {
|
|
|
|
domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Basic info.
|
|
|
|
childProcInfo->mChildID = info.childId;
|
2019-08-30 21:55:42 +00:00
|
|
|
childProcInfo->mType = ProcTypeToWebIDL(info.type);
|
2020-05-06 20:11:55 +00:00
|
|
|
childProcInfo->mOrigin = info.origin;
|
2019-02-23 18:07:59 +00:00
|
|
|
childProcInfo->mPid = info.pid;
|
|
|
|
childProcInfo->mFilename.Assign(info.filename);
|
|
|
|
childProcInfo->mVirtualMemorySize = info.virtualMemorySize;
|
|
|
|
childProcInfo->mResidentSetSize = info.residentSetSize;
|
|
|
|
childProcInfo->mCpuUser = info.cpuUser;
|
|
|
|
childProcInfo->mCpuKernel = info.cpuKernel;
|
|
|
|
|
|
|
|
// Threads info.
|
|
|
|
mozilla::dom::Sequence<mozilla::dom::ThreadInfoDictionary>
|
|
|
|
threads;
|
|
|
|
for (const ThreadInfo& entry : info.threads) {
|
|
|
|
ThreadInfoDictionary* thread =
|
|
|
|
threads.AppendElement(fallible);
|
|
|
|
if (NS_WARN_IF(!thread)) {
|
|
|
|
domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
thread->mCpuUser = entry.cpuUser;
|
|
|
|
thread->mCpuKernel = entry.cpuKernel;
|
|
|
|
thread->mTid = entry.tid;
|
|
|
|
thread->mName.Assign(entry.name);
|
|
|
|
}
|
2020-04-29 08:42:37 +00:00
|
|
|
childProcInfo->mThreads = std::move(threads);
|
2019-02-23 18:07:59 +00:00
|
|
|
}
|
2020-04-29 08:42:37 +00:00
|
|
|
procInfo.mChildren = std::move(children);
|
2019-02-23 18:07:59 +00:00
|
|
|
domPromise->MaybeResolve(procInfo);
|
|
|
|
}; // end of ProcInfoResolver
|
|
|
|
|
|
|
|
ProcInfoPromise::All(target, promises)
|
|
|
|
->Then(target, __func__, std::move(ProcInfoResolver),
|
|
|
|
[domPromise](const nsresult aResult) {
|
|
|
|
domPromise->MaybeReject(aResult);
|
|
|
|
}); // end of ProcInfoPromise::All
|
|
|
|
},
|
|
|
|
[domPromise](nsresult aRv) {
|
|
|
|
domPromise->MaybeReject(aRv);
|
|
|
|
}); // end of mozilla::GetProcInfo
|
|
|
|
|
|
|
|
// sending back the promise instance
|
|
|
|
return domPromise.forget();
|
|
|
|
}
|
|
|
|
|
2018-07-05 14:32:03 +00:00
|
|
|
/* static */
|
2018-11-19 22:51:12 +00:00
|
|
|
already_AddRefed<Promise> ChromeUtils::RequestPerformanceMetrics(
|
|
|
|
GlobalObject& aGlobal, ErrorResult& aRv) {
|
2018-03-20 19:07:41 +00:00
|
|
|
MOZ_ASSERT(XRE_IsParentProcess());
|
2018-04-04 11:36:25 +00:00
|
|
|
|
2018-11-19 22:51:12 +00:00
|
|
|
// Creating a JS promise
|
2018-07-05 14:32:03 +00:00
|
|
|
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
|
|
|
MOZ_ASSERT(global);
|
|
|
|
RefPtr<Promise> domPromise = Promise::Create(global, aRv);
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
|
|
return nullptr;
|
2018-03-20 19:07:41 +00:00
|
|
|
}
|
2018-07-05 14:32:03 +00:00
|
|
|
MOZ_ASSERT(domPromise);
|
2018-11-19 22:51:12 +00:00
|
|
|
RefPtr<nsISerialEventTarget> target =
|
|
|
|
global->EventTargetFor(TaskCategory::Performance);
|
2018-04-04 11:36:25 +00:00
|
|
|
|
2018-07-05 14:32:03 +00:00
|
|
|
// requesting metrics, that will be returned into the promise
|
2018-11-19 22:51:12 +00:00
|
|
|
PerformanceMetricsCollector::RequestMetrics()->Then(
|
|
|
|
target, __func__,
|
|
|
|
[domPromise,
|
|
|
|
target](nsTArray<dom::PerformanceInfoDictionary>&& aResults) {
|
|
|
|
domPromise->MaybeResolve(std::move(aResults));
|
|
|
|
},
|
|
|
|
[domPromise](const nsresult& aRv) { domPromise->MaybeReject(aRv); });
|
2018-04-04 11:36:25 +00:00
|
|
|
|
2018-07-05 14:32:03 +00:00
|
|
|
// sending back the promise instance
|
|
|
|
return domPromise.forget();
|
2018-03-20 19:07:41 +00:00
|
|
|
}
|
|
|
|
|
2019-05-21 19:01:31 +00:00
|
|
|
void ChromeUtils::SetPerfStatsCollectionMask(GlobalObject& aGlobal,
|
|
|
|
uint64_t aMask) {
|
|
|
|
PerfStats::SetCollectionMask(static_cast<PerfStats::MetricMask>(aMask));
|
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<Promise> ChromeUtils::CollectPerfStats(GlobalObject& aGlobal,
|
|
|
|
ErrorResult& aRv) {
|
|
|
|
// Creating a JS promise
|
|
|
|
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
|
|
|
MOZ_ASSERT(global);
|
|
|
|
|
|
|
|
RefPtr<Promise> promise = Promise::Create(global, aRv);
|
|
|
|
if (aRv.Failed()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<PerfStats::PerfStatsPromise> extPromise =
|
|
|
|
PerfStats::CollectPerfStatsJSON();
|
|
|
|
|
|
|
|
extPromise->Then(
|
2020-06-23 05:05:36 +00:00
|
|
|
GetCurrentSerialEventTarget(), __func__,
|
2019-05-21 19:01:31 +00:00
|
|
|
[promise](const nsCString& aResult) {
|
|
|
|
promise->MaybeResolve(NS_ConvertUTF8toUTF16(aResult));
|
|
|
|
},
|
|
|
|
[promise](bool aValue) { promise->MaybeReject(NS_ERROR_FAILURE); });
|
|
|
|
|
|
|
|
return promise.forget();
|
|
|
|
}
|
|
|
|
|
Bug 1441333: Part 1 - Add helper to retrieve closest stack frame with a given principal. r=bz
Most WebExtension APIs are async, and have fairly complicated error reporting
semantics. As a result, when we report an error, the current JS stack has very
little to do with the JS caller that triggered the error, which makes it
difficult to diagnose.
In order to improve the situation, we need to store the location of the caller
at the start of an async operation, so we can tie the error to some marginally
useful location. We don't have a reasonable way to do that now other than
proactively creating an error object when the API is called, or creating a
promise with a full async stack, both of which are too expensive.
This helper instead returns a single SavedStack frame with a given principal,
which should be considerably cheaper, and likely good enough to give a
starting point for debugging cryptic errors.
MozReview-Commit-ID: BTxhpZK9Fdz
--HG--
extra : rebase_source : 7f2c66b1dc18d4ce4c47bef2e3b9d5d3ade929aa
2017-11-12 01:39:16 +00:00
|
|
|
constexpr auto kSkipSelfHosted = JS::SavedFrameSelfHosted::Exclude;
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::GetCallerLocation(const GlobalObject& aGlobal,
|
|
|
|
nsIPrincipal* aPrincipal,
|
|
|
|
JS::MutableHandle<JSObject*> aRetval) {
|
Bug 1441333: Part 1 - Add helper to retrieve closest stack frame with a given principal. r=bz
Most WebExtension APIs are async, and have fairly complicated error reporting
semantics. As a result, when we report an error, the current JS stack has very
little to do with the JS caller that triggered the error, which makes it
difficult to diagnose.
In order to improve the situation, we need to store the location of the caller
at the start of an async operation, so we can tie the error to some marginally
useful location. We don't have a reasonable way to do that now other than
proactively creating an error object when the API is called, or creating a
promise with a full async stack, both of which are too expensive.
This helper instead returns a single SavedStack frame with a given principal,
which should be considerably cheaper, and likely good enough to give a
starting point for debugging cryptic errors.
MozReview-Commit-ID: BTxhpZK9Fdz
--HG--
extra : rebase_source : 7f2c66b1dc18d4ce4c47bef2e3b9d5d3ade929aa
2017-11-12 01:39:16 +00:00
|
|
|
JSContext* cx = aGlobal.Context();
|
|
|
|
|
|
|
|
auto* principals = nsJSPrincipals::get(aPrincipal);
|
|
|
|
|
|
|
|
JS::StackCapture captureMode(JS::FirstSubsumedFrame(cx, principals));
|
|
|
|
|
|
|
|
JS::RootedObject frame(cx);
|
2018-05-30 19:15:35 +00:00
|
|
|
if (!JS::CaptureCurrentStack(cx, &frame, std::move(captureMode))) {
|
Bug 1441333: Part 1 - Add helper to retrieve closest stack frame with a given principal. r=bz
Most WebExtension APIs are async, and have fairly complicated error reporting
semantics. As a result, when we report an error, the current JS stack has very
little to do with the JS caller that triggered the error, which makes it
difficult to diagnose.
In order to improve the situation, we need to store the location of the caller
at the start of an async operation, so we can tie the error to some marginally
useful location. We don't have a reasonable way to do that now other than
proactively creating an error object when the API is called, or creating a
promise with a full async stack, both of which are too expensive.
This helper instead returns a single SavedStack frame with a given principal,
which should be considerably cheaper, and likely good enough to give a
starting point for debugging cryptic errors.
MozReview-Commit-ID: BTxhpZK9Fdz
--HG--
extra : rebase_source : 7f2c66b1dc18d4ce4c47bef2e3b9d5d3ade929aa
2017-11-12 01:39:16 +00:00
|
|
|
JS_ClearPendingException(cx);
|
|
|
|
aRetval.set(nullptr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FirstSubsumedFrame gets us a stack which stops at the first principal which
|
|
|
|
// is subsumed by the given principal. That means that we may have a lot of
|
|
|
|
// privileged frames that we don't care about at the top of the stack, though.
|
|
|
|
// We need to filter those out to get the frame we actually want.
|
|
|
|
aRetval.set(
|
|
|
|
js::GetFirstSubsumedSavedFrame(cx, principals, frame, kSkipSelfHosted));
|
|
|
|
}
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::CreateError(const GlobalObject& aGlobal,
|
|
|
|
const nsAString& aMessage,
|
|
|
|
JS::Handle<JSObject*> aStack,
|
|
|
|
JS::MutableHandle<JSObject*> aRetVal,
|
|
|
|
ErrorResult& aRv) {
|
2018-07-21 12:32:25 +00:00
|
|
|
if (aStack && !JS::IsMaybeWrappedSavedFrame(aStack)) {
|
2018-03-01 22:00:00 +00:00
|
|
|
aRv.Throw(NS_ERROR_INVALID_ARG);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSContext* cx = aGlobal.Context();
|
|
|
|
|
|
|
|
auto cleanup = MakeScopeExit([&]() { aRv.NoteJSContextException(cx); });
|
|
|
|
|
|
|
|
JS::RootedObject retVal(cx);
|
|
|
|
{
|
|
|
|
JS::RootedString fileName(cx, JS_GetEmptyString(cx));
|
|
|
|
uint32_t line = 0;
|
|
|
|
uint32_t column = 0;
|
|
|
|
|
2018-08-02 06:48:40 +00:00
|
|
|
Maybe<JSAutoRealm> ar;
|
2018-03-01 22:00:00 +00:00
|
|
|
JS::RootedObject stack(cx);
|
|
|
|
if (aStack) {
|
|
|
|
stack = UncheckedUnwrap(aStack);
|
2018-05-16 08:53:16 +00:00
|
|
|
ar.emplace(cx, stack);
|
2018-03-01 22:00:00 +00:00
|
|
|
|
2018-07-21 12:34:58 +00:00
|
|
|
JSPrincipals* principals =
|
|
|
|
JS::GetRealmPrincipals(js::GetContextRealm(cx));
|
|
|
|
if (JS::GetSavedFrameLine(cx, principals, stack, &line) !=
|
|
|
|
JS::SavedFrameResult::Ok ||
|
|
|
|
JS::GetSavedFrameColumn(cx, principals, stack, &column) !=
|
|
|
|
JS::SavedFrameResult::Ok ||
|
|
|
|
JS::GetSavedFrameSource(cx, principals, stack, &fileName) !=
|
|
|
|
JS::SavedFrameResult::Ok) {
|
2018-03-01 22:00:00 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::RootedString message(cx);
|
|
|
|
{
|
|
|
|
JS::RootedValue msgVal(cx);
|
|
|
|
if (!xpc::NonVoidStringToJsval(cx, aMessage, &msgVal)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
message = msgVal.toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::Rooted<JS::Value> err(cx);
|
|
|
|
if (!JS::CreateError(cx, JSEXN_ERR, stack, fileName, line, column, nullptr,
|
|
|
|
message, &err)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(err.isObject());
|
|
|
|
retVal = &err.toObject();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aStack && !JS_WrapObject(cx, &retVal)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup.release();
|
|
|
|
aRetVal.set(retVal);
|
|
|
|
}
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
already_AddRefed<Promise> ChromeUtils::RequestIOActivity(GlobalObject& aGlobal,
|
|
|
|
ErrorResult& aRv) {
|
2018-06-26 08:43:16 +00:00
|
|
|
MOZ_ASSERT(XRE_IsParentProcess());
|
|
|
|
MOZ_ASSERT(Preferences::GetBool(IO_ACTIVITY_ENABLED_PREF, false));
|
2018-07-06 11:43:08 +00:00
|
|
|
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
|
|
|
MOZ_ASSERT(global);
|
|
|
|
RefPtr<Promise> domPromise = Promise::Create(global, aRv);
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
MOZ_ASSERT(domPromise);
|
|
|
|
mozilla::net::IOActivityMonitor::RequestActivities(domPromise);
|
|
|
|
return domPromise.forget();
|
2018-06-26 08:43:16 +00:00
|
|
|
}
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
bool ChromeUtils::HasReportingHeaderForOrigin(GlobalObject& global,
|
|
|
|
const nsAString& aOrigin,
|
|
|
|
ErrorResult& aRv) {
|
2018-12-01 20:26:10 +00:00
|
|
|
if (!XRE_IsParentProcess()) {
|
|
|
|
aRv.Throw(NS_ERROR_FAILURE);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ReportingHeader::HasReportingHeaderForOrigin(
|
|
|
|
NS_ConvertUTF16toUTF8(aOrigin));
|
|
|
|
}
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
PopupBlockerState ChromeUtils::GetPopupControlState(GlobalObject& aGlobal) {
|
2019-01-04 15:16:59 +00:00
|
|
|
switch (PopupBlocker::GetPopupControlState()) {
|
|
|
|
case PopupBlocker::PopupControlState::openAllowed:
|
|
|
|
return PopupBlockerState::OpenAllowed;
|
|
|
|
|
|
|
|
case PopupBlocker::PopupControlState::openControlled:
|
|
|
|
return PopupBlockerState::OpenControlled;
|
|
|
|
|
|
|
|
case PopupBlocker::PopupControlState::openBlocked:
|
|
|
|
return PopupBlockerState::OpenBlocked;
|
|
|
|
|
|
|
|
case PopupBlocker::PopupControlState::openAbused:
|
|
|
|
return PopupBlockerState::OpenAbused;
|
|
|
|
|
|
|
|
case PopupBlocker::PopupControlState::openOverridden:
|
|
|
|
return PopupBlockerState::OpenOverridden;
|
|
|
|
|
|
|
|
default:
|
|
|
|
MOZ_CRASH(
|
|
|
|
"PopupBlocker::PopupControlState and PopupBlockerState are out of "
|
|
|
|
"sync");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
bool ChromeUtils::IsPopupTokenUnused(GlobalObject& aGlobal) {
|
2019-01-04 15:16:59 +00:00
|
|
|
return PopupBlocker::IsPopupOpeningTokenUnused();
|
2019-01-04 17:44:01 +00:00
|
|
|
}
|
2019-01-04 16:38:34 +00:00
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
double ChromeUtils::LastExternalProtocolIframeAllowed(GlobalObject& aGlobal) {
|
2019-01-24 19:05:03 +00:00
|
|
|
TimeStamp when = PopupBlocker::WhenLastExternalProtocolIframeAllowed();
|
|
|
|
if (when.IsNull()) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
TimeDuration duration = TimeStamp::Now() - when;
|
|
|
|
return duration.ToMilliseconds();
|
|
|
|
}
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::ResetLastExternalProtocolIframeAllowed(
|
2019-01-30 11:19:35 +00:00
|
|
|
GlobalObject& aGlobal) {
|
|
|
|
PopupBlocker::ResetLastExternalProtocolIframeAllowed();
|
|
|
|
}
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::RegisterWindowActor(const GlobalObject& aGlobal,
|
2020-04-17 10:56:22 +00:00
|
|
|
const nsACString& aName,
|
2019-02-25 22:05:29 +00:00
|
|
|
const WindowActorOptions& aOptions,
|
|
|
|
ErrorResult& aRv) {
|
2019-01-03 16:45:42 +00:00
|
|
|
MOZ_ASSERT(XRE_IsParentProcess());
|
|
|
|
|
2020-04-30 16:42:53 +00:00
|
|
|
RefPtr<JSActorService> service = JSActorService::GetSingleton();
|
2019-01-03 16:45:42 +00:00
|
|
|
service->RegisterWindowActor(aName, aOptions, aRv);
|
2019-01-04 15:16:59 +00:00
|
|
|
}
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::UnregisterWindowActor(const GlobalObject& aGlobal,
|
2020-04-17 10:56:22 +00:00
|
|
|
const nsACString& aName) {
|
2019-02-06 20:50:42 +00:00
|
|
|
MOZ_ASSERT(XRE_IsParentProcess());
|
|
|
|
|
2020-04-30 16:42:53 +00:00
|
|
|
RefPtr<JSActorService> service = JSActorService::GetSingleton();
|
2019-02-06 20:50:42 +00:00
|
|
|
service->UnregisterWindowActor(aName);
|
|
|
|
}
|
|
|
|
|
2020-04-30 16:43:31 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::RegisterProcessActor(const GlobalObject& aGlobal,
|
|
|
|
const nsACString& aName,
|
|
|
|
const ProcessActorOptions& aOptions,
|
|
|
|
ErrorResult& aRv) {
|
|
|
|
MOZ_ASSERT(XRE_IsParentProcess());
|
|
|
|
|
|
|
|
RefPtr<JSActorService> service = JSActorService::GetSingleton();
|
|
|
|
service->RegisterProcessActor(aName, aOptions, aRv);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
void ChromeUtils::UnregisterProcessActor(const GlobalObject& aGlobal,
|
|
|
|
const nsACString& aName) {
|
|
|
|
MOZ_ASSERT(XRE_IsParentProcess());
|
|
|
|
|
|
|
|
RefPtr<JSActorService> service = JSActorService::GetSingleton();
|
|
|
|
service->UnregisterProcessActor(aName);
|
|
|
|
}
|
|
|
|
|
2019-02-25 22:05:29 +00:00
|
|
|
/* static */
|
|
|
|
bool ChromeUtils::IsClassifierBlockingErrorCode(GlobalObject& aGlobal,
|
|
|
|
uint32_t aError) {
|
2019-01-30 12:43:34 +00:00
|
|
|
return net::UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode(
|
|
|
|
static_cast<nsresult>(aError));
|
|
|
|
}
|
|
|
|
|
2019-08-15 19:28:16 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::PrivateNoteIntentionalCrash(const GlobalObject& aGlobal,
|
|
|
|
ErrorResult& aError) {
|
|
|
|
if (XRE_IsContentProcess()) {
|
|
|
|
NoteIntentionalCrash("tab");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
aError.Throw(NS_ERROR_NOT_IMPLEMENTED);
|
|
|
|
}
|
|
|
|
|
2019-12-21 00:10:13 +00:00
|
|
|
/* static */
|
2020-06-09 02:59:57 +00:00
|
|
|
void ChromeUtils::GenerateMediaControlKey(const GlobalObject& aGlobal,
|
|
|
|
MediaControlKey aKey) {
|
2019-12-21 00:10:13 +00:00
|
|
|
RefPtr<MediaControlService> service = MediaControlService::GetService();
|
|
|
|
if (service) {
|
2020-06-09 02:59:57 +00:00
|
|
|
service->GenerateTestMediaControlKey(aKey);
|
2019-12-21 00:10:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-20 09:11:32 +00:00
|
|
|
/* static */
|
2020-06-25 20:35:18 +00:00
|
|
|
nsIDOMProcessChild* ChromeUtils::GetDomProcessChild(const GlobalObject&) {
|
|
|
|
if (XRE_IsParentProcess()) {
|
|
|
|
return InProcessChild::Singleton();
|
|
|
|
}
|
2020-03-20 09:11:32 +00:00
|
|
|
return ContentChild::GetSingleton();
|
|
|
|
}
|
|
|
|
|
2020-03-05 19:43:50 +00:00
|
|
|
/* static */
|
|
|
|
void ChromeUtils::GetCurrentActiveMediaMetadata(const GlobalObject& aGlobal,
|
|
|
|
MediaMetadataInit& aMetadata) {
|
|
|
|
if (RefPtr<MediaControlService> service = MediaControlService::GetService()) {
|
|
|
|
MediaMetadataBase metadata = service->GetMainControllerMediaMetadata();
|
|
|
|
aMetadata.mTitle = metadata.mTitle;
|
|
|
|
aMetadata.mArtist = metadata.mArtist;
|
|
|
|
aMetadata.mAlbum = metadata.mAlbum;
|
|
|
|
for (const auto& artwork : metadata.mArtwork) {
|
|
|
|
// If OOM happens resulting in not able to append the element, then we
|
|
|
|
// would get incorrect result and fail on test, so we don't need to throw
|
|
|
|
// an error explicitly.
|
|
|
|
if (MediaImage* image = aMetadata.mArtwork.AppendElement(fallible)) {
|
|
|
|
image->mSrc = artwork.mSrc;
|
|
|
|
image->mSizes = artwork.mSizes;
|
|
|
|
image->mType = artwork.mType;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-17 01:01:31 +00:00
|
|
|
/* static */
|
|
|
|
MediaSessionPlaybackTestState ChromeUtils::GetCurrentMediaSessionPlaybackState(
|
|
|
|
GlobalObject& aGlobal) {
|
|
|
|
static_assert(int(MediaSessionPlaybackState::None) ==
|
2020-03-17 01:01:33 +00:00
|
|
|
int(MediaSessionPlaybackTestState::Stopped) &&
|
2020-03-17 01:01:31 +00:00
|
|
|
int(MediaSessionPlaybackState::Paused) ==
|
|
|
|
int(MediaSessionPlaybackTestState::Paused) &&
|
|
|
|
int(MediaSessionPlaybackState::Playing) ==
|
|
|
|
int(MediaSessionPlaybackTestState::Playing) &&
|
|
|
|
MediaSessionPlaybackStateValues::Count ==
|
|
|
|
MediaSessionPlaybackTestStateValues::Count);
|
|
|
|
if (RefPtr<MediaControlService> service = MediaControlService::GetService()) {
|
|
|
|
return ConvertToMediaSessionPlaybackTestState(
|
|
|
|
service->GetMainControllerPlaybackState());
|
|
|
|
}
|
2020-03-17 01:01:33 +00:00
|
|
|
return MediaSessionPlaybackTestState::Stopped;
|
2020-03-17 01:01:31 +00:00
|
|
|
}
|
|
|
|
|
2015-06-17 18:12:23 +00:00
|
|
|
} // namespace dom
|
|
|
|
} // namespace mozilla
|