1 /**
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <algorithm>
17 #include <cmath>
18 #include <thread>
19 #include <set>
20
21 #include "libpandabase/macros.h"
22 #include "libpandabase/os/exec.h"
23 #include "libpandabase/os/filesystem.h"
24 #include "libpandabase/os/kill.h"
25 #include "libpandabase/os/pipe.h"
26 #include "libpandabase/os/system_environment.h"
27 #include "libpandabase/os/time.h"
28 #include "plugins/ets/stdlib/native/escompat/Process.h"
29 #include "plugins/ets/stdlib/native/core/stdlib_ani_helpers.h"
30
31 namespace ark::ets::stdlib {
32
33 enum Signals : uint32_t { SIG_INT = 2, SIG_QUIT = 3, SIG_KILL = 9, SIG_TERM = 15 };
34
35 #ifdef PANDA_TARGET_OHOS
36 // constexpr variables used by isAppUid & isIsolatedProcess, refered to arkts 1.0
37 // See: https://gitee.com/openharmony/js_sys_module/blob/master/process/js_process.cpp#L38
38 constexpr int PER_USER_RANGE = 100000;
39 // See: https://gitee.com/openharmony/js_sys_module/blob/master/process/js_process.h#L242
40 constexpr std::pair<int, int> APP_UID_RANGE = {10000, 19999};
41 // Only isolateuid numbers between 99000 and 99999.
42 // See: https://gitee.com/openharmony/js_sys_module/blob/master/process/js_process.cpp#L290
43 constexpr std::pair<int, int> ISOLATE_UID_RANGE = {99000, 99999};
44 // Only appuid numbers between 9000 and 98999.
45 // See: https://gitee.com/openharmony/js_sys_module/blob/master/process/js_process.cpp#L291
46 constexpr std::pair<int, int> GENERAL_UID_RANGE = {9000, 98999};
47 #endif
48
GetPipeHandler(int stdOutFdIn,int stdOutFdOut,int stdErrFdIn,int stdErrFdOut)49 static auto GetPipeHandler(int stdOutFdIn, int stdOutFdOut, int stdErrFdIn, int stdErrFdOut)
50 {
51 auto handlePipes = [stdOutFdIn, stdOutFdOut, stdErrFdIn, stdErrFdOut] {
52 std::pair<ark::os::unique_fd::UniqueFd, ark::os::unique_fd::UniqueFd> out {stdOutFdIn, stdOutFdOut};
53 std::pair<ark::os::unique_fd::UniqueFd, ark::os::unique_fd::UniqueFd> err {stdErrFdIn, stdErrFdOut};
54 out.first.Reset();
55 err.first.Reset();
56 ark::os::unique_fd::UniqueFd defaultStdOut {1};
57 ark::os::unique_fd::UniqueFd defaultStdErr {2};
58 os::Dup2(out.second, defaultStdOut);
59 os::Dup2(err.second, defaultStdErr);
60 out.second.Release();
61 err.second.Release();
62 defaultStdOut.Release();
63 defaultStdErr.Release();
64 };
65 return handlePipes;
66 }
67
68 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
69 os::memory::Mutex g_terminatedChildSetLock {};
70 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
GUARDED_BY(g_terminatedChildSetLock)71 static std::set<ani_double> g_terminatedChildSet GUARDED_BY(g_terminatedChildSetLock) {};
72
SpawnChildProcess(ani_env * env,ani_object child,ani_string cmd,ani_int timeout,ani_int signal)73 static void SpawnChildProcess(ani_env *env, ani_object child, ani_string cmd, ani_int timeout, ani_int signal)
74 {
75 auto stdOutFd = os::CreatePipe();
76 if (!stdOutFd.first.IsValid()) {
77 ThrowNewError(env, "Lstd/core/RuntimeException;", "Failed to create a child process", "Lstd/core/String;:V");
78 return;
79 }
80 auto stdErrFd = os::CreatePipe();
81 if (!stdErrFd.first.IsValid()) {
82 ThrowNewError(env, "Lstd/core/RuntimeException;", "Failed to create a child process", "Lstd/core/String;:V");
83 return;
84 }
85
86 auto pipeHandler =
87 GetPipeHandler(stdOutFd.first.Get(), stdOutFd.second.Get(), stdErrFd.first.Get(), stdErrFd.second.Get());
88
89 auto cmdString = ConvertFromAniString(env, cmd);
90 auto result = ark::os::exec::ExecWithCallbackNoWait(pipeHandler, "/bin/sh", "-c", cmdString.c_str());
91
92 stdOutFd.second.Reset();
93 stdErrFd.second.Reset();
94
95 if (result.HasValue()) {
96 ANI_FATAL_IF_ERROR(env->Object_SetFieldByName_Double(child, "pid", result.Value()));
97 } else {
98 stdOutFd.first.Reset();
99 stdErrFd.first.Reset();
100 ThrowNewError(env, "Lstd/core/RuntimeException;", "Failed to create a child process", "Lstd/core/String;:V");
101 return;
102 }
103
104 ANI_FATAL_IF_ERROR(env->Object_SetFieldByName_Double(child, "ppid", ark::os::thread::GetPid()));
105 ANI_FATAL_IF_ERROR(env->Object_SetFieldByName_Int(child, "outFd", stdOutFd.first.Release()));
106 ANI_FATAL_IF_ERROR(env->Object_SetFieldByName_Int(child, "errorFd", stdErrFd.first.Release()));
107
108 if (timeout == 0) {
109 return;
110 }
111
112 ani_double pidToTerminate;
113 ANI_FATAL_IF_ERROR(env->Object_GetFieldByName_Double(child, "pid", &pidToTerminate));
114
115 auto terminator = [timeout, signal, pidToTerminate] {
116 ark::os::thread::NativeSleep(timeout);
117 os::memory::LockHolder lock {g_terminatedChildSetLock};
118 if (g_terminatedChildSet.count(pidToTerminate) == 0 && kill(pidToTerminate, signal) == 0) {
119 auto signalType = std::array {SIG_INT, SIG_QUIT, SIG_KILL, SIG_TERM};
120 if (std::find(signalType.begin(), signalType.end(), signal) != signalType.end()) {
121 g_terminatedChildSet.insert(pidToTerminate);
122 }
123 }
124 };
125
126 std::thread timeoutListener {terminator};
127 timeoutListener.detach();
128 }
129
ReadFinalizer(ani_env * env,ani_object child,bool isStdErr)130 static void ReadFinalizer(ani_env *env, ani_object child, bool isStdErr)
131 {
132 bool terminated = false;
133
134 ani_double exitCode;
135 ANI_FATAL_IF_ERROR(env->Object_GetFieldByName_Double(child, "exitCode", &exitCode));
136
137 if (exitCode > -1) {
138 terminated = true;
139 } else {
140 os::memory::LockHolder lock {g_terminatedChildSetLock};
141 ani_double pid;
142 ANI_FATAL_IF_ERROR(env->Object_GetFieldByName_Double(child, "pid", &pid));
143 terminated = g_terminatedChildSet.count(pid) != 0U;
144 }
145
146 if (terminated) {
147 std::string fdName = isStdErr ? "errorFd" : "outFd";
148 ani_int fd;
149 ANI_FATAL_IF_ERROR(env->Object_GetFieldByName_Int(child, fdName.data(), &fd));
150 ark::os::unique_fd::UniqueFd out {fd};
151 out.Reset();
152 ANI_FATAL_IF_ERROR(env->Object_SetFieldByName_Int(child, fdName.data(), -1));
153 }
154 }
155
ReadChildProcessStdOut(ani_env * env,ani_object child)156 static void ReadChildProcessStdOut(ani_env *env, ani_object child)
157 {
158 ani_int fd;
159 ANI_FATAL_IF_ERROR(env->Object_GetFieldByName_Int(child, "outFd", &fd));
160 if (fd == -1) {
161 return;
162 }
163
164 ani_ref bufferObject;
165 ANI_FATAL_IF_ERROR(env->Object_GetFieldByName_Ref(child, "outBuffer", &bufferObject));
166
167 ani_ref outBuffer;
168 ANI_FATAL_IF_ERROR(env->Object_GetFieldByName_Ref(reinterpret_cast<ani_object>(bufferObject), "data", &outBuffer));
169
170 while (true) {
171 ani_int outBytesRead;
172 ANI_FATAL_IF_ERROR(env->Object_GetFieldByName_Int(child, "outBytesRead", &outBytesRead));
173
174 ani_int outBufferLength;
175 ANI_FATAL_IF_ERROR(env->Object_GetFieldByName_Int(reinterpret_cast<ani_object>(bufferObject), "_byteLength",
176 &outBufferLength));
177
178 if (outBytesRead >= outBufferLength) {
179 break;
180 }
181
182 constexpr int MAX_SIZE = 1024;
183 std::array<int8_t, MAX_SIZE> buffer {};
184 int bytesRead = read(fd, buffer.data(), sizeof(buffer.size()) - 1);
185 if (bytesRead == 0) {
186 ReadFinalizer(env, child, false);
187 break;
188 }
189
190 if (bytesRead + outBytesRead > outBufferLength) {
191 bytesRead = outBufferLength - outBytesRead;
192 ark::os::unique_fd::UniqueFd out {fd};
193 out.Reset();
194 ANI_FATAL_IF_ERROR(env->Object_SetFieldByName_Int(child, "outFd", -1));
195 }
196
197 ANI_FATAL_IF_ERROR(env->Array_SetRegion_Byte(reinterpret_cast<ani_array_byte>(outBuffer), outBytesRead,
198 bytesRead, buffer.data()));
199 ANI_FATAL_IF_ERROR(env->Object_SetFieldByName_Int(child, "outBytesRead", outBytesRead + bytesRead));
200 }
201 }
202
ReadChildProcessStdErr(ani_env * env,ani_object child)203 static void ReadChildProcessStdErr(ani_env *env, ani_object child)
204 {
205 ani_int fd;
206 ANI_FATAL_IF_ERROR(env->Object_GetFieldByName_Int(child, "errorFd", &fd));
207 if (fd == -1) {
208 return;
209 }
210
211 ani_ref bufferObject;
212 ANI_FATAL_IF_ERROR(env->Object_GetFieldByName_Ref(child, "errBuffer", &bufferObject));
213
214 ani_ref errBuffer;
215 ANI_FATAL_IF_ERROR(env->Object_GetFieldByName_Ref(reinterpret_cast<ani_object>(bufferObject), "data", &errBuffer));
216
217 ani_type childClassType;
218 ANI_FATAL_IF_ERROR(env->Object_GetType(child, &childClassType));
219
220 ani_field errBytesReadId;
221 ANI_FATAL_IF_ERROR(env->Class_FindField(static_cast<ani_class>(childClassType), "errBytesRead", &errBytesReadId));
222
223 while (true) {
224 ani_int errBytesRead;
225 ANI_FATAL_IF_ERROR(env->Object_GetField_Int(child, errBytesReadId, &errBytesRead));
226
227 ani_int errBufferLength;
228 ANI_FATAL_IF_ERROR(env->Object_GetFieldByName_Int(reinterpret_cast<ani_object>(bufferObject), "_byteLength",
229 &errBufferLength));
230
231 if (errBytesRead >= errBufferLength) {
232 break;
233 }
234
235 constexpr int MAX_SIZE = 1024;
236 std::array<int8_t, MAX_SIZE> buffer {};
237 int bytesRead = read(fd, buffer.data(), sizeof(buffer.size()) - 1);
238 if (bytesRead == 0) {
239 ReadFinalizer(env, child, true);
240 break;
241 }
242
243 if (bytesRead + errBytesRead > errBufferLength) {
244 bytesRead = errBufferLength - errBytesRead;
245
246 ark::os::unique_fd::UniqueFd out {fd};
247 out.Reset();
248 ANI_FATAL_IF_ERROR(env->Object_SetFieldByName_Int(child, "errorFd", -1));
249 }
250
251 ANI_FATAL_IF_ERROR(env->Array_SetRegion_Byte(reinterpret_cast<ani_array_byte>(errBuffer), errBytesRead,
252 bytesRead, buffer.data()));
253 ANI_FATAL_IF_ERROR(env->Object_SetField_Int(child, errBytesReadId, errBytesRead + bytesRead));
254 }
255 }
256
WaitChildProcess(ani_env * env,ani_object child)257 static void WaitChildProcess(ani_env *env, ani_object child)
258 {
259 ani_double pid;
260 ANI_FATAL_IF_ERROR(env->Object_GetFieldByName_Double(child, "pid", &pid));
261
262 ani_type childClassType;
263 ANI_FATAL_IF_ERROR(env->Object_GetType(child, &childClassType));
264
265 ani_field exitCodeId;
266 ANI_FATAL_IF_ERROR(env->Class_FindField(static_cast<ani_class>(childClassType), "exitCode", &exitCodeId));
267
268 ani_double exitCode;
269 ANI_FATAL_IF_ERROR(env->Object_GetField_Double(child, exitCodeId, &exitCode));
270
271 if (exitCode < 0) {
272 auto result = ark::os::exec::Wait(pid, false);
273 if (result.HasValue()) {
274 ANI_FATAL_IF_ERROR(env->Object_SetField_Double(child, exitCodeId, result.Value()));
275 } else {
276 ThrowNewError(env, "Lstd/core/RuntimeException;", "Wait failed", "Lstd/core/String;:V");
277 return;
278 }
279 }
280
281 ReadChildProcessStdOut(env, child);
282 ReadChildProcessStdErr(env, child);
283
284 {
285 os::memory::LockHolder lock {g_terminatedChildSetLock};
286 g_terminatedChildSet.erase(pid);
287 }
288 }
289
KillChildProcess(ani_env * env,ani_object child,ani_int signal)290 static void KillChildProcess(ani_env *env, ani_object child, ani_int signal)
291 {
292 auto signalType = std::array {SIG_INT, SIG_QUIT, SIG_KILL, SIG_TERM};
293
294 auto intSignal = static_cast<int>(signal);
295
296 ani_double pid;
297 ANI_FATAL_IF_ERROR(env->Object_GetFieldByName_Double(child, "pid", &pid));
298
299 if (ark::os::kill_process::Kill(pid, intSignal) == 0) {
300 if (std::find(signalType.begin(), signalType.end(), intSignal) != signalType.end()) {
301 os::memory::LockHolder lock {g_terminatedChildSetLock};
302 g_terminatedChildSet.insert(pid);
303 }
304 ANI_FATAL_IF_ERROR(env->Object_SetFieldByName_Boolean(child, "killed", 1U));
305 return;
306 }
307
308 ThrowNewError(env, "Lstd/core/RuntimeException;", "Kill failed", "Lstd/core/String;:V");
309 }
310
CloseChildProcess(ani_env * env,ani_object child)311 static void CloseChildProcess(ani_env *env, ani_object child)
312 {
313 ani_type childClassType;
314 ANI_FATAL_IF_ERROR(env->Object_GetType(child, &childClassType));
315
316 ani_field exitCodeId;
317 ANI_FATAL_IF_ERROR(env->Class_FindField(static_cast<ani_class>(childClassType), "exitCode", &exitCodeId));
318
319 ani_double pid;
320 ANI_FATAL_IF_ERROR(env->Object_GetFieldByName_Double(child, "pid", &pid));
321
322 ani_double exitCode;
323 ANI_FATAL_IF_ERROR(env->Object_GetField_Double(child, exitCodeId, &exitCode));
324
325 if (exitCode > -1) {
326 return;
327 }
328
329 {
330 os::memory::LockHolder lock {g_terminatedChildSetLock};
331
332 if (g_terminatedChildSet.count(pid) != 0U) {
333 return;
334 }
335 }
336
337 auto status = ark::os::kill_process::Close(pid);
338 if (LIKELY(status != -1)) {
339 ANI_FATAL_IF_ERROR(env->Object_SetField_Double(child, exitCodeId, status));
340 return;
341 }
342
343 ThrowNewError(env, "Lstd/core/RuntimeException;", "Close failed", "Lstd/core/String;:V");
344 }
345
PManagerIsAppUid(ani_env * env,ani_object process,ani_double uid)346 static ani_boolean PManagerIsAppUid([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object process,
347 [[maybe_unused]] ani_double uid)
348 {
349 #ifdef PANDA_TARGET_OHOS
350 // refer to https://gitee.com/openharmony/js_sys_module/blob/master/process/js_process.cpp#L300
351 int number = static_cast<int>(uid);
352 if (number > 0) {
353 const auto appId = number % PER_USER_RANGE;
354 return (appId >= APP_UID_RANGE.first && appId <= APP_UID_RANGE.second) ? ANI_TRUE : ANI_FALSE;
355 }
356
357 return ANI_FALSE;
358 #else
359 ThrowNewError(env, "Lstd/core/RuntimeException;", "not implemented for Non-OHOS target", "Lstd/core/String;:V");
360 return ANI_FALSE;
361 #endif
362 }
363
PManagerGetUidForName(ani_env * env,ani_object process,ani_string name)364 static ani_double PManagerGetUidForName(ani_env *env, [[maybe_unused]] ani_object process, ani_string name)
365 {
366 auto str = ConvertFromAniString(env, name);
367 auto result = ark::os::system_environment::GetUidForName(str);
368 return result;
369 }
370
PManagerGetThreadPriority(ani_env * env,ani_object process,ani_double tid)371 static ani_double PManagerGetThreadPriority([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object process,
372 ani_double tid)
373 {
374 return ark::os::thread::GetPriority(tid);
375 }
376
PManagerGetSystemConfig(ani_env * env,ani_object process,ani_double name)377 static ani_double PManagerGetSystemConfig([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object process,
378 ani_double name)
379 {
380 return ark::os::system_environment::GetSystemConfig(name);
381 }
382
PManagerGetEnvironmentVar(ani_env * env,ani_object process,ani_string name)383 static ani_string PManagerGetEnvironmentVar(ani_env *env, [[maybe_unused]] ani_object process, ani_string name)
384 {
385 auto str = ConvertFromAniString(env, name);
386 auto envVar = ark::os::system_environment::GetEnvironmentVar(str.c_str());
387 return CreateUtf8String(env, envVar.data(), envVar.size());
388 }
389
PManagerExit(ani_env * env,ani_object process,ani_double code)390 static void PManagerExit([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object process, ani_double code)
391 {
392 std::exit(code);
393 }
394
PManagerKill(ani_env * env,ani_object process,ani_double signal,ani_double pid)395 static ani_boolean PManagerKill(ani_env *env, [[maybe_unused]] ani_object process, ani_double signal, ani_double pid)
396 {
397 int integerPid = static_cast<int>(pid);
398 auto ownPid = ark::os::thread::GetPid();
399 if (integerPid == 0 || integerPid == -1 || integerPid == ownPid || integerPid == -ownPid) {
400 ThrowNewError(env, "Lstd/core/IllegalArgumentException;", "Invalid pid argument", "Lstd/core/String;:V");
401 return 0U;
402 }
403
404 constexpr int MIN_SIGNAL_VALUE = 1;
405 constexpr int MAX_SINAL_VALUE = 64;
406
407 if (std::trunc(signal) != signal || signal < MIN_SIGNAL_VALUE || signal > MAX_SINAL_VALUE) {
408 ThrowNewError(env, "Lstd/core/IllegalArgumentException;", "Invalid signal argument", "Lstd/core/String;:V");
409 return 0U;
410 }
411
412 return static_cast<ani_boolean>(ark::os::kill_process::Kill(integerPid, signal) == 0);
413 }
414
GetTid(ani_env * env)415 static ani_double GetTid([[maybe_unused]] ani_env *env)
416 {
417 return ark::os::thread::GetCurrentThreadId();
418 }
419
IsIsolatedProcImpl(ani_env * env)420 static ani_boolean IsIsolatedProcImpl([[maybe_unused]] ani_env *env)
421 {
422 #ifdef PANDA_TARGET_OHOS
423 // refer to https://gitee.com/openharmony/js_sys_module/blob/master/process/js_process.cpp#L284
424 auto uid = ark::os::thread::GetUid();
425 uid %= PER_USER_RANGE;
426 return ((uid >= ISOLATE_UID_RANGE.first && uid <= ISOLATE_UID_RANGE.second) ||
427 (uid >= GENERAL_UID_RANGE.first && uid <= GENERAL_UID_RANGE.second))
428 ? ANI_TRUE
429 : ANI_FALSE;
430 #else
431 ThrowNewError(env, "Lstd/core/RuntimeException;", "not implemented for Non-OHOS target", "Lstd/core/String;:V");
432 return ANI_FALSE;
433 #endif
434 }
435
GetPid(ani_env * env)436 static ani_double GetPid([[maybe_unused]] ani_env *env)
437 {
438 return ark::os::thread::GetPid();
439 }
440
GetPPid(ani_env * env)441 static ani_double GetPPid([[maybe_unused]] ani_env *env)
442 {
443 return ark::os::thread::GetPPid();
444 }
445
GetUid(ani_env * env)446 static ani_double GetUid([[maybe_unused]] ani_env *env)
447 {
448 return ark::os::thread::GetUid();
449 }
450
GetEuid(ani_env * env)451 static ani_double GetEuid([[maybe_unused]] ani_env *env)
452 {
453 return ark::os::thread::GetEuid();
454 }
455
GetGid(ani_env * env)456 static ani_double GetGid([[maybe_unused]] ani_env *env)
457 {
458 return ark::os::thread::GetGid();
459 }
460
GetEgid(ani_env * env)461 static ani_double GetEgid([[maybe_unused]] ani_env *env)
462 {
463 return ark::os::thread::GetEgid();
464 }
465
GetGroupIDs(ani_env * env)466 static ani_array_double GetGroupIDs(ani_env *env)
467 {
468 auto groups = ark::os::thread::GetGroups();
469 auto groupIds = std::vector<ani_double>(groups.begin(), groups.end());
470
471 ani_array_double result;
472 ANI_FATAL_IF_ERROR(env->Array_New_Double(groups.size(), &result));
473
474 if (groups.empty()) {
475 ThrowNewError(env, "Lstd/core/RuntimeException;", "Failed to get process groups", "Lstd/core/String;:V");
476 return result;
477 }
478
479 ANI_FATAL_IF_ERROR(env->Array_SetRegion_Double(result, 0, groups.size(), groupIds.data()));
480
481 return result;
482 }
483
Is64BitProcess(ani_env * env)484 static ani_boolean Is64BitProcess([[maybe_unused]] ani_env *env)
485 {
486 constexpr int SIZE_OF_64_BIT_PTR = 8;
487 return static_cast<ani_boolean>(sizeof(char *) == SIZE_OF_64_BIT_PTR);
488 }
489
GetProcessStartRealTime(ani_env * env)490 static ani_double GetProcessStartRealTime([[maybe_unused]] ani_env *env)
491 {
492 return ark::os::time::GetStartRealTime<std::chrono::milliseconds>();
493 }
494
GetProcessPastCpuTime(ani_env * env)495 static ani_double GetProcessPastCpuTime([[maybe_unused]] ani_env *env)
496 {
497 constexpr int PROCESS_CLOCK = 2;
498 return ark::os::time::GetClockTime<std::chrono::milliseconds>(PROCESS_CLOCK);
499 }
500
AbortProcess(ani_env * env)501 static void AbortProcess([[maybe_unused]] ani_env *env)
502 {
503 std::abort();
504 }
505
GetCurrentWorkingDirectory(ani_env * env)506 static ani_string GetCurrentWorkingDirectory(ani_env *env)
507 {
508 auto workDir = ark::os::GetCurrentWorkingDirectory();
509 return CreateUtf8String(env, workDir.data(), workDir.size());
510 }
511
ChangeCurrentWorkingDirectory(ani_env * env,ani_string path)512 static void ChangeCurrentWorkingDirectory(ani_env *env, ani_string path)
513 {
514 auto str = ConvertFromAniString(env, path);
515 os::ChangeCurrentWorkingDirectory(str);
516 }
517
GetSystemUptime(ani_env * env)518 static ani_double GetSystemUptime([[maybe_unused]] ani_env *env)
519 {
520 constexpr int BOOTTIME_CLOCK = 7;
521 return ark::os::time::GetClockTime<std::chrono::milliseconds>(BOOTTIME_CLOCK);
522 }
523
RegisterProcessNativeMethods(ani_env * env)524 void RegisterProcessNativeMethods(ani_env *env)
525 {
526 const auto childProcessImpls =
527 std::array {ani_native_function {"readOutput", ":V", reinterpret_cast<void *>(ReadChildProcessStdOut)},
528 ani_native_function {"readErrorOutput", ":V", reinterpret_cast<void *>(ReadChildProcessStdErr)},
529 ani_native_function {"close", ":V", reinterpret_cast<void *>(CloseChildProcess)},
530 ani_native_function {"killImpl", "I:V", reinterpret_cast<void *>(KillChildProcess)},
531 ani_native_function {"spawn", "Lstd/core/String;II:V", reinterpret_cast<void *>(SpawnChildProcess)},
532 ani_native_function {"waitImpl", ":D", reinterpret_cast<void *>(WaitChildProcess)}};
533
534 const auto processManagerImpls = std::array {
535 ani_native_function {"isAppUid", "D:Z", reinterpret_cast<void *>(PManagerIsAppUid)},
536 ani_native_function {"getUidForName", "Lstd/core/String;:D", reinterpret_cast<void *>(PManagerGetUidForName)},
537 ani_native_function {"getThreadPriority", "D:D", reinterpret_cast<void *>(PManagerGetThreadPriority)},
538 ani_native_function {"getSystemConfig", "D:D", reinterpret_cast<void *>(PManagerGetSystemConfig)},
539 ani_native_function {"getEnvironmentVar", "Lstd/core/String;:Lstd/core/String;",
540 reinterpret_cast<void *>(PManagerGetEnvironmentVar)},
541 ani_native_function {"exit", "D:V", reinterpret_cast<void *>(PManagerExit)},
542 ani_native_function {"kill", "DD:Z", reinterpret_cast<void *>(PManagerKill)},
543 };
544
545 const auto processImpls = std::array {
546 ani_native_function {"tid", ":D", reinterpret_cast<void *>(GetTid)},
547 ani_native_function {"pid", ":D", reinterpret_cast<void *>(GetPid)},
548 ani_native_function {"ppid", ":D", reinterpret_cast<void *>(GetPPid)},
549 ani_native_function {"uid", ":D", reinterpret_cast<void *>(GetUid)},
550 ani_native_function {"euid", ":D", reinterpret_cast<void *>(GetEuid)},
551 ani_native_function {"gid", ":D", reinterpret_cast<void *>(GetGid)},
552 ani_native_function {"egid", ":D", reinterpret_cast<void *>(GetEgid)},
553 ani_native_function {"groups", ":[D", reinterpret_cast<void *>(GetGroupIDs)},
554 ani_native_function {"is64Bit", ":Z", reinterpret_cast<void *>(Is64BitProcess)},
555 ani_native_function {"getStartRealtime", ":D", reinterpret_cast<void *>(GetProcessStartRealTime)},
556 ani_native_function {"getPastCpuTime", ":D", reinterpret_cast<void *>(GetProcessPastCpuTime)},
557 ani_native_function {"abort", ":V", reinterpret_cast<void *>(AbortProcess)},
558 ani_native_function {"cwd", ":Lstd/core/String;", reinterpret_cast<void *>(GetCurrentWorkingDirectory)},
559 ani_native_function {"chdir", "Lstd/core/String;:V", reinterpret_cast<void *>(ChangeCurrentWorkingDirectory)},
560 ani_native_function {"uptime", ":D", reinterpret_cast<void *>(GetSystemUptime)},
561 ani_native_function {"isIsolatedProcess", ":Z", reinterpret_cast<void *>(IsIsolatedProcImpl)},
562 };
563
564 ani_class childProcessKlass;
565 ANI_FATAL_IF_ERROR(env->FindClass("Lescompat/StdProcess/ChildProcess;", &childProcessKlass));
566 ANI_FATAL_IF_ERROR(
567 env->Class_BindNativeMethods(childProcessKlass, childProcessImpls.data(), childProcessImpls.size()));
568
569 ani_class processManagerKlass;
570 ANI_FATAL_IF_ERROR(env->FindClass("Lescompat/StdProcess/ProcessManager;", &processManagerKlass));
571 ANI_FATAL_IF_ERROR(
572 env->Class_BindNativeMethods(processManagerKlass, processManagerImpls.data(), processManagerImpls.size()));
573
574 ani_namespace ns {};
575 ANI_FATAL_IF_ERROR(env->FindNamespace("Lescompat/StdProcess;", &ns));
576
577 ANI_FATAL_IF_ERROR(env->Namespace_BindNativeFunctions(ns, processImpls.data(), processImpls.size()));
578 }
579
580 } // namespace ark::ets::stdlib
581