Bug 820200 - Pass application directory to XRE_InitEmbedding2 in content process. r=bsmedberg
authorJim Mathies <jmathies@mozilla.com>
Tue, 18 Dec 2012 10:24:42 -0600
changeset 125526 3ec0a08450d8df0bee40bba7ed7b1301156696fc
parent 125525 95566cb18e2e13f0ed5a4a7dfd6270c273f0da91
child 125527 8e79ce6ac5056e2592eed09d5630a077c7de89ac
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmedberg
bugs820200
milestone20.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 820200 - Pass application directory to XRE_InitEmbedding2 in content process. r=bsmedberg
dom/ipc/ContentProcess.cpp
dom/ipc/ContentProcess.h
ipc/glue/GeckoChildProcessHost.cpp
ipc/glue/ScopedXREEmbed.cpp
ipc/glue/ScopedXREEmbed.h
toolkit/xre/nsEmbedFunctions.cpp
--- a/dom/ipc/ContentProcess.cpp
+++ b/dom/ipc/ContentProcess.cpp
@@ -8,16 +8,22 @@
 
 #include "ContentProcess.h"
 
 using mozilla::ipc::IOThreadChild;
 
 namespace mozilla {
 namespace dom {
 
+void
+ContentProcess::SetAppDir(const nsACString& aPath)
+{
+  mXREEmbed.SetAppDir(aPath);
+}
+
 bool
 ContentProcess::Init()
 {
     mContent.Init(IOThreadChild::message_loop(),
                          ParentHandle(),
                          IOThreadChild::channel());
     mXREEmbed.Start();
     mContent.InitXPCOM();
--- a/dom/ipc/ContentProcess.h
+++ b/dom/ipc/ContentProcess.h
@@ -31,16 +31,18 @@ public:
     { }
 
     ~ContentProcess()
     { }
 
     virtual bool Init() MOZ_OVERRIDE;
     virtual void CleanUp() MOZ_OVERRIDE;
 
+    void SetAppDir(const nsACString& aPath);
+
 private:
     ContentChild mContent;
     mozilla::ipc::ScopedXREEmbed mXREEmbed;
 
     DISALLOW_EVIL_CONSTRUCTORS(ContentProcess);
 };
 
 }  // namespace dom
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -405,16 +405,50 @@ GeckoChildProcessHost::PerformAsyncLaunc
   bool retval = PerformAsyncLaunchInternal(aExtraOpts, arch);
 
   // Revert to original value
   PR_SetEnv(restoreOrigLogName);
 
   return retval;
 }
 
+void
+#if defined(XP_WIN)
+AddAppDirToCommandLine(CommandLine& aCmdLine)
+#else
+AddAppDirToCommandLine(std::vector<std::string>& aCmdLine)
+#endif
+{
+  // Content processes need access to application resources, so pass
+  // the full application directory path to the child process.
+  if (ShouldHaveDirectoryService()) {
+    nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
+    NS_ASSERTION(directoryService, "Expected XPCOM to be available");
+    if (directoryService) {
+      nsCOMPtr<nsIFile> appDir;
+      // NS_XPCOM_CURRENT_PROCESS_DIR really means the app dir, not the
+      // current process dir.
+      nsresult rv = directoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR,
+                                          NS_GET_IID(nsIFile),
+                                          getter_AddRefs(appDir));
+      if (NS_SUCCEEDED(rv)) {
+        nsAutoCString path;
+        appDir->GetNativePath(path);
+#if defined(XP_WIN)
+        aCmdLine.AppendLooseValue(UTF8ToWide("-appdir"));
+        aCmdLine.AppendLooseValue(UTF8ToWide(path.get()));
+#else
+        aCmdLine.push_back("-appdir");
+        aCmdLine.push_back(path.get());
+#endif
+      }
+    }
+  }
+}
+
 bool
 GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExtraOpts, base::ProcessArchitecture arch)
 {
   // We rely on the fact that InitializeChannel() has already been processed
   // on the IO thread before this point is reached.
   if (!GetChannel()) {
     return false;
   }
@@ -570,16 +604,19 @@ GeckoChildProcessHost::PerformAsyncLaunc
     }
     file = Omnijar::GetPath(Omnijar::APP);
     if (file && NS_SUCCEEDED(file->GetNativePath(path))) {
       childArgv.push_back("-appomni");
       childArgv.push_back(path.get());
     }
   }
 
