Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

580 lines
16 KiB

  1. /******************************************************************************
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. SystemMonitor.cpp
  5. Abstract:
  6. This file contains the implementation of the CPCHSystemMonitor class,
  7. which implements the data collection functionality.
  8. Revision History:
  9. Davide Massarenti (Dmassare) 08/25/99
  10. created
  11. ******************************************************************************/
  12. #include "stdafx.h"
  13. #include <initguid.h>
  14. #include <mstask.h> // for task scheduler apis
  15. #include <msterr.h>
  16. /////////////////////////////////////////////////////////////////////////////
  17. static const ULONG INITIAL_RESCHEDULE_TIME = 10 * 60; // (10 minutes)
  18. static const ULONG DATACOLLECTION_RESCHEDULE_TIME = 6 * 60 * 60; // (6 hours)
  19. static const ULONG DATACOLLECTION_IDLE_TIME = 5; // (5 minutes)
  20. static const ULONG SECONDS_IN_A_DAY = 24 * 60 * 60;
  21. static const ULONG SECONDS_IN_A_MINUTE = 60;
  22. static const ULONG MINUTES_IN_A_DAY = 24 * 60;
  23. /////////////////////////////////////////////////////////////////////////////
  24. static HRESULT Exec( LPCWSTR szExec )
  25. {
  26. MPC::wstring strCmdLine( szExec ); MPC::SubstituteEnvVariables( strCmdLine );
  27. return MPC::ExecuteCommand( strCmdLine );
  28. }
  29. /////////////////////////////////////////////////////////////////////////////
  30. CPCHSystemMonitor::CPCHSystemMonitor()
  31. {
  32. __HCP_FUNC_ENTRY( "CPCHSystemMonitor::CPCHSystemMonitor" );
  33. m_fLoadCache = false; // bool m_fLoadCache;
  34. m_fScanBatch = true; // bool m_fScanBatch;
  35. m_fDataCollection = false; // bool m_fDataCollection;
  36. (void)MPC::_MPC_Module.RegisterCallback( this, (void (CPCHSystemMonitor::*)())Shutdown );
  37. }
  38. CPCHSystemMonitor::~CPCHSystemMonitor()
  39. {
  40. MPC::_MPC_Module.UnregisterCallback( this );
  41. Shutdown();
  42. }
  43. ////////////////////
  44. CPCHSystemMonitor* CPCHSystemMonitor::s_GLOBAL( NULL );
  45. HRESULT CPCHSystemMonitor::InitializeSystem()
  46. {
  47. if(s_GLOBAL == NULL)
  48. {
  49. s_GLOBAL = new CPCHSystemMonitor;
  50. }
  51. return s_GLOBAL ? S_OK : E_OUTOFMEMORY;
  52. }
  53. void CPCHSystemMonitor::FinalizeSystem()
  54. {
  55. if(s_GLOBAL)
  56. {
  57. delete s_GLOBAL; s_GLOBAL = NULL;
  58. }
  59. }
  60. ////////////////////
  61. void CPCHSystemMonitor::Shutdown()
  62. {
  63. Thread_Wait();
  64. }
  65. /////////////////////////////////////////////////////////////////////////////
  66. /////////////////////////////////////////////////////////////////////////////
  67. HRESULT CPCHSystemMonitor::EnsureStarted()
  68. {
  69. __HCP_FUNC_ENTRY( "CPCHSystemMonitor::EnsureStarted" );
  70. HRESULT hr;
  71. if(Thread_IsRunning() == false &&
  72. Thread_IsAborted() == false )
  73. {
  74. __MPC_EXIT_IF_METHOD_FAILS(hr, Thread_Start( this, Run, NULL ));
  75. }
  76. hr = S_OK;
  77. __HCP_FUNC_CLEANUP;
  78. __HCP_FUNC_EXIT(hr);
  79. }
  80. HRESULT CPCHSystemMonitor::Run()
  81. {
  82. __HCP_FUNC_ENTRY( "CPCHSystemMonitor::Run" );
  83. const DWORD s_dwNotify = FILE_NOTIFY_CHANGE_FILE_NAME |
  84. FILE_NOTIFY_CHANGE_DIR_NAME |
  85. FILE_NOTIFY_CHANGE_ATTRIBUTES |
  86. FILE_NOTIFY_CHANGE_SIZE |
  87. FILE_NOTIFY_CHANGE_CREATION;
  88. HRESULT hr;
  89. MPC::wstring strBatch( HC_ROOT_HELPSVC_BATCH ); MPC::SubstituteEnvVariables( strBatch );
  90. HANDLE hBatchNotification = INVALID_HANDLE_VALUE;
  91. DWORD dwTimeout = INFINITE;
  92. MPC::SmartLock<_ThreadModel> lock( this );
  93. ::SetThreadPriority( ::GetCurrentThread(), THREAD_PRIORITY_LOWEST ); ::Sleep( 0 ); // Yield processor...
  94. ////
  95. //// Don't touch task scheduler, it brings in too many things...
  96. ////
  97. //// //
  98. //// // Move forward the scheduled data collection by at least 10 minutes.
  99. //// // Task scheduler is available only on normal boots.
  100. //// //
  101. //// if(::GetSystemMetrics( SM_CLEANBOOT ) == 0)
  102. //// {
  103. //// __MPC_EXIT_IF_METHOD_FAILS(hr, TaskScheduler_Add( true ));
  104. //// }
  105. hBatchNotification = ::FindFirstChangeNotificationW( strBatch.c_str(), TRUE, s_dwNotify );
  106. while(Thread_IsAborted() == false)
  107. {
  108. DWORD dwRes;
  109. lock = NULL;
  110. __MPC_EXIT_IF_METHOD_FAILS(hr, RunLoop());
  111. lock = this;
  112. //
  113. // Done, for now...
  114. //
  115. lock = NULL;
  116. dwRes = Thread_WaitForEvents( hBatchNotification == INVALID_HANDLE_VALUE ? NULL : hBatchNotification, dwTimeout );
  117. lock = this;
  118. switch(dwRes)
  119. {
  120. case WAIT_OBJECT_0 :
  121. case WAIT_ABANDONED_0:
  122. break;
  123. case WAIT_OBJECT_0 + 1:
  124. case WAIT_ABANDONED_0 + 1:
  125. ::FindNextChangeNotification( hBatchNotification );
  126. dwTimeout = 1*1000; // Don't scan immediately, wait some time.
  127. break;
  128. case WAIT_TIMEOUT:
  129. dwTimeout = INFINITE;
  130. m_fScanBatch = true;
  131. break;
  132. case WAIT_FAILED:
  133. __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ::GetLastError());
  134. }
  135. }
  136. hr = S_OK;
  137. __HCP_FUNC_CLEANUP;
  138. if(hBatchNotification != INVALID_HANDLE_VALUE)
  139. {
  140. ::FindCloseChangeNotification( hBatchNotification );
  141. }
  142. Thread_Abort (); // To tell the MPC:Thread object to close the worker thread...
  143. Thread_Release(); // To tell the MPC:Thread object to clean up...
  144. __HCP_FUNC_EXIT(hr);
  145. }
  146. HRESULT CPCHSystemMonitor::RunLoop()
  147. {
  148. __HCP_FUNC_ENTRY( "CPCHSystemMonitor::RunLoop" );
  149. HRESULT hr;
  150. ////////////////////////////////////////////////////////////////////////////////
  151. //
  152. // Batch processing for the other update packages.
  153. //
  154. if(m_fScanBatch)
  155. {
  156. CComPtr<CPCHSetOfHelpTopics> sht;
  157. m_fScanBatch = false;
  158. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &sht ));
  159. __MPC_EXIT_IF_METHOD_FAILS(hr, sht->ScanBatch());
  160. }
  161. ////////////////////////////////////////////////////////////////////////////////
  162. //
  163. // Load the cache for active SKUs.
  164. //
  165. if(m_fLoadCache)
  166. {
  167. Taxonomy::LockingHandle handle;
  168. Taxonomy::InstalledInstanceIterConst itBegin;
  169. Taxonomy::InstalledInstanceIterConst itEnd;
  170. Taxonomy::InstalledInstanceIterConst it;
  171. m_fLoadCache = false;
  172. //
  173. // Get the list of SKU installed on the machine.
  174. //
  175. __MPC_EXIT_IF_METHOD_FAILS(hr, Taxonomy::InstalledInstanceStore::s_GLOBAL->GrabControl( handle ));
  176. __MPC_EXIT_IF_METHOD_FAILS(hr, Taxonomy::InstalledInstanceStore::s_GLOBAL->SKU_GetList( itBegin, itEnd ));
  177. //
  178. // Enumerate all of the SKUs, creating the index.
  179. //
  180. for(it = itBegin; it != itEnd; it++)
  181. {
  182. __MPC_EXIT_IF_METHOD_FAILS(hr, Taxonomy::Cache::s_GLOBAL->LoadIfMarked( it->m_inst.m_ths ));
  183. }
  184. }
  185. if(m_fDataCollection)
  186. {
  187. CComPtr<CSAFDataCollection> pdc;
  188. m_fDataCollection = false;
  189. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &pdc ));
  190. __MPC_EXIT_IF_METHOD_FAILS(hr, pdc->ExecScheduledCollection());
  191. __MPC_EXIT_IF_METHOD_FAILS(hr, TaskScheduler_Add( false ));
  192. }
  193. hr = S_OK;
  194. __HCP_FUNC_CLEANUP;
  195. __HCP_FUNC_EXIT(hr);
  196. }
  197. ////////////////////////////////////////////////////////////////////////////////
  198. HRESULT CPCHSystemMonitor::LoadCache()
  199. {
  200. __HCP_FUNC_ENTRY( "CPCHSystemMonitor::LoadCache" );
  201. HRESULT hr;
  202. MPC::SmartLock<_ThreadModel> lock( this );
  203. __MPC_EXIT_IF_METHOD_FAILS(hr, EnsureStarted());
  204. m_fLoadCache = true;
  205. Thread_Signal();
  206. hr = S_OK;
  207. __HCP_FUNC_CLEANUP;
  208. __HCP_FUNC_EXIT(hr);
  209. }
  210. HRESULT CPCHSystemMonitor::TriggerDataCollection( /*[in]*/ bool fStart )
  211. {
  212. __HCP_FUNC_ENTRY( "CPCHSystemMonitor::TriggerDataCollection" );
  213. HRESULT hr;
  214. MPC::SmartLock<_ThreadModel> lock( this );
  215. if(fStart)
  216. {
  217. __MPC_EXIT_IF_METHOD_FAILS(hr, EnsureStarted());
  218. m_fDataCollection = true;
  219. Thread_Signal();
  220. }
  221. else
  222. {
  223. m_fDataCollection = false;
  224. Thread_Signal();
  225. }
  226. hr = S_OK;
  227. __HCP_FUNC_CLEANUP;
  228. __HCP_FUNC_EXIT(hr);
  229. }
  230. /////////////////////////////////////////////////////////////////////////////
  231. HRESULT CPCHSystemMonitor::TaskScheduler_Add( /*[in]*/ bool fAfterBoot )
  232. {
  233. MPC::wstring strDate;
  234. if(SUCCEEDED(MPC::ConvertDateToString( MPC::GetLocalTime(), strDate, /*fGMT*/false, /*fCIM*/true, 0 )))
  235. {
  236. static const WCHAR s_szRoot [] = HC_REGISTRY_PCHSVC;
  237. static const WCHAR s_szDataCollection[] = L"DataCollection";
  238. (void)MPC::RegKey_Value_Write( strDate, s_szRoot, s_szDataCollection );
  239. }
  240. return S_OK;
  241. }
  242. HRESULT CPCHSystemMonitor::TaskScheduler_Remove()
  243. {
  244. return S_OK;
  245. }
  246. ////HRESULT CPCHSystemMonitor::TaskScheduler_Add( /*[in]*/ bool fAfterBoot )
  247. ////{
  248. //// __HCP_FUNC_ENTRY( "CPCHSystemMonitor::TaskScheduler_Add" );
  249. ////
  250. //// HRESULT hr;
  251. //// CComPtr<ITaskScheduler> pTaskScheduler;
  252. //// CComPtr<ITask> pTask;
  253. //// CComPtr<IUnknown> pTaskUnknown;
  254. //// CComPtr<IScheduledWorkItem> pScheduledWorkItem;
  255. //// bool fTaskExists = false;
  256. ////
  257. //// WCHAR rgFileName[MAX_PATH];
  258. //// CComBSTR bstrTaskName;
  259. //// CComBSTR bstrComments;
  260. ////
  261. //// ULONG ulTime = fAfterBoot ? INITIAL_RESCHEDULE_TIME : DATACOLLECTION_RESCHEDULE_TIME;
  262. //// WORD wIdle = DATACOLLECTION_IDLE_TIME;
  263. ////
  264. //// ////////////////////////////////////////
  265. ////
  266. //// //
  267. //// // Get our complete filename -- needed to create a task in the task scheduler.
  268. //// //
  269. //// __MPC_EXIT_IF_CALL_RETURNS_ZERO(hr, ::GetModuleFileNameW( NULL, rgFileName, MAX_PATH ));
  270. ////
  271. ////
  272. //// __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::LocalizeString( IDS_HELPSVC_TASKNAME , bstrTaskName ));
  273. //// __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::LocalizeString( IDS_HELPSVC_TASKCOMMENT, bstrComments ));
  274. ////
  275. //// //
  276. //// // First create the task scheduler.
  277. //// //
  278. //// __MPC_EXIT_IF_METHOD_FAILS(hr, ::CoCreateInstance( CLSID_CTaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskScheduler, (void**)&pTaskScheduler ));
  279. ////
  280. ////
  281. //// //
  282. //// // See if the task already exists in the task scheduler
  283. //// //
  284. //// if(SUCCEEDED(pTaskScheduler->Activate( bstrTaskName, IID_ITask, &pTaskUnknown )))
  285. //// {
  286. //// fTaskExists = true;
  287. ////
  288. //// __MPC_EXIT_IF_METHOD_FAILS(hr, pTaskUnknown->QueryInterface( IID_ITask, (void **)&pTask ));
  289. //// }
  290. //// else
  291. //// {
  292. //// //
  293. //// // Create a new task and set its app name and parameters.
  294. //// //
  295. //// if(FAILED(hr = pTaskScheduler->NewWorkItem( bstrTaskName, CLSID_CTask, IID_ITask, (IUnknown**)&pTask )))
  296. //// {
  297. //// if(hr != ERROR_FILE_EXISTS)
  298. //// {
  299. //// __MPC_TRACE_HRESULT(hr);
  300. //// __MPC_FUNC_LEAVE;
  301. //// }
  302. //// }
  303. //// }
  304. ////
  305. //// __MPC_EXIT_IF_METHOD_FAILS(hr, pTask->QueryInterface( IID_IScheduledWorkItem, (void **)&pScheduledWorkItem ));
  306. ////
  307. //// //
  308. //// // Run under SYSTEM.
  309. //// //
  310. //// __MPC_EXIT_IF_METHOD_FAILS(hr, pScheduledWorkItem->SetAccountInformation( L"", NULL ));
  311. ////
  312. //// __MPC_EXIT_IF_METHOD_FAILS(hr, pTask->SetApplicationName( CComBSTR( rgFileName ) ));
  313. //// __MPC_EXIT_IF_METHOD_FAILS(hr, pTask->SetParameters ( CComBSTR( L"-collect" ) ));
  314. ////
  315. //// // Set the comment, so we know how this job go there.
  316. //// __MPC_EXIT_IF_METHOD_FAILS(hr, pScheduledWorkItem->SetComment( bstrComments ));
  317. //// __MPC_EXIT_IF_METHOD_FAILS(hr, pScheduledWorkItem->SetFlags ( 0 ));
  318. ////
  319. ////
  320. ////
  321. ////
  322. //// // Now, fill in the trigger as necessary.
  323. //// {
  324. //// CComPtr<ITaskTrigger> pTaskTrigger;
  325. //// SYSTEMTIME stNow;
  326. //// DOUBLE dblNextScheduledTime;
  327. //// TASK_TRIGGER ttTaskTrig;
  328. ////
  329. ////
  330. //// ::ZeroMemory( &ttTaskTrig, sizeof(ttTaskTrig) );
  331. //// ttTaskTrig.cbTriggerSize = sizeof(ttTaskTrig);
  332. ////
  333. ////
  334. //// if(fTaskExists)
  335. //// {
  336. //// __MPC_EXIT_IF_METHOD_FAILS(hr, pScheduledWorkItem->GetTrigger( 0, &pTaskTrigger ));
  337. //// __MPC_EXIT_IF_METHOD_FAILS(hr, pTaskTrigger ->GetTrigger( &ttTaskTrig ));
  338. //// }
  339. //// else
  340. //// {
  341. //// WORD wTrigNumber;
  342. ////
  343. //// __MPC_EXIT_IF_METHOD_FAILS(hr, pScheduledWorkItem->CreateTrigger( &wTrigNumber, &pTaskTrigger ));
  344. //// }
  345. ////
  346. ////
  347. //// //
  348. //// // Calculate the exact time of next activation.
  349. //// //
  350. //// ::GetLocalTime ( &stNow );
  351. //// ::SystemTimeToVariantTime( &stNow, &dblNextScheduledTime );
  352. ////
  353. //// dblNextScheduledTime += (double)ulTime / SECONDS_IN_A_DAY;
  354. //// ::VariantTimeToSystemTime( dblNextScheduledTime, &stNow );
  355. ////
  356. ////
  357. //// ttTaskTrig.wBeginYear = stNow.wYear;
  358. //// ttTaskTrig.wBeginMonth = stNow.wMonth;
  359. //// ttTaskTrig.wBeginDay = stNow.wDay;
  360. //// ttTaskTrig.wStartHour = stNow.wHour;
  361. //// ttTaskTrig.wStartMinute = stNow.wMinute;
  362. ////
  363. //// ttTaskTrig.MinutesDuration = MINUTES_IN_A_DAY;
  364. //// ttTaskTrig.MinutesInterval = ulTime / SECONDS_IN_A_MINUTE;
  365. //// ttTaskTrig.TriggerType = TASK_TIME_TRIGGER_DAILY;
  366. ////
  367. //// ttTaskTrig.Type.Daily.DaysInterval = 1;
  368. ////
  369. //// if(wIdle)
  370. //// {
  371. //// __MPC_EXIT_IF_METHOD_FAILS(hr, pScheduledWorkItem->SetIdleWait( wIdle, 0x7FFF ));
  372. //// __MPC_EXIT_IF_METHOD_FAILS(hr, pScheduledWorkItem->SetFlags ( TASK_FLAG_START_ONLY_IF_IDLE ));
  373. //// }
  374. ////
  375. //// // Add this trigger to the task.
  376. //// __MPC_EXIT_IF_METHOD_FAILS(hr, pTaskTrigger->SetTrigger( &ttTaskTrig ));
  377. //// }
  378. ////
  379. //// //
  380. //// // Make the changes permanent.
  381. //// //
  382. //// {
  383. //// CComPtr<IPersistFile> pIPF;
  384. ////
  385. //// __MPC_EXIT_IF_METHOD_FAILS(hr, pTask->QueryInterface( IID_IPersistFile, (void **)&pIPF ));
  386. ////
  387. //// __MPC_EXIT_IF_METHOD_FAILS(hr, pIPF->Save( NULL, FALSE ));
  388. //// }
  389. ////
  390. ////
  391. //// hr = S_OK;
  392. ////
  393. ////
  394. //// __HCP_FUNC_CLEANUP;
  395. ////
  396. //// __HCP_FUNC_EXIT(hr);
  397. ////}
  398. ////
  399. ////HRESULT CPCHSystemMonitor::TaskScheduler_Remove()
  400. ////{
  401. //// __HCP_FUNC_ENTRY( "CPCHSystemMonitor::TaskScheduler_Remove" );
  402. ////
  403. //// HRESULT hr;
  404. //// CComPtr<ITaskScheduler> pTaskScheduler;
  405. //// CComBSTR bstrTaskName;
  406. ////
  407. ////
  408. //// ////////////////////////////////////////
  409. ////
  410. //// __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::LocalizeString( IDS_HELPSVC_TASKNAME, bstrTaskName ));
  411. ////
  412. //// //
  413. //// // First create the task scheduler.
  414. //// //
  415. //// __MPC_EXIT_IF_METHOD_FAILS(hr, ::CoCreateInstance( CLSID_CTaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskScheduler, (void**)&pTaskScheduler ));
  416. ////
  417. ////
  418. //// if(FAILED(hr = pTaskScheduler->Delete( bstrTaskName )))
  419. //// {
  420. //// if(hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
  421. //// {
  422. //// __MPC_TRACE_HRESULT(hr);
  423. //// __MPC_FUNC_LEAVE;
  424. //// }
  425. //// }
  426. ////
  427. ////
  428. //// hr = S_OK;
  429. ////
  430. ////
  431. //// __HCP_FUNC_CLEANUP;
  432. ////
  433. //// __HCP_FUNC_EXIT(hr);
  434. ////}
  435. ////////////////////////////////////////////////////////////////////////////////
  436. HRESULT CPCHSystemMonitor::Startup()
  437. {
  438. __HCP_FUNC_ENTRY( "CPCHSystemMonitor::Startup" );
  439. HRESULT hr;
  440. //
  441. // This forces the Content Store to be loaded.
  442. //
  443. __MPC_EXIT_IF_METHOD_FAILS(hr, CPCHContentStore::s_GLOBAL->Acquire());
  444. __MPC_EXIT_IF_METHOD_FAILS(hr, CPCHContentStore::s_GLOBAL->Release());
  445. ////////////////////////////////////////////////////////////////////////////////
  446. //
  447. // Force the loading of the cache.
  448. //
  449. {
  450. Taxonomy::LockingHandle handle;
  451. __MPC_EXIT_IF_METHOD_FAILS(hr, Taxonomy::InstalledInstanceStore::s_GLOBAL->GrabControl( handle ));
  452. }
  453. __MPC_EXIT_IF_METHOD_FAILS(hr, EnsureStarted());
  454. hr = S_OK;
  455. __HCP_FUNC_CLEANUP;
  456. __HCP_FUNC_EXIT(hr);
  457. }