• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <pthread.h>
23 #include <pwd.h>
24 #include <sched.h>
25 #include <unistd.h>
26 #include <uv.h>
27 
28 #include <sys/resource.h>
29 #include <sys/syscall.h>
30 #include <sys/sysinfo.h>
31 #include <sys/types.h>
32 
33 #include "securec.h"
34 #include "utils/log.h"
35 namespace OHOS::Js_sys_module::Process {
36     namespace {
37         constexpr int NUM_OF_DATA = 4;
38         constexpr int PER_USER_RANGE = 100000;
39         constexpr int32_t NAPI_RETURN_ZERO = 0;
40         constexpr int32_t NAPI_RETURN_ONE = 1;
41     }
42     thread_local std::multimap<std::string, napi_ref> eventMap;
43     thread_local std::map<napi_ref, napi_ref> pendingUnHandledRejections;
44     // support events
45     thread_local std::string events = "UnHandleRejection";
46 
GetUid(napi_env env) const47     napi_value Process::GetUid(napi_env env) const
48     {
49         napi_value result = nullptr;
50         auto processGetuid = static_cast<uint32_t>(getuid());
51         NAPI_CALL(env, napi_create_uint32(env, processGetuid, &result));
52         return result;
53     }
54 
GetGid(napi_env env) const55     napi_value Process::GetGid(napi_env env) const
56     {
57         napi_value result = nullptr;
58         auto processGetgid = static_cast<uint32_t>(getgid());
59         NAPI_CALL(env, napi_create_uint32(env, processGetgid, &result));
60         return result;
61     }
62 
GetEUid(napi_env env) const63     napi_value Process::GetEUid(napi_env env) const
64     {
65         napi_value result = nullptr;
66         auto processGeteuid = static_cast<uint32_t>(geteuid());
67         NAPI_CALL(env, napi_create_uint32(env, processGeteuid, &result));
68         return result;
69     }
70 
GetEGid(napi_env env) const71     napi_value Process::GetEGid(napi_env env) const
72     {
73         napi_value result = nullptr;
74         auto processGetegid = static_cast<uint32_t>(getegid());
75         NAPI_CALL(env, napi_create_uint32(env, processGetegid, &result));
76         return result;
77     }
78 
GetGroups(napi_env env) const79     napi_value Process::GetGroups(napi_env env) const
80     {
81         napi_value result = nullptr;
82         int progroups = getgroups(0, nullptr);
83         if (progroups == -1) {
84             napi_throw_error(env, "-1", "getgroups initialize failed");
85         }
86         std::vector<gid_t> pgrous(progroups);
87         progroups = getgroups(progroups, pgrous.data());
88         if (progroups == -1) {
89             napi_throw_error(env, "-1", "getgroups");
90         }
91         pgrous.resize(static_cast<size_t>(progroups));
92         gid_t proegid = getegid();
93         if (std::find(pgrous.begin(), pgrous.end(), proegid) == pgrous.end()) {
94             pgrous.push_back(proegid);
95         }
96         std::vector<uint32_t> array;
97         for (auto iter = pgrous.begin(); iter != pgrous.end(); iter++) {
98             auto receive = static_cast<uint32_t>(*iter);
99             array.push_back(receive);
100         }
101         NAPI_CALL(env, napi_create_array(env, &result));
102         size_t len = array.size();
103         for (size_t i = 0; i < len; i++) {
104             napi_value numvalue = nullptr;
105             NAPI_CALL(env, napi_create_uint32(env, array[i], &numvalue));
106             NAPI_CALL(env, napi_set_element(env, result, i, numvalue));
107         }
108         return result;
109     }
110 
GetPid(napi_env env) const111     napi_value Process::GetPid(napi_env env) const
112     {
113         napi_value result = nullptr;
114         auto proPid = static_cast<int32_t>(getpid());
115         napi_create_int32(env, proPid, &result);
116         return result;
117     }
118 
GetPpid(napi_env env) const119     napi_value Process::GetPpid(napi_env env) const
120     {
121         napi_value result = nullptr;
122         auto proPpid = static_cast<int32_t>(getppid());
123         napi_create_int32(env, proPpid, &result);
124         return result;
125     }
126 
Chdir(napi_env env,napi_value args) const127     void Process::Chdir(napi_env env, napi_value args) const
128     {
129         size_t prolen = 0;
130         if (napi_get_value_string_utf8(env, args, nullptr, 0, &prolen) != napi_ok) {
131             HILOG_ERROR("can not get args size");
132             return;
133         }
134         std::string result = "";
135         result.reserve(prolen + 1);
136         result.resize(prolen);
137         if (napi_get_value_string_utf8(env, args, result.data(), prolen + 1, &prolen) != napi_ok) {
138             HILOG_ERROR("can not get args value");
139             return;
140         }
141         int proerr = 0;
142         proerr = uv_chdir(result.c_str());
143         if (proerr) {
144             napi_throw_error(env, "-1", "chdir");
145         }
146     }
147 
Kill(napi_env env,napi_value signal,napi_value proid)148     napi_value Process::Kill(napi_env env, napi_value signal, napi_value proid)
149     {
150         int32_t pid = 0;
151         int32_t sig = 0;
152         napi_get_value_int32(env, proid, &pid);
153         napi_get_value_int32(env, signal, &sig);
154         uv_pid_t ownPid = uv_os_getpid();
155         // 64:The maximum valid signal value is 64.
156         if (sig > 64 && (!pid || pid == -1 || pid == ownPid || pid == -ownPid)) {
157             napi_throw_error(env, "0", "process exit");
158         }
159         bool flag = false;
160         int err = uv_kill(pid, sig);
161         if (!err) {
162             flag = true;
163         }
164         napi_value result = nullptr;
165         NAPI_CALL(env, napi_get_boolean(env, flag, &result));
166         return result;
167     }
168 
Uptime(napi_env env) const169     napi_value Process::Uptime(napi_env env) const
170     {
171         napi_value result = nullptr;
172         struct sysinfo information = {0};
173         time_t systimer = 0;
174         double runsystime = 0.0;
175         if (sysinfo(&information)) {
176             napi_throw_error(env, "-1", "Failed to get sysinfo");
177         }
178         systimer = information.uptime;
179         if (systimer > 0) {
180             runsystime = static_cast<double>(systimer);
181             NAPI_CALL(env, napi_create_double(env, runsystime, &result));
182         } else {
183             napi_throw_error(env, "-1", "Failed to get systimer");
184         }
185         return result;
186     }
187 
Exit(napi_env env,napi_value number) const188     void Process::Exit(napi_env env, napi_value number) const
189     {
190         int32_t result = 0;
191         napi_get_value_int32(env, number, &result);
192         exit(result);
193     }
194 
Cwd(napi_env env) const195     napi_value Process::Cwd(napi_env env) const
196     {
197         napi_value result = nullptr;
198         char buf[260 * NUM_OF_DATA] = { 0 }; // 260:Only numbers path String size is 260.
199         size_t length = sizeof(buf);
200         int err = uv_cwd(buf, &length);
201         if (err) {
202             napi_throw_error(env, "1", "uv_cwd");
203         }
204         napi_create_string_utf8(env, buf, length, &result);
205         return result;
206     }
207 
Abort() const208     void Process::Abort() const
209     {
210         exit(0);
211     }
212 
On(napi_env env,napi_value str,napi_value function)213     void Process::On(napi_env env, napi_value str, napi_value function)
214     {
215         std::string result = "";
216         size_t bufferSize = 0;
217         if (napi_get_value_string_utf8(env, str, nullptr, NAPI_RETURN_ZERO, &bufferSize) != napi_ok) {
218             HILOG_ERROR("can not get str size");
219             return;
220         }
221         result.reserve(bufferSize + NAPI_RETURN_ONE);
222         result.resize(bufferSize);
223         if (napi_get_value_string_utf8(env, str, result.data(), bufferSize + NAPI_RETURN_ONE,
224                                        &bufferSize) != napi_ok) {
225             HILOG_ERROR("can not get str value");
226             return;
227         }
228         if (function == nullptr) {
229             HILOG_ERROR("function is nullptr");
230             return;
231         }
232         napi_ref myCallRef = nullptr;
233         napi_status status = napi_create_reference(env, function, 1, &myCallRef);
234         if (status != napi_ok) {
235             HILOG_ERROR("napi_create_reference is failed");
236             return;
237         }
238         if (!result.empty()) {
239             size_t pos = events.find(result);
240             if (pos == std::string::npos) {
241                 HILOG_ERROR("illegal event");
242                 return;
243             }
244             eventMap.insert(std::make_pair(result, myCallRef));
245         }
246     }
247 
Off(napi_env env,napi_value str)248     napi_value Process::Off(napi_env env, napi_value str)
249     {
250         size_t bufferSize = 0;
251         bool flag = false;
252         if (napi_get_value_string_utf8(env, str, nullptr, 0, &bufferSize) != napi_ok) {
253             HILOG_ERROR("can not get str size");
254             return nullptr;
255         }
256         std::string result = "";
257         result.reserve(bufferSize + 1);
258         result.resize(bufferSize);
259         if (napi_get_value_string_utf8(env, str, result.data(), bufferSize + 1, &bufferSize) != napi_ok) {
260             HILOG_ERROR("can not get str value");
261             return nullptr;
262         }
263         std::string temp = "";
264         temp = result;
265         auto iter = eventMap.equal_range(temp);
266         while (iter.first != iter.second) {
267             NAPI_CALL(env, napi_delete_reference(env, iter.first->second));
268             iter.first = eventMap.erase(iter.first);
269             flag = true;
270         }
271         napi_value convertResult = nullptr;
272         NAPI_CALL(env, napi_get_boolean(env, flag, &convertResult));
273         return convertResult;
274     }
275 
GetTid(napi_env env) const276     napi_value Process::GetTid(napi_env env) const
277     {
278         napi_value result = nullptr;
279         auto proTid = static_cast<int32_t>(gettid());
280         napi_create_int32(env, proTid, &result);
281         return result;
282     }
283 
IsIsolatedProcess(napi_env env) const284     napi_value Process::IsIsolatedProcess(napi_env env) const
285     {
286         napi_value result = nullptr;
287         bool flag = true;
288         auto prouid = static_cast<int32_t>(getuid());
289         auto uid = prouid % PER_USER_RANGE;
290         if ((uid >= 99000 && uid <= 99999) || // 99999:Only isolateuid numbers between 99000 and 99999.
291             (uid >= 9000 && uid <= 98999)) { // 98999:Only appuid numbers between 9000 and 98999.
292             NAPI_CALL(env, napi_get_boolean(env, flag, &result));
293             return result;
294         }
295         flag = false;
296         NAPI_CALL(env, napi_get_boolean(env, flag, &result));
297         return result;
298     }
299 
IsAppUid(napi_env env,napi_value uid) const300     napi_value Process::IsAppUid(napi_env env, napi_value uid) const
301     {
302         int32_t number = 0;
303         napi_value result = nullptr;
304         bool flag = true;
305         napi_get_value_int32(env, uid, &number);
306         if (number > 0) {
307             const auto appId = number % PER_USER_RANGE;
308             if (appId >= FIRST_APPLICATION_UID && appId <= LAST_APPLICATION_UID) {
309                 napi_get_boolean(env, flag, &result);
310                 return result;
311             }
312             flag = false;
313             NAPI_CALL(env, napi_get_boolean(env, flag, &result));
314             return result;
315         } else {
316             flag = false;
317             NAPI_CALL(env, napi_get_boolean(env, flag, &result));
318             return result;
319         }
320     }
321 
Is64Bit(napi_env env) const322     napi_value Process::Is64Bit(napi_env env) const
323     {
324         napi_value result = nullptr;
325         bool flag = true;
326         auto size = sizeof(char*);
327         flag = (size == NUM_OF_DATA) ? false : true;
328         NAPI_CALL(env, napi_get_boolean(env, flag, &result));
329         return result;
330     }
331 
GetEnvironmentVar(napi_env env,napi_value name) const332     napi_value Process::GetEnvironmentVar(napi_env env, napi_value name) const
333     {
334         napi_value convertResult = nullptr;
335         char buf[260 * NUM_OF_DATA] = { 0 }; // 260:Only numbers path String size is 260.
336         size_t length = sizeof(buf);
337         size_t bufferSize = 0;
338         if (napi_get_value_string_utf8(env, name, nullptr, 0, &bufferSize) != napi_ok) {
339             HILOG_ERROR("can not get name size");
340             return nullptr;
341         }
342         std::string result = "";
343         result.reserve(bufferSize + 1);
344         result.resize(bufferSize);
345         if (napi_get_value_string_utf8(env, name, result.data(), bufferSize + 1, &bufferSize) != napi_ok) {
346             HILOG_ERROR("can not get name value");
347             return nullptr;
348         }
349         std::string temp = "";
350         temp = result;
351         auto envNum = uv_os_getenv(temp.c_str(), buf, &length);
352         if (envNum == UV_ENOENT) {
353             NAPI_CALL(env, napi_get_undefined(env, &convertResult));
354             return convertResult;
355         }
356         napi_create_string_utf8(env, buf, strlen(buf), &convertResult);
357         return convertResult;
358     }
359 
GetUidForName(napi_env env,napi_value name) const360     napi_value Process::GetUidForName(napi_env env, napi_value name) const
361     {
362         struct passwd *user = nullptr;
363         int32_t uid = 0;
364         napi_value convertResult = nullptr;
365         size_t bufferSize = 0;
366         if (napi_get_value_string_utf8(env, name, nullptr, 0, &bufferSize) != napi_ok) {
367             HILOG_ERROR("can not get name size");
368             return nullptr;
369         }
370         std::string result = "";
371         result.reserve(bufferSize + 1);
372         result.resize(bufferSize);
373         if (napi_get_value_string_utf8(env, name, result.data(), bufferSize + 1, &bufferSize) != napi_ok) {
374             HILOG_ERROR("can not get name value");
375             return nullptr;
376         }
377         std::string temp = "";
378         temp = result;
379         user = getpwnam(temp.c_str());
380         if (user != nullptr) {
381             uid = static_cast<int32_t>(user->pw_uid);
382             napi_create_int32(env, uid, &convertResult);
383             return convertResult;
384         }
385         napi_create_int32(env, (-1), &convertResult);
386         return convertResult;
387     }
388 
GetThreadPriority(napi_env env,napi_value tid) const389     napi_value Process::GetThreadPriority(napi_env env, napi_value tid) const
390     {
391         errno = 0;
392         int32_t proTid = 0;
393         napi_value result = nullptr;
394         napi_get_value_int32(env, tid, &proTid);
395         int32_t pri = getpriority(PRIO_PROCESS, proTid);
396         if (errno) {
397             napi_throw_error(env, "-1", "Invalid tid");
398         }
399         napi_create_int32(env, pri, &result);
400         return result;
401     }
402 
GetStartRealtime(napi_env env) const403     napi_value Process::GetStartRealtime(napi_env env) const
404     {
405         struct timespec timespro = {0, 0};
406         struct timespec timessys = {0, 0};
407         napi_value result = nullptr;
408         auto res = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &timespro);
409         if (res) {
410             return 0;
411         }
412         auto res1 = clock_gettime(CLOCK_MONOTONIC, &timessys);
413         if (res1) {
414             return 0;
415         }
416         int whenpro = ConvertTime(timespro.tv_sec, timespro.tv_nsec);
417         int whensys = ConvertTime(timessys.tv_sec, timessys.tv_nsec);
418         auto timedif = (whensys - whenpro);
419         napi_create_int32(env, timedif, &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 
UnHandle(napi_env env,napi_value promise,napi_value reason)451     napi_value UnHandle(napi_env env, napi_value promise, napi_value reason)
452     {
453         napi_ref promiseRef = nullptr;
454         NAPI_CALL(env, napi_create_reference(env, promise, 1, &promiseRef));
455         napi_ref reasonRef = nullptr;
456         NAPI_CALL(env, napi_create_reference(env, reason, 1, &reasonRef));
457         pendingUnHandledRejections.insert(std::make_pair(promiseRef, reasonRef));
458         napi_value res = nullptr;
459         NAPI_CALL(env, napi_get_undefined(env, &res));
460         return res;
461     }
462 
AddHandle(napi_env env,napi_value promise)463     napi_value AddHandle(napi_env env, napi_value promise)
464     {
465         auto iter = pendingUnHandledRejections.begin();
466         while (iter != pendingUnHandledRejections.end()) {
467             napi_value prom = nullptr;
468             NAPI_CALL(env, napi_get_reference_value(env, iter->first, &prom));
469             bool isEquals = false;
470             NAPI_CALL(env, napi_strict_equals(env, promise, prom, &isEquals));
471             if (isEquals) {
472                 NAPI_CALL(env, napi_delete_reference(env, iter->first));
473                 NAPI_CALL(env, napi_delete_reference(env, iter->second));
474                 iter = pendingUnHandledRejections.erase(iter);
475                 continue;
476             }
477             iter++;
478         }
479         napi_value res = nullptr;
480         NAPI_CALL(env, napi_get_undefined(env, &res));
481         return res;
482     }
483 
UnHandleRejection(napi_env env,napi_value promise,napi_value reason)484     napi_value UnHandleRejection(napi_env env, napi_value promise, napi_value reason)
485     {
486         auto it = eventMap.find("UnHandleRejection");
487         if (it != eventMap.end()) {
488             napi_value global = nullptr;
489             NAPI_CALL(env, napi_get_global(env, &global));
490             size_t argc = 2; // 2 parameter size
491             napi_value args[] = {reason, promise};
492             auto iter = eventMap.equal_range("UnHandleRejection");
493             while (iter.first != iter.second) {
494                 napi_value cb = nullptr;
495                 NAPI_CALL(env, napi_get_reference_value(env, iter.first->second, &cb));
496                 napi_value result = nullptr;
497                 NAPI_CALL(env, napi_call_function(env, global, cb, argc, args, &result));
498                 iter.first++;
499             }
500         }
501         napi_value res = nullptr;
502         NAPI_CALL(env, napi_get_undefined(env, &res));
503         return res;
504     }
505 
OnUnHandleRejection(napi_env env,napi_callback_info info)506     static napi_value OnUnHandleRejection(napi_env env, napi_callback_info info)
507     {
508         size_t argc = 3; // 3 parameter size
509         napi_value argv[3] = {0}; // 3 array length
510         NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
511         int32_t event = 0;
512         NAPI_CALL(env, napi_get_value_int32(env, argv[0], &event));
513         if (event == static_cast<int32_t>(PromiseRejectionEvent::REJECT)) {
514             UnHandle(env, argv[1], argv[2]); // 2 array index
515         } else if (event == static_cast<int32_t>(PromiseRejectionEvent::HANDLE)) {
516             AddHandle(env, argv[1]);
517         }
518         napi_value res = nullptr;
519         NAPI_CALL(env, napi_get_undefined(env, &res));
520         return res;
521     }
522 
CheckUnhandleRejections(napi_env env,napi_callback_info info)523     static napi_value CheckUnhandleRejections(napi_env env, napi_callback_info info)
524     {
525         if (!pendingUnHandledRejections.empty()) {
526             auto iter = pendingUnHandledRejections.begin();
527             while (iter != pendingUnHandledRejections.end()) {
528                 napi_value promise = nullptr;
529                 NAPI_CALL(env, napi_get_reference_value(env, iter->first, &promise));
530                 napi_value reason = nullptr;
531                 NAPI_CALL(env, napi_get_reference_value(env, iter->second, &reason));
532 
533                 UnHandleRejection(env, promise, reason);
534 
535                 NAPI_CALL(env, napi_delete_reference(env, iter->first));
536                 NAPI_CALL(env, napi_delete_reference(env, iter->second));
537                 iter = pendingUnHandledRejections.erase(iter);
538             }
539         }
540         napi_value res = nullptr;
541         NAPI_CALL(env, napi_get_undefined(env, &res));
542         return res;
543     }
544 
SetRejectionCallback(napi_env env) const545     napi_value Process::SetRejectionCallback(napi_env env) const
546     {
547         napi_value cb = nullptr;
548         std::string callbackName = "onUnHandleRejection";
549         NAPI_CALL(env, napi_create_function(env, callbackName.c_str(), callbackName.size(), OnUnHandleRejection,
550                                              nullptr, &cb));
551         napi_ref unHandleRejectionCallbackRef = nullptr;
552         NAPI_CALL(env, napi_create_reference(env, cb, 1, &unHandleRejectionCallbackRef));
553 
554         napi_ref checkUnhandleRejectionsRef = nullptr;
555         napi_value checkcb = nullptr;
556         std::string cbName = "CheckUnhandleRejections";
557         NAPI_CALL(env, napi_create_function(env, cbName.c_str(), cbName.size(), CheckUnhandleRejections,
558                                              nullptr, &checkcb));
559         NAPI_CALL(env, napi_create_reference(env, checkcb, 1, &checkUnhandleRejectionsRef));
560         napi_value res = nullptr;
561         NAPI_CALL(env, napi_get_undefined(env, &res));
562         return res;
563     }
ClearReference(napi_env env)564     void Process::ClearReference(napi_env env)
565     {
566         auto iter = eventMap.begin();
567         while (iter != eventMap.end()) {
568             napi_status status = napi_delete_reference(env, iter->second);
569             if (status != napi_ok) {
570                 napi_throw_error(env, nullptr, "ClearReference failed");
571             }
572             iter++;
573         }
574         eventMap.clear();
575     }
576 } // namespace OHOS::Js_sys_module::Process
577