tor-browser

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

GPUProcessHost.cpp (10360B)


      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 "GPUProcessHost.h"
      8 #include "chrome/common/process_watcher.h"
      9 #include "gfxPlatform.h"
     10 #include "mozilla/dom/ContentParent.h"
     11 #include "mozilla/gfx/GPUChild.h"
     12 #include "mozilla/gfx/Logging.h"
     13 #include "mozilla/layers/SynchronousTask.h"
     14 #include "mozilla/Preferences.h"
     15 #include "mozilla/StaticPrefs_layers.h"
     16 #include "VRGPUChild.h"
     17 #include "mozilla/ipc/ProcessUtils.h"
     18 #ifdef MOZ_WIDGET_ANDROID
     19 #  include "mozilla/java/GeckoProcessManagerWrappers.h"
     20 #endif
     21 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
     22 #  include "mozilla/SandboxSettings.h"
     23 #endif
     24 
     25 namespace mozilla {
     26 namespace gfx {
     27 
     28 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
     29 bool GPUProcessHost::sLaunchWithMacSandbox = false;
     30 #endif
     31 
     32 using namespace ipc;
     33 
     34 GPUProcessHost::GPUProcessHost(Listener* aListener)
     35    : GeckoChildProcessHost(GeckoProcessType_GPU),
     36      mListener(aListener),
     37      mLaunchPhase(LaunchPhase::Unlaunched),
     38      mProcessToken(0),
     39      mShutdownRequested(false),
     40      mChannelClosed(false),
     41      mLiveToken(new media::Refcountable<bool>(true)) {
     42  MOZ_COUNT_CTOR(GPUProcessHost);
     43 
     44 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
     45  if (!sLaunchWithMacSandbox) {
     46    sLaunchWithMacSandbox = IsGPUSandboxEnabled();
     47  }
     48  mDisableOSActivityMode = sLaunchWithMacSandbox;
     49 #endif
     50 }
     51 
     52 GPUProcessHost::~GPUProcessHost() { MOZ_COUNT_DTOR(GPUProcessHost); }
     53 
     54 bool GPUProcessHost::Launch(geckoargs::ChildProcessArgs aExtraOpts) {
     55  MOZ_ASSERT(mLaunchPhase == LaunchPhase::Unlaunched);
     56  MOZ_ASSERT(!mGPUChild);
     57  MOZ_ASSERT(!gfxPlatform::IsHeadless());
     58 
     59  mPrefSerializer = MakeUnique<ipc::SharedPreferenceSerializer>();
     60  if (!mPrefSerializer->SerializeToSharedMemory(GeckoProcessType_GPU,
     61                                                /* remoteType */ ""_ns)) {
     62    return false;
     63  }
     64  mPrefSerializer->AddSharedPrefCmdLineArgs(*this, aExtraOpts);
     65 
     66 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
     67  mSandboxLevel = Preferences::GetInt("security.sandbox.gpu.level");
     68 #endif
     69 
     70  mLaunchPhase = LaunchPhase::Waiting;
     71  mLaunchTime = TimeStamp::Now();
     72 
     73  if (!GeckoChildProcessHost::AsyncLaunch(std::move(aExtraOpts))) {
     74    mLaunchPhase = LaunchPhase::Complete;
     75    mPrefSerializer = nullptr;
     76    return false;
     77  }
     78  return true;
     79 }
     80 
     81 bool GPUProcessHost::WaitForLaunch() {
     82  MOZ_ASSERT(mLaunchPhase != LaunchPhase::Unlaunched);
     83  if (mLaunchPhase == LaunchPhase::Complete) {
     84    return !!mGPUChild;
     85  }
     86 
     87  int32_t timeoutMs =
     88      StaticPrefs::layers_gpu_process_startup_timeout_ms_AtStartup();
     89 
     90  // If one of the following environment variables are set we can effectively
     91  // ignore the timeout - as we can guarantee the compositor process will be
     92  // terminated
     93  if (PR_GetEnv("MOZ_DEBUG_CHILD_PROCESS") ||
     94      PR_GetEnv("MOZ_DEBUG_CHILD_PAUSE")) {
     95    timeoutMs = 0;
     96  }
     97 
     98  if (mLaunchPhase == LaunchPhase::Waiting) {
     99    // Our caller expects the connection to be finished by the time we return,
    100    // so we immediately set up the IPDL actor and fire callbacks. The IO thread
    101    // will still dispatch a notification to the main thread - we'll just ignore
    102    // it.
    103    bool result = GeckoChildProcessHost::WaitUntilConnected(timeoutMs);
    104    InitAfterConnect(result);
    105    if (!result) {
    106      return false;
    107    }
    108  }
    109  MOZ_ASSERT(mLaunchPhase == LaunchPhase::Connected);
    110  // Our caller expects post-connection initialization tasks, such as ensuring
    111  // the GPUChild is initialized, to be finished by the time we return, so
    112  // finish these tasks synchronously now.
    113  return CompleteInitSynchronously();
    114 }
    115 
    116 void GPUProcessHost::OnChannelConnected(base::ProcessId peer_pid) {
    117  MOZ_ASSERT(!NS_IsMainThread());
    118 
    119  GeckoChildProcessHost::OnChannelConnected(peer_pid);
    120 
    121  NS_DispatchToMainThread(NS_NewRunnableFunction(
    122      "GPUProcessHost::OnChannelConnected",
    123      [self = this, liveToken = mLiveToken]() {
    124        if (*liveToken && self->mLaunchPhase == LaunchPhase::Waiting) {
    125          self->InitAfterConnect(true);
    126        }
    127      }));
    128 }
    129 
    130 static uint64_t sProcessTokenCounter = 0;
    131 
    132 void GPUProcessHost::InitAfterConnect(bool aSucceeded) {
    133  MOZ_ASSERT(mLaunchPhase == LaunchPhase::Waiting);
    134  MOZ_ASSERT(!mGPUChild);
    135 
    136  mPrefSerializer = nullptr;
    137 
    138  if (aSucceeded) {
    139    mLaunchPhase = LaunchPhase::Connected;
    140    mProcessToken = ++sProcessTokenCounter;
    141    mGPUChild = MakeRefPtr<GPUChild>(this);
    142    DebugOnly<bool> rv = TakeInitialEndpoint().Bind(mGPUChild.get());
    143    MOZ_ASSERT(rv);
    144 
    145    nsTArray<RefPtr<GPUChild::InitPromiseType>> initPromises;
    146    initPromises.AppendElement(mGPUChild->Init());
    147 
    148 #ifdef MOZ_WIDGET_ANDROID
    149    nsCOMPtr<nsISerialEventTarget> launcherThread(GetIPCLauncher());
    150    MOZ_ASSERT(launcherThread);
    151    RefPtr<GPUChild::InitPromiseType> csmPromise =
    152        InvokeAsync(
    153            launcherThread, __func__,
    154            [] {
    155              java::CompositorSurfaceManager::LocalRef csm =
    156                  java::GeckoProcessManager::GetCompositorSurfaceManager();
    157              return MozPromise<java::CompositorSurfaceManager::GlobalRef, Ok,
    158                                true>::CreateAndResolve(csm, __func__);
    159            })
    160            ->Map(GetCurrentSerialEventTarget(), __func__,
    161                  [self = this, liveToken = mLiveToken](
    162                      java::CompositorSurfaceManager::GlobalRef&& aCsm) {
    163                    if (*liveToken) {
    164                      self->mCompositorSurfaceManager = aCsm;
    165                    }
    166                    return Ok{};
    167                  });
    168    initPromises.AppendElement(csmPromise);
    169 #endif
    170 
    171    GPUChild::InitPromiseType::All(GetCurrentSerialEventTarget(), initPromises)
    172        ->Then(GetCurrentSerialEventTarget(), __func__,
    173               [self = this, liveToken = mLiveToken]() {
    174                 if (*liveToken) {
    175                   self->OnAsyncInitComplete();
    176                 }
    177               });
    178  } else {
    179    mLaunchPhase = LaunchPhase::Complete;
    180    if (mListener) {
    181      mListener->OnProcessLaunchComplete(this);
    182    }
    183  }
    184 }
    185 
    186 void GPUProcessHost::OnAsyncInitComplete() {
    187  MOZ_ASSERT(NS_IsMainThread());
    188  if (mLaunchPhase == LaunchPhase::Connected) {
    189    mLaunchPhase = LaunchPhase::Complete;
    190    if (mListener) {
    191      mListener->OnProcessLaunchComplete(this);
    192    }
    193  }
    194 }
    195 
    196 bool GPUProcessHost::CompleteInitSynchronously() {
    197  MOZ_ASSERT(mLaunchPhase == LaunchPhase::Connected);
    198 
    199  const bool result = mGPUChild->EnsureGPUReady();
    200 
    201 #ifdef MOZ_WIDGET_ANDROID
    202  if (!mCompositorSurfaceManager) {
    203    layers::SynchronousTask task(
    204        "GeckoProcessManager::GetCompositorSurfaceManager");
    205 
    206    nsCOMPtr<nsIEventTarget> launcherThread(GetIPCLauncher());
    207    MOZ_ASSERT(launcherThread);
    208    launcherThread->Dispatch(NS_NewRunnableFunction(
    209        "GeckoProcessManager::GetCompositorSurfaceManager", [&]() {
    210          layers::AutoCompleteTask complete(&task);
    211          mCompositorSurfaceManager =
    212              java::GeckoProcessManager::GetCompositorSurfaceManager();
    213        }));
    214 
    215    task.Wait();
    216  }
    217 #endif
    218 
    219  mLaunchPhase = LaunchPhase::Complete;
    220  if (mListener) {
    221    mListener->OnProcessLaunchComplete(this);
    222  }
    223 
    224  return result;
    225 }
    226 
    227 void GPUProcessHost::Shutdown(bool aUnexpectedShutdown) {
    228  MOZ_ASSERT(!mShutdownRequested);
    229 
    230  mListener = nullptr;
    231 
    232  if (mGPUChild) {
    233    // OnChannelClosed uses this to check if the shutdown was expected or
    234    // unexpected.
    235    mShutdownRequested = true;
    236 
    237    if (aUnexpectedShutdown) {
    238      mGPUChild->OnUnexpectedShutdown();
    239    }
    240 
    241    // The channel might already be closed if we got here unexpectedly.
    242    if (!mChannelClosed) {
    243      if (VRGPUChild::IsCreated()) {
    244        VRGPUChild::Get()->Close();
    245      }
    246      mGPUChild->SendShutdownVR();
    247      mGPUChild->Close();
    248    }
    249 
    250 #ifndef NS_FREE_PERMANENT_DATA
    251    // No need to communicate shutdown, the GPU process doesn't need to
    252    // communicate anything back.
    253    KillHard(/* aGenerateMinidump */ false);
    254 #endif
    255 
    256    // If we're shutting down unexpectedly, we're in the middle of handling an
    257    // ActorDestroy for PGPUChild, which is still on the stack. We'll return
    258    // back to OnChannelClosed.
    259    //
    260    // Otherwise, we'll wait for OnChannelClose to be called whenever PGPUChild
    261    // acknowledges shutdown.
    262    return;
    263  }
    264 
    265  DestroyProcess();
    266 }
    267 
    268 void GPUProcessHost::OnChannelClosed() {
    269  mChannelClosed = true;
    270 
    271  if (!mShutdownRequested && mListener) {
    272    // This is an unclean shutdown. Notify our listener that we're going away.
    273    mListener->OnProcessUnexpectedShutdown(this);
    274  } else {
    275    DestroyProcess();
    276  }
    277 
    278  // Release the actor.
    279  GPUChild::Destroy(std::move(mGPUChild));
    280  MOZ_ASSERT(!mGPUChild);
    281 }
    282 
    283 void GPUProcessHost::KillHard(bool aGenerateMinidump) {
    284  MOZ_ASSERT(NS_IsMainThread());
    285 
    286  if (mGPUChild && aGenerateMinidump) {
    287    mGPUChild->GeneratePairedMinidump();
    288  }
    289 
    290  const ProcessHandle handle = GetChildProcessHandle();
    291  if (!base::KillProcess(handle, base::PROCESS_END_KILLED_BY_USER)) {
    292    if (mGPUChild) {
    293      mGPUChild->DeletePairedMinidump();
    294    }
    295    NS_WARNING("failed to kill subprocess!");
    296  }
    297 
    298  SetAlreadyDead();
    299 }
    300 
    301 uint64_t GPUProcessHost::GetProcessToken() const { return mProcessToken; }
    302 
    303 void GPUProcessHost::KillProcess(bool aGenerateMinidump) {
    304  KillHard(aGenerateMinidump);
    305 }
    306 
    307 void GPUProcessHost::CrashProcess() { mGPUChild->SendCrashProcess(); }
    308 
    309 void GPUProcessHost::DestroyProcess() {
    310  MOZ_ASSERT(NS_IsMainThread());
    311 
    312  // Any pending tasks will be cancelled from now on.
    313  *mLiveToken = false;
    314 
    315  NS_DispatchToMainThread(
    316      NS_NewRunnableFunction("DestroyProcessRunnable", [this] { Destroy(); }));
    317 }
    318 
    319 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
    320 bool GPUProcessHost::FillMacSandboxInfo(MacSandboxInfo& aInfo) {
    321  GeckoChildProcessHost::FillMacSandboxInfo(aInfo);
    322  if (!aInfo.shouldLog && PR_GetEnv("MOZ_SANDBOX_GPU_LOGGING")) {
    323    aInfo.shouldLog = true;
    324  }
    325  aInfo.type = MacSandboxType::MacSandboxType_GPU;
    326  return true;
    327 }
    328 #endif
    329 
    330 #ifdef MOZ_WIDGET_ANDROID
    331 java::CompositorSurfaceManager::Param
    332 GPUProcessHost::GetCompositorSurfaceManager() {
    333  return mCompositorSurfaceManager;
    334 }
    335 #endif
    336 
    337 }  // namespace gfx
    338 }  // namespace mozilla