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