Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/gfx/ipc/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 11 kB image not shown  

Quelle  GPUProcessHost.cpp

  Sprache: C
 

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "GPUProcessHost.h"
#include "chrome/common/process_watcher.h"
#include "gfxPlatform.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/gfx/GPUChild.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/layers/SynchronousTask.h"
#include "mozilla/Preferences.h"
#include "mozilla/StaticPrefs_layers.h"
#include "VRGPUChild.h"
#include "mozilla/ipc/ProcessUtils.h"
#ifdef MOZ_WIDGET_ANDROID
#  include "mozilla/java/GeckoProcessManagerWrappers.h"
#endif
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
#  include "mozilla/SandboxSettings.h"
#endif
#ifdef XP_WIN
#  include <windows.h>
#endif

namespace mozilla {
namespace gfx {

#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
bool GPUProcessHost::sLaunchWithMacSandbox = false;
#endif

using namespace ipc;

GPUProcessHost::GPUProcessHost(Listener* aListener)
    : GeckoChildProcessHost(GeckoProcessType_GPU),
      mListener(aListener),
      mLaunchPhase(LaunchPhase::Unlaunched),
      mProcessToken(0),
      mShutdownRequested(false),
      mChannelClosed(false),
      mLiveToken(new media::Refcountable<bool>(true)) {
  MOZ_COUNT_CTOR(GPUProcessHost);

#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
  if (!sLaunchWithMacSandbox) {
    sLaunchWithMacSandbox = IsGPUSandboxEnabled();
  }
  mDisableOSActivityMode = sLaunchWithMacSandbox;
#endif
}

GPUProcessHost::~GPUProcessHost() { MOZ_COUNT_DTOR(GPUProcessHost); }

bool GPUProcessHost::Launch(geckoargs::ChildProcessArgs aExtraOpts) {
  MOZ_ASSERT(mLaunchPhase == LaunchPhase::Unlaunched);
  MOZ_ASSERT(!mGPUChild);
  MOZ_ASSERT(!gfxPlatform::IsHeadless());

  mPrefSerializer = MakeUnique<ipc::SharedPreferenceSerializer>();
  if (!mPrefSerializer->SerializeToSharedMemory(GeckoProcessType_GPU,
                                                /* remoteType */ ""_ns)) {
    return false;
  }
  mPrefSerializer->AddSharedPrefCmdLineArgs(*this, aExtraOpts);

#if defined(XP_WIN) && defined(MOZ_SANDBOX)
  mSandboxLevel = Preferences::GetInt("security.sandbox.gpu.level");
#endif

  mLaunchPhase = LaunchPhase::Waiting;
  mLaunchTime = TimeStamp::Now();

  if (!GeckoChildProcessHost::AsyncLaunch(std::move(aExtraOpts))) {
    mLaunchPhase = LaunchPhase::Complete;
    mPrefSerializer = nullptr;
    return false;
  }

  return true;
}

bool GPUProcessHost::WaitForLaunch() {
  MOZ_ASSERT(mLaunchPhase != LaunchPhase::Unlaunched);
  if (mLaunchPhase == LaunchPhase::Complete) {
    return !!mGPUChild;
  }

  int32_t timeoutMs =
      StaticPrefs::layers_gpu_process_startup_timeout_ms_AtStartup();

  // If one of the following environment variables are set we can effectively
  // ignore the timeout - as we can guarantee the compositor process will be
  // terminated
  if (PR_GetEnv("MOZ_DEBUG_CHILD_PROCESS") ||
      PR_GetEnv("MOZ_DEBUG_CHILD_PAUSE")) {
    timeoutMs = 0;
  }

  if (mLaunchPhase == LaunchPhase::Waiting) {
    // Our caller expects the connection to be finished by the time we return,
    // so we immediately set up the IPDL actor and fire callbacks. The IO thread
    // will still dispatch a notification to the main thread - we'll just ignore
    // it.
    bool result = GeckoChildProcessHost::WaitUntilConnected(timeoutMs);
    InitAfterConnect(result);
    if (!result) {
      return false;
    }
  }
  MOZ_ASSERT(mLaunchPhase == LaunchPhase::Connected);
  // Our caller expects post-connection initialization tasks, such as ensuring
  // the GPUChild is initialized, to be finished by the time we return, so
  // finish these tasks synchronously now.
  return CompleteInitSynchronously();
}

void GPUProcessHost::OnProcessLaunchError(const base::LaunchError aError) {
  bool oom = false;
#ifdef XP_WIN
  static const size_t kLowMemoryThreshold = 1024 * 1024 * 1024;

  MEMORYSTATUSEX stat;
  switch (aError.ErrorCode()) {
    case ERROR_NOT_ENOUGH_MEMORY:
    case ERROR_OUTOFMEMORY:
    case ERROR_DEVICE_NO_RESOURCES:
    case ERROR_COMMITMENT_LIMIT:
      oom = true;
      break;
    default:
      // It could fail for many reasons but if it isn't an explicit memory
      // failure, but we are low on memory, it is probably due to OOM.
      stat.dwLength = sizeof(stat);
      oom = GlobalMemoryStatusEx(&stat) &&
            (stat.ullAvailVirtual < kLowMemoryThreshold ||
             stat.ullAvailPhys < kLowMemoryThreshold);
      break;
  }
#endif

  gfxCriticalNote << "GPU proc launch error " << aError.FunctionName().get()
                  << (oom ? " OOM " : " ") << gfx::hexa(aError.ErrorCode());

  MonitorAutoLock lock(mMonitor);
  mProcessState = PROCESS_ERROR;
  mLaunchOomError = oom;
  lock.Notify();
}

void GPUProcessHost::OnChannelConnected(base::ProcessId peer_pid) {
  MOZ_ASSERT(!NS_IsMainThread());

  GeckoChildProcessHost::OnChannelConnected(peer_pid);

  NS_DispatchToMainThread(NS_NewRunnableFunction(
      "GPUProcessHost::OnChannelConnected",
      [self = this, liveToken = mLiveToken]() {
        if (*liveToken && self->mLaunchPhase == LaunchPhase::Waiting) {
          self->InitAfterConnect(true);
        }
      }));
}

static uint64_t sProcessTokenCounter = 0;

void GPUProcessHost::InitAfterConnect(bool aSucceeded) {
  MOZ_ASSERT(mLaunchPhase == LaunchPhase::Waiting);
  MOZ_ASSERT(!mGPUChild);

  mPrefSerializer = nullptr;

  if (aSucceeded) {
    mLaunchPhase = LaunchPhase::Connected;
    mProcessToken = ++sProcessTokenCounter;
    mGPUChild = MakeRefPtr<GPUChild>(this);
    DebugOnly<bool> rv = TakeInitialEndpoint().Bind(mGPUChild.get());
    MOZ_ASSERT(rv);

    nsTArray<RefPtr<GPUChild::InitPromiseType>> initPromises;
    initPromises.AppendElement(mGPUChild->Init());

#ifdef MOZ_WIDGET_ANDROID
    nsCOMPtr<nsISerialEventTarget> launcherThread(GetIPCLauncher());
    MOZ_ASSERT(launcherThread);
    RefPtr<GPUChild::InitPromiseType> csmPromise =
        InvokeAsync(
            launcherThread, __func__,
            [] {
              java::CompositorSurfaceManager::LocalRef csm =
                  java::GeckoProcessManager::GetCompositorSurfaceManager();
              return MozPromise<java::CompositorSurfaceManager::GlobalRef, Ok,
                                true>::CreateAndResolve(csm, __func__);
            })
            ->Map(GetCurrentSerialEventTarget(), __func__,
                  [self = this, liveToken = mLiveToken](
                      java::CompositorSurfaceManager::GlobalRef&& aCsm) {
                    if (*liveToken) {
                      self->mCompositorSurfaceManager = aCsm;
                    }
                    return Ok{};
                  });
    initPromises.AppendElement(csmPromise);
#endif

    GPUChild::InitPromiseType::All(GetCurrentSerialEventTarget(), initPromises)
        ->Then(GetCurrentSerialEventTarget(), __func__,
               [self = this, liveToken = mLiveToken]() {
                 if (*liveToken) {
                   self->OnAsyncInitComplete();
                 }
               });
  } else {
    mLaunchPhase = LaunchPhase::Complete;
    if (mListener) {
      mListener->OnProcessLaunchComplete(this);
    }
  }
}

void GPUProcessHost::OnAsyncInitComplete() {
  MOZ_ASSERT(NS_IsMainThread());
  if (mLaunchPhase == LaunchPhase::Connected) {
    mLaunchPhase = LaunchPhase::Complete;
    if (mListener) {
      mListener->OnProcessLaunchComplete(this);
    }
  }
}

bool GPUProcessHost::CompleteInitSynchronously() {
  MOZ_ASSERT(mLaunchPhase == LaunchPhase::Connected);

  const bool result = mGPUChild->EnsureGPUReady();

#ifdef MOZ_WIDGET_ANDROID
  if (!mCompositorSurfaceManager) {
    layers::SynchronousTask task(
        "GeckoProcessManager::GetCompositorSurfaceManager");

    nsCOMPtr<nsIEventTarget> launcherThread(GetIPCLauncher());
    MOZ_ASSERT(launcherThread);
    launcherThread->Dispatch(NS_NewRunnableFunction(
        "GeckoProcessManager::GetCompositorSurfaceManager", [&]() {
          layers::AutoCompleteTask complete(&task);
          mCompositorSurfaceManager =
              java::GeckoProcessManager::GetCompositorSurfaceManager();
        }));

    task.Wait();
  }
#endif

  mLaunchPhase = LaunchPhase::Complete;
  if (mListener) {
    mListener->OnProcessLaunchComplete(this);
  }

  return result;
}

void GPUProcessHost::Shutdown(bool aUnexpectedShutdown) {
  MOZ_ASSERT(!mShutdownRequested);

  mListener = nullptr;

  if (mGPUChild) {
    // OnChannelClosed uses this to check if the shutdown was expected or
    // unexpected.
    mShutdownRequested = true;

    if (aUnexpectedShutdown) {
      mGPUChild->OnUnexpectedShutdown();
    }

    // The channel might already be closed if we got here unexpectedly.
    if (!mChannelClosed) {
      if (VRGPUChild::IsCreated()) {
        VRGPUChild::Get()->Close();
      }
      mGPUChild->SendShutdownVR();
      mGPUChild->Close();
    }

#ifndef NS_FREE_PERMANENT_DATA
    // No need to communicate shutdown, the GPU process doesn't need to
    // communicate anything back.
    KillHard(/* aGenerateMinidump */ false);
#endif

    // If we're shutting down unexpectedly, we're in the middle of handling an
    // ActorDestroy for PGPUChild, which is still on the stack. We'll return
    // back to OnChannelClosed.
    //
    // Otherwise, we'll wait for OnChannelClose to be called whenever PGPUChild
    // acknowledges shutdown.
    return;
  }

  DestroyProcess();
}

void GPUProcessHost::OnChannelClosed() {
  mChannelClosed = true;

  if (!mShutdownRequested && mListener) {
    // This is an unclean shutdown. Notify our listener that we're going away.
    mListener->OnProcessUnexpectedShutdown(this);
  } else {
    DestroyProcess();
  }

  // Release the actor.
  GPUChild::Destroy(std::move(mGPUChild));
  MOZ_ASSERT(!mGPUChild);
}

void GPUProcessHost::KillHard(bool aGenerateMinidump) {
  MOZ_ASSERT(NS_IsMainThread());

  if (mGPUChild && aGenerateMinidump) {
    mGPUChild->GeneratePairedMinidump();
  }

  const ProcessHandle handle = GetChildProcessHandle();
  if (!base::KillProcess(handle, base::PROCESS_END_KILLED_BY_USER)) {
    if (mGPUChild) {
      mGPUChild->DeletePairedMinidump();
    }
    NS_WARNING("failed to kill subprocess!");
  }

  SetAlreadyDead();
}

uint64_t GPUProcessHost::GetProcessToken() const { return mProcessToken; }

void GPUProcessHost::KillProcess(bool aGenerateMinidump) {
  KillHard(aGenerateMinidump);
}

void GPUProcessHost::CrashProcess() { mGPUChild->SendCrashProcess(); }

void GPUProcessHost::DestroyProcess() {
  MOZ_ASSERT(NS_IsMainThread());

  // Any pending tasks will be cancelled from now on.
  *mLiveToken = false;

  NS_DispatchToMainThread(
      NS_NewRunnableFunction("DestroyProcessRunnable", [this] { Destroy(); }));
}

#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
bool GPUProcessHost::FillMacSandboxInfo(MacSandboxInfo& aInfo) {
  GeckoChildProcessHost::FillMacSandboxInfo(aInfo);
  if (!aInfo.shouldLog && PR_GetEnv("MOZ_SANDBOX_GPU_LOGGING")) {
    aInfo.shouldLog = true;
  }
  aInfo.type = MacSandboxType::MacSandboxType_GPU;
  return true;
}
#endif

#ifdef MOZ_WIDGET_ANDROID
java::CompositorSurfaceManager::Param
GPUProcessHost::GetCompositorSurfaceManager() {
  return mCompositorSurfaceManager;
}
#endif

}  // namespace gfx
}  // namespace mozilla

Messung V0.5 in Prozent
C=89 H=95 G=91

¤ Dauer der Verarbeitung: 0.17 Sekunden  (vorverarbeitet am  2026-08-25) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.