1/*
2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "ProcessLauncher.h"
28
29#include "Connection.h"
30#include "RunLoop.h"
31#include <shlwapi.h>
32#include <wtf/text/WTFString.h>
33
34#ifdef DEBUG_ALL
35const LPCWSTR webProcessName = L"WebKit2WebProcess_debug.exe";
36#else
37const LPCWSTR webProcessName = L"WebKit2WebProcess.exe";
38#endif
39
40#ifdef DEBUG_ALL
41const LPCWSTR webKitDLLName = L"WebKit_debug.dll";
42#else
43const LPCWSTR webKitDLLName = L"WebKit.dll";
44#endif
45
46namespace WebKit {
47
48void ProcessLauncher::launchProcess()
49{
50    // First, create the server and client identifiers.
51    HANDLE serverIdentifier, clientIdentifier;
52    if (!CoreIPC::Connection::createServerAndClientIdentifiers(serverIdentifier, clientIdentifier)) {
53        // FIXME: What should we do here?
54        ASSERT_NOT_REACHED();
55    }
56
57    // Ensure that the child process inherits the client identifier.
58    ::SetHandleInformation(clientIdentifier, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
59
60    // To get the full file path to WebKit2WebProcess.exe, we fild the location of WebKit.dll,
61    // remove the last path component, and then append WebKit2WebProcess(_debug).exe.
62    HMODULE webKitModule = ::GetModuleHandleW(webKitDLLName);
63    ASSERT(webKitModule);
64    if (!webKitModule)
65        return;
66
67    WCHAR pathStr[MAX_PATH];
68    if (!::GetModuleFileNameW(webKitModule, pathStr, WTF_ARRAY_LENGTH(pathStr)))
69        return;
70
71    ::PathRemoveFileSpecW(pathStr);
72    if (!::PathAppendW(pathStr, webProcessName))
73        return;
74
75    String commandLine(pathStr);
76
77    // FIXME: It would be nice if we could just create a CommandLine object and output a command line vector from it.
78    Vector<UChar> commandLineVector;
79    append(commandLineVector, "\"");
80    append(commandLineVector, commandLine);
81    append(commandLineVector, "\"");
82    append(commandLineVector, " -type webprocess");
83    append(commandLineVector, " -clientIdentifier ");
84    append(commandLineVector, String::number(reinterpret_cast<uintptr_t>(clientIdentifier)));
85    commandLineVector.append('\0');
86
87    STARTUPINFO startupInfo = { 0 };
88    startupInfo.cb = sizeof(startupInfo);
89    PROCESS_INFORMATION processInformation = { 0 };
90    BOOL result = ::CreateProcessW(0, commandLineVector.data(), 0, 0, true, 0, 0, 0, &startupInfo, &processInformation);
91
92    // We can now close the client identifier handle.
93    ::CloseHandle(clientIdentifier);
94
95    if (!result) {
96        // FIXME: What should we do here?
97        DWORD error = ::GetLastError();
98        ASSERT_NOT_REACHED();
99    }
100
101    // Don't leak the thread handle.
102    ::CloseHandle(processInformation.hThread);
103
104    // We've finished launching the process, message back to the run loop.
105    RunLoop::main()->scheduleWork(WorkItem::create(this, &ProcessLauncher::didFinishLaunchingProcess, processInformation.hProcess, serverIdentifier));
106}
107
108void ProcessLauncher::terminateProcess()
109{
110    if (!m_processIdentifier)
111        return;
112
113    ::TerminateProcess(m_processIdentifier, 0);
114}
115
116void ProcessLauncher::platformInvalidate()
117{
118    if (!m_processIdentifier)
119        return;
120
121    ::CloseHandle(m_processIdentifier);
122    m_processIdentifier = 0;
123}
124
125} // namespace WebKit
126