Bug 1850713: remove duplicated setting of early hint preloader id in `ScriptLoader...
[gecko.git] / dom / base / ChromeUtils.cpp
blob2db0faf549bc183492447111c9ae0fa575bd55be
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/. */
7 #include "ChromeUtils.h"
9 #include "JSOracleParent.h"
10 #include "js/CallAndConstruct.h" // JS::Call
11 #include "js/ColumnNumber.h" // JS::TaggedColumnNumberOneOrigin, JS::ColumnNumberOneOrigin
12 #include "js/CharacterEncoding.h"
13 #include "js/Object.h" // JS::GetClass
14 #include "js/PropertyAndElement.h" // JS_DefineProperty, JS_DefinePropertyById, JS_Enumerate, JS_GetProperty, JS_GetPropertyById, JS_SetProperty, JS_SetPropertyById, JS::IdVector
15 #include "js/PropertyDescriptor.h" // JS::PropertyDescriptor, JS_GetOwnPropertyDescriptorById
16 #include "js/SavedFrameAPI.h"
17 #include "js/Value.h" // JS::Value, JS::StringValue
18 #include "jsfriendapi.h"
19 #include "WrapperFactory.h"
21 #include "mozilla/Base64.h"
22 #include "mozilla/CycleCollectedJSRuntime.h"
23 #include "mozilla/ErrorNames.h"
24 #include "mozilla/EventStateManager.h"
25 #include "mozilla/FormAutofillNative.h"
26 #include "mozilla/IntentionalCrash.h"
27 #include "mozilla/PerfStats.h"
28 #include "mozilla/Preferences.h"
29 #include "mozilla/ProcInfo.h"
30 #include "mozilla/ResultExtensions.h"
31 #include "mozilla/ScopeExit.h"
32 #include "mozilla/ScrollingMetrics.h"
33 #include "mozilla/SharedStyleSheetCache.h"
34 #include "mozilla/TimeStamp.h"
35 #include "mozilla/dom/ContentParent.h"
36 #include "mozilla/dom/IdleDeadline.h"
37 #include "mozilla/dom/InProcessParent.h"
38 #include "mozilla/dom/JSActorService.h"
39 #include "mozilla/dom/MediaSessionBinding.h"
40 #include "mozilla/dom/PBrowserParent.h"
41 #include "mozilla/dom/Performance.h"
42 #include "mozilla/dom/PopupBlocker.h"
43 #include "mozilla/dom/Promise.h"
44 #include "mozilla/dom/Record.h"
45 #include "mozilla/dom/ReportingHeader.h"
46 #include "mozilla/dom/UnionTypes.h"
47 #include "mozilla/dom/WindowBinding.h" // For IdleRequestCallback/Options
48 #include "mozilla/dom/WindowGlobalParent.h"
49 #include "mozilla/dom/WorkerScope.h"
50 #include "mozilla/ipc/GeckoChildProcessHost.h"
51 #include "mozilla/ipc/UtilityProcessSandboxing.h"
52 #include "mozilla/ipc/UtilityProcessManager.h"
53 #include "mozilla/ipc/UtilityProcessHost.h"
54 #include "mozilla/net/UrlClassifierFeatureFactory.h"
55 #include "mozilla/WheelHandlingHelper.h"
56 #include "IOActivityMonitor.h"
57 #include "nsNativeTheme.h"
58 #include "nsThreadUtils.h"
59 #include "mozJSModuleLoader.h"
60 #include "mozilla/ProfilerLabels.h"
61 #include "mozilla/ProfilerMarkers.h"
62 #include "nsIException.h"
63 #include "VsyncSource.h"
65 #ifdef XP_UNIX
66 # include <errno.h>
67 # include <unistd.h>
68 # include <fcntl.h>
69 # include <poll.h>
70 # include <sys/wait.h>
72 # ifdef XP_LINUX
73 # include <sys/prctl.h>
74 # endif
75 #endif
77 namespace mozilla::dom {
79 /* static */
80 void ChromeUtils::NondeterministicGetWeakMapKeys(
81 GlobalObject& aGlobal, JS::Handle<JS::Value> aMap,
82 JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv) {
83 if (!aMap.isObject()) {
84 aRetval.setUndefined();
85 } else {
86 JSContext* cx = aGlobal.Context();
87 JS::Rooted<JSObject*> objRet(cx);
88 JS::Rooted<JSObject*> mapObj(cx, &aMap.toObject());
89 if (!JS_NondeterministicGetWeakMapKeys(cx, mapObj, &objRet)) {
90 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
91 } else {
92 aRetval.set(objRet ? JS::ObjectValue(*objRet) : JS::UndefinedValue());
97 /* static */
98 void ChromeUtils::NondeterministicGetWeakSetKeys(
99 GlobalObject& aGlobal, JS::Handle<JS::Value> aSet,
100 JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv) {
101 if (!aSet.isObject()) {
102 aRetval.setUndefined();
103 } else {
104 JSContext* cx = aGlobal.Context();
105 JS::Rooted<JSObject*> objRet(cx);
106 JS::Rooted<JSObject*> setObj(cx, &aSet.toObject());
107 if (!JS_NondeterministicGetWeakSetKeys(cx, setObj, &objRet)) {
108 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
109 } else {
110 aRetval.set(objRet ? JS::ObjectValue(*objRet) : JS::UndefinedValue());
115 /* static */
116 void ChromeUtils::Base64URLEncode(GlobalObject& aGlobal,
117 const ArrayBufferViewOrArrayBuffer& aSource,
118 const Base64URLEncodeOptions& aOptions,
119 nsACString& aResult, ErrorResult& aRv) {
120 size_t length = 0;
121 uint8_t* data = nullptr;
122 if (aSource.IsArrayBuffer()) {
123 const ArrayBuffer& buffer = aSource.GetAsArrayBuffer();
124 buffer.ComputeState();
125 length = buffer.Length();
126 data = buffer.Data();
127 } else if (aSource.IsArrayBufferView()) {
128 const ArrayBufferView& view = aSource.GetAsArrayBufferView();
129 view.ComputeState();
130 length = view.Length();
131 data = view.Data();
132 } else {
133 MOZ_CRASH("Uninitialized union: expected buffer or view");
136 auto paddingPolicy = aOptions.mPad ? Base64URLEncodePaddingPolicy::Include
137 : Base64URLEncodePaddingPolicy::Omit;
138 nsresult rv = mozilla::Base64URLEncode(length, data, paddingPolicy, aResult);
139 if (NS_WARN_IF(NS_FAILED(rv))) {
140 aResult.Truncate();
141 aRv.Throw(rv);
145 /* static */
146 void ChromeUtils::Base64URLDecode(GlobalObject& aGlobal,
147 const nsACString& aString,
148 const Base64URLDecodeOptions& aOptions,
149 JS::MutableHandle<JSObject*> aRetval,
150 ErrorResult& aRv) {
151 Base64URLDecodePaddingPolicy paddingPolicy;
152 switch (aOptions.mPadding) {
153 case Base64URLDecodePadding::Require:
154 paddingPolicy = Base64URLDecodePaddingPolicy::Require;
155 break;
157 case Base64URLDecodePadding::Ignore:
158 paddingPolicy = Base64URLDecodePaddingPolicy::Ignore;
159 break;
161 case Base64URLDecodePadding::Reject:
162 paddingPolicy = Base64URLDecodePaddingPolicy::Reject;
163 break;
165 default:
166 aRv.Throw(NS_ERROR_INVALID_ARG);
167 return;
169 FallibleTArray<uint8_t> data;
170 nsresult rv = mozilla::Base64URLDecode(aString, paddingPolicy, data);
171 if (NS_WARN_IF(NS_FAILED(rv))) {
172 aRv.Throw(rv);
173 return;
176 JS::Rooted<JSObject*> buffer(
177 aGlobal.Context(),
178 ArrayBuffer::Create(aGlobal.Context(), data.Length(), data.Elements()));
179 if (NS_WARN_IF(!buffer)) {
180 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
181 return;
183 aRetval.set(buffer);
186 /* static */
187 void ChromeUtils::ReleaseAssert(GlobalObject& aGlobal, bool aCondition,
188 const nsAString& aMessage) {
189 // If the condition didn't fail, which is the likely case, immediately return.
190 if (MOZ_LIKELY(aCondition)) {
191 return;
194 // Extract the current stack from the JS runtime to embed in the crash reason.
195 nsAutoString filename;
196 uint32_t lineNo = 0;
198 if (nsCOMPtr<nsIStackFrame> location = GetCurrentJSStack(1)) {
199 location->GetFilename(aGlobal.Context(), filename);
200 lineNo = location->GetLineNumber(aGlobal.Context());
201 } else {
202 filename.Assign(u"<unknown>"_ns);
205 // Convert to utf-8 for adding as the MozCrashReason.
206 NS_ConvertUTF16toUTF8 filenameUtf8(filename);
207 NS_ConvertUTF16toUTF8 messageUtf8(aMessage);
209 // Actually crash.
210 MOZ_CRASH_UNSAFE_PRINTF("Failed ChromeUtils.releaseAssert(\"%s\") @ %s:%u",
211 messageUtf8.get(), filenameUtf8.get(), lineNo);
214 /* static */
215 void ChromeUtils::AddProfilerMarker(
216 GlobalObject& aGlobal, const nsACString& aName,
217 const ProfilerMarkerOptionsOrDouble& aOptions,
218 const Optional<nsACString>& aText) {
219 if (!profiler_thread_is_being_profiled_for_markers()) {
220 return;
223 MarkerOptions options;
225 MarkerCategory category = ::geckoprofiler::category::JS;
227 DOMHighResTimeStamp startTime = 0;
228 uint64_t innerWindowId = 0;
229 if (aOptions.IsDouble()) {
230 startTime = aOptions.GetAsDouble();
231 } else {
232 const ProfilerMarkerOptions& opt = aOptions.GetAsProfilerMarkerOptions();
233 startTime = opt.mStartTime;
234 innerWindowId = opt.mInnerWindowId;
236 if (opt.mCaptureStack) {
237 // If we will be capturing a stack, change the category of the
238 // ChromeUtils.addProfilerMarker label automatically added by the webidl
239 // binding from DOM to PROFILER so that this function doesn't appear in
240 // the marker stack.
241 JSContext* cx = aGlobal.Context();
242 ProfilingStack* stack = js::GetContextProfilingStackIfEnabled(cx);
243 if (MOZ_LIKELY(stack)) {
244 uint32_t sp = stack->stackPointer;
245 if (MOZ_LIKELY(sp > 0)) {
246 js::ProfilingStackFrame& frame = stack->frames[sp - 1];
247 if (frame.isLabelFrame() && "ChromeUtils"_ns.Equals(frame.label()) &&
248 "addProfilerMarker"_ns.Equals(frame.dynamicString())) {
249 frame.setLabelCategory(JS::ProfilingCategoryPair::PROFILER);
254 options.Set(MarkerStack::Capture());
256 #define BEGIN_CATEGORY(name, labelAsString, color) \
257 if (opt.mCategory.Equals(labelAsString)) { \
258 category = ::geckoprofiler::category::name; \
259 } else
260 #define SUBCATEGORY(supercategory, name, labelAsString)
261 #define END_CATEGORY
262 MOZ_PROFILING_CATEGORY_LIST(BEGIN_CATEGORY, SUBCATEGORY, END_CATEGORY)
263 #undef BEGIN_CATEGORY
264 #undef SUBCATEGORY
265 #undef END_CATEGORY
267 category = ::geckoprofiler::category::OTHER;
270 if (startTime) {
271 RefPtr<Performance> performance;
273 if (NS_IsMainThread()) {
274 nsCOMPtr<nsPIDOMWindowInner> ownerWindow =
275 do_QueryInterface(aGlobal.GetAsSupports());
276 if (ownerWindow) {
277 performance = ownerWindow->GetPerformance();
279 } else {
280 JSContext* cx = aGlobal.Context();
281 WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
282 if (workerPrivate) {
283 performance = workerPrivate->GlobalScope()->GetPerformance();
287 if (performance) {
288 options.Set(MarkerTiming::IntervalUntilNowFrom(
289 performance->CreationTimeStamp() +
290 TimeDuration::FromMilliseconds(startTime)));
291 } else {
292 options.Set(MarkerTiming::IntervalUntilNowFrom(
293 TimeStamp::ProcessCreation() +
294 TimeDuration::FromMilliseconds(startTime)));
298 if (innerWindowId) {
299 options.Set(MarkerInnerWindowId(innerWindowId));
300 } else {
301 options.Set(MarkerInnerWindowIdFromJSContext(aGlobal.Context()));
305 AUTO_PROFILER_STATS(ChromeUtils_AddProfilerMarker);
306 if (aText.WasPassed()) {
307 profiler_add_marker(aName, category, std::move(options),
308 ::geckoprofiler::markers::TextMarker{},
309 aText.Value());
310 } else {
311 profiler_add_marker(aName, category, std::move(options));
316 /* static */
317 void ChromeUtils::GetXPCOMErrorName(GlobalObject& aGlobal, uint32_t aErrorCode,
318 nsACString& aRetval) {
319 GetErrorName((nsresult)aErrorCode, aRetval);
322 /* static */
323 void ChromeUtils::WaiveXrays(GlobalObject& aGlobal, JS::Handle<JS::Value> aVal,
324 JS::MutableHandle<JS::Value> aRetval,
325 ErrorResult& aRv) {
326 JS::Rooted<JS::Value> value(aGlobal.Context(), aVal);
327 if (!xpc::WrapperFactory::WaiveXrayAndWrap(aGlobal.Context(), &value)) {
328 aRv.NoteJSContextException(aGlobal.Context());
329 } else {
330 aRetval.set(value);
334 /* static */
335 void ChromeUtils::UnwaiveXrays(GlobalObject& aGlobal,
336 JS::Handle<JS::Value> aVal,
337 JS::MutableHandle<JS::Value> aRetval,
338 ErrorResult& aRv) {
339 if (!aVal.isObject()) {
340 aRetval.set(aVal);
341 return;
344 JS::Rooted<JSObject*> obj(aGlobal.Context(),
345 js::UncheckedUnwrap(&aVal.toObject()));
346 if (!JS_WrapObject(aGlobal.Context(), &obj)) {
347 aRv.NoteJSContextException(aGlobal.Context());
348 } else {
349 aRetval.setObject(*obj);
353 /* static */
354 void ChromeUtils::GetClassName(GlobalObject& aGlobal,
355 JS::Handle<JSObject*> aObj, bool aUnwrap,
356 nsAString& aRetval) {
357 JS::Rooted<JSObject*> obj(aGlobal.Context(), aObj);
358 if (aUnwrap) {
359 obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
362 aRetval = NS_ConvertUTF8toUTF16(nsDependentCString(JS::GetClass(obj)->name));
365 /* static */
366 bool ChromeUtils::IsDOMObject(GlobalObject& aGlobal, JS::Handle<JSObject*> aObj,
367 bool aUnwrap) {
368 JS::Rooted<JSObject*> obj(aGlobal.Context(), aObj);
369 if (aUnwrap) {
370 obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
373 return mozilla::dom::IsDOMObject(obj);
376 /* static */
377 void ChromeUtils::ShallowClone(GlobalObject& aGlobal,
378 JS::Handle<JSObject*> aObj,
379 JS::Handle<JSObject*> aTarget,
380 JS::MutableHandle<JSObject*> aRetval,
381 ErrorResult& aRv) {
382 JSContext* cx = aGlobal.Context();
384 auto cleanup = MakeScopeExit([&]() { aRv.NoteJSContextException(cx); });
386 JS::Rooted<JS::IdVector> ids(cx, JS::IdVector(cx));
387 JS::RootedVector<JS::Value> values(cx);
388 JS::RootedVector<jsid> valuesIds(cx);
391 // cx represents our current Realm, so it makes sense to use it for the
392 // CheckedUnwrapDynamic call. We do want CheckedUnwrapDynamic, in case
393 // someone is shallow-cloning a Window.
394 JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrapDynamic(aObj, cx));
395 if (!obj) {
396 js::ReportAccessDenied(cx);
397 return;
400 if (js::IsScriptedProxy(obj)) {
401 JS_ReportErrorASCII(cx, "Shallow cloning a proxy object is not allowed");
402 return;
405 JSAutoRealm ar(cx, obj);
407 if (!JS_Enumerate(cx, obj, &ids) || !values.reserve(ids.length()) ||
408 !valuesIds.reserve(ids.length())) {
409 return;
412 JS::Rooted<Maybe<JS::PropertyDescriptor>> desc(cx);
413 JS::Rooted<JS::PropertyKey> id(cx);
414 for (jsid idVal : ids) {
415 id = idVal;
416 if (!JS_GetOwnPropertyDescriptorById(cx, obj, id, &desc)) {
417 continue;
419 if (desc.isNothing() || desc->isAccessorDescriptor()) {
420 continue;
422 valuesIds.infallibleAppend(id);
423 values.infallibleAppend(desc->value());
427 JS::Rooted<JSObject*> obj(cx);
429 Maybe<JSAutoRealm> ar;
430 if (aTarget) {
431 // Our target could be anything, so we want CheckedUnwrapDynamic here.
432 // "cx" represents the current Realm when we were called from bindings, so
433 // we can just use that.
434 JS::Rooted<JSObject*> target(cx, js::CheckedUnwrapDynamic(aTarget, cx));
435 if (!target) {
436 js::ReportAccessDenied(cx);
437 return;
439 ar.emplace(cx, target);
442 obj = JS_NewPlainObject(cx);
443 if (!obj) {
444 return;
447 JS::Rooted<JS::Value> value(cx);
448 JS::Rooted<JS::PropertyKey> id(cx);
449 for (uint32_t i = 0; i < valuesIds.length(); i++) {
450 id = valuesIds[i];
451 value = values[i];
453 JS_MarkCrossZoneId(cx, id);
454 if (!JS_WrapValue(cx, &value) ||
455 !JS_SetPropertyById(cx, obj, id, value)) {
456 return;
461 if (aTarget && !JS_WrapObject(cx, &obj)) {
462 return;
465 cleanup.release();
466 aRetval.set(obj);
469 namespace {
470 class IdleDispatchRunnable final : public IdleRunnable,
471 public nsITimerCallback {
472 public:
473 NS_DECL_ISUPPORTS_INHERITED
475 IdleDispatchRunnable(nsIGlobalObject* aParent, IdleRequestCallback& aCallback)
476 : IdleRunnable("ChromeUtils::IdleDispatch"),
477 mCallback(&aCallback),
478 mParent(aParent) {}
480 // MOZ_CAN_RUN_SCRIPT_BOUNDARY until Runnable::Run is MOZ_CAN_RUN_SCRIPT.
481 // See bug 1535398.
482 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override {
483 if (mCallback) {
484 CancelTimer();
486 auto deadline = mDeadline - TimeStamp::ProcessCreation();
488 ErrorResult rv;
489 RefPtr<IdleDeadline> idleDeadline =
490 new IdleDeadline(mParent, mTimedOut, deadline.ToMilliseconds());
492 RefPtr<IdleRequestCallback> callback(std::move(mCallback));
493 MOZ_ASSERT(!mCallback);
494 callback->Call(*idleDeadline, "ChromeUtils::IdleDispatch handler");
495 mParent = nullptr;
497 return NS_OK;
500 void SetDeadline(TimeStamp aDeadline) override { mDeadline = aDeadline; }
502 NS_IMETHOD Notify(nsITimer* aTimer) override {
503 mTimedOut = true;
504 SetDeadline(TimeStamp::Now());
505 return Run();
508 void SetTimer(uint32_t aDelay, nsIEventTarget* aTarget) override {
509 MOZ_ASSERT(aTarget);
510 MOZ_ASSERT(!mTimer);
511 NS_NewTimerWithCallback(getter_AddRefs(mTimer), this, aDelay,
512 nsITimer::TYPE_ONE_SHOT, aTarget);
515 protected:
516 virtual ~IdleDispatchRunnable() { CancelTimer(); }
518 private:
519 void CancelTimer() {
520 if (mTimer) {
521 mTimer->Cancel();
522 mTimer = nullptr;
526 RefPtr<IdleRequestCallback> mCallback;
527 nsCOMPtr<nsIGlobalObject> mParent;
529 nsCOMPtr<nsITimer> mTimer;
531 TimeStamp mDeadline{};
532 bool mTimedOut = false;
535 NS_IMPL_ISUPPORTS_INHERITED(IdleDispatchRunnable, IdleRunnable,
536 nsITimerCallback)
537 } // anonymous namespace
539 /* static */
540 void ChromeUtils::IdleDispatch(const GlobalObject& aGlobal,
541 IdleRequestCallback& aCallback,
542 const IdleRequestOptions& aOptions,
543 ErrorResult& aRv) {
544 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
545 MOZ_ASSERT(global);
547 auto runnable = MakeRefPtr<IdleDispatchRunnable>(global, aCallback);
549 if (aOptions.mTimeout.WasPassed()) {
550 aRv = NS_DispatchToCurrentThreadQueue(
551 runnable.forget(), aOptions.mTimeout.Value(), EventQueuePriority::Idle);
552 } else {
553 aRv = NS_DispatchToCurrentThreadQueue(runnable.forget(),
554 EventQueuePriority::Idle);
558 /* static */
559 void ChromeUtils::Import(const GlobalObject& aGlobal,
560 const nsACString& aResourceURI,
561 const Optional<JS::Handle<JSObject*>>& aTargetObj,
562 JS::MutableHandle<JSObject*> aRetval,
563 ErrorResult& aRv) {
564 RefPtr moduleloader = mozJSModuleLoader::Get();
565 MOZ_ASSERT(moduleloader);
567 AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING_NONSENSITIVE("ChromeUtils::Import",
568 OTHER, aResourceURI);
570 JSContext* cx = aGlobal.Context();
572 JS::Rooted<JSObject*> global(cx);
573 JS::Rooted<JSObject*> exports(cx);
574 nsresult rv = moduleloader->Import(cx, aResourceURI, &global, &exports);
575 if (NS_FAILED(rv)) {
576 aRv.Throw(rv);
577 return;
580 // Import() on the component loader can return NS_OK while leaving an
581 // exception on the JSContext. Check for that case.
582 if (JS_IsExceptionPending(cx)) {
583 aRv.NoteJSContextException(cx);
584 return;
587 if (aTargetObj.WasPassed()) {
588 if (!JS_AssignObject(cx, aTargetObj.Value(), exports)) {
589 aRv.Throw(NS_ERROR_FAILURE);
590 return;
594 if (!JS_WrapObject(cx, &exports)) {
595 aRv.Throw(NS_ERROR_FAILURE);
596 return;
598 aRetval.set(exports);
601 static mozJSModuleLoader* GetContextualESLoader(
602 const Optional<bool>& aLoadInDevToolsLoader, JSObject* aGlobal) {
603 RefPtr devToolsModuleloader = mozJSModuleLoader::GetDevToolsLoader();
604 // We should load the module in the DevTools loader if:
605 // - ChromeUtils.importESModule's `loadInDevToolsLoader` option is true, or,
606 // - if the callsite is from a module loaded in the DevTools loader and
607 // `loadInDevToolsLoader` isn't an explicit false.
608 bool shouldUseDevToolsLoader =
609 (aLoadInDevToolsLoader.WasPassed() && aLoadInDevToolsLoader.Value()) ||
610 (devToolsModuleloader && !aLoadInDevToolsLoader.WasPassed() &&
611 devToolsModuleloader->IsLoaderGlobal(aGlobal));
612 if (shouldUseDevToolsLoader) {
613 return mozJSModuleLoader::GetOrCreateDevToolsLoader();
615 return mozJSModuleLoader::Get();
618 /* static */
619 void ChromeUtils::ImportESModule(
620 const GlobalObject& aGlobal, const nsAString& aResourceURI,
621 const ImportESModuleOptionsDictionary& aOptions,
622 JS::MutableHandle<JSObject*> aRetval, ErrorResult& aRv) {
623 RefPtr moduleloader =
624 GetContextualESLoader(aOptions.mLoadInDevToolsLoader, aGlobal.Get());
625 MOZ_ASSERT(moduleloader);
627 NS_ConvertUTF16toUTF8 registryLocation(aResourceURI);
629 AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING_NONSENSITIVE(
630 "ChromeUtils::ImportESModule", OTHER, registryLocation);
632 JSContext* cx = aGlobal.Context();
634 JS::Rooted<JSObject*> moduleNamespace(cx);
635 nsresult rv =
636 moduleloader->ImportESModule(cx, registryLocation, &moduleNamespace);
637 if (NS_FAILED(rv)) {
638 aRv.Throw(rv);
639 return;
642 MOZ_ASSERT(!JS_IsExceptionPending(cx));
644 if (!JS_WrapObject(cx, &moduleNamespace)) {
645 aRv.Throw(NS_ERROR_FAILURE);
646 return;
648 aRetval.set(moduleNamespace);
651 namespace lazy_getter {
653 static const size_t SLOT_ID = 0;
654 static const size_t SLOT_URI = 1;
655 static const size_t SLOT_PARAMS = 1;
657 static const size_t PARAM_INDEX_TARGET = 0;
658 static const size_t PARAM_INDEX_LAMBDA = 1;
659 static const size_t PARAMS_COUNT = 2;
661 static bool ExtractArgs(JSContext* aCx, JS::CallArgs& aArgs,
662 JS::MutableHandle<JSObject*> aCallee,
663 JS::MutableHandle<JSObject*> aThisObj,
664 JS::MutableHandle<jsid> aId) {
665 aCallee.set(&aArgs.callee());
667 JS::Handle<JS::Value> thisv = aArgs.thisv();
668 if (!thisv.isObject()) {
669 JS_ReportErrorASCII(aCx, "Invalid target object");
670 return false;
673 aThisObj.set(&thisv.toObject());
675 JS::Rooted<JS::Value> id(aCx,
676 js::GetFunctionNativeReserved(aCallee, SLOT_ID));
677 MOZ_ALWAYS_TRUE(JS_ValueToId(aCx, id, aId));
678 return true;
681 static bool JSLazyGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
682 JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
684 JS::Rooted<JSObject*> callee(aCx);
685 JS::Rooted<JSObject*> unused(aCx);
686 JS::Rooted<jsid> id(aCx);
687 if (!ExtractArgs(aCx, args, &callee, &unused, &id)) {
688 return false;
691 JS::Rooted<JS::Value> paramsVal(
692 aCx, js::GetFunctionNativeReserved(callee, SLOT_PARAMS));
693 if (paramsVal.isUndefined()) {
694 args.rval().setUndefined();
695 return true;
697 // Avoid calling the lambda multiple times, in case of:
698 // * the getter function is retrieved from property descriptor and called
699 // * the lambda gets the property again
700 // * the getter function throws and accessed again
701 js::SetFunctionNativeReserved(callee, SLOT_PARAMS, JS::UndefinedHandleValue);
703 JS::Rooted<JSObject*> paramsObj(aCx, &paramsVal.toObject());
705 JS::Rooted<JS::Value> targetVal(aCx);
706 JS::Rooted<JS::Value> lambdaVal(aCx);
707 if (!JS_GetElement(aCx, paramsObj, PARAM_INDEX_TARGET, &targetVal)) {
708 return false;
710 if (!JS_GetElement(aCx, paramsObj, PARAM_INDEX_LAMBDA, &lambdaVal)) {
711 return false;
714 JS::Rooted<JSObject*> targetObj(aCx, &targetVal.toObject());
716 JS::Rooted<JS::Value> value(aCx);
717 if (!JS::Call(aCx, targetObj, lambdaVal, JS::HandleValueArray::empty(),
718 &value)) {
719 return false;
722 if (!JS_DefinePropertyById(aCx, targetObj, id, value, JSPROP_ENUMERATE)) {
723 return false;
726 args.rval().set(value);
727 return true;
730 static bool DefineLazyGetter(JSContext* aCx, JS::Handle<JSObject*> aTarget,
731 JS::Handle<JS::Value> aName,
732 JS::Handle<JSObject*> aLambda) {
733 JS::Rooted<jsid> id(aCx);
734 if (!JS_ValueToId(aCx, aName, &id)) {
735 return false;
738 JS::Rooted<JSObject*> getter(
739 aCx, JS_GetFunctionObject(
740 js::NewFunctionByIdWithReserved(aCx, JSLazyGetter, 0, 0, id)));
741 if (!getter) {
742 JS_ReportOutOfMemory(aCx);
743 return false;
746 JS::RootedVector<JS::Value> params(aCx);
747 if (!params.resize(PARAMS_COUNT)) {
748 return false;
750 params[PARAM_INDEX_TARGET].setObject(*aTarget);
751 params[PARAM_INDEX_LAMBDA].setObject(*aLambda);
752 JS::Rooted<JSObject*> paramsObj(aCx, JS::NewArrayObject(aCx, params));
753 if (!paramsObj) {
754 return false;
757 js::SetFunctionNativeReserved(getter, SLOT_ID, aName);
758 js::SetFunctionNativeReserved(getter, SLOT_PARAMS,
759 JS::ObjectValue(*paramsObj));
761 return JS_DefinePropertyById(aCx, aTarget, id, getter, nullptr,
762 JSPROP_ENUMERATE);
765 enum class ModuleType { JSM, ESM };
767 static bool ModuleGetterImpl(JSContext* aCx, unsigned aArgc, JS::Value* aVp,
768 ModuleType aType) {
769 JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
771 JS::Rooted<JSObject*> callee(aCx);
772 JS::Rooted<JSObject*> thisObj(aCx);
773 JS::Rooted<jsid> id(aCx);
774 if (!ExtractArgs(aCx, args, &callee, &thisObj, &id)) {
775 return false;
778 JS::Rooted<JSString*> moduleURI(
779 aCx, js::GetFunctionNativeReserved(callee, SLOT_URI).toString());
780 JS::UniqueChars bytes = JS_EncodeStringToUTF8(aCx, moduleURI);
781 if (!bytes) {
782 return false;
784 nsDependentCString uri(bytes.get());
786 RefPtr moduleloader =
787 aType == ModuleType::JSM
788 ? mozJSModuleLoader::Get()
789 : GetContextualESLoader(
790 Optional<bool>(),
791 JS::GetNonCCWObjectGlobal(js::UncheckedUnwrap(thisObj)));
792 MOZ_ASSERT(moduleloader);
794 JS::Rooted<JS::Value> value(aCx);
795 if (aType == ModuleType::JSM) {
796 JS::Rooted<JSObject*> moduleGlobal(aCx);
797 JS::Rooted<JSObject*> moduleExports(aCx);
798 nsresult rv = moduleloader->Import(aCx, uri, &moduleGlobal, &moduleExports);
799 if (NS_FAILED(rv)) {
800 Throw(aCx, rv);
801 return false;
804 // JSM's exports is from the same realm.
805 if (!JS_GetPropertyById(aCx, moduleExports, id, &value)) {
806 return false;
808 } else {
809 JS::Rooted<JSObject*> moduleNamespace(aCx);
810 nsresult rv = moduleloader->ImportESModule(aCx, uri, &moduleNamespace);
811 if (NS_FAILED(rv)) {
812 Throw(aCx, rv);
813 return false;
816 // ESM's namespace is from the module's realm.
818 JSAutoRealm ar(aCx, moduleNamespace);
819 if (!JS_GetPropertyById(aCx, moduleNamespace, id, &value)) {
820 return false;
823 if (!JS_WrapValue(aCx, &value)) {
824 return false;
828 if (!JS_DefinePropertyById(aCx, thisObj, id, value, JSPROP_ENUMERATE)) {
829 return false;
832 args.rval().set(value);
833 return true;
836 static bool JSModuleGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
837 return ModuleGetterImpl(aCx, aArgc, aVp, ModuleType::JSM);
840 static bool ESModuleGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
841 return ModuleGetterImpl(aCx, aArgc, aVp, ModuleType::ESM);
844 static bool ModuleSetterImpl(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
845 JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
847 JS::Rooted<JSObject*> callee(aCx);
848 JS::Rooted<JSObject*> thisObj(aCx);
849 JS::Rooted<jsid> id(aCx);
850 if (!ExtractArgs(aCx, args, &callee, &thisObj, &id)) {
851 return false;
854 return JS_DefinePropertyById(aCx, thisObj, id, args.get(0), JSPROP_ENUMERATE);
857 static bool JSModuleSetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
858 return ModuleSetterImpl(aCx, aArgc, aVp);
861 static bool ESModuleSetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
862 return ModuleSetterImpl(aCx, aArgc, aVp);
865 static bool DefineJSModuleGetter(JSContext* aCx, JS::Handle<JSObject*> aTarget,
866 const nsAString& aId,
867 const nsAString& aResourceURI) {
868 JS::Rooted<JS::Value> uri(aCx);
869 JS::Rooted<JS::Value> idValue(aCx);
870 JS::Rooted<jsid> id(aCx);
871 if (!xpc::NonVoidStringToJsval(aCx, aResourceURI, &uri) ||
872 !xpc::NonVoidStringToJsval(aCx, aId, &idValue) ||
873 !JS_ValueToId(aCx, idValue, &id)) {
874 return false;
876 idValue = js::IdToValue(id);
878 JS::Rooted<JSObject*> getter(
879 aCx, JS_GetFunctionObject(
880 js::NewFunctionByIdWithReserved(aCx, JSModuleGetter, 0, 0, id)));
882 JS::Rooted<JSObject*> setter(
883 aCx, JS_GetFunctionObject(
884 js::NewFunctionByIdWithReserved(aCx, JSModuleSetter, 0, 0, id)));
886 if (!getter || !setter) {
887 JS_ReportOutOfMemory(aCx);
888 return false;
891 js::SetFunctionNativeReserved(getter, SLOT_ID, idValue);
892 js::SetFunctionNativeReserved(setter, SLOT_ID, idValue);
894 js::SetFunctionNativeReserved(getter, SLOT_URI, uri);
896 return JS_DefinePropertyById(aCx, aTarget, id, getter, setter,
897 JSPROP_ENUMERATE);
900 static bool DefineESModuleGetter(JSContext* aCx, JS::Handle<JSObject*> aTarget,
901 JS::Handle<JS::PropertyKey> aId,
902 JS::Handle<JS::Value> aResourceURI) {
903 JS::Rooted<JS::Value> idVal(aCx, JS::StringValue(aId.toString()));
905 JS::Rooted<JSObject*> getter(
906 aCx, JS_GetFunctionObject(js::NewFunctionByIdWithReserved(
907 aCx, ESModuleGetter, 0, 0, aId)));
909 JS::Rooted<JSObject*> setter(
910 aCx, JS_GetFunctionObject(js::NewFunctionByIdWithReserved(
911 aCx, ESModuleSetter, 0, 0, aId)));
913 if (!getter || !setter) {
914 JS_ReportOutOfMemory(aCx);
915 return false;
918 js::SetFunctionNativeReserved(getter, SLOT_ID, idVal);
919 js::SetFunctionNativeReserved(setter, SLOT_ID, idVal);
921 js::SetFunctionNativeReserved(getter, SLOT_URI, aResourceURI);
923 return JS_DefinePropertyById(aCx, aTarget, aId, getter, setter,
924 JSPROP_ENUMERATE);
927 } // namespace lazy_getter
929 /* static */
930 void ChromeUtils::DefineLazyGetter(const GlobalObject& aGlobal,
931 JS::Handle<JSObject*> aTarget,
932 JS::Handle<JS::Value> aName,
933 JS::Handle<JSObject*> aLambda,
934 ErrorResult& aRv) {
935 JSContext* cx = aGlobal.Context();
936 if (!lazy_getter::DefineLazyGetter(cx, aTarget, aName, aLambda)) {
937 aRv.NoteJSContextException(cx);
938 return;
942 /* static */
943 void ChromeUtils::DefineModuleGetter(const GlobalObject& global,
944 JS::Handle<JSObject*> target,
945 const nsAString& id,
946 const nsAString& resourceURI,
947 ErrorResult& aRv) {
948 if (!lazy_getter::DefineJSModuleGetter(global.Context(), target, id,
949 resourceURI)) {
950 aRv.NoteJSContextException(global.Context());
954 /* static */
955 void ChromeUtils::DefineESModuleGetters(const GlobalObject& global,
956 JS::Handle<JSObject*> target,
957 JS::Handle<JSObject*> modules,
958 ErrorResult& aRv) {
959 JSContext* cx = global.Context();
961 JS::Rooted<JS::IdVector> props(cx, JS::IdVector(cx));
962 if (!JS_Enumerate(cx, modules, &props)) {
963 aRv.NoteJSContextException(cx);
964 return;
967 JS::Rooted<JS::PropertyKey> prop(cx);
968 JS::Rooted<JS::Value> resourceURIVal(cx);
969 for (JS::PropertyKey tmp : props) {
970 prop = tmp;
972 if (!prop.isString()) {
973 aRv.Throw(NS_ERROR_FAILURE);
974 return;
977 if (!JS_GetPropertyById(cx, modules, prop, &resourceURIVal)) {
978 aRv.NoteJSContextException(cx);
979 return;
982 if (!lazy_getter::DefineESModuleGetter(cx, target, prop, resourceURIVal)) {
983 aRv.NoteJSContextException(cx);
984 return;
989 #ifdef XP_UNIX
990 /* static */
991 void ChromeUtils::GetLibcConstants(const GlobalObject&,
992 LibcConstants& aConsts) {
993 aConsts.mEINTR.Construct(EINTR);
994 aConsts.mEACCES.Construct(EACCES);
995 aConsts.mEAGAIN.Construct(EAGAIN);
996 aConsts.mEINVAL.Construct(EINVAL);
997 aConsts.mENOSYS.Construct(ENOSYS);
999 aConsts.mF_SETFD.Construct(F_SETFD);
1000 aConsts.mF_SETFL.Construct(F_SETFL);
1002 aConsts.mFD_CLOEXEC.Construct(FD_CLOEXEC);
1004 aConsts.mAT_EACCESS.Construct(AT_EACCESS);
1006 aConsts.mO_CREAT.Construct(O_CREAT);
1007 aConsts.mO_NONBLOCK.Construct(O_NONBLOCK);
1008 aConsts.mO_WRONLY.Construct(O_WRONLY);
1010 aConsts.mPOLLERR.Construct(POLLERR);
1011 aConsts.mPOLLHUP.Construct(POLLHUP);
1012 aConsts.mPOLLIN.Construct(POLLIN);
1013 aConsts.mPOLLNVAL.Construct(POLLNVAL);
1014 aConsts.mPOLLOUT.Construct(POLLOUT);
1016 aConsts.mWNOHANG.Construct(WNOHANG);
1018 # ifdef XP_LINUX
1019 aConsts.mPR_CAPBSET_READ.Construct(PR_CAPBSET_READ);
1020 # endif
1022 #endif
1024 /* static */
1025 void ChromeUtils::OriginAttributesToSuffix(
1026 dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs,
1027 nsCString& aSuffix)
1030 OriginAttributes attrs(aAttrs);
1031 attrs.CreateSuffix(aSuffix);
1034 /* static */
1035 bool ChromeUtils::OriginAttributesMatchPattern(
1036 dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs,
1037 const dom::OriginAttributesPatternDictionary& aPattern) {
1038 OriginAttributes attrs(aAttrs);
1039 OriginAttributesPattern pattern(aPattern);
1040 return pattern.Matches(attrs);
1043 /* static */
1044 void ChromeUtils::CreateOriginAttributesFromOrigin(
1045 dom::GlobalObject& aGlobal, const nsAString& aOrigin,
1046 dom::OriginAttributesDictionary& aAttrs, ErrorResult& aRv) {
1047 OriginAttributes attrs;
1048 nsAutoCString suffix;
1049 if (!attrs.PopulateFromOrigin(NS_ConvertUTF16toUTF8(aOrigin), suffix)) {
1050 aRv.Throw(NS_ERROR_FAILURE);
1051 return;
1053 aAttrs = attrs;
1056 /* static */
1057 void ChromeUtils::CreateOriginAttributesFromOriginSuffix(
1058 dom::GlobalObject& aGlobal, const nsAString& aSuffix,
1059 dom::OriginAttributesDictionary& aAttrs, ErrorResult& aRv) {
1060 OriginAttributes attrs;
1061 nsAutoCString suffix;
1062 if (!attrs.PopulateFromSuffix(NS_ConvertUTF16toUTF8(aSuffix))) {
1063 aRv.Throw(NS_ERROR_FAILURE);
1064 return;
1066 aAttrs = attrs;
1069 /* static */
1070 void ChromeUtils::FillNonDefaultOriginAttributes(
1071 dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs,
1072 dom::OriginAttributesDictionary& aNewAttrs) {
1073 aNewAttrs = aAttrs;
1076 /* static */
1077 bool ChromeUtils::IsOriginAttributesEqual(
1078 dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aA,
1079 const dom::OriginAttributesDictionary& aB) {
1080 return IsOriginAttributesEqual(aA, aB);
1083 /* static */
1084 bool ChromeUtils::IsOriginAttributesEqual(
1085 const dom::OriginAttributesDictionary& aA,
1086 const dom::OriginAttributesDictionary& aB) {
1087 return aA == aB;
1090 /* static */
1091 void ChromeUtils::GetBaseDomainFromPartitionKey(dom::GlobalObject& aGlobal,
1092 const nsAString& aPartitionKey,
1093 nsAString& aBaseDomain,
1094 ErrorResult& aRv) {
1095 nsString scheme;
1096 nsString pkBaseDomain;
1097 int32_t port;
1099 if (!mozilla::OriginAttributes::ParsePartitionKey(aPartitionKey, scheme,
1100 pkBaseDomain, port)) {
1101 aRv.Throw(NS_ERROR_FAILURE);
1102 return;
1105 aBaseDomain = pkBaseDomain;
1108 /* static */
1109 void ChromeUtils::GetPartitionKeyFromURL(dom::GlobalObject& aGlobal,
1110 const nsAString& aURL,
1111 nsAString& aPartitionKey,
1112 ErrorResult& aRv) {
1113 nsCOMPtr<nsIURI> uri;
1114 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL);
1115 if (NS_SUCCEEDED(rv) && uri->SchemeIs("chrome")) {
1116 rv = NS_ERROR_FAILURE;
1119 if (NS_WARN_IF(NS_FAILED(rv))) {
1120 aPartitionKey.Truncate();
1121 aRv.Throw(rv);
1122 return;
1125 mozilla::OriginAttributes attrs;
1126 attrs.SetPartitionKey(uri);
1128 aPartitionKey = attrs.mPartitionKey;
1131 #ifdef NIGHTLY_BUILD
1132 /* static */
1133 void ChromeUtils::GetRecentJSDevError(GlobalObject& aGlobal,
1134 JS::MutableHandle<JS::Value> aRetval,
1135 ErrorResult& aRv) {
1136 aRetval.setUndefined();
1137 auto runtime = CycleCollectedJSRuntime::Get();
1138 MOZ_ASSERT(runtime);
1140 auto cx = aGlobal.Context();
1141 if (!runtime->GetRecentDevError(cx, aRetval)) {
1142 aRv.NoteJSContextException(cx);
1143 return;
1147 /* static */
1148 void ChromeUtils::ClearRecentJSDevError(GlobalObject&) {
1149 auto runtime = CycleCollectedJSRuntime::Get();
1150 MOZ_ASSERT(runtime);
1152 runtime->ClearRecentDevError();
1154 #endif // NIGHTLY_BUILD
1156 void ChromeUtils::ClearStyleSheetCacheByPrincipal(GlobalObject&,
1157 nsIPrincipal* aForPrincipal) {
1158 SharedStyleSheetCache::Clear(aForPrincipal);
1161 void ChromeUtils::ClearStyleSheetCacheByBaseDomain(
1162 GlobalObject&, const nsACString& aBaseDomain) {
1163 SharedStyleSheetCache::Clear(nullptr, &aBaseDomain);
1166 void ChromeUtils::ClearStyleSheetCache(GlobalObject&) {
1167 SharedStyleSheetCache::Clear();
1170 #define PROCTYPE_TO_WEBIDL_CASE(_procType, _webidl) \
1171 case mozilla::ProcType::_procType: \
1172 return WebIDLProcType::_webidl
1174 static WebIDLProcType ProcTypeToWebIDL(mozilla::ProcType aType) {
1175 // Max is the value of the last enum, not the length, so add one.
1176 static_assert(
1177 WebIDLProcTypeValues::Count == static_cast<size_t>(ProcType::Max) + 1,
1178 "In order for this static cast to be okay, "
1179 "WebIDLProcType must match ProcType exactly");
1181 // These must match the similar ones in E10SUtils.sys.mjs, RemoteTypes.h,
1182 // ProcInfo.h and ChromeUtils.webidl
1183 switch (aType) {
1184 PROCTYPE_TO_WEBIDL_CASE(Web, Web);
1185 PROCTYPE_TO_WEBIDL_CASE(WebIsolated, WebIsolated);
1186 PROCTYPE_TO_WEBIDL_CASE(File, File);
1187 PROCTYPE_TO_WEBIDL_CASE(Extension, Extension);
1188 PROCTYPE_TO_WEBIDL_CASE(PrivilegedAbout, Privilegedabout);
1189 PROCTYPE_TO_WEBIDL_CASE(PrivilegedMozilla, Privilegedmozilla);
1190 PROCTYPE_TO_WEBIDL_CASE(WebCOOPCOEP, WithCoopCoep);
1191 PROCTYPE_TO_WEBIDL_CASE(WebServiceWorker, WebServiceWorker);
1193 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
1194 process_bin_type, procinfo_typename, \
1195 webidl_typename, allcaps_name) \
1196 PROCTYPE_TO_WEBIDL_CASE(procinfo_typename, webidl_typename);
1197 #define SKIP_PROCESS_TYPE_CONTENT
1198 #ifndef MOZ_ENABLE_FORKSERVER
1199 # define SKIP_PROCESS_TYPE_FORKSERVER
1200 #endif // MOZ_ENABLE_FORKSERVER
1201 #include "mozilla/GeckoProcessTypes.h"
1202 #undef SKIP_PROCESS_TYPE_CONTENT
1203 #ifndef MOZ_ENABLE_FORKSERVER
1204 # undef SKIP_PROCESS_TYPE_FORKSERVER
1205 #endif // MOZ_ENABLE_FORKSERVER
1206 #undef GECKO_PROCESS_TYPE
1208 PROCTYPE_TO_WEBIDL_CASE(Preallocated, Preallocated);
1209 PROCTYPE_TO_WEBIDL_CASE(Unknown, Unknown);
1212 MOZ_ASSERT(false, "Unhandled case in ProcTypeToWebIDL");
1213 return WebIDLProcType::Unknown;
1216 #undef PROCTYPE_TO_WEBIDL_CASE
1218 /* static */
1219 already_AddRefed<Promise> ChromeUtils::RequestProcInfo(GlobalObject& aGlobal,
1220 ErrorResult& aRv) {
1221 // This function will use IPDL to enable threads info on macOS
1222 // see https://bugzilla.mozilla.org/show_bug.cgi?id=1529023
1223 if (!XRE_IsParentProcess()) {
1224 aRv.Throw(NS_ERROR_FAILURE);
1225 return nullptr;
1227 // Prepare the JS promise that will hold our response.
1228 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
1229 MOZ_ASSERT(global);
1230 RefPtr<Promise> domPromise = Promise::Create(global, aRv);
1231 if (NS_WARN_IF(aRv.Failed())) {
1232 return nullptr;
1234 MOZ_ASSERT(domPromise);
1236 // Get a list of processes to examine and pre-fill them with available info.
1237 // Note that this is subject to race conditions: just because we have a
1238 // process in the list doesn't mean that the process will still be alive when
1239 // we attempt to get its information. Followup code MUST be able to fail
1240 // gracefully on some processes and still return whichever information is
1241 // available.
1243 // Get all the content parents.
1244 // Note that this array includes even the long dead content parents, so we
1245 // might have some garbage, especially with Fission.
1246 // SAFETY NOTE: `contentParents` is only valid if used synchronously.
1247 // Anything else and you may end up dealing with dangling pointers.
1248 nsTArray<ContentParent*> contentParents;
1249 ContentParent::GetAll(contentParents);
1251 // Prepare our background request.
1252 // We reserve one more slot for the browser process itself.
1253 nsTArray<ProcInfoRequest> requests(contentParents.Length() + 1);
1254 // Requesting process info for the browser process itself.
1255 requests.EmplaceBack(
1256 /* aPid = */ base::GetCurrentProcId(),
1257 /* aProcessType = */ ProcType::Browser,
1258 /* aOrigin = */ ""_ns,
1259 /* aWindowInfo = */ nsTArray<WindowInfo>(),
1260 /* aUtilityInfo = */ nsTArray<UtilityInfo>());
1262 // First handle non-ContentParent processes.
1263 mozilla::ipc::GeckoChildProcessHost::GetAll(
1264 [&requests](mozilla::ipc::GeckoChildProcessHost* aGeckoProcess) {
1265 base::ProcessId childPid = aGeckoProcess->GetChildProcessId();
1266 if (childPid == 0) {
1267 // Something went wrong with this process, it may be dead already,
1268 // fail gracefully.
1269 return;
1271 mozilla::ProcType type = mozilla::ProcType::Unknown;
1273 switch (aGeckoProcess->GetProcessType()) {
1274 case GeckoProcessType::GeckoProcessType_Content: {
1275 // These processes are handled separately.
1276 return;
1279 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
1280 process_bin_type, procinfo_typename, \
1281 webidl_typename, allcaps_name) \
1282 case GeckoProcessType::GeckoProcessType_##enum_name: { \
1283 type = mozilla::ProcType::procinfo_typename; \
1284 break; \
1286 #define SKIP_PROCESS_TYPE_CONTENT
1287 #ifndef MOZ_ENABLE_FORKSERVER
1288 # define SKIP_PROCESS_TYPE_FORKSERVER
1289 #endif // MOZ_ENABLE_FORKSERVER
1290 #include "mozilla/GeckoProcessTypes.h"
1291 #ifndef MOZ_ENABLE_FORKSERVER
1292 # undef SKIP_PROCESS_TYPE_FORKSERVER
1293 #endif // MOZ_ENABLE_FORKSERVER
1294 #undef SKIP_PROCESS_TYPE_CONTENT
1295 #undef GECKO_PROCESS_TYPE
1296 default:
1297 // Leave the default Unknown value in |type|.
1298 break;
1301 // Attach utility actor information to the process.
1302 nsTArray<UtilityInfo> utilityActors;
1303 if (aGeckoProcess->GetProcessType() ==
1304 GeckoProcessType::GeckoProcessType_Utility) {
1305 RefPtr<mozilla::ipc::UtilityProcessManager> upm =
1306 mozilla::ipc::UtilityProcessManager::GetSingleton();
1307 if (!utilityActors.AppendElements(upm->GetActors(aGeckoProcess),
1308 fallible)) {
1309 NS_WARNING("Error adding actors");
1310 return;
1314 requests.EmplaceBack(
1315 /* aPid = */ childPid,
1316 /* aProcessType = */ type,
1317 /* aOrigin = */ ""_ns,
1318 /* aWindowInfo = */ nsTArray<WindowInfo>(), // Without a
1319 // ContentProcess, no
1320 // DOM windows.
1321 /* aUtilityInfo = */ std::move(utilityActors),
1322 /* aChild = */ 0 // Without a ContentProcess, no ChildId.
1323 #ifdef XP_MACOSX
1325 /* aChildTask = */ aGeckoProcess->GetChildTask()
1326 #endif // XP_MACOSX
1330 // Now handle ContentParents.
1331 for (const auto* contentParent : contentParents) {
1332 if (!contentParent || !contentParent->Process()) {
1333 // Presumably, the process is dead or dying.
1334 continue;
1336 base::ProcessId pid = contentParent->Process()->GetChildProcessId();
1337 if (pid == 0) {
1338 // Presumably, the process is dead or dying.
1339 continue;
1341 if (contentParent->Process()->GetProcessType() !=
1342 GeckoProcessType::GeckoProcessType_Content) {
1343 // We're probably racing against a process changing type.
1344 // We'll get it in the next call, skip it for the moment.
1345 continue;
1348 // Since this code is executed synchronously on the main thread,
1349 // processes cannot die while we're in this loop.
1350 mozilla::ProcType type = mozilla::ProcType::Unknown;
1352 // Convert the remoteType into a ProcType.
1353 // Ideally, the remoteType should be strongly typed
1354 // upstream, this would make the conversion less brittle.
1355 const nsAutoCString remoteType(contentParent->GetRemoteType());
1356 if (StringBeginsWith(remoteType, FISSION_WEB_REMOTE_TYPE)) {
1357 // WARNING: Do not change the order, as
1358 // `DEFAULT_REMOTE_TYPE` is a prefix of
1359 // `FISSION_WEB_REMOTE_TYPE`.
1360 type = mozilla::ProcType::WebIsolated;
1361 } else if (StringBeginsWith(remoteType, SERVICEWORKER_REMOTE_TYPE)) {
1362 type = mozilla::ProcType::WebServiceWorker;
1363 } else if (StringBeginsWith(remoteType,
1364 WITH_COOP_COEP_REMOTE_TYPE_PREFIX)) {
1365 type = mozilla::ProcType::WebCOOPCOEP;
1366 } else if (remoteType == FILE_REMOTE_TYPE) {
1367 type = mozilla::ProcType::File;
1368 } else if (remoteType == EXTENSION_REMOTE_TYPE) {
1369 type = mozilla::ProcType::Extension;
1370 } else if (remoteType == PRIVILEGEDABOUT_REMOTE_TYPE) {
1371 type = mozilla::ProcType::PrivilegedAbout;
1372 } else if (remoteType == PRIVILEGEDMOZILLA_REMOTE_TYPE) {
1373 type = mozilla::ProcType::PrivilegedMozilla;
1374 } else if (remoteType == PREALLOC_REMOTE_TYPE) {
1375 type = mozilla::ProcType::Preallocated;
1376 } else if (StringBeginsWith(remoteType, DEFAULT_REMOTE_TYPE)) {
1377 type = mozilla::ProcType::Web;
1378 } else {
1379 MOZ_CRASH_UNSAFE_PRINTF("Unknown remoteType '%s'", remoteType.get());
1382 // By convention, everything after '=' is the origin.
1383 nsAutoCString origin;
1384 nsACString::const_iterator cursor;
1385 nsACString::const_iterator end;
1386 remoteType.BeginReading(cursor);
1387 remoteType.EndReading(end);
1388 if (FindCharInReadable('=', cursor, end)) {
1389 origin = Substring(++cursor, end);
1392 // Attach DOM window information to the process.
1393 nsTArray<WindowInfo> windows;
1394 for (const auto& browserParentWrapperKey :
1395 contentParent->ManagedPBrowserParent()) {
1396 for (const auto& windowGlobalParentWrapperKey :
1397 browserParentWrapperKey->ManagedPWindowGlobalParent()) {
1398 // WindowGlobalParent is the only immediate subclass of
1399 // PWindowGlobalParent.
1400 auto* windowGlobalParent =
1401 static_cast<WindowGlobalParent*>(windowGlobalParentWrapperKey);
1403 nsString documentTitle;
1404 windowGlobalParent->GetDocumentTitle(documentTitle);
1405 WindowInfo* window = windows.EmplaceBack(
1406 fallible,
1407 /* aOuterWindowId = */ windowGlobalParent->OuterWindowId(),
1408 /* aDocumentURI = */ windowGlobalParent->GetDocumentURI(),
1409 /* aDocumentTitle = */ std::move(documentTitle),
1410 /* aIsProcessRoot = */ windowGlobalParent->IsProcessRoot(),
1411 /* aIsInProcess = */ windowGlobalParent->IsInProcess());
1412 if (!window) {
1413 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
1414 return nullptr;
1418 requests.EmplaceBack(
1419 /* aPid = */ pid,
1420 /* aProcessType = */ type,
1421 /* aOrigin = */ origin,
1422 /* aWindowInfo = */ std::move(windows),
1423 /* aUtilityInfo = */ nsTArray<UtilityInfo>(),
1424 /* aChild = */ contentParent->ChildID()
1425 #ifdef XP_MACOSX
1427 /* aChildTask = */ contentParent->Process()->GetChildTask()
1428 #endif // XP_MACOSX
1432 // Now place background request.
1433 RefPtr<nsISerialEventTarget> target =
1434 global->EventTargetFor(TaskCategory::Performance);
1435 mozilla::GetProcInfo(std::move(requests))
1436 ->Then(
1437 target, __func__,
1438 [target,
1439 domPromise](const HashMap<base::ProcessId, ProcInfo>& aSysProcInfo) {
1440 ParentProcInfoDictionary parentInfo;
1441 if (aSysProcInfo.count() == 0) {
1442 // For some reason, we couldn't get *any* info.
1443 // Maybe a sandboxing issue?
1444 domPromise->MaybeReject(NS_ERROR_UNEXPECTED);
1445 return;
1447 nsTArray<ChildProcInfoDictionary> childrenInfo(
1448 aSysProcInfo.count() - 1);
1449 for (auto iter = aSysProcInfo.iter(); !iter.done(); iter.next()) {
1450 const auto& sysProcInfo = iter.get().value();
1451 nsresult rv;
1452 if (sysProcInfo.type == ProcType::Browser) {
1453 rv = mozilla::CopySysProcInfoToDOM(sysProcInfo, &parentInfo);
1454 if (NS_FAILED(rv)) {
1455 // Failing to copy? That's probably not something from we can
1456 // (or should) try to recover gracefully.
1457 domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
1458 return;
1460 MOZ_ASSERT(sysProcInfo.childId == 0);
1461 MOZ_ASSERT(sysProcInfo.origin.IsEmpty());
1462 } else {
1463 mozilla::dom::ChildProcInfoDictionary* childInfo =
1464 childrenInfo.AppendElement(fallible);
1465 if (!childInfo) {
1466 domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
1467 return;
1469 rv = mozilla::CopySysProcInfoToDOM(sysProcInfo, childInfo);
1470 if (NS_FAILED(rv)) {
1471 domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
1472 return;
1474 // Copy Firefox info.
1475 childInfo->mChildID = sysProcInfo.childId;
1476 childInfo->mOrigin = sysProcInfo.origin;
1477 childInfo->mType = ProcTypeToWebIDL(sysProcInfo.type);
1479 for (const auto& source : sysProcInfo.windows) {
1480 auto* dest = childInfo->mWindows.AppendElement(fallible);
1481 if (!dest) {
1482 domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
1483 return;
1485 dest->mOuterWindowId = source.outerWindowId;
1486 dest->mDocumentURI = source.documentURI;
1487 dest->mDocumentTitle = source.documentTitle;
1488 dest->mIsProcessRoot = source.isProcessRoot;
1489 dest->mIsInProcess = source.isInProcess;
1492 if (sysProcInfo.type == ProcType::Utility) {
1493 for (const auto& source : sysProcInfo.utilityActors) {
1494 auto* dest =
1495 childInfo->mUtilityActors.AppendElement(fallible);
1496 if (!dest) {
1497 domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
1498 return;
1501 dest->mActorName = source.actorName;
1507 // Attach the children to the parent.
1508 mozilla::dom::Sequence<mozilla::dom::ChildProcInfoDictionary>
1509 children(std::move(childrenInfo));
1510 parentInfo.mChildren = std::move(children);
1511 domPromise->MaybeResolve(parentInfo);
1513 [domPromise](nsresult aRv) { domPromise->MaybeReject(aRv); });
1514 MOZ_ASSERT(domPromise);
1516 // sending back the promise instance
1517 return domPromise.forget();
1520 /* static */
1521 bool ChromeUtils::VsyncEnabled(GlobalObject& aGlobal) {
1522 return mozilla::gfx::VsyncSource::GetFastestVsyncRate().isSome();
1525 void ChromeUtils::SetPerfStatsCollectionMask(GlobalObject& aGlobal,
1526 uint64_t aMask) {
1527 PerfStats::SetCollectionMask(static_cast<PerfStats::MetricMask>(aMask));
1530 already_AddRefed<Promise> ChromeUtils::CollectPerfStats(GlobalObject& aGlobal,
1531 ErrorResult& aRv) {
1532 // Creating a JS promise
1533 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
1534 MOZ_ASSERT(global);
1536 RefPtr<Promise> promise = Promise::Create(global, aRv);
1537 if (aRv.Failed()) {
1538 return nullptr;
1541 RefPtr<PerfStats::PerfStatsPromise> extPromise =
1542 PerfStats::CollectPerfStatsJSON();
1544 extPromise->Then(
1545 GetCurrentSerialEventTarget(), __func__,
1546 [promise](const nsCString& aResult) {
1547 promise->MaybeResolve(NS_ConvertUTF8toUTF16(aResult));
1549 [promise](bool aValue) { promise->MaybeReject(NS_ERROR_FAILURE); });
1551 return promise.forget();
1554 constexpr auto kSkipSelfHosted = JS::SavedFrameSelfHosted::Exclude;
1556 /* static */
1557 void ChromeUtils::GetCallerLocation(const GlobalObject& aGlobal,
1558 nsIPrincipal* aPrincipal,
1559 JS::MutableHandle<JSObject*> aRetval) {
1560 JSContext* cx = aGlobal.Context();
1562 auto* principals = nsJSPrincipals::get(aPrincipal);
1564 JS::StackCapture captureMode(JS::FirstSubsumedFrame(cx, principals));
1566 JS::Rooted<JSObject*> frame(cx);
1567 if (!JS::CaptureCurrentStack(cx, &frame, std::move(captureMode))) {
1568 JS_ClearPendingException(cx);
1569 aRetval.set(nullptr);
1570 return;
1573 // FirstSubsumedFrame gets us a stack which stops at the first principal which
1574 // is subsumed by the given principal. That means that we may have a lot of
1575 // privileged frames that we don't care about at the top of the stack, though.
1576 // We need to filter those out to get the frame we actually want.
1577 aRetval.set(
1578 js::GetFirstSubsumedSavedFrame(cx, principals, frame, kSkipSelfHosted));
1581 /* static */
1582 void ChromeUtils::CreateError(const GlobalObject& aGlobal,
1583 const nsAString& aMessage,
1584 JS::Handle<JSObject*> aStack,
1585 JS::MutableHandle<JSObject*> aRetVal,
1586 ErrorResult& aRv) {
1587 if (aStack && !JS::IsMaybeWrappedSavedFrame(aStack)) {
1588 aRv.Throw(NS_ERROR_INVALID_ARG);
1589 return;
1592 JSContext* cx = aGlobal.Context();
1594 auto cleanup = MakeScopeExit([&]() { aRv.NoteJSContextException(cx); });
1596 JS::Rooted<JSObject*> retVal(cx);
1598 JS::Rooted<JSString*> fileName(cx, JS_GetEmptyString(cx));
1599 uint32_t line = 0;
1600 JS::TaggedColumnNumberOneOrigin column;
1602 Maybe<JSAutoRealm> ar;
1603 JS::Rooted<JSObject*> stack(cx);
1604 if (aStack) {
1605 stack = UncheckedUnwrap(aStack);
1606 ar.emplace(cx, stack);
1608 JSPrincipals* principals =
1609 JS::GetRealmPrincipals(js::GetContextRealm(cx));
1610 if (JS::GetSavedFrameLine(cx, principals, stack, &line) !=
1611 JS::SavedFrameResult::Ok ||
1612 JS::GetSavedFrameColumn(cx, principals, stack, &column) !=
1613 JS::SavedFrameResult::Ok ||
1614 JS::GetSavedFrameSource(cx, principals, stack, &fileName) !=
1615 JS::SavedFrameResult::Ok) {
1616 return;
1620 JS::Rooted<JSString*> message(cx);
1622 JS::Rooted<JS::Value> msgVal(cx);
1623 if (!xpc::NonVoidStringToJsval(cx, aMessage, &msgVal)) {
1624 return;
1626 message = msgVal.toString();
1629 JS::Rooted<JS::Value> err(cx);
1630 if (!JS::CreateError(cx, JSEXN_ERR, stack, fileName, line,
1631 JS::ColumnNumberOneOrigin(column.oneOriginValue()),
1632 nullptr, message, JS::NothingHandleValue, &err)) {
1633 return;
1636 MOZ_ASSERT(err.isObject());
1637 retVal = &err.toObject();
1640 if (aStack && !JS_WrapObject(cx, &retVal)) {
1641 return;
1644 cleanup.release();
1645 aRetVal.set(retVal);
1648 /* static */
1649 already_AddRefed<Promise> ChromeUtils::RequestIOActivity(GlobalObject& aGlobal,
1650 ErrorResult& aRv) {
1651 MOZ_ASSERT(XRE_IsParentProcess());
1652 MOZ_ASSERT(Preferences::GetBool(IO_ACTIVITY_ENABLED_PREF, false));
1653 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
1654 MOZ_ASSERT(global);
1655 RefPtr<Promise> domPromise = Promise::Create(global, aRv);
1656 if (NS_WARN_IF(aRv.Failed())) {
1657 return nullptr;
1659 MOZ_ASSERT(domPromise);
1660 mozilla::net::IOActivityMonitor::RequestActivities(domPromise);
1661 return domPromise.forget();
1664 /* static */
1665 bool ChromeUtils::HasReportingHeaderForOrigin(GlobalObject& global,
1666 const nsAString& aOrigin,
1667 ErrorResult& aRv) {
1668 if (!XRE_IsParentProcess()) {
1669 aRv.Throw(NS_ERROR_FAILURE);
1670 return false;
1673 return ReportingHeader::HasReportingHeaderForOrigin(
1674 NS_ConvertUTF16toUTF8(aOrigin));
1677 /* static */
1678 PopupBlockerState ChromeUtils::GetPopupControlState(GlobalObject& aGlobal) {
1679 switch (PopupBlocker::GetPopupControlState()) {
1680 case PopupBlocker::PopupControlState::openAllowed:
1681 return PopupBlockerState::OpenAllowed;
1683 case PopupBlocker::PopupControlState::openControlled:
1684 return PopupBlockerState::OpenControlled;
1686 case PopupBlocker::PopupControlState::openBlocked:
1687 return PopupBlockerState::OpenBlocked;
1689 case PopupBlocker::PopupControlState::openAbused:
1690 return PopupBlockerState::OpenAbused;
1692 case PopupBlocker::PopupControlState::openOverridden:
1693 return PopupBlockerState::OpenOverridden;
1695 default:
1696 MOZ_CRASH(
1697 "PopupBlocker::PopupControlState and PopupBlockerState are out of "
1698 "sync");
1702 /* static */
1703 double ChromeUtils::LastExternalProtocolIframeAllowed(GlobalObject& aGlobal) {
1704 TimeStamp when = PopupBlocker::WhenLastExternalProtocolIframeAllowed();
1705 if (when.IsNull()) {
1706 return 0;
1709 TimeDuration duration = TimeStamp::Now() - when;
1710 return duration.ToMilliseconds();
1713 /* static */
1714 void ChromeUtils::ResetLastExternalProtocolIframeAllowed(
1715 GlobalObject& aGlobal) {
1716 PopupBlocker::ResetLastExternalProtocolIframeAllowed();
1719 /* static */
1720 void ChromeUtils::EndWheelTransaction(GlobalObject& aGlobal) {
1721 // This allows us to end the current wheel transaction from the browser
1722 // chrome. We do not need to perform any checks before calling
1723 // EndTransaction(), as it should do nothing in the case that there is
1724 // no current wheel transaction.
1725 WheelTransaction::EndTransaction();
1728 /* static */
1729 void ChromeUtils::RegisterWindowActor(const GlobalObject& aGlobal,
1730 const nsACString& aName,
1731 const WindowActorOptions& aOptions,
1732 ErrorResult& aRv) {
1733 MOZ_ASSERT(XRE_IsParentProcess());
1735 RefPtr<JSActorService> service = JSActorService::GetSingleton();
1736 service->RegisterWindowActor(aName, aOptions, aRv);
1739 /* static */
1740 void ChromeUtils::UnregisterWindowActor(const GlobalObject& aGlobal,
1741 const nsACString& aName) {
1742 MOZ_ASSERT(XRE_IsParentProcess());
1744 RefPtr<JSActorService> service = JSActorService::GetSingleton();
1745 service->UnregisterWindowActor(aName);
1748 /* static */
1749 void ChromeUtils::RegisterProcessActor(const GlobalObject& aGlobal,
1750 const nsACString& aName,
1751 const ProcessActorOptions& aOptions,
1752 ErrorResult& aRv) {
1753 MOZ_ASSERT(XRE_IsParentProcess());
1755 RefPtr<JSActorService> service = JSActorService::GetSingleton();
1756 service->RegisterProcessActor(aName, aOptions, aRv);
1759 /* static */
1760 void ChromeUtils::UnregisterProcessActor(const GlobalObject& aGlobal,
1761 const nsACString& aName) {
1762 MOZ_ASSERT(XRE_IsParentProcess());
1764 RefPtr<JSActorService> service = JSActorService::GetSingleton();
1765 service->UnregisterProcessActor(aName);
1768 /* static */
1769 bool ChromeUtils::IsClassifierBlockingErrorCode(GlobalObject& aGlobal,
1770 uint32_t aError) {
1771 return net::UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode(
1772 static_cast<nsresult>(aError));
1775 /* static */
1776 void ChromeUtils::PrivateNoteIntentionalCrash(const GlobalObject& aGlobal,
1777 ErrorResult& aError) {
1778 if (XRE_IsContentProcess()) {
1779 NoteIntentionalCrash("tab");
1780 return;
1782 aError.Throw(NS_ERROR_NOT_IMPLEMENTED);
1785 /* static */
1786 nsIDOMProcessChild* ChromeUtils::GetDomProcessChild(const GlobalObject&) {
1787 return nsIDOMProcessChild::GetSingleton();
1790 /* static */
1791 void ChromeUtils::GetAllDOMProcesses(
1792 GlobalObject& aGlobal, nsTArray<RefPtr<nsIDOMProcessParent>>& aParents,
1793 ErrorResult& aRv) {
1794 if (!XRE_IsParentProcess()) {
1795 aRv.ThrowNotAllowedError(
1796 "getAllDOMProcesses() may only be called in the parent process");
1797 return;
1799 aParents.Clear();
1800 // Always add the parent process nsIDOMProcessParent first
1801 aParents.AppendElement(InProcessParent::Singleton());
1803 // Before adding nsIDOMProcessParent for all the content processes
1804 for (auto* cp : ContentParent::AllProcesses(ContentParent::eLive)) {
1805 aParents.AppendElement(cp);
1809 /* static */
1810 void ChromeUtils::ConsumeInteractionData(
1811 GlobalObject& aGlobal, Record<nsString, InteractionData>& aInteractions,
1812 ErrorResult& aRv) {
1813 if (!XRE_IsParentProcess()) {
1814 aRv.ThrowNotAllowedError(
1815 "consumeInteractionData() may only be called in the parent "
1816 "process");
1817 return;
1819 EventStateManager::ConsumeInteractionData(aInteractions);
1822 already_AddRefed<Promise> ChromeUtils::CollectScrollingData(
1823 GlobalObject& aGlobal, ErrorResult& aRv) {
1824 // Creating a JS promise
1825 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
1826 MOZ_ASSERT(global);
1828 RefPtr<Promise> promise = Promise::Create(global, aRv);
1829 if (aRv.Failed()) {
1830 return nullptr;
1833 RefPtr<ScrollingMetrics::ScrollingMetricsPromise> extPromise =
1834 ScrollingMetrics::CollectScrollingMetrics();
1836 extPromise->Then(
1837 GetCurrentSerialEventTarget(), __func__,
1838 [promise](const std::tuple<uint32_t, uint32_t>& aResult) {
1839 InteractionData out = {};
1840 out.mInteractionTimeInMilliseconds = std::get<0>(aResult);
1841 out.mScrollingDistanceInPixels = std::get<1>(aResult);
1842 promise->MaybeResolve(out);
1844 [promise](bool aValue) { promise->MaybeReject(NS_ERROR_FAILURE); });
1846 return promise.forget();
1849 /* static */
1850 void ChromeUtils::GetFormAutofillConfidences(
1851 GlobalObject& aGlobal, const Sequence<OwningNonNull<Element>>& aElements,
1852 nsTArray<FormAutofillConfidences>& aResults, ErrorResult& aRv) {
1853 FormAutofillNative::GetFormAutofillConfidences(aGlobal, aElements, aResults,
1854 aRv);
1857 bool ChromeUtils::IsDarkBackground(GlobalObject&, Element& aElement) {
1858 nsIFrame* f = aElement.GetPrimaryFrame(FlushType::Frames);
1859 if (!f) {
1860 return false;
1862 return nsNativeTheme::IsDarkBackground(f);
1865 double ChromeUtils::DateNow(GlobalObject&) { return JS_Now() / 1000.0; }
1867 /* static */
1868 void ChromeUtils::EnsureJSOracleStarted(GlobalObject&) {
1869 if (StaticPrefs::browser_opaqueResponseBlocking_javascriptValidator()) {
1870 JSOracleParent::WithJSOracle([](JSOracleParent* aParent) {});
1874 /* static */
1875 unsigned ChromeUtils::AliveUtilityProcesses(const GlobalObject&) {
1876 const auto& utilityProcessManager =
1877 mozilla::ipc::UtilityProcessManager::GetIfExists();
1878 return utilityProcessManager ? utilityProcessManager->AliveProcesses() : 0;
1881 /* static */
1882 void ChromeUtils::GetAllPossibleUtilityActorNames(GlobalObject& aGlobal,
1883 nsTArray<nsCString>& aNames) {
1884 aNames.Clear();
1885 for (size_t i = 0; i < WebIDLUtilityActorNameValues::Count; ++i) {
1886 auto idlName = static_cast<UtilityActorName>(i);
1887 aNames.AppendElement(WebIDLUtilityActorNameValues::GetString(idlName));
1891 /* static */
1892 bool ChromeUtils::ShouldResistFingerprinting(GlobalObject& aGlobal,
1893 JSRFPTarget aTarget) {
1894 RFPTarget target;
1895 switch (aTarget) {
1896 case JSRFPTarget::RoundWindowSize:
1897 target = RFPTarget::RoundWindowSize;
1898 break;
1899 case JSRFPTarget::SiteSpecificZoom:
1900 target = RFPTarget::SiteSpecificZoom;
1901 break;
1902 default:
1903 MOZ_CRASH("Unhandled JSRFPTarget enum value");
1906 return nsRFPService::IsRFPEnabledFor(target);
1909 std::atomic<uint32_t> ChromeUtils::sDevToolsOpenedCount = 0;
1911 /* static */
1912 bool ChromeUtils::IsDevToolsOpened() {
1913 return ChromeUtils::sDevToolsOpenedCount > 0;
1916 /* static */
1917 bool ChromeUtils::IsDevToolsOpened(GlobalObject& aGlobal) {
1918 return ChromeUtils::IsDevToolsOpened();
1921 /* static */
1922 void ChromeUtils::NotifyDevToolsOpened(GlobalObject& aGlobal) {
1923 ChromeUtils::sDevToolsOpenedCount++;
1926 /* static */
1927 void ChromeUtils::NotifyDevToolsClosed(GlobalObject& aGlobal) {
1928 MOZ_ASSERT(ChromeUtils::sDevToolsOpenedCount >= 1);
1929 ChromeUtils::sDevToolsOpenedCount--;
1932 } // namespace mozilla::dom