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