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, ×pro); 409 if (res) { 410 return 0; 411 } 412 auto res1 = clock_gettime(CLOCK_MONOTONIC, ×sys); 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, ×); 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