Skip to main content

GeneralUpdate.Bowl — Execution Flow Deep Dive

Target Audience: Developers who need to understand Bowl's crash surveillance mechanism

After reading you will understand:

  • Bowl's role and responsibilities in the GeneralUpdate upgrade closed loop
  • The complete execution chain from LaunchAsync to crash handling completion
  • The two-phase design of ProcDump process monitoring (Prepare → Run)
  • Dump file detection logic and crash determination rules
  • The five-step remediation pipeline when a crash is detected (Report → Diagnostics → Rollback → Cleanup → Callback)
  • Behavioral differences between Upgrade and Normal modes
  • Cross-platform strategy adaptation (Windows / Linux / macOS)
  • Graceful degradation and fault tolerance design

Table of Contents

  1. Architecture Overview
  2. Entry Point: BowlBootstrap's Dependency Injection Design
  3. BowlContext: Immutable Execution Context
  4. LaunchAsync: Monitoring Main Flow
  5. Phase 1: Strategy.Prepare — Platform Strategy Preparation
  6. Phase 2: ProcessRunner — Child Process Execution & Timeout Control
  7. Phase 3: FindDumpFile — Dump Detection & Crash Determination
  8. Phase 4: HandleCrashAsync — Crash Remediation Pipeline
  9. Upgrade vs Normal: Two Working Modes
  10. Platform Strategy Adaptation: Windows / Linux / macOS
  11. Fault Tolerance & Graceful Degradation
  12. Integration with GeneralUpdate.Core
  13. Key Code Path Index

1. Architecture Overview

1.1 Bowl's Position in the Upgrade Closed Loop

Bowl is the last line of defense in the GeneralUpdate upgrade closed loop. It does not participate in downloading, extracting, or replacing files — those are Core's responsibilities. Bowl's only job is: after new version files are deployed and the main process starts, monitor whether the target process crashes during startup.

┌──────────────────────────────────────────────────────────────┐
│ GeneralUpdate Upgrade Closed Loop │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐│
│ │ Core │───▶│ Upgrade │───▶│ Launch │───▶│ Bowl ││
│ │ Download │ │ Apply │ │ New Ver │ │ Crash ││
│ │ +Verify │ │ Patches │ │ Main App │ │ Guard ││
│ └──────────┘ └──────────┘ └──────────┘ └────┬────┘│
│ │ │
│ ┌────────────▼───┐ │
│ │ Normal Exit→OK │ │
│ │ Crash→Remediate│ │
│ └────────────────┘ │
└──────────────────────────────────────────────────────────────┘

1.2 Three-Layer Dependency Architecture

Bowl uses a Strategy + Reporter + Diagnostics three-layer DI design:

┌──────────────────────────────────────────────────────────┐
│ BowlBootstrap (Orchestration Layer) │
│ │
│ ┌──────────────────┐ ┌──────────────┐ ┌────────────┐ │
│ │ IBowlStrategy │ │ICrashReporter│ │ISystemInfo │ │
│ │ Platform monitor │ │ Crash report │ │ Provider │ │
│ │ strategy │ │ generation │ │ System diag │ │
│ └────────┬─────────┘ └──────┬───────┘ └─────┬──────┘ │
│ │ │ │ │
│ ┌────────▼─────────┐ ┌──────▼───────┐ ┌─────▼──────┐ │
│ │WindowsBowl │ │ CrashReporter│ │WindowsSystem│ │
│ │Strategy │ │ → JSON report│ │InfoProvider │ │
│ │(procdump.exe) │ │ │ │(export.bat) │ │
│ ├──────────────────┤ └──────────────┘ ├────────────┤ │
│ │LinuxBowlStrategy │ │LinuxSystem │ │
│ │(procdump pkg) │ │InfoProvider│ │
│ ├──────────────────┤ └────────────┘ │
│ │MacBowlStrategy │ │
│ │(lldb) │ │
│ └──────────────────┘ │
└──────────────────────────────────────────────────────────┘

