From bb99b54722596b205a07dfa2a6d784862b20c9b1 Mon Sep 17 00:00:00 2001
From: "S. Ganesh" <ganesh@chromium.org>
Date: Wed, 7 May 2025 06:53:31 -0700
Subject: [PATCH] updater: Force Install feature for MSI installers

This is a follow-up CL to r1456197 and r1454963.

Fixed: 408017292
Change-Id: If7f6e55ad23686d13580373af172ec32d5bc0321
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6513376
Commit-Queue: Joshua Pawlicki <waffles@chromium.org>
Auto-Submit: S Ganesh <ganesh@chromium.org>
Reviewed-by: Joshua Pawlicki <waffles@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1456967}
---
 .../enterprise_standalone_installer.wxs.xml   | 48 ++++++++++---------
 docs/updater/functional_spec.md               |  5 ++
 2 files changed, 30 insertions(+), 23 deletions(-)

diff --git a/chrome/updater/win/signing/enterprise_standalone_installer.wxs.xml b/chrome/updater/win/signing/enterprise_standalone_installer.wxs.xml
index ed91427fab800..f462743b666a8 100644
--- a/chrome/updater/win/signing/enterprise_standalone_installer.wxs.xml
+++ b/chrome/updater/win/signing/enterprise_standalone_installer.wxs.xml
@@ -78,16 +78,18 @@
     </Property>
     <Property Id="AllowDowngradeSubstitution" Value="false" />
 
-    <!-- Allows running the `updater` with a `--recover` option to recover from
-         cases where the installed `updater` may be non-operational.
+    <!-- Allows running the `updater` with a `--force-install` option. This
+         force-installs the installer that is run with this switch and makes it
+         the active `updater`. In addition, if the MSI is tagged, this also
+         installs the application(s) that are implicitly specified in the tag.
     -->
-    <Property Id="RUNRECOVER" Secure="yes" />
+    <Property Id="RUNFORCEINSTALL" Secure="yes" />
 
     <!-- Eliminates "warning LGHT1076 : ICE71: The Media table has no entries." -->
     <Media Id="1" />
 
     <Feature Id="Complete" Level="1" AllowAbsent="yes">
-      <Level Value="0" Condition="RUNRECOVER &lt;&gt; &quot;&quot;" />
+      <Level Value="0" Condition="RUNFORCEINSTALL &lt;&gt; &quot;&quot;" />
       <ComponentRef Id="ProductClientState" />
     </Feature>
 
@@ -223,10 +225,10 @@
     />
 
     <CustomAction
-      Id="DoRunRecover"
+      Id="DoRunForceInstall"
       Impersonate="no"
       Execute="deferred"
-      ExeCommand="--recover --system"
+      ExeCommand="--force-install --system"
       Return="check"
       BinaryRef="$(var.ProductNameLegalIdentifier)Installer"
     />
@@ -236,7 +238,7 @@
 
       <Custom Action="NewerVersionError"
         After="FindRelatedProducts"
-        Condition="((RUNRECOVER = &quot;&quot;) AND NEWPRODUCTFOUND AND (ALLOWDOWNGRADE = &quot;&quot;))"
+        Condition="((RUNFORCEINSTALL = &quot;&quot;) AND NEWPRODUCTFOUND AND (ALLOWDOWNGRADE = &quot;&quot;))"
       />
 
       <!-- The conditions in the following custom actions trigger the action when either:
@@ -253,19 +255,19 @@
       <Custom
         Action="ExtractTagInfoFromInstaller"
         Before="SetProductTagProperty"
-        Condition="((RUNRECOVER = &quot;&quot;) AND ((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL))"
+        Condition="((RUNFORCEINSTALL = &quot;&quot;) AND ((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL))"
       />
       <!-- Now start forming [ProdutTag], first with the appguid and name. -->
       <Custom
         Action="SetProductTagProperty"
         Before="AppendCustomParamsToProductTagProperty"
-        Condition="((RUNRECOVER = &quot;&quot;) AND ((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL))"
+        Condition="((RUNFORCEINSTALL = &quot;&quot;) AND ((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL))"
       />
       <!-- Add on the build-time string. -->
       <Custom
         Action="AppendCustomParamsToProductTagProperty"
         Before="TaggedMSIOverrideProductTagProperty"
-        Condition="((RUNRECOVER = &quot;&quot;) AND ((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL))"
+        Condition="((RUNFORCEINSTALL = &quot;&quot;) AND ((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL))"
       />
       <!-- Override the tag completely if the MSI is tagged, or if the caller
            has set the `TAGSTRING` property. Among all actions that change
@@ -275,46 +277,46 @@
       <Custom
         Action="TaggedMSIOverrideProductTagProperty"
         Before="BuildInstallCommand"
-        Condition="((RUNRECOVER = &quot;&quot;) AND ((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL)) AND (TAGSTRING &lt;&gt; &quot;&quot;)"
+        Condition="((RUNFORCEINSTALL = &quot;&quot;) AND ((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL)) AND (TAGSTRING &lt;&gt; &quot;&quot;)"
       />
       <Custom
         Action="SetOptArgsProperty"
         Before="AppendEnterpriseToOptArgsProperty"
