tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ChromeUtils.cpp (92852B)


      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/. */
      6 
      7 #include "ChromeUtils.h"
      8 
      9 #include "JSOracleParent.h"
     10 #include "ThirdPartyUtil.h"
     11 #include "VsyncSource.h"
     12 #include "WrapperFactory.h"
     13 #include "imgLoader.h"
     14 #include "js/CallAndConstruct.h"  // JS::Call
     15 #include "js/CharacterEncoding.h"
     16 #include "js/ColumnNumber.h"  // JS::TaggedColumnNumberOneOrigin, JS::ColumnNumberOneOrigin
     17 #include "js/Date.h"                // JS::IsISOStyleDate
     18 #include "js/Object.h"              // JS::GetClass
     19 #include "js/PropertyAndElement.h"  // JS_DefineProperty, JS_DefinePropertyById, JS_Enumerate, JS_GetProperty, JS_GetPropertyById, JS_SetProperty, JS_SetPropertyById, JS::IdVector
     20 #include "js/PropertyDescriptor.h"  // JS::PropertyDescriptor, JS_GetOwnPropertyDescriptorById
     21 #include "js/SavedFrameAPI.h"
     22 #include "js/Value.h"  // JS::Value, JS::StringValue
     23 #include "jsfriendapi.h"
     24 #include "mozJSModuleLoader.h"
     25 #include "mozilla/Base64.h"
     26 #include "mozilla/ControllerCommand.h"
     27 #include "mozilla/CycleCollectedJSRuntime.h"
     28 #include "mozilla/ErrorNames.h"
     29 #include "mozilla/EventStateManager.h"
     30 #include "mozilla/FormAutofillNative.h"
     31 #include "mozilla/IntentionalCrash.h"
     32 #include "mozilla/KeySystemConfig.h"
     33 #include "mozilla/PerfStats.h"
     34 #include "mozilla/Preferences.h"
     35 #include "mozilla/ProcInfo.h"
     36 #include "mozilla/ProfilerLabels.h"
     37 #include "mozilla/ProfilerMarkers.h"
     38 #include "mozilla/RemoteMediaManagerChild.h"
     39 #include "mozilla/ScopeExit.h"
     40 #include "mozilla/ScrollingMetrics.h"
     41 #include "mozilla/SharedStyleSheetCache.h"
     42 #include "mozilla/SpinEventLoopUntil.h"
     43 #include "mozilla/TimeStamp.h"
     44 #include "mozilla/WheelHandlingHelper.h"
     45 #include "mozilla/dom/ContentParent.h"
     46 #include "mozilla/dom/IdleDeadline.h"
     47 #include "mozilla/dom/InProcessParent.h"
     48 #include "mozilla/dom/JSActorService.h"
     49 #include "mozilla/dom/MediaSessionBinding.h"
     50 #include "mozilla/dom/PBrowserParent.h"
     51 #include "mozilla/dom/PopupBlocker.h"
     52 #include "mozilla/dom/Promise.h"
     53 #include "mozilla/dom/Record.h"
     54 #include "mozilla/dom/ReportingHeader.h"
     55 #include "mozilla/dom/SharedScriptCache.h"
     56 #include "mozilla/dom/UnionTypes.h"
     57 #include "mozilla/dom/WindowBinding.h"  // For IdleRequestCallback/Options
     58 #include "mozilla/dom/WindowGlobalParent.h"
     59 #include "mozilla/dom/WorkerScope.h"
     60 #include "mozilla/dom/quota/QuotaManager.h"
     61 #include "mozilla/image/FetchDecodedImage.h"
     62 #include "mozilla/ipc/GeckoChildProcessHost.h"
     63 #include "mozilla/ipc/UtilityProcessHost.h"
     64 #include "mozilla/ipc/UtilityProcessManager.h"
     65 #include "mozilla/ipc/UtilityProcessSandboxing.h"
     66 #include "mozilla/layers/WebRenderBridgeChild.h"
     67 #include "mozilla/layers/WebRenderLayerManager.h"
     68 #include "mozilla/net/UrlClassifierFeatureFactory.h"
     69 #include "nsContentUtils.h"
     70 #include "nsControllerCommandTable.h"
     71 #include "nsDocShell.h"
     72 #include "nsIException.h"
     73 #include "nsIRFPTargetSetIDL.h"
     74 #include "nsIWidget.h"
     75 #include "nsNativeTheme.h"
     76 #include "nsRFPTargetSetIDL.h"
     77 #include "nsString.h"
     78 #include "nsThreadUtils.h"
     79 
     80 #ifdef XP_UNIX
     81 #  include <errno.h>
     82 #  include <fcntl.h>
     83 #  include <poll.h>
     84 #  include <sys/wait.h>
     85 #  include <unistd.h>
     86 
     87 #  ifdef XP_LINUX
     88 #    include <sys/prctl.h>
     89 #  endif
     90 #endif
     91 
     92 #ifdef MOZ_WMF_CDM
     93 #  include "mozilla/MFCDMParent.h"
     94 #endif
     95 
     96 #ifdef MOZ_WIDGET_ANDROID
     97 #  include "mozilla/java/GeckoAppShellWrappers.h"
     98 #endif
     99 
    100 namespace mozilla::dom {
    101 
    102 // Setup logging
    103 extern mozilla::LazyLogModule gMlsLog;
    104 
    105 /* static */
    106 void ChromeUtils::NondeterministicGetWeakMapKeys(
    107    GlobalObject& aGlobal, JS::Handle<JS::Value> aMap,
    108    JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv) {
    109  if (!aMap.isObject()) {
    110    aRetval.setUndefined();
    111  } else {
    112    JSContext* cx = aGlobal.Context();
    113    JS::Rooted<JSObject*> objRet(cx);
    114    JS::Rooted<JSObject*> mapObj(cx, &aMap.toObject());
    115    if (!JS_NondeterministicGetWeakMapKeys(cx, mapObj, &objRet)) {
    116      aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
    117    } else {
    118      aRetval.set(objRet ? JS::ObjectValue(*objRet) : JS::UndefinedValue());
    119    }
    120  }
    121 }
    122 
    123 /* static */
    124 void ChromeUtils::NondeterministicGetWeakSetKeys(
    125    GlobalObject& aGlobal, JS::Handle<JS::Value> aSet,
    126    JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv) {
    127  if (!aSet.isObject()) {
    128    aRetval.setUndefined();
    129  } else {
    130    JSContext* cx = aGlobal.Context();
    131    JS::Rooted<JSObject*> objRet(cx);
    132    JS::Rooted<JSObject*> setObj(cx, &aSet.toObject());
    133    if (!JS_NondeterministicGetWeakSetKeys(cx, setObj, &objRet)) {
    134      aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
    135    } else {
    136      aRetval.set(objRet ? JS::ObjectValue(*objRet) : JS::UndefinedValue());
    137    }
    138  }
    139 }
    140 
    141 /* static */
    142 void ChromeUtils::Base64URLEncode(GlobalObject& aGlobal,
    143                                  const ArrayBufferViewOrArrayBuffer& aSource,
    144                                  const Base64URLEncodeOptions& aOptions,
    145                                  nsACString& aResult, ErrorResult& aRv) {
    146  auto paddingPolicy = aOptions.mPad ? Base64URLEncodePaddingPolicy::Include
    147                                     : Base64URLEncodePaddingPolicy::Omit;
    148  ProcessTypedArrays(
    149      aSource, [&](const Span<uint8_t>& aData, JS::AutoCheckCannotGC&&) {
    150        nsresult rv = mozilla::Base64URLEncode(aData.Length(), aData.Elements(),
    151                                               paddingPolicy, aResult);
    152        if (NS_WARN_IF(NS_FAILED(rv))) {
    153          aResult.Truncate();
    154          aRv.Throw(rv);
    155        }
    156      });
    157 }
    158 
    159 /* static */
    160 void ChromeUtils::Base64URLDecode(GlobalObject& aGlobal,
    161                                  const nsACString& aString,
    162                                  const Base64URLDecodeOptions& aOptions,
    163                                  JS::MutableHandle<JSObject*> aRetval,
    164                                  ErrorResult& aRv) {
    165  Base64URLDecodePaddingPolicy paddingPolicy;
    166  switch (aOptions.mPadding) {
    167    case Base64URLDecodePadding::Require:
    168      paddingPolicy = Base64URLDecodePaddingPolicy::Require;
    169      break;
    170 
    171    case Base64URLDecodePadding::Ignore:
    172      paddingPolicy = Base64URLDecodePaddingPolicy::Ignore;
    173      break;
    174 
    175    case Base64URLDecodePadding::Reject:
    176      paddingPolicy = Base64URLDecodePaddingPolicy::Reject;
    177      break;
    178 
    179    default:
    180      aRv.Throw(NS_ERROR_INVALID_ARG);
    181      return;
    182  }
    183  FallibleTArray<uint8_t> data;
    184  nsresult rv = mozilla::Base64URLDecode(aString, paddingPolicy, data);
    185  if (NS_WARN_IF(NS_FAILED(rv))) {
    186    aRv.Throw(rv);
    187    return;
    188  }
    189 
    190  JS::Rooted<JSObject*> buffer(
    191      aGlobal.Context(), ArrayBuffer::Create(aGlobal.Context(), data, aRv));
    192  if (aRv.Failed()) {
    193    return;
    194  }
    195  aRetval.set(buffer);
    196 }
    197 
    198 /* static */
    199 void ChromeUtils::ReleaseAssert(GlobalObject& aGlobal, bool aCondition,
    200                                const nsAString& aMessage) {
    201  // If the condition didn't fail, which is the likely case, immediately return.
    202  if (MOZ_LIKELY(aCondition)) {
    203    return;
    204  }
    205 
    206  // Extract the current stack from the JS runtime to embed in the crash reason.
    207  nsAutoCString filename;
    208  uint32_t lineNo = 0;
    209 
    210  if (nsCOMPtr<nsIStackFrame> location = GetCurrentJSStack(1)) {
    211    location->GetFilename(aGlobal.Context(), filename);
    212    lineNo = location->GetLineNumber(aGlobal.Context());
    213  } else {
    214    filename.Assign("<unknown>"_ns);
    215  }
    216 
    217  // Convert to utf-8 for adding as the MozCrashReason.
    218  NS_ConvertUTF16toUTF8 messageUtf8(aMessage);
    219 
    220  // Actually crash.
    221  MOZ_CRASH_UNSAFE_PRINTF("Failed ChromeUtils.releaseAssert(\"%s\") @ %s:%u",
    222                          messageUtf8.get(), filename.get(), lineNo);
    223 }
    224 
    225 /* static */
    226 void ChromeUtils::AddProfilerMarker(
    227    GlobalObject& aGlobal, const nsACString& aName,
    228    const ProfilerMarkerOptionsOrDouble& aOptions,
    229    const Optional<nsACString>& aText) {
    230  if (!profiler_thread_is_being_profiled_for_markers()) {
    231    return;
    232  }
    233 
    234  MarkerOptions options;
    235 
    236  MarkerCategory category = ::geckoprofiler::category::JS;
    237 
    238  DOMHighResTimeStamp startTime = 0;
    239  uint64_t innerWindowId = 0;
    240  if (aOptions.IsDouble()) {
    241    startTime = aOptions.GetAsDouble();
    242  } else {
    243    const ProfilerMarkerOptions& opt = aOptions.GetAsProfilerMarkerOptions();
    244    startTime = opt.mStartTime;
    245    innerWindowId = opt.mInnerWindowId;
    246 
    247    if (opt.mCaptureStack) {
    248      // If we will be capturing a stack, change the category of the
    249      // ChromeUtils.addProfilerMarker label automatically added by the webidl
    250      // binding from DOM to PROFILER so that this function doesn't appear in
    251      // the marker stack.
    252      JSContext* cx = aGlobal.Context();
    253      ProfilingStack* stack = js::GetContextProfilingStackIfEnabled(cx);
    254      if (MOZ_LIKELY(stack)) {
    255        uint32_t sp = stack->stackPointer;
    256        if (MOZ_LIKELY(sp > 0)) {
    257          js::ProfilingStackFrame& frame = stack->frames[sp - 1];
    258          if (frame.isLabelFrame() && "ChromeUtils"_ns.Equals(frame.label()) &&
    259              "addProfilerMarker"_ns.Equals(frame.dynamicString())) {
    260            frame.setLabelCategory(JS::ProfilingCategoryPair::PROFILER);
    261          }
    262        }
    263      }
    264 
    265      options.Set(MarkerStack::Capture());
    266    }
    267 #define BEGIN_CATEGORY(name, labelAsString, color) \
    268  if (opt.mCategory.Equals(labelAsString)) {       \
    269    category = ::geckoprofiler::category::name;    \
    270  } else
    271 #define SUBCATEGORY(supercategory, name, labelAsString)
    272 #define END_CATEGORY
    273    MOZ_PROFILING_CATEGORY_LIST(BEGIN_CATEGORY, SUBCATEGORY, END_CATEGORY)
    274 #undef BEGIN_CATEGORY
    275 #undef SUBCATEGORY
    276 #undef END_CATEGORY
    277    {
    278      category = ::geckoprofiler::category::OTHER;
    279    }
    280  }
    281  if (startTime) {
    282    options.Set(MarkerTiming::IntervalUntilNowFrom(
    283        TimeStamp::ProcessCreation() +
    284        TimeDuration::FromMilliseconds(startTime)));
    285  }
    286 
    287  if (innerWindowId) {
    288    options.Set(MarkerInnerWindowId(innerWindowId));
    289  } else {
    290    options.Set(MarkerInnerWindowIdFromJSContext(aGlobal.Context()));
    291  }
    292 
    293  {
    294    AUTO_PROFILER_STATS(ChromeUtils_AddProfilerMarker);
    295    if (aText.WasPassed()) {
    296      profiler_add_marker(aName, category, std::move(options),
    297                          ::geckoprofiler::markers::TextMarker{},
    298                          aText.Value());
    299    } else {
    300      profiler_add_marker(aName, category, std::move(options));
    301    }
    302  }
    303 }
    304 
    305 /* static */
    306 void ChromeUtils::GetXPCOMErrorName(GlobalObject& aGlobal, uint32_t aErrorCode,
    307                                    nsACString& aRetval) {
    308  GetErrorName((nsresult)aErrorCode, aRetval);
    309 }
    310 
    311 /* static */
    312 void ChromeUtils::WaiveXrays(GlobalObject& aGlobal, JS::Handle<JS::Value> aVal,
    313                             JS::MutableHandle<JS::Value> aRetval,
    314                             ErrorResult& aRv) {
    315  JS::Rooted<JS::Value> value(aGlobal.Context(), aVal);
    316  if (!xpc::WrapperFactory::WaiveXrayAndWrap(aGlobal.Context(), &value)) {
    317    aRv.NoteJSContextException(aGlobal.Context());
    318  } else {
    319    aRetval.set(value);
    320  }
    321 }
    322 
    323 /* static */
    324 void ChromeUtils::UnwaiveXrays(GlobalObject& aGlobal,
    325                               JS::Handle<JS::Value> aVal,
    326                               JS::MutableHandle<JS::Value> aRetval,
    327                               ErrorResult& aRv) {
    328  if (!aVal.isObject()) {
    329    aRetval.set(aVal);
    330    return;
    331  }
    332 
    333  JS::Rooted<JSObject*> obj(aGlobal.Context(),
    334                            js::UncheckedUnwrap(&aVal.toObject()));
    335  if (!JS_WrapObject(aGlobal.Context(), &obj)) {
    336    aRv.NoteJSContextException(aGlobal.Context());
    337  } else {
    338    aRetval.setObject(*obj);
    339  }
    340 }
    341 
    342 /* static */
    343 void ChromeUtils::GetClassName(GlobalObject& aGlobal,
    344                               JS::Handle<JSObject*> aObj, bool aUnwrap,
    345                               nsAString& aRetval) {
    346  JS::Rooted<JSObject*> obj(aGlobal.Context(), aObj);
    347  if (aUnwrap) {
    348    obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
    349  }
    350 
    351  aRetval = NS_ConvertUTF8toUTF16(nsDependentCString(JS::GetClass(obj)->name));
    352 }
    353 
    354 /* static */
    355 bool ChromeUtils::IsDOMObject(GlobalObject& aGlobal, JS::Handle<JSObject*> aObj,
    356                              bool aUnwrap) {
    357  JS::Rooted<JSObject*> obj(aGlobal.Context(), aObj);
    358  if (aUnwrap) {
    359    obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
    360  }
    361 
    362  return mozilla::dom::IsDOMObject(obj);
    363 }
    364 
    365 /* static */
    366 bool ChromeUtils::IsISOStyleDate(GlobalObject& aGlobal,
    367                                 const nsACString& aStr) {
    368  // aStr is a UTF-8 string, however we can cast to JS::Latin1Chars
    369  // because JS::IsISOStyleDate handles ASCII only
    370  return JS::IsISOStyleDate(aGlobal.Context(),
    371                            JS::Latin1Chars(aStr.Data(), aStr.Length()));
    372 }
    373 
    374 /* static */
    375 void ChromeUtils::ShallowClone(GlobalObject& aGlobal,
    376                               JS::Handle<JSObject*> aObj,
    377                               JS::Handle<JSObject*> aTarget,
    378                               JS::MutableHandle<JSObject*> aRetval,
    379                               ErrorResult& aRv) {
    380  JSContext* cx = aGlobal.Context();
    381 
    382  auto cleanup = MakeScopeExit([&]() { aRv.NoteJSContextException(cx); });
    383 
    384  JS::Rooted<JS::IdVector> ids(cx, JS::IdVector(cx));
    385  JS::RootedVector<JS::Value> values(cx);
    386  JS::RootedVector<jsid> valuesIds(cx);
    387 
    388  {
    389    // cx represents our current Realm, so it makes sense to use it for the
    390    // CheckedUnwrapDynamic call.  We do want CheckedUnwrapDynamic, in case
    391    // someone is shallow-cloning a Window.
    392    JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrapDynamic(aObj, cx));
    393    if (!obj) {
    394      js::ReportAccessDenied(cx);
    395      return;
    396    }
    397 
    398    if (js::IsScriptedProxy(obj)) {
    399      JS_ReportErrorASCII(cx, "Shallow cloning a proxy object is not allowed");
    400      return;
    401    }
    402 
    403    JSAutoRealm ar(cx, obj);
    404 
    405    if (!JS_Enumerate(cx, obj, &ids) || !values.reserve(ids.length()) ||
    406        !valuesIds.reserve(ids.length())) {
    407      return;
    408    }
    409 
    410    JS::Rooted<Maybe<JS::PropertyDescriptor>> desc(cx);
    411    JS::Rooted<JS::PropertyKey> id(cx);
    412    for (jsid idVal : ids) {
    413      id = idVal;
    414      if (!JS_GetOwnPropertyDescriptorById(cx, obj, id, &desc)) {
    415        continue;
    416      }
    417      if (desc.isNothing() || desc->isAccessorDescriptor()) {
    418        continue;
    419      }
    420      valuesIds.infallibleAppend(id);
    421      values.infallibleAppend(desc->value());
    422    }
    423  }
    424 
    425  JS::Rooted<JSObject*> obj(cx);
    426  {
    427    Maybe<JSAutoRealm> ar;
    428    if (aTarget) {
    429      // Our target could be anything, so we want CheckedUnwrapDynamic here.
    430      // "cx" represents the current Realm when we were called from bindings, so
    431      // we can just use that.
    432      JS::Rooted<JSObject*> target(cx, js::CheckedUnwrapDynamic(aTarget, cx));
    433      if (!target) {
    434        js::ReportAccessDenied(cx);
    435        return;
    436      }
    437      ar.emplace(cx, target);
    438    }
    439 
    440    obj = JS_NewPlainObject(cx);
    441    if (!obj) {
    442      return;
    443    }
    444 
    445    JS::Rooted<JS::Value> value(cx);
    446    JS::Rooted<JS::PropertyKey> id(cx);
    447    for (uint32_t i = 0; i < valuesIds.length(); i++) {
    448      id = valuesIds[i];
    449      value = values[i];
    450 
    451      JS_MarkCrossZoneId(cx, id);
    452      if (!JS_WrapValue(cx, &value) ||
    453          !JS_SetPropertyById(cx, obj, id, value)) {
    454        return;
    455      }
    456    }
    457  }
    458 
    459  if (aTarget && !JS_WrapObject(cx, &obj)) {
    460    return;
    461  }
    462 
    463  cleanup.release();
    464  aRetval.set(obj);
    465 }
    466 
    467 namespace {
    468 class IdleDispatchRunnable final : public IdleRunnable,
    469                                   public nsITimerCallback {
    470 public:
    471  NS_DECL_ISUPPORTS_INHERITED
    472 
    473  IdleDispatchRunnable(nsIGlobalObject* aParent, IdleRequestCallback& aCallback)
    474      : IdleRunnable("ChromeUtils::IdleDispatch"),
    475        mCallback(&aCallback),
    476        mParent(aParent) {}
    477 
    478  // MOZ_CAN_RUN_SCRIPT_BOUNDARY until Runnable::Run is MOZ_CAN_RUN_SCRIPT.
    479  // See bug 1535398.
    480  MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override {
    481    if (mCallback) {
    482      CancelTimer();
    483 
    484      auto deadline = mDeadline - TimeStamp::ProcessCreation();
    485 
    486      ErrorResult rv;
    487      RefPtr<IdleDeadline> idleDeadline =
    488          new IdleDeadline(mParent, mTimedOut, deadline.ToMilliseconds());
    489 
    490      RefPtr<IdleRequestCallback> callback(std::move(mCallback));
    491      MOZ_ASSERT(!mCallback);
    492      callback->Call(*idleDeadline, "ChromeUtils::IdleDispatch handler");
    493      mParent = nullptr;
    494    }
    495    return NS_OK;
    496  }
    497 
    498  void SetDeadline(TimeStamp aDeadline) override { mDeadline = aDeadline; }
    499 
    500  NS_IMETHOD Notify(nsITimer* aTimer) override {
    501    mTimedOut = true;
    502    SetDeadline(TimeStamp::Now());
    503    return Run();
    504  }
    505 
    506  void SetTimer(uint32_t aDelay, nsIEventTarget* aTarget) override {
    507    MOZ_ASSERT(aTarget);
    508    MOZ_ASSERT(!mTimer);
    509    NS_NewTimerWithCallback(getter_AddRefs(mTimer), this, aDelay,
    510                            nsITimer::TYPE_ONE_SHOT, aTarget);
    511  }
    512 
    513 protected:
    514  virtual ~IdleDispatchRunnable() { CancelTimer(); }
    515 
    516 private:
    517  void CancelTimer() {
    518    if (mTimer) {
    519      mTimer->Cancel();
    520      mTimer = nullptr;
    521    }
    522  }
    523 
    524  RefPtr<IdleRequestCallback> mCallback;
    525  nsCOMPtr<nsIGlobalObject> mParent;
    526 
    527  nsCOMPtr<nsITimer> mTimer;
    528 
    529  TimeStamp mDeadline{};
    530  bool mTimedOut = false;
    531 };
    532 
    533 NS_IMPL_ISUPPORTS_INHERITED(IdleDispatchRunnable, IdleRunnable,
    534                            nsITimerCallback)
    535 }  // anonymous namespace
    536 
    537 /* static */
    538 void ChromeUtils::IdleDispatch(const GlobalObject& aGlobal,
    539                               IdleRequestCallback& aCallback,
    540                               const IdleRequestOptions& aOptions,
    541                               ErrorResult& aRv) {
    542  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
    543  MOZ_ASSERT(global);
    544 
    545  auto runnable = MakeRefPtr<IdleDispatchRunnable>(global, aCallback);
    546 
    547  if (aOptions.mTimeout.WasPassed()) {
    548    aRv = NS_DispatchToCurrentThreadQueue(
    549        runnable.forget(), aOptions.mTimeout.Value(), EventQueuePriority::Idle);
    550  } else {
    551    aRv = NS_DispatchToCurrentThreadQueue(runnable.forget(),
    552                                          EventQueuePriority::Idle);
    553  }
    554 }
    555 
    556 static mozJSModuleLoader* GetModuleLoaderForCurrentGlobal(
    557    JSContext* aCx, const GlobalObject& aGlobal,
    558    Maybe<loader::NonSharedGlobalSyncModuleLoaderScope>&
    559        aMaybeSyncLoaderScope) {
    560  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
    561 
    562  if (mozJSModuleLoader::IsSharedSystemGlobal(global)) {
    563    return mozJSModuleLoader::Get();
    564  }
    565  if (mozJSModuleLoader::IsDevToolsLoaderGlobal(global)) {
    566    return mozJSModuleLoader::GetOrCreateDevToolsLoader(aCx);
    567  }
    568 
    569  if (loader::NonSharedGlobalSyncModuleLoaderScope::IsActive()) {
    570    mozJSModuleLoader* moduleloader =
    571        loader::NonSharedGlobalSyncModuleLoaderScope::ActiveLoader();
    572 
    573    if (!moduleloader->IsLoaderGlobal(global->GetGlobalJSObject())) {
    574      JS_ReportErrorASCII(aCx,
    575                          "global: \"current\" option cannot be used for "
    576                          "different global while other importESModule "
    577                          "with global: \"current\" is on the stack");
    578      return nullptr;
    579    }
    580 
    581    return moduleloader;
    582  }
    583 
    584  RefPtr targetModuleLoader = global->GetModuleLoader(aCx);
    585  if (!targetModuleLoader) {
    586    // Sandbox without associated window returns nullptr for GetModuleLoader.
    587    JS_ReportErrorASCII(aCx, "No ModuleLoader found for the current context");
    588    return nullptr;
    589  }
    590 
    591  if (targetModuleLoader->HasFetchingModules()) {
    592    if (!NS_IsMainThread()) {
    593      JS_ReportErrorASCII(aCx,
    594                          "ChromeUtils.importESModule cannot be used in worker "
    595                          "when there is ongoing dynamic import");
    596      return nullptr;
    597    }
    598 
    599    if (!mozilla::SpinEventLoopUntil(
    600            "importESModule for current global"_ns, [&]() -> bool {
    601              return !targetModuleLoader->HasFetchingModules();
    602            })) {
    603      JS_ReportErrorASCII(aCx, "Failed to wait for ongoing module requests");
    604      return nullptr;
    605    }
    606  }
    607 
    608  aMaybeSyncLoaderScope.emplace(aCx, global);
    609  return aMaybeSyncLoaderScope->ActiveLoader();
    610 }
    611 
    612 static mozJSModuleLoader* GetModuleLoaderForOptions(
    613    JSContext* aCx, const GlobalObject& aGlobal,
    614    const ImportESModuleOptionsDictionary& aOptions,
    615    Maybe<loader::NonSharedGlobalSyncModuleLoaderScope>&
    616        aMaybeSyncLoaderScope) {
    617  if (!aOptions.mGlobal.WasPassed()) {
    618    return mozJSModuleLoader::Get();
    619  }
    620 
    621  switch (aOptions.mGlobal.Value()) {
    622    case ImportESModuleTargetGlobal::Shared:
    623      return mozJSModuleLoader::Get();
    624 
    625    case ImportESModuleTargetGlobal::Devtools:
    626      return mozJSModuleLoader::GetOrCreateDevToolsLoader(aCx);
    627 
    628    case ImportESModuleTargetGlobal::Contextual: {
    629      if (!NS_IsMainThread()) {
    630        return GetModuleLoaderForCurrentGlobal(aCx, aGlobal,
    631                                               aMaybeSyncLoaderScope);
    632      }
    633 
    634      RefPtr devToolsModuleloader = mozJSModuleLoader::GetDevToolsLoader();
    635      if (devToolsModuleloader &&
    636          devToolsModuleloader->IsLoaderGlobal(aGlobal.Get())) {
    637        return mozJSModuleLoader::GetOrCreateDevToolsLoader(aCx);
    638      }
    639      return mozJSModuleLoader::Get();
    640    }
    641 
    642    case ImportESModuleTargetGlobal::Current:
    643      return GetModuleLoaderForCurrentGlobal(aCx, aGlobal,
    644                                             aMaybeSyncLoaderScope);
    645 
    646    default:
    647      MOZ_CRASH("Unknown ImportESModuleTargetGlobal");
    648  }
    649 }
    650 
    651 static bool ValidateImportOptions(
    652    JSContext* aCx, const GlobalObject& aGlobal,
    653    const ImportESModuleOptionsDictionary& aOptions) {
    654  if (!NS_IsMainThread() &&
    655      (!aOptions.mGlobal.WasPassed() ||
    656       (aOptions.mGlobal.Value() != ImportESModuleTargetGlobal::Current &&
    657        aOptions.mGlobal.Value() != ImportESModuleTargetGlobal::Contextual))) {
    658    JS_ReportErrorASCII(aCx,
    659                        "ChromeUtils.importESModule: Only { global: "
    660                        "\"current\" } and { global: \"contextual\" } options "
    661                        "are supported on worker");
    662    return false;
    663  }
    664 
    665  if (NS_IsMainThread()) {
    666    nsCOMPtr<nsIGlobalObject> global =
    667        do_QueryInterface(aGlobal.GetAsSupports());
    668 
    669    if (mozJSModuleLoader::IsDevToolsLoaderGlobal(global) &&
    670        !aOptions.mGlobal.WasPassed()) {
    671      JS_ReportErrorASCII(aCx,
    672                          "ChromeUtils.importESModule: global option is "
    673                          "required in DevTools distinct global");
    674      return false;
    675    }
    676  }
    677 
    678  return true;
    679 }
    680 
    681 /* static */
    682 void ChromeUtils::ImportESModule(
    683    const GlobalObject& aGlobal, const nsAString& aResourceURI,
    684    const ImportESModuleOptionsDictionary& aOptions,
    685    JS::MutableHandle<JSObject*> aRetval, ErrorResult& aRv) {
    686  JSContext* cx = aGlobal.Context();
    687 
    688  if (!ValidateImportOptions(cx, aGlobal, aOptions)) {
    689    aRv.Throw(NS_ERROR_FAILURE);
    690    return;
    691  }
    692 
    693  Maybe<loader::NonSharedGlobalSyncModuleLoaderScope> maybeSyncLoaderScope;
    694  RefPtr<mozJSModuleLoader> moduleloader =
    695      GetModuleLoaderForOptions(cx, aGlobal, aOptions, maybeSyncLoaderScope);
    696  if (!moduleloader) {
    697    aRv.Throw(NS_ERROR_FAILURE);
    698    return;
    699  }
    700 
    701  NS_ConvertUTF16toUTF8 registryLocation(aResourceURI);
    702 
    703  AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING_NONSENSITIVE(
    704      "ChromeUtils::ImportESModule", OTHER, registryLocation);
    705 
    706  JS::Rooted<JSObject*> moduleNamespace(cx);
    707  nsresult rv =
    708      moduleloader->ImportESModule(cx, registryLocation, &moduleNamespace);
    709  if (NS_FAILED(rv)) {
    710    aRv.Throw(rv);
    711    return;
    712  }
    713 
    714  MOZ_ASSERT(!JS_IsExceptionPending(cx));
    715 
    716  if (!JS_WrapObject(cx, &moduleNamespace)) {
    717    aRv.Throw(NS_ERROR_FAILURE);
    718    return;
    719  }
    720  aRetval.set(moduleNamespace);
    721 
    722  if (maybeSyncLoaderScope) {
    723    maybeSyncLoaderScope->Finish();
    724  }
    725 }
    726 
    727 // An integer encoding for ImportESModuleOptionsDictionary, to pass the value
    728 // to the lazy getters.
    729 class EncodedOptions {
    730 public:
    731  explicit EncodedOptions(const ImportESModuleOptionsDictionary& aOptions) {
    732    if (aOptions.mGlobal.WasPassed()) {
    733      mValue = uint32_t(aOptions.mGlobal.Value()) + 1;
    734    } else {
    735      mValue = 0;
    736    }
    737  }
    738 
    739  explicit EncodedOptions(uint32_t aValue) : mValue(aValue) {}
    740 
    741  int32_t toInt32() const { return int32_t(mValue); }
    742 
    743  void DecodeInto(ImportESModuleOptionsDictionary& aOptions) {
    744    if (mValue == 0) {
    745      aOptions.mGlobal.Reset();
    746    } else {
    747      aOptions.mGlobal.Construct(ImportESModuleTargetGlobal(mValue - 1));
    748    }
    749  }
    750 
    751 private:
    752  uint32_t mValue = 0;
    753 };
    754 
    755 namespace lazy_getter {
    756 
    757 // The property id of the getter.
    758 // Used by all lazy getters.
    759 static const size_t SLOT_ID = 0;
    760 
    761 // The URI of the module to import.
    762 // Used by ChromeUtils.defineESModuleGetters.
    763 static const size_t SLOT_URI = 1;
    764 
    765 // An array object that contians values for PARAM_INDEX_TARGET and
    766 // PARAM_INDEX_LAMBDA.
    767 // Used by ChromeUtils.defineLazyGetter.
    768 static const size_t SLOT_PARAMS = 1;
    769 
    770 // The EncodedOptions value.
    771 // Used by ChromeUtils.defineESModuleGetters.
    772 static const size_t SLOT_OPTIONS = 2;
    773 
    774 static const size_t PARAM_INDEX_TARGET = 0;
    775 static const size_t PARAM_INDEX_LAMBDA = 1;
    776 static const size_t PARAMS_COUNT = 2;
    777 
    778 static bool ExtractArgs(JSContext* aCx, JS::CallArgs& aArgs,
    779                        JS::MutableHandle<JSObject*> aCallee,
    780                        JS::MutableHandle<JSObject*> aThisObj,
    781                        JS::MutableHandle<jsid> aId) {
    782  aCallee.set(&aArgs.callee());
    783 
    784  JS::Handle<JS::Value> thisv = aArgs.thisv();
    785  if (!thisv.isObject()) {
    786    JS_ReportErrorASCII(aCx, "Invalid target object");
    787    return false;
    788  }
    789 
    790  aThisObj.set(&thisv.toObject());
    791 
    792  JS::Rooted<JS::Value> id(aCx,
    793                           js::GetFunctionNativeReserved(aCallee, SLOT_ID));
    794  MOZ_ALWAYS_TRUE(JS_ValueToId(aCx, id, aId));
    795  return true;
    796 }
    797 
    798 static bool JSLazyGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
    799  JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
    800 
    801  JS::Rooted<JSObject*> callee(aCx);
    802  JS::Rooted<JSObject*> unused(aCx);
    803  JS::Rooted<jsid> id(aCx);
    804  if (!ExtractArgs(aCx, args, &callee, &unused, &id)) {
    805    return false;
    806  }
    807 
    808  JS::Rooted<JS::Value> paramsVal(
    809      aCx, js::GetFunctionNativeReserved(callee, SLOT_PARAMS));
    810  if (paramsVal.isUndefined()) {
    811    args.rval().setUndefined();
    812    return true;
    813  }
    814  // Avoid calling the lambda multiple times, in case of:
    815  //   * the getter function is retrieved from property descriptor and called
    816  //   * the lambda gets the property again
    817  //   * the getter function throws and accessed again
    818  js::SetFunctionNativeReserved(callee, SLOT_PARAMS, JS::UndefinedHandleValue);
    819 
    820  JS::Rooted<JSObject*> paramsObj(aCx, &paramsVal.toObject());
    821 
    822  JS::Rooted<JS::Value> targetVal(aCx);
    823  JS::Rooted<JS::Value> lambdaVal(aCx);
    824  if (!JS_GetElement(aCx, paramsObj, PARAM_INDEX_TARGET, &targetVal)) {
    825    return false;
    826  }
    827  if (!JS_GetElement(aCx, paramsObj, PARAM_INDEX_LAMBDA, &lambdaVal)) {
    828    return false;
    829  }
    830 
    831  JS::Rooted<JSObject*> targetObj(aCx, &targetVal.toObject());
    832 
    833  JS::Rooted<JS::Value> value(aCx);
    834  if (!JS::Call(aCx, targetObj, lambdaVal, JS::HandleValueArray::empty(),
    835                &value)) {
    836    return false;
    837  }
    838 
    839  if (!JS_DefinePropertyById(aCx, targetObj, id, value, JSPROP_ENUMERATE)) {
    840    return false;
    841  }
    842 
    843  args.rval().set(value);
    844  return true;
    845 }
    846 
    847 static bool DefineLazyGetter(JSContext* aCx, JS::Handle<JSObject*> aTarget,
    848                             JS::Handle<JS::Value> aName,
    849                             JS::Handle<JSObject*> aLambda) {
    850  JS::Rooted<JS::PropertyKey> id(aCx);
    851  if (!JS_ValueToId(aCx, aName, &id)) {
    852    return false;
    853  }
    854 
    855  JS::Rooted<JS::PropertyKey> funId(aCx);
    856  if (id.isAtom()) {
    857    funId = id;
    858  } else {
    859    // Don't care int and symbol cases.
    860    funId = JS::PropertyKey::NonIntAtom(JS_GetEmptyString(aCx));
    861  }
    862 
    863  JS::Rooted<JSObject*> getter(
    864      aCx, JS_GetFunctionObject(js::NewFunctionByIdWithReserved(
    865               aCx, JSLazyGetter, 0, 0, funId)));
    866  if (!getter) {
    867    JS_ReportOutOfMemory(aCx);
    868    return false;
    869  }
    870 
    871  JS::RootedVector<JS::Value> params(aCx);
    872  if (!params.resize(PARAMS_COUNT)) {
    873    return false;
    874  }
    875  params[PARAM_INDEX_TARGET].setObject(*aTarget);
    876  params[PARAM_INDEX_LAMBDA].setObject(*aLambda);
    877  JS::Rooted<JSObject*> paramsObj(aCx, JS::NewArrayObject(aCx, params));
    878  if (!paramsObj) {
    879    return false;
    880  }
    881 
    882  js::SetFunctionNativeReserved(getter, SLOT_ID, aName);
    883  js::SetFunctionNativeReserved(getter, SLOT_PARAMS,
    884                                JS::ObjectValue(*paramsObj));
    885 
    886  return JS_DefinePropertyById(aCx, aTarget, id, getter, nullptr,
    887                               JSPROP_ENUMERATE);
    888 }
    889 
    890 static bool ESModuleGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
    891  JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
    892 
    893  JS::Rooted<JSObject*> callee(aCx);
    894  JS::Rooted<JSObject*> thisObj(aCx);
    895  JS::Rooted<jsid> id(aCx);
    896  if (!ExtractArgs(aCx, args, &callee, &thisObj, &id)) {
    897    return false;
    898  }
    899 
    900  JS::Rooted<JSString*> moduleURI(
    901      aCx, js::GetFunctionNativeReserved(callee, SLOT_URI).toString());
    902  JS::UniqueChars bytes = JS_EncodeStringToUTF8(aCx, moduleURI);
    903  if (!bytes) {
    904    return false;
    905  }
    906  nsDependentCString uri(bytes.get());
    907 
    908  JS::Rooted<JS::Value> value(aCx);
    909  EncodedOptions encodedOptions(
    910      js::GetFunctionNativeReserved(callee, SLOT_OPTIONS).toInt32());
    911 
    912  ImportESModuleOptionsDictionary options;
    913  encodedOptions.DecodeInto(options);
    914 
    915  GlobalObject global(aCx, callee);
    916 
    917  Maybe<loader::NonSharedGlobalSyncModuleLoaderScope> maybeSyncLoaderScope;
    918  RefPtr<mozJSModuleLoader> moduleloader =
    919      GetModuleLoaderForOptions(aCx, global, options, maybeSyncLoaderScope);
    920  if (!moduleloader) {
    921    return false;
    922  }
    923 
    924  JS::Rooted<JSObject*> moduleNamespace(aCx);
    925  nsresult rv = moduleloader->ImportESModule(aCx, uri, &moduleNamespace);
    926  if (NS_FAILED(rv)) {
    927    Throw(aCx, rv);
    928    return false;
    929  }
    930 
    931  // ESM's namespace is from the module's realm.
    932  {
    933    JSAutoRealm ar(aCx, moduleNamespace);
    934    if (!JS_GetPropertyById(aCx, moduleNamespace, id, &value)) {
    935      return false;
    936    }
    937  }
    938  if (!JS_WrapValue(aCx, &value)) {
    939    return false;
    940  }
    941 
    942  if (maybeSyncLoaderScope) {
    943    maybeSyncLoaderScope->Finish();
    944  }
    945 
    946  if (!JS_DefinePropertyById(aCx, thisObj, id, value, JSPROP_ENUMERATE)) {
    947    return false;
    948  }
    949 
    950  args.rval().set(value);
    951  return true;
    952 }
    953 
    954 static bool ESModuleSetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
    955  JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
    956 
    957  JS::Rooted<JSObject*> callee(aCx);
    958  JS::Rooted<JSObject*> thisObj(aCx);
    959  JS::Rooted<jsid> id(aCx);
    960  if (!ExtractArgs(aCx, args, &callee, &thisObj, &id)) {
    961    return false;
    962  }
    963 
    964  return JS_DefinePropertyById(aCx, thisObj, id, args.get(0), JSPROP_ENUMERATE);
    965 }
    966 
    967 static bool DefineESModuleGetter(JSContext* aCx, JS::Handle<JSObject*> aTarget,
    968                                 JS::Handle<JS::PropertyKey> aId,
    969                                 JS::Handle<JS::Value> aResourceURI,
    970                                 const EncodedOptions& encodedOptions) {
    971  JS::Rooted<JS::Value> idVal(aCx, JS::StringValue(aId.toString()));
    972 
    973  JS::Rooted<JS::Value> optionsVal(aCx,
    974                                   JS::Int32Value(encodedOptions.toInt32()));
    975 
    976  JS::Rooted<JSObject*> getter(
    977      aCx, JS_GetFunctionObject(js::NewFunctionByIdWithReserved(
    978               aCx, ESModuleGetter, 0, 0, aId)));
    979 
    980  JS::Rooted<JSObject*> setter(
    981      aCx, JS_GetFunctionObject(js::NewFunctionByIdWithReserved(
    982               aCx, ESModuleSetter, 0, 0, aId)));
    983 
    984  if (!getter || !setter) {
    985    JS_ReportOutOfMemory(aCx);
    986    return false;
    987  }
    988 
    989  js::SetFunctionNativeReserved(getter, SLOT_ID, idVal);
    990  js::SetFunctionNativeReserved(setter, SLOT_ID, idVal);
    991 
    992  js::SetFunctionNativeReserved(getter, SLOT_URI, aResourceURI);
    993 
    994  js::SetFunctionNativeReserved(getter, SLOT_OPTIONS, optionsVal);
    995 
    996  return JS_DefinePropertyById(aCx, aTarget, aId, getter, setter,
    997                               JSPROP_ENUMERATE);
    998 }
    999 
   1000 }  // namespace lazy_getter
   1001 
   1002 /* static */
   1003 void ChromeUtils::DefineLazyGetter(const GlobalObject& aGlobal,
   1004                                   JS::Handle<JSObject*> aTarget,
   1005                                   JS::Handle<JS::Value> aName,
   1006                                   JS::Handle<JSObject*> aLambda,
   1007                                   ErrorResult& aRv) {
   1008  JSContext* cx = aGlobal.Context();
   1009  if (!lazy_getter::DefineLazyGetter(cx, aTarget, aName, aLambda)) {
   1010    aRv.NoteJSContextException(cx);
   1011    return;
   1012  }
   1013 }
   1014 
   1015 /* static */
   1016 void ChromeUtils::DefineESModuleGetters(
   1017    const GlobalObject& global, JS::Handle<JSObject*> target,
   1018    JS::Handle<JSObject*> modules,
   1019    const ImportESModuleOptionsDictionary& aOptions, ErrorResult& aRv) {
   1020  JSContext* cx = global.Context();
   1021 
   1022  JS::Rooted<JS::IdVector> props(cx, JS::IdVector(cx));
   1023  if (!JS_Enumerate(cx, modules, &props)) {
   1024    aRv.NoteJSContextException(cx);
   1025    return;
   1026  }
   1027 
   1028  if (!ValidateImportOptions(cx, global, aOptions)) {
   1029    aRv.Throw(NS_ERROR_FAILURE);
   1030    return;
   1031  }
   1032 
   1033  EncodedOptions encodedOptions(aOptions);
   1034 
   1035  JS::Rooted<JS::PropertyKey> prop(cx);
   1036  JS::Rooted<JS::Value> resourceURIVal(cx);
   1037  for (JS::PropertyKey tmp : props) {
   1038    prop = tmp;
   1039 
   1040    if (!prop.isString()) {
   1041      aRv.Throw(NS_ERROR_FAILURE);
   1042      return;
   1043    }
   1044 
   1045    if (!JS_GetPropertyById(cx, modules, prop, &resourceURIVal)) {
   1046      aRv.NoteJSContextException(cx);
   1047      return;
   1048    }
   1049 
   1050    if (!lazy_getter::DefineESModuleGetter(cx, target, prop, resourceURIVal,
   1051                                           encodedOptions)) {
   1052      aRv.NoteJSContextException(cx);
   1053      return;
   1054    }
   1055  }
   1056 }
   1057 
   1058 #ifdef XP_UNIX
   1059 /* static */
   1060 void ChromeUtils::GetLibcConstants(const GlobalObject&,
   1061                                   LibcConstants& aConsts) {
   1062  aConsts.mEPERM.Construct(EPERM);
   1063  aConsts.mEINTR.Construct(EINTR);
   1064  aConsts.mEACCES.Construct(EACCES);
   1065  aConsts.mEAGAIN.Construct(EAGAIN);
   1066  aConsts.mEINVAL.Construct(EINVAL);
   1067  aConsts.mENOSYS.Construct(ENOSYS);
   1068 
   1069  aConsts.mF_SETFD.Construct(F_SETFD);
   1070  aConsts.mF_SETFL.Construct(F_SETFL);
   1071 
   1072  aConsts.mFD_CLOEXEC.Construct(FD_CLOEXEC);
   1073 
   1074  aConsts.mAT_EACCESS.Construct(AT_EACCESS);
   1075 
   1076  aConsts.mO_CREAT.Construct(O_CREAT);
   1077  aConsts.mO_NONBLOCK.Construct(O_NONBLOCK);
   1078  aConsts.mO_WRONLY.Construct(O_WRONLY);
   1079 
   1080  aConsts.mPOLLERR.Construct(POLLERR);
   1081  aConsts.mPOLLHUP.Construct(POLLHUP);
   1082  aConsts.mPOLLIN.Construct(POLLIN);
   1083  aConsts.mPOLLNVAL.Construct(POLLNVAL);
   1084  aConsts.mPOLLOUT.Construct(POLLOUT);
   1085 
   1086  aConsts.mWNOHANG.Construct(WNOHANG);
   1087 
   1088 #  ifdef XP_LINUX
   1089  aConsts.mPR_CAPBSET_READ.Construct(PR_CAPBSET_READ);
   1090 #  endif
   1091 }
   1092 #endif
   1093 
   1094 /* static */
   1095 void ChromeUtils::OriginAttributesToSuffix(
   1096    dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs,
   1097    nsCString& aSuffix)
   1098 
   1099 {
   1100  OriginAttributes attrs(aAttrs);
   1101  attrs.CreateSuffix(aSuffix);
   1102 }
   1103 
   1104 /* static */
   1105 bool ChromeUtils::OriginAttributesMatchPattern(
   1106    dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs,
   1107    const dom::OriginAttributesPatternDictionary& aPattern) {
   1108  OriginAttributes attrs(aAttrs);
   1109  OriginAttributesPattern pattern(aPattern);
   1110  return pattern.Matches(attrs);
   1111 }
   1112 
   1113 /* static */
   1114 void ChromeUtils::CreateOriginAttributesFromOrigin(
   1115    dom::GlobalObject& aGlobal, const nsAString& aOrigin,
   1116    dom::OriginAttributesDictionary& aAttrs, ErrorResult& aRv) {
   1117  OriginAttributes attrs;
   1118  nsAutoCString suffix;
   1119  if (!attrs.PopulateFromOrigin(NS_ConvertUTF16toUTF8(aOrigin), suffix)) {
   1120    aRv.Throw(NS_ERROR_FAILURE);
   1121    return;
   1122  }
   1123  aAttrs = attrs;
   1124 }
   1125 
   1126 /* static */
   1127 void ChromeUtils::CreateOriginAttributesFromOriginSuffix(
   1128    dom::GlobalObject& aGlobal, const nsAString& aSuffix,
   1129    dom::OriginAttributesDictionary& aAttrs, ErrorResult& aRv) {
   1130  OriginAttributes attrs;
   1131  nsAutoCString suffix;
   1132  if (!attrs.PopulateFromSuffix(NS_ConvertUTF16toUTF8(aSuffix))) {
   1133    aRv.Throw(NS_ERROR_FAILURE);
   1134    return;
   1135  }
   1136  aAttrs = attrs;
   1137 }
   1138 
   1139 /* static */
   1140 void ChromeUtils::FillNonDefaultOriginAttributes(
   1141    dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs,
   1142    dom::OriginAttributesDictionary& aNewAttrs) {
   1143  aNewAttrs = aAttrs;
   1144 }
   1145 
   1146 /* static */
   1147 bool ChromeUtils::IsOriginAttributesEqual(
   1148    dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aA,
   1149    const dom::OriginAttributesDictionary& aB) {
   1150  return IsOriginAttributesEqual(aA, aB);
   1151 }
   1152 
   1153 /* static */
   1154 bool ChromeUtils::IsOriginAttributesEqual(
   1155    const dom::OriginAttributesDictionary& aA,
   1156    const dom::OriginAttributesDictionary& aB) {
   1157  return aA == aB;
   1158 }
   1159 
   1160 /* static */
   1161 void ChromeUtils::GetBaseDomainFromPartitionKey(dom::GlobalObject& aGlobal,
   1162                                                const nsAString& aPartitionKey,
   1163                                                nsAString& aBaseDomain,
   1164                                                ErrorResult& aRv) {
   1165  nsString scheme;
   1166  nsString pkBaseDomain;
   1167  int32_t port;
   1168  bool ancestor;
   1169 
   1170  if (!mozilla::OriginAttributes::ParsePartitionKey(
   1171          aPartitionKey, scheme, pkBaseDomain, port, ancestor)) {
   1172    aRv.Throw(NS_ERROR_FAILURE);
   1173    return;
   1174  }
   1175 
   1176  aBaseDomain = pkBaseDomain;
   1177 }
   1178 
   1179 /* static */
   1180 void ChromeUtils::GetPartitionKeyFromURL(dom::GlobalObject& aGlobal,
   1181                                         const nsAString& aTopLevelUrl,
   1182                                         const nsAString& aSubresourceUrl,
   1183                                         const Optional<bool>& aForeignContext,
   1184                                         nsAString& aPartitionKey,
   1185                                         ErrorResult& aRv) {
   1186  nsCOMPtr<nsIURI> topLevelURI;
   1187  nsresult rv = NS_NewURI(getter_AddRefs(topLevelURI), aTopLevelUrl);
   1188  if (NS_SUCCEEDED(rv) && topLevelURI->SchemeIs("chrome")) {
   1189    rv = NS_ERROR_FAILURE;
   1190  }
   1191  if (NS_WARN_IF(NS_FAILED(rv))) {
   1192    aPartitionKey.Truncate();
   1193    aRv.Throw(rv);
   1194    return;
   1195  }
   1196 
   1197  bool foreignResource;
   1198  bool fallback = false;
   1199  if (!aSubresourceUrl.IsEmpty()) {
   1200    nsCOMPtr<nsIURI> resourceURI;
   1201    rv = NS_NewURI(getter_AddRefs(resourceURI), aSubresourceUrl);
   1202    if (NS_WARN_IF(NS_FAILED(rv))) {
   1203      aPartitionKey.Truncate();
   1204      aRv.Throw(rv);
   1205      return;
   1206    }
   1207 
   1208    ThirdPartyUtil* thirdPartyUtil = ThirdPartyUtil::GetInstance();
   1209    if (!thirdPartyUtil) {
   1210      aPartitionKey.Truncate();
   1211      aRv.Throw(NS_ERROR_SERVICE_NOT_AVAILABLE);
   1212      return;
   1213    }
   1214 
   1215    rv = thirdPartyUtil->IsThirdPartyURI(topLevelURI, resourceURI,
   1216                                         &foreignResource);
   1217    if (NS_FAILED(rv)) {
   1218      // we fallback to assuming the resource is foreign if there is an error
   1219      foreignResource = true;
   1220      fallback = true;
   1221    }
   1222  } else {
   1223    // Assume we have a foreign resource if the resource was not provided
   1224    foreignResource = true;
   1225    fallback = true;
   1226  }
   1227 
   1228  // aForeignContext is whether or not this is a foreign context.
   1229  // foreignResource is whether or not the resource is cross-site to the top
   1230  // level. So we need to validate that a false foreign context doesn't have a
   1231  // same-site resource. That is impossible!
   1232  if (aForeignContext.WasPassed() && !aForeignContext.Value() &&
   1233      foreignResource && !fallback) {
   1234    aPartitionKey.Truncate();
   1235    aRv.Throw(nsresult::NS_ERROR_INVALID_ARG);
   1236    return;
   1237  }
   1238 
   1239  bool foreignByAncestorContext = aForeignContext.WasPassed() &&
   1240                                  aForeignContext.Value() && !foreignResource;
   1241  mozilla::OriginAttributes attrs;
   1242  attrs.SetPartitionKey(topLevelURI, foreignByAncestorContext);
   1243  aPartitionKey = attrs.mPartitionKey;
   1244 }
   1245 
   1246 #ifdef NIGHTLY_BUILD
   1247 /* static */
   1248 void ChromeUtils::GetRecentJSDevError(GlobalObject& aGlobal,
   1249                                      JS::MutableHandle<JS::Value> aRetval,
   1250                                      ErrorResult& aRv) {
   1251  aRetval.setUndefined();
   1252  auto runtime = CycleCollectedJSRuntime::Get();
   1253  MOZ_ASSERT(runtime);
   1254 
   1255  auto cx = aGlobal.Context();
   1256  if (!runtime->GetRecentDevError(cx, aRetval)) {
   1257    aRv.NoteJSContextException(cx);
   1258    return;
   1259  }
   1260 }
   1261 
   1262 /* static */
   1263 void ChromeUtils::ClearRecentJSDevError(GlobalObject&) {
   1264  auto runtime = CycleCollectedJSRuntime::Get();
   1265  MOZ_ASSERT(runtime);
   1266 
   1267  runtime->ClearRecentDevError();
   1268 }
   1269 #endif  // NIGHTLY_BUILD
   1270 
   1271 void ChromeUtils::ClearMessagingLayerSecurityStateByPrincipal(
   1272    GlobalObject&, nsIPrincipal* aPrincipal, ErrorResult& aRv) {
   1273  MOZ_LOG(gMlsLog, LogLevel::Debug,
   1274          ("ClearMessagingLayerSecurityStateByPrincipal"));
   1275 
   1276  if (NS_WARN_IF(!aPrincipal)) {
   1277    MOZ_LOG(gMlsLog, LogLevel::Error, ("Principal is null"));
   1278    aRv.Throw(NS_ERROR_FAILURE);
   1279    return;
   1280  }
   1281 
   1282  // Get the profile directory
   1283  nsCOMPtr<nsIFile> file;
   1284  aRv = NS_GetSpecialDirectory("ProfD", getter_AddRefs(file));
   1285  if (NS_WARN_IF(aRv.Failed())) {
   1286    MOZ_LOG(gMlsLog, LogLevel::Error, ("Failed to get profile directory"));
   1287    aRv.Throw(NS_ERROR_FAILURE);
   1288    return;
   1289  }
   1290 
   1291  // Append the 'mls' directory
   1292  aRv = file->AppendNative("mls"_ns);
   1293  if (NS_WARN_IF(aRv.Failed())) {
   1294    MOZ_LOG(gMlsLog, LogLevel::Error,
   1295            ("Failed to append 'mls' to directory path"));
   1296    aRv.Throw(NS_ERROR_FAILURE);
   1297    return;
   1298  }
   1299 
   1300  bool exists;
   1301  aRv = file->Exists(&exists);
   1302  if (NS_WARN_IF(aRv.Failed())) {
   1303    MOZ_LOG(gMlsLog, LogLevel::Error,
   1304            ("Failed to check if 'mls' directory exists"));
   1305    aRv.Throw(NS_ERROR_FAILURE);
   1306    return;
   1307  }
   1308 
   1309  // If the 'mls' directory does not exist, we exit early
   1310  if (!exists) {
   1311    MOZ_LOG(gMlsLog, LogLevel::Error, ("'mls' directory does not exist"));
   1312    return;
   1313  }
   1314 
   1315  // Get the storage origin key
   1316  nsAutoCString originKey;
   1317  aRv = aPrincipal->GetStorageOriginKey(originKey);
   1318  if (NS_WARN_IF(aRv.Failed())) {
   1319    MOZ_LOG(gMlsLog, LogLevel::Error, ("Failed to get storage origin key"));
   1320    aRv.Throw(NS_ERROR_FAILURE);
   1321    return;
   1322  }
   1323 
   1324  // Get the origin attributes suffix
   1325  nsAutoCString originAttrSuffix;
   1326  aRv = aPrincipal->GetOriginSuffix(originAttrSuffix);
   1327  if (NS_WARN_IF(aRv.Failed())) {
   1328    MOZ_LOG(gMlsLog, LogLevel::Error,
   1329            ("Failed to get origin attributes suffix"));
   1330    aRv.Throw(NS_ERROR_FAILURE);
   1331    return;
   1332  }
   1333 
   1334  // Construct the full origin key
   1335  nsAutoCString fullOriginKey = originKey + originAttrSuffix;
   1336 
   1337  // We append the full origin key to the file path
   1338  aRv = file->AppendNative(fullOriginKey);
   1339  if (NS_WARN_IF(aRv.Failed())) {
   1340    MOZ_LOG(gMlsLog, LogLevel::Error,
   1341            ("Failed to append full origin key to the file path"));
   1342    aRv.Throw(NS_ERROR_FAILURE);
   1343    return;
   1344  }
   1345 
   1346  // Remove the directory recursively
   1347  aRv = file->Remove(/* recursive */ true);
   1348  if (NS_WARN_IF(aRv.Failed())) {
   1349    MOZ_LOG(gMlsLog, LogLevel::Error,
   1350            ("Failed to remove : %s", file->HumanReadablePath().get()));
   1351    aRv.Throw(NS_ERROR_FAILURE);
   1352    return;
   1353  }
   1354 
   1355  MOZ_LOG(gMlsLog, LogLevel::Debug,
   1356          ("Successfully cleared MLS state for principal"));
   1357 }
   1358 
   1359 void ChromeUtils::ClearMessagingLayerSecurityStateBySite(
   1360    GlobalObject&, const nsACString& aSchemelessSite,
   1361    const dom::OriginAttributesPatternDictionary& aPattern, ErrorResult& aRv) {
   1362  MOZ_LOG(gMlsLog, LogLevel::Debug, ("ClearMessagingLayerSecurityStateBySite"));
   1363 
   1364  // Get the profile directory
   1365  nsCOMPtr<nsIFile> file;
   1366  aRv = NS_GetSpecialDirectory("ProfD", getter_AddRefs(file));
   1367  if (NS_WARN_IF(aRv.Failed())) {
   1368    MOZ_LOG(gMlsLog, LogLevel::Error, ("Failed to get profile directory"));
   1369    aRv.Throw(NS_ERROR_FAILURE);
   1370    return;
   1371  }
   1372 
   1373  // Append the 'mls' directory
   1374  aRv = file->AppendNative("mls"_ns);
   1375  if (NS_WARN_IF(aRv.Failed())) {
   1376    MOZ_LOG(gMlsLog, LogLevel::Error,
   1377            ("Failed to append 'mls' to directory path"));
   1378    aRv.Throw(NS_ERROR_FAILURE);
   1379    return;
   1380  }
   1381 
   1382  bool exists;
   1383  aRv = file->Exists(&exists);
   1384  if (NS_WARN_IF(aRv.Failed())) {
   1385    MOZ_LOG(gMlsLog, LogLevel::Error,
   1386            ("Failed to check if 'mls' directory exists"));
   1387    aRv.Throw(NS_ERROR_FAILURE);
   1388    return;
   1389  }
   1390 
   1391  // If the 'mls' directory does not exist, we exit early
   1392  if (!exists) {
   1393    MOZ_LOG(gMlsLog, LogLevel::Error, ("'mls' directory does not exist"));
   1394    return;
   1395  }
   1396 
   1397  // Check if the schemeless site is empty
   1398  if (NS_WARN_IF(aSchemelessSite.IsEmpty())) {
   1399    MOZ_LOG(gMlsLog, LogLevel::Error, ("Schemeless site is empty"));
   1400    aRv.Throw(NS_ERROR_INVALID_ARG);
   1401    return;
   1402  }
   1403 
   1404  // Site pattern
   1405  OriginAttributesPattern pattern(aPattern);
   1406 
   1407  // Partition pattern
   1408  // This pattern is used to (additionally) clear state partitioned under
   1409  // aSchemelessSite.
   1410  OriginAttributesPattern partitionPattern = pattern;
   1411  partitionPattern.mPartitionKeyPattern.Construct();
   1412  partitionPattern.mPartitionKeyPattern.Value().mBaseDomain.Construct(
   1413      NS_ConvertUTF8toUTF16(aSchemelessSite));
   1414 
   1415  // Reverse the base domain using the existing function
   1416  nsAutoCString targetReversedBaseDomain(aSchemelessSite);
   1417  std::reverse(targetReversedBaseDomain.BeginWriting(),
   1418               targetReversedBaseDomain.EndWriting());
   1419 
   1420  MOZ_LOG(gMlsLog, LogLevel::Debug,
   1421          ("Reversed base domain: %s", targetReversedBaseDomain.get()));
   1422 
   1423  // Enumerate files in the 'mls' directory
   1424  nsCOMPtr<nsIDirectoryEnumerator> dirEnum;
   1425  aRv = file->GetDirectoryEntries(getter_AddRefs(dirEnum));
   1426  if (NS_WARN_IF(aRv.Failed())) {
   1427    MOZ_LOG(gMlsLog, LogLevel::Error,
   1428            ("Failed to get directory entries in 'mls' directory"));
   1429    aRv.Throw(NS_ERROR_FAILURE);
   1430    return;
   1431  }
   1432 
   1433  // Iterate through all entries in the directory
   1434  nsCOMPtr<nsIFile> entry;
   1435  while (NS_SUCCEEDED(dirEnum->GetNextFile(getter_AddRefs(entry))) && entry) {
   1436    nsAutoCString entryName;
   1437    aRv = entry->GetNativeLeafName(entryName);
   1438    if (NS_WARN_IF(aRv.Failed())) {
   1439      MOZ_LOG(gMlsLog, LogLevel::Error,
   1440              ("Failed to get native leaf name for entry"));
   1441      continue;
   1442    }
   1443 
   1444    // Find the position of .sqlite.enc or .key in the entry name
   1445    int32_t sqliteEncPos = entryName.RFind(".sqlite.enc");
   1446    int32_t keyPos = entryName.RFind(".key");
   1447 
   1448    // Remove the .sqlite.enc or .key suffix from the entryName
   1449    if (sqliteEncPos != kNotFound) {
   1450      entryName.SetLength(sqliteEncPos);
   1451    } else if (keyPos != kNotFound) {
   1452      entryName.SetLength(keyPos);
   1453    }
   1454 
   1455    // Decode the entry name
   1456    nsAutoCString decodedEntryName;
   1457    aRv = mozilla::Base64Decode(entryName, decodedEntryName);
   1458    if (NS_WARN_IF(aRv.Failed())) {
   1459      MOZ_LOG(gMlsLog, LogLevel::Debug,
   1460              ("Failed to decode entry name: %s", entryName.get()));
   1461      continue;
   1462    }
   1463 
   1464    // Find the origin attributes suffix in the entry name by taking the
   1465    // value of the entry name after the ^ separator
   1466    int32_t separatorPos = decodedEntryName.FindChar('^');
   1467 
   1468    // We extract the origin attributes suffix from the entry name
   1469    nsAutoCString originSuffix;
   1470    originSuffix.Assign(Substring(decodedEntryName, separatorPos));
   1471 
   1472    // Populate the origin attributes from the suffix
   1473    OriginAttributes originAttrs;
   1474    if (NS_WARN_IF(!originAttrs.PopulateFromSuffix(originSuffix))) {
   1475      MOZ_LOG(gMlsLog, LogLevel::Error,
   1476              ("Failed to populate origin attributes from suffix"));
   1477      continue;
   1478    }
   1479 
   1480    // Check if the entry name starts with the reversed base domain
   1481    if (StringBeginsWith(decodedEntryName, targetReversedBaseDomain)) {
   1482      MOZ_LOG(gMlsLog, LogLevel::Debug,
   1483              ("Entry file: %s", entry->HumanReadablePath().get()));
   1484 
   1485      // If there is a valid origin attributes suffix, we remove the entry
   1486      // only if it matches.
   1487      if (pattern.Matches(originAttrs)) {
   1488        aRv = entry->Remove(/* recursive */ false);
   1489        if (NS_WARN_IF(aRv.Failed())) {
   1490          MOZ_LOG(gMlsLog, LogLevel::Error,
   1491                  ("Failed to remove file: %s", decodedEntryName.get()));
   1492        }
   1493        MOZ_LOG(gMlsLog, LogLevel::Debug,
   1494                ("Removed file: %s", decodedEntryName.get()));
   1495      }
   1496    }
   1497 
   1498    // If there is a valid origin attributes suffix, we remove the entry
   1499    // only if it matches. We are checking for state partitioned under
   1500    // aSchemelessSite.
   1501    if (partitionPattern.Matches(originAttrs)) {
   1502      aRv = entry->Remove(/* recursive */ false);
   1503      if (NS_WARN_IF(aRv.Failed())) {
   1504        MOZ_LOG(gMlsLog, LogLevel::Error,
   1505                ("Failed to remove file: %s", decodedEntryName.get()));
   1506      }
   1507      MOZ_LOG(gMlsLog, LogLevel::Debug,
   1508              ("Removed file: %s", decodedEntryName.get()));
   1509    }
   1510  }
   1511 
   1512  // Close the directory enumerator
   1513  dirEnum->Close();
   1514 }
   1515 
   1516 void ChromeUtils::ClearMessagingLayerSecurityState(GlobalObject&,
   1517                                                   ErrorResult& aRv) {
   1518  MOZ_LOG(gMlsLog, LogLevel::Debug, ("ClearMessagingLayerSecurityState"));
   1519 
   1520  // Get the profile directory
   1521  nsCOMPtr<nsIFile> file;
   1522  aRv = NS_GetSpecialDirectory("ProfD", getter_AddRefs(file));
   1523  if (NS_WARN_IF(aRv.Failed())) {
   1524    MOZ_LOG(gMlsLog, LogLevel::Error, ("Failed to get profile directory"));
   1525    return;
   1526  }
   1527 
   1528  // Append the 'mls' directory
   1529  aRv = file->AppendNative("mls"_ns);
   1530  if (NS_WARN_IF(aRv.Failed())) {
   1531    MOZ_LOG(gMlsLog, LogLevel::Error,
   1532            ("Failed to append 'mls' to directory path"));
   1533    return;
   1534  }
   1535 
   1536  // Check if the directory exists
   1537  bool exists;
   1538  aRv = file->Exists(&exists);
   1539  if (NS_WARN_IF(aRv.Failed() || !exists)) {
   1540    MOZ_LOG(gMlsLog, LogLevel::Debug, ("'mls' directory does not exist"));
   1541    return;
   1542  }
   1543 
   1544  // Remove the MLS directory recursively
   1545  aRv = file->Remove(/* recursive */ true);
   1546  if (NS_WARN_IF(aRv.Failed())) {
   1547    MOZ_LOG(gMlsLog, LogLevel::Error, ("Failed to remove MLS directory"));
   1548    return;
   1549  }
   1550 
   1551  // Log the directory path
   1552  MOZ_LOG(gMlsLog, LogLevel::Debug,
   1553          ("Deleted MLS directory: %s", file->HumanReadablePath().get()));
   1554 
   1555  // Recreate the MLS directory
   1556  aRv = file->Create(nsIFile::DIRECTORY_TYPE, 0755);
   1557  if (NS_WARN_IF(aRv.Failed())) {
   1558    MOZ_LOG(gMlsLog, LogLevel::Error, ("Failed to recreate MLS directory"));
   1559    return;
   1560  }
   1561 
   1562  MOZ_LOG(gMlsLog, LogLevel::Debug, ("Successfully cleared all MLS state"));
   1563 }
   1564 
   1565 void ChromeUtils::ClearResourceCache(
   1566    GlobalObject& aGlobal, const dom::ClearResourceCacheOptions& aOptions,
   1567    ErrorResult& aRv) {
   1568  bool clearStyleSheet = false;
   1569  bool clearScript = false;
   1570  bool clearImage = false;
   1571 
   1572  if (aOptions.mTypes.WasPassed()) {
   1573    for (const auto& type : aOptions.mTypes.Value()) {
   1574      switch (type) {
   1575        case ResourceCacheType::Stylesheet:
   1576          clearStyleSheet = true;
   1577          break;
   1578        case ResourceCacheType::Script:
   1579          clearScript = true;
   1580          break;
   1581        case ResourceCacheType::Image:
   1582          clearImage = true;
   1583          break;
   1584      }
   1585    }
   1586  } else {
   1587    clearStyleSheet = true;
   1588    clearScript = true;
   1589    clearImage = true;
   1590  }
   1591 
   1592  int filterCount = 0;
   1593  if (aOptions.mTarget.WasPassed()) {
   1594    filterCount++;
   1595  }
   1596  if (aOptions.mPrincipal.WasPassed()) {
   1597    filterCount++;
   1598  }
   1599  if (aOptions.mSchemelessSite.WasPassed()) {
   1600    filterCount++;
   1601  }
   1602  if (aOptions.mUrl.WasPassed()) {
   1603    filterCount++;
   1604  }
   1605  if (filterCount > 1) {
   1606    aRv.ThrowInvalidStateError(
   1607        "target, principal, schemelessSite, and url properties are mutually "
   1608        "exclusive");
   1609    return;
   1610  }
   1611 
   1612  if (aOptions.mTarget.WasPassed()) {
   1613    Maybe<bool> chrome;
   1614    switch (aOptions.mTarget.Value()) {
   1615      case ResourceCacheTarget::Chrome:
   1616        chrome.emplace(true);
   1617        break;
   1618      case ResourceCacheTarget::Content:
   1619        chrome.emplace(false);
   1620        break;
   1621    }
   1622 
   1623    if (clearStyleSheet) {
   1624      SharedStyleSheetCache::Clear(chrome);
   1625    }
   1626    if (clearScript) {
   1627      SharedScriptCache::Clear(chrome);
   1628    }
   1629    if (clearImage) {
   1630      imgLoader::ClearCache(Nothing(), chrome);
   1631    }
   1632    return;
   1633  }
   1634 
   1635  if (aOptions.mPrincipal.WasPassed()) {
   1636    nsCOMPtr<nsIPrincipal> principal = aOptions.mPrincipal.Value().get();
   1637 
   1638    if (clearStyleSheet) {
   1639      SharedStyleSheetCache::Clear(Nothing(), Some(principal));
   1640    }
   1641    if (clearScript) {
   1642      SharedScriptCache::Clear(Nothing(), Some(principal));
   1643    }
   1644    if (clearImage) {
   1645      imgLoader::ClearCache(Nothing(), Nothing(), Some(principal));
   1646    }
   1647    return;
   1648  }
   1649 
   1650  if (aOptions.mSchemelessSite.WasPassed()) {
   1651    nsCString schemelessSite(aOptions.mSchemelessSite.Value());
   1652    mozilla::OriginAttributesPattern pattern(aOptions.mPattern);
   1653 
   1654    if (clearStyleSheet) {
   1655      SharedStyleSheetCache::Clear(Nothing(), Nothing(), Some(schemelessSite),
   1656                                   Some(pattern));
   1657    }
   1658    if (clearScript) {
   1659      SharedScriptCache::Clear(Nothing(), Nothing(), Some(schemelessSite),
   1660                               Some(pattern));
   1661    }
   1662    if (clearImage) {
   1663      imgLoader::ClearCache(Nothing(), Nothing(), Nothing(),
   1664                            Some(schemelessSite), Some(pattern));
   1665    }
   1666    return;
   1667  }
   1668 
   1669  if (aOptions.mUrl.WasPassed()) {
   1670    nsCString url(aOptions.mUrl.Value());
   1671 
   1672    if (clearStyleSheet) {
   1673      SharedStyleSheetCache::Clear(Nothing(), Nothing(), Nothing(), Nothing(),
   1674                                   Some(url));
   1675    }
   1676    if (clearScript) {
   1677      SharedScriptCache::Clear(Nothing(), Nothing(), Nothing(), Nothing(),
   1678                               Some(url));
   1679    }
   1680    if (clearImage) {
   1681      imgLoader::ClearCache(Nothing(), Nothing(), Nothing(), Nothing(),
   1682                            Nothing(), Some(url));
   1683    }
   1684    return;
   1685  }
   1686 
   1687  if (clearStyleSheet) {
   1688    SharedStyleSheetCache::Clear();
   1689  }
   1690  if (clearScript) {
   1691    SharedScriptCache::Clear();
   1692  }
   1693  if (clearImage) {
   1694    imgLoader::ClearCache();
   1695  }
   1696 }
   1697 
   1698 void ChromeUtils::InvalidateResourceCache(GlobalObject& aGlobal,
   1699                                          ErrorResult& aRv) {
   1700  SharedScriptCache::Invalidate();
   1701 }
   1702 
   1703 void ChromeUtils::ClearBfcacheByPrincipal(GlobalObject& aGlobal,
   1704                                          nsIPrincipal* aPrincipal,
   1705                                          ErrorResult& aRv) {
   1706  aRv = CanonicalBrowsingContext::ClearBfcacheByPrincipal(aPrincipal);
   1707 }
   1708 
   1709 #define PROCTYPE_TO_WEBIDL_CASE(_procType, _webidl) \
   1710  case mozilla::ProcType::_procType:                \
   1711    return WebIDLProcType::_webidl
   1712 
   1713 static WebIDLProcType ProcTypeToWebIDL(mozilla::ProcType aType) {
   1714  // Max is the value of the last enum, not the length, so add one.
   1715  static_assert(
   1716      static_cast<size_t>(MaxContiguousEnumValue<WebIDLProcType>::value) ==
   1717          static_cast<size_t>(ProcType::Max),
   1718      "In order for this static cast to be okay, "
   1719      "WebIDLProcType must match ProcType exactly");
   1720 
   1721  // These must match the similar ones in E10SUtils.sys.mjs, RemoteTypes.h,
   1722  // ProcInfo.h and ChromeUtils.webidl
   1723  switch (aType) {
   1724    PROCTYPE_TO_WEBIDL_CASE(Web, Web);
   1725    PROCTYPE_TO_WEBIDL_CASE(WebIsolated, WebIsolated);
   1726    PROCTYPE_TO_WEBIDL_CASE(File, File);
   1727    PROCTYPE_TO_WEBIDL_CASE(Extension, Extension);
   1728    PROCTYPE_TO_WEBIDL_CASE(PrivilegedAbout, Privilegedabout);
   1729    PROCTYPE_TO_WEBIDL_CASE(PrivilegedMozilla, Privilegedmozilla);
   1730    PROCTYPE_TO_WEBIDL_CASE(WebCOOPCOEP, WithCoopCoep);
   1731    PROCTYPE_TO_WEBIDL_CASE(WebServiceWorker, WebServiceWorker);
   1732    PROCTYPE_TO_WEBIDL_CASE(Inference, Inference);
   1733 
   1734 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
   1735                           process_bin_type, procinfo_typename,               \
   1736                           webidl_typename, allcaps_name)                     \
   1737  PROCTYPE_TO_WEBIDL_CASE(procinfo_typename, webidl_typename);
   1738 #define SKIP_PROCESS_TYPE_CONTENT
   1739 #ifndef MOZ_ENABLE_FORKSERVER
   1740 #  define SKIP_PROCESS_TYPE_FORKSERVER
   1741 #endif  // MOZ_ENABLE_FORKSERVER
   1742 #include "mozilla/GeckoProcessTypes.h"
   1743 #undef SKIP_PROCESS_TYPE_CONTENT
   1744 #ifndef MOZ_ENABLE_FORKSERVER
   1745 #  undef SKIP_PROCESS_TYPE_FORKSERVER
   1746 #endif  // MOZ_ENABLE_FORKSERVER
   1747 #undef GECKO_PROCESS_TYPE
   1748 
   1749    PROCTYPE_TO_WEBIDL_CASE(Preallocated, Preallocated);
   1750    PROCTYPE_TO_WEBIDL_CASE(Unknown, Unknown);
   1751  }
   1752 
   1753  MOZ_ASSERT(false, "Unhandled case in ProcTypeToWebIDL");
   1754  return WebIDLProcType::Unknown;
   1755 }
   1756 
   1757 #undef PROCTYPE_TO_WEBIDL_CASE
   1758 
   1759 /* static */
   1760 already_AddRefed<Promise> ChromeUtils::RequestProcInfo(GlobalObject& aGlobal,
   1761                                                       ErrorResult& aRv) {
   1762  // This function will use IPDL to enable threads info on macOS
   1763  // see https://bugzilla.mozilla.org/show_bug.cgi?id=1529023
   1764  if (!XRE_IsParentProcess()) {
   1765    aRv.Throw(NS_ERROR_FAILURE);
   1766    return nullptr;
   1767  }
   1768  // Prepare the JS promise that will hold our response.
   1769  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
   1770  MOZ_ASSERT(global);
   1771  RefPtr<Promise> domPromise = Promise::Create(global, aRv);
   1772  if (NS_WARN_IF(aRv.Failed())) {
   1773    return nullptr;
   1774  }
   1775  MOZ_ASSERT(domPromise);
   1776 
   1777  // Get a list of processes to examine and pre-fill them with available info.
   1778  // Note that this is subject to race conditions: just because we have a
   1779  // process in the list doesn't mean that the process will still be alive when
   1780  // we attempt to get its information. Followup code MUST be able to fail
   1781  // gracefully on some processes and still return whichever information is
   1782  // available.
   1783 
   1784  // Get all the content parents.
   1785  // Note that this array includes even the long dead content parents, so we
   1786  // might have some garbage, especially with Fission.
   1787  // SAFETY NOTE: `contentParents` is only valid if used synchronously.
   1788  // Anything else and you may end up dealing with dangling pointers.
   1789  nsTArray<ContentParent*> contentParents;
   1790  ContentParent::GetAll(contentParents);
   1791 
   1792  // Prepare our background request.
   1793  // We reserve one more slot for the browser process itself.
   1794  nsTArray<ProcInfoRequest> requests(contentParents.Length() + 1);
   1795  // Requesting process info for the browser process itself.
   1796  requests.EmplaceBack(
   1797      /* aPid = */ base::GetCurrentProcId(),
   1798      /* aProcessType = */ ProcType::Browser,
   1799      /* aOrigin = */ ""_ns,
   1800      /* aWindowInfo = */ nsTArray<WindowInfo>(),
   1801      /* aUtilityInfo = */ nsTArray<UtilityInfo>());
   1802 
   1803  // First handle non-ContentParent processes.
   1804  mozilla::ipc::GeckoChildProcessHost::GetAll(
   1805      [&requests](mozilla::ipc::GeckoChildProcessHost* aGeckoProcess) {
   1806        base::ProcessId childPid = aGeckoProcess->GetChildProcessId();
   1807        if (childPid == 0) {
   1808          // Something went wrong with this process, it may be dead already,
   1809          // fail gracefully.
   1810          return;
   1811        }
   1812        mozilla::ProcType type = mozilla::ProcType::Unknown;
   1813 
   1814        switch (aGeckoProcess->GetProcessType()) {
   1815          case GeckoProcessType::GeckoProcessType_Content: {
   1816            // These processes are handled separately.
   1817            return;
   1818          }
   1819 
   1820 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
   1821                           process_bin_type, procinfo_typename,               \
   1822                           webidl_typename, allcaps_name)                     \
   1823  case GeckoProcessType::GeckoProcessType_##enum_name: {                      \
   1824    type = mozilla::ProcType::procinfo_typename;                              \
   1825    break;                                                                    \
   1826  }
   1827 #define SKIP_PROCESS_TYPE_CONTENT
   1828 #ifndef MOZ_ENABLE_FORKSERVER
   1829 #  define SKIP_PROCESS_TYPE_FORKSERVER
   1830 #endif  // MOZ_ENABLE_FORKSERVER
   1831 #include "mozilla/GeckoProcessTypes.h"
   1832 #ifndef MOZ_ENABLE_FORKSERVER
   1833 #  undef SKIP_PROCESS_TYPE_FORKSERVER
   1834 #endif  // MOZ_ENABLE_FORKSERVER
   1835 #undef SKIP_PROCESS_TYPE_CONTENT
   1836 #undef GECKO_PROCESS_TYPE
   1837          default:
   1838            // Leave the default Unknown value in |type|.
   1839            break;
   1840        }
   1841 
   1842        // Attach utility actor information to the process.
   1843        nsTArray<UtilityInfo> utilityActors;
   1844        if (aGeckoProcess->GetProcessType() ==
   1845            GeckoProcessType::GeckoProcessType_Utility) {
   1846          RefPtr<mozilla::ipc::UtilityProcessManager> upm =
   1847              mozilla::ipc::UtilityProcessManager::GetSingleton();
   1848          if (!utilityActors.AppendElements(upm->GetActors(aGeckoProcess),
   1849                                            fallible)) {
   1850            NS_WARNING("Error adding actors");
   1851            return;
   1852          }
   1853        }
   1854 
   1855        requests.EmplaceBack(
   1856            /* aPid = */ childPid,
   1857            /* aProcessType = */ type,
   1858            /* aOrigin = */ ""_ns,
   1859            /* aWindowInfo = */ nsTArray<WindowInfo>(),  // Without a
   1860                                                         // ContentProcess, no
   1861                                                         // DOM windows.
   1862            /* aUtilityInfo = */ std::move(utilityActors),
   1863            /* aChild = */ 0  // Without a ContentProcess, no ChildId.
   1864 #ifdef XP_MACOSX
   1865            ,
   1866            /* aChildTask = */ aGeckoProcess->GetChildTask()
   1867 #endif  // XP_MACOSX
   1868        );
   1869      });
   1870 
   1871  // Now handle ContentParents.
   1872  for (const auto* contentParent : contentParents) {
   1873    if (!contentParent || !contentParent->Process()) {
   1874      // Presumably, the process is dead or dying.
   1875      continue;
   1876    }
   1877    base::ProcessId pid = contentParent->Process()->GetChildProcessId();
   1878    if (pid == 0) {
   1879      // Presumably, the process is dead or dying.
   1880      continue;
   1881    }
   1882    if (contentParent->Process()->GetProcessType() !=
   1883        GeckoProcessType::GeckoProcessType_Content) {
   1884      // We're probably racing against a process changing type.
   1885      // We'll get it in the next call, skip it for the moment.
   1886      continue;
   1887    }
   1888 
   1889    // Since this code is executed synchronously on the main thread,
   1890    // processes cannot die while we're in this loop.
   1891    mozilla::ProcType type = mozilla::ProcType::Unknown;
   1892 
   1893    // Convert the remoteType into a ProcType.
   1894    // Ideally, the remoteType should be strongly typed
   1895    // upstream, this would make the conversion less brittle.
   1896    const nsAutoCString remoteType(contentParent->GetRemoteType());
   1897    if (StringBeginsWith(remoteType, FISSION_WEB_REMOTE_TYPE)) {
   1898      // WARNING: Do not change the order, as
   1899      // `DEFAULT_REMOTE_TYPE` is a prefix of
   1900      // `FISSION_WEB_REMOTE_TYPE`.
   1901      type = mozilla::ProcType::WebIsolated;
   1902    } else if (StringBeginsWith(remoteType, SERVICEWORKER_REMOTE_TYPE)) {
   1903      type = mozilla::ProcType::WebServiceWorker;
   1904    } else if (StringBeginsWith(remoteType,
   1905                                WITH_COOP_COEP_REMOTE_TYPE_PREFIX)) {
   1906      type = mozilla::ProcType::WebCOOPCOEP;
   1907    } else if (remoteType == FILE_REMOTE_TYPE) {
   1908      type = mozilla::ProcType::File;
   1909    } else if (remoteType == EXTENSION_REMOTE_TYPE) {
   1910      type = mozilla::ProcType::Extension;
   1911    } else if (remoteType == PRIVILEGEDABOUT_REMOTE_TYPE) {
   1912      type = mozilla::ProcType::PrivilegedAbout;
   1913    } else if (remoteType == PRIVILEGEDMOZILLA_REMOTE_TYPE) {
   1914      type = mozilla::ProcType::PrivilegedMozilla;
   1915    } else if (remoteType == PREALLOC_REMOTE_TYPE) {
   1916      type = mozilla::ProcType::Preallocated;
   1917    } else if (remoteType == INFERENCE_REMOTE_TYPE) {
   1918      type = mozilla::ProcType::Inference;
   1919    } else if (StringBeginsWith(remoteType, DEFAULT_REMOTE_TYPE)) {
   1920      type = mozilla::ProcType::Web;
   1921    } else {
   1922      MOZ_CRASH_UNSAFE_PRINTF("Unknown remoteType '%s'", remoteType.get());
   1923    }
   1924 
   1925    // By convention, everything after '=' is the origin.
   1926    nsAutoCString origin;
   1927    nsACString::const_iterator cursor;
   1928    nsACString::const_iterator end;
   1929    remoteType.BeginReading(cursor);
   1930    remoteType.EndReading(end);
   1931    if (FindCharInReadable('=', cursor, end)) {
   1932      origin = Substring(++cursor, end);
   1933    }
   1934 
   1935    // Attach DOM window information to the process.
   1936    nsTArray<WindowInfo> windows;
   1937    for (const auto& browserParentWrapperKey :
   1938         contentParent->ManagedPBrowserParent()) {
   1939      for (const auto& windowGlobalParentWrapperKey :
   1940           browserParentWrapperKey->ManagedPWindowGlobalParent()) {
   1941        // WindowGlobalParent is the only immediate subclass of
   1942        // PWindowGlobalParent.
   1943        auto* windowGlobalParent =
   1944            static_cast<WindowGlobalParent*>(windowGlobalParentWrapperKey);
   1945 
   1946        nsString documentTitle;
   1947        windowGlobalParent->GetDocumentTitle(documentTitle);
   1948        WindowInfo* window = windows.EmplaceBack(
   1949            fallible,
   1950            /* aOuterWindowId = */ windowGlobalParent->OuterWindowId(),
   1951            /* aDocumentURI = */ windowGlobalParent->GetDocumentURI(),
   1952            /* aDocumentTitle = */ std::move(documentTitle),
   1953            /* aIsProcessRoot = */ windowGlobalParent->IsProcessRoot(),
   1954            /* aIsInProcess = */ windowGlobalParent->IsInProcess());
   1955        if (!window) {
   1956          aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
   1957          return nullptr;
   1958        }
   1959      }
   1960    }
   1961    requests.EmplaceBack(
   1962        /* aPid = */ pid,
   1963        /* aProcessType = */ type,
   1964        /* aOrigin = */ origin,
   1965        /* aWindowInfo = */ std::move(windows),
   1966        /* aUtilityInfo = */ nsTArray<UtilityInfo>(),
   1967        /* aChild = */ contentParent->ChildID()
   1968 #ifdef XP_MACOSX
   1969            ,
   1970        /* aChildTask = */ contentParent->Process()->GetChildTask()
   1971 #endif  // XP_MACOSX
   1972    );
   1973  }
   1974 
   1975  // Now place background request.
   1976  RefPtr<nsISerialEventTarget> target = global->SerialEventTarget();
   1977  mozilla::GetProcInfo(std::move(requests))
   1978      ->Then(
   1979          target, __func__,
   1980          [target,
   1981           domPromise](const HashMap<base::ProcessId, ProcInfo>& aSysProcInfo) {
   1982            ParentProcInfoDictionary parentInfo;
   1983            if (aSysProcInfo.count() == 0) {
   1984              // For some reason, we couldn't get *any* info.
   1985              // Maybe a sandboxing issue?
   1986              domPromise->MaybeReject(NS_ERROR_UNEXPECTED);
   1987              return;
   1988            }
   1989            nsTArray<ChildProcInfoDictionary> childrenInfo(
   1990                aSysProcInfo.count() - 1);
   1991            for (auto iter = aSysProcInfo.iter(); !iter.done(); iter.next()) {
   1992              const auto& sysProcInfo = iter.get().value();
   1993              nsresult rv;
   1994              if (sysProcInfo.type == ProcType::Browser) {
   1995                rv = mozilla::CopySysProcInfoToDOM(sysProcInfo, &parentInfo);
   1996                if (NS_FAILED(rv)) {
   1997                  // Failing to copy? That's probably not something from we can
   1998                  // (or should) try to recover gracefully.
   1999                  domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
   2000                  return;
   2001                }
   2002                MOZ_ASSERT(sysProcInfo.childId == 0);
   2003                MOZ_ASSERT(sysProcInfo.origin.IsEmpty());
   2004              } else {
   2005                mozilla::dom::ChildProcInfoDictionary* childInfo =
   2006                    childrenInfo.AppendElement(fallible);
   2007                if (!childInfo) {
   2008                  domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
   2009                  return;
   2010                }
   2011                rv = mozilla::CopySysProcInfoToDOM(sysProcInfo, childInfo);
   2012                if (NS_FAILED(rv)) {
   2013                  domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
   2014                  return;
   2015                }
   2016                // Copy Firefox info.
   2017                childInfo->mChildID = sysProcInfo.childId;
   2018                childInfo->mOrigin = sysProcInfo.origin;
   2019                childInfo->mType = ProcTypeToWebIDL(sysProcInfo.type);
   2020 
   2021                for (const auto& source : sysProcInfo.windows) {
   2022                  auto* dest = childInfo->mWindows.AppendElement(fallible);
   2023                  if (!dest) {
   2024                    domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
   2025                    return;
   2026                  }
   2027                  dest->mOuterWindowId = source.outerWindowId;
   2028                  dest->mDocumentURI = source.documentURI;
   2029                  dest->mDocumentTitle = source.documentTitle;
   2030                  dest->mIsProcessRoot = source.isProcessRoot;
   2031                  dest->mIsInProcess = source.isInProcess;
   2032                }
   2033 
   2034                if (sysProcInfo.type == ProcType::Utility) {
   2035                  for (const auto& source : sysProcInfo.utilityActors) {
   2036                    auto* dest =
   2037                        childInfo->mUtilityActors.AppendElement(fallible);
   2038                    if (!dest) {
   2039                      domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
   2040                      return;
   2041                    }
   2042 
   2043                    dest->mActorName = source.actorName;
   2044                  }
   2045                }
   2046              }
   2047            }
   2048 
   2049            // Attach the children to the parent.
   2050            mozilla::dom::Sequence<mozilla::dom::ChildProcInfoDictionary>
   2051                children(std::move(childrenInfo));
   2052            parentInfo.mChildren = std::move(children);
   2053            domPromise->MaybeResolve(parentInfo);
   2054          },
   2055          [domPromise](nsresult aRv) { domPromise->MaybeReject(aRv); });
   2056  MOZ_ASSERT(domPromise);
   2057 
   2058  // sending back the promise instance
   2059  return domPromise.forget();
   2060 }
   2061 
   2062 /* static */
   2063 uint64_t ChromeUtils::GetCurrentProcessMemoryUsage(GlobalObject& aGlobal,
   2064                                                   ErrorResult& aRv) {
   2065  uint64_t retVal = 0;
   2066  nsresult rv = mozilla::GetCurrentProcessMemoryUsage(&retVal);
   2067  if (NS_FAILED(rv)) {
   2068    aRv.Throw(rv);
   2069  }
   2070  return retVal;
   2071 }
   2072 
   2073 /* static */
   2074 uint64_t ChromeUtils::GetCpuTimeSinceProcessStart(GlobalObject& aGlobal,
   2075                                                  ErrorResult& aRv) {
   2076  uint64_t retVal = 0;
   2077  nsresult rv = mozilla::GetCpuTimeSinceProcessStartInMs(&retVal);
   2078  if (NS_FAILED(rv)) {
   2079    aRv.Throw(rv);
   2080  }
   2081  return retVal;
   2082 }
   2083 
   2084 /* static */
   2085 bool ChromeUtils::VsyncEnabled(GlobalObject& aGlobal) {
   2086  return mozilla::gfx::VsyncSource::GetFastestVsyncRate().isSome();
   2087 }
   2088 
   2089 void ChromeUtils::EnableAllPerfStatsFeatures(GlobalObject& aGlobal) {
   2090  PerfStats::MetricMask mask =
   2091      std::numeric_limits<PerfStats::MetricMask>::max();
   2092  PerfStats::SetCollectionMask(mask);
   2093 }
   2094 
   2095 void ChromeUtils::SetPerfStatsFeatures(GlobalObject& aGlobal,
   2096                                       const Sequence<nsString>& aMetrics) {
   2097  // Convert string array to bitmask
   2098  PerfStats::MetricMask mask = 0;
   2099  for (const auto& metricName : aMetrics) {
   2100    // Convert string to corresponding enum value and set bit
   2101    NS_ConvertUTF16toUTF8 utf8MetricName(metricName);
   2102    mask |= PerfStats::GetFeatureMask(utf8MetricName.get());
   2103  }
   2104 
   2105  PerfStats::SetCollectionMask(mask);
   2106 }
   2107 
   2108 already_AddRefed<Promise> ChromeUtils::CollectPerfStats(GlobalObject& aGlobal,
   2109                                                        ErrorResult& aRv) {
   2110  // Creating a JS promise
   2111  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
   2112  MOZ_ASSERT(global);
   2113 
   2114  RefPtr<Promise> promise = Promise::Create(global, aRv);
   2115  if (aRv.Failed()) {
   2116    return nullptr;
   2117  }
   2118 
   2119  RefPtr<PerfStats::PerfStatsPromise> extPromise =
   2120      PerfStats::CollectPerfStatsJSON();
   2121 
   2122  extPromise->Then(
   2123      GetCurrentSerialEventTarget(), __func__,
   2124      [promise](const nsCString& aResult) {
   2125        promise->MaybeResolve(NS_ConvertUTF8toUTF16(aResult));
   2126      },
   2127      [promise](bool aValue) { promise->MaybeReject(NS_ERROR_FAILURE); });
   2128 
   2129  return promise.forget();
   2130 }
   2131 
   2132 constexpr auto kSkipSelfHosted = JS::SavedFrameSelfHosted::Exclude;
   2133 
   2134 /* static */
   2135 void ChromeUtils::GetCallerLocation(const GlobalObject& aGlobal,
   2136                                    nsIPrincipal* aPrincipal,
   2137                                    JS::MutableHandle<JSObject*> aRetval) {
   2138  JSContext* cx = aGlobal.Context();
   2139 
   2140  auto* principals = nsJSPrincipals::get(aPrincipal);
   2141 
   2142  JS::StackCapture captureMode(JS::FirstSubsumedFrame(cx, principals));
   2143 
   2144  JS::Rooted<JSObject*> frame(cx);
   2145  if (!JS::CaptureCurrentStack(cx, &frame, std::move(captureMode))) {
   2146    JS_ClearPendingException(cx);
   2147    aRetval.set(nullptr);
   2148    return;
   2149  }
   2150 
   2151  // FirstSubsumedFrame gets us a stack which stops at the first principal which
   2152  // is subsumed by the given principal. That means that we may have a lot of
   2153  // privileged frames that we don't care about at the top of the stack, though.
   2154  // We need to filter those out to get the frame we actually want.
   2155  aRetval.set(
   2156      js::GetFirstSubsumedSavedFrame(cx, principals, frame, kSkipSelfHosted));
   2157 }
   2158 
   2159 /* static */
   2160 void ChromeUtils::CreateError(const GlobalObject& aGlobal,
   2161                              const nsAString& aMessage,
   2162                              JS::Handle<JSObject*> aStack,
   2163                              JS::MutableHandle<JSObject*> aRetVal,
   2164                              ErrorResult& aRv) {
   2165  if (aStack && !JS::IsMaybeWrappedSavedFrame(aStack)) {
   2166    aRv.Throw(NS_ERROR_INVALID_ARG);
   2167    return;
   2168  }
   2169 
   2170  JSContext* cx = aGlobal.Context();
   2171 
   2172  auto cleanup = MakeScopeExit([&]() { aRv.NoteJSContextException(cx); });
   2173 
   2174  JS::Rooted<JSObject*> retVal(cx);
   2175  {
   2176    JS::Rooted<JSString*> fileName(cx, JS_GetEmptyString(cx));
   2177    uint32_t line = 0;
   2178    JS::TaggedColumnNumberOneOrigin column;
   2179 
   2180    Maybe<JSAutoRealm> ar;
   2181    JS::Rooted<JSObject*> stack(cx);
   2182    if (aStack) {
   2183      stack = UncheckedUnwrap(aStack);
   2184      ar.emplace(cx, stack);
   2185 
   2186      JSPrincipals* principals =
   2187          JS::GetRealmPrincipals(js::GetContextRealm(cx));
   2188      if (JS::GetSavedFrameLine(cx, principals, stack, &line) !=
   2189              JS::SavedFrameResult::Ok ||
   2190          JS::GetSavedFrameColumn(cx, principals, stack, &column) !=
   2191              JS::SavedFrameResult::Ok ||
   2192          JS::GetSavedFrameSource(cx, principals, stack, &fileName) !=
   2193              JS::SavedFrameResult::Ok) {
   2194        return;
   2195      }
   2196    }
   2197 
   2198    JS::Rooted<JSString*> message(cx);
   2199    {
   2200      JS::Rooted<JS::Value> msgVal(cx);
   2201      if (!xpc::NonVoidStringToJsval(cx, aMessage, &msgVal)) {
   2202        return;
   2203      }
   2204      message = msgVal.toString();
   2205    }
   2206 
   2207    JS::Rooted<JS::Value> err(cx);
   2208    if (!JS::CreateError(cx, JSEXN_ERR, stack, fileName, line,
   2209                         JS::ColumnNumberOneOrigin(column.oneOriginValue()),
   2210                         nullptr, message, JS::NothingHandleValue, &err)) {
   2211      return;
   2212    }
   2213 
   2214    MOZ_ASSERT(err.isObject());
   2215    retVal = &err.toObject();
   2216  }
   2217 
   2218  if (aStack && !JS_WrapObject(cx, &retVal)) {
   2219    return;
   2220  }
   2221 
   2222  cleanup.release();
   2223  aRetVal.set(retVal);
   2224 }
   2225 
   2226 /* static */
   2227 bool ChromeUtils::HasReportingHeaderForOrigin(GlobalObject& global,
   2228                                              const nsAString& aOrigin,
   2229                                              ErrorResult& aRv) {
   2230  if (!XRE_IsParentProcess()) {
   2231    aRv.Throw(NS_ERROR_FAILURE);
   2232    return false;
   2233  }
   2234 
   2235  return ReportingHeader::HasReportingHeaderForOrigin(
   2236      NS_ConvertUTF16toUTF8(aOrigin));
   2237 }
   2238 
   2239 /* static */
   2240 PopupBlockerState ChromeUtils::GetPopupControlState(GlobalObject& aGlobal) {
   2241  switch (PopupBlocker::GetPopupControlState()) {
   2242    case PopupBlocker::PopupControlState::openAllowed:
   2243      return PopupBlockerState::OpenAllowed;
   2244 
   2245    case PopupBlocker::PopupControlState::openControlled:
   2246      return PopupBlockerState::OpenControlled;
   2247 
   2248    case PopupBlocker::PopupControlState::openBlocked:
   2249      return PopupBlockerState::OpenBlocked;
   2250 
   2251    case PopupBlocker::PopupControlState::openAbused:
   2252      return PopupBlockerState::OpenAbused;
   2253 
   2254    case PopupBlocker::PopupControlState::openOverridden:
   2255      return PopupBlockerState::OpenOverridden;
   2256 
   2257    default:
   2258      MOZ_CRASH(
   2259          "PopupBlocker::PopupControlState and PopupBlockerState are out of "
   2260          "sync");
   2261  }
   2262 }
   2263 
   2264 /* static */
   2265 double ChromeUtils::LastExternalProtocolIframeAllowed(GlobalObject& aGlobal) {
   2266  TimeStamp when = PopupBlocker::WhenLastExternalProtocolIframeAllowed();
   2267  if (when.IsNull()) {
   2268    return 0;
   2269  }
   2270 
   2271  TimeDuration duration = TimeStamp::Now() - when;
   2272  return duration.ToMilliseconds();
   2273 }
   2274 
   2275 /* static */
   2276 void ChromeUtils::ResetLastExternalProtocolIframeAllowed(
   2277    GlobalObject& aGlobal) {
   2278  PopupBlocker::ResetLastExternalProtocolIframeAllowed();
   2279 }
   2280 
   2281 /* static */
   2282 already_AddRefed<Promise> ChromeUtils::EndWheelTransaction(
   2283    GlobalObject& aGlobal, WindowProxyHolder& aWindow, ErrorResult& aRv) {
   2284  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
   2285  MOZ_ASSERT(global);
   2286 
   2287  RefPtr<Promise> promise = Promise::Create(global, aRv);
   2288  if (aRv.Failed()) {
   2289    return nullptr;
   2290  }
   2291 
   2292  // This allows us to end the current wheel transaction from the browser
   2293  // chrome. We do not need to perform any checks before calling
   2294  // EndTransaction(), as it should do nothing in the case that there is
   2295  // no current wheel transaction.
   2296  WheelTransaction::EndTransaction();
   2297 
   2298  // We also need to end the wheel transaction in APZ.
   2299  nsIDocShell* docShell = aWindow.get()->GetDocShell();
   2300  if (!docShell) {
   2301    promise->MaybeResolveWithUndefined();
   2302    return promise.forget();
   2303  }
   2304 
   2305  nsIWidget* widget =
   2306      nsContentUtils::GetWidget(docShell->GetPresShell(), nullptr);
   2307  if (!widget) {
   2308    promise->MaybeResolveWithUndefined();
   2309    return promise.forget();
   2310  }
   2311 
   2312  WindowRenderer* renderer = widget->GetWindowRenderer();
   2313  if (!renderer) {
   2314    promise->MaybeResolveWithUndefined();
   2315    return promise.forget();
   2316  }
   2317 
   2318  layers::WebRenderLayerManager* wr = renderer->AsWebRender();
   2319  if (!wr) {
   2320    promise->MaybeResolveWithUndefined();
   2321    return promise.forget();
   2322  }
   2323 
   2324  layers::WebRenderBridgeChild* wrbc = wr->WrBridge();
   2325  if (!wrbc) {
   2326    promise->MaybeResolveWithUndefined();
   2327    return promise.forget();
   2328  }
   2329 
   2330  wrbc->SendEndWheelTransaction()->Then(
   2331      GetCurrentSerialEventTarget(), __func__,
   2332      [promise](bool) { promise->MaybeResolveWithUndefined(); },
   2333      [promise](mozilla::ipc::ResponseRejectReason) {
   2334        promise->MaybeRejectWithUnknownError(
   2335            "actor died while ending wheel transaction");
   2336      });
   2337 
   2338  return promise.forget();
   2339 }
   2340 
   2341 /* static */
   2342 void ChromeUtils::RegisterWindowActor(const GlobalObject& aGlobal,
   2343                                      const nsACString& aName,
   2344                                      const WindowActorOptions& aOptions,
   2345                                      ErrorResult& aRv) {
   2346  if (!XRE_IsParentProcess()) {
   2347    aRv.ThrowNotAllowedError(
   2348        "registerWindowActor() may only be called in the parent process");
   2349    return;
   2350  }
   2351 
   2352  RefPtr<JSActorService> service = JSActorService::GetSingleton();
   2353  service->RegisterWindowActor(aName, aOptions, aRv);
   2354 }
   2355 
   2356 /* static */
   2357 void ChromeUtils::UnregisterWindowActor(const GlobalObject& aGlobal,
   2358                                        const nsACString& aName,
   2359                                        ErrorResult& aRv) {
   2360  if (!XRE_IsParentProcess()) {
   2361    aRv.ThrowNotAllowedError(
   2362        "unregisterWindowActor() may only be called in the parent process");
   2363    return;
   2364  }
   2365 
   2366  RefPtr<JSActorService> service = JSActorService::GetSingleton();
   2367  service->UnregisterWindowActor(aName);
   2368 }
   2369 
   2370 /* static */
   2371 void ChromeUtils::RegisterProcessActor(const GlobalObject& aGlobal,
   2372                                       const nsACString& aName,
   2373                                       const ProcessActorOptions& aOptions,
   2374                                       ErrorResult& aRv) {
   2375  if (!XRE_IsParentProcess()) {
   2376    aRv.ThrowNotAllowedError(
   2377        "registerProcessActor() may only be called in the parent process");
   2378    return;
   2379  }
   2380 
   2381  RefPtr<JSActorService> service = JSActorService::GetSingleton();
   2382  service->RegisterProcessActor(aName, aOptions, aRv);
   2383 }
   2384 
   2385 /* static */
   2386 void ChromeUtils::UnregisterProcessActor(const GlobalObject& aGlobal,
   2387                                         const nsACString& aName,
   2388                                         ErrorResult& aRv) {
   2389  if (!XRE_IsParentProcess()) {
   2390    aRv.ThrowNotAllowedError(
   2391        "unregisterProcessActor() may only be called in the parent process");
   2392    return;
   2393  }
   2394 
   2395  RefPtr<JSActorService> service = JSActorService::GetSingleton();
   2396  service->UnregisterProcessActor(aName);
   2397 }
   2398 
   2399 /* static */
   2400 already_AddRefed<Promise> ChromeUtils::EnsureHeadlessContentProcess(
   2401    const GlobalObject& aGlobal, const nsACString& aRemoteType,
   2402    ErrorResult& aRv) {
   2403  if (!XRE_IsParentProcess()) {
   2404    aRv.ThrowNotAllowedError(
   2405        "ensureHeadlessContentProcess() may only be called in the parent "
   2406        "process");
   2407    return nullptr;
   2408  }
   2409 
   2410  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
   2411  RefPtr<Promise> promise = Promise::Create(global, aRv);
   2412  if (aRv.Failed()) {
   2413    return nullptr;
   2414  }
   2415 
   2416  ContentParent::GetNewOrUsedBrowserProcessAsync(aRemoteType)
   2417      ->Then(
   2418          GetCurrentSerialEventTarget(), __func__,
   2419          [promise](UniqueContentParentKeepAlive&& aKeepAlive) {
   2420            nsCOMPtr<nsIContentParentKeepAlive> jsKeepAlive =
   2421                WrapContentParentKeepAliveForJS(std::move(aKeepAlive));
   2422            promise->MaybeResolve(jsKeepAlive);
   2423          },
   2424          [promise](nsresult aError) { promise->MaybeReject(aError); });
   2425  return promise.forget();
   2426 }
   2427 
   2428 /* static */
   2429 bool ChromeUtils::IsClassifierBlockingErrorCode(GlobalObject& aGlobal,
   2430                                                uint32_t aError) {
   2431  return net::UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode(
   2432      static_cast<nsresult>(aError));
   2433 }
   2434 
   2435 /* static */
   2436 void ChromeUtils::PrivateNoteIntentionalCrash(const GlobalObject& aGlobal,
   2437                                              ErrorResult& aError) {
   2438  if (XRE_IsContentProcess()) {
   2439    NoteIntentionalCrash("tab");
   2440    return;
   2441  }
   2442  aError.Throw(NS_ERROR_NOT_IMPLEMENTED);
   2443 }
   2444 
   2445 /* static */
   2446 nsIDOMProcessChild* ChromeUtils::GetDomProcessChild(const GlobalObject&) {
   2447  return nsIDOMProcessChild::GetSingleton();
   2448 }
   2449 
   2450 /* static */
   2451 void ChromeUtils::GetAllDOMProcesses(
   2452    GlobalObject& aGlobal, nsTArray<RefPtr<nsIDOMProcessParent>>& aParents,
   2453    ErrorResult& aRv) {
   2454  if (!XRE_IsParentProcess()) {
   2455    aRv.ThrowNotAllowedError(
   2456        "getAllDOMProcesses() may only be called in the parent process");
   2457    return;
   2458  }
   2459  aParents.Clear();
   2460  // Always add the parent process nsIDOMProcessParent first
   2461  aParents.AppendElement(InProcessParent::Singleton());
   2462 
   2463  // Before adding nsIDOMProcessParent for all the content processes
   2464  for (auto* cp : ContentParent::AllProcesses(ContentParent::eLive)) {
   2465    aParents.AppendElement(cp);
   2466  }
   2467 }
   2468 
   2469 /* static */
   2470 void ChromeUtils::ConsumeInteractionData(
   2471    GlobalObject& aGlobal, Record<nsString, InteractionData>& aInteractions,
   2472    ErrorResult& aRv) {
   2473  if (!XRE_IsParentProcess()) {
   2474    aRv.ThrowNotAllowedError(
   2475        "consumeInteractionData() may only be called in the parent "
   2476        "process");
   2477    return;
   2478  }
   2479  EventStateManager::ConsumeInteractionData(aInteractions);
   2480 }
   2481 
   2482 already_AddRefed<Promise> ChromeUtils::CollectScrollingData(
   2483    GlobalObject& aGlobal, ErrorResult& aRv) {
   2484  // Creating a JS promise
   2485  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
   2486  MOZ_ASSERT(global);
   2487 
   2488  RefPtr<Promise> promise = Promise::Create(global, aRv);
   2489  if (aRv.Failed()) {
   2490    return nullptr;
   2491  }
   2492 
   2493  RefPtr<ScrollingMetrics::ScrollingMetricsPromise> extPromise =
   2494      ScrollingMetrics::CollectScrollingMetrics();
   2495 
   2496  extPromise->Then(
   2497      GetCurrentSerialEventTarget(), __func__,
   2498      [promise](const std::tuple<uint32_t, uint32_t>& aResult) {
   2499        InteractionData out = {};
   2500        out.mInteractionTimeInMilliseconds = std::get<0>(aResult);
   2501        out.mScrollingDistanceInPixels = std::get<1>(aResult);
   2502        promise->MaybeResolve(out);
   2503      },
   2504      [promise](bool aValue) { promise->MaybeReject(NS_ERROR_FAILURE); });
   2505 
   2506  return promise.forget();
   2507 }
   2508 
   2509 /* static */
   2510 void ChromeUtils::GetFormAutofillConfidences(
   2511    GlobalObject& aGlobal, const Sequence<OwningNonNull<Element>>& aElements,
   2512    nsTArray<FormAutofillConfidences>& aResults, ErrorResult& aRv) {
   2513  FormAutofillNative::GetFormAutofillConfidences(aGlobal, aElements, aResults,
   2514                                                 aRv);
   2515 }
   2516 
   2517 bool ChromeUtils::IsDarkBackground(GlobalObject&, Element& aElement) {
   2518  nsIFrame* f = aElement.GetPrimaryFrame(FlushType::Frames);
   2519  if (!f) {
   2520    return false;
   2521  }
   2522  return nsNativeTheme::IsDarkBackground(f);
   2523 }
   2524 
   2525 double ChromeUtils::DateNow(GlobalObject&) { return JS_Now() / 1000.0; }
   2526 
   2527 /* static */
   2528 double ChromeUtils::Now(GlobalObject&) {
   2529  return (TimeStamp::Now() - TimeStamp::ProcessCreation()).ToMilliseconds();
   2530 }
   2531 
   2532 /* static */
   2533 void ChromeUtils::EnsureJSOracleStarted(GlobalObject&) {
   2534  if (StaticPrefs::browser_opaqueResponseBlocking_javascriptValidator()) {
   2535    JSOracleParent::WithJSOracle([](JSOracleParent* aParent) {});
   2536  }
   2537 }
   2538 
   2539 /* static */
   2540 unsigned ChromeUtils::AliveUtilityProcesses(const GlobalObject&) {
   2541  const auto& utilityProcessManager =
   2542      mozilla::ipc::UtilityProcessManager::GetIfExists();
   2543  return utilityProcessManager ? utilityProcessManager->AliveProcesses() : 0;
   2544 }
   2545 
   2546 /* static */
   2547 void ChromeUtils::GetAllPossibleUtilityActorNames(GlobalObject& aGlobal,
   2548                                                  nsTArray<nsCString>& aNames) {
   2549  aNames.Clear();
   2550  for (UtilityActorName idlName :
   2551       MakeWebIDLEnumeratedRange<WebIDLUtilityActorName>()) {
   2552    aNames.AppendElement(GetEnumString(idlName));
   2553  }
   2554 }
   2555 
   2556 /* static */
   2557 bool ChromeUtils::ShouldResistFingerprinting(
   2558    GlobalObject& aGlobal, JSRFPTarget aTarget,
   2559    nsIRFPTargetSetIDL* aOverriddenFingerprintingSettings,
   2560    const Optional<bool>& aIsPBM) {
   2561  RFPTarget target;
   2562 #define JSRFP_TARGET_TO_RFP_TARGET(rfptarget) \
   2563  case JSRFPTarget::rfptarget:                \
   2564    target = RFPTarget::rfptarget;            \
   2565    break;
   2566  switch (aTarget) {
   2567    JSRFP_TARGET_TO_RFP_TARGET(RoundWindowSize);
   2568    JSRFP_TARGET_TO_RFP_TARGET(SiteSpecificZoom);
   2569    JSRFP_TARGET_TO_RFP_TARGET(CSSPrefersColorScheme);
   2570    JSRFP_TARGET_TO_RFP_TARGET(JSLocalePrompt);
   2571    JSRFP_TARGET_TO_RFP_TARGET(HttpUserAgent);
   2572    default:
   2573      MOZ_CRASH("Unhandled JSRFPTarget enum value");
   2574  }
   2575 #undef JSRFP_TARGET_TO_RFP_TARGET
   2576 
   2577  bool isPBM = false;
   2578  if (aIsPBM.WasPassed()) {
   2579    isPBM = aIsPBM.Value();
   2580  } else {
   2581    nsCOMPtr<nsIGlobalObject> global =
   2582        do_QueryInterface(aGlobal.GetAsSupports());
   2583    if (global) {
   2584      nsPIDOMWindowInner* win = global->GetAsInnerWindow();
   2585      if (win) {
   2586        nsIDocShell* docshell = win->GetDocShell();
   2587        if (docshell) {
   2588          nsDocShell::Cast(docshell)->GetUsePrivateBrowsing(&isPBM);
   2589        }
   2590      }
   2591    }
   2592  }
   2593 
   2594  Maybe<RFPTargetSet> overriddenFingerprintingSettings;
   2595  if (aOverriddenFingerprintingSettings) {
   2596    overriddenFingerprintingSettings.emplace(
   2597        static_cast<nsRFPTargetSetIDL*>(aOverriddenFingerprintingSettings)
   2598            ->ToRFPTargetSet());
   2599  }
   2600 
   2601  // This global object appears to be the global window, not for individual
   2602  // sites so to exempt individual sites (instead of just PBM/Not-PBM windows)
   2603  // more work would be needed to get the correct context.
   2604  return nsRFPService::IsRFPEnabledFor(isPBM, target,
   2605                                       overriddenFingerprintingSettings);
   2606 }
   2607 
   2608 /* static */
   2609 void ChromeUtils::CallFunctionAndLogException(
   2610    GlobalObject& aGlobal, JS::Handle<JS::Value> aTargetGlobal,
   2611    JS::Handle<JS::Value> aFunction, JS::MutableHandle<JS::Value> aRetVal,
   2612    ErrorResult& aRv) {
   2613  JSContext* cx = aGlobal.Context();
   2614  if (!aTargetGlobal.isObject() || !aFunction.isObject()) {
   2615    aRv.Throw(NS_ERROR_INVALID_ARG);
   2616    return;
   2617  }
   2618 
   2619  JS::Rooted<JS::Realm*> contextRealm(cx, JS::GetCurrentRealmOrNull(cx));
   2620  if (!contextRealm) {
   2621    aRv.Throw(NS_ERROR_INVALID_ARG);
   2622    return;
   2623  }
   2624 
   2625  JS::Rooted<JSObject*> global(
   2626      cx, js::CheckedUnwrapDynamic(&aTargetGlobal.toObject(), cx));
   2627  if (!global) {
   2628    aRv.Throw(NS_ERROR_INVALID_ARG);
   2629    return;
   2630  }
   2631 
   2632  // Use AutoJSAPI in order to trigger AutoJSAPI::ReportException
   2633  // which will do most of the work required for this function.
   2634  //
   2635  // We only have to pick the right global for which we want to flag
   2636  // the exception against.
   2637  dom::AutoJSAPI jsapi;
   2638  if (!jsapi.Init(global)) {
   2639    aRv.Throw(NS_ERROR_UNEXPECTED);
   2640    return;
   2641  }
   2642  JSContext* ccx = jsapi.cx();
   2643 
   2644  // AutoJSAPI picks `aTargetGlobal` as execution compartment
   2645  // whereas we expect to run `aFunction` from the callsites compartment.
   2646  JSAutoRealm ar(ccx, JS::GetRealmGlobalOrNull(contextRealm));
   2647 
   2648  JS::Rooted<JS::Value> funVal(ccx, aFunction);
   2649  if (!JS_WrapValue(ccx, &funVal)) {
   2650    aRv.Throw(NS_ERROR_FAILURE);
   2651    return;
   2652  }
   2653  if (!JS_CallFunctionValue(ccx, nullptr, funVal, JS::HandleValueArray::empty(),
   2654                            aRetVal)) {
   2655    // Ensure re-throwing the exception which may have been thrown by
   2656    // `aFunction`
   2657    if (JS_IsExceptionPending(ccx)) {
   2658      JS::Rooted<JS::Value> exception(cx);
   2659      if (JS_GetPendingException(ccx, &exception)) {
   2660        if (JS_WrapValue(cx, &exception)) {
   2661          aRv.MightThrowJSException();
   2662          aRv.ThrowJSException(cx, exception);
   2663        }
   2664      }
   2665    }
   2666  }
   2667 }
   2668 
   2669 static Atomic<uint32_t, Relaxed> sDevToolsOpenedCount{0};
   2670 
   2671 /* static */
   2672 bool ChromeUtils::IsDevToolsOpened() { return sDevToolsOpenedCount > 0; }
   2673 
   2674 /* static */
   2675 bool ChromeUtils::IsDevToolsOpened(GlobalObject& aGlobal) {
   2676  return IsDevToolsOpened();
   2677 }
   2678 
   2679 /* static */
   2680 void ChromeUtils::NotifyDevToolsOpened(GlobalObject& aGlobal) {
   2681  sDevToolsOpenedCount++;
   2682 }
   2683 
   2684 /* static */
   2685 void ChromeUtils::NotifyDevToolsClosed(GlobalObject& aGlobal) {
   2686  MOZ_ASSERT(sDevToolsOpenedCount >= 1);
   2687  sDevToolsOpenedCount--;
   2688 }
   2689 
   2690 /* static */
   2691 bool ChromeUtils::IsJSIdentifier(GlobalObject& aGlobal, const nsAString& aStr) {
   2692  return JS_IsIdentifier(aStr.BeginReading(), aStr.Length());
   2693 }
   2694 
   2695 #ifdef MOZ_WMF_CDM
   2696 /* static */
   2697 already_AddRefed<Promise> ChromeUtils::GetWMFContentDecryptionModuleInformation(
   2698    GlobalObject& aGlobal, ErrorResult& aRv) {
   2699  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
   2700  MOZ_ASSERT(global);
   2701  RefPtr<Promise> domPromise = Promise::Create(global, aRv);
   2702  if (NS_WARN_IF(aRv.Failed())) {
   2703    return nullptr;
   2704  }
   2705  MOZ_ASSERT(domPromise);
   2706  MFCDMService::GetAllKeySystemsCapabilities(domPromise);
   2707  return domPromise.forget();
   2708 }
   2709 #endif
   2710 
   2711 already_AddRefed<Promise> ChromeUtils::GetGMPContentDecryptionModuleInformation(
   2712    GlobalObject& aGlobal, ErrorResult& aRv) {
   2713  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
   2714  MOZ_ASSERT(global);
   2715  RefPtr<Promise> domPromise = Promise::Create(global, aRv);
   2716  if (NS_WARN_IF(aRv.Failed())) {
   2717    return nullptr;
   2718  }
   2719  MOZ_ASSERT(domPromise);
   2720  KeySystemConfig::GetGMPKeySystemConfigs(domPromise);
   2721  return domPromise.forget();
   2722 }
   2723 
   2724 void ChromeUtils::AndroidMoveTaskToBack(GlobalObject& aGlobal) {
   2725 #ifdef MOZ_WIDGET_ANDROID
   2726  MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
   2727  java::GeckoAppShell::MoveTaskToBack();
   2728 #endif
   2729 }
   2730 
   2731 already_AddRefed<nsIContentSecurityPolicy> ChromeUtils::CreateCSPFromHeader(
   2732    GlobalObject& aGlobal, const nsAString& aHeader, nsIURI* aSelfURI,
   2733    nsIPrincipal* aLoadingPrincipal, ErrorResult& aRv) {
   2734  return CSP_CreateFromHeader(aHeader, aSelfURI, aLoadingPrincipal, aRv);
   2735 }
   2736 
   2737 Nullable<bool> ChromeUtils::GetGlobalWindowCommandEnabled(
   2738    GlobalObject&, const nsACString& aName) {
   2739  const auto* table = nsControllerCommandTable::WindowCommandTable();
   2740  RefPtr handler = table->FindCommandHandler(aName);
   2741  if (!handler) {
   2742    return nullptr;
   2743  }
   2744  return handler->IsCommandEnabled(aName, nullptr);
   2745 }
   2746 
   2747 already_AddRefed<Promise> ChromeUtils::FetchDecodedImage(GlobalObject& aGlobal,
   2748                                                         nsIURI* aURI,
   2749                                                         nsIChannel* aChannel,
   2750                                                         ErrorResult& aRv) {
   2751  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
   2752  MOZ_ASSERT(global);
   2753  RefPtr<Promise> domPromise = Promise::Create(global, aRv);
   2754  if (NS_WARN_IF(aRv.Failed())) {
   2755    return nullptr;
   2756  }
   2757 
   2758  image::FetchDecodedImage(aURI, aChannel, gfx::IntSize{})
   2759      ->Then(
   2760          GetCurrentSerialEventTarget(), __func__,
   2761          [global, domPromise](already_AddRefed<imgIContainer> aImage) {
   2762            nsCOMPtr<imgIContainer> image(std::move(aImage));
   2763 
   2764            AutoJSAPI jsapi;
   2765            if (!jsapi.Init(global)) {
   2766              domPromise->MaybeRejectWithUndefined();
   2767              return;
   2768            }
   2769 
   2770            JS::Rooted<JS::Value> value(jsapi.cx());
   2771            if (!WrapObject(jsapi.cx(), image, &NS_GET_IID(imgIContainer),
   2772                            &value)) {
   2773              domPromise->MaybeRejectWithUndefined();
   2774              return;
   2775            }
   2776 
   2777            domPromise->MaybeResolve(value);
   2778          },
   2779          [domPromise](nsresult aStatus) { domPromise->MaybeReject(aStatus); });
   2780 
   2781  return domPromise.forget();
   2782 }
   2783 
   2784 void ChromeUtils::EncodeURIForSrcset(GlobalObject&, const nsACString& aIn,
   2785                                     nsACString& aOut) {
   2786  const auto inputLen = aIn.Length();
   2787  if (!inputLen) {
   2788    return;
   2789  }
   2790  size_t start = 0;
   2791  while (true) {
   2792    auto idx = aIn.View().find_first_of(nsContentUtils::kHTMLWhitespace, start);
   2793    if (idx == std::string_view::npos) {
   2794      break;
   2795    }
   2796    aOut.Append(Substring(aIn, start, idx - start));
   2797    aOut.AppendPrintf("%%%x", aIn.CharAt(idx));
   2798    start = idx + 1;
   2799    if (start == inputLen) {
   2800      return;
   2801    }
   2802  }
   2803  if (start == 0) {
   2804    aOut.Assign(aIn);
   2805  } else {
   2806    aOut.Append(Substring(aIn, start));
   2807  }
   2808 }
   2809 
   2810 void ChromeUtils::GetLastOOMStackTrace(GlobalObject& aGlobal,
   2811                                       nsAString& aRetval) {
   2812  JSContext* cx = aGlobal.Context();
   2813  aRetval = NS_ConvertUTF8toUTF16(JS_GetLastOOMStackTrace(cx));
   2814 }
   2815 
   2816 }  // namespace mozilla::dom