2018-11-14 21:06:24 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
|
|
/* 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 "RDDProcessManager.h"
|
|
|
|
|
2020-09-18 14:07:18 +03:00
|
|
|
#include "RDDChild.h"
|
|
|
|
#include "RDDProcessHost.h"
|
2018-11-26 17:49:44 +03:00
|
|
|
#include "mozilla/MemoryReportingProcess.h"
|
2020-09-18 14:07:18 +03:00
|
|
|
#include "mozilla/Preferences.h"
|
2018-11-14 21:06:24 +03:00
|
|
|
#include "mozilla/RemoteDecoderManagerChild.h"
|
|
|
|
#include "mozilla/RemoteDecoderManagerParent.h"
|
2019-07-26 04:10:23 +03:00
|
|
|
#include "mozilla/StaticPrefs_media.h"
|
2020-10-21 02:32:54 +03:00
|
|
|
#include "mozilla/SyncRunnable.h" // for LaunchRDDProcess
|
2019-05-25 13:12:47 +03:00
|
|
|
#include "mozilla/dom/ContentParent.h"
|
2019-11-04 06:41:57 +03:00
|
|
|
#include "mozilla/gfx/GPUProcessManager.h"
|
2020-11-23 19:06:42 +03:00
|
|
|
#include "mozilla/ipc/Endpoint.h"
|
2020-09-18 14:03:48 +03:00
|
|
|
#include "mozilla/layers/CompositorThread.h"
|
2020-09-18 14:07:18 +03:00
|
|
|
#include "mozilla/layers/VideoBridgeParent.h"
|
2018-11-14 21:06:24 +03:00
|
|
|
#include "nsAppRunner.h"
|
|
|
|
#include "nsContentUtils.h"
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
2019-11-04 06:41:57 +03:00
|
|
|
using namespace gfx;
|
|
|
|
using namespace layers;
|
2018-11-14 21:06:24 +03:00
|
|
|
|
|
|
|
static StaticAutoPtr<RDDProcessManager> sRDDSingleton;
|
|
|
|
|
|
|
|
RDDProcessManager* RDDProcessManager::Get() { return sRDDSingleton; }
|
|
|
|
|
|
|
|
void RDDProcessManager::Initialize() {
|
|
|
|
MOZ_ASSERT(XRE_IsParentProcess());
|
|
|
|
sRDDSingleton = new RDDProcessManager();
|
|
|
|
}
|
|
|
|
|
|
|
|
void RDDProcessManager::Shutdown() { sRDDSingleton = nullptr; }
|
|
|
|
|
|
|
|
RDDProcessManager::RDDProcessManager()
|
2020-09-18 14:07:18 +03:00
|
|
|
: mObserver(new Observer(this)), mTaskFactory(this) {
|
2018-11-14 21:06:24 +03:00
|
|
|
MOZ_COUNT_CTOR(RDDProcessManager);
|
2020-09-18 14:07:18 +03:00
|
|
|
// Start listening for pref changes so we can
|
|
|
|
// forward them to the process once it is running.
|
|
|
|
nsContentUtils::RegisterShutdownObserver(mObserver);
|
|
|
|
Preferences::AddStrongObserver(mObserver, "");
|
2018-11-14 21:06:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
RDDProcessManager::~RDDProcessManager() {
|
|
|
|
MOZ_COUNT_DTOR(RDDProcessManager);
|
2020-09-18 14:07:18 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2018-11-14 21:06:24 +03:00
|
|
|
|
|
|
|
// The RDD process should have already been shut down.
|
|
|
|
MOZ_ASSERT(!mProcess && !mRDDChild);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS(RDDProcessManager::Observer, nsIObserver);
|
|
|
|
|
|
|
|
RDDProcessManager::Observer::Observer(RDDProcessManager* aManager)
|
|
|
|
: mManager(aManager) {}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
RDDProcessManager::Observer::Observe(nsISupports* aSubject, const char* aTopic,
|
|
|
|
const char16_t* aData) {
|
|
|
|
if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
|
|
|
|
mManager->OnXPCOMShutdown();
|
2019-05-25 13:12:47 +03:00
|
|
|
} else if (!strcmp(aTopic, "nsPref:changed")) {
|
|
|
|
mManager->OnPreferenceChange(aData);
|
2018-11-14 21:06:24 +03:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RDDProcessManager::OnXPCOMShutdown() {
|
2020-09-18 14:07:18 +03:00
|
|
|
nsContentUtils::UnregisterShutdownObserver(mObserver);
|
|
|
|
Preferences::RemoveObserver(mObserver, "");
|
2018-11-14 21:06:24 +03:00
|
|
|
CleanShutdown();
|
|
|
|
}
|
|
|
|
|
2019-05-25 13:12:47 +03:00
|
|
|
void RDDProcessManager::OnPreferenceChange(const char16_t* aData) {
|
2020-10-21 02:32:54 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2020-09-18 14:07:18 +03:00
|
|
|
if (!mProcess) {
|
|
|
|
// Process hasn't been launched yet
|
|
|
|
return;
|
|
|
|
}
|
2020-06-23 20:50:23 +03:00
|
|
|
// A pref changed. If it is useful to do so, inform child processes.
|
2019-05-25 13:12:47 +03:00
|
|
|
if (!dom::ContentParent::ShouldSyncPreference(aData)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We know prefs are ASCII here.
|
|
|
|
NS_LossyConvertUTF16toASCII strData(aData);
|
|
|
|
|
|
|
|
mozilla::dom::Pref pref(strData, /* isLocked */ false, Nothing(), Nothing());
|
|
|
|
Preferences::GetPreference(&pref);
|
|
|
|
if (!!mRDDChild) {
|
|
|
|
MOZ_ASSERT(mQueuedPrefs.IsEmpty());
|
|
|
|
mRDDChild->SendPreferenceUpdate(pref);
|
2020-02-18 18:57:14 +03:00
|
|
|
} else if (IsRDDProcessLaunching()) {
|
2019-05-25 13:12:47 +03:00
|
|
|
mQueuedPrefs.AppendElement(pref);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-04 08:43:08 +03:00
|
|
|
auto RDDProcessManager::EnsureRDDProcessAndCreateBridge(
|
|
|
|
base::ProcessId aOtherProcess) -> RefPtr<EnsureRDDPromise> {
|
|
|
|
return InvokeAsync(
|
2020-11-19 04:21:05 +03:00
|
|
|
GetMainThreadSerialEventTarget(), __func__,
|
2021-01-04 08:43:08 +03:00
|
|
|
[aOtherProcess, this]() -> RefPtr<EnsureRDDPromise> {
|
2020-11-19 04:21:05 +03:00
|
|
|
if (!Get()) {
|
|
|
|
// Shutdown?
|
2021-01-04 08:43:08 +03:00
|
|
|
return EnsureRDDPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE,
|
|
|
|
__func__);
|
2020-11-19 04:21:05 +03:00
|
|
|
}
|
2021-01-04 08:43:08 +03:00
|
|
|
if (mProcess) {
|
|
|
|
return mProcess->LaunchPromise()->Then(
|
|
|
|
GetMainThreadSerialEventTarget(), __func__,
|
|
|
|
[aOtherProcess, this](bool) {
|
|
|
|
ipc::Endpoint<PRemoteDecoderManagerChild> endpoint;
|
|
|
|
if (!CreateContentBridge(aOtherProcess, &endpoint)) {
|
|
|
|
return EnsureRDDPromise::CreateAndReject(
|
|
|
|
NS_ERROR_NOT_AVAILABLE, __func__);
|
|
|
|
}
|
|
|
|
return EnsureRDDPromise::CreateAndResolve(std::move(endpoint),
|
|
|
|
__func__);
|
|
|
|
},
|
|
|
|
[](nsresult aError) {
|
|
|
|
return EnsureRDDPromise::CreateAndReject(aError, __func__);
|
|
|
|
});
|
2020-11-19 04:21:05 +03:00
|
|
|
}
|
|
|
|
|
2021-01-04 08:43:08 +03:00
|
|
|
if (mNumProcessAttempts &&
|
|
|
|
!StaticPrefs::media_rdd_retryonfailure_enabled()) {
|
|
|
|
// We failed to start the RDD process earlier, abort now.
|
|
|
|
return EnsureRDDPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE,
|
|
|
|
__func__);
|
2020-11-16 20:42:55 +03:00
|
|
|
}
|
2021-01-04 08:43:08 +03:00
|
|
|
// Launch the RDD process.
|
|
|
|
std::vector<std::string> extraArgs;
|
|
|
|
nsCString parentBuildID(mozilla::PlatformBuildID());
|
|
|
|
extraArgs.push_back("-parentBuildID");
|
|
|
|
extraArgs.push_back(parentBuildID.get());
|
|
|
|
|
|
|
|
// The subprocess is launched asynchronously, so we
|
|
|
|
// wait for the promise to be resolved to acquire the IPDL actor.
|
|
|
|
mProcess = new RDDProcessHost(this);
|
|
|
|
if (!mProcess->Launch(extraArgs)) {
|
2020-11-19 04:21:05 +03:00
|
|
|
DestroyProcess();
|
2021-01-04 08:43:08 +03:00
|
|
|
return EnsureRDDPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE,
|
|
|
|
__func__);
|
2020-11-19 04:21:05 +03:00
|
|
|
}
|
2021-01-04 08:43:08 +03:00
|
|
|
return mProcess->LaunchPromise()->Then(
|
2020-11-19 04:21:05 +03:00
|
|
|
GetMainThreadSerialEventTarget(), __func__,
|
2021-01-04 08:43:08 +03:00
|
|
|
[aOtherProcess, this](bool) {
|
|
|
|
mRDDChild = mProcess->GetActor();
|
|
|
|
mProcessToken = mProcess->GetProcessToken();
|
|
|
|
|
|
|
|
// Flush any pref updates that happened during
|
|
|
|
// launch and weren't included in the blobs set
|
|
|
|
// up in LaunchRDDProcess.
|
|
|
|
for (const mozilla::dom::Pref& pref : mQueuedPrefs) {
|
|
|
|
Unused << NS_WARN_IF(!mRDDChild->SendPreferenceUpdate(pref));
|
2020-11-19 04:21:05 +03:00
|
|
|
}
|
2021-01-04 08:43:08 +03:00
|
|
|
mQueuedPrefs.Clear();
|
|
|
|
|
|
|
|
CrashReporter::AnnotateCrashReport(
|
|
|
|
CrashReporter::Annotation::RDDProcessStatus, "Running"_ns);
|
|
|
|
|
2020-11-19 04:21:05 +03:00
|
|
|
ipc::Endpoint<PRemoteDecoderManagerChild> endpoint;
|
2021-01-04 08:43:08 +03:00
|
|
|
|
|
|
|
if (!CreateVideoBridge() ||
|
|
|
|
!CreateContentBridge(aOtherProcess, &endpoint)) {
|
|
|
|
mNumProcessAttempts++;
|
2020-11-19 04:21:05 +03:00
|
|
|
return EnsureRDDPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE,
|
|
|
|
__func__);
|
|
|
|
}
|
2020-11-16 20:42:55 +03:00
|
|
|
mNumProcessAttempts = 0;
|
2020-11-19 04:21:05 +03:00
|
|
|
return EnsureRDDPromise::CreateAndResolve(std::move(endpoint),
|
|
|
|
__func__);
|
|
|
|
},
|
2021-01-04 08:43:08 +03:00
|
|
|
[this](nsresult aError) {
|
|
|
|
mNumProcessAttempts++;
|
|
|
|
DestroyProcess();
|
2020-11-19 04:21:05 +03:00
|
|
|
return EnsureRDDPromise::CreateAndReject(aError, __func__);
|
|
|
|
});
|
|
|
|
});
|
2019-11-04 06:41:54 +03:00
|
|
|
}
|
2019-10-31 04:21:24 +03:00
|
|
|
|
2020-02-18 18:57:14 +03:00
|
|
|
bool RDDProcessManager::IsRDDProcessLaunching() {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
return !!mProcess && !mRDDChild;
|
|
|
|
}
|
|
|
|
|
2018-11-14 21:06:24 +03:00
|
|
|
void RDDProcessManager::OnProcessUnexpectedShutdown(RDDProcessHost* aHost) {
|
2020-10-21 02:32:54 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2018-11-14 21:06:24 +03:00
|
|
|
MOZ_ASSERT(mProcess && mProcess == aHost);
|
|
|
|
|
2020-11-24 09:38:29 +03:00
|
|
|
mNumUnexpectedCrashes++;
|
|
|
|
|
2018-11-14 21:06:24 +03:00
|
|
|
DestroyProcess();
|
|
|
|
}
|
|
|
|
|
|
|
|
void RDDProcessManager::NotifyRemoteActorDestroyed(
|
|
|
|
const uint64_t& aProcessToken) {
|
|
|
|
if (!NS_IsMainThread()) {
|
|
|
|
RefPtr<Runnable> task = mTaskFactory.NewRunnableMethod(
|
|
|
|
&RDDProcessManager::NotifyRemoteActorDestroyed, aProcessToken);
|
|
|
|
NS_DispatchToMainThread(task.forget());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mProcessToken != aProcessToken) {
|
|
|
|
// This token is for an older process; we can safely ignore it.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// One of the bridged top-level actors for the RDD process has been
|
|
|
|
// prematurely terminated, and we're receiving a notification. This
|
|
|
|
// can happen if the ActorDestroy for a bridged protocol fires
|
|
|
|
// before the ActorDestroy for PRDDChild.
|
|
|
|
OnProcessUnexpectedShutdown(mProcess);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RDDProcessManager::CleanShutdown() { DestroyProcess(); }
|
|
|
|
|
|
|
|
void RDDProcessManager::DestroyProcess() {
|
2020-10-21 02:32:54 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2018-11-14 21:06:24 +03:00
|
|
|
if (!mProcess) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mProcess->Shutdown();
|
|
|
|
mProcessToken = 0;
|
|
|
|
mProcess = nullptr;
|
|
|
|
mRDDChild = nullptr;
|
2020-02-18 18:57:14 +03:00
|
|
|
mQueuedPrefs.Clear();
|
2018-11-14 21:06:24 +03:00
|
|
|
|
|
|
|
CrashReporter::AnnotateCrashReport(
|
|
|
|
CrashReporter::Annotation::RDDProcessStatus, "Destroyed"_ns);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RDDProcessManager::CreateContentBridge(
|
|
|
|
base::ProcessId aOtherProcess,
|
|
|
|
ipc::Endpoint<PRemoteDecoderManagerChild>* aOutRemoteDecoderManager) {
|
2020-11-13 07:21:16 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
|
|
|
ipc::Endpoint<PRemoteDecoderManagerParent> parentPipe;
|
|
|
|
ipc::Endpoint<PRemoteDecoderManagerChild> childPipe;
|
|
|
|
|
|
|
|
nsresult rv = PRemoteDecoderManager::CreateEndpoints(
|
|
|
|
mRDDChild->OtherPid(), aOtherProcess, &parentPipe, &childPipe);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
MOZ_LOG(sPDMLog, LogLevel::Debug,
|
|
|
|
("Could not create content remote decoder: %d", int(rv)));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
mRDDChild->SendNewContentRemoteDecoderManager(std::move(parentPipe));
|
|
|
|
|
|
|
|
*aOutRemoteDecoderManager = std::move(childPipe);
|
|
|
|
return true;
|
2018-11-14 21:06:24 +03:00
|
|
|
}
|
|
|
|
|
2019-11-04 06:41:57 +03:00
|
|
|
bool RDDProcessManager::CreateVideoBridge() {
|
2020-10-21 02:32:54 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2019-11-04 06:41:57 +03:00
|
|
|
ipc::Endpoint<PVideoBridgeParent> parentPipe;
|
|
|
|
ipc::Endpoint<PVideoBridgeChild> childPipe;
|
|
|
|
|
|
|
|
GPUProcessManager* gpuManager = GPUProcessManager::Get();
|
|
|
|
base::ProcessId gpuProcessPid = gpuManager ? gpuManager->GPUProcessPid() : -1;
|
|
|
|
|
|
|
|
// The child end is the producer of video frames; the parent end is the
|
|
|
|
// consumer.
|
|
|
|
base::ProcessId childPid = RDDProcessPid();
|
|
|
|
base::ProcessId parentPid =
|
|
|
|
gpuProcessPid != -1 ? gpuProcessPid : base::GetCurrentProcId();
|
|
|
|
|
|
|
|
nsresult rv = PVideoBridge::CreateEndpoints(parentPid, childPid, &parentPipe,
|
|
|
|
&childPipe);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
MOZ_LOG(sPDMLog, LogLevel::Debug,
|
|
|
|
("Could not create video bridge: %d", int(rv)));
|
2021-01-04 08:43:08 +03:00
|
|
|
DestroyProcess();
|
2019-11-04 06:41:57 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-01-04 08:43:08 +03:00
|
|
|
ContentDeviceData contentDeviceData;
|
|
|
|
gfxPlatform::GetPlatform()->BuildContentDeviceData(&contentDeviceData);
|
|
|
|
|
2020-11-24 09:38:29 +03:00
|
|
|
mRDDChild->SendInitVideoBridge(std::move(childPipe),
|
|
|
|
mNumUnexpectedCrashes == 0, contentDeviceData);
|
2019-11-04 06:41:57 +03:00
|
|
|
if (gpuProcessPid != -1) {
|
|
|
|
gpuManager->InitVideoBridge(std::move(parentPipe));
|
|
|
|
} else {
|
|
|
|
VideoBridgeParent::Open(std::move(parentPipe),
|
|
|
|
VideoBridgeSource::RddProcess);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-11-14 21:06:24 +03:00
|
|
|
base::ProcessId RDDProcessManager::RDDProcessPid() {
|
2020-10-21 02:32:54 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2018-11-14 21:06:24 +03:00
|
|
|
base::ProcessId rddPid = mRDDChild ? mRDDChild->OtherPid() : -1;
|
|
|
|
return rddPid;
|
|
|
|
}
|
|
|
|
|
|
|
|
class RDDMemoryReporter : public MemoryReportingProcess {
|
|
|
|
public:
|
|
|
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RDDMemoryReporter, override)
|
|
|
|
|
|
|
|
bool IsAlive() const override { return !!GetChild(); }
|
|
|
|
|
2019-03-01 00:20:40 +03:00
|
|
|
bool SendRequestMemoryReport(
|
|
|
|
const uint32_t& aGeneration, const bool& aAnonymize,
|
|
|
|
const bool& aMinimizeMemoryUsage,
|
|
|
|
const Maybe<ipc::FileDescriptor>& aDMDFile) override {
|
2018-11-14 21:06:24 +03:00
|
|
|
RDDChild* child = GetChild();
|
|
|
|
if (!child) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return child->SendRequestMemoryReport(aGeneration, aAnonymize,
|
|
|
|
aMinimizeMemoryUsage, aDMDFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t Pid() const override {
|
|
|
|
if (RDDChild* child = GetChild()) {
|
|
|
|
return (int32_t)child->OtherPid();
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
RDDChild* GetChild() const {
|
|
|
|
if (RDDProcessManager* rddpm = RDDProcessManager::Get()) {
|
|
|
|
if (RDDChild* child = rddpm->GetRDDChild()) {
|
|
|
|
return child;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
~RDDMemoryReporter() = default;
|
|
|
|
};
|
|
|
|
|
|
|
|
RefPtr<MemoryReportingProcess> RDDProcessManager::GetProcessMemoryReporter() {
|
2020-11-19 04:21:05 +03:00
|
|
|
if (!mProcess || !mProcess->IsConnected()) {
|
2018-11-14 21:06:24 +03:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return new RDDMemoryReporter();
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace mozilla
|