1 // Copyright (c) 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/app/chrome_watcher_command_line_win.h"
9 #include "base/command_line.h"
10 #include "base/files/file_path.h"
11 #include "base/logging.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/stringprintf.h"
14 #include "chrome/common/chrome_switches.h"
18 const char kOnIninitializedEventHandleSwitch
[] = "on-initialized-event-handle";
19 const char kParentHandleSwitch
[] = "parent-handle";
20 const char kMainThreadIdSwitch
[] = "main-thread-id";
22 void AppendHandleSwitch(const std::string
& switch_name
,
24 base::CommandLine
* command_line
) {
25 command_line
->AppendSwitchASCII(
26 switch_name
, base::UintToString(reinterpret_cast<uint32_t>(handle
)));
29 uint32_t ReadUintSwitch(const base::CommandLine
& command_line
,
30 const std::string
& switch_name
) {
31 std::string switch_string
= command_line
.GetSwitchValueASCII(switch_name
);
32 unsigned int switch_uint
= 0;
33 if (switch_string
.empty() ||
34 !base::StringToUint(switch_string
, &switch_uint
)) {
35 DLOG(ERROR
) << "Missing or invalid " << switch_name
<< " argument.";
41 HANDLE
ReadHandleFromSwitch(const base::CommandLine
& command_line
,
42 const std::string
& switch_name
) {
43 return reinterpret_cast<HANDLE
>(ReadUintSwitch(command_line
, switch_name
));
48 base::CommandLine
GenerateChromeWatcherCommandLine(
49 const base::FilePath
& chrome_exe
,
50 HANDLE parent_process
,
52 HANDLE on_initialized_event
) {
53 base::CommandLine
command_line(chrome_exe
);
54 command_line
.AppendSwitchASCII(switches::kProcessType
, "watcher");
55 command_line
.AppendSwitchASCII(kMainThreadIdSwitch
,
56 base::UintToString(main_thread_id
));
57 AppendHandleSwitch(kOnIninitializedEventHandleSwitch
, on_initialized_event
,
59 AppendHandleSwitch(kParentHandleSwitch
, parent_process
, &command_line
);
63 bool InterpretChromeWatcherCommandLine(
64 const base::CommandLine
& command_line
,
65 base::win::ScopedHandle
* parent_process
,
66 DWORD
* main_thread_id
,
67 base::win::ScopedHandle
* on_initialized_event
) {
68 DCHECK(on_initialized_event
);
69 DCHECK(parent_process
);
71 // For consistency, always close any existing HANDLEs here.
72 on_initialized_event
->Close();
73 parent_process
->Close();
75 HANDLE parent_handle
=
76 ReadHandleFromSwitch(command_line
, kParentHandleSwitch
);
77 HANDLE on_initialized_event_handle
=
78 ReadHandleFromSwitch(command_line
, kOnIninitializedEventHandleSwitch
);
79 *main_thread_id
= ReadUintSwitch(command_line
, kMainThreadIdSwitch
);
82 // Initial test of the handle, a zero PID indicates invalid handle, or not
83 // a process handle. In this case, parsing fails and we avoid closing the
85 DWORD process_pid
= ::GetProcessId(parent_handle
);
86 if (process_pid
== 0) {
87 DLOG(ERROR
) << "Invalid " << kParentHandleSwitch
88 << " argument. Can't get parent PID.";
90 parent_process
->Set(parent_handle
);
94 if (on_initialized_event_handle
) {
95 DWORD result
= ::WaitForSingleObject(on_initialized_event_handle
, 0);
96 if (result
== WAIT_FAILED
) {
98 << "Unexpected error while testing the initialization event.";
99 } else if (result
!= WAIT_TIMEOUT
) {
100 DLOG(ERROR
) << "Unexpected result while testing the initialization event "
101 "with WaitForSingleObject: " << result
;
103 on_initialized_event
->Set(on_initialized_event_handle
);
107 if (!*main_thread_id
|| !on_initialized_event
->IsValid() ||
108 !parent_process
->IsValid()) {
109 // If one was valid and not the other, free the valid one.
110 on_initialized_event
->Close();
111 parent_process
->Close();