spshell.cpp 35 KB

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