1.3 Core Design Principles

PrincipleDescription
Monitor Only, No UpdateBowl never downloads, extracts, or replaces files — only monitors process crash status
Strategy PatternIBowlStrategy encapsulates platform differences: ProcDump for Windows/Linux, lldb for macOS
Graceful DegradationFailure of any step does not block subsequent steps — report failure won't prevent rollback, rollback failure won't prevent callback
Crash = Dump ExistsThe sole criterion for crash determination is whether a dump file exists
Immutable ContextBowlContext is a readonly record struct, normalized via Normalize()

1.4 Two Working Modes

ModeWorkModelBehavior
Upgrade"Upgrade"Monitor new version startup → auto-rollback on crash → mark failed version → set env var
Normal"Normal"Standalone monitoring → generate reports and diagnostics on crash → no auto-rollback → no failure marking

2. Entry Point: BowlBootstrap's Dependency Injection Design

BowlBootstrap provides two constructors: a parameterless one for auto-wiring defaults, and a three-parameter one for DI injection.

2.1 Dual Constructors

// Out of the box: auto-detect platform strategy + default reporter/diagnostics provider
public BowlBootstrap()
: this(
StrategyFactory.Create(), // Auto-select based on RuntimeInformation
new CrashReporter(), // JSON crash report
SystemInfoProviderFactory.Create()) // Platform system diagnostics
{ }

// DI friendly: all dependencies replaceable and mockable
internal BowlBootstrap(
IBowlStrategy strategy,
ICrashReporter crashReporter,
ISystemInfoProvider systemInfoProvider)
{
_strategy = strategy;
_crashReporter = crashReporter;
_systemInfoProvider = systemInfoProvider;
}

2.2 Strategy Factory Decision Tree

StrategyFactory.Create()

├── IsWindows() ──▶ WindowsBowlStrategy
│ Uses procdump.exe / procdump64.exe
│ Attaches to target process via -e flag

├── IsLinux() ──▶ LinuxBowlStrategy
│ Probes procdump availability
│ Auto-detects distro (deb/rpm)
│ Installs procdump package on demand

└── IsMacOS() ──▶ MacBowlStrategy
Uses /usr/bin/lldb
Limited by SIP and debug permissions

3. BowlContext: Immutable Execution Context

BowlContext is a readonly record struct carrying all surveillance parameters. Defaults are applied via Normalize().

3.1 Core Fields

FieldTypeDefaultDescription
ProcessNameOrIdstring(required)Target process name or PID
TargetPathstringTarget installation path
FailDirectorystringTargetPath/fails/Dump and report output directory
BackupDirectorystringTargetPath/.backups/latest/Backup directory (rollback source in Upgrade mode)
DumpFileNamestring{processName}.dmpExpected dump file name
TimeoutMsint30000 (30s)Monitoring timeout
DumpTypeDumpTypeFullDump type: Full / Mini / Heap
WorkModelstring"Upgrade"Working mode: Upgrade / Normal
AutoRestorebooltrueAuto-rollback backup on crash
ExtendedFieldstringExtended field (typically stores version)
OnCrashFunc<CrashInfo, CT, Task>nullCrash callback

4. LaunchAsync: Monitoring Main Flow

LaunchAsync is Bowl's only public method, encapsulating the complete chain from strategy preparation to crash remediation.

4.1 Full Flow Diagram


5. Phase 1: Strategy.Prepare — Platform Strategy Preparation

The Prepare method's responsibility is to construct the ProcessStartInfo needed to launch the ProcDump (or lldb) child process based on platform differences. If the tool is unavailable, return null for graceful degradation.

5.1 WindowsBowlStrategy

