From 160b595e2f55a3aecd041fbf584d9798b9b2be68 Mon Sep 17 00:00:00 2001 From: NINI Date: Wed, 7 Oct 2026 01:22:46 +0900 Subject: [PATCH] Verify recorder identity once and retain original native process handles --- tools/android/exercise-content.ps1 | 15 ++++++++++----- tools/android/exercise-final-boundaries.ps1 | 8 ++++---- tools/android/exercise-final-progression.ps1 | 8 ++++---- tools/android/exercise-final-rapid.ps1 | 8 ++++---- tools/android/final-common.ps1 | 7 ++++++- 5 files changed, 28 insertions(+), 18 deletions(-) diff --git a/tools/android/exercise-content.ps1 b/tools/android/exercise-content.ps1 index 72fdacb..707d0ef 100644 --- a/tools/android/exercise-content.ps1 +++ b/tools/android/exercise-content.ps1 @@ -110,7 +110,7 @@ function StartAudio([string]$Name,[int]$Seconds) { if (Test-Path -LiteralPath $readyPath) { Remove-Item -LiteralPath $readyPath } $args=@('-NoProfile','-File',(Join-Path $PSScriptRoot 'record-native-audio.ps1'),'-OutputPath',(Join-Path $EvidenceDir "$Name.wav"),'-Seconds',"$Seconds",'-Serial',$Serial) $process=Start-Process pwsh -ArgumentList ($args | ForEach-Object {'"'+$_+'"'}) -WindowStyle Hidden -RedirectStandardOutput (Join-Path $EvidenceDir "$Name.stdout") -RedirectStandardError (Join-Path $EvidenceDir "$Name.stderr") -PassThru - $recorders.Add(@{name=$Name;process=$process;seconds=$Seconds;startedUtc=[DateTime]::UtcNow}) + $recorders.Add(@{name=$Name;process=$process;seconds=$Seconds;nativeProcess=$null;startedUtc=[DateTime]::UtcNow}) $readyPath=Join-Path $EvidenceDir "$Name.wav.ready.json" $ready=$false for ($attempt=0; $attempt -lt 120; $attempt++) { @@ -119,6 +119,11 @@ function StartAudio([string]$Name,[int]$Seconds) { Start-Sleep -Milliseconds 100 } Check "audio-ready-$Name" $ready 'Recorder reported actual Recording started before interaction' + $readyRecord=Get-Content -LiteralPath $readyPath -Raw|ConvertFrom-Json + $native=Get-Process -Id $readyRecord.recorderPid -ErrorAction Stop + Check "audio-native-identity-$Name" ($native.ProcessName-eq'scrcpy'-and$native.StartTime.ToUniversalTime()-ge$recorders[-1].startedUtc-and$native.StartTime.ToUniversalTime()-le([DateTime]$readyRecord.readyUtc).ToUniversalTime()) 'Own scrcpy created in this recording window; retain Process object rather than recycled PID lookup' + $native.Handle|Out-Null # Retain this native process handle through its exit, even if Windows reuses its PID. + $recorders[-1].nativeProcess=$native for ($attempt=0; $attempt -lt 20; $attempt++) { Adb @('shell','cmd','audio','set-volume','3','15') | Out-Null $route=Adb @('shell','dumpsys','audio') @@ -236,16 +241,16 @@ finally { if (!$recorder.process.HasExited -and !$recorder.process.WaitForExit(($recorder.seconds+30)*1000)) { $result.status='failed'; $result.recorderError='Recorder exceeded completion bound; own native process stopped before restoration' $ready=Get-Content -LiteralPath (Join-Path $EvidenceDir "$($recorder.name).wav.ready.json") -Raw | ConvertFrom-Json - $native=Get-Process -Id $ready.recorderPid -ErrorAction SilentlyContinue - if ($native) { $native.Kill(); $native.WaitForExit() } + $native=$recorder.nativeProcess + if ($native -and !$native.HasExited) { $native.Kill(); $native.WaitForExit() } $recorder.process.WaitForExit(10000) | Out-Null if (!$recorder.process.HasExited) { $recorder.process.Kill(); $recorder.process.WaitForExit() } } $readyPath=Join-Path $EvidenceDir "$($recorder.name).wav.ready.json" if (Test-Path -LiteralPath $readyPath) { $ready=Get-Content -LiteralPath $readyPath -Raw | ConvertFrom-Json - $native=Get-Process -Id $ready.recorderPid -ErrorAction SilentlyContinue - if ($native) { $native.WaitForExit() } + $native=$recorder.nativeProcess + if ($native -and !$native.HasExited -and !$native.WaitForExit(10000)) { throw 'Own native recorder did not terminate' } $commands.Add(@{command='recorder termination boundary';recorderPid=$ready.recorderPid;wrapperPid=$recorder.process.Id;nativeExited=$true;wrapperExited=$recorder.process.HasExited;utc=[DateTime]::UtcNow.ToString('o')}) } } diff --git a/tools/android/exercise-final-boundaries.ps1 b/tools/android/exercise-final-boundaries.ps1 index 1b14c47..6ec03c2 100644 --- a/tools/android/exercise-final-boundaries.ps1 +++ b/tools/android/exercise-final-boundaries.ps1 @@ -119,16 +119,16 @@ finally { if (!$recorder.process.HasExited -and !$recorder.process.WaitForExit(($recorder.seconds+30)*1000)) { $result.status='failed'; $result.recorderError='Recorder exceeded completion bound; own native process stopped before restoration' $ready=Get-Content -LiteralPath (Join-Path $EvidenceDir "$($recorder.name).wav.ready.json") -Raw | ConvertFrom-Json - $native=Get-Process -Id $ready.recorderPid -ErrorAction SilentlyContinue - if ($native) { $native.Kill(); $native.WaitForExit() } + $native=$recorder.nativeProcess + if ($native -and !$native.HasExited) { $native.Kill(); $native.WaitForExit() } $recorder.process.WaitForExit(10000) | Out-Null if (!$recorder.process.HasExited) { $recorder.process.Kill(); $recorder.process.WaitForExit() } } $readyPath=Join-Path $EvidenceDir "$($recorder.name).wav.ready.json" if (Test-Path -LiteralPath $readyPath) { $ready=Get-Content -LiteralPath $readyPath -Raw | ConvertFrom-Json - $native=Get-Process -Id $ready.recorderPid -ErrorAction SilentlyContinue - if ($native) { $native.WaitForExit() } + $native=$recorder.nativeProcess + if ($native -and !$native.HasExited -and !$native.WaitForExit(10000)) { throw 'Own native recorder did not terminate' } $commands.Add(@{command='recorder termination boundary';recorderPid=$ready.recorderPid;wrapperPid=$recorder.process.Id;nativeExited=$true;wrapperExited=$recorder.process.HasExited;utc=[DateTime]::UtcNow.ToString('o')}) } } diff --git a/tools/android/exercise-final-progression.ps1 b/tools/android/exercise-final-progression.ps1 index b7e6a09..3660eb0 100644 --- a/tools/android/exercise-final-progression.ps1 +++ b/tools/android/exercise-final-progression.ps1 @@ -217,16 +217,16 @@ finally { if (!$recorder.process.HasExited -and !$recorder.process.WaitForExit(($recorder.seconds+30)*1000)) { $result.status='failed'; $result.recorderError='Recorder exceeded completion bound; own native process stopped before restoration' $ready=Get-Content -LiteralPath (Join-Path $EvidenceDir "$($recorder.name).wav.ready.json") -Raw | ConvertFrom-Json - $native=Get-Process -Id $ready.recorderPid -ErrorAction SilentlyContinue - if ($native) { $native.Kill(); $native.WaitForExit() } + $native=$recorder.nativeProcess + if ($native -and !$native.HasExited) { $native.Kill(); $native.WaitForExit() } $recorder.process.WaitForExit(10000) | Out-Null if (!$recorder.process.HasExited) { $recorder.process.Kill(); $recorder.process.WaitForExit() } } $readyPath=Join-Path $EvidenceDir "$($recorder.name).wav.ready.json" if (Test-Path -LiteralPath $readyPath) { $ready=Get-Content -LiteralPath $readyPath -Raw | ConvertFrom-Json - $native=Get-Process -Id $ready.recorderPid -ErrorAction SilentlyContinue - if ($native) { $native.WaitForExit() } + $native=$recorder.nativeProcess + if ($native -and !$native.HasExited -and !$native.WaitForExit(10000)) { throw 'Own native recorder did not terminate' } $commands.Add(@{command='recorder termination boundary';recorderPid=$ready.recorderPid;wrapperPid=$recorder.process.Id;nativeExited=$true;wrapperExited=$recorder.process.HasExited;utc=[DateTime]::UtcNow.ToString('o')}) } } diff --git a/tools/android/exercise-final-rapid.ps1 b/tools/android/exercise-final-rapid.ps1 index 1866020..e55c236 100644 --- a/tools/android/exercise-final-rapid.ps1 +++ b/tools/android/exercise-final-rapid.ps1 @@ -59,16 +59,16 @@ finally { if (!$recorder.process.HasExited -and !$recorder.process.WaitForExit(($recorder.seconds+30)*1000)) { $result.status='failed'; $result.recorderError='Recorder exceeded completion bound; own native process stopped before restoration' $ready=Get-Content -LiteralPath (Join-Path $EvidenceDir "$($recorder.name).wav.ready.json") -Raw | ConvertFrom-Json - $native=Get-Process -Id $ready.recorderPid -ErrorAction SilentlyContinue - if ($native) { $native.Kill(); $native.WaitForExit() } + $native=$recorder.nativeProcess + if ($native -and !$native.HasExited) { $native.Kill(); $native.WaitForExit() } $recorder.process.WaitForExit(10000) | Out-Null if (!$recorder.process.HasExited) { $recorder.process.Kill(); $recorder.process.WaitForExit() } } $readyPath=Join-Path $EvidenceDir "$($recorder.name).wav.ready.json" if (Test-Path -LiteralPath $readyPath) { $ready=Get-Content -LiteralPath $readyPath -Raw | ConvertFrom-Json - $native=Get-Process -Id $ready.recorderPid -ErrorAction SilentlyContinue - if ($native) { $native.WaitForExit() } + $native=$recorder.nativeProcess + if ($native -and !$native.HasExited -and !$native.WaitForExit(10000)) { throw 'Own native recorder did not terminate' } $commands.Add(@{command='recorder termination boundary';recorderPid=$ready.recorderPid;wrapperPid=$recorder.process.Id;nativeExited=$true;wrapperExited=$recorder.process.HasExited;utc=[DateTime]::UtcNow.ToString('o')}) } } diff --git a/tools/android/final-common.ps1 b/tools/android/final-common.ps1 index e36ca1d..709bb42 100644 --- a/tools/android/final-common.ps1 +++ b/tools/android/final-common.ps1 @@ -142,7 +142,7 @@ function StartAudio([string]$Name,[int]$Seconds) { if (Test-Path -LiteralPath $readyPath) { Remove-Item -LiteralPath $readyPath } $args=@('-NoProfile','-File',(Join-Path $PSScriptRoot 'record-native-audio.ps1'),'-OutputPath',(Join-Path $EvidenceDir "$Name.wav"),'-Seconds',"$Seconds",'-Serial',$Serial) $process=Start-Process pwsh -ArgumentList ($args | ForEach-Object {'"'+$_+'"'}) -WindowStyle Hidden -RedirectStandardOutput (Join-Path $EvidenceDir "$Name.stdout") -RedirectStandardError (Join-Path $EvidenceDir "$Name.stderr") -PassThru - $recorders.Add(@{name=$Name;process=$process;seconds=$Seconds;startedUtc=[DateTime]::UtcNow}) + $recorders.Add(@{name=$Name;process=$process;seconds=$Seconds;nativeProcess=$null;startedUtc=[DateTime]::UtcNow}) $readyPath=Join-Path $EvidenceDir "$Name.wav.ready.json" $ready=$false for ($attempt=0; $attempt -lt 120; $attempt++) { @@ -151,6 +151,11 @@ function StartAudio([string]$Name,[int]$Seconds) { Start-Sleep -Milliseconds 100 } Check "audio-ready-$Name" $ready 'Recorder reported actual Recording started before interaction' + $readyRecord=Get-Content -LiteralPath $readyPath -Raw|ConvertFrom-Json + $native=Get-Process -Id $readyRecord.recorderPid -ErrorAction Stop + Check "audio-native-identity-$Name" ($native.ProcessName-eq'scrcpy'-and$native.StartTime.ToUniversalTime()-ge$recorders[-1].startedUtc-and$native.StartTime.ToUniversalTime()-le([DateTime]$readyRecord.readyUtc).ToUniversalTime()) 'Own scrcpy created in this recording window; retain Process object rather than recycled PID lookup' + $native.Handle|Out-Null # Retain this native process handle through its exit, even if Windows reuses its PID. + $recorders[-1].nativeProcess=$native for ($attempt=0; $attempt -lt 20; $attempt++) { Adb @('shell','cmd','audio','set-volume','3','15') | Out-Null $route=Adb @('shell','dumpsys','audio')