Merge mozilla-central to autoland on a CLOSED TREE
[gecko.git] / dom / base / ChromeUtils.cpp
blob2c979922d09e095989444fc95e5f2bc59b41be2e
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/CharacterEncoding.h"
12 #include "js/Object.h" // JS::GetClass
13 #include "js/PropertyAndElement.h" // JS_DefineProperty, JS_DefinePropertyById, JS_Enumerate, JS_GetProperty, JS_GetPropertyById, JS_SetProperty, JS_SetPropertyById, JS::IdVector
14 #include "js/PropertyDescriptor.h" // JS::PropertyDescriptor, JS_GetOwnPropertyDescriptorById
15 #include "js/SavedFrameAPI.h"
16 #include "js/Value.h" // JS::Value, JS::StringValue
17 #include "jsfriendapi.h"
18 #include "WrapperFactory.h"
20 #include "mozilla/Base64.h"
21 #include "mozilla/CycleCollectedJSRuntime.h"
22 #include "mozilla/ErrorNames.h"
23 #include "mozilla/EventStateManager.h"
24 #include "mozilla/FormAutofillNative.h"
25 #include "mozilla/IntentionalCrash.h"
26 #include "mozilla/PerfStats.h"
27 #include "mozilla/Preferences.h"
28 #include "mozilla/ProcInfo.h"
29 #include "mozilla/ResultExtensions.h"
30 #include "mozilla/ScopeExit.h"
31 #include "mozilla/ScrollingMetrics.h"
32 #include "mozilla/SharedStyleSheetCache.h"
33 #include "mozilla/TimeStamp.h"
34 #include "mozilla/dom/ContentParent.h"
35 #include "mozilla/dom/IdleDeadline.h"
36 #include "mozilla/dom/InProcessParent.h"
37 #include "mozilla/dom/JSActorService.h"
38 #include "mozilla/dom/MediaSessionBinding.h"
39 #include "mozilla/dom/PBrowserParent.h"
40 #include "mozilla/dom/Performance.h"
41 #include "mozilla/dom/PopupBlocker.h"
42 #include "mozilla/dom/Promise.h"
43 #include "mozilla/dom/Record.h"
44 #include "mozilla/dom/ReportingHeader.h"
45 #include "mozilla/dom/UnionTypes.h"
46 #include "mozilla/dom/WindowBinding.h" // For IdleRequestCallback/Options
47 #include "mozilla/dom/WindowGlobalParent.h"
48 #include "mozilla/dom/WorkerScope.h"
49 #include "mozilla/ipc/GeckoChildProcessHost.h"
50 #include "mozilla/ipc/UtilityProcessSandboxing.h"
51 #include "mozilla/ipc/UtilityProcessManager.h"
52 #include "mozilla/ipc/UtilityProcessHost.h"
53 #include "mozilla/net/UrlClassifierFeatureFactory.h"
54 #include "mozilla/WheelHandlingHelper.h"
55 #include "IOActivityMonitor.h"
56 #include "nsNativeTheme.h"
57 #include "nsThreadUtils.h"
58 #include "mozJSModuleLoader.h"
59 #include "mozilla/ProfilerLabels.h"
60 #include "mozilla/ProfilerMarkers.h"
61 #include "nsIException.h"
62 #include "VsyncSource.h"
64 #ifdef XP_UNIX
65 # include <errno.h>
66 # include <unistd.h>
67 # include <fcntl.h>
68 # include <poll.h>
69 # include <sys/wait.h>
71 # ifdef XP_LINUX
72 # include <sys/prctl.h>
73 # endif
74 #endif
76 namespace mozilla::dom {
78 /* static */
79 void ChromeUtils::NondeterministicGetWeakMapKeys(
80 GlobalObject& aGlobal, JS::Handle<JS::Value> aMap,
81 JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv) {
82 if (!aMap.isObject()) {
83 aRetval.setUndefined();
84 } else {
85 JSContext* cx = aGlobal.Context();
86 JS::Rooted<JSObject*> objRet(cx);
87 JS::Rooted<JSObject*> mapObj(cx, &aMap.toObject());
88 if (!JS_NondeterministicGetWeakMapKeys(cx, mapObj, &objRet)) {
89 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
90 } else {
91 aRetval.set(objRet ? JS::ObjectValue(*objRet) : JS::UndefinedValue());
96 /* static */
97 void ChromeUtils::NondeterministicGetWeakSetKeys(
98 GlobalObject& aGlobal, JS::Handle<JS::Value> aSet,
99 JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv) {
100 if (!aSet.isObject()) {
101 aRetval.setUndefined();
102 } else {
103 JSContext* cx = aGlobal.Context();
104 JS::Rooted<JSObject*> objRet(cx);
105 JS::Rooted<JSObject*> setObj(cx, &aSet.toObject());
106 if (!JS_NondeterministicGetWeakSetKeys(cx, setObj, &objRet)) {
107 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
108 } else {
109 aRetval.set(objRet ? JS::ObjectValue(*objRet) : JS::UndefinedValue());
114 /* static */
115 void ChromeUtils::Base64URLEncode(GlobalObject& aGlobal,
116 const ArrayBufferViewOrArrayBuffer& aSource,
117 const Base64URLEncodeOptions& aOptions,
118 nsACString& aResult, ErrorResult& aRv) {
119 size_t length = 0;
120 uint8_t* data = nullptr;
121 if (aSource.IsArrayBuffer()) {
122 const ArrayBuffer& buffer = aSource.GetAsArrayBuffer();
123 buffer.ComputeState();
124 length = buffer.Length();
125 data = buffer.Data();
126 } else if (aSource.IsArrayBufferView()) {
127 const ArrayBufferView& view = aSource.GetAsArrayBufferView();
128 view.ComputeState();
129 length = view.Length();
130 data = view.Data();
131 } else {
132 MOZ_CRASH("Uninitialized union: expected buffer or view");
135 auto paddingPolicy = aOptions.mPad ? Base64URLEncodePaddingPolicy::Include
136 : Base64URLEncodePaddingPolicy::Omit;
137 nsresult rv = mozilla::Base64URLEncode(length, data, paddingPolicy, aResult);
138 if (NS_WARN_IF(NS_FAILED(rv))) {
139 aResult.Truncate();
140 aRv.Throw(rv);
144 /* static */
145 void ChromeUtils::Base64URLDecode(GlobalObject& aGlobal,
146 const nsACString& aString,
147 const Base64URLDecodeOptions& aOptions,
148 JS::MutableHandle<JSObject*> aRetval,
149 ErrorResult& aRv) {
150 Base64URLDecodePaddingPolicy paddingPolicy;
151 switch (aOptions.mPadding) {
152 case Base64URLDecodePadding::Require:
153 paddingPolicy = Base64URLDecodePaddingPolicy::Require;
154 break;
156 case Base64URLDecodePadding::Ignore:
157 paddingPolicy = Base64URLDecodePaddingPolicy::Ignore;
158 break;
160 case Base64URLDecodePadding::Reject:
161 paddingPolicy = Base64URLDecodePaddingPolicy::Reject;
162 break;
164 default:
165 aRv.Throw(NS_ERROR_INVALID_ARG);
166 return;
168 FallibleTArray<uint8_t> data;
169 nsresult rv = mozilla::Base64URLDecode(aString, paddingPolicy, data);
170 if (NS_WARN_IF(NS_FAILED(rv))) {
171 aRv.Throw(rv);
172 return;
175 JS::Rooted<JSObject*> buffer(
176 aGlobal.Context(),
177 ArrayBuffer::Create(aGlobal.Context(), data.Length(), data.Elements()));
178 if (NS_WARN_IF(!buffer)) {
179 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
180 return;
182 aRetval.set(buffer);
185 /* static */
186 void ChromeUtils::ReleaseAssert(GlobalObject& aGlobal, bool aCondition,
187 const nsAString& aMessage) {
188 // If the condition didn't fail, which is the likely case, immediately return.
189 if (MOZ_LIKELY(aCondition)) {
190 return;
193 // Extract the current stack from the JS runtime to embed in the crash reason.
194 nsAutoString filename;
195 uint32_t lineNo = 0;
197 if (nsCOMPtr<nsIStackFrame> location = GetCurrentJSStack(1)) {
198 location->GetFilename(aGlobal.Context(), filename);
199 lineNo = location->GetLineNumber(aGlobal.Context());
200 } else {
201 filename.Assign(u"<unknown>"_ns);
204 // Convert to utf-8 for adding as the MozCrashReason.
205 NS_ConvertUTF16toUTF8 filenameUtf8(filename);
206 NS_ConvertUTF16toUTF8 messageUtf8(aMessage);
208 // Actually crash.
209 MOZ_CRASH_UNSAFE_PRINTF("Failed ChromeUtils.releaseAssert(\"%s\") @ %s:%u",
210 messageUtf8.get(), filenameUtf8.get(), lineNo);
213 /* static */
214 void ChromeUtils::AddProfilerMarker(
215 GlobalObject& aGlobal, const nsACString& aName,
216 const ProfilerMarkerOptionsOrDouble& aOptions,
217 const Optional<nsACString>& aText) {
218 if (!profiler_thread_is_being_profiled_for_markers()) {
219 return;
222 MarkerOptions options;
224 MarkerCategory category = ::geckoprofiler::category::JS;
226 DOMHighResTimeStamp startTime = 0;
227 uint64_t innerWindowId = 0;
228 if (aOptions.IsDouble()) {
229 startTime = aOptions.GetAsDouble();
230 } else {
231 const ProfilerMarkerOptions& opt = aOptions.GetAsProfilerMarkerOptions();
232 startTime = opt.mStartTime;
233 innerWindowId = opt.mInnerWindowId;
235 if (opt.mCaptureStack) {
236 // If we will be capturing a stack, change the category of the
237 // ChromeUtils.addProfilerMarker label automatically added by the webidl
238 // binding from DOM to PROFILER so that this function doesn't appear in
239 // the marker stack.
240 JSContext* cx = aGlobal.Context();
241 ProfilingStack* stack = js::GetContextProfilingStackIfEnabled(cx);
242 if (MOZ_LIKELY(stack)) {
243 uint32_t sp = stack->stackPointer;
244 if (MOZ_LIKELY(sp > 0)) {
245 js::ProfilingStackFrame& frame = stack->frames[sp - 1];
246 if (frame.isLabelFrame() && "ChromeUtils"_ns.Equals(frame.label()) &&
247 "addProfilerMarker"_ns.Equals(frame.dynamicString())) {
248 frame.setLabelCategory(JS::ProfilingCategoryPair::PROFILER);
253 options.Set(MarkerStack::Capture());
255 #define BEGIN_CATEGORY(name, labelAsString, color) \
256 if (opt.mCategory.Equals(labelAsString)) { \
257 category = ::geckoprofiler::category::name; \
258 } else
259 #define SUBCATEGORY(supercategory, name, labelAsString)
260 #define END_CATEGORY
261 MOZ_PROFILING_CATEGORY_LIST(BEGIN_CATEGORY, SUBCATEGORY, END_CATEGORY)
262 #undef BEGIN_CATEGORY
263 #undef SUBCATEGORY
264 #undef END_CATEGORY
266 category = ::geckoprofiler::category::OTHER;
269 if (startTime) {
270 RefPtr<Performance> performance;
272 if (NS_IsMainThread()) {
273 nsCOMPtr<nsPIDOMWindowInner> ownerWindow =
274 do_QueryInterface(aGlobal.GetAsSupports());
275 if (ownerWindow) {
276 performance = ownerWindow->GetPerformance();
278 } else {
279 JSContext* cx = aGlobal.Context();
280 WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
281 if (workerPrivate) {
282 performance = workerPrivate->GlobalScope()->GetPerformance();
286 if (performance) {
287 options.Set(MarkerTiming::IntervalUntilNowFrom(
288 performance->CreationTimeStamp() +
289 TimeDuration::FromMilliseconds(startTime)));
290 } else {
291 options.Set(MarkerTiming::IntervalUntilNowFrom(
292 TimeStamp::ProcessCreation() +
293 TimeDuration::FromMilliseconds(startTime)));
297 if (innerWindowId) {
298 options.Set(MarkerInnerWindowId(innerWindowId));
299 } else {
300 options.Set(MarkerInnerWindowIdFromJSContext(aGlobal.Context()));
304 AUTO_PROFILER_STATS(ChromeUtils_AddProfilerMarker);
305 if (aText.WasPassed()) {
306 profiler_add_marker(aName, category, std::move(options),
307 ::geckoprofiler::markers::TextMarker{},
308 aText.Value());
309 } else {
310 profiler_add_marker(aName, category, std::move(options));
315 /* static */
316 void ChromeUtils::GetXPCOMErrorName(GlobalObject& aGlobal, uint32_t aErrorCode,
317 nsACString& aRetval) {
318 GetErrorName((nsresult)aErrorCode, aRetval);
321 /* static */
322 void ChromeUtils::WaiveXrays(GlobalObject& aGlobal, JS::Handle<JS::Value> aVal,
323 JS::MutableHandle<JS::Value> aRetval,
324 ErrorResult& aRv) {
325 JS::Rooted<JS::Value> value(aGlobal.Context(), aVal);
326 if (!xpc::WrapperFactory::WaiveXrayAndWrap(aGlobal.Context(), &value)) {
327 aRv.NoteJSContextException(aGlobal.Context());
328 } else {
329 aRetval.set(value);
333 /* static */
334 void ChromeUtils::UnwaiveXrays(GlobalObject& aGlobal,
335 JS::Handle<JS::Value> aVal,
336 JS::MutableHandle<JS::Value> aRetval,
337 ErrorResult& aRv) {
338 if (!aVal.isObject()) {
339 aRetval.set(aVal);
340 return;
343 JS::Rooted<JSObject*> obj(aGlobal.Context(),
344 js::UncheckedUnwrap(&aVal.toObject()));
345 if (!JS_WrapObject(aGlobal.Context(), &obj)) {
346 aRv.NoteJSContextException(aGlobal.Context());
347 } else {
348 aRetval.setObject(*obj);
352 /* static */
353 void ChromeUtils::GetClassName(GlobalObject& aGlobal,
354 JS::Handle<JSObject*> aObj, bool aUnwrap,
355 nsAString& aRetval) {
356 JS::Rooted<JSObject*> obj(aGlobal.Context(), aObj);
357 if (aUnwrap) {
358 obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
361 aRetval = NS_ConvertUTF8toUTF16(nsDependentCString(JS::GetClass(obj)->name));
364 /* static */
365 bool ChromeUtils::IsDOMObject(GlobalObject& aGlobal, JS::Handle<JSObject*> aObj,
366 bool aUnwrap) {
367 JS::Rooted<JSObject*> obj(aGlobal.Context(), aObj);
368 if (aUnwrap) {
369 obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
372 return mozilla::dom::IsDOMObject(obj);
375 /* static */
376 void ChromeUtils::ShallowClone(GlobalObject& aGlobal,
377 JS::Handle<JSObject*> aObj,
378 JS::Handle<JSObject*> aTarget,
379 JS::MutableHandle<JSObject*> aRetval,
380 ErrorResult& aRv) {
381 JSContext* cx = aGlobal.Context();
383 auto cleanup = MakeScopeExit([&]() { aRv.NoteJSContextException(cx); });
385 JS::Rooted<JS::IdVector> ids(cx, JS::IdVector(cx));
386 JS::RootedVector<JS::Value> values(cx);
387 JS::RootedVector<jsid> valuesIds(cx);
390 // cx represents our current Realm, so it makes sense to use it for the
391 // CheckedUnwrapDynamic call. We do want CheckedUnwrapDynamic, in case
392 // someone is shallow-cloning a Window.
393 JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrapDynamic(aObj, cx));
394 if (!obj) {
395 js::ReportAccessDenied(cx);
396 return;
399 if (js::IsScriptedProxy(obj)) {
400 JS_ReportErrorASCII(cx, "Shallow cloning a proxy object is not allowed");
401 return;
404 JSAutoRealm ar(cx, obj);
406 if (!JS_Enumerate(cx, obj, &ids) || !values.reserve(ids.length()) ||
407 !valuesIds.reserve(ids.length())) {
408 return;
411 JS::Rooted<Maybe<JS::PropertyDescriptor>> desc(cx);
412 JS::Rooted<JS::PropertyKey> id(cx);
413 for (jsid idVal : ids) {
414 id = idVal;
415 if (!JS_GetOwnPropertyDescriptorById(cx, obj, id, &desc)) {
416 continue;
418 if (desc.isNothing() || desc->isAccessorDescriptor()) {
419 continue;
421 valuesIds.infallibleAppend(id);
422 values.infallibleAppend(desc->value());
426 JS::Rooted<JSObject*> obj(cx);
428 Maybe<JSAutoRealm> ar;
429 if (aTarget) {
430 // Our target could be anything, so we want CheckedUnwrapDynamic here.
431 // "cx" represents the current Realm when we were called from bindings, so
432 // we can just use that.
433 JS::Rooted<JSObject*> target(cx, js::CheckedUnwrapDynamic(aTarget, cx));
434 if (!target) {
435 js::ReportAccessDenied(cx);
436 return;
438 ar.emplace(cx, target);
441 obj = JS_NewPlainObject(cx);
442 if (!obj) {
443 return;
446 JS::Rooted<JS::Value> value(cx);
447 JS::Rooted<JS::PropertyKey> id(cx);
448 for (uint32_t i = 0; i < valuesIds.length(); i++) {
449 id = valuesIds[i];
450 value = values[i];
452 JS_MarkCrossZoneId(cx, id);
453 if (!JS_WrapValue(cx, &value) ||
454 !JS_SetPropertyById(cx, obj, id, value)) {
455 return;
460 if (aTarget && !JS_WrapObject(cx, &obj)) {
461 return;
464 cleanup.release();
465 aRetval.set(obj);
468 namespace {
469 class IdleDispatchRunnable final : public IdleRunnable,
470 public nsITimerCallback {
471 public:
472 NS_DECL_ISUPPORTS_INHERITED
474 IdleDispatchRunnable(nsIGlobalObject* aParent, IdleRequestCallback& aCallback)
475 : IdleRunnable("ChromeUtils::IdleDispatch"),
476 mCallback(&aCallback),
477 mParent(aParent) {}
479 // MOZ_CAN_RUN_SCRIPT_BOUNDARY until Runnable::Run is MOZ_CAN_RUN_SCRIPT.
480 // See bug 1535398.
481 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override {
482 if (mCallback) {
483 CancelTimer();
485 auto deadline = mDeadline - TimeStamp::ProcessCreation();
487 ErrorResult rv;
488 RefPtr<IdleDeadline> idleDeadline =
489 new IdleDeadline(mParent, mTimedOut, deadline.ToMilliseconds());
491 RefPtr<IdleRequestCallback> callback(std::move(mCallback));
492 MOZ_ASSERT(!mCallback);
493 callback->Call(*idleDeadline, "ChromeUtils::IdleDispatch handler");
494 mParent = nullptr;
496 return NS_OK;
499 void SetDeadline(TimeStamp aDeadline) override { mDeadline = aDeadline; }
501 NS_IMETHOD Notify(nsITimer* aTimer) override {
502 mTimedOut = true;
503 SetDeadline(TimeStamp::Now());
504 return Run();
507 void SetTimer(uint32_t aDelay, nsIEventTarget* aTarget) override {
508 MOZ_ASSERT(aTarget);
509 MOZ_ASSERT(!mTimer);
510 NS_NewTimerWithCallback(getter_AddRefs(mTimer), this, aDelay,
511 nsITimer::TYPE_ONE_SHOT, aTarget);
514 protected:
515 virtual ~IdleDispatchRunnable() { CancelTimer(); }
517 private:
518 void CancelTimer() {
519 if (mTimer) {
520 mTimer->Cancel();
521 mTimer = nullptr;
525 RefPtr<IdleRequestCallback> mCallback;
526 nsCOMPtr<nsIGlobalObject> mParent;
528 nsCOMPtr<nsITimer> mTimer;
530 TimeStamp mDeadline{};
531 bool mTimedOut = false;
534 NS_IMPL_ISUPPORTS_INHERITED(IdleDispatchRunnable, IdleRunnable,
535 nsITimerCallback)
536 } // anonymous namespace
538 /* static */
539 void ChromeUtils::IdleDispatch(const GlobalObject& aGlobal,
540 IdleRequestCallback& aCallback,
541 const IdleRequestOptions& aOptions,
542 ErrorResult& aRv) {
543 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
544 MOZ_ASSERT(global);
546 auto runnable = MakeRefPtr<IdleDispatchRunnable>(global, aCallback);
548 if (aOptions.mTimeout.WasPassed()) {
549 aRv = NS_DispatchToCurrentThreadQueue(
550 runnable.forget(), aOptions.mTimeout.Value(), EventQueuePriority::Idle);
551 } else {
552 aRv = NS_DispatchToCurrentThreadQueue(runnable.forget(),
553 EventQueuePriority::Idle);
557 /* static */
558 void ChromeUtils::Import(const GlobalObject& aGlobal,
559 const nsACString& aResourceURI,
560 const Optional<JS::Handle<JSObject*>>& aTargetObj,
561 JS::MutableHandle<JSObject*> aRetval,
562 ErrorResult& aRv) {
563 RefPtr moduleloader = mozJSModuleLoader::Get();
564 MOZ_ASSERT(moduleloader);
566 AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING_NONSENSITIVE("ChromeUtils::Import",
567 OTHER, aResourceURI);
569 JSContext* cx = aGlobal.Context();
571 JS::Rooted<JSObject*> global(cx);
572 JS::Rooted<JSObject*> exports(cx);
573 nsresult rv = moduleloader->Import(cx, aResourceURI, &global, &exports);
574 if (NS_FAILED(rv)) {
575 aRv.Throw(rv);
576 return;
579 // Import() on the component loader can return NS_OK while leaving an
580 // exception on the JSContext. Check for that case.
581 if (JS_IsExceptionPending(cx)) {
582 aRv.NoteJSContextException(cx);
583 return;
586 if (aTargetObj.WasPassed()) {
587 if (!JS_AssignObject(cx, aTargetObj.Value(), exports)) {
588 aRv.Throw(NS_ERROR_FAILURE);
589 return;
593 if (!JS_WrapObject(cx, &exports)) {
594 aRv.Throw(NS_ERROR_FAILURE);
595 return;
597 aRetval.set(exports);
600 static mozJSModuleLoader* GetContextualESLoader(
601 const Optional<bool>& aLoadInDevToolsLoader, JSObject* aGlobal) {
602 RefPtr devToolsModuleloader = mozJSModuleLoader::GetDevToolsLoader();
603 // We should load the module in the DevTools loader if:
604 // - ChromeUtils.importESModule's `loadInDevToolsLoader` option is true, or,
605 // - if the callsite is from a module loaded in the DevTools loader and
606 // `loadInDevToolsLoader` isn't an explicit false.
607 bool shouldUseDevToolsLoader =
608 (aLoadInDevToolsLoader.WasPassed() && aLoadInDevToolsLoader.Value()) ||
609 (devToolsModuleloader && !aLoadInDevToolsLoader.WasPassed() &&
610 devToolsModuleloader->IsLoaderGlobal(aGlobal));
611 if (shouldUseDevToolsLoader) {
612 return mozJSModuleLoader::GetOrCreateDevToolsLoader();
614 return mozJSModuleLoader::Get();
617 /* static */
618 void ChromeUtils::ImportESModule(
619 const GlobalObject& aGlobal, const nsAString& aResourceURI,
620 const ImportESModuleOptionsDictionary& aOptions,
621 JS::MutableHandle<JSObject*> aRetval, ErrorResult& aRv) {
622 RefPtr moduleloader =
623 GetContextualESLoader(aOptions.mLoadInDevToolsLoader, aGlobal.Get());
624 MOZ_ASSERT(moduleloader);
626 NS_ConvertUTF16toUTF8 registryLocation(aResourceURI);
628 AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING_NONSENSITIVE(
629 "ChromeUtils::ImportESModule", OTHER, registryLocation);
631 JSContext* cx = aGlobal.Context();
633 JS::Rooted<JSObject*> moduleNamespace(cx);
634 nsresult rv =
635 moduleloader->ImportESModule(cx, registryLocation, &moduleNamespace);
636 if (NS_FAILED(rv)) {
637 aRv.Throw(rv);
638 return;
641 MOZ_ASSERT(!JS_IsExceptionPending(cx));
643 if (!JS_WrapObject(cx, &moduleNamespace)) {
644 aRv.Throw(NS_ERROR_FAILURE);
645 return;
647 aRetval.set(moduleNamespace);
650 namespace lazy_getter {
652 static const size_t SLOT_ID = 0;
653 static const size_t SLOT_URI = 1;
654 static const size_t SLOT_PARAMS = 1;
656 static const size_t PARAM_INDEX_TARGET = 0;
657 static const size_t PARAM_INDEX_LAMBDA = 1;
658 static const size_t PARAMS_COUNT = 2;
660 static bool ExtractArgs(JSContext* aCx, JS::CallArgs& aArgs,
661 JS::MutableHandle<JSObject*> aCallee,
662 JS::MutableHandle<JSObject*> aThisObj,
663 JS::MutableHandle<jsid> aId) {
664 aCallee.set(&aArgs.callee());
666 JS::Handle<JS::Value> thisv = aArgs.thisv();
667 if (!thisv.isObject()) {
668 JS_ReportErrorASCII(aCx, "Invalid target object");
669 return false;
672 aThisObj.set(&thisv.toObject());
674 JS::Rooted<JS::Value> id(aCx,
675 js::GetFunctionNativeReserved(aCallee, SLOT_ID));
676 MOZ_ALWAYS_TRUE(JS_ValueToId(aCx, id, aId));
677 return true;
680 static bool JSLazyGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
681 JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
683 JS::Rooted<JSObject*> callee(aCx);
684 JS::Rooted<JSObject*> unused(aCx);
685 JS::Rooted<jsid> id(aCx);
686 if (!ExtractArgs(aCx, args, &callee, &unused, &id)) {
687 return false;
690 JS::Rooted<JS::Value> paramsVal(
691 aCx, js::GetFunctionNativeReserved(callee, SLOT_PARAMS));
692 if (paramsVal.isUndefined()) {
693 args.rval().setUndefined();
694 return true;
696 // Avoid calling the lambda multiple times, in case of:
697 // * the getter function is retrieved from property descriptor and called
698 // * the lambda gets the property again
699 // * the getter function throws and accessed again
700 js::SetFunctionNativeReserved(callee, SLOT_PARAMS, JS::UndefinedHandleValue);
702 JS::Rooted<JSObject*> paramsObj(aCx, &paramsVal.toObject());
704 JS::Rooted<JS::Value> targetVal(aCx);
705 JS::Rooted<JS::Value> lambdaVal(aCx);
706 if (!JS_GetElement(aCx, paramsObj, PARAM_INDEX_TARGET, &targetVal)) {
707 return false;
709 if (!JS_GetElement(aCx, paramsObj, PARAM_INDEX_LAMBDA, &lambdaVal)) {
710 return false;
713 JS::Rooted<JSObject*> targetObj(aCx, &targetVal.toObject());
715 JS::Rooted<JS::Value> value(aCx);
716 if (!JS::Call(aCx, targetObj, lambdaVal, JS::HandleValueArray::empty(),
717 &value)) {
718 return false;
721 if (!JS_DefinePropertyById(aCx, targetObj, id, value, JSPROP_ENUMERATE)) {
722 return false;
725 args.rval().set(value);
726 return true;
729 static bool DefineLazyGetter(JSContext* aCx, JS::Handle<JSObject*> aTarget,
730 JS::Handle<JS::Value> aName,
731 JS::Handle<JSObject*> aLambda) {
732 JS::Rooted<jsid> id(aCx);
733 if (!JS_ValueToId(aCx, aName, &id)) {
734 return false;
737 JS::Rooted<JSObject*> getter(
738 aCx, JS_GetFunctionObject(
739 js::NewFunctionByIdWithReserved(aCx, JSLazyGetter, 0, 0, id)));
740 if (!getter) {
741 JS_ReportOutOfMemory(aCx);
742 return false;
745 JS::RootedVector<JS::Value> params(aCx);
746 if (!params.resize(PARAMS_COUNT)) {
747 return false;
749 params[PARAM_INDEX_TARGET].setObject(*aTarget);
750 params[PARAM_INDEX_LAMBDA].setObject(*aLambda);
751 JS::Rooted<JSObject*> paramsObj(aCx, JS::NewArrayObject(aCx, params));
752 if (!paramsObj) {
753 return false;
756 js::SetFunctionNativeReserved(getter, SLOT_ID, aName);
757 js::SetFunctionNativeReserved(getter, SLOT_PARAMS,
758 JS::ObjectValue(*paramsObj));
760 return JS_DefinePropertyById(aCx, aTarget, id, getter, nullptr,
761 JSPROP_ENUMERATE);
764 enum class ModuleType { JSM, ESM };
766 static bool ModuleGetterImpl(JSContext* aCx, unsigned aArgc, JS::Value* aVp,
767 ModuleType aType) {
768 JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
770 JS::Rooted<JSObject*> callee(aCx);
771 JS::Rooted<JSObject*> thisObj(aCx);
772 JS::Rooted<jsid> id(aCx);
773 if (!ExtractArgs(aCx, args, &callee, &thisObj, &id)) {
774 return false;
777 JS::Rooted<JSString*> moduleURI(
778 aCx, js::GetFunctionNativeReserved(callee, SLOT_URI).toString());
779 JS::UniqueChars bytes = JS_EncodeStringToUTF8(aCx, moduleURI);
780 if (!bytes) {
781 return false;
783 nsDependentCString uri(bytes.get());
785 RefPtr moduleloader =
786 aType == ModuleType::JSM
787 ? mozJSModuleLoader::Get()
788 : GetContextualESLoader(
789 Optional<bool>(),
790 JS::GetNonCCWObjectGlobal(js::UncheckedUnwrap(thisObj)));
791 MOZ_ASSERT(moduleloader);
793 JS::Rooted<JS::Value> value(aCx);
794 if (aType == ModuleType::JSM) {
795 JS::Rooted<JSObject*> moduleGlobal(aCx);
796 JS::Rooted<JSObject*> moduleExports(aCx);
797 nsresult rv = moduleloader->Import(aCx, uri, &moduleGlobal, &moduleExports);
798 if (NS_FAILED(rv)) {
799 Throw(aCx, rv);
800 return false;
803 // JSM's exports is from the same realm.
804 if (!JS_GetPropertyById(aCx, moduleExports, id, &value)) {
805 return false;
807 } else {
808 JS::Rooted<JSObject*> moduleNamespace(aCx);
809 nsresult rv = moduleloader->ImportESModule(aCx, uri, &moduleNamespace);
810 if (NS_FAILED(rv)) {
811 Throw(aCx, rv);
812 return false;
815 // ESM's namespace is from the module's realm.
817 JSAutoRealm ar(aCx, moduleNamespace);
818 if (!JS_GetPropertyById(aCx, moduleNamespace, id, &value)) {
819 return false;
822 if (!JS_WrapValue(aCx, &value)) {
823 return false;
827 if (!JS_DefinePropertyById(aCx, thisObj, id, value, JSPROP_ENUMERATE)) {
828 return false;
831 args.rval().set(value);
832 return true;
835 static bool JSModuleGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
836 return ModuleGetterImpl(aCx, aArgc, aVp, ModuleType::JSM);
839 static bool ESModuleGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
840 return ModuleGetterImpl(aCx, aArgc, aVp, ModuleType::ESM);
843 static bool ModuleSetterImpl(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
844 JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
846 JS::Rooted<JSObject*> callee(aCx);
847 JS::Rooted<JSObject*> thisObj(aCx);
848 JS::Rooted<jsid> id(aCx);
849 if (!ExtractArgs(aCx, args, &callee, &thisObj, &id)) {
850 return false;
853 return JS_DefinePropertyById(aCx, thisObj, id, args.get(0), JSPROP_ENUMERATE);
856 static bool JSModuleSetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
857 return ModuleSetterImpl(aCx, aArgc, aVp);
860 static bool ESModuleSetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
861 return ModuleSetterImpl(aCx, aArgc, aVp);
864 static bool DefineJSModuleGetter(JSContext* aCx, JS::Handle<JSObject*> aTarget,
865 const nsAString& aId,
866 const nsAString& aResourceURI) {
867 JS::Rooted<JS::Value> uri(aCx);
868 JS::Rooted<JS::Value> idValue(aCx);
869 JS::Rooted<jsid> id(aCx);
870 if (!xpc::NonVoidStringToJsval(aCx, aResourceURI, &uri) ||
871 !xpc::NonVoidStringToJsval(aCx, aId, &idValue) ||
872 !JS_ValueToId(aCx, idValue, &id)) {
873 return false;
875 idValue = js::IdToValue(id);
877 JS::Rooted<JSObject*> getter(
878 aCx, JS_GetFunctionObject(
879 js::NewFunctionByIdWithReserved(aCx, JSModuleGetter, 0, 0, id)));
881 JS::Rooted<JSObject*> setter(
882 aCx, JS_GetFunctionObject(
883 js::NewFunctionByIdWithReserved(aCx, JSModuleSetter, 0, 0, id)));
885 if (!getter || !setter) {
886 JS_ReportOutOfMemory(aCx);
887 return false;
890 js::SetFunctionNativeReserved(getter, SLOT_ID, idValue);
891 js::SetFunctionNativeReserved(setter, SLOT_ID, idValue);
893 js::SetFunctionNativeReserved(getter, SLOT_URI, uri);
895 return JS_DefinePropertyById(aCx, aTarget, id, getter, setter,
896 JSPROP_ENUMERATE);
899 static bool DefineESModuleGetter(JSContext* aCx, JS::Handle<JSObject*> aTarget,
900 JS::Handle<JS::PropertyKey> aId,
901 JS::Handle<JS::Value> aResourceURI) {
902 JS::Rooted<JS::Value> idVal(aCx, JS::StringValue(aId.toString()));
904 JS::Rooted<JSObject*> getter(
905 aCx, JS_GetFunctionObject(js::NewFunctionByIdWithReserved(
906 aCx, ESModuleGetter, 0, 0, aId)));
908 JS::Rooted<JSObject*> setter(
909 aCx, JS_GetFunctionObject(js::NewFunctionByIdWithReserved(
910 aCx, ESModuleSetter, 0, 0, aId)));
912 if (!getter || !setter) {
913 JS_ReportOutOfMemory(aCx);
914 return false;
917 js::SetFunctionNativeReserved(getter, SLOT_ID, idVal);
918 js::SetFunctionNativeReserved(setter, SLOT_ID, idVal);
920 js::SetFunctionNativeReserved(getter, SLOT_URI, aResourceURI);
922 return JS_DefinePropertyById(aCx, aTarget, aId, getter, setter,
923 JSPROP_ENUMERATE);
926 } // namespace lazy_getter
928 /* static */
929 void ChromeUtils::DefineLazyGetter(const GlobalObject& aGlobal,
930 JS::Handle<JSObject*> aTarget,
931 JS::Handle<JS::Value> aName,
932 JS::Handle<JSObject*> aLambda,
933 ErrorResult& aRv) {
934 JSContext* cx = aGlobal.Context();
935 if (!lazy_getter::DefineLazyGetter(cx, aTarget, aName, aLambda)) {
936 aRv.NoteJSContextException(cx);
937 return;
941 /* static */
942 void ChromeUtils::DefineModuleGetter(const GlobalObject& global,
943 JS::Handle<JSObject*> target,
944 const nsAString& id,
945 const nsAString& resourceURI,
946 ErrorResult& aRv) {
947 if (!lazy_getter::DefineJSModuleGetter(global.Context(), target, id,
948 resourceURI)) {
949 aRv.NoteJSContextException(global.Context());
953 /* static */
954 void ChromeUtils::DefineESModuleGetters(const GlobalObject& global,
955 JS::Handle<JSObject*> target,
956 JS::Handle<JSObject*> modules,
957 ErrorResult& aRv) {
958 JSContext* cx = global.Context();
960 JS::Rooted<JS::IdVector> props(cx, JS::IdVector(cx));
961 if (!JS_Enumerate(cx, modules, &props)) {
962 aRv.NoteJSContextException(cx);
963 return;
966 JS::Rooted<JS::PropertyKey> prop(cx);
967 JS::Rooted<JS::Value> resourceURIVal(cx);
968 for (JS::PropertyKey tmp : props) {
969 prop = tmp;
971 if (!prop.isString()) {
972 aRv.Throw(NS_ERROR_FAILURE);
973 return;
976 if (!JS_GetPropertyById(cx, modules, prop, &resourceURIVal)) {
977 aRv.NoteJSContextException(cx);
978 return;
981 if (!lazy_getter::DefineESModuleGetter(cx, target, prop, resourceURIVal)) {
982 aRv.NoteJSContextException(cx);
983 return;
988 #ifdef XP_UNIX
989 /* static */
990 void ChromeUtils::GetLibcConstants(const GlobalObject&,
991 LibcConstants& aConsts) {
992 aConsts.mEINTR.Construct(EINTR);
993 aConsts.mEACCES.Construct(EACCES);
994 aConsts.mEAGAIN.Construct(EAGAIN);
995 aConsts.mEINVAL.Construct(EINVAL);
996 aConsts.mENOSYS.Construct(ENOSYS);
998 aConsts.mF_SETFD.Construct(F_SETFD);
999 aConsts.mF_SETFL.Construct(F_SETFL);
1001 aConsts.mFD_CLOEXEC.Construct(FD_CLOEXEC);
1003 aConsts.mAT_EACCESS.Construct(AT_EACCESS);
1005 aConsts.mO_CREAT.Construct(O_CREAT);
1006 aConsts.mO_NONBLOCK.Construct(O_NONBLOCK);
1007 aConsts.mO_WRONLY.Construct(O_WRONLY);
1009 aConsts.mPOLLERR.Construct(POLLERR);
1010 aConsts.mPOLLHUP.Construct(POLLHUP);
1011 aConsts.mPOLLIN.Construct(POLLIN);
1012 aConsts.mPOLLNVAL.Construct(POLLNVAL);
1013 aConsts.mPOLLOUT.Construct(POLLOUT);
1015 aConsts.mWNOHANG.Construct(WNOHANG);
1017 # ifdef XP_LINUX
1018 aConsts.mPR_CAPBSET_READ.Construct(PR_CAPBSET_READ);
1019 # endif
1021 #endif
1023 /* static */
1024 void ChromeUtils::OriginAttributesToSuffix(
1025 dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs,
1026 nsCString& aSuffix)
1029 OriginAttributes attrs(aAttrs);
1030 attrs.CreateSuffix(aSuffix);
1033 /* static */
1034 bool ChromeUtils::OriginAttributesMatchPattern(
1035 dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs,
1036 const dom::OriginAttributesPatternDictionary& aPattern) {
1037 OriginAttributes attrs(aAttrs);
1038 OriginAttributesPattern pattern(aPattern);
1039 return pattern.Matches(attrs);
1042 /* static */
1043 void ChromeUtils::CreateOriginAttributesFromOrigin(
1044 dom::GlobalObject& aGlobal, const nsAString& aOrigin,
1045 dom::OriginAttributesDictionary& aAttrs, ErrorResult& aRv) {
1046 OriginAttributes attrs;
1047 nsAutoCString suffix;
1048 if (!attrs.PopulateFromOrigin(NS_ConvertUTF16toUTF8(aOrigin), suffix)) {
1049 aRv.Throw(NS_ERROR_FAILURE);
1050 return;
1052 aAttrs = attrs;
1055 /* static */
1056 void ChromeUtils::CreateOriginAttributesFromOriginSuffix(
1057 dom::GlobalObject& aGlobal, const nsAString& aSuffix,
1058 dom::OriginAttributesDictionary& aAttrs, ErrorResult& aRv) {
1059 OriginAttributes attrs;
1060 nsAutoCString suffix;
1061 if (!attrs.PopulateFromSuffix(NS_ConvertUTF16toUTF8(aSuffix))) {
1062 aRv.Throw(NS_ERROR_FAILURE);
1063 return;
1065 aAttrs = attrs;
1068 /* static */
1069 void ChromeUtils::FillNonDefaultOriginAttributes(
1070 dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs,
1071 dom::OriginAttributesDictionary& aNewAttrs) {
1072 aNewAttrs = aAttrs;
1075 /* static */
1076 bool ChromeUtils::IsOriginAttributesEqual(
1077 dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aA,
1078 const dom::OriginAttributesDictionary& aB) {
1079 return IsOriginAttributesEqual(aA, aB);
1082 /* static */
1083 bool ChromeUtils::IsOriginAttributesEqual(
1084 const dom::OriginAttributesDictionary& aA,
1085 const dom::OriginAttributesDictionary& aB) {
1086 return aA == aB;
1089 /* static */
1090 void ChromeUtils::GetBaseDomainFromPartitionKey(dom::GlobalObject& aGlobal,
1091 const nsAString& aPartitionKey,
1092 nsAString& aBaseDomain,
1093 ErrorResult& aRv) {
1094 nsString scheme;
1095 nsString pkBaseDomain;
1096 int32_t port;
1098 if (!mozilla::OriginAttributes::ParsePartitionKey(aPartitionKey, scheme,
1099 pkBaseDomain, port)) {
1100 aRv.Throw(NS_ERROR_FAILURE);
1101 return;
1104 aBaseDomain = pkBaseDomain;
1107 /* static */
1108 void ChromeUtils::GetPartitionKeyFromURL(dom::GlobalObject& aGlobal,
1109 const nsAString& aURL,
1110 nsAString& aPartitionKey,
1111 ErrorResult& aRv) {
1112 nsCOMPtr<nsIURI> uri;
1113 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL);
1114 if (NS_SUCCEEDED(rv) && uri->SchemeIs("chrome")) {
1115 rv = NS_ERROR_FAILURE;
1118 if (NS_WARN_IF(NS_FAILED(rv))) {
1119 aPartitionKey.Truncate();
1120 aRv.Throw(rv);
1121 return;
1124 mozilla::OriginAttributes attrs;
1125 attrs.SetPartitionKey(uri);
1127 aPartitionKey = attrs.mPartitionKey;
1130 #ifdef NIGHTLY_BUILD
1131 /* static */
1132 void ChromeUtils::GetRecentJSDevError(GlobalObject& aGlobal,
1133 JS::MutableHandle<JS::Value> aRetval,
1134 ErrorResult& aRv) {
1135 aRetval.setUndefined();
1136 auto runtime = CycleCollectedJSRuntime::Get();
1137 MOZ_ASSERT(runtime);
1139 auto cx = aGlobal.Context();
1140 if (!runtime->GetRecentDevError(cx, aRetval)) {
1141 aRv.NoteJSContextException(cx);
1142 return;
1146 /* static */
1147 void ChromeUtils::ClearRecentJSDevError(GlobalObject&) {
1148 auto runtime = CycleCollectedJSRuntime::Get();
1149 MOZ_ASSERT(runtime);
1151 runtime->ClearRecentDevError();
1153 #endif // NIGHTLY_BUILD
1155 void ChromeUtils::ClearStyleSheetCacheByPrincipal(GlobalObject&,
1156 nsIPrincipal* aForPrincipal) {
1157 SharedStyleSheetCache::Clear(aForPrincipal);
1160 void ChromeUtils::ClearStyleSheetCacheByBaseDomain(
1161 GlobalObject&, const nsACString& aBaseDomain) {
1162 SharedStyleSheetCache::Clear(nullptr, &aBaseDomain);
1165 void ChromeUtils::ClearStyleSheetCache(GlobalObject&) {
1166 SharedStyleSheetCache::Clear();
1169 #define PROCTYPE_TO_WEBIDL_CASE(_procType, _webidl) \
1170 case mozilla::ProcType::_procType: \
1171 return WebIDLProcType::_webidl
1173 static WebIDLProcType ProcTypeToWebIDL(mozilla::ProcType aType) {
1174 // Max is the value of the last enum, not the length, so add one.
1175 static_assert(
1176 WebIDLProcTypeValues::Count == static_cast<size_t>(ProcType::Max) + 1,
1177 "In order for this static cast to be okay, "
1178 "WebIDLProcType must match ProcType exactly");
1180 // These must match the similar ones in E10SUtils.sys.mjs, RemoteTypes.h,
1181 // ProcInfo.h and ChromeUtils.webidl
1182 switch (aType) {
1183 PROCTYPE_TO_WEBIDL_CASE(Web, Web);
1184 PROCTYPE_TO_WEBIDL_CASE(WebIsolated, WebIsolated);
1185 PROCTYPE_TO_WEBIDL_CASE(File, File);
1186 PROCTYPE_TO_WEBIDL_CASE(Extension, Extension);
1187 PROCTYPE_TO_WEBIDL_CASE(PrivilegedAbout, Privilegedabout);
1188 PROCTYPE_TO_WEBIDL_CASE(PrivilegedMozilla, Privilegedmozilla);
1189 PROCTYPE_TO_WEBIDL_CASE(WebCOOPCOEP, WithCoopCoep);
1190 PROCTYPE_TO_WEBIDL_CASE(WebServiceWorker, WebServiceWorker);
1192 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
1193 process_bin_type, procinfo_typename, \
1194 webidl_typename, allcaps_name) \
1195 PROCTYPE_TO_WEBIDL_CASE(procinfo_typename, webidl_typename);
1196 #define SKIP_PROCESS_TYPE_CONTENT
1197 #ifndef MOZ_ENABLE_FORKSERVER
1198 # define SKIP_PROCESS_TYPE_FORKSERVER
1199 #endif // MOZ_ENABLE_FORKSERVER
1200 #include "mozilla/GeckoProcessTypes.h"
1201 #undef SKIP_PROCESS_TYPE_CONTENT
1202 #ifndef MOZ_ENABLE_FORKSERVER
1203 # undef SKIP_PROCESS_TYPE_FORKSERVER
1204 #endif // MOZ_ENABLE_FORKSERVER
1205 #undef GECKO_PROCESS_TYPE
1207 PROCTYPE_TO_WEBIDL_CASE(Preallocated, Preallocated);
1208 PROCTYPE_TO_WEBIDL_CASE(Unknown, Unknown);
1211 MOZ_ASSERT(false, "Unhandled case in ProcTypeToWebIDL");
1212 return WebIDLProcType::Unknown;
1215 #undef PROCTYPE_TO_WEBIDL_CASE
1217 /* static */
1218 already_AddRefed<Promise> ChromeUtils::RequestProcInfo(GlobalObject& aGlobal,
1219 ErrorResult& aRv) {
1220 // This function will use IPDL to enable threads info on macOS
1221 // see https://bugzilla.mozilla.org/show_bug.cgi?id=1529023
1222 if (!XRE_IsParentProcess()) {
1223 aRv.Throw(NS_ERROR_FAILURE);
1224 return nullptr;
1226 // Prepare the JS promise that will hold our response.
1227 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
1228 MOZ_ASSERT(global);
1229 RefPtr<Promise> domPromise = Promise::Create(global, aRv);
1230 if (NS_WARN_IF(aRv.Failed())) {
1231 return nullptr;
1233 MOZ_ASSERT(domPromise);
1235 // Get a list of processes to examine and pre-fill them with available info.
1236 // Note that this is subject to race conditions: just because we have a
1237 // process in the list doesn't mean that the process will still be alive when
1238 // we attempt to get its information. Followup code MUST be able to fail
1239 // gracefully on some processes and still return whichever information is
1240 // available.
1242 // Get all the content parents.
1243 // Note that this array includes even the long dead content parents, so we
1244 // might have some garbage, especially with Fission.
1245 // SAFETY NOTE: `contentParents` is only valid if used synchronously.
1246 // Anything else and you may end up dealing with dangling pointers.
1247 nsTArray<ContentParent*> contentParents;
1248 ContentParent::GetAll(contentParents);
1250 // Prepare our background request.
1251 // We reserve one more slot for the browser process itself.
1252 nsTArray<ProcInfoRequest> requests(contentParents.Length() + 1);
1253 // Requesting process info for the browser process itself.
1254 requests.EmplaceBack(
1255 /* aPid = */ base::GetCurrentProcId(),
1256 /* aProcessType = */ ProcType::Browser,
1257 /* aOrigin = */ ""_ns,
1258 /* aWindowInfo = */ nsTArray<WindowInfo>(),
1259 /* aUtilityInfo = */ nsTArray<UtilityInfo>());
1261 // First handle non-ContentParent processes.
1262 mozilla::ipc::GeckoChildProcessHost::GetAll(
1263 [&requests](mozilla::ipc::GeckoChildProcessHost* aGeckoProcess) {
1264 base::ProcessId childPid = aGeckoProcess->GetChildProcessId();
1265 if (childPid == 0) {
1266 // Something went wrong with this process, it may be dead already,
1267 // fail gracefully.
1268 return;
1270 mozilla::ProcType type = mozilla::ProcType::Unknown;
1272 switch (aGeckoProcess->GetProcessType()) {
1273 case GeckoProcessType::GeckoProcessType_Content: {
1274 // These processes are handled separately.
1275 return;
1278 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
1279 process_bin_type, procinfo_typename, \
1280 webidl_typename, allcaps_name) \
1281 case GeckoProcessType::GeckoProcessType_##enum_name: { \
1282 type = mozilla::ProcType::procinfo_typename; \
1283 break; \
1285 #define SKIP_PROCESS_TYPE_CONTENT
1286 #ifndef MOZ_ENABLE_FORKSERVER
1287 # define SKIP_PROCESS_TYPE_FORKSERVER
1288 #endif // MOZ_ENABLE_FORKSERVER
1289 #include "mozilla/GeckoProcessTypes.h"
1290 #ifndef MOZ_ENABLE_FORKSERVER
1291 # undef SKIP_PROCESS_TYPE_FORKSERVER
1292 #endif // MOZ_ENABLE_FORKSERVER
1293 #undef SKIP_PROCESS_TYPE_CONTENT
1294 #undef GECKO_PROCESS_TYPE
1295 default:
1296 // Leave the default Unknown value in |type|.
1297 break;
1300 // Attach utility actor information to the process.
1301 nsTArray<UtilityInfo> utilityActors;
1302 if (aGeckoProcess->GetProcessType() ==
1303 GeckoProcessType::GeckoProcessType_Utility) {
1304 RefPtr<mozilla::ipc::UtilityProcessManager> upm =
1305 mozilla::ipc::UtilityProcessManager::GetSingleton();
1306 if (!utilityActors.AppendElements(upm->GetActors(aGeckoProcess),
1307 fallible)) {
1308 NS_WARNING("Error adding actors");
1309 return;
1313 requests.EmplaceBack(
1314 /* aPid = */ childPid,
1315 /* aProcessType = */ type,
1316 /* aOrigin = */ ""_ns,
1317 /* aWindowInfo = */ nsTArray<WindowInfo>(), // Without a
1318 // ContentProcess, no
1319 // DOM windows.
1320 /* aUtilityInfo = */ std::move(utilityActors),
1321 /* aChild = */ 0 // Without a ContentProcess, no ChildId.
1322 #ifdef XP_MACOSX
1324 /* aChildTask = */ aGeckoProcess->GetChildTask()
1325 #endif // XP_MACOSX
1329 // Now handle ContentParents.
1330 for (const auto* contentParent : contentParents) {
1331 if (!contentParent || !contentParent->Process()) {
1332 // Presumably, the process is dead or dying.
1333 continue;
1335 base::ProcessId pid = contentParent->Process()->GetChildProcessId();
1336 if (pid == 0) {
1337 // Presumably, the process is dead or dying.
1338 continue;
1340 if (contentParent->Process()->GetProcessType() !=
1341 GeckoProcessType::GeckoProcessType_Content) {
1342 // We're probably racing against a process changing type.
1343 // We'll get it in the next call, skip it for the moment.
1344 continue;
1347 // Since this code is executed synchronously on the main thread,
1348 // processes cannot die while we're in this loop.
1349 mozilla::ProcType type = mozilla::ProcType::Unknown;
1351 // Convert the remoteType into a ProcType.
1352 // Ideally, the remoteType should be strongly typed
1353 // upstream, this would make the conversion less brittle.
1354 const nsAutoCString remoteType(contentParent->GetRemoteType());
1355 if (StringBeginsWith(remoteType, FISSION_WEB_REMOTE_TYPE)) {
1356 // WARNING: Do not change the order, as
1357 // `DEFAULT_REMOTE_TYPE` is a prefix of
1358 // `FISSION_WEB_REMOTE_TYPE`.
1359 type = mozilla::ProcType::WebIsolated;
1360 } else if (StringBeginsWith(remoteType, SERVICEWORKER_REMOTE_TYPE)) {
1361 type = mozilla::ProcType::WebServiceWorker;
1362 } else if (StringBeginsWith(remoteType,
1363 WITH_COOP_COEP_REMOTE_TYPE_PREFIX)) {
1364 type = mozilla::ProcType::WebCOOPCOEP;
1365 } else if (remoteType == FILE_REMOTE_TYPE) {
1366 type = mozilla::ProcType::File;
1367 } else if (remoteType == EXTENSION_REMOTE_TYPE) {
1368 type = mozilla::ProcType::Extension;
1369 } else if (remoteType == PRIVILEGEDABOUT_REMOTE_TYPE) {
1370 type = mozilla::ProcType::PrivilegedAbout;
1371 } else if (remoteType == PRIVILEGEDMOZILLA_REMOTE_TYPE) {
1372 type = mozilla::ProcType::PrivilegedMozilla;
1373 } else if (remoteType == PREALLOC_REMOTE_TYPE) {
1374 type = mozilla::ProcType::Preallocated;
1375 } else if (StringBeginsWith(remoteType, DEFAULT_REMOTE_TYPE)) {
1376 type = mozilla::ProcType::Web;
1377 } else {
1378 MOZ_CRASH_UNSAFE_PRINTF("Unknown remoteType '%s'", remoteType.get());
1381 // By convention, everything after '=' is the origin.
1382 nsAutoCString origin;
1383 nsACString::const_iterator cursor;
1384 nsACString::const_iterator end;
1385 remoteType.BeginReading(cursor);
1386 remoteType.EndReading(end);
1387 if (FindCharInReadable('=', cursor, end)) {
1388 origin = Substring(++cursor, end);
1391 // Attach DOM window information to the process.
1392 nsTArray<WindowInfo> windows;
1393 for (const auto& browserParentWrapperKey :
1394 contentParent->ManagedPBrowserParent()) {
1395 for (const auto& windowGlobalParentWrapperKey :
1396 browserParentWrapperKey->ManagedPWindowGlobalParent()) {
1397 // WindowGlobalParent is the only immediate subclass of
1398 // PWindowGlobalParent.
1399 auto* windowGlobalParent =
1400 static_cast<WindowGlobalParent*>(windowGlobalParentWrapperKey);
1402 nsString documentTitle;
1403 windowGlobalParent->GetDocumentTitle(documentTitle);
1404 WindowInfo* window = windows.EmplaceBack(
1405 fallible,
1406 /* aOuterWindowId = */ windowGlobalParent->OuterWindowId(),
1407 /* aDocumentURI = */ windowGlobalParent->GetDocumentURI(),
1408 /* aDocumentTitle = */ std::move(documentTitle),
1409 /* aIsProcessRoot = */ windowGlobalParent->IsProcessRoot(),
1410 /* aIsInProcess = */ windowGlobalParent->IsInProcess());
1411 if (!window) {
1412 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
1413 return nullptr;
1417 requests.EmplaceBack(
1418 /* aPid = */ pid,
1419 /* aProcessType = */ type,
1420 /* aOrigin = */ origin,
1421 /* aWindowInfo = */ std::move(windows),
1422 /* aUtilityInfo = */ nsTArray<UtilityInfo>(),
1423 /* aChild = */ contentParent->ChildID()
1424 #ifdef XP_MACOSX
1426 /* aChildTask = */ contentParent->Process()->GetChildTask()
1427 #endif // XP_MACOSX
1431 // Now place background request.
1432 RefPtr<nsISerialEventTarget> target =
1433 global->EventTargetFor(TaskCategory::Performance);
1434 mozilla::GetProcInfo(std::move(requests))
1435 ->Then(
1436 target, __func__,
1437 [target,
1438 domPromise](const HashMap<base::ProcessId, ProcInfo>& aSysProcInfo) {
1439 ParentProcInfoDictionary parentInfo;
1440 if (aSysProcInfo.count() == 0) {
1441 // For some reason, we couldn't get *any* info.
1442 // Maybe a sandboxing issue?
1443 domPromise->MaybeReject(NS_ERROR_UNEXPECTED);
1444 return;
1446 nsTArray<ChildProcInfoDictionary> childrenInfo(
1447 aSysProcInfo.count() - 1);
1448 for (auto iter = aSysProcInfo.iter(); !iter.done(); iter.next()) {
1449 const auto& sysProcInfo = iter.get().value();
1450 nsresult rv;
1451 if (sysProcInfo.type == ProcType::Browser) {
1452 rv = mozilla::CopySysProcInfoToDOM(sysProcInfo, &parentInfo);
1453 if (NS_FAILED(rv)) {
1454 // Failing to copy? That's probably not something from we can
1455 // (or should) try to recover gracefully.
1456 domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
1457 return;
1459 MOZ_ASSERT(sysProcInfo.childId == 0);
1460 MOZ_ASSERT(sysProcInfo.origin.IsEmpty());
1461 } else {
1462 mozilla::dom::ChildProcInfoDictionary* childInfo =
1463 childrenInfo.AppendElement(fallible);
1464 if (!childInfo) {
1465 domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
1466 return;
1468 rv = mozilla::CopySysProcInfoToDOM(sysProcInfo, childInfo);
1469 if (NS_FAILED(rv)) {
1470 domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
1471 return;
1473 // Copy Firefox info.
1474 childInfo->mChildID = sysProcInfo.childId;
1475 childInfo->mOrigin = sysProcInfo.origin;
1476 childInfo->mType = ProcTypeToWebIDL(sysProcInfo.type);
1478 for (const auto& source : sysProcInfo.windows) {
1479 auto* dest = childInfo->mWindows.AppendElement(fallible);
1480 if (!dest) {
1481 domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
1482 return;
1484 dest->mOuterWindowId = source.outerWindowId;
1485 dest->mDocumentURI = source.documentURI;
1486 dest->mDocumentTitle = source.documentTitle;
1487 dest->mIsProcessRoot = source.isProcessRoot;
1488 dest->mIsInProcess = source.isInProcess;
1491 if (sysProcInfo.type == ProcType::Utility) {
1492 for (const auto& source : sysProcInfo.utilityActors) {
1493 auto* dest =
1494 childInfo->mUtilityActors.AppendElement(fallible);
1495 if (!dest) {
1496 domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
1497 return;
1500 dest->mActorName = source.actorName;
1506 // Attach the children to the parent.
1507 mozilla::dom::Sequence<mozilla::dom::ChildProcInfoDictionary>
1508 children(std::move(childrenInfo));
1509 parentInfo.mChildren = std::move(children);
1510 domPromise->MaybeResolve(parentInfo);
1512 [domPromise](nsresult aRv) { domPromise->MaybeReject(aRv); });
1513 MOZ_ASSERT(domPromise);
1515 // sending back the promise instance
1516 return domPromise.forget();
1519 /* static */
1520 bool ChromeUtils::VsyncEnabled(GlobalObject& aGlobal) {
1521 return mozilla::gfx::VsyncSource::GetFastestVsyncRate().isSome();
1524 void ChromeUtils::SetPerfStatsCollectionMask(GlobalObject& aGlobal,
1525 uint64_t aMask) {
1526 PerfStats::SetCollectionMask(static_cast<PerfStats::MetricMask>(aMask));
1529 already_AddRefed<Promise> ChromeUtils::CollectPerfStats(GlobalObject& aGlobal,
1530 ErrorResult& aRv) {
1531 // Creating a JS promise
1532 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
1533 MOZ_ASSERT(global);
1535 RefPtr<Promise> promise = Promise::Create(global, aRv);
1536 if (aRv.Failed()) {
1537 return nullptr;
1540 RefPtr<PerfStats::PerfStatsPromise> extPromise =
1541 PerfStats::CollectPerfStatsJSON();
1543 extPromise->Then(
1544 GetCurrentSerialEventTarget(), __func__,
1545 [promise](const nsCString& aResult) {
1546 promise->MaybeResolve(NS_ConvertUTF8toUTF16(aResult));
1548 [promise](bool aValue) { promise->MaybeReject(NS_ERROR_FAILURE); });
1550 return promise.forget();
1553 constexpr auto kSkipSelfHosted = JS::SavedFrameSelfHosted::Exclude;
1555 /* static */
1556 void ChromeUtils::GetCallerLocation(const GlobalObject& aGlobal,
1557 nsIPrincipal* aPrincipal,
1558 JS::MutableHandle<JSObject*> aRetval) {
1559 JSContext* cx = aGlobal.Context();
1561 auto* principals = nsJSPrincipals::get(aPrincipal);
1563 JS::StackCapture captureMode(JS::FirstSubsumedFrame(cx, principals));
1565 JS::Rooted<JSObject*> frame(cx);
1566 if (!JS::CaptureCurrentStack(cx, &frame, std::move(captureMode))) {
1567 JS_ClearPendingException(cx);
1568 aRetval.set(nullptr);
1569 return;
1572 // FirstSubsumedFrame gets us a stack which stops at the first principal which
1573 // is subsumed by the given principal. That means that we may have a lot of
1574 // privileged frames that we don't care about at the top of the stack, though.
1575 // We need to filter those out to get the frame we actually want.
1576 aRetval.set(
1577 js::GetFirstSubsumedSavedFrame(cx, principals, frame, kSkipSelfHosted));
1580 /* static */
1581 void ChromeUtils::CreateError(const GlobalObject& aGlobal,
1582 const nsAString& aMessage,
1583 JS::Handle<JSObject*> aStack,
1584 JS::MutableHandle<JSObject*> aRetVal,
1585 ErrorResult& aRv) {
1586 if (aStack && !JS::IsMaybeWrappedSavedFrame(aStack)) {
1587 aRv.Throw(NS_ERROR_INVALID_ARG);
1588 return;
1591 JSContext* cx = aGlobal.Context();
1593 auto cleanup = MakeScopeExit([&]() { aRv.NoteJSContextException(cx); });
1595 JS::Rooted<JSObject*> retVal(cx);
1597 JS::Rooted<JSString*> fileName(cx, JS_GetEmptyString(cx));
1598 uint32_t line = 0;
1599 uint32_t column = 0;
1601 Maybe<JSAutoRealm> ar;
1602 JS::Rooted<JSObject*> stack(cx);
1603 if (aStack) {
1604 stack = UncheckedUnwrap(aStack);
1605 ar.emplace(cx, stack);
1607 JSPrincipals* principals =
1608 JS::GetRealmPrincipals(js::GetContextRealm(cx));
1609 if (JS::GetSavedFrameLine(cx, principals, stack, &line) !=
1610 JS::SavedFrameResult::Ok ||
1611 JS::GetSavedFrameColumn(cx, principals, stack, &column) !=
1612 JS::SavedFrameResult::Ok ||
1613 JS::GetSavedFrameSource(cx, principals, stack, &fileName) !=
1614 JS::SavedFrameResult::Ok) {
1615 return;
1619 JS::Rooted<JSString*> message(cx);
1621 JS::Rooted<JS::Value> msgVal(cx);
1622 if (!xpc::NonVoidStringToJsval(cx, aMessage, &msgVal)) {
1623 return;
1625 message = msgVal.toString();
1628 JS::Rooted<JS::Value> err(cx);
1629 if (!JS::CreateError(cx, JSEXN_ERR, stack, fileName, line, column, nullptr,
1630 message, JS::NothingHandleValue, &err)) {
1631 return;
1634 MOZ_ASSERT(err.isObject());
1635 retVal = &err.toObject();
1638 if (aStack && !JS_WrapObject(cx, &retVal)) {
1639 return;
1642 cleanup.release();
1643 aRetVal.set(retVal);
1646 /* static */
1647 already_AddRefed<Promise> ChromeUtils::RequestIOActivity(GlobalObject& aGlobal,
1648 ErrorResult& aRv) {
1649 MOZ_ASSERT(XRE_IsParentProcess());
1650 MOZ_ASSERT(Preferences::GetBool(IO_ACTIVITY_ENABLED_PREF, false));
1651 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
1652 MOZ_ASSERT(global);
1653 RefPtr<Promise> domPromise = Promise::Create(global, aRv);
1654 if (NS_WARN_IF(aRv.Failed())) {
1655 return nullptr;
1657 MOZ_ASSERT(domPromise);
1658 mozilla::net::IOActivityMonitor::RequestActivities(domPromise);
1659 return domPromise.forget();
1662 /* static */
1663 bool ChromeUtils::HasReportingHeaderForOrigin(GlobalObject& global,
1664 const nsAString& aOrigin,
1665 ErrorResult& aRv) {
1666 if (!XRE_IsParentProcess()) {
1667 aRv.Throw(NS_ERROR_FAILURE);
1668 return false;
1671 return ReportingHeader::HasReportingHeaderForOrigin(
1672 NS_ConvertUTF16toUTF8(aOrigin));
1675 /* static */
1676 PopupBlockerState ChromeUtils::GetPopupControlState(GlobalObject& aGlobal) {
1677 switch (PopupBlocker::GetPopupControlState()) {
1678 case PopupBlocker::PopupControlState::openAllowed:
1679 return PopupBlockerState::OpenAllowed;
1681 case PopupBlocker::PopupControlState::openControlled:
1682 return PopupBlockerState::OpenControlled;
1684 case PopupBlocker::PopupControlState::openBlocked:
1685 return PopupBlockerState::OpenBlocked;
1687 case PopupBlocker::PopupControlState::openAbused:
1688 return PopupBlockerState::OpenAbused;
1690 case PopupBlocker::PopupControlState::openOverridden:
1691 return PopupBlockerState::OpenOverridden;
1693 default:
1694 MOZ_CRASH(
1695 "PopupBlocker::PopupControlState and PopupBlockerState are out of "
1696 "sync");
1700 /* static */
1701 double ChromeUtils::LastExternalProtocolIframeAllowed(GlobalObject& aGlobal) {
1702 TimeStamp when = PopupBlocker::WhenLastExternalProtocolIframeAllowed();
1703 if (when.IsNull()) {
1704 return 0;
1707 TimeDuration duration = TimeStamp::Now() - when;
1708 return duration.ToMilliseconds();
1711 /* static */
1712 void ChromeUtils::ResetLastExternalProtocolIframeAllowed(
1713 GlobalObject& aGlobal) {
1714 PopupBlocker::ResetLastExternalProtocolIframeAllowed();
1717 /* static */
1718 void ChromeUtils::EndWheelTransaction(GlobalObject& aGlobal) {
1719 // This allows us to end the current wheel transaction from the browser
1720 // chrome. We do not need to perform any checks before calling
1721 // EndTransaction(), as it should do nothing in the case that there is
1722 // no current wheel transaction.
1723 WheelTransaction::EndTransaction();
1726 /* static */
1727 void ChromeUtils::RegisterWindowActor(const GlobalObject& aGlobal,
1728 const nsACString& aName,
1729 const WindowActorOptions& aOptions,
1730 ErrorResult& aRv) {
1731 MOZ_ASSERT(XRE_IsParentProcess());
1733 RefPtr<JSActorService> service = JSActorService::GetSingleton();
1734 service->RegisterWindowActor(aName, aOptions, aRv);
1737 /* static */
1738 void ChromeUtils::UnregisterWindowActor(const GlobalObject& aGlobal,
1739 const nsACString& aName) {
1740 MOZ_ASSERT(XRE_IsParentProcess());
1742 RefPtr<JSActorService> service = JSActorService::GetSingleton();
1743 service->UnregisterWindowActor(aName);
1746 /* static */
1747 void ChromeUtils::RegisterProcessActor(const GlobalObject& aGlobal,
1748 const nsACString& aName,
1749 const ProcessActorOptions& aOptions,
1750 ErrorResult& aRv) {
1751 MOZ_ASSERT(XRE_IsParentProcess());
1753 RefPtr<JSActorService> service = JSActorService::GetSingleton();
1754 service->RegisterProcessActor(aName, aOptions, aRv);
1757 /* static */
1758 void ChromeUtils::UnregisterProcessActor(const GlobalObject& aGlobal,
1759 const nsACString& aName) {
1760 MOZ_ASSERT(XRE_IsParentProcess());
1762 RefPtr<JSActorService> service = JSActorService::GetSingleton();
1763 service->UnregisterProcessActor(aName);
1766 /* static */
1767 bool ChromeUtils::IsClassifierBlockingErrorCode(GlobalObject& aGlobal,
1768 uint32_t aError) {
1769 return net::UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode(
1770 static_cast<nsresult>(aError));
1773 /* static */
1774 void ChromeUtils::PrivateNoteIntentionalCrash(const GlobalObject& aGlobal,
1775 ErrorResult& aError) {
1776 if (XRE_IsContentProcess()) {
1777 NoteIntentionalCrash("tab");
1778 return;
1780 aError.Throw(NS_ERROR_NOT_IMPLEMENTED);
1783 /* static */
1784 nsIDOMProcessChild* ChromeUtils::GetDomProcessChild(const GlobalObject&) {
1785 return nsIDOMProcessChild::GetSingleton();
1788 /* static */
1789 void ChromeUtils::GetAllDOMProcesses(
1790 GlobalObject& aGlobal, nsTArray<RefPtr<nsIDOMProcessParent>>& aParents,
1791 ErrorResult& aRv) {
1792 if (!XRE_IsParentProcess()) {
1793 aRv.ThrowNotAllowedError(
1794 "getAllDOMProcesses() may only be called in the parent process");
1795 return;
1797 aParents.Clear();
1798 // Always add the parent process nsIDOMProcessParent first
1799 aParents.AppendElement(InProcessParent::Singleton());
1801 // Before adding nsIDOMProcessParent for all the content processes
1802 for (auto* cp : ContentParent::AllProcesses(ContentParent::eLive)) {
1803 aParents.AppendElement(cp);
1807 /* static */
1808 void ChromeUtils::ConsumeInteractionData(
1809 GlobalObject& aGlobal, Record<nsString, InteractionData>& aInteractions,
1810 ErrorResult& aRv) {
1811 if (!XRE_IsParentProcess()) {
1812 aRv.ThrowNotAllowedError(
1813 "consumeInteractionData() may only be called in the parent "
1814 "process");
1815 return;
1817 EventStateManager::ConsumeInteractionData(aInteractions);
1820 already_AddRefed<Promise> ChromeUtils::CollectScrollingData(
1821 GlobalObject& aGlobal, ErrorResult& aRv) {
1822 // Creating a JS promise
1823 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
1824 MOZ_ASSERT(global);
1826 RefPtr<Promise> promise = Promise::Create(global, aRv);
1827 if (aRv.Failed()) {
1828 return nullptr;
1831 RefPtr<ScrollingMetrics::ScrollingMetricsPromise> extPromise =
1832 ScrollingMetrics::CollectScrollingMetrics();
1834 extPromise->Then(
1835 GetCurrentSerialEventTarget(), __func__,
1836 [promise](const std::tuple<uint32_t, uint32_t>& aResult) {
1837 InteractionData out = {};
1838 out.mInteractionTimeInMilliseconds = std::get<0>(aResult);
1839 out.mScrollingDistanceInPixels = std::get<1>(aResult);
1840 promise->MaybeResolve(out);
1842 [promise](bool aValue) { promise->MaybeReject(NS_ERROR_FAILURE); });
1844 return promise.forget();
1847 /* static */
1848 void ChromeUtils::GetFormAutofillConfidences(
1849 GlobalObject& aGlobal, const Sequence<OwningNonNull<Element>>& aElements,
1850 nsTArray<FormAutofillConfidences>& aResults, ErrorResult& aRv) {
1851 FormAutofillNative::GetFormAutofillConfidences(aGlobal, aElements, aResults,
1852 aRv);
1855 bool ChromeUtils::IsDarkBackground(GlobalObject&, Element& aElement) {
1856 nsIFrame* f = aElement.GetPrimaryFrame(FlushType::Frames);
1857 if (!f) {
1858 return false;
1860 return nsNativeTheme::IsDarkBackground(f);
1863 double ChromeUtils::DateNow(GlobalObject&) { return JS_Now() / 1000.0; }
1865 /* static */
1866 void ChromeUtils::EnsureJSOracleStarted(GlobalObject&) {
1867 if (StaticPrefs::browser_opaqueResponseBlocking_javascriptValidator()) {
1868 JSOracleParent::WithJSOracle([](JSOracleParent* aParent) {});
1872 /* static */
1873 unsigned ChromeUtils::AliveUtilityProcesses(const GlobalObject&) {
1874 const auto& utilityProcessManager =
1875 mozilla::ipc::UtilityProcessManager::GetIfExists();
1876 return utilityProcessManager ? utilityProcessManager->AliveProcesses() : 0;
1879 /* static */
1880 void ChromeUtils::GetAllPossibleUtilityActorNames(GlobalObject& aGlobal,
1881 nsTArray<nsCString>& aNames) {
1882 aNames.Clear();
1883 for (size_t i = 0; i < WebIDLUtilityActorNameValues::Count; ++i) {
1884 auto idlName = static_cast<UtilityActorName>(i);
1885 aNames.AppendElement(WebIDLUtilityActorNameValues::GetString(idlName));
1889 /* static */
1890 bool ChromeUtils::ShouldResistFingerprinting(GlobalObject& aGlobal,
1891 JSRFPTarget aTarget) {
1892 RFPTarget target;
1893 switch (aTarget) {
1894 case JSRFPTarget::RoundWindowSize:
1895 target = RFPTarget::RoundWindowSize;
1896 break;
1897 case JSRFPTarget::SiteSpecificZoom:
1898 target = RFPTarget::SiteSpecificZoom;
1899 break;
1900 default:
1901 MOZ_CRASH("Unhandled JSRFPTarget enum value");
1904 return nsRFPService::IsRFPEnabledFor(target);
1907 std::atomic<uint32_t> ChromeUtils::sDevToolsOpenedCount = 0;
1909 /* static */
1910 bool ChromeUtils::IsDevToolsOpened() {
1911 return ChromeUtils::sDevToolsOpenedCount > 0;
1914 /* static */
1915 bool ChromeUtils::IsDevToolsOpened(GlobalObject& aGlobal) {
1916 return ChromeUtils::IsDevToolsOpened();
1919 /* static */
1920 void ChromeUtils::NotifyDevToolsOpened(GlobalObject& aGlobal) {
1921 ChromeUtils::sDevToolsOpenedCount++;
1924 /* static */
1925 void ChromeUtils::NotifyDevToolsClosed(GlobalObject& aGlobal) {
1926 MOZ_ASSERT(ChromeUtils::sDevToolsOpenedCount >= 1);
1927 ChromeUtils::sDevToolsOpenedCount--;
1930 } // namespace mozilla::dom