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, ×); 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