+  // Add the application directory path (-appdir path)
+  AddAppDirToCommandLine(childArgv);
+
   childArgv.push_back(pidstring);
 
 #if defined(MOZ_CRASHREPORTER)
 #  if defined(OS_LINUX) || defined(OS_BSD)
   int childCrashFd, childCrashRemapFd;
   if (!CrashReporter::CreateNotificationPipeForChild(
         &childCrashFd, &childCrashRemapFd))
     return false;
@@ -669,41 +706,51 @@ GeckoChildProcessHost::PerformAsyncLaunc
   cmdLine.AppendSwitchWithValue(switches::kProcessChannelID, channel_id());
 
   for (std::vector<std::string>::iterator it = aExtraOpts.begin();
        it != aExtraOpts.end();
        ++it) {
       cmdLine.AppendLooseValue(UTF8ToWide(*it));
   }
 
-  cmdLine.AppendLooseValue(std::wstring(mGroupId.get()));
-
   if (Omnijar::IsInitialized()) {
     // Make sure the child process can find the omnijar
     // See XRE_InitCommandLine in nsAppRunner.cpp
     nsAutoString path;
     nsCOMPtr<nsIFile> file = Omnijar::GetPath(Omnijar::GRE);
     if (file && NS_SUCCEEDED(file->GetPath(path))) {
       cmdLine.AppendLooseValue(UTF8ToWide("-greomni"));
       cmdLine.AppendLooseValue(path.get());
     }
     file = Omnijar::GetPath(Omnijar::APP);
     if (file && NS_SUCCEEDED(file->GetPath(path))) {
       cmdLine.AppendLooseValue(UTF8ToWide("-appomni"));
       cmdLine.AppendLooseValue(path.get());
     }
   }
 
+  // Add the application directory path (-appdir path)
+  AddAppDirToCommandLine(cmdLine);
+
+  // XXX Command line params past this point are expected to be at
+  // the end of the command line string, and in a specific order.
+  // See XRE_InitChildProcess in nsEmbedFunction.
+
+  // Win app model id
+  cmdLine.AppendLooseValue(std::wstring(mGroupId.get()));
+
+  // Process id
   cmdLine.AppendLooseValue(UTF8ToWide(pidstring));
 
 #if defined(MOZ_CRASHREPORTER)
   cmdLine.AppendLooseValue(
     UTF8ToWide(CrashReporter::GetChildNotificationPipe()));
 #endif
 
+  // Process type
   cmdLine.AppendLooseValue(UTF8ToWide(childProcessType));
 
   base::LaunchApp(cmdLine, false, false, &process);
 
 #else
 #  error Sorry
 #endif
 
--- a/ipc/glue/ScopedXREEmbed.cpp
+++ b/ipc/glue/ScopedXREEmbed.cpp
@@ -24,16 +24,29 @@ ScopedXREEmbed::ScopedXREEmbed()
 
 ScopedXREEmbed::~ScopedXREEmbed()
 {
   Stop();
   NS_LogTerm();
 }
 
 void
+ScopedXREEmbed::SetAppDir(const nsACString& aPath)
+{
+  bool flag;
+  nsresult rv =
+    XRE_GetFileFromPath(aPath.BeginReading(), getter_AddRefs(mAppDir));
+  if (NS_FAILED(rv) ||
+      NS_FAILED(mAppDir->Exists(&flag)) || !flag) {
+    NS_WARNING("Invalid application directory passed to content process.");
+    mAppDir = nullptr;
+  }
+}
+
+void
 ScopedXREEmbed::Start()
 {
   std::string path;
 #if defined(OS_WIN)
   path = WideToUTF8(CommandLine::ForCurrentProcess()->program());
 #elif defined(OS_POSIX)
   path = CommandLine::ForCurrentProcess()->argv()[0];
 #else
@@ -75,17 +88,20 @@ ScopedXREEmbed::Start()
     if (NS_FAILED(rv))
       return;
 
     localFile = do_QueryInterface(parent);
     NS_ENSURE_TRUE_VOID(localFile);
   }
 #endif
 
