Bug 1513057 - P4: Update online/offline status to socket process r=dragana,mayhemer
authorKershaw Chang <kershaw@mozilla.com>
Fri, 11 Jan 2019 20:54:06 +0000
changeset 513524 ca35e0cd0782f9b63b51494e553dd312f6d96d1b
parent 513523 7c4eddc3a80db9c9166d84314bd7a35629868857
child 513525 b5904e4ffc0ca4bdab4084a92176c6a70f93f01c
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdragana, mayhemer
bugs1513057
milestone66.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 1513057 - P4: Update online/offline status to socket process r=dragana,mayhemer Differential Revision: https://phabricator.services.mozilla.com/D14161
netwerk/base/nsIOService.cpp
netwerk/ipc/NeckoCommon.h
netwerk/ipc/PSocketProcess.ipdl
netwerk/ipc/SocketProcessChild.cpp
netwerk/ipc/SocketProcessChild.h
netwerk/ipc/SocketProcessHost.cpp
netwerk/ipc/SocketProcessHost.h
--- a/netwerk/base/nsIOService.cpp
+++ b/netwerk/base/nsIOService.cpp
@@ -1525,17 +1525,17 @@ nsIOService::SetManageOfflineStatus(bool
 NS_IMETHODIMP
 nsIOService::GetManageOfflineStatus(bool *aManage) {
   *aManage = mManageLinkStatus;
   return NS_OK;
 }
 
 // input argument 'data' is already UTF8'ed
 nsresult nsIOService::OnNetworkLinkEvent(const char *data) {
-  if (IsNeckoChild()) {
+  if (IsNeckoChild() || IsSocketProcessChild()) {
     // There is nothing IO service could do on the child process
     // with this at the moment.  Feel free to add functionality
     // here at will, though.
     return NS_OK;
   }
 
   if (mShutdown) {
     return NS_ERROR_NOT_AVAILABLE;
--- a/netwerk/ipc/NeckoCommon.h
+++ b/netwerk/ipc/NeckoCommon.h
@@ -90,16 +90,21 @@ inline bool IsNeckoChild() {
   if (!didCheck) {
     didCheck = true;
     amChild = (XRE_GetProcessType() == GeckoProcessType_Content) &&
               !recordreplay::IsMiddleman();
   }
   return amChild;
 }
 
+inline bool IsSocketProcessChild() {
+  static bool amChild = (XRE_GetProcessType() == GeckoProcessType_Socket);
+  return amChild;
+}
+
 namespace NeckoCommonInternal {
 extern bool gSecurityDisabled;
 extern bool gRegisteredBool;
 }  // namespace NeckoCommonInternal
 
 // This should always return true unless xpcshell tests are being used
 inline bool UsingNeckoIPCSecurity() {
   return !NeckoCommonInternal::gSecurityDisabled;
--- a/netwerk/ipc/PSocketProcess.ipdl
+++ b/netwerk/ipc/PSocketProcess.ipdl
@@ -19,12 +19,13 @@ parent:
   async FinishMemoryReport(uint32_t aGeneration);
 
 child:
   async PreferenceUpdate(Pref pref);
   async RequestMemoryReport(uint32_t generation,
                             bool anonymize,
                             bool minimizeMemoryUsage,
                             MaybeFileDesc DMDFile);
+  async SetOffline(bool offline);
 };
 
 } // namespace net
 } // namespace mozilla
--- a/netwerk/ipc/SocketProcessChild.cpp
+++ b/netwerk/ipc/SocketProcessChild.cpp
@@ -101,10 +101,22 @@ mozilla::ipc::IPCResult SocketProcessChi
         Unused << GetSingleton()->SendAddMemoryReport(aReport);
       },
       [&](const uint32_t& aGeneration) {
         return GetSingleton()->SendFinishMemoryReport(aGeneration);
       });
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult SocketProcessChild::RecvSetOffline(
+    const bool& aOffline) {
+  LOG(("SocketProcessChild::RecvSetOffline aOffline=%d\n", aOffline));
+
+  nsCOMPtr<nsIIOService> io(do_GetIOService());
+  NS_ASSERTION(io, "IO Service can not be null");
+
+  io->SetOffline(aOffline);
+
+  return IPC_OK();
+}
+
 }  // namespace net
 }  // namespace mozilla
--- a/netwerk/ipc/SocketProcessChild.h
+++ b/netwerk/ipc/SocketProcessChild.h
@@ -24,16 +24,17 @@ class SocketProcessChild final : public 
             MessageLoop* aIOLoop, IPC::Channel* aChannel);
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
   mozilla::ipc::IPCResult RecvPreferenceUpdate(const Pref& aPref) override;
   mozilla::ipc::IPCResult RecvRequestMemoryReport(
       const uint32_t& generation, const bool& anonymize,
       const bool& minimizeMemoryUsage, const MaybeFileDesc& DMDFile) override;
+  mozilla::ipc::IPCResult RecvSetOffline(const bool& aOffline) override;
 
   void CleanUp();
 
  private:
 };
 
 }  // namespace net
 }  // namespace mozilla
--- a/netwerk/ipc/SocketProcessHost.cpp
+++ b/netwerk/ipc/SocketProcessHost.cpp
@@ -1,32 +1,95 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "SocketProcessHost.h"
+
+#include "nsAppRunner.h"
+#include "nsIObserverService.h"
 #include "SocketProcessParent.h"