// Windows strategy: select the correct procdump architecture version
public ProcessStartInfo? Prepare(BowlContext context)
{
var procDumpPath = GetProcDumpPath(); // Choose based on process bitness
if (!File.Exists(procDumpPath))
return null; // Tool missing → graceful degradation

return new ProcessStartInfo
{
FileName = procDumpPath,
Arguments = $"-e -ma -accepteula {context.ProcessNameOrId} {dumpOutputPath}",
// -e: capture unhandled exceptions only
// -ma: Full Dump
// -accepteula: auto-accept EULA
};
}

5.2 LinuxBowlStrategy

// Linux strategy: probe procdump availability, attempt auto-install if missing
public ProcessStartInfo? Prepare(BowlContext context)
{
if (!IsProcDumpAvailable())
{
var installed = TryInstallProcDump(); // Detect distro, run install.sh or package manager
if (!installed) return null; // Install failed → graceful degradation
}

return new ProcessStartInfo
{
FileName = "procdump",
Arguments = $"-e -ma {context.ProcessNameOrId} {dumpOutputPath}"
};
}

6. Phase 2: ProcessRunner — Child Process Execution & Timeout Control

ProcessRunner is an async wrapper responsible for launching the child process, collecting output, and waiting for exit or timeout.

6.1 Execution Model

ProcessRunner.RunAsync(startInfo, timeoutMs, ct)

├── Process.Start(startInfo)
│ RedirectStandardOutput = true
│ RedirectStandardError = true

├── Concurrent execution:
│ Task 1: process.WaitForExitAsync(ct) → Wait for process exit
│ Task 2: Task.Delay(timeoutMs, ct) → Timeout timer

├── Collect stdout/stderr lines → List<string> OutputLines

└── Return ProcessExitResult { ExitCode, OutputLines }

7. Phase 3: FindDumpFile — Dump Detection & Crash Determination

The crash determination logic is extremely simple:

private static string? FindDumpFile(BowlContext context)
{
var path = Path.Combine(context.FailDirectory, context.DumpFileName);
return File.Exists(path) ? path : null;
}

Core rule: Dump file exists = Crash, No dump file = Normal exit.

This design leverages ProcDump's -e flag behavior — ProcDump only generates a dump file when the target process encounters an unhandled exception. If the process exits normally, ProcDump produces no files, thus never triggering the crash handling flow.


8. Phase 4: HandleCrashAsync — Crash Remediation Pipeline

When a dump file is detected, the five-step remediation pipeline starts:

8.1 Step 1: Generate Crash Report

// CrashReporter.GenerateReportAsync
// Output: {FailDirectory}/{version}_fail.json
var crashReportPath = await _crashReporter.GenerateReportAsync(
context, exitResult.OutputLines, ct);

Report contents: monitoring parameter snapshot, ProcDump output lines, timestamp.

Fault tolerance: Report generation failure does not block subsequent steps — exceptions are caught and logged.

8.2 Step 2: Export System Diagnostics

await _systemInfoProvider.ExportAsync(context.FailDirectory, ct);

Windows: Runs built-in export.bat collecting driver list, system info, recent event logs. Linux/macOS: Collects dmesg, journalctl, and other system logs.

Fault tolerance: Diagnostic export failure does not block subsequent steps.

8.3 Step 3: Auto Rollback (Upgrade mode only)

if (context.AutoRestore && context.WorkModel == "Upgrade")
{
StorageHelper.Restore(context.BackupDirectory, context.TargetPath);
restored = true;
}

StorageHelper.Restore copies backup directory contents over the install directory.

Preconditions: AutoRestore = true (default), WorkModel = "Upgrade", backup directory must exist.

8.4 Step 4: Platform Cleanup

await _strategy.PostProcessAsync(context, exitResult, ct);

Platform-specific: Windows cleans temp ProcDump files, Linux terminates residual procdump processes, macOS cleans lldb session files.

8.5 Step 5: Callback Notification

if (context.OnCrash != null)
{
var crashInfo = new CrashInfo
{
DumpFilePath = dumpPath,
CrashReportPath = crashReportPath,
Version = context.ExtendedField,
ExitCode = exitResult.ExitCode,
};
await context.OnCrash(crashInfo, ct);
}