-        Condition="((RUNRECOVER = &quot;&quot;) AND ((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL))"
+        Condition="((RUNFORCEINSTALL = &quot;&quot;) AND ((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL))"
       />
       <Custom
         Action="AppendEnterpriseToOptArgsProperty"
         Before="BuildInstallCommand"
-        Condition="((RUNRECOVER = &quot;&quot;) AND ((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL)) AND (NOGOOGLEUPDATEPING &lt;&gt; &quot;&quot;)"
+        Condition="((RUNFORCEINSTALL = &quot;&quot;) AND ((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL)) AND (NOGOOGLEUPDATEPING &lt;&gt; &quot;&quot;)"
       />
 
       <!-- Set [AllowDowngradeSubstitution] to true if downgrades are allowed. -->
       <Custom
         Action="DoAllowDowngradeSubstitution"
         Before="BuildInstallCommand"
-        Condition="((RUNRECOVER = &quot;&quot;) AND ((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL)) AND (ALLOWDOWNGRADE &lt;&gt; &quot;&quot;)"
+        Condition="((RUNFORCEINSTALL = &quot;&quot;) AND ((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL)) AND (ALLOWDOWNGRADE &lt;&gt; &quot;&quot;)"
       />
 
       <Custom
         Action="BuildInstallCommand"
         Before="SetAppGuidProperty"
-        Condition="((RUNRECOVER = &quot;&quot;) AND ((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL))"
+        Condition="((RUNFORCEINSTALL = &quot;&quot;) AND ((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL))"
       />
       <Custom
         Action="SetAppGuidProperty"
         Before="ShowInstallerResultUIString"
-        Condition="((RUNRECOVER = &quot;&quot;) AND ((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL))"
+        Condition="((RUNFORCEINSTALL = &quot;&quot;) AND ((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL))"
       />
       <Custom
         Action="ShowInstallerResultUIString"
         Before="DoInstall"
-        Condition="((RUNRECOVER = &quot;&quot;) AND ((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL))"
+        Condition="((RUNFORCEINSTALL = &quot;&quot;) AND ((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL))"
       />
 
       <Custom
         Action="DoInstall"
         After="InstallFiles"
-        Condition="((RUNRECOVER = &quot;&quot;) AND ((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL))"
+        Condition="((RUNFORCEINSTALL = &quot;&quot;) AND ((?ProductClientState=2) AND ($ProductClientState=3)) OR ((?ProductClientState=3) AND REINSTALL))"
       />
 
       <!-- The conditions in the following custom actions trigger the action when the product is
@@ -323,24 +325,24 @@
       <Custom
         Action="CallUninstallerArgs.SetProperty"
         Before="CallUninstaller.SetProperty"
-        Condition="((RUNRECOVER = &quot;&quot;) AND (?ProductClientState=3) AND ($ProductClientState=2) AND NOT UPGRADINGPRODUCTCODE)"
+        Condition="((RUNFORCEINSTALL = &quot;&quot;) AND (?ProductClientState=3) AND ($ProductClientState=2) AND NOT UPGRADINGPRODUCTCODE)"
       />
       <Custom
         Action="CallUninstaller.SetProperty"
         Before="CallUninstaller"
-        Condition="((RUNRECOVER = &quot;&quot;) AND (?ProductClientState=3) AND ($ProductClientState=2) AND NOT UPGRADINGPRODUCTCODE)"
+        Condition="((RUNFORCEINSTALL = &quot;&quot;) AND (?ProductClientState=3) AND ($ProductClientState=2) AND NOT UPGRADINGPRODUCTCODE)"
       />
       <Custom
         Action="CallUninstaller"
         Before="RemoveFiles"
-        Condition="((RUNRECOVER = &quot;&quot;) AND (?ProductClientState=3) AND ($ProductClientState=2) AND NOT UPGRADINGPRODUCTCODE)"
+        Condition="((RUNFORCEINSTALL = &quot;&quot;) AND (?ProductClientState=3) AND ($ProductClientState=2) AND NOT UPGRADINGPRODUCTCODE)"
       />
       <!-- Google Update will uninstall itself if the product is the only app it
            so no need to have an uninstall operation. -->
 
-      <Custom Action="DoRunRecover"
+      <Custom Action="DoRunForceInstall"
         After="InstallInitialize"
-        Condition="RUNRECOVER &lt;&gt; &quot;&quot;"
+        Condition="RUNFORCEINSTALL &lt;&gt; &quot;&quot;"
       />
     </InstallExecuteSequence>
 
diff --git a/docs/updater/functional_spec.md b/docs/updater/functional_spec.md
index 6c5bb8753a44b..101a956b11f05 100644
--- a/docs/updater/functional_spec.md
+++ b/docs/updater/functional_spec.md
@@ -368,6 +368,11 @@ process is determined by command-line arguments:
       * Installs the application(s) that are implicitly specified in the tagged
         metainstaller, or explicitly specified using the `--install` or
         `--handoff` parameters.
+*   `RUNFORCEINSTALL` (for MSI installers)
+    * Allows running an MSI metainstaller with the `--force-install` option.
+    * In addition, if the MSI is tagged, this also installs the application(s)
+      that are implicitly specified in the tag.
+    * For example, `msiexec /i GoogleChrome.msi RUNFORCEINSTALL=1`.
 *   --test
     *   Exit immediately with no error.
 *   --healthcheck