1 // Copyright 2018 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.
4 
5 #ifndef CHROME_CHROME_CLEANER_IPC_IPC_TEST_UTIL_H_
6 #define CHROME_CHROME_CLEANER_IPC_IPC_TEST_UTIL_H_
7 
8 #include <memory>
9 #include <string>
10 
11 #include "base/callback_forward.h"
12 #include "base/command_line.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/process/launch.h"
15 #include "base/process/process.h"
16 #include "base/time/time.h"
17 #include "chrome/chrome_cleaner/ipc/chrome_prompt_ipc.h"
18 #include "chrome/chrome_cleaner/ipc/mojo_task_runner.h"
19 #include "chrome/chrome_cleaner/test/child_process_logger.h"
20 #include "mojo/public/cpp/platform/platform_channel.h"
21 #include "mojo/public/cpp/system/invitation.h"
22 #include "mojo/public/cpp/system/message_pipe.h"
23 
24 namespace chrome_cleaner {
25 
26 typedef base::RepeatingCallback<void(mojo::ScopedMessagePipeHandle mojo_pipe)>
27     CreateImplCallback;
28 
29 class ParentProcess : public base::RefCountedThreadSafe<ParentProcess> {
30  public:
31   explicit ParentProcess(scoped_refptr<MojoTaskRunner> mojo_task_runner);
32 
33   bool LaunchConnectedChildProcess(const std::string& child_main_function,
34                                    int32_t* exit_code);
35 
36   bool LaunchConnectedChildProcess(const std::string& child_main_function,
37                                    base::TimeDelta timeout,
38                                    int32_t* exit_code);
39 
40   void AppendSwitch(const std::string& switch_string);
41   void AppendSwitch(const std::string& switch_string, const std::string& value);
42   void AppendSwitchNative(const std::string& switch_string,
43                           const std::wstring& value);
44   void AppendSwitchPath(const std::string& switch_string,
45                         const base::FilePath& value);
46   void AppendSwitchHandleToShare(const std::string& switch_string,
47                                  HANDLE handle);
48 
49   // The following methods are called during the launch sequence. They are
50   // public so they can be called from helper classes.
51   void CreateImplOnIPCThread(mojo::ScopedMessagePipeHandle mojo_pipe);
52   void DestroyImplOnIPCThread();
53   void CreateMojoPipe(base::CommandLine* command_line,
54                       base::HandlesToInheritVector* handles_to_inherit);
55   void ConnectMojoPipe(base::Process child_process);
56 
extra_handles_to_inherit()57   base::HandlesToInheritVector extra_handles_to_inherit() const {
58     return extra_handles_to_inherit_;
59   }
60 
child_process_logger()61   const ChildProcessLogger& child_process_logger() const {
62     return child_process_logger_;
63   }
64 
65  protected:
66   friend base::RefCountedThreadSafe<ParentProcess>;
67   virtual ~ParentProcess();
68 
69   // This is called on the IPC thread.
70   virtual void CreateImpl(mojo::ScopedMessagePipeHandle mojo_pipe) = 0;
71   virtual void DestroyImpl() = 0;
72 
73   // Subclasses can override this to launch the child in different ways, such
74   // as in the sandbox. Subclasses should call CreateMojoPipe before the
75   // subprocess is spawned and ConnectMojoPipe afterward.
76   virtual bool PrepareAndLaunchTestChildProcess(
77       const std::string& child_main_function);
78 
79   scoped_refptr<MojoTaskRunner> mojo_task_runner();
80 
81   base::CommandLine command_line_;
82   base::HandlesToInheritVector extra_handles_to_inherit_;
83   ChildProcessLogger child_process_logger_;
84 
85  private:
86   scoped_refptr<MojoTaskRunner> mojo_task_runner_;
87   mojo::OutgoingInvitation outgoing_invitation_;
88   mojo::ScopedMessagePipeHandle mojo_pipe_;
89   mojo::PlatformChannel mojo_channel_;
90   base::Process child_process_;
91 };
92 
93 class SandboxedParentProcess : public ParentProcess {
94  public:
95   explicit SandboxedParentProcess(
96       scoped_refptr<MojoTaskRunner> mojo_task_runner);
97 
98  protected:
99   friend base::RefCountedThreadSafe<SandboxedParentProcess>;
100   ~SandboxedParentProcess() override;
101 
102   bool PrepareAndLaunchTestChildProcess(
103       const std::string& child_main_function) override;
104 };
105 
106 class ChildProcess : public base::RefCountedThreadSafe<ChildProcess> {
107  public:
108   explicit ChildProcess(scoped_refptr<MojoTaskRunner> mojo_task_runner);
109 
110   mojo::ScopedMessagePipeHandle CreateMessagePipeFromCommandLine();
111 
112   std::string mojo_pipe_token() const;
113 
command_line()114   const base::CommandLine& command_line() const { return *command_line_; }
115 
116   // This will drop all privileges if the child process is running in a
117   // sandbox. If not, it will do nothing.
118   void LowerToken() const;
119 
120  protected:
121   friend base::RefCountedThreadSafe<ChildProcess>;
122   virtual ~ChildProcess();
123 
124   scoped_refptr<MojoTaskRunner> mojo_task_runner_;
125 
126  private:
127   base::CommandLine* command_line_;
128 
129   // This will be true iff the process is running in a sandbox and
130   // TargetServices was initialized successfully.
131   bool target_services_initialized_ = false;
132 };
133 
134 class ChromePromptIPCTestErrorHandler : public ChromePromptIPC::ErrorHandler {
135  public:
136   ChromePromptIPCTestErrorHandler(base::OnceClosure on_closed,
137                                   base::OnceClosure on_closed_after_done);
138 
139   ~ChromePromptIPCTestErrorHandler() override;
140 
141   void OnConnectionClosed() override;
142   void OnConnectionClosedAfterDone() override;
143 
144  private:
145   base::OnceClosure on_closed_;
146   base::OnceClosure on_closed_after_done_;
147 };
148 
149 }  // namespace chrome_cleaner
150 
151 #endif  // CHROME_CHROME_CLEANER_IPC_IPC_TEST_UTIL_H_
152