1 /*
2  * Copyright (c) 2022 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 "js_process.h"
17 
18 #include <cstdlib>
19 #include <vector>
20 
21 #include <grp.h>
22 #include <mutex>
23 #include <pthread.h>
24 #include <pwd.h>
25 #include <sched.h>
26 #include <unistd.h>
27 #include <uv.h>
28 
29 #include <sys/resource.h>
30 #include <sys/syscall.h>
31 #include <sys/types.h>
32 
33 #include "securec.h"
34 #include "process_helper.h"
35 #include "tools/log.h"
36 namespace OHOS::JsSysModule::Process {
37 
38     using namespace Commonlibrary::Platform;
39     namespace {
40         constexpr int NUM_OF_DATA = 4;
41         constexpr int PER_USER_RANGE = 100000;
42         constexpr int32_t NAPI_RETURN_ZERO = 0;
43         constexpr int32_t NAPI_RETURN_ONE = 1;
44     }
45     constexpr int FIRST_APPLICATION_UID = 10000; // 10000 : bundleId lower limit
46     constexpr int LAST_APPLICATION_UID = 65535; // 65535 : bundleId upper limit
47     thread_local std::multimap<std::string, napi_ref> eventMap;
48     static std::mutex g_sharedTimedMutex;
49     thread_local std::map<napi_ref, napi_ref> pendingUnHandledRejections;
50     // support g_events
51     thread_local std::string g_events = "UnHandleRejection";
52 
GetUid(napi_env env) const53     napi_value Process::GetUid(napi_env env) const
54     {
55         napi_value result = nullptr;
56         auto processGetuid = static_cast<uint32_t>(getuid());
57         NAPI_CALL(env, napi_create_uint32(env, processGetuid, &result));
58         return result;
59     }
60 
GetGid(napi_env env) const61     napi_value Process::GetGid(napi_env env) const
62     {
63         napi_value result = nullptr;
64         auto processGetgid = static_cast<uint32_t>(getgid());
65         NAPI_CALL(env, napi_create_uint32(env, processGetgid, &result));
66         return result;
67     }
68 
GetEUid(napi_env env) const69     napi_value Process::GetEUid(napi_env env) const
70     {
71         napi_value result = nullptr;
72         auto processGeteuid = static_cast<uint32_t>(geteuid());
73         NAPI_CALL(env, napi_create_uint32(env, processGeteuid, &result));
74         return result;
75     }
76 
GetEGid(napi_env env) const77     napi_value Process::GetEGid(napi_env env) const
78     {
79         napi_value result = nullptr;
80         auto processGetegid = static_cast<uint32_t>(getegid());
81         NAPI_CALL(env, napi_create_uint32(env, processGetegid, &result));
82         return result;
83     }
84 
GetGroups(napi_env env) const85     napi_value Process::GetGroups(napi_env env) const
86     {
87         napi_value result = nullptr;
88         int progroups = getgroups(0, nullptr);
89         if (progroups == -1) {
90             napi_throw_error(env, "-1", "getgroups initialize failed");
91             return nullptr;
92         }
93         std::vector<gid_t> pgrous(progroups);
94         progroups = getgroups(progroups, pgrous.data());
95         if (progroups == -1) {
96             napi_throw_error(env, "-1", "getgroups");
97             return nullptr;
98         }
99         pgrous.resize(static_cast<size_t>(progroups));
100         gid_t proegid = getegid();
101         if (std::find(pgrous.begin(), pgrous.end(), proegid) == pgrous.end()) {
102             pgrous.push_back(proegid);
103         }
104         std::vector<uint32_t> array;
105         for (auto iter = pgrous.begin(); iter != pgrous.end(); iter++) {
106             auto receive = static_cast<uint32_t>(*iter);
107             array.push_back(receive);
108         }
109         NAPI_CALL(env, napi_create_array(env, &result));
110         size_t len = array.size();
111         for (size_t i = 0; i < len; i++) {
112             napi_value numvalue = nullptr;
113             NAPI_CALL(env, napi_create_uint32(env, array[i], &numvalue));
114             NAPI_CALL(env, napi_set_element(env, result, i, numvalue));
115         }
116         return result;
117     }
118 
GetPid(napi_env env) const119     napi_value Process::GetPid(napi_env env) const
120     {
121         napi_value result = nullptr;
122         auto proPid = static_cast<int32_t>(getpid());
123         napi_create_int32(env, proPid, &result);
124         return result;
125     }
126 
GetPpid(napi_env env) const127     napi_value Process::GetPpid(napi_env env) const
128     {
129         napi_value result = nullptr;
130         auto proPpid = static_cast<int32_t>(getppid());
131         napi_create_int32(env, proPpid, &result);
132         return result;
133     }
134 
Chdir(napi_env env,napi_value args) const135     void Process::Chdir(napi_env env, napi_value args) const
136     {
137         size_t prolen = 0;
138         if (napi_get_value_string_utf8(env, args, nullptr, 0, &prolen) != napi_ok) {
139             HILOG_ERROR("can not get args size");
140             return;
141         }
142         std::string result = "";
143         result.reserve(prolen + 1);
144         result.resize(prolen);
145         if (napi_get_value_string_utf8(env, args, result.data(), prolen + 1, &prolen) != napi_ok) {
146             HILOG_ERROR("can not get args value");
147             return;
148         }
149         int proerr = 0;
150         proerr = uv_chdir(result.c_str());
151         if (proerr) {
152             napi_throw_error(env, "-1", "chdir");
153             return;
154         }
155     }
156 
Kill(napi_env env,napi_value signal,napi_value proid)157     napi_value Process::Kill(napi_env env, napi_value signal, napi_value proid)
158     {
159         int32_t pid = 0;
160         int32_t sig = 0;
161         napi_get_value_int32(env, proid, &pid);
162         napi_get_value_int32(env, signal, &sig);
163         uv_pid_t ownPid = uv_os_getpid();
164         // 64:The maximum valid signal value is 64.
165         if (sig > 64 && (!pid || pid == -1 || pid == ownPid || pid == -ownPid)) {
166             napi_throw_error(env, "0", "process exit");
167             return nullptr;
168         }
169         bool flag = false;
170         int err = uv_kill(pid, sig);
171         if (!err) {
172             flag = true;
173         }
174         napi_value result = nullptr;
175         NAPI_CALL(env, napi_get_boolean(env, flag, &result));
176         return result;
177     }
178 
Uptime(napi_env env) const179     napi_value Process::Uptime(napi_env env) const
180     {
181         napi_value result = nullptr;
182         double runsystime = 0.0;
183         auto systimer = GetSysTimer();
184         if (systimer > 0) {
185             runsystime = static_cast<double>(systimer);
186             NAPI_CALL(env, napi_create_double(env, runsystime, &result));
187         } else {
188             napi_throw_error(env, "-1", "Failed to get systimer");
189             return nullptr;
190         }
191         return result;
192     }
193 
Exit(napi_env env,napi_value number) const194     void Process::Exit(napi_env env, napi_value number) const
195     {
196         int32_t result = 0;
197         napi_get_value_int32(env, number, &result);
198         ProcessExit(result);
199     }
200 
Cwd(napi_env env) const201     napi_value Process::Cwd(napi_env env) const
202     {
203         napi_value result = nullptr;
204         char buf[260 * NUM_OF_DATA] = { 0 }; // 260:Only numbers path String size is 260.
205         size_t length = sizeof(buf);
206         int err = uv_cwd(buf, &length);
207         if (err) {
208             napi_throw_error(env, "1", "uv_cwd");
209             return nullptr;
210         }
211         napi_create_string_utf8(env, buf, length, &result);
212         return result;
213     }
214 
Abort() const215     void Process::Abort() const
216     {
217         std::abort();
218     }
219 
On(napi_env env,napi_value str,napi_value function)220     void Process::On(napi_env env, napi_value str, napi_value function)
221     {
222         std::string result = "";
223         size_t bufferSize = 0;
224         if (napi_get_value_string_utf8(env, str, nullptr, NAPI_RETURN_ZERO, &bufferSize) != napi_ok) {
225             HILOG_ERROR("can not get str size");
226             return;
227         }
228         result.reserve(bufferSize + NAPI_RETURN_ONE);
229         result.resize(bufferSize);
230         if (napi_get_value_string_utf8(env, str, result.data(), bufferSize + NAPI_RETURN_ONE,
231                                        &bufferSize) != napi_ok) {
232             HILOG_ERROR("can not get str value");
233             return;
234         }
235         if (function == nullptr) {
236             HILOG_ERROR("function is nullptr");
237             return;
238         }
239         napi_ref myCallRef = nullptr;
240         napi_status status = napi_create_reference(env, function, 1, &myCallRef);
241         if (status != napi_ok) {
242             HILOG_ERROR("napi_create_reference is failed");
243             return;
244         }
245         if (!result.empty()) {
246             size_t pos = g_events.find(result);
247             if (pos == std::string::npos) {
248                 HILOG_ERROR("illegal event");
249                 return;
250             }
251             std::unique_lock<std::mutex> lock(g_sharedTimedMutex);
252             eventMap.insert(std::make_pair(result, myCallRef));
253         }
254     }
255 
Off(napi_env env,napi_value str)256     napi_value Process::Off(napi_env env, napi_value str)
257     {
258         size_t bufferSize = 0;
259         bool flag = false;
260         if (napi_get_value_string_utf8(env, str, nullptr, 0, &bufferSize) != napi_ok) {
261             HILOG_ERROR("can not get str size");
262             return nullptr;
263         }
264         std::string result = "";
265         result.reserve(bufferSize + 1);
266         result.resize(bufferSize);
267         if (napi_get_value_string_utf8(env, str, result.data(), bufferSize + 1, &bufferSize) != napi_ok) {
268             HILOG_ERROR("can not get str value");
269             return nullptr;
270         }
271         std::string temp = "";
272         temp = result;
273         auto iter = eventMap.equal_range(temp);
274         while (iter.first != iter.second) {
275             NAPI_CALL(env, napi_delete_reference(env, iter.first->second));
276             std::unique_lock<std::mutex> lock(g_sharedTimedMutex);
277             iter.first = eventMap.erase(iter.first);
278             flag = true;
279         }
280         napi_value convertResult = nullptr;
281         NAPI_CALL(env, napi_get_boolean(env, flag, &convertResult));
282         return convertResult;
283     }
284 
GetTid(napi_env env) const285     napi_value Process::GetTid(napi_env env) const
286     {
287         napi_value result = nullptr;
288         auto proTid = static_cast<int32_t>(GetThreadId());
289         napi_create_int64(env, proTid, &result);
290         return result;
291     }
292 
IsIsolatedProcess(napi_env env) const293     napi_value Process::IsIsolatedProcess(napi_env env) const
294     {
295         napi_value result = nullptr;
296         bool flag = true;
297         auto prouid = static_cast<int32_t>(getuid());
298         auto uid = prouid % PER_USER_RANGE;
299         if ((uid >= 99000 && uid <= 99999) || // 99999:Only isolateuid numbers between 99000 and 99999.
300             (uid >= 9000 && uid <= 98999)) { // 98999:Only appuid numbers between 9000 and 98999.
301             NAPI_CALL(env, napi_get_boolean(env, flag, &result));
302             return result;
303         }
304         flag = false;
305         NAPI_CALL(env, napi_get_boolean(env, flag, &result));
306         return result;
307     }
308 
IsAppUid(napi_env env,napi_value uid) const309     napi_value Process::IsAppUid(napi_env env, napi_value uid) const
310     {
311         int32_t number = 0;
312         napi_value result = nullptr;
313         bool flag = true;
314         napi_get_value_int32(env, uid, &number);
315         if (number > 0) {
316             const auto appId = number % PER_USER_RANGE;
317             if (appId >= FIRST_APPLICATION_UID && appId <= LAST_APPLICATION_UID) {
318                 napi_get_boolean(env, flag, &result);
319                 return result;
320             }
321         }
322         flag = false;
323         NAPI_CALL(env, napi_get_boolean(env, flag, &result));
324         return result;
325     }
326 
Is64Bit(napi_env env) const327     napi_value Process::Is64Bit(napi_env env) const
328     {
329         napi_value result = nullptr;
330         bool flag = true;
331         auto size = sizeof(char*);
332         flag = (size == NUM_OF_DATA) ? false : true;
333         NAPI_CALL(env, napi_get_boolean(env, flag, &result));
334         return result;
335     }
336 
GetEnvironmentVar(napi_env env,napi_value name) const337     napi_value Process::GetEnvironmentVar(napi_env env, napi_value name) const
338     {
339         napi_value convertResult = nullptr;
340         char buf[260 * NUM_OF_DATA] = { 0 }; // 260:Only numbers path String size is 260.
341         size_t length = sizeof(buf);
342         size_t bufferSize = 0;
343         if (napi_get_value_string_utf8(env, name, nullptr, 0, &bufferSize) != napi_ok) {
344             HILOG_ERROR("can not get name size");
345             return nullptr;
346         }
347         std::string result = "";
348         result.reserve(bufferSize + 1);
349         result.resize(bufferSize);
350         if (napi_get_value_string_utf8(env, name, result.data(), bufferSize + 1, &bufferSize) != napi_ok) {
351             HILOG_ERROR("can not get name value");
352             return nullptr;
353         }
354         std::string temp = "";
355         temp = result;
356         auto envNum = uv_os_getenv(temp.c_str(), buf, &length);
357         if (envNum == UV_ENOENT) {
358             NAPI_CALL(env, napi_get_undefined(env, &convertResult));
359             return convertResult;
360         }
361         napi_create_string_utf8(env, buf, strlen(buf), &convertResult);
362         return convertResult;
363     }
364 
GetUidForName(napi_env env,napi_value name) const365     napi_value Process::GetUidForName(napi_env env, napi_value name) const
366     {
367         napi_value convertResult = nullptr;
368         size_t bufferSize = 0;
369         if (napi_get_value_string_utf8(env, name, nullptr, 0, &bufferSize) != napi_ok) {
370             HILOG_ERROR("can not get name size");
371             return nullptr;
372         }
373         std::string result = "";
374         result.reserve(bufferSize + 1);
375         result.resize(bufferSize);
376         if (napi_get_value_string_utf8(env, name, result.data(), bufferSize + 1, &bufferSize) != napi_ok) {
377             HILOG_ERROR("can not get name value");
378             return nullptr;
379         }
380         struct passwd user;
381         int32_t uid = 0;
382         struct passwd *bufp = nullptr;
383         long bufLen = sysconf(_SC_GETPW_R_SIZE_MAX);
384         if (bufLen == -1) {
385             bufLen = 16384; // 16384:Should be more than enough
386         }
387 
388         std::string buf;
389         buf.reserve(bufLen + 1);
390         buf.resize(bufLen);
391         if (getpwnam_r(result.c_str(), &user, buf.data(), bufLen, &bufp) == 0 && bufp != nullptr) {
392             uid = static_cast<int32_t>(bufp->pw_uid);
393             napi_create_int32(env, uid, &convertResult);
394             return convertResult;
395         }
396         napi_create_int32(env, (-1), &convertResult);
397         return convertResult;
398     }
399 
GetThreadPriority(napi_env env,napi_value tid) const400     napi_value Process::GetThreadPriority(napi_env env, napi_value tid) const
401     {
402         errno = 0;
403         napi_value result = nullptr;
404         int32_t proTid = 0;
405         napi_get_value_int32(env, tid, &proTid);
406         int32_t pri = getpriority(PRIO_PROCESS, proTid);
407         if (errno) {
408             napi_throw_error(env, "-1", "Invalid tid");
409             return nullptr;
410         }
411         napi_create_int32(env, pri, &result);
412         return result;
413     }
414 
GetStartRealtime(napi_env env) const415     napi_value Process::GetStartRealtime(napi_env env) const
416     {
417         napi_value result = nullptr;
418         double startRealtime = GetProcessStartRealtime();
419         napi_create_double(env, startRealtime, &result);
420         return result;
421     }
422 
ConvertTime(time_t tvsec,int64_t tvnsec) const423     int Process::ConvertTime(time_t tvsec, int64_t tvnsec) const
424     {
425         return int(tvsec * 1000) + int(tvnsec / 1000000); // 98999:Only converttime numbers is 1000 and 1000000.
426     }
427 
GetPastCputime(napi_env env) const428     napi_value Process::GetPastCputime(napi_env env) const
429     {
430         struct timespec times = {0, 0};
431         napi_value result = nullptr;
432         auto res = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &times);
433         if (res) {
434             return 0;
435         }
436         int when =  ConvertTime(times.tv_sec, times.tv_nsec);
437         napi_create_int32(env, when, &result);
438         return result;
439     }
440 
GetSystemConfig(napi_env env,napi_value name) const441     napi_value Process::GetSystemConfig(napi_env env, napi_value name) const
442     {
443         int32_t number = 0;
444         napi_value result = nullptr;
445         napi_get_value_int32(env, name, &number);
446         auto configinfo = static_cast<int32_t>(sysconf(number));
447         napi_create_int32(env, configinfo, &result);
448         return result;
449     }
450 
ClearReference(napi_env env)451     void Process::ClearReference(napi_env env)
452     {
453         auto iter = eventMap.begin();
454         while (iter != eventMap.end()) {
455             napi_status status = napi_delete_reference(env, iter->second);
456             if (status != napi_ok) {
457                 napi_throw_error(env, nullptr, "ClearReference failed");
458                 return;
459             }
460             iter++;
461         }
462         eventMap.clear();
463     }
464 
IsAppUid(napi_env env,napi_value uid) const465     napi_value ProcessManager::IsAppUid(napi_env env, napi_value uid) const
466     {
467         int32_t number = 0;
468         napi_value result = nullptr;
469         bool flag = true;
470         napi_get_value_int32(env, uid, &number);
471         if (number > 0) {
472             const auto appId = number % PER_USER_RANGE;
473             if (appId >= FIRST_APPLICATION_UID && appId <= LAST_APPLICATION_UID) {
474                 napi_get_boolean(env, flag, &result);
475                 return result;
476             }
477         }
478         flag = false;
479         NAPI_CALL(env, napi_get_boolean(env, flag, &result));
480         return result;
481     }
482 
GetUidForName(napi_env env,napi_value name) const483     napi_value ProcessManager::GetUidForName(napi_env env, napi_value name) const
484     {
485         napi_value convertResult = nullptr;
486         size_t bufferSize = 0;
487         if (napi_get_value_string_utf8(env, name, nullptr, 0, &bufferSize) != napi_ok) {
488             HILOG_ERROR("can not get name size");
489             return nullptr;
490         }
491         std::string result = "";
492         result.reserve(bufferSize + 1);
493         result.resize(bufferSize);
494         if (napi_get_value_string_utf8(env, name, result.data(), bufferSize + 1, &bufferSize) != napi_ok) {
495             HILOG_ERROR("can not get name value");
496             return nullptr;
497         }
498         struct passwd user;
499         int32_t uid = 0;
500         struct passwd *bufp = nullptr;
501         long bufLen = sysconf(_SC_GETPW_R_SIZE_MAX);
502         if (bufLen == -1) {
503             bufLen = 16384; // 16384:Should be more than enough
504         }
505 
506         std::string buf;
507         buf.reserve(bufLen + 1);
508         buf.resize(bufLen);
509         if (getpwnam_r(result.c_str(), &user, buf.data(), bufLen, &bufp) == 0 && bufp != nullptr) {
510             uid = static_cast<int32_t>(bufp->pw_uid);
511             napi_create_int32(env, uid, &convertResult);
512             return convertResult;
513         }
514         napi_create_int32(env, (-1), &convertResult);
515         return convertResult;
516     }
517 
GetThreadPriority(napi_env env,napi_value tid) const518     napi_value ProcessManager::GetThreadPriority(napi_env env, napi_value tid) const
519     {
520         errno = 0;
521         napi_value result = nullptr;
522         int32_t proTid = 0;
523         napi_get_value_int32(env, tid, &proTid);
524         int32_t pri = GetThreadPRY(proTid);
525         if (errno) {
526             napi_throw_error(env, "401", "Parameter error. The type of Parameter must be number and a valid tid.");
527             return nullptr;
528         }
529         napi_create_int32(env, pri, &result);
530         return result;
531     }
532 
GetSystemConfig(napi_env env,napi_value name) const533     napi_value ProcessManager::GetSystemConfig(napi_env env, napi_value name) const
534     {
535         int32_t number = 0;
536         napi_value result = nullptr;
537         napi_get_value_int32(env, name, &number);
538         int32_t configinfo = GetSysConfig(number);
539         napi_create_int32(env, configinfo, &result);
540         return result;
541     }
542 
GetEnvironmentVar(napi_env env,napi_value name) const543     napi_value ProcessManager::GetEnvironmentVar(napi_env env, napi_value name) const
544     {
545         size_t bufferSize = 0;
546         if (napi_get_value_string_utf8(env, name, nullptr, 0, &bufferSize) != napi_ok) {
547             HILOG_ERROR("can not get name size");
548             return nullptr;
549         }
550         std::string result = "";
551         result.reserve(bufferSize + 1);
552         result.resize(bufferSize);
553         if (napi_get_value_string_utf8(env, name, result.data(), bufferSize + 1, &bufferSize) != napi_ok) {
554             HILOG_ERROR("can not get name value");
555             return nullptr;
556         }
557         std::string temp = "";
558         temp = result;
559         char buf[260 * NUM_OF_DATA] = { 0 }; // 260:Only numbers path String size is 260.
560         size_t length = sizeof(buf);
561         auto envNum = uv_os_getenv(temp.c_str(), buf, &length);
562         napi_value convertResult = nullptr;
563         if (envNum == UV_ENOENT) {
564             NAPI_CALL(env, napi_get_undefined(env, &convertResult));
565             return convertResult;
566         }
567         napi_create_string_utf8(env, buf, strlen(buf), &convertResult);
568         return convertResult;
569     }
570 
Exit(napi_env env,napi_value number) const571     void ProcessManager::Exit(napi_env env, napi_value number) const
572     {
573         int32_t result = 0;
574         napi_get_value_int32(env, number, &result);
575         ProcessExit(result);
576     }
577 
Kill(napi_env env,napi_value signal,napi_value proid)578     napi_value ProcessManager::Kill(napi_env env, napi_value signal, napi_value proid)
579     {
580         int32_t pid = 0;
581         int32_t sig = 0;
582         napi_get_value_int32(env, proid, &pid);
583         napi_get_value_int32(env, signal, &sig);
584         uv_pid_t ownPid = uv_os_getpid();
585         // 64:The maximum valid signal value is 64.
586         if (sig > 64 && (!pid || pid == -1 || pid == ownPid || pid == -ownPid)) {
587             napi_throw_error(env, "401", "Parameter error. The type of signal must be number,and from 1 to 64.");
588             return nullptr;
589         }
590         bool flag = false;
591         int err = uv_kill(pid, sig);
592         if (!err) {
593             flag = true;
594         }
595         napi_value result = nullptr;
596         NAPI_CALL(env, napi_get_boolean(env, flag, &result));
597         return result;
598     }
599 } // namespace OHOS::JsSysModule::Process
600