spshell.cpp 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070
  1. #include "precompile.h"
  2. #include "app.h"
  3. #include "osutil.h"
  4. #include "version.h"
  5. #include "memtrace.h"
  6. #include "sp_def.h"
  7. #ifdef RVC_OS_WIN
  8. #include <DbgHelp.h>
  9. #include <TlHelp32.h>
  10. #include <shellapi.h>
  11. #else
  12. #include <unistd.h>
  13. #endif //RVC_OS_WIN
  14. #include "fileutil.h"
  15. #include "iniutil.h"
  16. #include "getopt.h"
  17. #include "toolkit.h"
  18. #include "SimpleString.h"
  19. #include "md5file.h"
  20. #include "SpBase.h"
  21. #include "SpComm.hpp"
  22. #ifdef RVC_OS_WIN
  23. #include <io.h>
  24. #pragma comment(lib, "dbghelp.lib")
  25. #else
  26. #include <unistd.h>
  27. #include <sys/syscall.h>
  28. #endif //RVC_OS_WIN
  29. #include <map>
  30. #include <iterator>
  31. #include <fstream>
  32. #include "libtoolkit/log.h"
  33. #include <signal.h>
  34. #include "SpBase.h"
  35. #include "sp_dbg_export.h"
  36. #include "versionBase.h"
  37. #include "base64File.hpp"
  38. #include "RVCEventCode.h"
  39. #include "dbgutil.h"
  40. #include <locale.h>
  41. #include <winpr/library.h>
  42. #include <winpr/environment.h>
  43. #include <winpr/registry.h>
  44. #include <winpr/sysinfo.h>
  45. #ifdef realloc
  46. #undef realloc //(p, s)
  47. #endif
  48. using namespace std;
  49. #include <spbase/sp_runTask.h>
  50. #ifndef RVC_OS_WIN
  51. static int GetParentProcessID()
  52. {
  53. #if 0
  54. return getppid();
  55. #else
  56. return (int)syscall(SYS_getppid);
  57. #endif
  58. }
  59. #endif //NOT _WIN32
  60. #ifdef RVC_OS_WIN
  61. static char spshell_execute_name[] = "SpShell.exe";
  62. static char sphost_execute_name[] = "SpHost.exe";
  63. static char guardian_execute_name[] = "Guardian.exe";
  64. static char cefclient_execute_name[] = "cefclient.exe";
  65. #else
  66. static char spshell_execute_name[] = "spshell";
  67. static char sphost_execute_name[] = "sphost";
  68. static char guardian_execute_name[] = "guardian";
  69. static char cefclient_execute_name[] = "cefclient";
  70. #endif //_WIN32
  71. #define RESTART_MODE_DEFAULT 0
  72. #define RESTART_MODE_NORMAL 1
  73. #define RESTART_MODE_PRE 2
  74. #define RESTART_MODE_SHUTDOWN 3
  75. #define RESTART_MODE_POWEROFF 4
  76. #define RESTART_MODE_REBOOT 5
  77. #define DRIVER_NAME "HelloDDK"
  78. #define DRIVER_PATH "InterceptDll.sys"
  79. #define SET_EVENT \
  80. CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
  81. #define GET_SHARE_ADD \
  82. CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
  83. HANDLE g_hEvent = NULL;
  84. bool g_bMD5Exist = false;
  85. bool g_bWow64 = false;
  86. CSimpleStringA g_strMD5ListPath;
  87. static int g_restartMode = RESTART_MODE_DEFAULT;
  88. static bool g_immediately = false;
  89. char* relate_processes[] = { spshell_execute_name, sphost_execute_name, cefclient_execute_name };
  90. const int relate_processes_count = 3;
  91. char* relate_processes_ex[] = { spshell_execute_name, sphost_execute_name, guardian_execute_name, cefclient_execute_name };
  92. const int relate_processes_ex_count = 4;
  93. const int MAX_LEN = 256;
  94. //E:\Run\version\3.10.0.1\dep;E:\Run\version\3.10.0.1\bin;E:\Run\version\3.10.0.1\dev;E:\Run\version\3.10.0.1\imdep
  95. static bool IsSpPathType(const CSimpleStringA& value, const char* key)
  96. {
  97. const int leastLength = strlen("Run//1.0.0.0/") + strlen(key);
  98. CSimpleStringA path(value.GetData());
  99. if (path.IsNullOrEmpty() || path.GetLength() < leastLength) return false;
  100. for (int i = 0; i < path.GetLength(); ++i) {
  101. if (path[i] >= 'A' && path[i] <= 'Z') path[i] = path[i] + ('a' - 'A');
  102. }
  103. const int sionPos = path.IndexOf(key);
  104. const int verPos = sionPos + strlen(key) + strlen(SPLIT_SLASH_STR);
  105. if (sionPos < 0) return false;
  106. int suffixPos = -1, i;
  107. int dotCnt = 0;
  108. bool lastIsNum = false;
  109. for (i = verPos; i < path.GetLength() && (path[i] >= '0' && path[i] <= '9' || path[i] == '.'); ++i) {
  110. lastIsNum = !(path[i] == '.');
  111. if (!lastIsNum) dotCnt++;
  112. }
  113. //if (i == path.GetLength() && dotCnt == 3 && lastIsNum) return true; //D:\Run\version\3.7.1.0
  114. if (i >= path.GetLength() || dotCnt != 3 || !lastIsNum)
  115. return false;
  116. return true;
  117. }
  118. static CSimpleStringA CutSpPathFromPathValue(const char* value, const char* prefix)
  119. {
  120. CSimpleStringA path(value);
  121. CSimpleStringA result(true);
  122. CAutoArray<CSimpleStringA> values = path.Split(ENV_SEP_CHAR);
  123. if (values.GetCount() <= 0) {
  124. return path;
  125. }
  126. for (int i = 0; i < values.GetCount(); ++i) {
  127. if (!values[i].IsStartWith(prefix) && !IsSpPathType(values[i], "version") &&! IsSpPathType(values[i], "dep")) {
  128. if (!result.IsNullOrEmpty()) result += ENV_SEP_STR;
  129. result += values[i];
  130. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("toadd:%s", values[i].GetData());
  131. }
  132. }
  133. //if (!result.IsNullOrEmpty() && path[path.GetLength() - 1] == ENV_SEP_CHAR) {
  134. // result += ENV_SEP_STR;
  135. //}
  136. return result;
  137. }
  138. static void ResetEnvPath()
  139. {
  140. char path[MAX_PATH];
  141. char *buf;
  142. DWORD size;
  143. #if defined(_MSC_VER)
  144. const char* name = "PATH";
  145. #else
  146. const char* name = "LD_LIBRARY_PATH";
  147. #endif //_MSC_VER
  148. // set current path
  149. GetModuleFileNameA(NULL, path, MAX_PATH);
  150. *strrchr(path, SPLIT_SLASH) = 0; //bin
  151. *strrchr(path, SPLIT_SLASH) = 0; //1.2.3.4
  152. SetCurrentDirectoryA(path);
  153. size = GetEnvironmentVariableA(name, NULL, 0);
  154. buf = (char*)malloc(size+MAX_PATH*3);
  155. size = GetEnvironmentVariableA(name, buf, size);
  156. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("origin path:%s", buf);
  157. CSimpleStringA newValue = CutSpPathFromPathValue(buf, path);
  158. memset(buf, 0, size + MAX_PATH * 3);
  159. size = newValue.GetLength();
  160. if (!newValue.IsNullOrEmpty()) {
  161. strcpy(buf, newValue.GetData());
  162. strcat(buf, ENV_SEP_STR);
  163. }
  164. // append bin sub dir to %PATH%
  165. strcat(path, SPLIT_SLASH_STR "bin");
  166. strcat(buf, path);
  167. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("new path:%s", buf);
  168. SetEnvironmentVariableA(name, buf);
  169. free(buf);
  170. SetEnvironmentVariableA("ModuleName", "SpShell");
  171. }
  172. #ifdef RVC_OS_WIN
  173. static void SetWorkingSet()
  174. {
  175. SIZE_T dwMinSize, dwMaxSize;
  176. HANDLE hCurrProcess = GetCurrentProcess();
  177. GetProcessWorkingSetSize(hCurrProcess, &dwMinSize, &dwMaxSize);
  178. if (dwMaxSize < (2 << 20))
  179. dwMaxSize = 2 << 20;
  180. SetProcessWorkingSetSize(hCurrProcess, dwMinSize, dwMaxSize);
  181. }
  182. static LONG WINAPI SuppressError(struct _EXCEPTION_POINTERS* ExceptionInfo)
  183. {
  184. static bool hasCall = false;
  185. if (hasCall)
  186. ExitProcess(Error_Exception);
  187. else
  188. hasCall = true;
  189. char tmp[MAX_PATH];
  190. HANDLE hDumpFile;
  191. std::string dmpFileStr;
  192. GetModuleFileNameA(NULL, tmp, MAX_PATH);
  193. *strrchr(tmp, SPLIT_SLASH) = 0;
  194. *strrchr(tmp, SPLIT_SLASH) = 0;
  195. *strrchr(tmp, SPLIT_SLASH) = 0;
  196. *strrchr(tmp, SPLIT_SLASH) = 0;
  197. *strrchr(tmp, SPLIT_SLASH) = 0;
  198. wsprintfA(tmp, "%s\\rvc\\dmp\\expt.spshell.%d.%s.dmp", tmp, GetCurrentProcessId(), STRFILEVER);
  199. hDumpFile = CreateFileA( tmp, GENERIC_READ | GENERIC_WRITE,
  200. 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
  201. if( ( hDumpFile != NULL ) && ( hDumpFile != INVALID_HANDLE_VALUE ) )
  202. {
  203. MINIDUMP_EXCEPTION_INFORMATION mdei;
  204. MINIDUMP_TYPE mdt;
  205. mdei.ThreadId = GetCurrentThreadId();
  206. mdei.ExceptionPointers = ExceptionInfo;
  207. mdei.ClientPointers = FALSE;
  208. mdt = MiniDumpNormal;
  209. MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
  210. hDumpFile, mdt, (ExceptionInfo != 0) ? &mdei : 0, 0, 0 );
  211. CloseHandle( hDumpFile );
  212. }
  213. char szCmd[256];
  214. sprintf_s(szCmd, 256, "TASKKILL /f /im sphost.exe");
  215. system(szCmd);
  216. sprintf_s(szCmd, 256, "TASKKILL /f /im sphost_re.exe");
  217. system(szCmd);
  218. DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__).setLogCode(ERR_SPSHELL_EXCETION).setResultCode(RTAERR_SPSHELL_EXCEPTION)("spshell exit exception, saveDmp, %s, detail:%d:%s"
  219. , tmp, dmpFileStr.length() ,dmpFileStr.c_str());
  220. ExitProcess(Error_Exception); // exit process to suppress reporting exception
  221. return EXCEPTION_EXECUTE_HANDLER;
  222. }
  223. __declspec(dllimport) bool DisableCharmbar();
  224. __declspec(dllimport) bool EnableCharmbar();
  225. static void AutoHideTaskBar(bool bHide)
  226. {
  227. APPBARDATA apBar;
  228. memset(&apBar, 0, sizeof(apBar));
  229. apBar.cbSize = sizeof(apBar);
  230. apBar.lParam = bHide ? ABS_AUTOHIDE : ABS_ALWAYSONTOP;
  231. apBar.hWnd = FindWindow("Shell_TrayWnd", NULL);
  232. if (apBar.hWnd != NULL)
  233. {
  234. SHAppBarMessage(ABM_SETSTATE, &apBar);
  235. }
  236. }
  237. static bool AddFirewallRules()
  238. {
  239. char szBinDir[MAX_PATH] = {};
  240. GetModuleFileNameA(NULL, szBinDir, MAX_PATH);
  241. *strrchr(szBinDir, SPLIT_SLASH) = 0;
  242. int nRet = (int)ShellExecute(NULL, "open", "cmd.exe", "/s /c \"netsh advfirewall firewall delete rule name=\"\"SpShell\"\"", NULL, SW_HIDE);
  243. nRet = (int)ShellExecute(NULL, "open", "cmd.exe", "/s /c \"netsh advfirewall firewall delete rule name=\"\"SpHost_re\"\"", NULL, SW_HIDE);
  244. nRet = (int)ShellExecute(NULL, "open", "cmd.exe", "/s /c \"netsh advfirewall firewall delete rule name=\"\"SpHost\"\"", NULL, SW_HIDE);
  245. nRet = (int)ShellExecute(NULL, "open", "cmd.exe", "/s /c \"netsh advfirewall firewall delete rule name=\"\"SpGuardian\"\"", NULL, SW_HIDE);
  246. nRet = (int)ShellExecute(NULL, "open", "cmd.exe", "/s /c \"netsh advfirewall firewall delete rule name=\"\"cefclient\"\"", NULL, SW_HIDE);
  247. char szParam[1024] = {};
  248. sprintf_s(szParam, 1024, "/s /c \"netsh advfirewall firewall add rule name=\"\"SpShell\"\" dir=out program=\"\"%s\\spshell.exe\"\" action=allow\"", szBinDir);
  249. nRet = (int)ShellExecute(NULL, "open", "cmd.exe", szParam, NULL, SW_HIDE);
  250. sprintf_s(szParam, 1024, "/s /c \"netsh advfirewall firewall add rule name=\"\"SpHost\"\" dir=out program=\"\"%s\\sphost.exe\"\" action=allow\"", szBinDir);
  251. nRet = (int)ShellExecute(NULL, "open", "cmd.exe", szParam, NULL, SW_HIDE);
  252. sprintf_s(szParam, 1024, "/s /c \"netsh advfirewall firewall add rule name=\"\"SpGuardian\"\" dir=out program=\"\"%s\\guardian.exe\"\" action=allow\"", szBinDir);
  253. nRet = (int)ShellExecute(NULL, "open", "cmd.exe", szParam, NULL, SW_HIDE);
  254. sprintf_s(szParam, 1024, "/s /c \"netsh advfirewall firewall add rule name=\"\"cefclient\"\" dir=out program=\"\"%s\\Chromium\\cefclient.exe\"\" action=allow\"", szBinDir);
  255. nRet = (int)ShellExecute(NULL, "open", "cmd.exe", szParam, NULL, SW_HIDE);
  256. return nRet > 32;
  257. }
  258. int AddFireAddFirewallRulesThread(void* param)
  259. {
  260. if (!AddFirewallRules())
  261. {
  262. DbgWithLink(LOG_LEVEL_FATAL, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("设置Windows防火墙策略失败!!!");
  263. Sleep(10000);
  264. return -1;
  265. }
  266. else
  267. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("设置Windows防火墙策略成功!!!");
  268. return 0;
  269. }
  270. static void AddFirewallRulesEx()
  271. {
  272. CloseHandle(CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)& AddFireAddFirewallRulesThread, NULL, 0, NULL));
  273. }
  274. #endif //RVC_OS_WIN
  275. /*!
  276. * at Linux, judge whether current process runs as root privilege.
  277. * @return : True only if run as admin or root
  278. */
  279. static bool IsProcessRunAsAdmin()
  280. {
  281. BOOL bAdmin = FALSE;
  282. #ifdef RVC_OS_WIN
  283. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  284. PSID AdministratorsGroup = NULL;
  285. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("start AllocateAndInitializeSid");
  286. if (AllocateAndInitializeSid(
  287. &NtAuthority,
  288. 2,
  289. SECURITY_BUILTIN_DOMAIN_RID,
  290. DOMAIN_ALIAS_RID_ADMINS,
  291. 0, 0, 0, 0, 0, 0,
  292. &AdministratorsGroup))
  293. {
  294. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("start CheckTokenMembership");
  295. CheckTokenMembership(NULL, AdministratorsGroup, &bAdmin);
  296. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("start FreeSid");
  297. FreeSid(AdministratorsGroup);
  298. }
  299. #else
  300. if (geteuid() == 0) {
  301. bAdmin = TRUE;
  302. } else {
  303. DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM)("current process is not run as root privilege, euid:%u, uid:%d", geteuid(), getuid());
  304. }
  305. #endif //RVC_OS_WIN
  306. return bAdmin == TRUE;
  307. }
  308. const char *GetMachineType()
  309. {
  310. auto env = sp_get_env();
  311. if (env == NULL)
  312. {
  313. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("sp_get_env return null");
  314. return NULL;
  315. }
  316. return env->cfg->root_ini->machine_type;
  317. }
  318. #ifdef RVC_OS_WIN
  319. const char *GetCenterSettingNameBySite(const char *pszSite)
  320. {
  321. ///*TODO(80374374@3/23/2023): CenterSettings */
  322. #if defined(_MSC_VER)
  323. return "CenterSetting.ini";
  324. #else
  325. if (pszSite == NULL || strlen(pszSite) == 0)
  326. return "CenterSetting.ini";
  327. if ((stricmp(pszSite, "CMB.LIB") == 0)
  328. || (stricmp(pszSite, "CMB.SSB") == 0)) {
  329. return "CenterSetting.LAN.ini";
  330. } else if ((stricmp(pszSite, "CMB.LSS") == 0)
  331. || (stricmp(pszSite, "CMB.FLB") == 0)
  332. || (stricmp(pszSite, "CMB.OSB") == 0)
  333. || (stricmp(pszSite, "CMB.SMM") == 0)) {
  334. return "CenterSetting.DMZ.ini";
  335. } else {
  336. return "CenterSetting.DMZ.ini";
  337. }
  338. #endif //_MSC_VER
  339. }
  340. #endif //RVC_OS_WIN
  341. static bool SpTerminateProcess(HANDLE hProc, DWORD dwProcID)
  342. {
  343. if (!TerminateProcess(hProc, -1))
  344. {
  345. #ifdef RVC_OS_WIN
  346. char szCmd[256];
  347. int nRet = 0;
  348. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("terminate process %d fail: 0x%X, retry with taskkill", dwProcID, GetLastError());
  349. sprintf_s(szCmd, 256, "TASKKILL /PID %d /F", dwProcID);
  350. WinExec(szCmd, SW_HIDE);
  351. return nRet != -1;
  352. #else
  353. return false;
  354. #endif //RVC_OS_WIN
  355. }
  356. return true;
  357. }
  358. void DisplayUsage()
  359. {
  360. char szHelp[4097] = { '\0' };
  361. sprintf_s(szHelp, 4096, "\n"
  362. "Usage spshell [--entity {EntityName}][--guardian][--test][--benchmark][--kill][--debug][--ipc <pipe|tcp>][--restart][--noroot]\n"
  363. "--entity {EntityName} --启动特定的实体,选项后面输入实体名称\n"
  364. "--guardian --以后台进程的方式运行,暂未实现\n"
  365. "--test --以测试模式运行\n"
  366. "--autotest --自动化验证\n"
  367. "--debug --以调试模式运行,输出更为详细的日志\n"
  368. "--benchmark --以压力测试的模式启动\n"
  369. "--kill --直接杀死终端相关进程,比如 spshell, sphost 等\n"
  370. "--shutdown --彻底退出终端相关进程,不单独使用\n"
  371. "--systemoff --执行系统关机指令,关机前会彻底退出应用,不单独使用\n"
  372. "--reboot --执行系统重启指令,重启关机前会彻底退出应用,不单独使用\n"
  373. "--ipc <pipe|tcp> --指定实体间的通讯方式,使用管道或TCP,默认使用管道\n"
  374. "--noroot -- 允许以非管理员或Root权限方式启动\n"
  375. "--restart --重启当前应用\n"
  376. "--version --显示当前的版本\n"
  377. #ifdef WITH_DEBUG
  378. "--telnet {listern port} --激活远程调用功能\n"
  379. #endif
  380. );
  381. #ifdef RVC_OS_WIN
  382. MessageBoxA(NULL, szHelp, "Spshell Usage Tip", MB_OK);
  383. #else
  384. printf("%s\n", szHelp);
  385. #endif
  386. }
  387. static void DestroyArgs(sp_cfg_start_args_t* args)
  388. {
  389. if (args != NULL) {
  390. FREE(args->program);
  391. FREE(args->arguments);
  392. }
  393. FREE(args);
  394. }
  395. sp_cfg_start_args_t* DealWithArgs(int argc, char** argv)
  396. {
  397. int allocedEntitiyLen = 0;
  398. sp_cfg_start_args_t* args = MALLOC_T(sp_cfg_start_args_t);
  399. TOOLKIT_ASSERT(args);
  400. memset(args, 0, sizeof(sp_cfg_start_args_t));
  401. args->program = args->arguments = NULL;
  402. if (argc > 0) {
  403. args->program = CALLOC_T(strlen(argv[0]) + 1, char);
  404. if (!args->program) { exit(-1); }
  405. memset(args->program, '\0', sizeof(char) * (strlen(argv[0]) + 1));
  406. strcpy(args->program, argv[0]);
  407. printf("program: %s\n", args->program);
  408. std::string params;
  409. for (int i = 1, k=0; i < argc; ++i) {
  410. if(strcmp(argv[i], "--restart") == 0 || strcmp(argv[i], "-R") == 0 || strcmp(argv[i], "-Rwait")/*QT*/ == 0 || strcmp(argv[i], "wait") == 0)
  411. continue;
  412. if (k != 0) params += " ";
  413. params += argv[i];
  414. k++;
  415. }
  416. if (!params.empty()) {
  417. args->arguments = CALLOC_T(params.length() + 1, char);
  418. if (!args->arguments) { exit(-1); }
  419. memset(args->arguments, '\0', sizeof(char) * (params.length()));
  420. strcpy(args->arguments, params.c_str());
  421. }
  422. printf("param: %s\n", args->arguments);
  423. }
  424. args->gui = 1;
  425. args->root = 1;
  426. static struct option spshell_options[] = {
  427. {"entity", required_argument, 0, 'E' },
  428. {"guardian", no_argument, 0, 'G'},
  429. {"test", no_argument, 0, 'T'},
  430. {"autotest", no_argument, 0, 'C'},
  431. {"debug", no_argument, 0, 'D'},
  432. {"ipc", required_argument, 0, 'I'},
  433. {"shutdown", no_argument, 0, 'S'},
  434. {"kill", no_argument, 0, 'K'},
  435. {"benchmark", no_argument, 0, 'B'},
  436. {"gui", required_argument, 0, 'U'},
  437. #ifdef WITH_DEBUG
  438. {"telnet", required_argument, 0, 'N' },
  439. #endif
  440. {"help", no_argument, 0, 'H'},
  441. {"version", no_argument, 0, 'V'},
  442. {"noroot", no_argument, 0, 'O'},
  443. {"restart", optional_argument, 0, 'R'},
  444. {"systemoff", optional_argument, 0, 'Y'},
  445. {"reboot", optional_argument, 0, 'J'},
  446. {"env", required_argument, 0, 'A' },
  447. {0, 0, 0, 0}
  448. };
  449. int spshell_index = 0;
  450. int c;
  451. while ((c = getopt_long(argc, argv, "E:GTCDI:SKBU:HVOR::Y::J::A:?", spshell_options, &spshell_index)) != EOF) {
  452. switch (c) {
  453. case 'C':
  454. #ifndef DEVOPS_ON_PRD
  455. //非生产情况下,才支持测试模式
  456. args->auto_test = 1;
  457. #endif // DEVOPS_ON_PRD
  458. break;
  459. case 'E':
  460. {
  461. if (optarg != NULL) {
  462. const int len = strlen(optarg);
  463. if (args->start_entities == NULL || len + strlen(args->start_entities) + 2 /*;\0*/ >= allocedEntitiyLen) {
  464. if (args->start_entities == NULL) {
  465. TOOLKIT_ASSERT(allocedEntitiyLen == 0);
  466. allocedEntitiyLen = 128;
  467. args->start_entities = CALLOC_T(allocedEntitiyLen, char);
  468. if (NULL == args->start_entities) {
  469. DestroyArgs(args);
  470. exit(-1);
  471. }
  472. } else {
  473. TOOLKIT_ASSERT(allocedEntitiyLen != 0);
  474. const int newLen = allocedEntitiyLen + len + 32;
  475. char* newAlloc = CALLOC_T(newLen, char);
  476. if (NULL == newAlloc) {
  477. DestroyArgs(args);
  478. exit(-1);
  479. }
  480. memset(newAlloc, '\0', sizeof(char) * newLen);
  481. strcpy_s(newAlloc, newLen, args->start_entities);
  482. FREE(args->start_entities);
  483. args->start_entities = newAlloc;
  484. allocedEntitiyLen = newLen;
  485. }
  486. }
  487. strcat(args->start_entities, optarg);
  488. strcat(args->start_entities, ";");
  489. }
  490. }
  491. break;
  492. case 'G':
  493. args->guardian_mode = 1;
  494. break;
  495. case 'D':
  496. args->debug_mode = 1;
  497. break;
  498. case 'T':
  499. args->test_mode = (args->test_mode | 1);
  500. break;
  501. case 'B':
  502. args->test_mode = (args->test_mode | 2);
  503. break;
  504. case 'I':
  505. if (optarg) {
  506. if (strnicmp(optarg, "tcp", strlen("tcp")) == 0)
  507. args->ipc_type = 1;
  508. }
  509. break;
  510. #ifdef WITH_DEBUG
  511. case 'N':
  512. if (optarg) {
  513. int nPort = 0;
  514. if (0 < sscanf(optarg, "%d", &nPort))
  515. args->telnet_port = nPort;
  516. }
  517. break;
  518. #endif
  519. case 'K':
  520. {
  521. osutil_terminate_related_process(relate_processes_ex, array_size(relate_processes_ex), 1);
  522. DestroyArgs(args);
  523. exit(0);
  524. }
  525. break;
  526. case 'U':
  527. if (optarg) {
  528. if (strnicmp(optarg, "ON", strlen("ON")) == 0)
  529. args->gui = 1;
  530. else if(strnicmp(optarg, "OFF", strlen("OFF")) == 0)
  531. args->gui = 0;
  532. }
  533. break;
  534. case 'A':
  535. if (optarg) {
  536. if (strnicmp(optarg, "ST", strlen("ST")) == 0)
  537. args->test_mode = (args->test_mode | 4);
  538. else if (strnicmp(optarg, "UAT", strlen("UAT")) == 0)
  539. args->test_mode = (args->test_mode | 8);
  540. }
  541. break;
  542. case 'V':
  543. {
  544. DestroyArgs(args);
  545. exit(0);
  546. break;
  547. }
  548. break;
  549. case 'O':
  550. args->root = 0;
  551. break;
  552. case 'R':
  553. g_restartMode = RESTART_MODE_NORMAL;
  554. if (optarg && strcmp(optarg, "wait") == 0) {
  555. g_restartMode = RESTART_MODE_PRE;
  556. }
  557. break;
  558. case 'S':
  559. g_restartMode = RESTART_MODE_SHUTDOWN;
  560. break;
  561. case 'Y':
  562. g_restartMode = RESTART_MODE_POWEROFF;
  563. if (optarg && strnicmp(optarg, "now", strlen("now")) == 0) {
  564. g_immediately = true;
  565. }
  566. break;
  567. case 'J':
  568. g_restartMode = RESTART_MODE_REBOOT;
  569. if (optarg && strnicmp(optarg, "now", strlen("now")) == 0) {
  570. g_immediately = true;
  571. }
  572. break;
  573. case 'H':
  574. case '?':
  575. default:
  576. DisplayUsage();
  577. DestroyArgs(args);
  578. exit(0);
  579. break;
  580. }
  581. }
  582. if (optind < argc) {
  583. while (optind < argc) {
  584. //DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM)("\t%s", argv[optind++]);
  585. }
  586. }
  587. if (args && args->start_entities != 0) {
  588. args->start_entities[strlen(args->start_entities) - 1] = '\0';
  589. }
  590. return args;
  591. }
  592. void normal_signal_handle(int num)
  593. {
  594. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("receive signal %d", num);
  595. signal(num, SIG_DFL);
  596. raise(num);
  597. }
  598. static bool NeedToRestartFramework()
  599. {
  600. //Shutdown 表明退掉框架不重启
  601. return !((g_restartMode == RESTART_MODE_SHUTDOWN
  602. || g_restartMode == RESTART_MODE_POWEROFF
  603. || g_restartMode == RESTART_MODE_REBOOT));
  604. }
  605. #if defined(_MSC_VER)
  606. ///*TODO(80374374@3/23/2023): osutil_detect_unique_app 替代 */
  607. static bool DetectDuplicateInstance(char** pNames, int nNum)
  608. {
  609. DWORD dwCurProcID = GetCurrentProcessId();
  610. HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  611. std::shared_ptr<void> delHandleFun((void*)0, [&](void*) {
  612. if (NULL != hSnapshot)
  613. CloseHandle(hSnapshot);
  614. });
  615. if (hSnapshot) {
  616. PROCESSENTRY32 pe = {};
  617. pe.dwSize = sizeof(pe);
  618. if (Process32First(hSnapshot, &pe)) {
  619. do {
  620. for (int i = 0; i < nNum; i++) {
  621. if (stricmp(&pe.szExeFile[0], pNames[i]) == 0 && pe.th32ProcessID != dwCurProcID) {
  622. HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID);
  623. if (hProc == NULL) {
  624. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("find duplicated process: %s, id: %d", pNames[i], pe.th32ProcessID);
  625. return false;
  626. }
  627. if (!SpTerminateProcess(hProc, pe.th32ProcessID)) {
  628. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("terminate duplicated process %s fail, id: %d, error: %d",
  629. pNames[i], pe.th32ProcessID, GetLastError());
  630. return false;
  631. }
  632. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("terminate duplicated process: %s, id: %d", pNames[i], pe.th32ProcessID);
  633. }
  634. }
  635. } while (Process32Next(hSnapshot, &pe));
  636. }
  637. } else
  638. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("DetectDuplicateInstance can not enter Process32First!");
  639. return true;
  640. }
  641. #endif //_MSC_VER
  642. void SPBASE_API __stdcall setCurEntityIdx(int idx);
  643. std::string generateCenterSettingPath()
  644. {
  645. char pathbuf[1024] = "";
  646. int pathlen = ::GetModuleFileNameA(NULL, pathbuf, 1024);//获得GuiConsole路径
  647. // 替换掉单杠
  648. int times = 0;
  649. while (pathlen > 0) {
  650. if (pathbuf[pathlen--] == SPLIT_SLASH)
  651. times++;
  652. if (2 == times)
  653. break;
  654. }
  655. pathbuf[++pathlen] = '\0';
  656. std::string dstPath = pathbuf;
  657. dstPath.append(SPLIT_SLASH_STR "cfg" SPLIT_SLASH_STR "CenterSetting.ini");
  658. return dstPath;
  659. }
  660. int main(int argc, char** argv)
  661. {
  662. sp_cfg_start_args_t* args = DealWithArgs(argc, argv);
  663. #if defined(RVC_OS_LINUX)
  664. if (args->debug_mode) {
  665. SP::Perf::LeakDetector leakInstance;
  666. WLog_initRVC("SpShell");
  667. }
  668. #else
  669. //WLog_initRVC("SpShell");
  670. _CrtSetDebugFillThreshold(0);
  671. #endif //RVC_OS_LINUX
  672. #ifdef RVC_SAVEFILE
  673. bool saveFile = true;
  674. #else
  675. char tmp[MAX_LEN] = "";
  676. bool saveFile = false;
  677. if (Error_Succeed == sp_tryReadFromCenterSetting("Common", "SaveFile", tmp, MAX_LEN) && 0 == CSimpleStringA(tmp).Compare("1"))
  678. saveFile = true;
  679. #endif // RVC_SAVEFILE
  680. if (saveFile)
  681. sp_dbg_init("SpShell", 1);
  682. else
  683. sp_dbg_init("SpShell", 0);
  684. EntityResource::setSaveFile(saveFile);
  685. #if defined(RVC_OS_LINUX)
  686. sp_dbg_set_level(XLOG_LEVEL_DEBUG);
  687. #endif //RVC_OS_LINUX
  688. if (argc > 1) {
  689. std::string args_str;
  690. char cmdline[1024] = { '\0' };
  691. for (int i = 0; i < argc; ++i) {
  692. sprintf_s(cmdline, 1024, "%s", argv[i]);
  693. if (i != 0) args_str += " ";
  694. args_str += cmdline;
  695. }
  696. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("prefix: %s", args_str.c_str());
  697. }
  698. #if defined(_MSC_VER)
  699. auto centersettingPath = generateCenterSettingPath();
  700. load_debugLevelInCentersetting(centersettingPath.c_str());
  701. load_specialRunInfoInCentersetting(centersettingPath.c_str());
  702. auto setAffinity = [](long ulCpuMask) {
  703. HANDLE hCurrentProc;
  704. DWORD_PTR dwpProcAffinityMask = ulCpuMask;
  705. // Obtain a usable handle of the current process
  706. hCurrentProc = GetCurrentProcess();
  707. // Get the old affinity mask
  708. SetProcessAffinityMask(hCurrentProc, dwpProcAffinityMask);
  709. SetProcessAffinityUpdateMode(hCurrentProc, PROCESS_AFFINITY_ENABLE_AUTO_UPDATE);
  710. CloseHandle(hCurrentProc);
  711. };
  712. setAffinity(1);
  713. char* arrProcName[] = { "SpShell.exe", "SpHost.exe", "SpHost_re.exe" };
  714. //实际可以加快这个过程,如果进程过多会比较慢
  715. //后续可考虑用mutex进行控制
  716. if (!DetectDuplicateInstance(&arrProcName[0], sizeof(arrProcName) / sizeof(arrProcName[0]))) {
  717. DbgWithLink(LOG_LEVEL_FATAL, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__).setResultMsg(RTAERR_SPSHELL_REPEATPROCESS)("检测到重复spshell/sphost进程,系统启动失败!!!");
  718. Sleep(10000);
  719. return -200;
  720. }
  721. #else
  722. if (!!g_restartMode) {
  723. /** 因为没有明显的提示,等的时间(次数)不宜过长 [Gifur@202475]*/
  724. /*
  725. 阶段一:框架收到退出事件后会调用实体的stop接口,具体实现在app.cpp::stop_all_stated_entity
  726. 阶段二:框架会温和杀死实体相关进程
  727. 阶段三:框架会强制杀死实体相关进程
  728. */
  729. const DWORD eachPreTimeout = 500;//等待进程自行退出的每次等待间隔时间
  730. const int maxPreTimies = 6;//等待进程自行退出的最大等待次数
  731. const DWORD eachTimeout = 2000;//杀死进程后的每次等待间隔时间
  732. const int maxTimes = 15;//杀死进程后的最大等待次数
  733. const int gentleKillThresholdTimes = 10; //允许温和杀死实体进程的次数
  734. const DWORD skipInterval = 5;
  735. int currTimes = 0, preTimes = 0;
  736. bool needWait = (g_restartMode > RESTART_MODE_NORMAL && !g_immediately); //Rwait 框架触发的重启
  737. const bool needlessRestart = !NeedToRestartFramework();
  738. int aliveCount = 0, lastAliveCount(1000);
  739. char** relates = relate_processes;
  740. int reletes_cnt = relate_processes_count;
  741. if (needWait) {
  742. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("等待应用进程退出...");
  743. }
  744. if (needlessRestart) {
  745. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("to shutdown guardian...");
  746. char* tmp_processes[] = { guardian_execute_name };
  747. osutil_terminate_related_process(tmp_processes, array_size(tmp_processes), 1);
  748. relates = relate_processes_ex;
  749. reletes_cnt = relate_processes_ex_count;
  750. }
  751. bool switch_flag = false;
  752. while (switch_flag || !osutil_detect_unique_app(relates, reletes_cnt, &aliveCount, NULL)) {
  753. if (!needWait && currTimes++ >= maxTimes) {
  754. DbgWithLink(LOG_LEVEL_FATAL, LOG_TYPE_SYSTEM)("detect ex-spshell or sphost process, abort cur boot !!!");
  755. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("等待应用进程退出超时,请尝试重启机器!");
  756. sp_dbg_term();
  757. DestroyArgs(args);
  758. return -200;
  759. } else {
  760. if (needWait) {
  761. Sleep(eachPreTimeout);
  762. if (preTimes++ >= maxPreTimies && (aliveCount >= lastAliveCount)) {
  763. needWait = false;
  764. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("set need wait flag false");
  765. }
  766. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("wait... last active process count:%d, curr process count: %d, ppid: %d", lastAliveCount, aliveCount, GetParentProcessID());
  767. lastAliveCount = aliveCount;
  768. } else {
  769. const int force_flag = gentleKillThresholdTimes < currTimes ? 1 : 0;
  770. DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM)("detect ex-spshell or sphost process %d, %d, %d terminate all !!!", preTimes, currTimes, force_flag);
  771. osutil_terminate_related_process(relates, reletes_cnt, force_flag);
  772. Sleep(eachTimeout);
  773. }
  774. const DWORD consumedTime = (currTimes * eachTimeout) / 1000 + (eachPreTimeout * preTimes) / 1000;
  775. if (consumedTime > 0) {
  776. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("等待应用进程退出,已等待 %d 秒...", consumedTime);
  777. }
  778. }
  779. //aliveCount = 0; //important!!!
  780. switch_flag = (((preTimes + currTimes) % skipInterval) != 0);
  781. if (!switch_flag) {
  782. aliveCount = 0;
  783. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("will enter osutil_detect_unique_app");
  784. }
  785. }
  786. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("finish detecting unique app.");
  787. if (needlessRestart) {
  788. const DWORD sleepMillsecs = 2000;
  789. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("restart mode: %d", g_restartMode);
  790. if (g_restartMode == RESTART_MODE_SHUTDOWN) {
  791. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("应用进程已完全清理,退出当前窗口...");
  792. } else if (g_restartMode == RESTART_MODE_POWEROFF) {
  793. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("应用进程已完全清理,准备关机...");
  794. osutil_shutdown_system();
  795. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("应用进程已完全清理,正在关机...");
  796. } else if (g_restartMode == RESTART_MODE_REBOOT) {
  797. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("应用进程已完全清理,准备关机重启...");
  798. osutil_restart_system();
  799. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("应用进程已完全清理,正在关机并重启...");
  800. }
  801. Sleep(sleepMillsecs);
  802. sp_dbg_term();
  803. DestroyArgs(args);
  804. return 0;
  805. }
  806. } else if (!osutil_detect_unique_app(relate_processes, array_size(relate_processes), NULL, NULL)) {
  807. do {
  808. bool clearTotal = false;
  809. int innerClearEnhance = 0;
  810. do
  811. {
  812. osutil_terminate_related_process(relate_processes, array_size(relate_processes), innerClearEnhance > 8 ? 1 : 0);
  813. Sleep(3000);
  814. int count = MAX_ALIVE_PROCESS_COUNT;
  815. alive_process_info processes[MAX_ALIVE_PROCESS_COUNT];
  816. memset(processes, 0, sizeof(processes));
  817. if (osutil_detect_unique_app(relate_processes, array_size(relate_processes), &count, processes)) {
  818. clearTotal = true;
  819. break;
  820. }
  821. } while (innerClearEnhance++ < 10);
  822. if (clearTotal) {
  823. break;
  824. }
  825. DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM)("clear ex-spshell/sphost process failed!");
  826. sp_dbg_term();
  827. DestroyArgs(args);
  828. return -200;
  829. } while (false);
  830. }
  831. #endif //_MSC_VER
  832. sp_runtask_loadLogLevel();
  833. sp_tryquickStartCef();
  834. create_log_producer_default("SpShell", 0);
  835. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("===================SpShell start=====================");
  836. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("process id: %d, saveFile:%d", GetCurrentProcessId(), saveFile);
  837. if (argc > 1) {
  838. std::string args_str;
  839. char cmdline[1024] = { '\0' };
  840. for (int i = 0; i < argc; ++i) {
  841. sprintf_s(cmdline, 1024, "%s", argv[i]);
  842. if (i != 0) args_str += " ";
  843. args_str += cmdline;
  844. }
  845. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)(args_str.c_str());
  846. SP_TRACE(args_str.c_str());
  847. }
  848. if (!IsProcessRunAsAdmin()) {
  849. if (args->root) {
  850. DbgWithLink(LOG_LEVEL_FATAL, LOG_TYPE_SYSTEM)("current process need run with administrator or root privilege !!!");
  851. DbgWithLink(LOG_LEVEL_FATAL, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__).setResultMsg(RTAERR_SPSHELL_NOPRIVILEGE)("需要以管理员权限运行!!!");
  852. Sleep(10000);
  853. sp_dbg_term();
  854. DestroyArgs(args);
  855. return -201;
  856. } else {
  857. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("current process requires normal privilege.");
  858. }
  859. } else {
  860. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("current process has been run with administrator or root privilege.");
  861. args->root = (char)1;
  862. #if defined(_MSC_VER)
  863. SYSTEM_INFO SystemInfo;
  864. GetSystemInfo(&SystemInfo);
  865. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("当前以管理员权限运行, curProcessId:%d, curVersion:%s ,dwNumberOfProcessors=%u, dwActiveProcessorMask=%u, wProcessorLevel=%u, wProcessorArchitecture=%u, dwPageSize=%u",
  866. GetCurrentProcessId(), STRFILEVER, SystemInfo.dwNumberOfProcessors, SystemInfo.dwActiveProcessorMask, SystemInfo.wProcessorLevel,
  867. SystemInfo.wProcessorArchitecture, SystemInfo.dwPageSize);
  868. #endif //_MSC_VER
  869. }
  870. #ifdef RVC_OS_WIN
  871. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("Config firewall policies......");
  872. // 设置防火墙注册表配置
  873. AddFirewallRulesEx();
  874. setlocale(LC_ALL, "chs");
  875. #else
  876. if (NULL == setlocale(LC_ALL, "zh_CN.UTF-8")) {
  877. //zh_CN.UTF-8 zh_CN.GBK
  878. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM)("setlocale failed: %s", strerror(errno));
  879. }
  880. #endif //RVC_OS_WIN
  881. ResetEnvPath();
  882. #ifdef RVC_OS_WIN
  883. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("Config working set......");
  884. SetWorkingSet();//获取设置内存使用率,4G
  885. #endif //RVC_OS_WIN
  886. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("basic config success");
  887. #ifdef RVC_OS_WIN
  888. // 检测是否Win8及64位
  889. OSVERSIONINFO ver = {};
  890. ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  891. GetVersionEx(&ver);
  892. bool bWin8 = (ver.dwMajorVersion >= 7 || (ver.dwMajorVersion == 6 && ver.dwMinorVersion >= 2)); //version over 7 or over 6.2
  893. SYSTEM_INFO sysInfo = {};
  894. GetNativeSystemInfo(&sysInfo);
  895. bool bX64 = (sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64);
  896. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("OS version: %s %d.%d.%d , SetErrorMode %s", bX64 ? "windows 64" : "windows 32", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber,
  897. 0 == SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX) ? "success" : "failed");
  898. SetUnhandledExceptionFilter(&SuppressError);
  899. #endif //RVC_OS_WIN
  900. auto msg_lamda_func = [&](const char* msg, bool ctritial)->void {
  901. };
  902. //////////////////////////////////////////////////////////////////////////
  903. #if defined(_MSC_VER)
  904. auto rc = app_init(args);
  905. int result = rc.first;
  906. #else
  907. int result = app_init(args, msg_lamda_func);
  908. #endif //_MSC_VER
  909. //////////////////////////////////////////////////////////////////////////
  910. if (result == 0)
  911. {
  912. sp_trace_term();
  913. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("run circle loop in main thread!!");
  914. result = app_run();
  915. app_term();
  916. }
  917. else
  918. {
  919. uint32_t waitIntervals = 10000;
  920. if (sp_trace_exist()) {
  921. char* last_err = NULL;
  922. sp_trace_retrieve(&last_err, NULL);
  923. if (last_err) {
  924. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("to show last error dialog...");
  925. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM)("应用启动失败:%s", last_err);
  926. waitIntervals = 1;
  927. FREE(last_err);
  928. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("to show last error dialog done!");
  929. }
  930. sp_trace_term();
  931. }
  932. #if defined(_MSC_VER)
  933. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("======================================================");
  934. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__).setResultMsg(RTAERR_SPSHELL_APPINITERR)(rc.second.GetData());
  935. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("!!!!!! 启动失败,请检查dbg\\spshell日志排除故障 !!!!!!");
  936. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("======================================================");
  937. #else
  938. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("======================================================");
  939. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__).setResultMsg(RTAERR_SPSHELL_APPINITERR)("!!!!!! Startup failed, get more detail information from dbg/spshell !!!!!!");
  940. DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("======================================================");
  941. #endif //_MSC_VER
  942. app_upload_last_log();
  943. Sleep(waitIntervals);
  944. }
  945. #ifdef RVC_OS_WIN
  946. if (bWin8 && !bX64) {
  947. EnableCharmbar();
  948. }
  949. #endif //RVC_OS_WIN
  950. sp_dbg_term();
  951. DestroyArgs(args);
  952. return result;
  953. }
  954. #ifdef RVC_OS_WIN
  955. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
  956. {
  957. return main(__argc, __argv);
  958. }
  959. #endif //RVC_OS_WIN