Flutter Engine
The Flutter Engine
process.cc
Go to the documentation of this file.
1// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "bin/process.h"
6
7#include "bin/dartutils.h"
8#include "bin/io_buffer.h"
9#include "bin/namespace.h"
10#include "bin/platform.h"
11#include "bin/socket.h"
12#include "bin/utils.h"
13#include "platform/syslog.h"
14
15#include "include/dart_api.h"
16
17namespace dart {
18namespace bin {
19
20static constexpr int kProcessIdNativeField = 0;
21
22// Extract an array of C strings from a list of Dart strings.
23static char** ExtractCStringList(Dart_Handle strings,
24 Dart_Handle status_handle,
25 const char* error_msg,
26 intptr_t* length) {
27 static constexpr intptr_t kMaxArgumentListLength = 1024 * 1024;
28 ASSERT(Dart_IsList(strings));
29 intptr_t len = 0;
32 // Protect against user-defined list implementations that can have
33 // arbitrary length.
34 if ((len < 0) || (len > kMaxArgumentListLength)) {
35 result = DartUtils::SetIntegerField(status_handle, "_errorCode", 0);
37 result = DartUtils::SetStringField(status_handle, "_errorMessage",
38 "Max argument list length exceeded");
40 return nullptr;
41 }
42 *length = len;
43 char** string_args;
44 string_args =
45 reinterpret_cast<char**>(Dart_ScopeAllocate(len * sizeof(*string_args)));
46 for (int i = 0; i < len; i++) {
47 Dart_Handle arg = Dart_ListGetAt(strings, i);
48 ThrowIfError(arg);
49 if (!Dart_IsString(arg)) {
50 result = DartUtils::SetIntegerField(status_handle, "_errorCode", 0);
52 result =
53 DartUtils::SetStringField(status_handle, "_errorMessage", error_msg);
55 return nullptr;
56 }
57 string_args[i] = const_cast<char*>(DartUtils::GetStringValue(arg));
58 }
59 return string_args;
60}
61
63 return (mode == kNormal) || (mode == kInheritStdio);
64}
65
67 return (mode == kNormal) || (mode == kDetachedWithStdio);
68}
69
71 for (intptr_t i = 1; i <= kLastSignal; i++) {
73 }
74}
75
78 intptr_t process_stdin;
79 intptr_t process_stdout;
80 intptr_t process_stderr;
81 intptr_t exit_event;
83 Dart_Handle status_handle = Dart_GetNativeArgument(args, 11);
84 Dart_Handle path_handle = Dart_GetNativeArgument(args, 2);
86
87#if DART_HOST_OS_IOS
88 // Do the iOS check here because the return value of Process::Start is
89 // interpreted as a error with 0 meaning success while `ProcessException`
90 // (which will be constructed with `_errorCode`) interprets 0 to mean that
91 // no OS error code was available.
92 result = DartUtils::SetIntegerField(status_handle, "_errorCode", 0);
95 status_handle, "_errorMessage",
96 "Starting new processes is not supported on iOS");
99 return;
100#endif
101
102 // The Dart code verifies that the path implements the String
103 // interface. However, only builtin Strings are handled by
104 // GetStringValue.
105 if (!Dart_IsString(path_handle)) {
106 result = DartUtils::SetIntegerField(status_handle, "_errorCode", 0);
108 result = DartUtils::SetStringField(status_handle, "_errorMessage",
109 "Path must be a builtin string");
112 return;
113 }
114 const char* path = DartUtils::GetStringValue(path_handle);
116 intptr_t args_length = 0;
117 char** string_args =
118 ExtractCStringList(arguments, status_handle,
119 "Arguments must be builtin strings", &args_length);
120 if (string_args == nullptr) {
122 return;
123 }
124 Dart_Handle working_directory_handle = Dart_GetNativeArgument(args, 4);
125 // Defaults to the current working directory.
126 const char* working_directory = nullptr;
127 if (Dart_IsString(working_directory_handle)) {
128 working_directory = DartUtils::GetStringValue(working_directory_handle);
129 } else if (!Dart_IsNull(working_directory_handle)) {
130 result = DartUtils::SetIntegerField(status_handle, "_errorCode", 0);
132 result =
133 DartUtils::SetStringField(status_handle, "_errorMessage",
134 "WorkingDirectory must be a builtin string");
137 return;
138 }
140 intptr_t environment_length = 0;
141 char** string_environment = nullptr;
142 if (!Dart_IsNull(environment)) {
143 string_environment = ExtractCStringList(
144 environment, status_handle,
145 "Environment values must be builtin strings", &environment_length);
146 if (string_environment == nullptr) {
148 return;
149 }
150 }
151 int64_t mode =
153 Dart_Handle stdin_handle = Dart_GetNativeArgument(args, 7);
154 Dart_Handle stdout_handle = Dart_GetNativeArgument(args, 8);
155 Dart_Handle stderr_handle = Dart_GetNativeArgument(args, 9);
156 Dart_Handle exit_handle = Dart_GetNativeArgument(args, 10);
157 intptr_t pid = -1;
158 char* os_error_message = nullptr; // Scope allocated by Process::Start.
159
160 int error_code = Process::Start(
161 namespc, path, string_args, args_length, working_directory,
162 string_environment, environment_length,
163 static_cast<ProcessStartMode>(mode), &process_stdout, &process_stdin,
164 &process_stderr, &pid, &exit_event, &os_error_message);
165 if (error_code == 0) {
166 if (Process::ModeHasStdio(static_cast<ProcessStartMode>(mode))) {
167 Socket::SetSocketIdNativeField(stdin_handle, process_stdin,
169 Socket::SetSocketIdNativeField(stdout_handle, process_stdout,
171 Socket::SetSocketIdNativeField(stderr_handle, process_stderr,
173 }
174 if (Process::ModeIsAttached(static_cast<ProcessStartMode>(mode))) {
175 Socket::SetSocketIdNativeField(exit_handle, exit_event,
177 }
179 } else {
180 result =
181 DartUtils::SetIntegerField(status_handle, "_errorCode", error_code);
183
184 const char* error_message = (os_error_message != nullptr)
185 ? os_error_message
186 : "Failed to get error message";
187 Dart_Handle val = DartUtils::NewString(error_message);
188 if (Dart_IsError(val)) {
189 // Try to clean the message from non-ASCII characters.
190 const intptr_t len = strlen(error_message);
191 char* ascii_message =
192 reinterpret_cast<char*>(Dart_ScopeAllocate(len + 1));
193 for (intptr_t i = 0; i < len; i++) {
194 if (static_cast<uint8_t>(error_message[i]) < 0x80) {
195 ascii_message[i] = error_message[i];
196 } else {
197 ascii_message[i] = '?';
198 }
199 }
200 ascii_message[len] = '\0';
201
203 "Failed to start %s. OS returned an error (code %d) which can't be "
204 "fully converted to Dart string (%s): %s",
205 path, error_code, Dart_GetError(val), ascii_message);
206 }
207 result = Dart_SetField(status_handle, DartUtils::NewString("_errorMessage"),
208 val);
210 }
211 Dart_SetBooleanReturnValue(args, error_code == 0);
212}
213
216 Socket* process_stdin =
218 Socket* process_stdout =
220 Socket* process_stderr =
222 Socket* exit_event =
225 intptr_t pid;
227 bool success = Process::Wait(pid, process_stdin->fd(), process_stdout->fd(),
228 process_stderr->fd(), exit_event->fd(), &result);
229 // Process::Wait() closes the file handles, so blow away the fds in the
230 // Sockets so that they don't get picked up by the finalizer on _NativeSocket.
231 process_stdin->CloseFd();
232 process_stdout->CloseFd();
233 process_stderr->CloseFd();
234 exit_event->CloseFd();
235 if (success) {
236 Dart_Handle out = result.stdout_data();
238 Dart_Handle err = result.stderr_data();
239 ThrowIfError(err);
240 Dart_Handle list = Dart_NewList(4);
241 Dart_ListSetAt(list, 0, Dart_NewInteger(pid));
242 Dart_ListSetAt(list, 1, Dart_NewInteger(result.exit_code()));
243 Dart_ListSetAt(list, 2, out);
244 Dart_ListSetAt(list, 3, err);
246 } else {
248 Process::Kill(pid, 9);
250 }
251}
252
256 bool success = Process::Kill(pid, signal);
258}
259
261 int64_t status = 0;
262 // Ignore result if passing invalid argument and just exit 0.
264 Process::RunExitHook(status);
266 // We're not doing a full VM shutdown with Dart_Cleanup, which might block,
267 // and other VM threads may be accessing state with global destructors, so
268 // we skip global destructors by using _exit instead of exit.
269 Platform::_Exit(static_cast<int>(status));
270}
271
273 int64_t status = 0;
274 // Ignore result if passing invalid argument and just set exit code to 0.
277}
278
281}
282
284 ScopedBlockingCall blocker;
285 int64_t milliseconds = 0;
286 // Ignore result if passing invalid argument and just set exit code to 0.
288 TimerUtils::Sleep(milliseconds);
289}
290
292 // Ignore result if passing invalid argument and just set exit code to 0.
293 intptr_t pid = -1;
295 if (Dart_IsNull(process)) {
297 } else {
299 }
301}
302
305 intptr_t id = Process::SetSignalHandler(signal);
306 if (id == -1) {
308 } else {
310 }
311}
312
316}
317
319 intptr_t* pid) {
321}
322
324 intptr_t pid) {
326}
327
330 intptr_t bytes_length = 0;
331 Dart_Handle result = Dart_ListLength(bytes, &bytes_length);
333 uint8_t* buffer = Dart_ScopeAllocate(bytes_length + 1);
334 result = Dart_ListGetAsBytes(bytes, 0, buffer, bytes_length);
335 buffer[bytes_length] = '\0';
337 intptr_t len;
338 char* str = StringUtils::ConsoleStringToUtf8(reinterpret_cast<char*>(buffer),
339 bytes_length, &len);
340 if (str == nullptr) {
342 "SystemEncodingToString not supported on this operating system"));
343 }
344 result = Dart_NewStringFromUTF8(reinterpret_cast<const uint8_t*>(str), len);
347}
348
351 char* utf8;
352 intptr_t utf8_len;
354 Dart_StringToUTF8(str, reinterpret_cast<uint8_t**>(&utf8), &utf8_len);
356 intptr_t system_len;
357 const char* system_string =
358 StringUtils::Utf8ToConsoleString(utf8, utf8_len, &system_len);
359 if (system_string == nullptr) {
361 "StringToSystemEncoding not supported on this operating system"));
362 }
363 uint8_t* buffer = nullptr;
364 Dart_Handle external_array = IOBuffer::Allocate(system_len, &buffer);
365 if (Dart_IsNull(external_array)) {
367 return;
368 }
369 if (!Dart_IsError(external_array)) {
370 memmove(buffer, system_string, system_len);
371 }
372 Dart_SetReturnValue(args, external_array);
373}
374
376 int64_t current_rss = Process::CurrentRSS();
377 if (current_rss < 0) {
379 return;
380 }
381 Dart_SetIntegerReturnValue(args, current_rss);
382}
383
385 int64_t max_rss = Process::MaxRSS();
386 if (max_rss < 0) {
388 return;
389 }
391}
392
393void Process::GetRSSInformation(int64_t* max_rss, int64_t* current_rss) {
394 ASSERT(max_rss != nullptr);
395 ASSERT(current_rss != nullptr);
396 // Max RSS should be queried after current RSS to produce
397 // consistent values as current RSS can grow beyond max RSS which
398 // was queried before.
399 *current_rss = Process::CurrentRSS();
400 *max_rss = Process::MaxRSS();
401}
402
403} // namespace bin
404} // namespace dart
#define FUNCTION_NAME(name)
Definition: builtin.h:19
static int64_t GetInt64ValueCheckRange(Dart_Handle value_obj, int64_t lower, int64_t upper)
Definition: dartutils.cc:90
static Dart_Handle NewDartOSError()
Definition: dartutils.cc:702
static bool GetInt64Value(Dart_Handle value_obj, int64_t *value)
Definition: dartutils.cc:112
static const char * GetStringValue(Dart_Handle str_obj)
Definition: dartutils.cc:128
static Dart_Handle NewStringFormatted(const char *format,...)
Definition: dartutils.cc:785
static Dart_Handle NewDartUnsupportedError(const char *message)
Definition: dartutils.cc:754
static Dart_Handle NewString(const char *str)
Definition: dartutils.h:214
static Dart_Handle SetIntegerField(Dart_Handle handle, const char *name, int64_t val)
Definition: dartutils.cc:203
static Dart_Handle SetStringField(Dart_Handle handle, const char *name, const char *val)
Definition: dartutils.cc:209
static intptr_t GetIntptrValue(Dart_Handle value_obj)
Definition: dartutils.cc:100
static Dart_Handle Allocate(intptr_t size, uint8_t **buffer)
Definition: io_buffer.cc:12
static Namespace * GetNamespace(Dart_NativeArguments args, intptr_t index)
Definition: namespace.cc:101
static DART_NORETURN void _Exit(int exit_code)
static bool ModeIsAttached(ProcessStartMode mode)
Definition: process.cc:62
static void ClearSignalHandler(intptr_t signal, Dart_Port port)
static void SetGlobalExitCode(int exit_code)
Definition: process.h:129
static bool ModeHasStdio(ProcessStartMode mode)
Definition: process.cc:66
static Dart_Handle GetProcessIdNativeField(Dart_Handle process, intptr_t *pid)
Definition: process.cc:318
static int64_t CurrentRSS()
static void GetRSSInformation(int64_t *max_rss, int64_t *current_rss)
Definition: process.cc:393
static intptr_t CurrentProcessId()
static int GlobalExitCode()
Definition: process.h:124
static bool Wait(intptr_t id, intptr_t in, intptr_t out, intptr_t err, intptr_t exit_handler, ProcessResult *result)
static int64_t MaxRSS()
static bool Kill(intptr_t id, int signal)
static intptr_t SetSignalHandler(intptr_t signal)
static Dart_Handle SetProcessIdNativeField(Dart_Handle process, intptr_t pid)
Definition: process.cc:323
static void ClearAllSignalHandlers()
Definition: process.cc:70
static void RunExitHook(int64_t exit_code)
Definition: process.h:136
static int Start(Namespace *namespc, const char *path, char *arguments[], intptr_t arguments_length, const char *working_directory, char *environment[], intptr_t environment_length, ProcessStartMode mode, intptr_t *in, intptr_t *out, intptr_t *err, intptr_t *id, intptr_t *exit_handler, char **os_error_message)
intptr_t fd() const
Definition: socket.h:52
static void SetSocketIdNativeField(Dart_Handle handle, intptr_t id, SocketFinalizer finalizer)
Definition: socket.cc:1489
static Socket * GetSocketIdNativeField(Dart_Handle socket)
Definition: socket.cc:1496
static const char * Utf8ToConsoleString(const char *utf8, intptr_t len=-1, intptr_t *result_len=nullptr)
static const char * ConsoleStringToUtf8(const char *str, intptr_t len=-1, intptr_t *result_len=nullptr)
static void Sleep(int64_t millis)
#define ILLEGAL_PORT
Definition: dart_api.h:1535
struct _Dart_Handle * Dart_Handle
Definition: dart_api.h:258
struct _Dart_NativeArguments * Dart_NativeArguments
Definition: dart_api.h:3019
#define ASSERT(E)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const uint8_t uint32_t uint32_t GError ** error
GAsyncResult * result
size_t length
void FUNCTION_NAME() Process_SetExitCode(Dart_NativeArguments args)
Definition: process.cc:272
void FUNCTION_NAME() Process_Pid(Dart_NativeArguments args)
Definition: process.cc:291
static Dart_Handle ThrowIfError(Dart_Handle handle)
Definition: dartutils.h:31
void FUNCTION_NAME() ProcessInfo_CurrentRSS(Dart_NativeArguments args)
Definition: process.cc:375
static char ** ExtractCStringList(Dart_Handle strings, Dart_Handle status_handle, const char *error_msg, intptr_t *length)
Definition: process.cc:23
void FUNCTION_NAME() Process_GetExitCode(Dart_NativeArguments args)
Definition: process.cc:279
void FUNCTION_NAME() Process_Start(Dart_NativeArguments args)
Definition: process.cc:76
void FUNCTION_NAME() Process_Sleep(Dart_NativeArguments args)
Definition: process.cc:283
static constexpr int kProcessIdNativeField
Definition: process.cc:20
void FUNCTION_NAME() Process_Wait(Dart_NativeArguments args)
Definition: process.cc:214
void FUNCTION_NAME() ProcessInfo_MaxRSS(Dart_NativeArguments args)
Definition: process.cc:384
void FUNCTION_NAME() Process_SetSignalHandler(Dart_NativeArguments args)
Definition: process.cc:303
ProcessStartMode
Definition: process.h:81
@ kInheritStdio
Definition: process.h:83
@ kNormal
Definition: process.h:82
@ kDetachedWithStdio
Definition: process.h:85
void FUNCTION_NAME() Process_KillPid(Dart_NativeArguments args)
Definition: process.cc:253
void FUNCTION_NAME() SystemEncodingToString(Dart_NativeArguments args)
Definition: process.cc:328
void FUNCTION_NAME() StringToSystemEncoding(Dart_NativeArguments args)
Definition: process.cc:349
@ kLastSignal
Definition: process.h:77
void FUNCTION_NAME() Process_Exit(Dart_NativeArguments args)
Definition: process.cc:260
void FUNCTION_NAME() Process_ClearSignalHandler(Dart_NativeArguments args)
Definition: process.cc:313
static dart::SimpleHashMap * environment
Definition: gen_snapshot.cc:59
Definition: dart_vm.cc:33
DART_EXPORT Dart_Handle Dart_StringToUTF8(Dart_Handle str, uint8_t **utf8_array, intptr_t *length)
DART_EXPORT Dart_Handle Dart_ListGetAt(Dart_Handle list, intptr_t index)
DART_EXPORT Dart_Port Dart_GetMainPortId()
DART_EXPORT Dart_Handle Dart_GetNativeInstanceField(Dart_Handle obj, int index, intptr_t *value)
DART_EXPORT void Dart_SetBooleanReturnValue(Dart_NativeArguments args, bool retval)
DART_EXPORT Dart_Handle Dart_NewInteger(int64_t value)
DART_EXPORT Dart_Handle Dart_NewStringFromUTF8(const uint8_t *utf8_array, intptr_t length)
DART_EXPORT const char * Dart_GetError(Dart_Handle handle)
DART_EXPORT uint8_t * Dart_ScopeAllocate(intptr_t size)
DART_EXPORT void Dart_SetReturnValue(Dart_NativeArguments args, Dart_Handle retval)
DART_EXPORT Dart_Handle Dart_ListSetAt(Dart_Handle list, intptr_t index, Dart_Handle value)
DART_EXPORT bool Dart_IsError(Dart_Handle handle)
DART_EXPORT Dart_Handle Dart_SetNativeInstanceField(Dart_Handle obj, int index, intptr_t value)
DART_EXPORT void Dart_SetIntegerReturnValue(Dart_NativeArguments args, int64_t retval)
DART_EXPORT Dart_Handle Dart_GetNativeArgument(Dart_NativeArguments args, int index)
DART_EXPORT void Dart_ExitIsolate()
DART_EXPORT Dart_Handle Dart_SetField(Dart_Handle container, Dart_Handle name, Dart_Handle value)
DART_EXPORT Dart_Handle Dart_ListGetAsBytes(Dart_Handle list, intptr_t offset, uint8_t *native_array, intptr_t length)
DART_EXPORT Dart_Handle Dart_ListLength(Dart_Handle list, intptr_t *len)
DART_EXPORT Dart_Handle Dart_NewList(intptr_t length)
DART_EXPORT bool Dart_IsList(Dart_Handle object)
DART_EXPORT Dart_Handle Dart_ThrowException(Dart_Handle exception)
DART_EXPORT bool Dart_IsNull(Dart_Handle object)
DART_EXPORT bool Dart_IsString(Dart_Handle object)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
Definition: switches.h:228
static void process(const char *inPath, const char *lexer, const char *token, const char *hPath, const char *cppPath)
Definition: Main.cpp:114