Chrome rename: gradually backoff on the wait at each attempt

With this CL, if the CoCreate for the `ProcessLauncher` times out, the
timeout is increased by 15 seconds at each failed attempt and persisted
for the next attempt.

This CL also introduces a `PerInstallValue` class that can be used to
store named persisted `base::Value` objects on a per-install basis.
i.e., a single `base::Value` stored in a system-wide location for system
installs, and a single `base::Value` stored per-user for user installs.
The values are stored in the registry under
`Google\Update\ClientState{Medium}\{ChromeAppId}` for branded installs.

Fixed: 348199036,40792898
Change-Id: Iac173d5e271b05b7e8901c0a166d875edf2a6fd6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5727256
Code-Coverage: [email protected] <[email protected]>
Commit-Queue: Sean Maher <[email protected]>
Reviewed-by: Sean Maher <[email protected]>
Reviewed-by: Greg Thompson <[email protected]>
Auto-Submit: S Ganesh <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1340493}
diff --git a/chrome/browser/first_run/upgrade_util_win.cc b/chrome/browser/first_run/upgrade_util_win.cc
index 0be6665..3a243615 100644
--- a/chrome/browser/first_run/upgrade_util_win.cc
+++ b/chrome/browser/first_run/upgrade_util_win.cc
@@ -25,7 +25,7 @@
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/metrics/histogram_macros.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/path_service.h"
 #include "base/process/launch.h"
 #include "base/process/process_handle.h"
@@ -36,7 +36,9 @@
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
 #include "base/time/time.h"
+#include "base/timer/elapsed_timer.h"
 #include "base/trace_event/trace_event.h"
+#include "base/values.h"
 #include "base/win/registry.h"
 #include "base/win/windows_version.h"
 #include "build/branding_buildflags.h"
@@ -49,6 +51,7 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/install_static/install_util.h"
 #include "chrome/installer/util/app_command.h"
+#include "chrome/installer/util/per_install_values.h"
 #include "chrome/installer/util/util_constants.h"
 #include "components/prefs/pref_service.h"
 #include "third_party/abseil-cpp/absl/cleanup/cleanup.h"
@@ -103,7 +106,6 @@
       return;
     }
   }
-  Microsoft::WRL::ComPtr<IStream> stream;
   const HRESULT hr = ::CoMarshalInterThreadInterfaceInStream(
       __uuidof(IUnknown), unknown.Get(), &result->stream);
   if (FAILED(hr)) {
@@ -118,17 +120,34 @@
 }
 
 // CoCreates the Google Update `ProcessLauncherClass` in a `ThreadPool` thread
-// with a timeout. If the `ThreadPool` is not operational, the CoCreate is done
+// with a timeout, if the `ThreadPool` is operational. The starting value for
+// the timeout is 15 seconds. If the CoCreate times out, the timeout is
+// increased by 15 seconds at each failed attempt and persisted for the next
+// attempt.
+//
+// If the `ThreadPool` is not operational, the CoCreate is done
 // without a timeout.
-// TODO(crbug.com/40792898): gradually backoff on the wait at each attempt
-// to rename, instead of a fixed 15 seconds.
 Microsoft::WRL::ComPtr<IUnknown> CreateProcessLauncher() {
+  constexpr int kDefaultTimeoutIncrementSeconds = 15;
+
   auto result = base::MakeRefCounted<CreateProcessLauncherResult>();
   if (base::ThreadPool::CreateCOMSTATaskRunner(
           {base::MayBlock(), base::TaskPriority::USER_BLOCKING})
           ->PostTask(FROM_HERE, base::BindOnce(&CreateAndMarshalProcessLauncher,
                                                result))) {
-    if (!result->completion_event.TimedWait(base::Seconds(15))) {
+    installer::PerInstallValue creation_timeout(
+        L"ProcessLauncherCreationTimeout");
+    const base::TimeDelta timeout = base::Seconds(
+        creation_timeout.Get()
+            .value_or(base::Value(kDefaultTimeoutIncrementSeconds))
+            .GetIfInt()
+            .value_or(kDefaultTimeoutIncrementSeconds));
+    const base::ElapsedTimer timer;
+    if (!result->completion_event.TimedWait(timeout)) {
+      base::UmaHistogramMediumTimes(
+          "Startup.CreateProcessLauncher.TimedWaitFailed", timer.Elapsed());
+      creation_timeout.Set(base::Value(static_cast<int>(timeout.InSeconds()) +
+                                       kDefaultTimeoutIncrementSeconds));
       TRACE_EVENT_INSTANT0(
           "startup", "InvokeGoogleUpdateForRename CoCreateInstance timed out",
           TRACE_EVENT_SCOPE_THREAD);
@@ -139,6 +158,8 @@
     if (!result->stream) {
       return {};
     }
+    base::UmaHistogramMediumTimes(
+        "Startup.CreateProcessLauncher.TimedWaitSucceeded", timer.Elapsed());
 
     Microsoft::WRL::ComPtr<IUnknown> unknown;
     const HRESULT hr =