mod_UpgradeMgr.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. #include "stdafx.h"
  2. #include "mod_UpgradeMgr.h"
  3. #include "..\mod_UpgradeRun\UpgradeRun_client_g.h"
  4. using namespace UpgradeRun;
  5. #include "..\mod_download\Download_client_g.h"
  6. using namespace Download;
  7. #include "..\mod_accessauth\AccessAuthorization_client_g.h"
  8. using namespace AccessAuthorization;
  9. #include "LocalMediaPlay_client_g.h"
  10. //using namespace LocalMediaPlay;
  11. #include "EventCode.h"
  12. #include "md5file.h"
  13. #include <io.h>
  14. #include "fileutil.h"
  15. #include <regex>
  16. // 升级管理 UpgradeManager 0x506
  17. void CUpgradeMgrEntity::OnStarted()
  18. {
  19. // 初始化状态机
  20. m_fsm.Init(this);
  21. auto pFunc = GetFunction();
  22. CUUID subID;
  23. auto rc = pFunc->SubscribeBroadcast("UpgradeRun", NULL, this, subID);
  24. if (rc != Error_Succeed)
  25. {
  26. LogError(Severity_Middle, rc, 0, "subscribe entity [UpgradeRun] broadcast msg fail");
  27. //return;
  28. }
  29. //// 监视准入状态
  30. //CSimpleStringA strValue;
  31. //if (pFunc->GetSysVar("EntryPermit", strValue) == Error_Succeed && strValue.Compare("L") ==0)
  32. //{
  33. // // 已经进入准入状态
  34. // m_fsm.PostEventFIFO(new FSMEvent(CUpgradeMgrFSM::Event_EntryPermit));
  35. //}
  36. //else
  37. //{
  38. // rc= pFunc->RegistSysVarEvent("EntryPermit", this);
  39. // assert(rc == Error_Succeed);
  40. //}
  41. //zl@20190311 每次启动时生成新的MD5List
  42. rc = GetMD5List(m_strMD5List);
  43. if (rc != Error_Succeed)
  44. {
  45. LogError(Severity_Middle, rc, 0, "GetMD5List fail");
  46. }
  47. else
  48. {
  49. Dbg("get MD5 list success, len=%d", m_strMD5List.GetLength());
  50. }
  51. // 由于准入未上线或可能不稳定,为了保持升级服务的可用性,一直保持可升级状态
  52. m_fsm.PostEventFIFO(new FSMEvent(CUpgradeMgrFSM::Event_EntryPermit));
  53. }
  54. void CUpgradeMgrEntity::OnPreClose(EntityCloseCauseEnum eCloseCause,CSmartPointer<ITransactionContext> pTransactionContext)
  55. {
  56. GetFunction()->UnsubscribeBroadcast("Download");
  57. GetFunction()->UnsubscribeBroadcast("UpgradeRun");
  58. pTransactionContext->SendAnswer(Error_Succeed);
  59. }
  60. void CUpgradeMgrEntity::OnSysVarEvent(const char *pszKey, const char *pszValue,const char *pszOldValue,const char *pszEntityName)
  61. {
  62. if (strcmp(pszKey, "EntryPermit") ==0)
  63. {
  64. if (strcmp(pszValue, "L") ==0)
  65. {
  66. // 准入成功
  67. m_fsm.PostEventFIFO(new FSMEvent(CUpgradeMgrFSM::Event_EntryPermit));
  68. // 取消监视
  69. this->GetFunction()->UnregistSysVarEvent("EntryPermit");
  70. }
  71. }
  72. }
  73. void CUpgradeMgrEntity::OnDownloadEvent(const char *pszEntityName, DWORD dwMessageId, DWORD dwMessageSignature, Download::DownloadResult &evt)
  74. {
  75. Dbg("OnDownloadEvent, file:%s, result:%d, errMsg:%s", (const char*)evt.strFileName, evt.errorCode, (const char*)evt.errorMsg);
  76. m_fsm.PostEventFIFO(new CUpgradeMgrFSM::DownloadedEvent(evt.strFileName, evt.errorCode, evt.errorMsg));
  77. }
  78. void CUpgradeMgrEntity::OnUpgradeCheckEvent(const char *pszEntityName, DWORD dwMessageId, DWORD dwMessageSignature, UpgradeRun::UpgradeCheckEvent &evt)
  79. {
  80. Dbg("OnUpgradeCheckEvent, pack:%s, result:%d, errMsg:%s", (const char*)evt.strPackName, evt.error, (const char*)evt.strComment);
  81. auto pEvent = new CUpgradeMgrFSM::UpgradeRunCheckEvent(evt.strPackName, evt.error, evt.coverList, evt.strComment);
  82. m_fsm.PostEventFIFO(pEvent);
  83. }
  84. void CUpgradeMgrEntity::OnUpgradeDoneEvent(const char *pszEntityName, DWORD dwMessageId, DWORD dwMessageSignature, UpgradeRun::UpgradeDoneEvent &evt)
  85. {
  86. Dbg("OnUpgradeDoneEvent, pack:%s, result:%d, errMsg:%s", (const char*)evt.strPackName, evt.error, (const char*)evt.strComment);
  87. auto pEvent = new CUpgradeMgrFSM::UpgradeRunDoneEvent(evt.strPackName, evt.error, evt.bSysInstall, evt.bLightPack, evt.strNewVersion, evt.strFWID, evt.strSysPatchName,evt.strComment);
  88. m_fsm.PostEventFIFO(pEvent);
  89. //add by zl 20190221
  90. // 终端置为非升级状态。1:升级状态,0:非升级状态。处于升级状态时调用播放接口不生效
  91. auto rc = GetFunction()->SetSysVar("UpdateState", "0", true);
  92. assert(rc == Error_Succeed);
  93. }
  94. char CUpgradeMgrEntity::GetInstallStateVal(const InstallStateEnum enumVal)
  95. {
  96. const struct {
  97. int ch;
  98. InstallStateEnum val;
  99. } tbl[] = {
  100. {'A', Install_Active},
  101. {'I', Install_Pending},
  102. {'S', Install_SetToStart},
  103. {'F', Install_FailRun},
  104. {'R', Install_RollBack},
  105. {'U', Install_Upgraded},
  106. {'C',Install_Cancelled},
  107. {'W',Install_WaitConfirm},
  108. {'D', Install_Installed},
  109. };
  110. int i;
  111. for (i = 0; i < sizeof(tbl)/sizeof(tbl[0]); ++i) {
  112. if (tbl[i].val == enumVal) {
  113. return tbl[i].ch;
  114. }
  115. }
  116. return ' '; // error
  117. }
  118. ErrorCodeEnum CUpgradeMgrEntity::RegistLocalPack(const CSimpleStringA &strPackFile)
  119. {
  120. // 手动拷贝升级包,本地升级
  121. return m_fsm.RegistLocalPack(strPackFile);
  122. }
  123. DWORD CUpgradeMgrEntity::RegistManualPack(const CSimpleStringA &strPackFile)
  124. {
  125. // 用户桌面手动升级
  126. return m_fsm.RegistManualPack(strPackFile);
  127. }
  128. ErrorCodeEnum CUpgradeMgrEntity::DownloadPack(const CSimpleStringA &strPackFile)
  129. {
  130. // 通知下载实体准备下载
  131. auto pClient = new DownloadService_ClientBase(this);
  132. auto rc = pClient->Connect();
  133. if (rc == Error_Succeed)
  134. {
  135. DownloadService_DownloadFile_Req req = {};
  136. DownloadService_DownloadFile_Ans ans = {};
  137. req.strFileName = strPackFile;
  138. req.dwExpireTime = CSmallDateTime::GetNow() + 3600 * 24 * 14;
  139. rc = pClient->DownloadFile(req, ans, 5000);
  140. pClient->GetFunction()->CloseSession();
  141. }
  142. else
  143. {
  144. Dbg("connect to download entity fail: %d", rc);
  145. }
  146. pClient->SafeDelete();
  147. return rc;
  148. }
  149. ErrorCodeEnum CUpgradeMgrEntity::CancelDownloadPack(const CSimpleStringA &strPackFile)
  150. {
  151. // 通知下载实体准备下载
  152. auto pClient = new DownloadService_ClientBase(this);
  153. auto rc = pClient->Connect();
  154. if (rc == Error_Succeed)
  155. {
  156. DownloadService_CancelDownloadFile_Req req = {};
  157. DownloadService_CancelDownloadFile_Ans ans = {};
  158. req.strFileName = strPackFile;
  159. rc = pClient->CancelDownloadFile(req, ans, 5000);
  160. pClient->GetFunction()->CloseSession();
  161. }
  162. else
  163. {
  164. Dbg("connect to download entity fail: %d", rc);
  165. }
  166. pClient->SafeDelete();
  167. return rc;
  168. }
  169. ErrorCodeEnum CUpgradeMgrEntity::CancelUpdate(const CSimpleStringA &strPackFile)
  170. {
  171. // 取消安装
  172. m_fsm.PushCancelUpgradePack(strPackFile);
  173. return Error_Succeed;
  174. }
  175. ErrorCodeEnum CUpgradeMgrEntity::RollbackUpdate(const CSimpleStringA &strVersion)
  176. {
  177. // 调用框架接口回滚升级
  178. auto pFunc = GetFunction()->GetPrivilegeFunction();
  179. assert(pFunc != NULL);
  180. auto rc = Error_Succeed;
  181. if (strVersion.GetLength() == 0)
  182. {
  183. Dbg("try rollback to previous version");
  184. rc = pFunc->RollBackToPreviousVersion();
  185. }
  186. else
  187. {
  188. Dbg("try rollback to version: [%s]", (const char*)strVersion);
  189. int w1, w2, w3, w4;
  190. int rc = sscanf(strVersion, "%d.%d.%d.%d", &w1, &w2, &w3, &w4);
  191. if (rc <4)
  192. {
  193. Dbg("version [%s] parse fail", (const char*)strVersion);
  194. rc= Error_Param;
  195. }
  196. else
  197. {
  198. rc = pFunc->RollBackToHistoryVersion(CVersion(w1, w2, w3, w4));
  199. }
  200. }
  201. if (rc == Error_Succeed)
  202. {
  203. // 通过事件通知健康实体
  204. LogEvent(Severity_Middle, Event_Req_Framework_Rollback, "rollback upgrade succeed");
  205. ////更新安装失败包信息(包名和失败次数)
  206. //UpdatePackFailInfo();
  207. }
  208. else
  209. {
  210. LogError(Severity_Low, rc, 0, "rollback upgrade fail");
  211. }
  212. return rc;
  213. }
  214. DWORD CUpgradeMgrEntity::GetManualPacks(CSimpleStringA &strManualPacks)
  215. {
  216. return m_fsm.GetManualPacks(strManualPacks);
  217. }
  218. ErrorCodeEnum CUpgradeMgrEntity::SyncTime()
  219. {
  220. // 通知准入实体同步时间
  221. AccessAuthService_ClientBase *pClient = new AccessAuthService_ClientBase(this);
  222. auto rc = pClient->Connect();
  223. if (rc == Error_Succeed)
  224. {
  225. Dbg("connect to entity [AccessAuthorization] succeed, start syncTime now");
  226. rc = pClient->SyncTime();
  227. pClient->GetFunction()->CloseSession();
  228. }
  229. else
  230. {
  231. LogError(Severity_Low, rc, 0, "connect to entity [AccessAuthorization] fail");
  232. }
  233. pClient->SafeDelete();
  234. return rc;
  235. }
  236. // 将升级任务推送到运行实体
  237. ErrorCodeEnum CUpgradeMgrEntity::PushUpdateTask(const CSimpleStringA &strPackName, const int nPackType)
  238. //ErrorCodeEnum CUpgradeMgrEntity::PushUpdateTask(const CSimpleStringA &strPackName)
  239. {
  240. auto pClient = new UpgradeRunService_ClientBase(this);
  241. auto rc = pClient->Connect();
  242. if (rc == Error_Succeed)
  243. {
  244. UpgradeRunService_PushUpdateTask_Info info;
  245. info.strPackName = strPackName;
  246. info.nTaskType = nPackType;
  247. rc = pClient->PushUpdateTask(info);
  248. pClient->GetFunction()->CloseSession();
  249. }
  250. else
  251. {
  252. Dbg("connect to upgrade run entity fail: %d", rc);
  253. }
  254. pClient->SafeDelete();
  255. return rc;
  256. }
  257. CServerSessionBase* CUpgradeMgrEntity::OnNewSession(const char* /*pszRemoteEntityName*/, const char * /*pszParam*/)
  258. {
  259. return new CUpgradeMgrSession(this);
  260. }
  261. ErrorCodeEnum CUpgradeMgrEntity::SwitchUpgrade(const CSimpleStringA &strPack)
  262. {
  263. m_fsm.PostEventFIFO(new FSMEvent(CUpgradeMgrFSM::Event_SwitchNow));
  264. return Error_Succeed;
  265. }
  266. ErrorCodeEnum CUpgradeMgrEntity::GetUpgradeState(bool &bInstalling, CSimpleStringA &strPackFile, CSimpleStringA &strExecID,
  267. char &cInstallState, bool &bSysInstall, bool &bLightPack, CSimpleStringA &strNewVersion)
  268. {
  269. return m_fsm.GetUpgradeState(bInstalling, strPackFile, strExecID, cInstallState, bSysInstall, bLightPack, strNewVersion);
  270. }
  271. ErrorCodeEnum CUpgradeMgrEntity::MD5File(CSimpleStringA strFilePath, CSimpleStringA &strMD5)
  272. {
  273. char* pMd5 = MD5FILE::MD5_file((char*)strFilePath.GetData(), 32);
  274. if (NULL == pMd5)
  275. {
  276. Dbg("Get %s MD5 value fail");
  277. return Error_Unexpect;
  278. }
  279. strMD5 = pMd5;
  280. return Error_Succeed;
  281. }
  282. ErrorCodeEnum CUpgradeMgrEntity::MD5Data(CSimpleStringA strData, CSimpleStringA &strMD5)
  283. {
  284. char* pMd5 = MD5FILE::MD5_data((char*)strData.GetData(), 32);
  285. if (NULL == pMd5)
  286. {
  287. Dbg("Get %s MD5 value fail");
  288. return Error_Unexpect;
  289. }
  290. strMD5 = pMd5;
  291. return Error_Succeed;
  292. }
  293. ErrorCodeEnum CUpgradeMgrEntity::MD5Folder(CSimpleStringA strFolderPath,bool isDepDIr)
  294. {
  295. if (strFolderPath.IsNullOrEmpty())
  296. {
  297. return Error_Null;
  298. }
  299. Dbg("Start to get file hash list, dir=[%s] ", strFolderPath);
  300. _finddata_t FileInfo;
  301. CSimpleStringA strfind = strFolderPath + "\\*";
  302. long Handle = _findfirst(strfind, &FileInfo);
  303. if (-1L == Handle)
  304. {
  305. _findclose(Handle);
  306. Dbg("%s文件夹为空", strFolderPath);
  307. return Error_Succeed;
  308. }
  309. CSimpleStringA newPath;
  310. do{
  311. if (FileInfo.attrib & _A_SUBDIR)
  312. {
  313. if ((strcmp(FileInfo.name, ".") != 0) && (strcmp(FileInfo.name, "..") != 0))
  314. {
  315. CSimpleStringA strFindName = FileInfo.name;
  316. //整个黑名单文件夹过滤
  317. bool isBlackDir = false;
  318. list<CSimpleStringA>::iterator itor = m_fsm.m_DirBlacklist.begin();
  319. while(itor!=m_fsm.m_DirBlacklist.end())
  320. {
  321. CSimpleStringA dirBlack = *itor;
  322. if(strcmp(dirBlack.GetData(),FileInfo.name)==0){
  323. isBlackDir=true;
  324. break;
  325. }
  326. itor++;
  327. }
  328. if(isBlackDir){
  329. CSimpleStringA dirPath = strFolderPath + "\\" + FileInfo.name;
  330. Dbg("BlackDir Filter don't add to md5 list, dir=[%s]", dirPath.GetData());
  331. continue;//跳过文件夹
  332. }else{
  333. //判断是否是dep文件夹
  334. if(strcmp(FileInfo.name, "dep") == 0){
  335. newPath = strFolderPath + "\\" + FileInfo.name;
  336. MD5Folder(newPath,true);
  337. }else{
  338. newPath = strFolderPath + "\\" + FileInfo.name;
  339. MD5Folder(newPath);
  340. }
  341. }
  342. }
  343. }
  344. else
  345. {
  346. CSimpleStringA strFindName = FileInfo.name;
  347. {
  348. if (strFindName.IndexOf(".") == -1)
  349. {
  350. Dbg("%s file name is illegal", strFindName);
  351. continue;
  352. }
  353. //Dbg("计算hash码文件:%s",strFindName);
  354. //整体黑名单文件过滤
  355. bool isBlackFile = false;
  356. list<CSimpleStringA>::iterator itor = m_fsm.m_FileBlacklist.begin();
  357. while(itor!=m_fsm.m_FileBlacklist.end())
  358. {
  359. CSimpleStringA fileBlack = *itor;
  360. if(strFindName.IsEndWith(fileBlack.GetData(),true)){
  361. isBlackFile=true;
  362. break;
  363. }
  364. itor++;
  365. }
  366. if(isBlackFile){
  367. Dbg("BlackFile Filter don't add to md5 list, file = [%s]", strFindName.GetData());
  368. continue;
  369. }
  370. //对历史遗留的centerSetting错误缓存文件特殊处理,不纳入hash文件列表
  371. //对所有集中配置文件都过滤,规则是CenterSetting.*.ini*
  372. regex e("CenterSetting[.][^.]*[.]ini.*");
  373. if(std::regex_match(strFindName.GetData(),e,regex_constants::match_default)){
  374. continue;
  375. }
  376. /*if(strFindName.IndexOf("CenterSetting.")>-1&&strFindName.IndexOf(".ini")>-1){
  377. continue;
  378. }*/
  379. // 过滤install.ini,集中配置,log文件和cfg\certs目录
  380. // TODO:改成配置
  381. //if (strFindName.IsEndWith("install.ini", true)
  382. // || strFindName.IsEndWith("CenterSetting.DMZ.ini", true)
  383. // || strFindName.IsEndWith("CenterSetting.LAN.ini", true)
  384. // || strFindName.IsEndWith(".log", true)
  385. // || strFindName.IsEndWith("RootCert.pem", true)
  386. // || strFindName.IsEndWith("CaCert.pem", true)
  387. // || strFindName.IsEndWith("userCert.pem", true)
  388. // || strFindName.IsEndWith("CertBlackList.txt", true)
  389. // || strFindName.IsEndWith("idfront.jpg", true)
  390. // || strFindName.IsEndWith("idback.jpg", true))
  391. //{
  392. // Dbg("don't add %s to md5 list", strFindName);
  393. // continue;
  394. //}
  395. //判断是否需要用dep白名单过滤
  396. if(isDepDIr){
  397. bool isWhiteFile = false;
  398. list<CSimpleStringA>::iterator itor = m_fsm.m_DepWhitelist.begin();
  399. while(itor!=m_fsm.m_DepWhitelist.end())
  400. {
  401. CSimpleStringA fileWhite = *itor;
  402. if(strFindName.IsEndWith(fileWhite.GetData(),true)){
  403. isWhiteFile=true;
  404. break;
  405. }
  406. itor++;
  407. }
  408. //不是白名单也不是默认dll文件,不需要加入hash计算
  409. if(!isWhiteFile&&!strFindName.IsEndWith(".dll", true)){
  410. Dbg("WhiteFile Filter don't add to md5 list, file = [%s]", strFindName.GetData());
  411. continue;
  412. }
  413. }
  414. CSimpleStringA strFilePath = strFolderPath + "\\" + strFindName;
  415. CSimpleStringA strMD5Val;
  416. ErrorCodeEnum rErrcode = MD5File(strFilePath, strMD5Val);
  417. if (Error_Succeed != rErrcode)
  418. {
  419. Dbg("%s获取MD5失败,错误码:%d", strFilePath.GetData(), (int)rErrcode);
  420. return rErrcode;
  421. }
  422. m_FileHashMap[strFilePath] = strMD5Val;
  423. }
  424. }
  425. } while (_findnext(Handle, &FileInfo) == 0);
  426. _findclose(Handle);
  427. return Error_Succeed;
  428. }
  429. ErrorCodeEnum CUpgradeMgrEntity::GetMD5List(CSimpleStringA &strMD5List)
  430. {
  431. if (!m_strMD5List.IsNullOrEmpty())
  432. {
  433. strMD5List = m_strMD5List;
  434. return Error_Succeed;
  435. }
  436. m_FileHashMap.clear();//生成文件hash列表前先清空
  437. CSystemStaticInfo ssInfo;
  438. this->GetFunction()->GetSystemStaticInfo(ssInfo);
  439. CSimpleStringA curVer = ssInfo.InstallVersion.ToString();
  440. if (curVer.IsNullOrEmpty())
  441. {
  442. Dbg("InstallVersion is null");
  443. return Error_Null;
  444. }
  445. CSimpleStringA strRootVerPath;
  446. this->GetFunction()->GetPath("RootVer", strRootVerPath);
  447. Dbg("strRootVerPath %s,curVer:%s", strRootVerPath.GetData(),curVer.GetData());
  448. CSimpleStringA strCurVerPath = CSimpleStringA::Format("%s\\%s", (const char*)strRootVerPath, (const char*)curVer);
  449. if (!ExistsDirA(strCurVerPath))
  450. {
  451. Dbg("%d not exist", strCurVerPath);
  452. return Error_Unexpect;
  453. }
  454. ErrorCodeEnum rc = MD5Folder(strCurVerPath);
  455. if (Error_Succeed != rc)
  456. {
  457. return rc;
  458. }
  459. for(auto it=m_FileHashMap.begin(); it!=m_FileHashMap.end(); it++)
  460. {
  461. strMD5List += it->first;
  462. strMD5List += ",";
  463. strMD5List += it->second;
  464. strMD5List += ";";
  465. }
  466. m_strMD5List = strMD5List;
  467. return Error_Succeed;
  468. }
  469. ErrorCodeEnum CUpgradeMgrEntity::StopMediaPlay()
  470. {
  471. // 通知准入实体同步时间
  472. LocalMediaPlay::PlayService_ClientBase *pClient = new LocalMediaPlay::PlayService_ClientBase(this);
  473. auto rc = pClient->Connect();
  474. if (rc == Error_Succeed)
  475. {
  476. Dbg("connect to entity [LocalMediaPlay] succeed, start StopMediaPlay now");
  477. LocalMediaPlay::PlayService_StopPlayVideo_Req req1 = {};
  478. LocalMediaPlay::PlayService_StopPlayVideo_Ans ans1 = {};
  479. req1.CfgInx = 1;
  480. if (Error_Succeed == pClient->StopPlayVideo(req1, ans1, 5000))
  481. {
  482. Dbg("StopPlayVideo success");
  483. }
  484. LocalMediaPlay::PlayService_StopPlayAudio_Req req2 = {};
  485. LocalMediaPlay::PlayService_StopPlayAudio_Ans ans2 = {};
  486. if (Error_Succeed == pClient->StopPlayAudio(req2, ans2, 5000))
  487. {
  488. Dbg("StopPlayAudio success");
  489. }
  490. pClient->GetFunction()->CloseSession();
  491. }
  492. else
  493. {
  494. LogError(Severity_Low, rc, 0, "connect to entity [LocalMediaPlay] fail");
  495. }
  496. pClient->SafeDelete();
  497. return rc;
  498. }
  499. SP_BEGIN_ENTITY_MAP()
  500. SP_ENTITY(CUpgradeMgrEntity)
  501. SP_END_ENTITY_MAP()