LCOV - code coverage report
Current view: directory - ipc/glue - GeckoChildProcessHost.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 153 0 0.0 %
Date: 2012-06-02 Functions: 19 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2                 :  */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Mozilla IPC.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  *   Ben Turner <bent.mozilla@gmail.com>.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 2009
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "GeckoChildProcessHost.h"
      40                 : 
      41                 : #include "base/command_line.h"
      42                 : #include "base/path_service.h"
      43                 : #include "base/string_util.h"
      44                 : #include "chrome/common/chrome_switches.h"
      45                 : #include "chrome/common/process_watcher.h"
      46                 : #ifdef MOZ_WIDGET_COCOA
      47                 : #include "chrome/common/mach_ipc_mac.h"
      48                 : #include "base/rand_util.h"
      49                 : #include "nsILocalFileMac.h"
      50                 : #endif
      51                 : 
      52                 : #include "prprf.h"
      53                 : #include "prenv.h"
      54                 : 
      55                 : #if defined(OS_LINUX)
      56                 : #  define XP_LINUX 1
      57                 : #endif
      58                 : #include "nsExceptionHandler.h"
      59                 : 
      60                 : #include "nsDirectoryServiceDefs.h"
      61                 : #include "nsIFile.h"
      62                 : #include "nsILocalFile.h"
      63                 : 
      64                 : #include "mozilla/ipc/BrowserProcessSubThread.h"
      65                 : #include "mozilla/Omnijar.h"
      66                 : #include <sys/stat.h>
      67                 : 
      68                 : #ifdef XP_WIN
      69                 : #include "nsIWinTaskbar.h"
      70                 : #define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
      71                 : #endif
      72                 : 
      73                 : #ifdef MOZ_WIDGET_ANDROID
      74                 : #include "APKOpen.h"
      75                 : #endif
      76                 : 
      77                 : using mozilla::MonitorAutoLock;
      78                 : using mozilla::ipc::GeckoChildProcessHost;
      79                 : 
      80                 : #ifdef MOZ_WIDGET_ANDROID
      81                 : // Like its predecessor in nsExceptionHandler.cpp, this is
      82                 : // the magic number of a file descriptor remapping we must
      83                 : // preserve for the child process.
      84                 : static const int kMagicAndroidSystemPropFd = 5;
      85                 : #endif
      86                 : 
      87                 : static bool
      88               0 : ShouldHaveDirectoryService()
      89                 : {
      90               0 :   return GeckoProcessType_Default == XRE_GetProcessType();
      91                 : }
      92                 : 
      93                 : template<>
      94                 : struct RunnableMethodTraits<GeckoChildProcessHost>
      95               0 : {
      96               0 :     static void RetainCallee(GeckoChildProcessHost* obj) { }
      97               0 :     static void ReleaseCallee(GeckoChildProcessHost* obj) { }
      98                 : };
      99                 : 
     100               0 : GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
     101                 :                                              base::WaitableEventWatcher::Delegate* aDelegate)
     102                 :   : ChildProcessHost(RENDER_PROCESS), // FIXME/cjones: we should own this enum
     103                 :     mProcessType(aProcessType),
     104                 :     mMonitor("mozilla.ipc.GeckChildProcessHost.mMonitor"),
     105                 :     mLaunched(false),
     106                 :     mChannelInitialized(false),
     107                 :     mDelegate(aDelegate),
     108               0 :     mChildProcessHandle(0)
     109                 : #if defined(MOZ_WIDGET_COCOA)
     110                 :   , mChildTask(MACH_PORT_NULL)
     111                 : #endif
     112                 : {
     113               0 :     MOZ_COUNT_CTOR(GeckoChildProcessHost);
     114                 :     
     115               0 :     MessageLoop* ioLoop = XRE_GetIOMessageLoop();
     116                 :     ioLoop->PostTask(FROM_HERE,
     117                 :                      NewRunnableMethod(this,
     118               0 :                                        &GeckoChildProcessHost::InitializeChannel));
     119               0 : }
     120                 : 
     121               0 : GeckoChildProcessHost::~GeckoChildProcessHost()
     122                 : 
     123                 : {
     124               0 :   AssertIOThread();
     125                 : 
     126               0 :   MOZ_COUNT_DTOR(GeckoChildProcessHost);
     127                 : 
     128               0 :   if (mChildProcessHandle > 0)
     129                 :     ProcessWatcher::EnsureProcessTerminated(mChildProcessHandle
     130                 : #if defined(NS_BUILD_REFCNT_LOGGING)
     131                 :                                             , false // don't "force"
     132                 : #endif
     133               0 :     );
     134                 : 
     135                 : #if defined(MOZ_WIDGET_COCOA)
     136                 :   if (mChildTask != MACH_PORT_NULL)
     137                 :     mach_port_deallocate(mach_task_self(), mChildTask);
     138                 : #endif
     139               0 : }
     140                 : 
     141               0 : void GetPathToBinary(FilePath& exePath)
     142                 : {
     143                 : #if defined(OS_WIN)
     144                 :   exePath = FilePath::FromWStringHack(CommandLine::ForCurrentProcess()->program());
     145                 :   exePath = exePath.DirName();
     146                 :   exePath = exePath.AppendASCII(MOZ_CHILD_PROCESS_NAME);
     147                 : #elif defined(OS_POSIX)
     148               0 :   if (ShouldHaveDirectoryService()) {
     149               0 :     nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
     150               0 :     NS_ASSERTION(directoryService, "Expected XPCOM to be available");
     151               0 :     if (directoryService) {
     152               0 :       nsCOMPtr<nsIFile> greDir;
     153               0 :       nsresult rv = directoryService->Get(NS_GRE_DIR, NS_GET_IID(nsIFile), getter_AddRefs(greDir));
     154               0 :       if (NS_SUCCEEDED(rv)) {
     155               0 :         nsCString path;
     156               0 :         greDir->GetNativePath(path);
     157               0 :         exePath = FilePath(path.get());
     158                 : #ifdef MOZ_WIDGET_COCOA
     159                 :         // We need to use an App Bundle on OS X so that we can hide
     160                 :         // the dock icon. See Bug 557225.
     161                 :         exePath = exePath.AppendASCII(MOZ_CHILD_PROCESS_BUNDLE);
     162                 : #endif
     163                 :       }
     164                 :     }
     165                 :   }
     166                 : 
     167               0 :   if (exePath.empty()) {
     168               0 :     exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
     169               0 :     exePath = exePath.DirName();
     170                 :   }
     171                 : 
     172               0 :   exePath = exePath.AppendASCII(MOZ_CHILD_PROCESS_NAME);
     173                 : #endif
     174               0 : }
     175                 : 
     176                 : #ifdef MOZ_WIDGET_COCOA
     177                 : class AutoCFTypeObject {
     178                 : public:
     179                 :   AutoCFTypeObject(CFTypeRef object)
     180                 :   {
     181                 :     mObject = object;
     182                 :   }
     183                 :   ~AutoCFTypeObject()
     184                 :   {
     185                 :     ::CFRelease(mObject);
     186                 :   }
     187                 : private:
     188                 :   CFTypeRef mObject;
     189                 : };
     190                 : #endif
     191                 : 
     192               0 : nsresult GeckoChildProcessHost::GetArchitecturesForBinary(const char *path, uint32 *result)
     193                 : {
     194               0 :   *result = 0;
     195                 : 
     196                 : #ifdef MOZ_WIDGET_COCOA
     197                 :   CFURLRef url = ::CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
     198                 :                                                            (const UInt8*)path,
     199                 :                                                            strlen(path),
     200                 :                                                            false);
     201                 :   if (!url) {
     202                 :     return NS_ERROR_FAILURE;
     203                 :   }
     204                 :   AutoCFTypeObject autoPluginContainerURL(url);
     205                 : 
     206                 :   CFArrayRef pluginContainerArchs = ::CFBundleCopyExecutableArchitecturesForURL(url);
     207                 :   if (!pluginContainerArchs) {
     208                 :     return NS_ERROR_FAILURE;
     209                 :   }
     210                 :   AutoCFTypeObject autoPluginContainerArchs(pluginContainerArchs);
     211                 : 
     212                 :   CFIndex pluginArchCount = ::CFArrayGetCount(pluginContainerArchs);
     213                 :   for (CFIndex i = 0; i < pluginArchCount; i++) {
     214                 :     CFNumberRef currentArch = static_cast<CFNumberRef>(::CFArrayGetValueAtIndex(pluginContainerArchs, i));
     215                 :     int currentArchInt = 0;
     216                 :     if (!::CFNumberGetValue(currentArch, kCFNumberIntType, &currentArchInt)) {
     217                 :       continue;
     218                 :     }
     219                 :     switch (currentArchInt) {
     220                 :       case kCFBundleExecutableArchitectureI386:
     221                 :         *result |= base::PROCESS_ARCH_I386;
     222                 :         break;
     223                 :       case kCFBundleExecutableArchitectureX86_64:
     224                 :         *result |= base::PROCESS_ARCH_X86_64;
     225                 :         break;
     226                 :       case kCFBundleExecutableArchitecturePPC:
     227                 :         *result |= base::PROCESS_ARCH_PPC;
     228                 :         break;
     229                 :       default:
     230                 :         break;
     231                 :     }
     232                 :   }
     233                 : 
     234                 :   return (*result ? NS_OK : NS_ERROR_FAILURE);
     235                 : #else
     236               0 :   return NS_ERROR_NOT_IMPLEMENTED;
     237                 : #endif
     238                 : }
     239                 : 
     240               0 : uint32 GeckoChildProcessHost::GetSupportedArchitecturesForProcessType(GeckoProcessType type)
     241                 : {
     242                 : #ifdef MOZ_WIDGET_COCOA
     243                 :   if (type == GeckoProcessType_Plugin) {
     244                 :     // Cache this, it shouldn't ever change.
     245                 :     static uint32 pluginContainerArchs = 0;
     246                 :     if (pluginContainerArchs == 0) {
     247                 :       FilePath exePath;
     248                 :       GetPathToBinary(exePath);
     249                 :       nsresult rv = GetArchitecturesForBinary(exePath.value().c_str(), &pluginContainerArchs);
     250                 :       NS_ASSERTION(NS_SUCCEEDED(rv) && pluginContainerArchs != 0, "Getting architecture of plugin container failed!");
     251                 :       if (NS_FAILED(rv) || pluginContainerArchs == 0) {
     252                 :         pluginContainerArchs = base::GetCurrentProcessArchitecture();
     253                 :       }
     254                 :     }
     255                 :     return pluginContainerArchs;
     256                 :   }
     257                 : #endif
     258                 : 
     259               0 :   return base::GetCurrentProcessArchitecture();
     260                 : }
     261                 : 
     262                 : #ifdef XP_WIN
     263                 : void GeckoChildProcessHost::InitWindowsGroupID()
     264                 : {
     265                 :   // On Win7+, pass the application user model to the child, so it can
     266                 :   // register with it. This insures windows created by the container
     267                 :   // properly group with the parent app on the Win7 taskbar.
     268                 :   nsCOMPtr<nsIWinTaskbar> taskbarInfo =
     269                 :     do_GetService(NS_TASKBAR_CONTRACTID);
     270                 :   if (taskbarInfo) {
     271                 :     bool isSupported = false;
     272                 :     taskbarInfo->GetAvailable(&isSupported);
     273                 :     nsAutoString appId;
     274                 :     if (isSupported && NS_SUCCEEDED(taskbarInfo->GetDefaultGroupId(appId))) {
     275                 :       mGroupId.Append(appId);
     276                 :     } else {
     277                 :       mGroupId.AssignLiteral("-");
     278                 :     }
     279                 :   }
     280                 : }
     281                 : #endif
     282                 : 
     283                 : bool
     284               0 : GeckoChildProcessHost::SyncLaunch(std::vector<std::string> aExtraOpts, int aTimeoutMs, base::ProcessArchitecture arch)
     285                 : {
     286                 : #ifdef XP_WIN
     287                 :   InitWindowsGroupID();
     288                 : #endif
     289                 : 
     290                 :   PRIntervalTime timeoutTicks = (aTimeoutMs > 0) ? 
     291               0 :     PR_MillisecondsToInterval(aTimeoutMs) : PR_INTERVAL_NO_TIMEOUT;
     292               0 :   MessageLoop* ioLoop = XRE_GetIOMessageLoop();
     293               0 :   NS_ASSERTION(MessageLoop::current() != ioLoop, "sync launch from the IO thread NYI");
     294                 : 
     295                 :   ioLoop->PostTask(FROM_HERE,
     296                 :                    NewRunnableMethod(this,
     297                 :                                      &GeckoChildProcessHost::PerformAsyncLaunch,
     298               0 :                                      aExtraOpts, arch));
     299                 :   // NB: this uses a different mechanism than the chromium parent
     300                 :   // class.
     301               0 :   MonitorAutoLock lock(mMonitor);
     302               0 :   PRIntervalTime waitStart = PR_IntervalNow();
     303                 :   PRIntervalTime current;
     304                 : 
     305                 :   // We'll receive several notifications, we need to exit when we
     306                 :   // have either successfully launched or have timed out.
     307               0 :   while (!mLaunched) {
     308               0 :     lock.Wait(timeoutTicks);
     309                 : 
     310               0 :     if (timeoutTicks != PR_INTERVAL_NO_TIMEOUT) {
     311               0 :       current = PR_IntervalNow();
     312               0 :       PRIntervalTime elapsed = current - waitStart;
     313               0 :       if (elapsed > timeoutTicks) {
     314               0 :         break;
     315                 :       }
     316               0 :       timeoutTicks = timeoutTicks - elapsed;
     317               0 :       waitStart = current;
     318                 :     }
     319                 :   }
     320                 : 
     321               0 :   return mLaunched;
     322                 : }
     323                 : 
     324                 : bool
     325               0 : GeckoChildProcessHost::AsyncLaunch(std::vector<std::string> aExtraOpts)
     326                 : {
     327                 : #ifdef XP_WIN
     328                 :   InitWindowsGroupID();
     329                 : #endif
     330                 : 
     331               0 :   MessageLoop* ioLoop = XRE_GetIOMessageLoop();
     332                 :   ioLoop->PostTask(FROM_HERE,
     333                 :                    NewRunnableMethod(this,
     334                 :                                      &GeckoChildProcessHost::PerformAsyncLaunch,
     335               0 :                                      aExtraOpts, base::GetCurrentProcessArchitecture()));
     336                 : 
     337                 :   // This may look like the sync launch wait, but we only delay as
     338                 :   // long as it takes to create the channel.
     339               0 :   MonitorAutoLock lock(mMonitor);
     340               0 :   while (!mChannelInitialized) {
     341               0 :     lock.Wait();
     342                 :   }
     343                 : 
     344               0 :   return true;
     345                 : }
     346                 : 
     347                 : void
     348               0 : GeckoChildProcessHost::InitializeChannel()
     349                 : {
     350               0 :   CreateChannel();
     351                 : 
     352               0 :   MonitorAutoLock lock(mMonitor);
     353               0 :   mChannelInitialized = true;
     354               0 :   lock.Notify();
     355               0 : }
     356                 : 
     357                 : PRInt32 GeckoChildProcessHost::mChildCounter = 0;
     358                 : 
     359                 : //
     360                 : // Wrapper function for handling GECKO_SEPARATE_NSPR_LOGS
     361                 : //
     362                 : bool
     363               0 : GeckoChildProcessHost::PerformAsyncLaunch(std::vector<std::string> aExtraOpts, base::ProcessArchitecture arch)
     364                 : {
     365                 :   // If separate NSPR log files are not requested, we're done.
     366               0 :   const char* origLogName = PR_GetEnv("NSPR_LOG_FILE");
     367               0 :   const char* separateLogs = PR_GetEnv("GECKO_SEPARATE_NSPR_LOGS");
     368               0 :   if (!origLogName || !separateLogs || !*separateLogs ||
     369                 :       *separateLogs == '0' || *separateLogs == 'N' || *separateLogs == 'n') {
     370               0 :     return PerformAsyncLaunchInternal(aExtraOpts, arch);
     371                 :   }
     372                 : 
     373                 :   // We currently have no portable way to launch child with environment
     374                 :   // different than parent.  So temporarily change NSPR_LOG_FILE so child
     375                 :   // inherits value we want it to have. (NSPR only looks at NSPR_LOG_FILE at
     376                 :   // startup, so it's 'safe' to play with the parent's environment this way.)
     377               0 :   nsCAutoString setChildLogName("NSPR_LOG_FILE=");
     378               0 :   setChildLogName.Append(origLogName);
     379                 : 
     380                 :   // remember original value so we can restore it.
     381                 :   // - buffer needs to be permanently allocated for PR_SetEnv()
     382                 :   // - Note: this code is not called re-entrantly, nor are restoreOrigLogName
     383                 :   //   or mChildCounter touched by any other thread, so this is safe.
     384                 :   static char* restoreOrigLogName = 0;
     385               0 :   if (!restoreOrigLogName)
     386               0 :     restoreOrigLogName = strdup(setChildLogName.get());
     387                 : 
     388                 :   // Append child-specific postfix to name
     389               0 :   setChildLogName.AppendLiteral(".child-");
     390               0 :   setChildLogName.AppendInt(++mChildCounter);
     391                 : 
     392                 :   // Passing temporary to PR_SetEnv is ok here because env gets copied
     393                 :   // by exec, etc., to permanent storage in child when process launched.
     394               0 :   PR_SetEnv(setChildLogName.get());
     395               0 :   bool retval = PerformAsyncLaunchInternal(aExtraOpts, arch);
     396                 : 
     397                 :   // Revert to original value
     398               0 :   PR_SetEnv(restoreOrigLogName);
     399                 : 
     400               0 :   return retval;
     401                 : }
     402                 : 
     403                 : bool
     404               0 : GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExtraOpts, base::ProcessArchitecture arch)
     405                 : {
     406                 :   // FIXME/cjones: make this work from non-IO threads, too
     407                 : 
     408                 :   // We rely on the fact that InitializeChannel() has already been processed
     409                 :   // on the IO thread before this point is reached.
     410               0 :   if (!GetChannel()) {
     411               0 :     return false;
     412                 :   }
     413                 : 
     414                 :   base::ProcessHandle process;
     415                 : 
     416                 :   // send the child the PID so that it can open a ProcessHandle back to us.
     417                 :   // probably don't want to do this in the long run
     418                 :   char pidstring[32];
     419                 :   PR_snprintf(pidstring, sizeof(pidstring) - 1,
     420               0 :               "%ld", base::Process::Current().pid());
     421                 : 
     422                 :   const char* const childProcessType =
     423               0 :       XRE_ChildProcessTypeToString(mProcessType);
     424                 : 
     425                 : //--------------------------------------------------
     426                 : #if defined(OS_POSIX)
     427                 :   // For POSIX, we have to be extremely anal about *not* using
     428                 :   // std::wstring in code compiled with Mozilla's -fshort-wchar
     429                 :   // configuration, because chromium is compiled with -fno-short-wchar
     430                 :   // and passing wstrings from one config to the other is unsafe.  So
     431                 :   // we split the logic here.
     432                 : 
     433                 : #if defined(OS_LINUX) || defined(OS_MACOSX)
     434               0 :   base::environment_map newEnvVars;
     435                 :   // XPCOM may not be initialized in some subprocesses.  We don't want
     436                 :   // to initialize XPCOM just for the directory service, especially
     437                 :   // since LD_LIBRARY_PATH is already set correctly in subprocesses
     438                 :   // (meaning that we don't need to set that up in the environment).
     439               0 :   if (ShouldHaveDirectoryService()) {
     440               0 :     nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
     441               0 :     NS_ASSERTION(directoryService, "Expected XPCOM to be available");
     442               0 :     if (directoryService) {
     443               0 :       nsCOMPtr<nsIFile> greDir;
     444               0 :       nsresult rv = directoryService->Get(NS_GRE_DIR, NS_GET_IID(nsIFile), getter_AddRefs(greDir));
     445               0 :       if (NS_SUCCEEDED(rv)) {
     446               0 :         nsCString path;
     447               0 :         greDir->GetNativePath(path);
     448                 : # ifdef OS_LINUX
     449                 : #  ifdef MOZ_WIDGET_ANDROID
     450                 :         path += "/lib";
     451                 : #  endif  // MOZ_WIDGET_ANDROID
     452               0 :         const char *ld_library_path = PR_GetEnv("LD_LIBRARY_PATH");
     453               0 :         nsCString new_ld_lib_path;
     454               0 :         if (ld_library_path && *ld_library_path) {
     455               0 :             new_ld_lib_path.Assign(path.get());
     456               0 :             new_ld_lib_path.AppendLiteral(":");
     457               0 :             new_ld_lib_path.Append(ld_library_path);
     458               0 :             newEnvVars["LD_LIBRARY_PATH"] = new_ld_lib_path.get();
     459                 :         } else {
     460               0 :             newEnvVars["LD_LIBRARY_PATH"] = path.get();
     461                 :         }
     462                 : # elif OS_MACOSX
     463                 :         newEnvVars["DYLD_LIBRARY_PATH"] = path.get();
     464                 :         // XXX DYLD_INSERT_LIBRARIES should only be set when launching a plugin
     465                 :         //     process, and has no effect on other subprocesses (the hooks in
     466                 :         //     libplugin_child_interpose.dylib become noops).  But currently it
     467                 :         //     gets set when launching any kind of subprocess.
     468                 :         //
     469                 :         // Trigger "dyld interposing" for the dylib that contains
     470                 :         // plugin_child_interpose.mm.  This allows us to hook OS calls in the
     471                 :         // plugin process (ones that don't work correctly in a background
     472                 :         // process).  Don't break any other "dyld interposing" that has already
     473                 :         // been set up by whatever may have launched the browser.
     474                 :         const char* prevInterpose = PR_GetEnv("DYLD_INSERT_LIBRARIES");
     475                 :         nsCString interpose;
     476                 :         if (prevInterpose) {
     477                 :           interpose.Assign(prevInterpose);
     478                 :           interpose.AppendLiteral(":");
     479                 :         }
     480                 :         interpose.Append(path.get());
     481                 :         interpose.AppendLiteral("/libplugin_child_interpose.dylib");
     482                 :         newEnvVars["DYLD_INSERT_LIBRARIES"] = interpose.get();
     483                 : # endif  // OS_LINUX
     484                 :       }
     485                 :     }
     486                 :   }
     487                 : #endif  // OS_LINUX || OS_MACOSX
     488                 : 
     489               0 :   FilePath exePath;
     490               0 :   GetPathToBinary(exePath);
     491                 : 
     492                 : #ifdef MOZ_WIDGET_ANDROID
     493                 :   // The java wrapper unpacks this for us but can't make it executable
     494                 :   chmod(exePath.value().c_str(), 0700);
     495                 :   int cacheCount = 0;
     496                 :   const struct lib_cache_info * cache = getLibraryCache();
     497                 :   nsCString cacheStr;
     498                 :   while (cache &&
     499                 :          cacheCount++ < MAX_LIB_CACHE_ENTRIES &&
     500                 :          strlen(cache->name)) {
     501                 :     mFileMap.push_back(std::pair<int,int>(cache->fd, cache->fd));
     502                 :     cacheStr.Append(cache->name);
     503                 :     cacheStr.AppendPrintf(":%d;", cache->fd);
     504                 :     cache++;
     505                 :   }
     506                 :   // fill the last arg with something if there's no cache
     507                 :   if (cacheStr.IsEmpty())
     508                 :     cacheStr.AppendLiteral("-");
     509                 : 
     510                 :   // Remap the Android property workspace to a well-known int,
     511                 :   // and update the environment to reflect the new value for the
     512                 :   // child process.
     513                 :   const char *apws = getenv("ANDROID_PROPERTY_WORKSPACE");
     514                 :   if (apws) {
     515                 :     int fd = atoi(apws);
     516                 :     mFileMap.push_back(std::pair<int, int>(fd, kMagicAndroidSystemPropFd));
     517                 : 
     518                 :     char buf[32];
     519                 :     char *szptr = strchr(apws, ',');
     520                 : 
     521                 :     snprintf(buf, sizeof(buf), "%d%s", kMagicAndroidSystemPropFd, szptr);
     522                 :     newEnvVars["ANDROID_PROPERTY_WORKSPACE"] = buf;
     523                 :   }
     524                 : #endif  // MOZ_WIDGET_ANDROID
     525                 : 
     526                 :   // remap the IPC socket fd to a well-known int, as the OS does for
     527                 :   // STDOUT_FILENO, for example
     528                 :   int srcChannelFd, dstChannelFd;
     529               0 :   channel().GetClientFileDescriptorMapping(&srcChannelFd, &dstChannelFd);
     530               0 :   mFileMap.push_back(std::pair<int,int>(srcChannelFd, dstChannelFd));
     531                 : 
     532                 :   // no need for kProcessChannelID, the child process inherits the
     533                 :   // other end of the socketpair() from us
     534                 : 
     535               0 :   std::vector<std::string> childArgv;
     536                 : 
     537               0 :   childArgv.push_back(exePath.value());
     538                 : 
     539               0 :   childArgv.insert(childArgv.end(), aExtraOpts.begin(), aExtraOpts.end());
     540                 : 
     541               0 :   if (Omnijar::IsInitialized()) {
     542                 :     // Make sure that child processes can find the omnijar
     543                 :     // See XRE_InitCommandLine in nsAppRunner.cpp
     544               0 :     nsCAutoString path;
     545               0 :     nsCOMPtr<nsIFile> file = Omnijar::GetPath(Omnijar::GRE);
     546               0 :     if (file && NS_SUCCEEDED(file->GetNativePath(path))) {
     547               0 :       childArgv.push_back("-greomni");
     548               0 :       childArgv.push_back(path.get());
     549                 :     }
     550               0 :     file = Omnijar::GetPath(Omnijar::APP);
     551               0 :     if (file && NS_SUCCEEDED(file->GetNativePath(path))) {
     552               0 :       childArgv.push_back("-appomni");
     553               0 :       childArgv.push_back(path.get());
     554                 :     }
     555                 :   }
     556                 : 
     557               0 :   childArgv.push_back(pidstring);
     558                 : 
     559                 : #if defined(MOZ_CRASHREPORTER)
     560                 : #  if defined(OS_LINUX)
     561                 :   int childCrashFd, childCrashRemapFd;
     562               0 :   if (!CrashReporter::CreateNotificationPipeForChild(
     563               0 :         &childCrashFd, &childCrashRemapFd))
     564               0 :     return false;
     565               0 :   if (0 <= childCrashFd) {
     566               0 :     mFileMap.push_back(std::pair<int,int>(childCrashFd, childCrashRemapFd));
     567                 :     // "true" == crash reporting enabled
     568               0 :     childArgv.push_back("true");
     569                 :   }
     570                 :   else {
     571                 :     // "false" == crash reporting disabled
     572               0 :     childArgv.push_back("false");
     573                 :   }
     574                 : #  elif defined(MOZ_WIDGET_COCOA)
     575                 :   childArgv.push_back(CrashReporter::GetChildNotificationPipe());
     576                 : #  endif  // OS_LINUX
     577                 : #endif
     578                 : 
     579                 : #ifdef MOZ_WIDGET_COCOA
     580                 :   // Add a mach port to the command line so the child can communicate its
     581                 :   // 'task_t' back to the parent.
     582                 :   //
     583                 :   // Put a random number into the channel name, so that a compromised renderer
     584                 :   // can't pretend being the child that's forked off.
     585                 :   std::string mach_connection_name = StringPrintf("org.mozilla.machname.%d",
     586                 :                                                   base::RandInt(0, std::numeric_limits<int>::max()));
     587                 :   childArgv.push_back(mach_connection_name.c_str());
     588                 : #endif
     589                 : 
     590               0 :   childArgv.push_back(childProcessType);
     591                 : 
     592                 : #ifdef MOZ_WIDGET_ANDROID
     593                 :   childArgv.push_back(cacheStr.get());
     594                 : #endif
     595                 : 
     596                 :   base::LaunchApp(childArgv, mFileMap,
     597                 : #if defined(OS_LINUX) || defined(OS_MACOSX)
     598                 :                   newEnvVars,
     599                 : #endif
     600               0 :                   false, &process, arch);
     601                 : 
     602                 : #ifdef MOZ_WIDGET_COCOA
     603                 :   // Wait for the child process to send us its 'task_t' data.
     604                 :   const int kTimeoutMs = 10000;
     605                 : 
     606                 :   MachReceiveMessage child_message;
     607                 :   ReceivePort parent_recv_port(mach_connection_name.c_str());
     608                 :   kern_return_t err = parent_recv_port.WaitForMessage(&child_message, kTimeoutMs);
     609                 :   if (err != KERN_SUCCESS) {
     610                 :     std::string errString = StringPrintf("0x%x %s", err, mach_error_string(err));
     611                 :     LOG(ERROR) << "parent WaitForMessage() failed: " << errString;
     612                 :     return false;
     613                 :   }
     614                 : 
     615                 :   task_t child_task = child_message.GetTranslatedPort(0);
     616                 :   if (child_task == MACH_PORT_NULL) {
     617                 :     LOG(ERROR) << "parent GetTranslatedPort(0) failed.";
     618                 :     return false;
     619                 :   }
     620                 : 
     621                 :   if (child_message.GetTranslatedPort(1) == MACH_PORT_NULL) {
     622                 :     LOG(ERROR) << "parent GetTranslatedPort(1) failed.";
     623                 :     return false;
     624                 :   }
     625                 :   MachPortSender parent_sender(child_message.GetTranslatedPort(1));
     626                 : 
     627                 :   MachSendMessage parent_message(/* id= */0);
     628                 :   if (!parent_message.AddDescriptor(bootstrap_port)) {
     629                 :     LOG(ERROR) << "parent AddDescriptor(" << bootstrap_port << ") failed.";
     630                 :     return false;
     631                 :   }
     632                 : 
     633                 :   err = parent_sender.SendMessage(parent_message, kTimeoutMs);
     634                 :   if (err != KERN_SUCCESS) {
     635                 :     std::string errString = StringPrintf("0x%x %s", err, mach_error_string(err));
     636                 :     LOG(ERROR) << "parent SendMessage() failed: " << errString;
     637                 :     return false;
     638                 :   }
     639                 : #endif
     640                 : 
     641                 : //--------------------------------------------------
     642                 : #elif defined(OS_WIN)
     643                 : 
     644                 :   FilePath exePath;
     645                 :   GetPathToBinary(exePath);
     646                 : 
     647                 :   CommandLine cmdLine(exePath.ToWStringHack());
     648                 :   cmdLine.AppendSwitchWithValue(switches::kProcessChannelID, channel_id());
     649                 : 
     650                 :   for (std::vector<std::string>::iterator it = aExtraOpts.begin();
     651                 :        it != aExtraOpts.end();
     652                 :        ++it) {
     653                 :       cmdLine.AppendLooseValue(UTF8ToWide(*it));
     654                 :   }
     655                 : 
     656                 :   cmdLine.AppendLooseValue(std::wstring(mGroupId.get()));
     657                 : 
     658                 :   if (Omnijar::IsInitialized()) {
     659                 :     // Make sure the child process can find the omnijar
     660                 :     // See XRE_InitCommandLine in nsAppRunner.cpp
     661                 :     nsAutoString path;
     662                 :     nsCOMPtr<nsIFile> file = Omnijar::GetPath(Omnijar::GRE);
     663                 :     if (file && NS_SUCCEEDED(file->GetPath(path))) {
     664                 :       cmdLine.AppendLooseValue(UTF8ToWide("-greomni"));
     665                 :       cmdLine.AppendLooseValue(path.get());
     666                 :     }
     667                 :     file = Omnijar::GetPath(Omnijar::APP);
     668                 :     if (file && NS_SUCCEEDED(file->GetPath(path))) {
     669                 :       cmdLine.AppendLooseValue(UTF8ToWide("-appomni"));
     670                 :       cmdLine.AppendLooseValue(path.get());
     671                 :     }
     672                 :   }
     673                 : 
     674                 :   cmdLine.AppendLooseValue(UTF8ToWide(pidstring));
     675                 : 
     676                 : #if defined(MOZ_CRASHREPORTER)
     677                 :   cmdLine.AppendLooseValue(
     678                 :     UTF8ToWide(CrashReporter::GetChildNotificationPipe()));
     679                 : #endif
     680                 : 
     681                 :   cmdLine.AppendLooseValue(UTF8ToWide(childProcessType));
     682                 : 
     683                 :   base::LaunchApp(cmdLine, false, false, &process);
     684                 : 
     685                 : #else
     686                 : #  error Sorry
     687                 : #endif
     688                 : 
     689               0 :   if (!process) {
     690               0 :     return false;
     691                 :   }
     692               0 :   SetHandle(process);
     693                 : #if defined(MOZ_WIDGET_COCOA)
     694                 :   mChildTask = child_task;
     695                 : #endif
     696                 : 
     697               0 :   return true;
     698                 : }
     699                 : 
     700                 : void
     701               0 : GeckoChildProcessHost::OnChannelConnected(int32 peer_pid)
     702                 : {
     703               0 :   MonitorAutoLock lock(mMonitor);
     704               0 :   mLaunched = true;
     705                 : 
     706               0 :   if (!base::OpenPrivilegedProcessHandle(peer_pid, &mChildProcessHandle))
     707               0 :       NS_RUNTIMEABORT("can't open handle to child process");
     708                 : 
     709               0 :   lock.Notify();
     710               0 : }
     711                 : 
     712                 : // XXX/cjones: these next two methods should basically never be called.
     713                 : // after the process is launched, its channel will be used to create
     714                 : // one of our channels, AsyncChannel et al.
     715                 : void
     716               0 : GeckoChildProcessHost::OnMessageReceived(const IPC::Message& aMsg)
     717                 : {
     718               0 : }
     719                 : void
     720               0 : GeckoChildProcessHost::OnChannelError()
     721                 : {
     722                 :   // XXXbent Notify that the child process is gone?
     723               0 : }
     724                 : 
     725                 : void
     726               0 : GeckoChildProcessHost::OnWaitableEventSignaled(base::WaitableEvent *event)
     727                 : {
     728               0 :   if (mDelegate) {
     729               0 :     mDelegate->OnWaitableEventSignaled(event);
     730                 :   }
     731               0 :   ChildProcessHost::OnWaitableEventSignaled(event);
     732               0 : }

Generated by: LCOV version 1.7