fix(android): capture privacy exit states
This commit is contained in:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user