-  rv = XRE_InitEmbedding2(localFile, localFile, nullptr);
+  if (mAppDir)
+    rv = XRE_InitEmbedding2(localFile, mAppDir, nullptr);
+  else
+    rv = XRE_InitEmbedding2(localFile, localFile, nullptr);
   if (NS_FAILED(rv))
     return;
 
   mShouldKillEmbedding = true;
 }
 
 void
 ScopedXREEmbed::Stop()
--- a/ipc/glue/ScopedXREEmbed.h
+++ b/ipc/glue/ScopedXREEmbed.h
@@ -1,27 +1,33 @@
 /* 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/. */
 
 #ifndef __IPC_GLUE_SCOPEDXREEMBED_H__
 #define __IPC_GLUE_SCOPEDXREEMBED_H__
 
+#include "nsString.h"
+#include "nsAutoPtr.h"
+#include "nsIFile.h"
+
 namespace mozilla {
 namespace ipc {
 
 class ScopedXREEmbed
 {
 public:
   ScopedXREEmbed();
   ~ScopedXREEmbed();
 
   void Start();
   void Stop();
+  void SetAppDir(const nsACString& aPath);
 
 private:
   bool mShouldKillEmbedding;
+  nsCOMPtr<nsIFile> mAppDir;
 };
 
 } /* namespace ipc */
 } /* namespace mozilla */
 
 #endif /* __IPC_GLUE_SCOPEDXREEMBED_H__ */
\ No newline at end of file
--- a/toolkit/xre/nsEmbedFunctions.cpp
+++ b/toolkit/xre/nsEmbedFunctions.cpp
@@ -398,18 +398,17 @@ XRE_InitChildProcess(int aArgc,
   base::ProcessHandle parentHandle;
   mozilla::DebugOnly<bool> ok = base::OpenProcessHandle(parentPID, &parentHandle);
   NS_ABORT_IF_FALSE(ok, "can't open handle to parent");
 
 #if defined(XP_WIN)
   // On Win7+, register the application user model id passed in by
   // parent. This insures windows created by the container properly
   // group with the parent app on the Win7 taskbar.
-  const char* const appModelUserId = aArgv[aArgc-1];
-  --aArgc;
+  const char* const appModelUserId = aArgv[--aArgc];
   if (appModelUserId) {
     // '-' implies no support
     if (*appModelUserId != '-') {
       nsString appId;
       appId.AssignWithConversion(nsDependentCString(appModelUserId));
       // The version string is encased in quotes
       appId.Trim(NS_LITERAL_CSTRING("\"").get());
       // Set the id
@@ -455,18 +454,28 @@ XRE_InitChildProcess(int aArgc,
       case GeckoProcessType_Default:
         NS_RUNTIMEABORT("This makes no sense");
         break;
 
       case GeckoProcessType_Plugin:
         process = new PluginProcessChild(parentHandle);
         break;
 
-      case GeckoProcessType_Content:
-        process = new ContentProcess(parentHandle);
+      case GeckoProcessType_Content: {
+          process = new ContentProcess(parentHandle);
+          // If passed in grab the application path for xpcom init
+          nsCString appDir;
+          for (int idx = aArgc; idx > 0; idx--) {
+            if (aArgv[idx] && !strcmp(aArgv[idx], "-appdir")) {
+              appDir.Assign(nsDependentCString(aArgv[idx+1]));
+              static_cast<ContentProcess*>(process.get())->SetAppDir(appDir);
+              break;
+            }
+          }
+        }
         break;
 
       case GeckoProcessType_IPDLUnitTest:
 #ifdef MOZ_IPDL_TESTS
         process = new IPDLUnitTestProcessChild(parentHandle);
 #else 
         NS_RUNTIMEABORT("rebuild with --enable-ipdl-tests");
 #endif