Bug 1405877 - Bootstrap AudioIPC from Gecko IPC by passing server fd to content process. r=jld,kamidphish
authorMatthew Gregan <kinetik@flim.org>
Wed, 20 Dec 2017 14:51:11 +1300
changeset 396960 502337e7c6ae8a505d20a70c64d7506fa41d66a6
parent 396959 a4fcb75943aa10715baa13c1fdad8d92e986c607
child 396961 adadbeff32ec32d837e09c1a303817b47576fc4b
push id33117
push userebalazs@mozilla.com
push dateWed, 20 Dec 2017 09:47:43 +0000
treeherdermozilla-central@a235bf4868ab [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjld, kamidphish
bugs1405877
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1405877 - Bootstrap AudioIPC from Gecko IPC by passing server fd to content process. r=jld,kamidphish
dom/ipc/ContentChild.cpp
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
dom/media/CubebUtils.cpp
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -86,19 +86,16 @@
 
 #if defined(MOZ_CONTENT_SANDBOX)
 #include "mozilla/SandboxSettings.h"
 #if defined(XP_WIN)
 #include "mozilla/sandboxTarget.h"
 #elif defined(XP_LINUX)
 #include "mozilla/Sandbox.h"
 #include "mozilla/SandboxInfo.h"
-
-// Remove this include with Bug 1104619
-#include "CubebUtils.h"
 #elif defined(XP_MACOSX)
 #include "mozilla/Sandbox.h"
 #endif
 #endif
 
 #include "mozilla/Unused.h"
 
 #include "mozInlineSpellChecker.h"
@@ -1663,24 +1660,17 @@ ContentChild::RecvSetProcessSandbox(cons
 {
   // We may want to move the sandbox initialization somewhere else
   // at some point; see bug 880808.
 #if defined(MOZ_CONTENT_SANDBOX)
   bool sandboxEnabled = true;
 #if defined(XP_LINUX)
   // Otherwise, sandboxing is best-effort.
   if (!SandboxInfo::Get().CanSandboxContent()) {
-       sandboxEnabled = false;
-   } else {
-       // This triggers the initialization of cubeb, which needs to happen
-       // before seccomp is enabled (Bug 1259508). It also increases the startup
-       // time of the content process, because cubeb is usually initialized
-       // when it is actually needed. This call here is no longer required
-       // once Bug 1104619 (remoting audio) is resolved.
-       Unused << CubebUtils::GetCubebContext();
+    sandboxEnabled = false;
   }
 
   if (sandboxEnabled) {
     int brokerFd = -1;
     if (aBroker.type() == MaybeFileDesc::TFileDescriptor) {
       auto fd = aBroker.get_FileDescriptor().ClonePlatformHandle();
       brokerFd = fd.release();
       // brokerFd < 0 means to allow direct filesystem access, so
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -291,16 +291,20 @@ using mozilla::Telemetry::ProcessID;
 // XXX Workaround for bug 986973 to maintain the existing broken semantics
 template<>
 struct nsIConsoleService::COMTypeInfo<nsConsoleService, void> {
   static const nsIID kIID;
 };
 const nsIID nsIConsoleService::COMTypeInfo<nsConsoleService, void>::kIID = NS_ICONSOLESERVICE_IID;
 
 namespace mozilla {
+namespace CubebUtils {
+  extern FileDescriptor CreateAudioIPCConnection();
+}
+
 namespace dom {
 
 #define NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC "ipc:network:set-offline"
 #define NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC "ipc:network:set-connectivity"
 
 // IPC receiver for remote GC/CC logging.
 class CycleCollectWithLogsParent final : public PCycleCollectWithLogsParent
 {
@@ -4154,16 +4158,27 @@ ContentParent::RecvRequestAnonymousTempo
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return IPC_OK();
   }
 
   rv = NS_OK;
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult
+ContentParent::RecvCreateAudioIPCConnection(CreateAudioIPCConnectionResolver&& aResolver)
+{
+  FileDescriptor fd = CubebUtils::CreateAudioIPCConnection();
+  if (!fd.IsValid()) {
+    return IPC_FAIL(this, "CubebUtils::CreateAudioIPCConnection failed");
+  }
+  aResolver(Move(fd));
+  return IPC_OK();
+}
+
 static NS_DEFINE_CID(kFormProcessorCID, NS_FORMPROCESSOR_CID);
 
 mozilla::ipc::IPCResult
 ContentParent::RecvKeygenProcessValue(const nsString& oldValue,
                                       const nsString& challenge,
                                       const nsString& keytype,
                                       const nsString& keyparams,
                                       nsString* newValue)
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -1101,16 +1101,19 @@ private:
 
   virtual mozilla::ipc::IPCResult
   RecvBackUpXResources(const FileDescriptor& aXSocketFd) override;
 
   virtual mozilla::ipc::IPCResult
   RecvRequestAnonymousTemporaryFile(const uint64_t& aID) override;
 
   virtual mozilla::ipc::IPCResult
+  RecvCreateAudioIPCConnection(CreateAudioIPCConnectionResolver&& aResolver) override;
+
+  virtual mozilla::ipc::IPCResult
   RecvKeygenProcessValue(const nsString& oldValue, const nsString& challenge,
                          const nsString& keytype, const nsString& keyparams,
                          nsString* newValue) override;
 
   virtual mozilla::ipc::IPCResult
   RecvKeygenProvideContent(nsString* aAttribute,
                            nsTArray<nsString>* aContent) override;
 
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -759,16 +759,18 @@ parent:
     async PSpeechSynthesis();
 
     async PMedia();
 
     async PWebrtcGlobal();
 
     async PPresentation();
 
+    async CreateAudioIPCConnection() returns (FileDescriptor fd);
+
     sync PURLClassifier(Principal principal, bool useTrackingProtection)
         returns (bool success);
     sync ClassifyLocal(URIParams uri, nsCString tables)
         returns (nsresult rv, nsCString[] results);
     // The async version of ClassifyLocal.
     async PURLClassifierLocal(URIParams uri, nsCString tables);
 
     async PLoginReputation(URIParams formURI);
--- a/dom/media/CubebUtils.cpp
+++ b/dom/media/CubebUtils.cpp
@@ -3,16 +3,18 @@
 /* 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 "CubebUtils.h"
 
 #include "MediaInfo.h"
 #include "mozilla/AbstractThread.h"
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/ipc/FileDescriptor.h"
 #include "mozilla/Logging.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/Sprintf.h"
 #include "mozilla/StaticMutex.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/Telemetry.h"
 #include "nsAutoRef.h"
@@ -50,30 +52,34 @@
 
 #if defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID)
 #define MOZ_CUBEB_REMOTING
 #endif
 
 extern "C" {
 // These functions are provided by audioipc-server crate
 extern void* audioipc_server_start();
+extern mozilla::ipc::FileDescriptor::PlatformHandleType audioipc_server_new_client(void*);
 extern void audioipc_server_stop(void*);
 // These functions are provided by audioipc-client crate
-extern int audioipc_client_init(cubeb**, const char*);
+extern int audioipc_client_init(cubeb**, const char*, int);
 }
 
 namespace mozilla {
 
 namespace {
 
 #ifdef MOZ_CUBEB_REMOTING
 ////////////////////////////////////////////////////////////////////////////////
 // Cubeb Sound Server Thread
 void* sServerHandle = nullptr;
 
+// Initialized during early startup, protected by sMutex.
+ipc::FileDescriptor sIPCConnection;
+
 static bool
 StartSoundServer()
 {
   sServerHandle = audioipc_server_start();
   return sServerHandle != nullptr;
 }
 
 static void
@@ -373,16 +379,49 @@ void InitBrandName()
     }
   }
   NS_LossyConvertUTF16toASCII ascii(brandName);
   sBrandName = new char[ascii.Length() + 1];
   PodCopy(sBrandName.get(), ascii.get(), ascii.Length());
   sBrandName[ascii.Length()] = 0;
 }
 
+#ifdef MOZ_CUBEB_REMOTING
+void InitAudioIPCConnection()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  auto contentChild = dom::ContentChild::GetSingleton();
+  auto promise = contentChild->SendCreateAudioIPCConnection();
+  promise->Then(AbstractThread::GetCurrent(),
+                __func__,
+                [](ipc::FileDescriptor aFD) {
+                  StaticMutexAutoLock lock(sMutex);
+                  MOZ_ASSERT(!sIPCConnection.IsValid());
+                  sIPCConnection = aFD;
+                },
+                [](mozilla::ipc::ResponseRejectReason aReason) {
+                  MOZ_LOG(gCubebLog, LogLevel::Error, ("SendCreateAudioIPCConnection failed: %d",
+                                                       int(aReason)));
+                });
+}
+#endif
+
+ipc::FileDescriptor CreateAudioIPCConnection()
+{
+#ifdef MOZ_CUBEB_REMOTING
+  MOZ_ASSERT(sServerHandle);
+  int rawFD = audioipc_server_new_client(sServerHandle);
+  ipc::FileDescriptor fd(rawFD);
+  close(rawFD);
+  return fd;
+#else
+  return ipc::FileDescriptor();
+#endif
+}
+
 cubeb* GetCubebContextUnlocked()
 {
   sMutex.AssertCurrentThreadOwns();
   if (sCubebState != CubebState::Uninitialized) {
     // If we have already passed the initialization point (below), just return
     // the current context, which may be null (e.g., after error or shutdown.)
     return sCubebContext;
   }
@@ -390,20 +429,29 @@ cubeb* GetCubebContextUnlocked()
   if (!sBrandName && NS_IsMainThread()) {
     InitBrandName();
   } else {
     NS_WARNING_ASSERTION(
       sBrandName, "Did not initialize sbrandName, and not on the main thread?");
   }
 
 #ifdef MOZ_CUBEB_REMOTING
+  if (XRE_IsParentProcess()) {
+    // TODO: Don't use audio IPC when within the same process.
+    MOZ_ASSERT(!sIPCConnection.IsValid());
+    sIPCConnection = CreateAudioIPCConnection();
+  } else {
+    MOZ_DIAGNOSTIC_ASSERT(sIPCConnection.IsValid());
+  }
+
   MOZ_LOG(gCubebLog, LogLevel::Info, ("%s: %s", PREF_CUBEB_SANDBOX, sCubebSandbox ? "true" : "false"));
 
   int rv = sCubebSandbox
-    ? audioipc_client_init(&sCubebContext, sBrandName)
+    ? audioipc_client_init(&sCubebContext, sBrandName,
+                           sIPCConnection.ClonePlatformHandle().release())
     : cubeb_init(&sCubebContext, sBrandName, sCubebBackendName.get());
 #else // !MOZ_CUBEB_REMOTING
   int rv = cubeb_init(&sCubebContext, sBrandName, sCubebBackendName.get());
 #endif // MOZ_CUBEB_REMOTING
   NS_WARNING_ASSERTION(rv == CUBEB_OK, "Could not get a cubeb context.");
   sCubebState = (rv == CUBEB_OK) ? CubebState::Initialized : CubebState::Uninitialized;
 
   if (MOZ_LOG_TEST(gCubebLog, LogLevel::Verbose)) {
@@ -487,16 +535,22 @@ void InitLibrary()
   // empty string by default ("", which means "logging disabled"). Because the
   // logging can be enabled via environment variables (MOZ_LOG="module:5"),
   // calling this callback on init would immediately re-disble the logging.
   Preferences::RegisterCallback(PrefChanged, PREF_CUBEB_LOGGING_LEVEL);
 #ifndef MOZ_WIDGET_ANDROID
   AbstractThread::MainThread()->Dispatch(
     NS_NewRunnableFunction("CubebUtils::InitLibrary", &InitBrandName));
 #endif
+#ifdef MOZ_CUBEB_REMOTING
+  if (XRE_IsContentProcess()) {
+    AbstractThread::MainThread()->Dispatch(
+      NS_NewRunnableFunction("CubebUtils::InitLibrary", &InitAudioIPCConnection));
+  }
+#endif
 }
 
 void ShutdownLibrary()
 {
   Preferences::UnregisterCallback(PrefChanged, PREF_VOLUME_SCALE);
   Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_SANDBOX);
   Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_BACKEND);
   Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_LATENCY_PLAYBACK);
@@ -509,16 +563,17 @@ void ShutdownLibrary()
     sCubebContext = nullptr;
   }
   sBrandName = nullptr;
   sCubebBackendName = nullptr;
   // This will ensure we don't try to re-create a context.
   sCubebState = CubebState::Shutdown;
 
 #ifdef MOZ_CUBEB_REMOTING
+  sIPCConnection = ipc::FileDescriptor();
   ShutdownSoundServer();
 #endif
 }
 
 uint32_t MaxNumberOfChannels()
 {
   cubeb* cubebContext = GetCubebContext();
   uint32_t maxNumberOfChannels;