Bug 1852740: add tests for the `fetchpriority` attribute in Link headers. r=necko...
[gecko.git] / dom / base / ChromeUtils.cpp
blobd76fb3e83c158fa0aca51d01be8fbbfe60694075
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 auto paddingPolicy = aOptions.mPad ? Base64URLEncodePaddingPolicy::Include
121 : Base64URLEncodePaddingPolicy::Omit;
122 ProcessTypedArrays(
123 aSource, [&](const Span<uint8_t>& aData, JS::AutoCheckCannotGC&&) {
124 nsresult rv = mozilla::Base64URLEncode(aData.Length(), aData.Elements(),
125 paddingPolicy, aResult);
126 if (NS_WARN_IF(NS_FAILED(rv))) {
127 aResult.Truncate();
128 aRv.Throw(rv);
133 /* static */
134 void ChromeUtils::Base64URLDecode(GlobalObject& aGlobal,
135 const nsACString& aString,
136 const Base64URLDecodeOptions& aOptions,
137 JS::MutableHandle<JSObject*> aRetval,
138 ErrorResult& aRv) {
139 Base64URLDecodePaddingPolicy paddingPolicy;
140 switch (aOptions.mPadding) {
141 case Base64URLDecodePadding::Require:
142 paddingPolicy = Base64URLDecodePaddingPolicy::Require;
143 break;
145 case Base64URLDecodePadding::Ignore:
146 paddingPolicy = Base64URLDecodePaddingPolicy::Ignore;
147 break;
149 case Base64URLDecodePadding::Reject:
150 paddingPolicy = Base64URLDecodePaddingPolicy::Reject;
151 break;
153 default:
154 aRv.Throw(NS_ERROR_INVALID_ARG);
155 return;
157 FallibleTArray<uint8_t> data;
158 nsresult rv = mozilla::Base64URLDecode(aString, paddingPolicy, data);
159 if (NS_WARN_IF(NS_FAILED(rv))) {
160 aRv.Throw(rv);
161 return;
164 JS::Rooted<JSObject*> buffer(
165 aGlobal.Context(),
166 ArrayBuffer::Create(aGlobal.Context(), data.Length(), data.Elements()));
167 if (NS_WARN_IF(!buffer)) {
168 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
169 return;
171 aRetval.set(buffer);
174 /* static */
175 void ChromeUtils::ReleaseAssert(GlobalObject& aGlobal, bool aCondition,
176 const nsAString& aMessage) {
177 // If the condition didn't fail, which is the likely case, immediately return.
178 if (MOZ_LIKELY(aCondition)) {
179 return;
182 // Extract the current stack from the JS runtime to embed in the crash reason.
183 nsAutoString filename;
184 uint32_t lineNo = 0;
186 if (nsCOMPtr<nsIStackFrame> location = GetCurrentJSStack(1)) {
187 location->GetFilename(aGlobal.Context(), filename);
188 lineNo = location->GetLineNumber(aGlobal.Context());
189 } else {
190 filename.Assign(u"<unknown>"_ns);
193 // Convert to utf-8 for adding as the MozCrashReason.
194 NS_ConvertUTF16toUTF8 filenameUtf8(filename);
195 NS_ConvertUTF16toUTF8 messageUtf8(aMessage);
197 // Actually crash.
198 MOZ_CRASH_UNSAFE_PRINTF("Failed ChromeUtils.releaseAssert(\"%s\") @ %s:%u",
199 messageUtf8.get(), filenameUtf8.get(), lineNo);
202 /* static */
203 void ChromeUtils::AddProfilerMarker(
204 GlobalObject& aGlobal, const nsACString& aName,
205 const ProfilerMarkerOptionsOrDouble& aOptions,
206 const Optional<nsACString>& aText) {
207 if (!profiler_thread_is_being_profiled_for_markers()) {
208 return;
211 MarkerOptions options;
213 MarkerCategory category = ::geckoprofiler::category::JS;
215 DOMHighResTimeStamp startTime = 0;
216 uint64_t innerWindowId = 0;
217 if (aOptions.IsDouble()) {
218 startTime = aOptions.GetAsDouble();
219 } else {
220 const ProfilerMarkerOptions& opt = aOptions.GetAsProfilerMarkerOptions();
221 startTime = opt.mStartTime;
222 innerWindowId = opt.mInnerWindowId;
224 if (opt.mCaptureStack) {
225 // If we will be capturing a stack, change the category of the
226 // ChromeUtils.addProfilerMarker label automatically added by the webidl
227 // binding from DOM to PROFILER so that this function doesn't appear in
228 // the marker stack.
229 JSContext* cx = aGlobal.Context();
230 ProfilingStack* stack = js::GetContextProfilingStackIfEnabled(cx);
231 if (MOZ_LIKELY(stack)) {
232 uint32_t sp = stack->stackPointer;
233 if (MOZ_LIKELY(sp > 0)) {
234 js::ProfilingStackFrame& frame = stack->frames[sp - 1];
235 if (frame.isLabelFrame() && "ChromeUtils"_ns.Equals(frame.label()) &&
236 "addProfilerMarker"_ns.Equals(frame.dynamicString())) {
237 frame.setLabelCategory(JS::ProfilingCategoryPair::PROFILER);
242 options.Set(MarkerStack::Capture());
244 #define BEGIN_CATEGORY(name, labelAsString, color) \
245 if (opt.mCategory.Equals(labelAsString)) { \
246 category = ::geckoprofiler::category::name; \
247 } else
248 #define SUBCATEGORY(supercategory, name, labelAsString)
249 #define END_CATEGORY
250 MOZ_PROFILING_CATEGORY_LIST(BEGIN_CATEGORY, SUBCATEGORY, END_CATEGORY)
251 #undef BEGIN_CATEGORY
252 #undef SUBCATEGORY
253 #undef END_CATEGORY
255 category = ::geckoprofiler::category::OTHER;
258 if (startTime) {
259 RefPtr<Performance> performance;
261 if (NS_IsMainThread()) {
262 nsCOMPtr<nsPIDOMWindowInner> ownerWindow =
263 do_QueryInterface(aGlobal.GetAsSupports());
264 if (ownerWindow) {
265 performance = ownerWindow->GetPerformance();
267 } else {
268 JSContext* cx = aGlobal.Context();
269 WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
270 if (workerPrivate) {
271 performance = workerPrivate->GlobalScope()->GetPerformance();
275 if (performance) {
276 options.Set(MarkerTiming::IntervalUntilNowFrom(
277 performance->CreationTimeStamp() +
278 TimeDuration::FromMilliseconds(startTime)));
279 } else {
280 options.Set(MarkerTiming::IntervalUntilNowFrom(
281 TimeStamp::ProcessCreation() +
282 TimeDuration::FromMilliseconds(startTime)));
286 if (innerWindowId) {
287 options.Set(MarkerInnerWindowId(innerWindowId));
288 } else {
289 options.Set(MarkerInnerWindowIdFromJSContext(aGlobal.Context()));
293 AUTO_PROFILER_STATS(ChromeUtils_AddProfilerMarker);
294 if (aText.WasPassed()) {
295 profiler_add_marker(aName, category, std::move(options),
296 ::geckoprofiler::markers::TextMarker{},
297 aText.Value());
298 } else {
299 profiler_add_marker(aName, category, std::move(options));
304 /* static */
305 void ChromeUtils::GetXPCOMErrorName(GlobalObject& aGlobal, uint32_t aErrorCode,
306 nsACString& aRetval) {
307 GetErrorName((nsresult)aErrorCode, aRetval);
310 /* static */
311 void ChromeUtils::WaiveXrays(GlobalObject& aGlobal, JS::Handle<JS::Value> aVal,
312 JS::MutableHandle<JS::Value> aRetval,
313 ErrorResult& aRv) {
314 JS::Rooted<JS::Value> value(aGlobal.Context(), aVal);
315 if (!xpc::WrapperFactory::WaiveXrayAndWrap(aGlobal.Context(), &value)) {
316 aRv.NoteJSContextException(aGlobal.Context());
317 } else {
318 aRetval.set(value);
322 /* static */
323 void ChromeUtils::UnwaiveXrays(GlobalObject& aGlobal,
324 JS::Handle<JS::Value> aVal,
325 JS::MutableHandle<JS::Value> aRetval,
326 ErrorResult& aRv) {
327 if (!aVal.isObject()) {
328 aRetval.set(aVal);
329 return;
332 JS::Rooted<JSObject*> obj(aGlobal.Context(),
333 js::UncheckedUnwrap(&aVal.toObject()));
334 if (!JS_WrapObject(aGlobal.Context(), &obj)) {
335 aRv.NoteJSContextException(aGlobal.Context());
336 } else {
337 aRetval.setObject(*obj);
341 /* static */
342 void ChromeUtils::GetClassName(GlobalObject& aGlobal,
343 JS::Handle<JSObject*> aObj, bool aUnwrap,
344 nsAString& aRetval) {
345 JS::Rooted<JSObject*> obj(aGlobal.Context(), aObj);
346 if (aUnwrap) {
347 obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
350 aRetval = NS_ConvertUTF8toUTF16(nsDependentCString(JS::GetClass(obj)->name));
353 /* static */
354 bool ChromeUtils::IsDOMObject(GlobalObject& aGlobal, JS::Handle<JSObject*> aObj,
355 bool aUnwrap) {
356 JS::Rooted<JSObject*> obj(aGlobal.Context(), aObj);
357 if (aUnwrap) {
358 obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
361 return mozilla::dom::IsDOMObject(obj);
364 /* static */
365 void ChromeUtils::ShallowClone(GlobalObject& aGlobal,
366 JS::Handle<JSObject*> aObj,
367 JS::Handle<JSObject*> aTarget,
368 JS::MutableHandle<JSObject*> aRetval,
369 ErrorResult& aRv) {
370 JSContext* cx = aGlobal.Context();
372 auto cleanup = MakeScopeExit([&]() { aRv.NoteJSContextException(cx); });
374 JS::Rooted<JS::IdVector> ids(cx, JS::IdVector(cx));
375 JS::RootedVector<JS::Value> values(cx);
376 JS::RootedVector<jsid> valuesIds(cx);
379 // cx represents our current Realm, so it makes sense to use it for the
380 // CheckedUnwrapDynamic call. We do want CheckedUnwrapDynamic, in case
381 // someone is shallow-cloning a Window.
382 JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrapDynamic(aObj, cx));
383 if (!obj) {
384 js::ReportAccessDenied(cx);
385 return;
388 if (js::IsScriptedProxy(obj)) {
389 JS_ReportErrorASCII(cx, "Shallow cloning a proxy object is not allowed");
390 return;
393 JSAutoRealm ar(cx, obj);
395 if (!JS_Enumerate(cx, obj, &ids) || !values.reserve(ids.length()) ||
396 !valuesIds.reserve(ids.length())) {
397 return;
400 JS::Rooted<Maybe<JS::PropertyDescriptor>> desc(cx);
401 JS::Rooted<JS::PropertyKey> id(cx);
402 for (jsid idVal : ids) {
403 id = idVal;
404 if (!JS_GetOwnPropertyDescriptorById(cx, obj, id, &desc)) {
405 continue;
407 if (desc.isNothing() || desc->isAccessorDescriptor()) {
408 continue;
410 valuesIds.infallibleAppend(id);
411 values.infallibleAppend(desc->value());
415 JS::Rooted<JSObject*> obj(cx);
417 Maybe<JSAutoRealm> ar;
418 if (aTarget) {
419 // Our target could be anything, so we want CheckedUnwrapDynamic here.
420 // "cx" represents the current Realm when we were called from bindings, so
421 // we can just use that.
422 JS::Rooted<JSObject*> target(cx, js::CheckedUnwrapDynamic(aTarget, cx));
423 if (!target) {
424 js::ReportAccessDenied(cx);
425 return;
427 ar.emplace(cx, target);
430 obj = JS_NewPlainObject(cx);
431 if (!obj) {
432 return;
435 JS::Rooted<JS::Value> value(cx);
436 JS::Rooted<JS::PropertyKey> id(cx);
437 for (uint32_t i = 0; i < valuesIds.length(); i++) {
438 id = valuesIds[i];
439 value = values[i];
441 JS_MarkCrossZoneId(cx, id);
442 if (!JS_WrapValue(cx, &value) ||
443 !JS_SetPropertyById(cx, obj, id, value)) {
444 return;
449 if (aTarget && !JS_WrapObject(cx, &obj)) {
450 return;
453 cleanup.release();
454 aRetval.set(obj);
457 namespace {
458 class IdleDispatchRunnable final : public IdleRunnable,
459 public nsITimerCallback {
460 public:
461 NS_DECL_ISUPPORTS_INHERITED
463 IdleDispatchRunnable(nsIGlobalObject* aParent, IdleRequestCallback& aCallback)
464 : IdleRunnable("ChromeUtils::IdleDispatch"),
465 mCallback(&aCallback),
466 mParent(aParent) {}
468 // MOZ_CAN_RUN_SCRIPT_BOUNDARY until Runnable::Run is MOZ_CAN_RUN_SCRIPT.
469 // See bug 1535398.
470 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override {
471 if (mCallback) {
472 CancelTimer();
474 auto deadline = mDeadline - TimeStamp::ProcessCreation();
476 ErrorResult rv;
477 RefPtr<IdleDeadline> idleDeadline =
478 new IdleDeadline(mParent, mTimedOut, deadline.ToMilliseconds());
480 RefPtr<IdleRequestCallback> callback(std::move(mCallback));
481 MOZ_ASSERT(!mCallback);
482 callback->Call(*idleDeadline, "ChromeUtils::IdleDispatch handler");
483 mParent = nullptr;
485 return NS_OK;
488 void SetDeadline(TimeStamp aDeadline) override { mDeadline = aDeadline; }
490 NS_IMETHOD Notify(nsITimer* aTimer) override {
491 mTimedOut = true;
492 SetDeadline(TimeStamp::Now());
493 return Run();
496 void SetTimer(uint32_t aDelay, nsIEventTarget* aTarget) override {
497 MOZ_ASSERT(aTarget);
498 MOZ_ASSERT(!mTimer);
499 NS_NewTimerWithCallback(getter_AddRefs(mTimer), this, aDelay,
500 nsITimer::TYPE_ONE_SHOT, aTarget);
503 protected:
504 virtual ~IdleDispatchRunnable() { CancelTimer(); }
506 private:
507 void CancelTimer() {
508 if (mTimer) {
509 mTimer->Cancel();
510 mTimer = nullptr;
514 RefPtr<IdleRequestCallback> mCallback;
515 nsCOMPtr<nsIGlobalObject> mParent;
517 nsCOMPtr<nsITimer> mTimer;
519 TimeStamp mDeadline{};
520 bool mTimedOut = false;
523 NS_IMPL_ISUPPORTS_INHERITED(IdleDispatchRunnable, IdleRunnable,
524 nsITimerCallback)
525 } // anonymous namespace
527 /* static */
528 void ChromeUtils::IdleDispatch(const GlobalObject& aGlobal,
529 IdleRequestCallback& aCallback,
530 const IdleRequestOptions& aOptions,
531 ErrorResult& aRv) {
532 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
533 MOZ_ASSERT(global);
535 auto runnable = MakeRefPtr<IdleDispatchRunnable>(global, aCallback);
537 if (aOptions.mTimeout.WasPassed()) {
538 aRv = NS_DispatchToCurrentThreadQueue(
539 runnable.forget(), aOptions.mTimeout.Value(), EventQueuePriority::Idle);
540 } else {
541 aRv = NS_DispatchToCurrentThreadQueue(runnable.forget(),
542 EventQueuePriority::Idle);
546 /* static */
547 void ChromeUtils::Import(const GlobalObject& aGlobal,
548 const nsACString& aResourceURI,
549 const Optional<JS::Handle<JSObject*>>& aTargetObj,
550 JS::MutableHandle<JSObject*> aRetval,
551 ErrorResult& aRv) {
552 RefPtr moduleloader = mozJSModuleLoader::Get();
553 MOZ_ASSERT(moduleloader);
555 AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING_NONSENSITIVE("ChromeUtils::Import",
556 OTHER, aResourceURI);
558 JSContext* cx = aGlobal.Context();
560 JS::Rooted<JSObject*> global(cx);
561 JS::Rooted<JSObject*> exports(cx);
562 nsresult rv = moduleloader->Import(cx, aResourceURI, &global, &exports);
563 if (NS_FAILED(rv)) {
564 aRv.Throw(rv);
565 return;
568 // Import() on the component loader can return NS_OK while leaving an
569 // exception on the JSContext. Check for that case.
570 if (JS_IsExceptionPending(cx)) {
571 aRv.NoteJSContextException(cx);
572 return;
575 if (aTargetObj.WasPassed()) {
576 if (!JS_AssignObject(cx, aTargetObj.Value(), exports)) {
577 aRv.Throw(NS_ERROR_FAILURE);
578 return;
582 if (!JS_WrapObject(cx, &exports)) {
583 aRv.Throw(NS_ERROR_FAILURE);
584 return;
586 aRetval.set(exports);
589 static mozJSModuleLoader* GetContextualESLoader(
590 const Optional<bool>& aLoadInDevToolsLoader, JSObject* aGlobal) {
591 RefPtr devToolsModuleloader = mozJSModuleLoader::GetDevToolsLoader();
592 // We should load the module in the DevTools loader if:
593 // - ChromeUtils.importESModule's `loadInDevToolsLoader` option is true, or,
594 // - if the callsite is from a module loaded in the DevTools loader and
595 // `loadInDevToolsLoader` isn't an explicit false.
596 bool shouldUseDevToolsLoader =
597 (aLoadInDevToolsLoader.WasPassed() && aLoadInDevToolsLoader.Value()) ||
598 (devToolsModuleloader && !aLoadInDevToolsLoader.WasPassed() &&
599 devToolsModuleloader->IsLoaderGlobal(aGlobal));
600 if (shouldUseDevToolsLoader) {
601 return mozJSModuleLoader::GetOrCreateDevToolsLoader();
603 return mozJSModuleLoader::Get();
606 /* static */
607 void ChromeUtils::ImportESModule(
608 const GlobalObject& aGlobal, const nsAString& aResourceURI,
609 const ImportESModuleOptionsDictionary& aOptions,
610 JS::MutableHandle<JSObject*> aRetval, ErrorResult& aRv) {
611 RefPtr moduleloader =
612 GetContextualESLoader(aOptions.mLoadInDevToolsLoader, aGlobal.Get());
613 MOZ_ASSERT(moduleloader);
615 NS_ConvertUTF16toUTF8 registryLocation(aResourceURI);
617 AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING_NONSENSITIVE(
618 "ChromeUtils::ImportESModule", OTHER, registryLocation);
620 JSContext* cx = aGlobal.Context();
622 JS::Rooted<JSObject*> moduleNamespace(cx);
623 nsresult rv =
624 moduleloader->ImportESModule(cx, registryLocation, &moduleNamespace);
625 if (NS_FAILED(rv)) {
626 aRv.Throw(rv);
627 return;
630 MOZ_ASSERT(!JS_IsExceptionPending(cx));
632 if (!JS_WrapObject(cx, &moduleNamespace)) {
633 aRv.Throw(NS_ERROR_FAILURE);
634 return;
636 aRetval.set(moduleNamespace);
639 namespace lazy_getter {
641 static const size_t SLOT_ID = 0;
642 static const size_t SLOT_URI = 1;
643 static const size_t SLOT_PARAMS = 1;
645 static const size_t PARAM_INDEX_TARGET = 0;
646 static const size_t PARAM_INDEX_LAMBDA = 1;
647 static const size_t PARAMS_COUNT = 2;
649 static bool ExtractArgs(JSContext* aCx, JS::CallArgs& aArgs,
650 JS::MutableHandle<JSObject*> aCallee,
651 JS::MutableHandle<JSObject*> aThisObj,
652 JS::MutableHandle<jsid> aId) {
653 aCallee.set(&aArgs.callee());
655 JS::Handle<JS::Value> thisv = aArgs.thisv();
656 if (!thisv.isObject()) {
657 JS_ReportErrorASCII(aCx, "Invalid target object");
658 return false;
661 aThisObj.set(&thisv.toObject());
663 JS::Rooted<JS::Value> id(aCx,
664 js::GetFunctionNativeReserved(aCallee, SLOT_ID));
665 MOZ_ALWAYS_TRUE(JS_ValueToId(aCx, id, aId));
666 return true;
669 static bool JSLazyGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
670 JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
672 JS::Rooted<JSObject*> callee(aCx);
673 JS::Rooted<JSObject*> unused(aCx);
674 JS::Rooted<jsid> id(aCx);
675 if (!ExtractArgs(aCx, args, &callee, &unused, &id)) {
676 return false;
679 JS::Rooted<JS::Value> paramsVal(
680 aCx, js::GetFunctionNativeReserved(callee, SLOT_PARAMS));
681 if (paramsVal.isUndefined()) {
682 args.rval().setUndefined();
683 return true;
685 // Avoid calling the lambda multiple times, in case of:
686 // * the getter function is retrieved from property descriptor and called
687 // * the lambda gets the property again
688 // * the getter function throws and accessed again
689 js::SetFunctionNativeReserved(callee, SLOT_PARAMS, JS::UndefinedHandleValue);
691 JS::Rooted<JSObject*> paramsObj(aCx, &paramsVal.toObject());
693 JS::Rooted<JS::Value> targetVal(aCx);
694 JS::Rooted<JS::Value> lambdaVal(aCx);
695 if (!JS_GetElement(aCx, paramsObj, PARAM_INDEX_TARGET, &targetVal)) {
696 return false;
698 if (!JS_GetElement(aCx, paramsObj, PARAM_INDEX_LAMBDA, &lambdaVal)) {
699 return false;
702 JS::Rooted<JSObject*> targetObj(aCx, &targetVal.toObject());
704 JS::Rooted<JS::Value> value(aCx);
705 if (!JS::Call(aCx, targetObj, lambdaVal, JS::HandleValueArray::empty(),
706 &value)) {
707 return false;
710 if (!JS_DefinePropertyById(aCx, targetObj, id, value, JSPROP_ENUMERATE)) {
711 return false;
714 args.rval().set(value);
715 return true;
718 static bool DefineLazyGetter(JSContext* aCx, JS::Handle<JSObject*> aTarget,
719 JS::Handle<JS::Value> aName,
720 JS::Handle<JSObject*> aLambda) {
721 JS::Rooted<jsid> id(aCx);
722 if (!JS_ValueToId(aCx, aName, &id)) {
723 return false;
726 JS::Rooted<JSObject*> getter(
727 aCx, JS_GetFunctionObject(
728 js::NewFunctionByIdWithReserved(aCx, JSLazyGetter, 0, 0, id)));
729 if (!getter) {
730 JS_ReportOutOfMemory(aCx);
731 return false;
734 JS::RootedVector<JS::Value> params(aCx);
735 if (!params.resize(PARAMS_COUNT)) {
736 return false;
738 params[PARAM_INDEX_TARGET].setObject(*aTarget);
739 params[PARAM_INDEX_LAMBDA].setObject(*aLambda);
740 JS::Rooted<JSObject*> paramsObj(aCx, JS::NewArrayObject(aCx, params));
741 if (!paramsObj) {
742 return false;
745 js::SetFunctionNativeReserved(getter, SLOT_ID, aName);
746 js::SetFunctionNativeReserved(getter, SLOT_PARAMS,
747 JS::ObjectValue(*paramsObj));
749 return JS_DefinePropertyById(aCx, aTarget, id, getter, nullptr,
750 JSPROP_ENUMERATE);
753 enum class ModuleType { JSM, ESM };
755 static bool ModuleGetterImpl(JSContext* aCx, unsigned aArgc, JS::Value* aVp,
756 ModuleType aType) {
757 JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
759 JS::Rooted<JSObject*> callee(aCx);
760 JS::Rooted<JSObject*> thisObj(aCx);
761 JS::Rooted<jsid> id(aCx);
762 if (!ExtractArgs(aCx, args, &callee, &thisObj, &id)) {
763 return false;
766 JS::Rooted<JSString*> moduleURI(
767 aCx, js::GetFunctionNativeReserved(callee, SLOT_URI).toString());
768 JS::UniqueChars bytes = JS_EncodeStringToUTF8(aCx, moduleURI);
769 if (!bytes) {
770 return false;
772 nsDependentCString uri(bytes.get());
774 RefPtr moduleloader =
775 aType == ModuleType::JSM
776 ? mozJSModuleLoader::Get()
777 : GetContextualESLoader(
778 Optional<bool>(),
779 JS::GetNonCCWObjectGlobal(js::UncheckedUnwrap(thisObj)));
780 MOZ_ASSERT(moduleloader);
782 JS::Rooted<JS::Value> value(aCx);
783 if (aType == ModuleType::JSM) {
784 JS::Rooted<JSObject*> moduleGlobal(aCx);
785 JS::Rooted<JSObject*> moduleExports(aCx);
786 nsresult rv = moduleloader->Import(aCx, uri, &moduleGlobal, &moduleExports);
787 if (NS_FAILED(rv)) {
788 Throw(aCx, rv);
789 return false;
792 // JSM's exports is from the same realm.
793 if (!JS_GetPropertyById(aCx, moduleExports, id, &value)) {
794 return false;
796 } else {
797 JS::Rooted<JSObject*> moduleNamespace(aCx);
798 nsresult rv = moduleloader->ImportESModule(aCx, uri, &moduleNamespace);
799 if (NS_FAILED(rv)) {
800 Throw(aCx, rv);
801 return false;
804 // ESM's namespace is from the module's realm.
806 JSAutoRealm ar(aCx, moduleNamespace);
807 if (!JS_GetPropertyById(aCx, moduleNamespace, id, &value)) {
808 return false;
811 if (!JS_WrapValue(aCx, &value)) {
812 return false;
816 if (!JS_DefinePropertyById(aCx, thisObj, id, value, JSPROP_ENUMERATE)) {
817 return false;
820 args.rval().set(value);
821 return true;
824 static bool JSModuleGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
825 return ModuleGetterImpl(aCx, aArgc, aVp, ModuleType::JSM);
828 static bool ESModuleGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
829 return ModuleGetterImpl(aCx, aArgc, aVp, ModuleType::ESM);
832 static bool ModuleSetterImpl(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
833 JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
835 JS::Rooted<JSObject*> callee(aCx);
836 JS::Rooted<JSObject*> thisObj(aCx);
837 JS::Rooted<jsid> id(aCx);
838 if (!ExtractArgs(aCx, args, &callee, &thisObj, &id)) {
839 return false;
842 return JS_DefinePropertyById(aCx, thisObj, id, args.get(0), JSPROP_ENUMERATE);
845 static bool JSModuleSetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
846 return ModuleSetterImpl(aCx, aArgc, aVp);
849 static bool ESModuleSetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
850 return ModuleSetterImpl(aCx, aArgc, aVp);
853 static bool DefineJSModuleGetter(JSContext* aCx, JS::Handle<JSObject*> aTarget,
854 const nsAString& aId,
855 const nsAString& aResourceURI) {
856 JS::Rooted<JS::Value> uri(aCx);
857 JS::Rooted<JS::Value> idValue(aCx);
858 JS::Rooted<jsid> id(aCx);
859 if (!xpc::NonVoidStringToJsval(aCx, aResourceURI, &uri) ||
860 !xpc::NonVoidStringToJsval(aCx, aId, &idValue) ||
861 !JS_ValueToId(aCx, idValue, &id)) {
862 return false;
864 idValue = js::IdToValue(id);
866 JS::Rooted<JSObject*> getter(
867 aCx, JS_GetFunctionObject(
868 js::NewFunctionByIdWithReserved(aCx, JSModuleGetter, 0, 0, id)));
870 JS::Rooted<JSObject*> setter(
871 aCx, JS_GetFunctionObject(
872 js::NewFunctionByIdWithReserved(aCx, JSModuleSetter, 0, 0, id)));
874 if (!getter || !setter) {
875 JS_ReportOutOfMemory(aCx);
876 return false;
879 js::SetFunctionNativeReserved(getter, SLOT_ID, idValue);
880 js::SetFunctionNativeReserved(setter, SLOT_ID, idValue);
882 js::SetFunctionNativeReserved(getter, SLOT_URI, uri);
884 return JS_DefinePropertyById(aCx, aTarget, id, getter, setter,
885 JSPROP_ENUMERATE);
888 static bool DefineESModuleGetter(JSContext* aCx, JS::Handle<JSObject*> aTarget,
889 JS::Handle<JS::PropertyKey> aId,
890 JS::Handle<JS::Value> aResourceURI) {
891 JS::Rooted<JS::Value> idVal(aCx, JS::StringValue(aId.toString()));
893 JS::Rooted<JSObject*> getter(
894 aCx, JS_GetFunctionObject(js::NewFunctionByIdWithReserved(
895 aCx, ESModuleGetter, 0, 0, aId)));
897 JS::Rooted<JSObject*> setter(
898 aCx, JS_GetFunctionObject(js::NewFunctionByIdWithReserved(
899 aCx, ESModuleSetter, 0, 0, aId)));
901 if (!getter || !setter) {
902 JS_ReportOutOfMemory(aCx);
903 return false;
906 js::SetFunctionNativeReserved(getter, SLOT_ID, idVal);
907 js::SetFunctionNativeReserved(setter, SLOT_ID, idVal);
909 js::SetFunctionNativeReserved(getter, SLOT_URI, aResourceURI);
911 return JS_DefinePropertyById(aCx, aTarget, aId, getter, setter,
912 JSPROP_ENUMERATE);
915 } // namespace lazy_getter
917 /* static */
918 void ChromeUtils::DefineLazyGetter(const GlobalObject& aGlobal,
919 JS::Handle<JSObject*> aTarget,
920 JS::Handle<JS::Value> aName,
921 JS::Handle<JSObject*> aLambda,
922 ErrorResult& aRv) {
923 JSContext* cx = aGlobal.Context();
924 if (!lazy_getter::DefineLazyGetter(cx, aTarget, aName, aLambda)) {
925 aRv.NoteJSContextException(cx);
926 return;
930 /* static */
931 void ChromeUtils::DefineModuleGetter(const GlobalObject& global,
932 JS::Handle<JSObject*> target,
933 const nsAString& id,
934 const nsAString& resourceURI,
935 ErrorResult& aRv) {
936 if (!lazy_getter::DefineJSModuleGetter(global.Context(), target, id,
937 resourceURI)) {
938 aRv.NoteJSContextException(global.Context());
942 /* static */
943 void ChromeUtils::DefineESModuleGetters(const GlobalObject& global,
944 JS::Handle<JSObject*> target,
945 JS::Handle<JSObject*> modules,
946 ErrorResult& aRv) {
947 JSContext* cx = global.Context();
949 JS::Rooted<JS::IdVector> props(cx, JS::IdVector(cx));
950 if (!JS_Enumerate(cx, modules, &props)) {
951 aRv.NoteJSContextException(cx);
952 return;
955 JS::Rooted<JS::PropertyKey> prop(cx);
956 JS::Rooted<JS::Value> resourceURIVal(cx);
957 for (JS::PropertyKey tmp : props) {
958 prop = tmp;
960 if (!prop.isString()) {
961 aRv.Throw(NS_ERROR_FAILURE);
962 return;
965 if (!JS_GetPropertyById(cx, modules, prop, &resourceURIVal)) {
966 aRv.NoteJSContextException(cx);
967 return;
970 if (!lazy_getter::DefineESModuleGetter(cx, target, prop, resourceURIVal)) {
971 aRv.NoteJSContextException(cx);
972 return;
977 #ifdef XP_UNIX
978 /* static */
979 void ChromeUtils::GetLibcConstants(const GlobalObject&,
980 LibcConstants& aConsts) {
981 aConsts.mEINTR.Construct(EINTR);
982 aConsts.mEACCES.Construct(EACCES);
983 aConsts.mEAGAIN.Construct(EAGAIN);
984 aConsts.mEINVAL.Construct(EINVAL);
985 aConsts.mENOSYS.Construct(ENOSYS);
987 aConsts.mF_SETFD.Construct(F_SETFD);
988 aConsts.mF_SETFL.Construct(F_SETFL);
990 aConsts.mFD_CLOEXEC.Construct(FD_CLOEXEC);
992 aConsts.mAT_EACCESS.Construct(AT_EACCESS);
994 aConsts.mO_CREAT.Construct(O_CREAT);
995 aConsts.mO_NONBLOCK.Construct(O_NONBLOCK);
996 aConsts.mO_WRONLY.Construct(O_WRONLY);
998 aConsts.mPOLLERR.Construct(POLLERR);
999 aConsts.mPOLLHUP.Construct(POLLHUP);
1000 aConsts.mPOLLIN.Construct(POLLIN);
1001 aConsts.mPOLLNVAL.Construct(POLLNVAL);
1002 aConsts.mPOLLOUT.Construct(POLLOUT);
1004 aConsts.mWNOHANG.Construct(WNOHANG);
1006 # ifdef XP_LINUX
1007 aConsts.mPR_CAPBSET_READ.Construct(PR_CAPBSET_READ);
1008 # endif
1010 #endif
1012 /* static */
1013 void ChromeUtils::OriginAttributesToSuffix(
1014 dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs,
1015 nsCString& aSuffix)
1018 OriginAttributes attrs(aAttrs);
1019 attrs.CreateSuffix(aSuffix);
1022 /* static */
1023 bool ChromeUtils::OriginAttributesMatchPattern(
1024 dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs,
1025 const dom::OriginAttributesPatternDictionary& aPattern) {
1026 OriginAttributes attrs(aAttrs);
1027 OriginAttributesPattern pattern(aPattern);
1028 return pattern.Matches(attrs);
1031 /* static */
1032 void ChromeUtils::CreateOriginAttributesFromOrigin(
1033 dom::GlobalObject& aGlobal, const nsAString& aOrigin,
1034 dom::OriginAttributesDictionary& aAttrs, ErrorResult& aRv) {
1035 OriginAttributes attrs;
1036 nsAutoCString suffix;
1037 if (!attrs.PopulateFromOrigin(NS_ConvertUTF16toUTF8(aOrigin), suffix)) {
1038 aRv.Throw(NS_ERROR_FAILURE);
1039 return;
1041 aAttrs = attrs;
1044 /* static */
1045 void ChromeUtils::CreateOriginAttributesFromOriginSuffix(
1046 dom::GlobalObject& aGlobal, const nsAString& aSuffix,
1047 dom::OriginAttributesDictionary& aAttrs, ErrorResult& aRv) {
1048 OriginAttributes attrs;
1049 nsAutoCString suffix;
1050 if (!attrs.PopulateFromSuffix(NS_ConvertUTF16toUTF8(aSuffix))) {
1051 aRv.Throw(NS_ERROR_FAILURE);
1052 return;
1054 aAttrs = attrs;
1057 /* static */
1058 void ChromeUtils::FillNonDefaultOriginAttributes(
1059 dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs,
1060 dom::OriginAttributesDictionary& aNewAttrs) {
1061 aNewAttrs = aAttrs;
1064 /* static */
1065 bool ChromeUtils::IsOriginAttributesEqual(
1066 dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aA,
1067 const dom::OriginAttributesDictionary& aB) {
1068 return IsOriginAttributesEqual(aA, aB);
1071 /* static */
1072 bool ChromeUtils::IsOriginAttributesEqual(
1073 const dom::OriginAttributesDictionary& aA,
1074 const dom::OriginAttributesDictionary& aB) {
1075 return aA == aB;
1078 /* static */
1079 void ChromeUtils::GetBaseDomainFromPartitionKey(dom::GlobalObject& aGlobal,
1080 const nsAString& aPartitionKey,
1081 nsAString& aBaseDomain,
1082 ErrorResult& aRv) {
1083 nsString scheme;
1084 nsString pkBaseDomain;
1085 int32_t port;
1087 if (!mozilla::OriginAttributes::ParsePartitionKey(aPartitionKey, scheme,
1088 pkBaseDomain, port)) {
1089 aRv.Throw(NS_ERROR_FAILURE);
1090 return;
1093 aBaseDomain = pkBaseDomain;
1096 /* static */
1097 void ChromeUtils::GetPartitionKeyFromURL(dom::GlobalObject& aGlobal,
1098 const nsAString& aURL,
1099 nsAString& aPartitionKey,
1100 ErrorResult& aRv) {
1101 nsCOMPtr<nsIURI> uri;
1102 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL);
1103 if (NS_SUCCEEDED(rv) && uri->SchemeIs("chrome")) {
1104 rv = NS_ERROR_FAILURE;
1107 if (NS_WARN_IF(NS_FAILED(rv))) {
1108 aPartitionKey.Truncate();
1109 aRv.Throw(rv);
1110 return;
1113 mozilla::OriginAttributes attrs;
1114 attrs.SetPartitionKey(uri);
1116 aPartitionKey = attrs.mPartitionKey;
1119 #ifdef NIGHTLY_BUILD
1120 /* static */
1121 void ChromeUtils::GetRecentJSDevError(GlobalObject& aGlobal,
1122 JS::MutableHandle<JS::Value> aRetval,
1123 ErrorResult& aRv) {
1124 aRetval.setUndefined();
1125 auto runtime = CycleCollectedJSRuntime::Get();
1126 MOZ_ASSERT(runtime);
1128 auto cx = aGlobal.Context();
1129 if (!runtime->GetRecentDevError(cx, aRetval)) {
1130 aRv.NoteJSContextException(cx);
1131 return;
1135 /* static */
1136 void ChromeUtils::ClearRecentJSDevError(GlobalObject&) {
1137 auto runtime = CycleCollectedJSRuntime::Get();
1138 MOZ_ASSERT(runtime);
1140 runtime->ClearRecentDevError();
1142 #endif // NIGHTLY_BUILD
1144 void ChromeUtils::ClearStyleSheetCacheByPrincipal(GlobalObject&,
1145 nsIPrincipal* aForPrincipal) {
1146 SharedStyleSheetCache::Clear(aForPrincipal);
1149 void ChromeUtils::ClearStyleSheetCacheByBaseDomain(
1150 GlobalObject&, const nsACString& aBaseDomain) {
1151 SharedStyleSheetCache::Clear(nullptr, &aBaseDomain);
1154 void ChromeUtils::ClearStyleSheetCache(GlobalObject&) {
1155 SharedStyleSheetCache::Clear();
1158 #define PROCTYPE_TO_WEBIDL_CASE(_procType, _webidl) \
1159 case mozilla::ProcType::_procType: \
1160 return WebIDLProcType::_webidl
1162 static WebIDLProcType ProcTypeToWebIDL(mozilla::ProcType aType) {
1163 // Max is the value of the last enum, not the length, so add one.
1164 static_assert(
1165 WebIDLProcTypeValues::Count == static_cast<size_t>(ProcType::Max) + 1,
1166 "In order for this static cast to be okay, "
1167 "WebIDLProcType must match ProcType exactly");
1169 // These must match the similar ones in E10SUtils.sys.mjs, RemoteTypes.h,
1170 // ProcInfo.h and ChromeUtils.webidl
1171 switch (aType) {
1172 PROCTYPE_TO_WEBIDL_CASE(Web, Web);
1173 PROCTYPE_TO_WEBIDL_CASE(WebIsolated, WebIsolated);
1174 PROCTYPE_TO_WEBIDL_CASE(File, File);
1175 PROCTYPE_TO_WEBIDL_CASE(Extension, Extension);
1176 PROCTYPE_TO_WEBIDL_CASE(PrivilegedAbout, Privilegedabout);
1177 PROCTYPE_TO_WEBIDL_CASE(PrivilegedMozilla, Privilegedmozilla);
1178 PROCTYPE_TO_WEBIDL_CASE(WebCOOPCOEP, WithCoopCoep);
1179 PROCTYPE_TO_WEBIDL_CASE(WebServiceWorker, WebServiceWorker);
1181 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
1182 process_bin_type, procinfo_typename, \
1183 webidl_typename, allcaps_name) \
1184 PROCTYPE_TO_WEBIDL_CASE(procinfo_typename, webidl_typename);
1185 #define SKIP_PROCESS_TYPE_CONTENT
1186 #ifndef MOZ_ENABLE_FORKSERVER
1187 # define SKIP_PROCESS_TYPE_FORKSERVER
1188 #endif // MOZ_ENABLE_FORKSERVER
1189 #include "mozilla/GeckoProcessTypes.h"
1190 #undef SKIP_PROCESS_TYPE_CONTENT
1191 #ifndef MOZ_ENABLE_FORKSERVER
1192 # undef SKIP_PROCESS_TYPE_FORKSERVER
1193 #endif // MOZ_ENABLE_FORKSERVER
1194 #undef GECKO_PROCESS_TYPE
1196 PROCTYPE_TO_WEBIDL_CASE(Preallocated, Preallocated);
1197 PROCTYPE_TO_WEBIDL_CASE(Unknown, Unknown);
1200 MOZ_ASSERT(false, "Unhandled case in ProcTypeToWebIDL");
1201 return WebIDLProcType::Unknown;
1204 #undef PROCTYPE_TO_WEBIDL_CASE
1206 /* static */
1207 already_AddRefed<Promise> ChromeUtils::RequestProcInfo(GlobalObject& aGlobal,
1208 ErrorResult& aRv) {
1209 // This function will use IPDL to enable threads info on macOS
1210 // see https://bugzilla.mozilla.org/show_bug.cgi?id=1529023
1211 if (!XRE_IsParentProcess()) {
1212 aRv.Throw(NS_ERROR_FAILURE);
1213 return nullptr;
1215 // Prepare the JS promise that will hold our response.
1216 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
1217 MOZ_ASSERT(global);
1218 RefPtr<Promise> domPromise = Promise::Create(global, aRv);
1219 if (NS_WARN_IF(aRv.Failed())) {
1220 return nullptr;
1222 MOZ_ASSERT(domPromise);
1224 // Get a list of processes to examine and pre-fill them with available info.
1225 // Note that this is subject to race conditions: just because we have a
1226 // process in the list doesn't mean that the process will still be alive when
1227 // we attempt to get its information. Followup code MUST be able to fail
1228 // gracefully on some processes and still return whichever information is
1229 // available.
1231 // Get all the content parents.
1232 // Note that this array includes even the long dead content parents, so we
1233 // might have some garbage, especially with Fission.
1234 // SAFETY NOTE: `contentParents` is only valid if used synchronously.
1235 // Anything else and you may end up dealing with dangling pointers.
1236 nsTArray<ContentParent*> contentParents;
1237 ContentParent::GetAll(contentParents);
1239 // Prepare our background request.
1240 // We reserve one more slot for the browser process itself.
1241 nsTArray<ProcInfoRequest> requests(contentParents.Length() + 1);
1242 // Requesting process info for the browser process itself.
1243 requests.EmplaceBack(
1244 /* aPid = */ base::GetCurrentProcId(),
1245 /* aProcessType = */ ProcType::Browser,
1246 /* aOrigin = */ ""_ns,
1247 /* aWindowInfo = */ nsTArray<WindowInfo>(),
1248 /* aUtilityInfo = */ nsTArray<UtilityInfo>());
1250 // First handle non-ContentParent processes.
1251 mozilla::ipc::GeckoChildProcessHost::GetAll(
1252 [&requests](mozilla::ipc::GeckoChildProcessHost* aGeckoProcess) {
1253 base::ProcessId childPid = aGeckoProcess->GetChildProcessId();
1254 if (childPid == 0) {
1255 // Something went wrong with this process, it may be dead already,
1256 // fail gracefully.
1257 return;
1259 mozilla::ProcType type = mozilla::ProcType::Unknown;
1261 switch (aGeckoProcess->GetProcessType()) {
1262 case GeckoProcessType::GeckoProcessType_Content: {
1263 // These processes are handled separately.
1264 return;
1267 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
1268 process_bin_type, procinfo_typename, \
1269 webidl_typename, allcaps_name) \
1270 case GeckoProcessType::GeckoProcessType_##enum_name: { \
1271 type = mozilla::ProcType::procinfo_typename; \
1272 break; \
1274 #define SKIP_PROCESS_TYPE_CONTENT
1275 #ifndef MOZ_ENABLE_FORKSERVER
1276 # define SKIP_PROCESS_TYPE_FORKSERVER
1277 #endif // MOZ_ENABLE_FORKSERVER
1278 #include "mozilla/GeckoProcessTypes.h"
1279 #ifndef MOZ_ENABLE_FORKSERVER
1280 # undef SKIP_PROCESS_TYPE_FORKSERVER
1281 #endif // MOZ_ENABLE_FORKSERVER
1282 #undef SKIP_PROCESS_TYPE_CONTENT
1283 #undef GECKO_PROCESS_TYPE
1284 default:
1285 // Leave the default Unknown value in |type|.
1286 break;
1289 // Attach utility actor information to the process.
1290 nsTArray<UtilityInfo> utilityActors;
1291 if (aGeckoProcess->GetProcessType() ==
1292 GeckoProcessType::GeckoProcessType_Utility) {
1293 RefPtr<mozilla::ipc::UtilityProcessManager> upm =
1294 mozilla::ipc::UtilityProcessManager::GetSingleton();
1295 if (!utilityActors.AppendElements(upm->GetActors(aGeckoProcess),
1296 fallible)) {
1297 NS_WARNING("Error adding actors");
1298 return;
1302 requests.EmplaceBack(
1303 /* aPid = */ childPid,
1304 /* aProcessType = */ type,
1305 /* aOrigin = */ ""_ns,
1306 /* aWindowInfo = */ nsTArray<WindowInfo>(), // Without a
1307 // ContentProcess, no
1308 // DOM windows.
1309 /* aUtilityInfo = */ std::move(utilityActors),
1310 /* aChild = */ 0 // Without a ContentProcess, no ChildId.
1311 #ifdef XP_MACOSX
1313 /* aChildTask = */ aGeckoProcess->GetChildTask()
1314 #endif // XP_MACOSX
1318 // Now handle ContentParents.
1319 for (const auto* contentParent : contentParents) {
1320 if (!contentParent || !contentParent->Process()) {
1321 // Presumably, the process is dead or dying.
1322 continue;
1324 base::ProcessId pid = contentParent->Process()->GetChildProcessId();
1325 if (pid == 0) {
1326 // Presumably, the process is dead or dying.
1327 continue;
1329 if (contentParent->Process()->GetProcessType() !=
1330 GeckoProcessType::GeckoProcessType_Content) {
1331 // We're probably racing against a process changing type.
1332 // We'll get it in the next call, skip it for the moment.
1333 continue;
1336 // Since this code is executed synchronously on the main thread,
1337 // processes cannot die while we're in this loop.
1338 mozilla::ProcType type = mozilla::ProcType::Unknown;
1340 // Convert the remoteType into a ProcType.
1341 // Ideally, the remoteType should be strongly typed
1342 // upstream, this would make the conversion less brittle.
1343 const nsAutoCString remoteType(contentParent->GetRemoteType());
1344 if (StringBeginsWith(remoteType, FISSION_WEB_REMOTE_TYPE)) {
1345 // WARNING: Do not change the order, as
1346 // `DEFAULT_REMOTE_TYPE` is a prefix of
1347 // `FISSION_WEB_REMOTE_TYPE`.
1348 type = mozilla::ProcType::WebIsolated;
1349 } else if (StringBeginsWith(remoteType, SERVICEWORKER_REMOTE_TYPE)) {
1350 type = mozilla::ProcType::WebServiceWorker;
1351 } else if (StringBeginsWith(remoteType,
1352 WITH_COOP_COEP_REMOTE_TYPE_PREFIX)) {
1353 type = mozilla::ProcType::WebCOOPCOEP;
1354 } else if (remoteType == FILE_REMOTE_TYPE) {
1355 type = mozilla::ProcType::File;
1356 } else if (remoteType == EXTENSION_REMOTE_TYPE) {
1357 type = mozilla::ProcType::Extension;
1358 } else if (remoteType == PRIVILEGEDABOUT_REMOTE_TYPE) {
1359 type = mozilla::ProcType::PrivilegedAbout;
1360 } else if (remoteType == PRIVILEGEDMOZILLA_REMOTE_TYPE) {
1361 type = mozilla::ProcType::PrivilegedMozilla;
1362 } else if (remoteType == PREALLOC_REMOTE_TYPE) {
1363 type = mozilla::ProcType::Preallocated;
1364 } else if (StringBeginsWith(remoteType, DEFAULT_REMOTE_TYPE)) {
1365 type = mozilla::ProcType::Web;
1366 } else {
1367 MOZ_CRASH_UNSAFE_PRINTF("Unknown remoteType '%s'", remoteType.get());
1370 // By convention, everything after '=' is the origin.
1371 nsAutoCString origin;
1372 nsACString::const_iterator cursor;
1373 nsACString::const_iterator end;
1374 remoteType.BeginReading(cursor);
1375 remoteType.EndReading(end);
1376 if (FindCharInReadable('=', cursor, end)) {
1377 origin = Substring(++cursor, end);
1380 // Attach DOM window information to the process.
1381 nsTArray<WindowInfo> windows;
1382 for (const auto& browserParentWrapperKey :
1383 contentParent->ManagedPBrowserParent()) {
1384 for (const auto& windowGlobalParentWrapperKey :
1385 browserParentWrapperKey->ManagedPWindowGlobalParent()) {
1386 // WindowGlobalParent is the only immediate subclass of
1387 // PWindowGlobalParent.
1388 auto* windowGlobalParent =
1389 static_cast<WindowGlobalParent*>(windowGlobalParentWrapperKey);
1391 nsString documentTitle;
1392 windowGlobalParent->GetDocumentTitle(documentTitle);
1393 WindowInfo* window = windows.EmplaceBack(
1394 fallible,
1395 /* aOuterWindowId = */ windowGlobalParent->OuterWindowId(),
1396 /* aDocumentURI = */ windowGlobalParent->GetDocumentURI(),
1397 /* aDocumentTitle = */ std::move(documentTitle),
1398 /* aIsProcessRoot = */ windowGlobalParent->IsProcessRoot(),
1399 /* aIsInProcess = */ windowGlobalParent->IsInProcess());
1400 if (!window) {
1401 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
1402 return nullptr;
1406 requests.EmplaceBack(
1407 /* aPid = */ pid,
1408 /* aProcessType = */ type,
1409 /* aOrigin = */ origin,
1410 /* aWindowInfo = */ std::move(windows),
1411 /* aUtilityInfo = */ nsTArray<UtilityInfo>(),
1412 /* aChild = */ contentParent->ChildID()
1413 #ifdef XP_MACOSX
1415 /* aChildTask = */ contentParent->Process()->GetChildTask()
1416 #endif // XP_MACOSX
1420 // Now place background request.
1421 RefPtr<nsISerialEventTarget> target = global->SerialEventTarget();
1422 mozilla::GetProcInfo(std::move(requests))
1423 ->Then(
1424 target, __func__,
1425 [target,
1426 domPromise](const HashMap<base::ProcessId, ProcInfo>& aSysProcInfo) {
1427 ParentProcInfoDictionary parentInfo;
1428 if (aSysProcInfo.count() == 0) {
1429 // For some reason, we couldn't get *any* info.
1430 // Maybe a sandboxing issue?
1431 domPromise->MaybeReject(NS_ERROR_UNEXPECTED);
1432 return;
1434 nsTArray<ChildProcInfoDictionary> childrenInfo(
1435 aSysProcInfo.count() - 1);
1436 for (auto iter = aSysProcInfo.iter(); !iter.done(); iter.next()) {
1437 const auto& sysProcInfo = iter.get().value();
1438 nsresult rv;
1439 if (sysProcInfo.type == ProcType::Browser) {
1440 rv = mozilla::CopySysProcInfoToDOM(sysProcInfo, &parentInfo);
1441 if (NS_FAILED(rv)) {
1442 // Failing to copy? That's probably not something from we can
1443 // (or should) try to recover gracefully.
1444 domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
1445 return;
1447 MOZ_ASSERT(sysProcInfo.childId == 0);
1448 MOZ_ASSERT(sysProcInfo.origin.IsEmpty());
1449 } else {
1450 mozilla::dom::ChildProcInfoDictionary* childInfo =
1451 childrenInfo.AppendElement(fallible);
1452 if (!childInfo) {
1453 domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
1454 return;
1456 rv = mozilla::CopySysProcInfoToDOM(sysProcInfo, childInfo);
1457 if (NS_FAILED(rv)) {
1458 domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
1459 return;
1461 // Copy Firefox info.
1462 childInfo->mChildID = sysProcInfo.childId;
1463 childInfo->mOrigin = sysProcInfo.origin;
1464 childInfo->mType = ProcTypeToWebIDL(sysProcInfo.type);
1466 for (const auto& source : sysProcInfo.windows) {
1467 auto* dest = childInfo->mWindows.AppendElement(fallible);
1468 if (!dest) {
1469 domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
1470 return;
1472 dest->mOuterWindowId = source.outerWindowId;
1473 dest->mDocumentURI = source.documentURI;
1474 dest->mDocumentTitle = source.documentTitle;
1475 dest->mIsProcessRoot = source.isProcessRoot;
1476 dest->mIsInProcess = source.isInProcess;
1479 if (sysProcInfo.type == ProcType::Utility) {
1480 for (const auto& source : sysProcInfo.utilityActors) {
1481 auto* dest =
1482 childInfo->mUtilityActors.AppendElement(fallible);
1483 if (!dest) {
1484 domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
1485 return;
1488 dest->mActorName = source.actorName;
1494 // Attach the children to the parent.
1495 mozilla::dom::Sequence<mozilla::dom::ChildProcInfoDictionary>
1496 children(std::move(childrenInfo));
1497 parentInfo.mChildren = std::move(children);
1498 domPromise->MaybeResolve(parentInfo);
1500 [domPromise](nsresult aRv) { domPromise->MaybeReject(aRv); });
1501 MOZ_ASSERT(domPromise);
1503 // sending back the promise instance
1504 return domPromise.forget();
1507 /* static */
1508 bool ChromeUtils::VsyncEnabled(GlobalObject& aGlobal) {
1509 return mozilla::gfx::VsyncSource::GetFastestVsyncRate().isSome();
1512 void ChromeUtils::SetPerfStatsCollectionMask(GlobalObject& aGlobal,
1513 uint64_t aMask) {
1514 PerfStats::SetCollectionMask(static_cast<PerfStats::MetricMask>(aMask));
1517 already_AddRefed<Promise> ChromeUtils::CollectPerfStats(GlobalObject& aGlobal,
1518 ErrorResult& aRv) {
1519 // Creating a JS promise
1520 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
1521 MOZ_ASSERT(global);
1523 RefPtr<Promise> promise = Promise::Create(global, aRv);
1524 if (aRv.Failed()) {
1525 return nullptr;
1528 RefPtr<PerfStats::PerfStatsPromise> extPromise =
1529 PerfStats::CollectPerfStatsJSON();
1531 extPromise->Then(
1532 GetCurrentSerialEventTarget(), __func__,
1533 [promise](const nsCString& aResult) {
1534 promise->MaybeResolve(NS_ConvertUTF8toUTF16(aResult));
1536 [promise](bool aValue) { promise->MaybeReject(NS_ERROR_FAILURE); });
1538 return promise.forget();
1541 constexpr auto kSkipSelfHosted = JS::SavedFrameSelfHosted::Exclude;
1543 /* static */
1544 void ChromeUtils::GetCallerLocation(const GlobalObject& aGlobal,
1545 nsIPrincipal* aPrincipal,
1546 JS::MutableHandle<JSObject*> aRetval) {
1547 JSContext* cx = aGlobal.Context();
1549 auto* principals = nsJSPrincipals::get(aPrincipal);
1551 JS::StackCapture captureMode(JS::FirstSubsumedFrame(cx, principals));
1553 JS::Rooted<JSObject*> frame(cx);
1554 if (!JS::CaptureCurrentStack(cx, &frame, std::move(captureMode))) {
1555 JS_ClearPendingException(cx);
1556 aRetval.set(nullptr);
1557 return;
1560 // FirstSubsumedFrame gets us a stack which stops at the first principal which
1561 // is subsumed by the given principal. That means that we may have a lot of
1562 // privileged frames that we don't care about at the top of the stack, though.
1563 // We need to filter those out to get the frame we actually want.
1564 aRetval.set(
1565 js::GetFirstSubsumedSavedFrame(cx, principals, frame, kSkipSelfHosted));
1568 /* static */
1569 void ChromeUtils::CreateError(const GlobalObject& aGlobal,
1570 const nsAString& aMessage,
1571 JS::Handle<JSObject*> aStack,
1572 JS::MutableHandle<JSObject*> aRetVal,
1573 ErrorResult& aRv) {
1574 if (aStack && !JS::IsMaybeWrappedSavedFrame(aStack)) {
1575 aRv.Throw(NS_ERROR_INVALID_ARG);
1576 return;
1579 JSContext* cx = aGlobal.Context();
1581 auto cleanup = MakeScopeExit([&]() { aRv.NoteJSContextException(cx); });
1583 JS::Rooted<JSObject*> retVal(cx);
1585 JS::Rooted<JSString*> fileName(cx, JS_GetEmptyString(cx));
1586 uint32_t line = 0;
1587 JS::TaggedColumnNumberOneOrigin column;
1589 Maybe<JSAutoRealm> ar;
1590 JS::Rooted<JSObject*> stack(cx);
1591 if (aStack) {
1592 stack = UncheckedUnwrap(aStack);
1593 ar.emplace(cx, stack);
1595 JSPrincipals* principals =
1596 JS::GetRealmPrincipals(js::GetContextRealm(cx));
1597 if (JS::GetSavedFrameLine(cx, principals, stack, &line) !=
1598 JS::SavedFrameResult::Ok ||
1599 JS::GetSavedFrameColumn(cx, principals, stack, &column) !=
1600 JS::SavedFrameResult::Ok ||
1601 JS::GetSavedFrameSource(cx, principals, stack, &fileName) !=
1602 JS::SavedFrameResult::Ok) {
1603 return;
1607 JS::Rooted<JSString*> message(cx);
1609 JS::Rooted<JS::Value> msgVal(cx);
1610 if (!xpc::NonVoidStringToJsval(cx, aMessage, &msgVal)) {
1611 return;
1613 message = msgVal.toString();
1616 JS::Rooted<JS::Value> err(cx);
1617 if (!JS::CreateError(cx, JSEXN_ERR, stack, fileName, line,
1618 JS::ColumnNumberOneOrigin(column.oneOriginValue()),
1619 nullptr, message, JS::NothingHandleValue, &err)) {
1620 return;
1623 MOZ_ASSERT(err.isObject());
1624 retVal = &err.toObject();
1627 if (aStack && !JS_WrapObject(cx, &retVal)) {
1628 return;
1631 cleanup.release();
1632 aRetVal.set(retVal);
1635 /* static */
1636 already_AddRefed<Promise> ChromeUtils::RequestIOActivity(GlobalObject& aGlobal,
1637 ErrorResult& aRv) {
1638 MOZ_ASSERT(XRE_IsParentProcess());
1639 MOZ_ASSERT(Preferences::GetBool(IO_ACTIVITY_ENABLED_PREF, false));
1640 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
1641 MOZ_ASSERT(global);
1642 RefPtr<Promise> domPromise = Promise::Create(global, aRv);
1643 if (NS_WARN_IF(aRv.Failed())) {
1644 return nullptr;
1646 MOZ_ASSERT(domPromise);
1647 mozilla::net::IOActivityMonitor::RequestActivities(domPromise);
1648 return domPromise.forget();
1651 /* static */
1652 bool ChromeUtils::HasReportingHeaderForOrigin(GlobalObject& global,
1653 const nsAString& aOrigin,
1654 ErrorResult& aRv) {
1655 if (!XRE_IsParentProcess()) {
1656 aRv.Throw(NS_ERROR_FAILURE);
1657 return false;
1660 return ReportingHeader::HasReportingHeaderForOrigin(
1661 NS_ConvertUTF16toUTF8(aOrigin));
1664 /* static */
1665 PopupBlockerState ChromeUtils::GetPopupControlState(GlobalObject& aGlobal) {
1666 switch (PopupBlocker::GetPopupControlState()) {
1667 case PopupBlocker::PopupControlState::openAllowed:
1668 return PopupBlockerState::OpenAllowed;
1670 case PopupBlocker::PopupControlState::openControlled:
1671 return PopupBlockerState::OpenControlled;
1673 case PopupBlocker::PopupControlState::openBlocked:
1674 return PopupBlockerState::OpenBlocked;
1676 case PopupBlocker::PopupControlState::openAbused:
1677 return PopupBlockerState::OpenAbused;
1679 case PopupBlocker::PopupControlState::openOverridden:
1680 return PopupBlockerState::OpenOverridden;
1682 default:
1683 MOZ_CRASH(
1684 "PopupBlocker::PopupControlState and PopupBlockerState are out of "
1685 "sync");
1689 /* static */
1690 double ChromeUtils::LastExternalProtocolIframeAllowed(GlobalObject& aGlobal) {
1691 TimeStamp when = PopupBlocker::WhenLastExternalProtocolIframeAllowed();
1692 if (when.IsNull()) {
1693 return 0;
1696 TimeDuration duration = TimeStamp::Now() - when;
1697 return duration.ToMilliseconds();
1700 /* static */
1701 void ChromeUtils::ResetLastExternalProtocolIframeAllowed(
1702 GlobalObject& aGlobal) {
1703 PopupBlocker::ResetLastExternalProtocolIframeAllowed();
1706 /* static */
1707 void ChromeUtils::EndWheelTransaction(GlobalObject& aGlobal) {
1708 // This allows us to end the current wheel transaction from the browser
1709 // chrome. We do not need to perform any checks before calling
1710 // EndTransaction(), as it should do nothing in the case that there is
1711 // no current wheel transaction.
1712 WheelTransaction::EndTransaction();
1715 /* static */
1716 void ChromeUtils::RegisterWindowActor(const GlobalObject& aGlobal,
1717 const nsACString& aName,
1718 const WindowActorOptions& aOptions,
1719 ErrorResult& aRv) {
1720 MOZ_ASSERT(XRE_IsParentProcess());
1722 RefPtr<JSActorService> service = JSActorService::GetSingleton();
1723 service->RegisterWindowActor(aName, aOptions, aRv);
1726 /* static */
1727 void ChromeUtils::UnregisterWindowActor(const GlobalObject& aGlobal,
1728 const nsACString& aName) {
1729 MOZ_ASSERT(XRE_IsParentProcess());
1731 RefPtr<JSActorService> service = JSActorService::GetSingleton();
1732 service->UnregisterWindowActor(aName);
1735 /* static */
1736 void ChromeUtils::RegisterProcessActor(const GlobalObject& aGlobal,
1737 const nsACString& aName,
1738 const ProcessActorOptions& aOptions,
1739 ErrorResult& aRv) {
1740 MOZ_ASSERT(XRE_IsParentProcess());
1742 RefPtr<JSActorService> service = JSActorService::GetSingleton();
1743 service->RegisterProcessActor(aName, aOptions, aRv);
1746 /* static */
1747 void ChromeUtils::UnregisterProcessActor(const GlobalObject& aGlobal,
1748 const nsACString& aName) {
1749 MOZ_ASSERT(XRE_IsParentProcess());
1751 RefPtr<JSActorService> service = JSActorService::GetSingleton();
1752 service->UnregisterProcessActor(aName);
1755 /* static */
1756 bool ChromeUtils::IsClassifierBlockingErrorCode(GlobalObject& aGlobal,
1757 uint32_t aError) {
1758 return net::UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode(
1759 static_cast<nsresult>(aError));
1762 /* static */
1763 void ChromeUtils::PrivateNoteIntentionalCrash(const GlobalObject& aGlobal,
1764 ErrorResult& aError) {
1765 if (XRE_IsContentProcess()) {
1766 NoteIntentionalCrash("tab");
1767 return;
1769 aError.Throw(NS_ERROR_NOT_IMPLEMENTED);
1772 /* static */
1773 nsIDOMProcessChild* ChromeUtils::GetDomProcessChild(const GlobalObject&) {
1774 return nsIDOMProcessChild::GetSingleton();
1777 /* static */
1778 void ChromeUtils::GetAllDOMProcesses(
1779 GlobalObject& aGlobal, nsTArray<RefPtr<nsIDOMProcessParent>>& aParents,
1780 ErrorResult& aRv) {
1781 if (!XRE_IsParentProcess()) {
1782 aRv.ThrowNotAllowedError(
1783 "getAllDOMProcesses() may only be called in the parent process");
1784 return;
1786 aParents.Clear();
1787 // Always add the parent process nsIDOMProcessParent first
1788 aParents.AppendElement(InProcessParent::Singleton());
1790 // Before adding nsIDOMProcessParent for all the content processes
1791 for (auto* cp : ContentParent::AllProcesses(ContentParent::eLive)) {
1792 aParents.AppendElement(cp);
1796 /* static */
1797 void ChromeUtils::ConsumeInteractionData(
1798 GlobalObject& aGlobal, Record<nsString, InteractionData>& aInteractions,
1799 ErrorResult& aRv) {
1800 if (!XRE_IsParentProcess()) {
1801 aRv.ThrowNotAllowedError(
1802 "consumeInteractionData() may only be called in the parent "
1803 "process");
1804 return;
1806 EventStateManager::ConsumeInteractionData(aInteractions);
1809 already_AddRefed<Promise> ChromeUtils::CollectScrollingData(
1810 GlobalObject& aGlobal, ErrorResult& aRv) {
1811 // Creating a JS promise
1812 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
1813 MOZ_ASSERT(global);
1815 RefPtr<Promise> promise = Promise::Create(global, aRv);
1816 if (aRv.Failed()) {
1817 return nullptr;
1820 RefPtr<ScrollingMetrics::ScrollingMetricsPromise> extPromise =
1821 ScrollingMetrics::CollectScrollingMetrics();
1823 extPromise->Then(
1824 GetCurrentSerialEventTarget(), __func__,
1825 [promise](const std::tuple<uint32_t, uint32_t>& aResult) {
1826 InteractionData out = {};
1827 out.mInteractionTimeInMilliseconds = std::get<0>(aResult);
1828 out.mScrollingDistanceInPixels = std::get<1>(aResult);
1829 promise->MaybeResolve(out);
1831 [promise](bool aValue) { promise->MaybeReject(NS_ERROR_FAILURE); });
1833 return promise.forget();
1836 /* static */
1837 void ChromeUtils::GetFormAutofillConfidences(
1838 GlobalObject& aGlobal, const Sequence<OwningNonNull<Element>>& aElements,
1839 nsTArray<FormAutofillConfidences>& aResults, ErrorResult& aRv) {
1840 FormAutofillNative::GetFormAutofillConfidences(aGlobal, aElements, aResults,
1841 aRv);
1844 bool ChromeUtils::IsDarkBackground(GlobalObject&, Element& aElement) {
1845 nsIFrame* f = aElement.GetPrimaryFrame(FlushType::Frames);
1846 if (!f) {
1847 return false;
1849 return nsNativeTheme::IsDarkBackground(f);
1852 double ChromeUtils::DateNow(GlobalObject&) { return JS_Now() / 1000.0; }
1854 /* static */
1855 void ChromeUtils::EnsureJSOracleStarted(GlobalObject&) {
1856 if (StaticPrefs::browser_opaqueResponseBlocking_javascriptValidator()) {
1857 JSOracleParent::WithJSOracle([](JSOracleParent* aParent) {});
1861 /* static */
1862 unsigned ChromeUtils::AliveUtilityProcesses(const GlobalObject&) {
1863 const auto& utilityProcessManager =
1864 mozilla::ipc::UtilityProcessManager::GetIfExists();
1865 return utilityProcessManager ? utilityProcessManager->AliveProcesses() : 0;
1868 /* static */
1869 void ChromeUtils::GetAllPossibleUtilityActorNames(GlobalObject& aGlobal,
1870 nsTArray<nsCString>& aNames) {
1871 aNames.Clear();
1872 for (size_t i = 0; i < WebIDLUtilityActorNameValues::Count; ++i) {
1873 auto idlName = static_cast<UtilityActorName>(i);
1874 aNames.AppendElement(WebIDLUtilityActorNameValues::GetString(idlName));
1878 /* static */
1879 bool ChromeUtils::ShouldResistFingerprinting(GlobalObject& aGlobal,
1880 JSRFPTarget aTarget) {
1881 RFPTarget target;
1882 switch (aTarget) {
1883 case JSRFPTarget::RoundWindowSize:
1884 target = RFPTarget::RoundWindowSize;
1885 break;
1886 case JSRFPTarget::SiteSpecificZoom:
1887 target = RFPTarget::SiteSpecificZoom;
1888 break;
1889 default:
1890 MOZ_CRASH("Unhandled JSRFPTarget enum value");
1893 return nsRFPService::IsRFPEnabledFor(target);
1896 std::atomic<uint32_t> ChromeUtils::sDevToolsOpenedCount = 0;
1898 /* static */
1899 bool ChromeUtils::IsDevToolsOpened() {
1900 return ChromeUtils::sDevToolsOpenedCount > 0;
1903 /* static */
1904 bool ChromeUtils::IsDevToolsOpened(GlobalObject& aGlobal) {
1905 return ChromeUtils::IsDevToolsOpened();
1908 /* static */
1909 void ChromeUtils::NotifyDevToolsOpened(GlobalObject& aGlobal) {
1910 ChromeUtils::sDevToolsOpenedCount++;
1913 /* static */
1914 void ChromeUtils::NotifyDevToolsClosed(GlobalObject& aGlobal) {
1915 MOZ_ASSERT(ChromeUtils::sDevToolsOpenedCount >= 1);
1916 ChromeUtils::sDevToolsOpenedCount--;
1919 } // namespace mozilla::dom