9. Upgrade vs Normal: Two Working Modes

DimensionUpgrade ModeNormal Mode
Use CasePost-upgrade startup health checkGeneral process crash monitoring
Crash Report✅ Generated✅ Generated
System Diagnostics✅ Exported✅ Exported
Auto RollbackStorageHelper.Restore❌ Skipped
Failed Version Mark✅ Write UpgradeFail❌ Not marked
Environment Variable✅ Set GU_UPGRADE_FAIL❌ Not set
OnCrash Callback✅ Invoked✅ Invoked

10. Platform Strategy Adaptation: Windows / Linux / macOS

DimensionWindowsLinuxmacOS
Monitor Toolprocdump.exe / procdump64.exeprocdump (deb/rpm)/usr/bin/lldb
Tool AcquisitionBundled in NuGetAuto-detect + install.shSystem built-in
Dump Args-e -ma-e -malldb script
Arch SelectionAuto x86/x64/ARM64 by processNot differentiatedNot differentiated
PermissionsAdmin (debug privilege)root (ptrace)SIP authorization
System Diagnosticsexport.bat: drivers/sysinfo/eventsdmesg / journalctlsysdiagnose

11. Fault Tolerance & Graceful Degradation

Bowl's design philosophy: no single component failure should prevent other components from executing.

Degradation Levels

Level 0: Strategy cannot prepare tooling
→ Return BowlResult{Success=false, DumpCaptured=false}
→ No crash, no exception thrown

Level 1: Child process timeout
→ Return BowlResult{DumpCaptured=false}
→ Treated as "no crash captured", no rollback

Level 2: Report generation failure
→ Logged, continue to next step

Level 3: System diagnostics failure
→ Logged, continue to next step

Level 4: Auto rollback failure
→ Logged, continue to callback

Level 5: OnCrash callback exception
→ Logged, does not affect BowlResult return

12. Integration with GeneralUpdate.Core

12.1 Call Timing

Bowl should be called after Core completes file replacement and before launching the new version:

var bowlContext = new BowlContext
{
ProcessNameOrId = "MyApp",
TargetPath = installPath,
BackupDirectory = backupPath,
WorkModel = "Upgrade",
ExtendedField = newVersion,
AutoRestore = true,
OnCrash = async (info, ct) =>
{
await UploadCrashReportAsync(info, ct);
}
};

var bowl = new BowlBootstrap();
var result = await bowl.LaunchAsync(bowlContext);

12.2 Shared State with Core

State ChannelWriterReaderPurpose
{version}_fail.jsonBowlCore + BusinessPersistent crash report
Env var GU_UPGRADE_FAILBowlCoreFailed version skip
.backups/ directoryCore (create)Bowl (rollback)Backup & restore

13. Key Code Path Index

ComponentFileKey Methods
Entry OrchestratorBowlBootstrap.csLaunchAsync()HandleCrashAsync()
Execution ContextBowlContext.csNormalize()
Crash ReporterInternal/CrashReporter.csGenerateReportAsync()
System DiagnosticsInternal/WindowsSystemInfoProvider.csExportAsync()
File RollbackFileSystem/StorageHelper.csRestore()
Windows StrategyStrategies/WindowsBowlStrategy.csPrepare() / PostProcessAsync()
Linux StrategyStrategies/LinuxBowlStrategy.csPrepare() / PostProcessAsync()
Mac StrategyStrategies/MacBowlStrategy.csPrepare() / PostProcessAsync()
Process RunnerStrategies/ProcessRunner.csRunAsync()
Strategy FactoryStrategies/StrategyFactory.csCreate()
Crash DTOInternal/Crash.cs
Dump TypeDumpType.csFull / Mini / Heap
LoggerTracer/GeneralTracer.csInfo() / Warn() / Error()