Require re-Detect after Apply.
Sean Hall committed
Feb 2, 2021 at 16:57 UTC
39725a1a6d1c72a6748bd3c306af32bcae6dbf8f
7 files changed
+92
-7
src/engine/core.cpp
+46
-7
@@ -242,6 +242,13 @@ extern "C" HRESULT CoreDetect(
242
243
LogId(REPORT_STANDARD, MSG_DETECT_BEGIN, pEngineState->packages.cPackages);
244
245
+ // Always reset the detect state which means the plan should be reset too.
246
+ pEngineState->fDetected = FALSE;
247
+ pEngineState->fPlanned = FALSE;
248
+ pEngineState->fApplied = FALSE;
249
+ DetectReset(&pEngineState->registration, &pEngineState->packages);
250
+ PlanReset(&pEngineState->plan, &pEngineState->packages);
251
+
252
// Detect if bundle installed state has changed since start up. This
253
// only happens if Apply() changed the state of bundle (installed or
254
// uninstalled). In that case, Detect() can be used here to reset
@@ -266,10 +273,6 @@ extern "C" HRESULT CoreDetect(
273
274
pEngineState->userExperience.hwndDetect = hwndParent;
275
269
- // Always reset the detect state which means the plan should be reset too.
270
- DetectReset(&pEngineState->registration, &pEngineState->packages);
271
- PlanReset(&pEngineState->plan, &pEngineState->packages);
272
-
276
hr = SearchesExecute(&pEngineState->searches, &pEngineState->variables);
277
ExitOnFailure(hr, "Failed to execute searches.");
278
@@ -365,6 +368,11 @@ LExit:
368
hr = hrFirstPackageFailure;
369
}
370
371
+ if (SUCCEEDED(hr))
372
+ {
373
+ pEngineState->fDetected = TRUE;
374
+ }
375
+
376
if (fDetectBegan)
377
{
378
UserExperienceOnDetectComplete(&pEngineState->userExperience, hr);
@@ -388,6 +396,7 @@ extern "C" HRESULT CorePlan(
396
HANDLE hSyncpointEvent = NULL;
397
BURN_PACKAGE* pUpgradeBundlePackage = NULL;
398
BURN_PACKAGE* pForwardCompatibleBundlePackage = NULL;
399
+ BOOL fContinuePlanning = TRUE; // assume we won't skip planning due to dependencies.
400
401
LogId(REPORT_STANDARD, MSG_PLAN_BEGIN, pEngineState->packages.cPackages, LoggingBurnActionToString(action));
402
@@ -395,7 +404,17 @@ extern "C" HRESULT CorePlan(
404
hr = UserExperienceOnPlanBegin(&pEngineState->userExperience, pEngineState->packages.cPackages);
405
ExitOnRootFailure(hr, "BA aborted plan begin.");
406
407
+ if (!pEngineState->fDetected)
408
+ {
409
+ ExitOnFailure(hr = E_INVALIDSTATE, "Plan cannot be done without a successful Detect.");
410
+ }
411
+ else if (pEngineState->fApplied)
412
+ {
413
+ ExitOnFailure(hr = E_INVALIDSTATE, "Plan requires a new successful Detect after calling Apply.");
414
+ }
415
+
416
// Always reset the plan.
417
+ pEngineState->fPlanned = FALSE;
418
PlanReset(&pEngineState->plan, &pEngineState->packages);
419
420
// Remember the overall action state in the plan since it shapes the changes
@@ -447,7 +466,6 @@ extern "C" HRESULT CorePlan(
466
}
467
else // doing an action that modifies the machine state.
468
{
450
- BOOL fContinuePlanning = TRUE; // assume we'll be able to keep planning after registration.
469
pEngineState->plan.fPerMachine = pEngineState->registration.fPerMachine; // default the scope of the plan to the per-machine state of the bundle.
470
471
hr = PlanRegistration(&pEngineState->plan, &pEngineState->registration, pEngineState->command.resumeType, pEngineState->command.relationType, &fContinuePlanning);
@@ -477,12 +495,20 @@ extern "C" HRESULT CorePlan(
495
hr = PlanFinalizeActions(&pEngineState->plan);
496
ExitOnFailure(hr, "Failed to remove unnecessary actions from plan.");
497
480
- // Finally, display all packages and related bundles in the log.
481
- LogPackages(pUpgradeBundlePackage, pForwardCompatibleBundlePackage, &pEngineState->packages, &pEngineState->registration.relatedBundles, action);
498
+ if (fContinuePlanning)
499
+ {
500
+ // Finally, display all packages and related bundles in the log.
501
+ LogPackages(pUpgradeBundlePackage, pForwardCompatibleBundlePackage, &pEngineState->packages, &pEngineState->registration.relatedBundles, action);
502
+ }
503
504
PlanDump(&pEngineState->plan);
505
506
LExit:
507
+ if (SUCCEEDED(hr))
508
+ {
509
+ pEngineState->fPlanned = TRUE;
510
+ }
511
+
512
if (fPlanBegan)
513
{
514
UserExperienceOnPlanComplete(&pEngineState->userExperience, hr);
@@ -549,6 +575,15 @@ extern "C" HRESULT CoreApply(
575
576
LogId(REPORT_STANDARD, MSG_APPLY_BEGIN);
577
578
+ if (!pEngineState->fPlanned)
579
+ {
580
+ ExitOnFailure(hr = E_INVALIDSTATE, "Apply cannot be done without a successful Plan.");
581
+ }
582
+ else if (pEngineState->fApplied)
583
+ {
584
+ ExitOnFailure(hr = E_INVALIDSTATE, "Plans cannot be applied multiple times.");
585
+ }
586
+
587
// Ensure any previous attempts to execute are reset.
588
ApplyReset(&pEngineState->userExperience, &pEngineState->packages);
589
@@ -564,6 +599,8 @@ extern "C" HRESULT CoreApply(
599
hr = UserExperienceOnApplyBegin(&pEngineState->userExperience, dwPhaseCount);
600
ExitOnRootFailure(hr, "BA aborted apply begin.");
601
602
+ pEngineState->fApplied = TRUE;
603
+
604
// Abort if this bundle already requires a restart.
605
if (BOOTSTRAPPER_RESUME_TYPE_REBOOT_PENDING == pEngineState->command.resumeType)
606
{
@@ -758,6 +795,8 @@ extern "C" HRESULT CoreQuit(
795
796
LogId(REPORT_STANDARD, MSG_QUIT, nExitCode);
797
798
+ pEngineState->fQuit = TRUE;
799
+
800
::PostQuitMessage(nExitCode); // go bye-bye.
801
802
return hr;
src/engine/core.h
+4
@@ -78,6 +78,10 @@ enum BURN_AU_PAUSE_ACTION
78
typedef struct _BURN_ENGINE_STATE
79
{
80
// UX flow control
81
+ BOOL fDetected;
82
+ BOOL fPlanned;
83
+ BOOL fApplied;
84
+ BOOL fQuit;
85
//BOOL fSuspend; // Is TRUE when UX made Suspend() call on core.
86
//BOOL fForcedReboot; // Is TRUE when UX made Reboot() call on core.
87
//BOOL fCancelled; // Is TRUE when UX return cancel on UX OnXXX() methods.
src/engine/engine.cpp
+7
@@ -804,6 +804,12 @@ static HRESULT ProcessMessage(
804
805
UserExperienceActivateEngine(&pEngineState->userExperience);
806
807
+ if (pEngineState->fQuit)
808
+ {
809
+ LogId(REPORT_WARNING, MSG_IGNORE_OPERATION_AFTER_QUIT, LoggingBurnMessageToString(pmsg->message));
810
+ ExitFunction1(hr = E_INVALIDSTATE);
811
+ }
812
+
813
switch (pmsg->message)
814
{
815
case WM_BURN_DETECT:
@@ -831,6 +837,7 @@ static HRESULT ProcessMessage(
837
break;
838
}
839
840
+LExit:
841
UserExperienceDeactivateEngine(&pEngineState->userExperience);
842
843
return hr;
src/engine/engine.mc
+7
@@ -170,6 +170,13 @@ Language=English
170
Condition '%1!ls!' contains invalid version string '%2!ls!'.
171
.
172
173
+MessageId=58
174
+Severity=Warning
175
+SymbolicName=MSG_IGNORE_OPERATION_AFTER_QUIT
176
+Language=English
177
+Bootstrapper application already requested to quit, ignoring request: '%1!hs!'.
178
+.
179
+
180
MessageId=100
181
Severity=Success
182
SymbolicName=MSG_DETECT_BEGIN
src/engine/logging.cpp
+23
@@ -289,6 +289,29 @@ extern "C" LPCSTR LoggingBurnActionToString(
289
}
290
}
291
292
+LPCSTR LoggingBurnMessageToString(
293
+ __in UINT message
294
+ )
295
+{
296
+ switch (message)
297
+ {
298
+ case WM_BURN_APPLY:
299
+ return "Apply";
300
+ case WM_BURN_DETECT:
301
+ return "Detect";
302
+ case WM_BURN_ELEVATE:
303
+ return "Elevate";
304
+ case WM_BURN_LAUNCH_APPROVED_EXE:
305
+ return "LaunchApprovedExe";
306
+ case WM_BURN_PLAN:
307
+ return "Plan";
308
+ case WM_BURN_QUIT:
309
+ return "Quit";
310
+ default:
311
+ return "Invalid";
312
+ }
313
+}
314
+
315
extern "C" LPCSTR LoggingActionStateToString(
316
__in BOOTSTRAPPER_ACTION_STATE actionState
317
)
src/engine/logging.h
+4
@@ -65,6 +65,10 @@ LPCSTR LoggingBurnActionToString(
65
__in BOOTSTRAPPER_ACTION action
66
);
67
68
+LPCSTR LoggingBurnMessageToString(
69
+ __in UINT message
70
+ );
71
+
72
LPCSTR LoggingActionStateToString(
73
__in BOOTSTRAPPER_ACTION_STATE actionState
74
);
src/test/BurnUnitTest/PlanTest.cpp
+1
@@ -568,6 +568,7 @@ namespace Bootstrapper
568
NativeAssert::Succeeded(hr, "Failed to add the bundle provider key to the list of dependencies to ignore.");
569
570
pEngineState->userExperience.fEngineActive = TRUE;
571
+ pEngineState->fDetected = TRUE;
572
}
573
574
void DetectAttachedContainerAsAttached(BURN_ENGINE_STATE* pEngineState)