#include "il2cpp-config.h" #if IL2CPP_TARGET_LUMIN #include #include #include #include #include #include "os/Process.h" #include "utils/Logging.h" struct ProcessHandle { pid_t pid; }; namespace il2cpp { namespace os { const int _sc_clk_tck = sysconf(_SC_CLK_TCK); typedef struct { char name[256]; unsigned long utime; unsigned long stime; unsigned long long starttime; } ProcessStatInfo; typedef struct { unsigned vmpeak; unsigned vmsize; unsigned vmhwm; unsigned vmrss; unsigned vmdata; unsigned vmstk; unsigned vmswap; } ProcessStatusInfo; static bool GetProcessStatInfo(int pid, ProcessStatInfo *result) { char buffer[4096], *open_paren, *close_paren; FILE *fp; sprintf(buffer, "/proc/%d/stat", pid); fp = fopen(buffer, "r"); if (fp == NULL) { return false; } fgets(buffer, sizeof(buffer) - 1, fp); fclose(fp); buffer[sizeof(buffer) - 1] = 0; open_paren = strchr(buffer, '('); if (open_paren == NULL) { return false; } close_paren = strrchr(open_paren + 1, ')'); if (close_paren == NULL) { return false; } *close_paren = 0; strncpy(result->name, open_paren + 1, sizeof(result->name) - 1); result->name[sizeof(result->name) - 1] = 0; sscanf(close_paren + 1, " %*c %*d %*d %*d %*d %*d %*u %*lu %*lu %*lu %*lu %lu %lu %*ld %*ld %*ld %*ld %*ld %*ld %llu", &result->utime, &result->stime, &result->starttime); return true; } #define GPSI_STARTSWITH(s) (strncasecmp(buffer, s, sizeof(s) - 1) == 0) static bool GetProcessStatusInfo(int pid, ProcessStatusInfo *result) { char buffer[1024], *p; FILE *fp; sprintf(buffer, "/proc/%d/status", pid); fp = fopen(buffer, "r"); if (fp == NULL) { return false; } memset(result, 0, sizeof(*result)); while (fgets(buffer, sizeof(buffer) - 1, fp)) { buffer[sizeof(buffer) - 1] = 0; if (GPSI_STARTSWITH("VmPeak:")) { sscanf(buffer + sizeof("VmPeak:") - 1, "%u", &result->vmpeak); } else if (GPSI_STARTSWITH("VmSize:")) { sscanf(buffer + sizeof("VmSize:") - 1, "%u", &result->vmsize); } else if (GPSI_STARTSWITH("VmHWM:")) { sscanf(buffer + sizeof("VmHWM:") - 1, "%u", &result->vmhwm); } else if (GPSI_STARTSWITH("VmRSS:")) { sscanf(buffer + sizeof("VmRSS:") - 1, "%u", &result->vmrss); } else if (GPSI_STARTSWITH("VmData:")) { sscanf(buffer + sizeof("VmData:") - 1, "%u", &result->vmdata); } else if (GPSI_STARTSWITH("VmStk:")) { sscanf(buffer + sizeof("VmStk:") - 1, "%u", &result->vmstk); } else if (GPSI_STARTSWITH("VmSwap:")) { sscanf(buffer + sizeof("VmSwap:") - 1, "%u", &result->vmswap); } } fclose(fp); return true; } #undef GPSI_STARTSWITH int Process::GetCurrentProcessId() { return getpid(); } utils::Expected Process::GetProcess(int processId) { // If/when we implement the CreateProcess_internal icall we will likely // need to so something smarter here to find the process if we did // not create it and return a known pseudo-handle. For now this // is sufficient though. return (ProcessHandle*)(intptr_t)processId; } void Process::FreeProcess(ProcessHandle* handle) { // We have nothing to do here. } utils::Expected Process::GetProcessName(ProcessHandle* handle) { intptr_t pid = (intptr_t)handle; ProcessStatInfo psi; if (GetProcessStatInfo(pid, &psi)) { return std::string(psi.name); } else { return std::string(); } } int64_t Process::Times(ProcessHandle* handle, int32_t type) { int pid = (intptr_t)handle; ProcessStatInfo psi; int64_t result = 0; if (GetProcessStatInfo(pid, &psi)) { result = (int64_t)psi.utime * (10000000 / _sc_clk_tck); if (type == 2) // Total process time { result += (int64_t)psi.stime * (10000000 / _sc_clk_tck); } } return result; } int64_t Process::StartTime(ProcessHandle* handle) { int pid = (intptr_t)handle; ProcessStatInfo psi; if (GetProcessStatInfo(pid, &psi)) { struct sysinfo si; if (sysinfo(&si) == 0) { const int64_t unix_time_to_filetime = 11644473600ll; int64_t boot_time = (int64_t)time(NULL) - si.uptime + unix_time_to_filetime; return (boot_time + psi.starttime / _sc_clk_tck) * 10000000ll; } } return 0; } int64_t Process::GetProcessData(int32_t pid, int32_t data_type, int32_t* error) { ProcessStatusInfo psi; if (GetProcessStatusInfo(pid, &psi)) { switch (data_type) { case 4: // WorkingSet64 return (int64_t)psi.vmrss * 1024; case 5: // PeakWorkingSet64 return (int64_t)psi.vmhwm * 1024; case 6: // PrivateMemorySize64 return (int64_t)(psi.vmdata + psi.vmstk) * 1024; case 7: // VirtualMemorySize64 return (int64_t)psi.vmsize * 1024; case 8: // PeakVirtualMemorySize64 return (int64_t)psi.vmpeak * 1024; default: { char buf[256]; sprintf(buf, "Process::GetProcessData: Unknown data_type %d", data_type); utils::Logging::Write(buf); break; } } } return 0; } intptr_t Process::GetMainWindowHandle(int32_t pid) { return 0; } } } #endif