fix(android): capture privacy exit states

This commit is contained in:
key
2026-07-29 03:43:30 +08:00
parent 8354e4e9c2
commit 71f005c229
4 changed files with 67 additions and 13 deletions
+60 -12
View File
@@ -56,13 +56,14 @@ function Invoke-AdbText {
param(
[Parameter(Mandatory = $true)]
[string[]]$Arguments,
[switch]$AllowEmpty
[switch]$AllowEmpty,
[switch]$AllowNonZero
)
$output = & $script:resolvedAdbPath @Arguments 2>&1
$exitCode = $LASTEXITCODE
$text = ($output | Out-String).Trim()
if ($exitCode -ne 0) {
if ($exitCode -ne 0 -and -not $AllowNonZero) {
throw "adb failed with exit code $exitCode`: $($Arguments -join ' ')`n$text"
}
if (-not $AllowEmpty -and [string]::IsNullOrWhiteSpace($text)) {
@@ -119,7 +120,16 @@ function Get-FirstMatchingLine {
[string]$Text,
[string]$Pattern
)
return (($Text -split "`r?`n") | Where-Object { $_ -match $Pattern } | Select-Object -First 1).Trim()
$line = ($Text -split "`r?`n") | Where-Object { $_ -match $Pattern } | Select-Object -First 1
if ($null -eq $line) {
return ''
}
return $line.Trim()
}
function ConvertFrom-CodePoints {
param([int[]]$CodePoints)
return -join @($CodePoints | ForEach-Object { [char]$_ })
}
$script:resolvedAdbPath = Resolve-AdbPath -RequestedPath $AdbPath
@@ -160,7 +170,9 @@ New-Item -ItemType Directory -Path $evidenceDirectory | Out-Null
$activityDump = Invoke-AdbText -Arguments @('-s', $Serial, 'shell', 'dumpsys', 'activity', 'activities')
$resumedActivity = Get-FirstMatchingLine -Text $activityDump -Pattern 'topResumedActivity=|mResumedActivity:'
$processId = Invoke-AdbText -Arguments @('-s', $Serial, 'shell', 'pidof', $PackageName) -AllowEmpty
$processId = Invoke-AdbText -Arguments @('-s', $Serial, 'shell', 'pidof', $PackageName) -AllowEmpty -AllowNonZero
$processRunning = -not [string]::IsNullOrWhiteSpace($processId)
$appForeground = $resumedActivity -match [regex]::Escape($PackageName)
$exitInfo = Invoke-AdbText -Arguments @('-s', $Serial, 'shell', 'dumpsys', 'activity', 'exit-info', $PackageName)
$crashOrAnrDetected = $exitInfo -match '(?m)reason=\d+\s+\((?:CRASH|CRASH_NATIVE|ANR)\)'
@@ -179,17 +191,39 @@ $visibleTexts = @($uiDocument.SelectNodes('//node') |
$resourceIds = @($uiDocument.SelectNodes('//node') |
ForEach-Object { [string]$_.GetAttribute('resource-id') } |
Where-Object { -not [string]::IsNullOrWhiteSpace($_) })
$uiPackages = @($uiDocument.SelectNodes('//node') |
ForEach-Object { [string]$_.GetAttribute('package') } |
Where-Object { -not [string]::IsNullOrWhiteSpace($_) } |
Select-Object -Unique)
$privacyTitleVisible = $resourceIds -contains "$PackageName`:id/tv_custom_privacy_title"
$privacyRejectVisible = $resourceIds -contains "$PackageName`:id/btn_custom_privacy_cancel"
$privacyConsentVisible = $resourceIds -contains "$PackageName`:id/btn_custom_privacy_sure"
$loginLabel = -join @(
[char]0x624B,
[char]0x673A,
[char]0x53F7,
[char]0x767B,
[char]0x5F55
$firstPrivacyTitle = ConvertFrom-CodePoints @(
0x670D, 0x52A1, 0x534F, 0x8BAE, 0x548C, 0x9690, 0x79C1, 0x653F, 0x7B56
)
$secondPrivacyTitle = ConvertFrom-CodePoints @(0x786E, 0x8BA4, 0x63D0, 0x793A)
$firstRejectLabel = ConvertFrom-CodePoints @(0x6682, 0x4E0D, 0x540C, 0x610F)
$exitLabel = ConvertFrom-CodePoints @(0x9000, 0x51FA, 0x5E94, 0x7528)
$consentLabel = ConvertFrom-CodePoints @(0x540C, 0x610F, 0x5E76, 0x7EE7, 0x7EED)
$loginLabel = ConvertFrom-CodePoints @(0x624B, 0x673A, 0x53F7, 0x767B, 0x5F55)
$firstPrivacyTitleVisible = $visibleTexts -contains $firstPrivacyTitle
$secondPrivacyTitleVisible = $visibleTexts -contains $secondPrivacyTitle
$firstRejectLabelVisible = $visibleTexts -contains $firstRejectLabel
$exitLabelVisible = $visibleTexts -contains $exitLabel
$consentLabelVisible = $visibleTexts -contains $consentLabel
$loginVisible = $visibleTexts -contains $loginLabel
$privacyDialogStage = if ($secondPrivacyTitleVisible -or $exitLabelVisible) {
'exit-confirmation'
}
elseif ($firstPrivacyTitleVisible -or $firstRejectLabelVisible) {
'first-choice'
}
elseif ($privacyTitleVisible -or $privacyRejectVisible -or $privacyConsentVisible) {
'unknown-privacy-dialog'
}
else {
'not-visible'
}
$permissionNames = @(
'android.permission.CAMERA',
@@ -248,12 +282,21 @@ $evidence = [ordered]@{
minSdkVersion = [int]$sdkMatch.Groups[2].Value
targetSdkVersion = [int]$sdkMatch.Groups[3].Value
processId = $processId
processRunning = $processRunning
resumedActivity = $resumedActivity
foreground = $appForeground
}
screen = [ordered]@{
appUiVisible = $uiPackages -contains $PackageName
privacyDialogStage = $privacyDialogStage
privacyDialogTitleVisible = $privacyTitleVisible
privacyRejectVisible = $privacyRejectVisible
privacyConsentVisible = $privacyConsentVisible
firstPrivacyTitleVisible = $firstPrivacyTitleVisible
secondPrivacyTitleVisible = $secondPrivacyTitleVisible
firstRejectLabelVisible = $firstRejectLabelVisible
exitLabelVisible = $exitLabelVisible
consentLabelVisible = $consentLabelVisible
loginVisible = $loginVisible
}
permissions = $permissionStates
@@ -282,7 +325,11 @@ $markdown = @(
"- Device: $($device.manufacturer) $($device.model), Android $($device.androidRelease) / API $($device.apiLevel)",
"- App: $PackageName $($evidence.app.versionName) ($($evidence.app.versionCode)), target API $($evidence.app.targetSdkVersion)",
"- Resumed activity: $resumedActivity",
"- Privacy dialog: title=$privacyTitleVisible, reject=$privacyRejectVisible, consent=$privacyConsentVisible",
"- App process running: $processRunning",
"- App foreground: $appForeground",
"- Privacy dialog stage: $privacyDialogStage",
"- Privacy controls: title=$privacyTitleVisible, reject=$privacyRejectVisible, consent=$privacyConsentVisible",
"- Privacy labels: firstReject=$firstRejectLabelVisible, exit=$exitLabelVisible, consent=$consentLabelVisible",
"- Login visible: $loginVisible",
"- Historical crash or ANR found: $crashOrAnrDetected",
'',
@@ -298,7 +345,8 @@ Write-Output "android_acceptance_evidence=$evidenceDirectory"
Write-Output "device=$Serial Android/$($device.apiLevel)"
Write-Output "app=$PackageName $($evidence.app.versionName) ($($evidence.app.versionCode)) targetSdk=$($evidence.app.targetSdkVersion)"
Write-Output "resumed_activity=$resumedActivity"
Write-Output "privacy_dialog=title:$privacyTitleVisible reject:$privacyRejectVisible consent:$privacyConsentVisible login:$loginVisible"
Write-Output "app_state=process:$processRunning foreground:$appForeground ui:$($uiPackages -contains $PackageName)"
Write-Output "privacy_dialog=stage:$privacyDialogStage title:$privacyTitleVisible reject:$privacyRejectVisible consent:$privacyConsentVisible firstRejectLabel:$firstRejectLabelVisible exitLabel:$exitLabelVisible login:$loginVisible"
Write-Output "historical_crash_or_anr=$crashOrAnrDetected"
foreach ($permissionName in $permissionNames) {
Write-Output "permission_$permissionName=$($permissionStates[$permissionName])"
@@ -15,6 +15,11 @@ $requiredFragments = @(
"'android.permission.READ_MEDIA_IMAGES'",
"'android.permission.READ_MEDIA_VIDEO'",
"'read-only-current-state'",
"'exit-confirmation'",
"'first-choice'",
'processRunning',
'appForeground',
'AllowNonZero',
"Join-Path `$projectRoot 'output'"
)
foreach ($fragment in $requiredFragments) {