-#include "nsAppRunner.h"
 
 namespace mozilla {
 namespace net {
 
+#define NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC "ipc:network:set-offline"
+
+class OfflineObserver final : public nsIObserver {
+ public:
+  NS_DECL_THREADSAFE_ISUPPORTS
+  explicit OfflineObserver(SocketProcessHost* aProcessHost)
+      : mProcessHost(aProcessHost) {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+    if (obs) {
+      obs->AddObserver(this, NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC, false);
+    }
+  }
+
+  void Destroy() {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+    if (obs) {
+      obs->RemoveObserver(this, NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC);
+    }
+    mProcessHost = nullptr;
+  }
+
+ private:
+  // nsIObserver implementation.
+  NS_IMETHOD
+  Observe(nsISupports* aSubject, const char* aTopic,
+          const char16_t* aData) override {
+    if (!mProcessHost) {
+      return NS_OK;
+    }
+
+    if (!strcmp(aTopic, NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC)) {
+      NS_ConvertUTF16toUTF8 dataStr(aData);
+      const char* offline = dataStr.get();
+      if (!mProcessHost->IsConnected() ||
+          mProcessHost->GetActor()->SendSetOffline(
+              !strcmp(offline, "true") ? true : false)) {
+        return NS_ERROR_NOT_AVAILABLE;
+      }
+    }
+
+    return NS_OK;
+  }
+  virtual ~OfflineObserver() = default;
+
+  SocketProcessHost* mProcessHost;
+};
+
+NS_IMPL_ISUPPORTS(OfflineObserver, nsIObserver)
+
 SocketProcessHost::SocketProcessHost(Listener* aListener)
     : GeckoChildProcessHost(GeckoProcessType_Socket),
       mListener(aListener),
       mTaskFactory(this),
       mLaunchPhase(LaunchPhase::Unlaunched),
       mShutdownRequested(false),
       mChannelClosed(false) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_COUNT_CTOR(SocketProcessHost);
 }
 
-SocketProcessHost::~SocketProcessHost() { MOZ_COUNT_DTOR(SocketProcessHost); }
+SocketProcessHost::~SocketProcessHost() {
+  MOZ_COUNT_DTOR(SocketProcessHost);
+  if (mOfflineObserver) {
+    RefPtr<OfflineObserver> observer = mOfflineObserver;
+    NS_DispatchToMainThread(
+        NS_NewRunnableFunction("SocketProcessHost::DestroyOfflineObserver",
+                               [observer]() { observer->Destroy(); }));
+  }
+}
 
 bool SocketProcessHost::Launch() {
   MOZ_ASSERT(mLaunchPhase == LaunchPhase::Unlaunched);
   MOZ_ASSERT(!mSocketProcessParent);
   MOZ_ASSERT(NS_IsMainThread());
 
   std::vector<std::string> extraArgs;
 
@@ -138,28 +201,42 @@ void SocketProcessHost::InitAfterConnect
 
   mLaunchPhase = LaunchPhase::Complete;
 
   if (aSucceeded) {
     mSocketProcessParent = MakeUnique<SocketProcessParent>(this);
     DebugOnly<bool> rv = mSocketProcessParent->Open(
         GetChannel(), base::GetProcId(GetChildProcessHandle()));
     MOZ_ASSERT(rv);
+
+    nsCOMPtr<nsIIOService> ioService(do_GetIOService());
+    MOZ_ASSERT(ioService, "No IO service?");
+    bool offline = false;
+    DebugOnly<nsresult> result = ioService->GetOffline(&offline);
+    MOZ_ASSERT(NS_SUCCEEDED(result), "Failed getting offline?");
+
+    Unused << GetActor()->SendSetOffline(offline);
+
+    mOfflineObserver = new OfflineObserver(this);
   }
 
   if (mListener) {
     mListener->OnProcessLaunchComplete(this, aSucceeded);
   }
 }
 
 void SocketProcessHost::Shutdown() {
   MOZ_ASSERT(!mShutdownRequested);
   MOZ_ASSERT(NS_IsMainThread());
 
   mListener = nullptr;
+  if (mOfflineObserver) {
+    mOfflineObserver->Destroy();
+    mOfflineObserver = nullptr;
+  }
 
   if (mSocketProcessParent) {
     // OnChannelClosed uses this to check if the shutdown was expected or
     // unexpected.
     mShutdownRequested = true;
 
     // The channel might already be closed if we got here unexpectedly.
     if (!mChannelClosed) {
--- a/netwerk/ipc/SocketProcessHost.h
+++ b/netwerk/ipc/SocketProcessHost.h
@@ -9,16 +9,17 @@
 #include "mozilla/UniquePtr.h"
 #include "mozilla/ipc/GeckoChildProcessHost.h"
 #include "mozilla/MemoryReportingProcess.h"
 #include "mozilla/ipc/TaskFactory.h"
 
 namespace mozilla {
 namespace net {
 
+class OfflineObserver;
 class SocketProcessParent;
 
 // SocketProcessHost is the "parent process" container for a subprocess handle
 // and IPC connection. It owns the parent process IPDL actor, which in this
 // case, is a SocketProcessParent.
 // SocketProcessHost is allocated and managed by nsIOService in parent process.
 class SocketProcessHost final : public mozilla::ipc::GeckoChildProcessHost {
   friend class SocketProcessParent;
@@ -96,16 +97,18 @@ class SocketProcessHost final : public m
   LaunchPhase mLaunchPhase;
 
   UniquePtr<SocketProcessParent> mSocketProcessParent;
   // mShutdownRequested is set to true only when Shutdown() is called.
   // If mShutdownRequested is false and the IPC channel is closed,
   // OnProcessUnexpectedShutdown will be invoked.
   bool mShutdownRequested;
   bool mChannelClosed;
+
+  RefPtr<OfflineObserver> mOfflineObserver;
 };
 
 class SocketProcessMemoryReporter : public MemoryReportingProcess {
  public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SocketProcessMemoryReporter, override)
 
   SocketProcessMemoryReporter() = default;