From 39725a1a6d1c72a6748bd3c306af32bcae6dbf8f Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Tue, 2 Feb 2021 16:57:33 -0600 Subject: Require re-Detect after Apply. --- src/engine/core.cpp | 53 +++++++++++++++++++++++++++++++++----- src/engine/core.h | 4 +++ src/engine/engine.cpp | 7 +++++ src/engine/engine.mc | 7 +++++ src/engine/logging.cpp | 23 +++++++++++++++++ src/engine/logging.h | 4 +++ src/test/BurnUnitTest/PlanTest.cpp | 1 + 7 files changed, 92 insertions(+), 7 deletions(-) diff --git a/src/engine/core.cpp b/src/engine/core.cpp index a644d377..a4c118a3 100644 --- a/src/engine/core.cpp +++ b/src/engine/core.cpp @@ -242,6 +242,13 @@ extern "C" HRESULT CoreDetect( LogId(REPORT_STANDARD, MSG_DETECT_BEGIN, pEngineState->packages.cPackages); + // Always reset the detect state which means the plan should be reset too. + pEngineState->fDetected = FALSE; + pEngineState->fPlanned = FALSE; + pEngineState->fApplied = FALSE; + DetectReset(&pEngineState->registration, &pEngineState->packages); + PlanReset(&pEngineState->plan, &pEngineState->packages); + // Detect if bundle installed state has changed since start up. This // only happens if Apply() changed the state of bundle (installed or // uninstalled). In that case, Detect() can be used here to reset @@ -266,10 +273,6 @@ extern "C" HRESULT CoreDetect( pEngineState->userExperience.hwndDetect = hwndParent; - // Always reset the detect state which means the plan should be reset too. - DetectReset(&pEngineState->registration, &pEngineState->packages); - PlanReset(&pEngineState->plan, &pEngineState->packages); - hr = SearchesExecute(&pEngineState->searches, &pEngineState->variables); ExitOnFailure(hr, "Failed to execute searches."); @@ -365,6 +368,11 @@ LExit: hr = hrFirstPackageFailure; } + if (SUCCEEDED(hr)) + { + pEngineState->fDetected = TRUE; + } + if (fDetectBegan) { UserExperienceOnDetectComplete(&pEngineState->userExperience, hr); @@ -388,6 +396,7 @@ extern "C" HRESULT CorePlan( HANDLE hSyncpointEvent = NULL; BURN_PACKAGE* pUpgradeBundlePackage = NULL; BURN_PACKAGE* pForwardCompatibleBundlePackage = NULL; + BOOL fContinuePlanning = TRUE; // assume we won't skip planning due to dependencies. LogId(REPORT_STANDARD, MSG_PLAN_BEGIN, pEngineState->packages.cPackages, LoggingBurnActionToString(action)); @@ -395,7 +404,17 @@ extern "C" HRESULT CorePlan( hr = UserExperienceOnPlanBegin(&pEngineState->userExperience, pEngineState->packages.cPackages); ExitOnRootFailure(hr, "BA aborted plan begin."); + if (!pEngineState->fDetected) + { + ExitOnFailure(hr = E_INVALIDSTATE, "Plan cannot be done without a successful Detect."); + } + else if (pEngineState->fApplied) + { + ExitOnFailure(hr = E_INVALIDSTATE, "Plan requires a new successful Detect after calling Apply."); + } + // Always reset the plan. + pEngineState->fPlanned = FALSE; PlanReset(&pEngineState->plan, &pEngineState->packages); // Remember the overall action state in the plan since it shapes the changes @@ -447,7 +466,6 @@ extern "C" HRESULT CorePlan( } else // doing an action that modifies the machine state. { - BOOL fContinuePlanning = TRUE; // assume we'll be able to keep planning after registration. pEngineState->plan.fPerMachine = pEngineState->registration.fPerMachine; // default the scope of the plan to the per-machine state of the bundle. hr = PlanRegistration(&pEngineState->plan, &pEngineState->registration, pEngineState->command.resumeType, pEngineState->command.relationType, &fContinuePlanning); @@ -477,12 +495,20 @@ extern "C" HRESULT CorePlan( hr = PlanFinalizeActions(&pEngineState->plan); ExitOnFailure(hr, "Failed to remove unnecessary actions from plan."); - // Finally, display all packages and related bundles in the log. - LogPackages(pUpgradeBundlePackage, pForwardCompatibleBundlePackage, &pEngineState->packages, &pEngineState->registration.relatedBundles, action); + if (fContinuePlanning) + { + // Finally, display all packages and related bundles in the log. + LogPackages(pUpgradeBundlePackage, pForwardCompatibleBundlePackage, &pEngineState->packages, &pEngineState->registration.relatedBundles, action); + } PlanDump(&pEngineState->plan); LExit: + if (SUCCEEDED(hr)) + { + pEngineState->fPlanned = TRUE; + } + if (fPlanBegan) { UserExperienceOnPlanComplete(&pEngineState->userExperience, hr); @@ -549,6 +575,15 @@ extern "C" HRESULT CoreApply( LogId(REPORT_STANDARD, MSG_APPLY_BEGIN); + if (!pEngineState->fPlanned) + { + ExitOnFailure(hr = E_INVALIDSTATE, "Apply cannot be done without a successful Plan."); + } + else if (pEngineState->fApplied) + { + ExitOnFailure(hr = E_INVALIDSTATE, "Plans cannot be applied multiple times."); + } + // Ensure any previous attempts to execute are reset. ApplyReset(&pEngineState->userExperience, &pEngineState->packages); @@ -564,6 +599,8 @@ extern "C" HRESULT CoreApply( hr = UserExperienceOnApplyBegin(&pEngineState->userExperience, dwPhaseCount); ExitOnRootFailure(hr, "BA aborted apply begin."); + pEngineState->fApplied = TRUE; + // Abort if this bundle already requires a restart. if (BOOTSTRAPPER_RESUME_TYPE_REBOOT_PENDING == pEngineState->command.resumeType) { @@ -758,6 +795,8 @@ extern "C" HRESULT CoreQuit( LogId(REPORT_STANDARD, MSG_QUIT, nExitCode); + pEngineState->fQuit = TRUE; + ::PostQuitMessage(nExitCode); // go bye-bye. return hr; diff --git a/src/engine/core.h b/src/engine/core.h index fae4bfe5..fd7311e3 100644 --- a/src/engine/core.h +++ b/src/engine/core.h @@ -78,6 +78,10 @@ enum BURN_AU_PAUSE_ACTION typedef struct _BURN_ENGINE_STATE { // UX flow control + BOOL fDetected; + BOOL fPlanned; + BOOL fApplied; + BOOL fQuit; //BOOL fSuspend; // Is TRUE when UX made Suspend() call on core. //BOOL fForcedReboot; // Is TRUE when UX made Reboot() call on core. //BOOL fCancelled; // Is TRUE when UX return cancel on UX OnXXX() methods. diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 2c6bad03..e3ace592 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -804,6 +804,12 @@ static HRESULT ProcessMessage( UserExperienceActivateEngine(&pEngineState->userExperience); + if (pEngineState->fQuit) + { + LogId(REPORT_WARNING, MSG_IGNORE_OPERATION_AFTER_QUIT, LoggingBurnMessageToString(pmsg->message)); + ExitFunction1(hr = E_INVALIDSTATE); + } + switch (pmsg->message) { case WM_BURN_DETECT: @@ -831,6 +837,7 @@ static HRESULT ProcessMessage( break; } +LExit: UserExperienceDeactivateEngine(&pEngineState->userExperience); return hr; diff --git a/src/engine/engine.mc b/src/engine/engine.mc index b120c5bb..d2135839 100644 --- a/src/engine/engine.mc +++ b/src/engine/engine.mc @@ -170,6 +170,13 @@ Language=English Condition '%1!ls!' contains invalid version string '%2!ls!'. . +MessageId=58 +Severity=Warning +SymbolicName=MSG_IGNORE_OPERATION_AFTER_QUIT +Language=English +Bootstrapper application already requested to quit, ignoring request: '%1!hs!'. +. + MessageId=100 Severity=Success SymbolicName=MSG_DETECT_BEGIN diff --git a/src/engine/logging.cpp b/src/engine/logging.cpp index 49b2bcc3..9dca527a 100644 --- a/src/engine/logging.cpp +++ b/src/engine/logging.cpp @@ -289,6 +289,29 @@ extern "C" LPCSTR LoggingBurnActionToString( } } +LPCSTR LoggingBurnMessageToString( + __in UINT message + ) +{ + switch (message) + { + case WM_BURN_APPLY: + return "Apply"; + case WM_BURN_DETECT: + return "Detect"; + case WM_BURN_ELEVATE: + return "Elevate"; + case WM_BURN_LAUNCH_APPROVED_EXE: + return "LaunchApprovedExe"; + case WM_BURN_PLAN: + return "Plan"; + case WM_BURN_QUIT: + return "Quit"; + default: + return "Invalid"; + } +} + extern "C" LPCSTR LoggingActionStateToString( __in BOOTSTRAPPER_ACTION_STATE actionState ) diff --git a/src/engine/logging.h b/src/engine/logging.h index 381a295b..b5c6c052 100644 --- a/src/engine/logging.h +++ b/src/engine/logging.h @@ -65,6 +65,10 @@ LPCSTR LoggingBurnActionToString( __in BOOTSTRAPPER_ACTION action ); +LPCSTR LoggingBurnMessageToString( + __in UINT message + ); + LPCSTR LoggingActionStateToString( __in BOOTSTRAPPER_ACTION_STATE actionState ); diff --git a/src/test/BurnUnitTest/PlanTest.cpp b/src/test/BurnUnitTest/PlanTest.cpp index 10b12e7b..a65bef4d 100644 --- a/src/test/BurnUnitTest/PlanTest.cpp +++ b/src/test/BurnUnitTest/PlanTest.cpp @@ -568,6 +568,7 @@ namespace Bootstrapper NativeAssert::Succeeded(hr, "Failed to add the bundle provider key to the list of dependencies to ignore."); pEngineState->userExperience.fEngineActive = TRUE; + pEngineState->fDetected = TRUE; } void DetectAttachedContainerAsAttached(BURN_ENGINE_STATE* pEngineState) -- cgit v1.2.3-55-g6feb