LCOV - app.info - ipc/glue/GeckoChildProcessHost.cpp

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-07-07 | 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