Android Question Script to check compatibility 16kb

MarcoRome

Expert
Licensed User
Longtime User
As the title suggests, here's a script to check 16kb compatibility (for those who don't use Android Studio's APK Analyzer).

The script analyzes apk, aar, aab or zip files.

You need to download and unzip android-ndk-r28c-windows.zip, which you can find at this link: ( https://developer.android.com/ndk/downloads?hl=en )
After unzipping it, you can modify the script with your own path.
The script runs in Windows PowerShell. So, after running the command cmd ... and typing PowerShell or
Shift+right-clicking in the folder → "Open PowerShell window here".
Type:

PS F:\downloadF> .\check-16kb.ps1 -ArchivePath "F:\DownloadF\testpdf\name.apk"

if your script is blocked you can execute this comand:

Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
and repeat

PS F:\downloadF> .\check-16kb.ps1 -ArchivePath "F:\DownloadF\testpdf\name.apk"

The resul will be:

Negative (KO) if inside the arm64-v8a directory it will find libraries not aligned to 16kb
1756389097625.png

if the files arent aligned it will give their name ( look above )

or Positive (OK) if inside the arm64-v8a directory it will find libraries aligned to 16kb

1756389170002.png



(Of course, the path is yours, i.e., where the check-16kb.ps1 file was placed.)
Also inside the script insert your path (line 11)

This is the script:

B4X:
<# check-16kb-arm64.ps1
   Controlla SOLO le .so nella cartella arm64-v8a
   Verifica che TUTTI i segmenti PT_LOAD abbiano Alignment >= 16384 (16 KB).
#>

param(
  [Parameter(Mandatory = $true)]
  [Alias('ArchivePath')]
  [string]$Path,

  [string]$Readobj = "F:\android-ndk-r28c\toolchains\llvm\prebuilt\windows-x86_64\bin\llvm-readobj.exe",
  [string]$ReportPath,
  [int]$MinAlign = 16384
)

function Get-PtLoadAlignments {
  param([string]$SoPath, [string]$ReadobjExe)

  $result = New-Object PSObject -Property @{ Alignments = @(); Error = $null }

  $out = & $ReadobjExe --program-headers $SoPath 2>&1
  if ($LASTEXITCODE -ne 0) {
    $result.Error = ("llvm-readobj exit code {0}: {1}" -f $LASTEXITCODE, $SoPath)
    return $result
  }

  $reTypeLoad  = '^\s*Type:\s*(?:PT_)?LOAD\b'
  $reAnyType   = '^\s*Type:\s*\S+'
  $reAlignment = '^\s*Align(?:ment)?:\s*(0x[0-9A-Fa-f]+|\d+)'

  $inLoad = $false
  foreach ($line in ($out -split "`n")) {
    $l = $line.TrimEnd()

    if ($l -match $reTypeLoad) { $inLoad = $true; continue }
    if ($l -match $reAnyType)  { $inLoad = $false; continue }

    if ($inLoad -and ($l -match $reAlignment)) {
      $val = $Matches[1]
      if ($val -like '0x*') { $n = [Convert]::ToInt32($val,16) } else { $n = [int]$val }
      $result.Alignments += $n
    }
  }
  return $result
}

function Get-SoResult {
  param([string]$SoPath, [string]$ReadobjExe, [int]$MinAlign)

  $r = Get-PtLoadAlignments -SoPath $SoPath -ReadobjExe $ReadobjExe
  $aligns = $r.Alignments

  $ok = $true
  $reason = $null
  if ($r.Error) {
    $ok = $false; $reason = $r.Error
  } elseif ($aligns.Count -eq 0) {
    $ok = $false; $reason = "nessun segmento PT_LOAD trovato"
  } else {
    foreach ($a in $aligns) {
      if ($a -lt $MinAlign) { $ok = $false; $reason = ("PT_LOAD < {0}" -f $MinAlign); break }
    }
  }

  return New-Object PSObject -Property @{
    File       = $SoPath
    Alignments = $aligns
    OK         = $ok
    Reason     = $reason
  }
}

# --- Controlli preliminari ---
if (!(Test-Path -LiteralPath $Readobj)) { throw ("llvm-readobj.exe non trovato: {0}" -f $Readobj) }
if (!(Test-Path -LiteralPath $Path))    { throw ("Percorso non trovato: {0}" -f $Path) }

$AllLines = New-Object System.Collections.ArrayList
$FailList = New-Object System.Collections.ArrayList

# --- Determina i file da analizzare (SOLO arm64-v8a) ---
$TempRoot = $null
$soFiles = @()

if ((Get-Item -LiteralPath $Path).PSIsContainer) {
  $soFiles = Get-ChildItem -Recurse -Path $Path -Filter *.so | Where-Object { $_.FullName -match "arm64-v8a" } | Select-Object -Expand FullName
} else {
  $ext = [IO.Path]::GetExtension($Path).ToLower()
  if ($ext -eq ".so") {
    if ($Path -match "arm64-v8a") { $soFiles = ,(Resolve-Path -LiteralPath $Path).Path }
  } elseif ($ext -in @(".aar",".apk",".aab",".zip")) {
    $TempRoot = Join-Path $env:TEMP ("check16kb_" + (Get-Random))
    New-Item -ItemType Directory -Path $TempRoot | Out-Null
    $ZipCopy = Join-Path $TempRoot "archive.zip"
    Copy-Item -LiteralPath $Path -Destination $ZipCopy -Force
    Expand-Archive -LiteralPath $ZipCopy -DestinationPath $TempRoot -Force
    $soFiles = Get-ChildItem -Recurse -Path $TempRoot -Filter *.so | Where-Object { $_.FullName -match "arm64-v8a" } | Select-Object -Expand FullName
  } else {
    throw ("Estensione non supportata: {0}" -f $ext)
  }
}

if (!$soFiles -or $soFiles.Count -eq 0) {
  if ($TempRoot) { Remove-Item -Recurse -Force $TempRoot -ErrorAction SilentlyContinue }
  throw "Nessuna .so trovata nella cartella arm64-v8a."
}

# --- Analisi ---
foreach ($so in $soFiles) {
  $res = Get-SoResult -SoPath $so -ReadobjExe $Readobj -MinAlign $MinAlign

  [void]$AllLines.Add($res.File)
  [void]$AllLines.Add(("    PT_LOAD Alignments: {0}" -f $(if($res.Alignments){ ($res.Alignments -join ', ') }else{'<none>' })))
  if ($res.OK) {
    [void]$AllLines.Add(("    Risultato: OK (>= {0})" -f $MinAlign))
  } else {
    $msg = "    Risultato: NON allineato"
    if ($res.Reason) { $msg += " - " + $res.Reason }
    [void]$AllLines.Add($msg)
    [void]$FailList.Add($res.File)
  }
  [void]$AllLines.Add("")
}

# --- Pulizia e report ---
if ($TempRoot) { Remove-Item -Recurse -Force $TempRoot -ErrorAction SilentlyContinue }
if ($ReportPath) { $AllLines | Out-File -FilePath $ReportPath -Encoding UTF8 }

# --- Output finale ---
if ($FailList.Count -eq 0) {
  Write-Host ("OK: tutte le .so in arm64-v8a hanno PT_LOAD con Alignment >= {0}." -f $MinAlign)
  if ($ReportPath) { Write-Host ("Report salvato in: {0}" -f $ReportPath) }
  exit 0
} else {
  Write-Host ("KO: file arm64-v8a non conformi (almeno un PT_LOAD < {0}):" -f $MinAlign)
  $FailList | ForEach-Object { Write-Host (" - {0}" -f $_) }
  if ($ReportPath) { Write-Host ("Report completo in: {0}" -f $ReportPath) }
  exit 2
}

Save the same in a text file named check-16kb.ps1 ( in attachment if you want )
P.S.: Written with the help of chatgpt and after a few things to fix it works
Bye
 

Attachments

  • check-16kb.zip
    2 KB · Views: 84
Last edited:

mcqueccu

Well-Known Member
Licensed User
Longtime User
Hi did you find a solution to determine what was not compliant using the script or otherwise?
EDIT: Check the Enhanced Script which checks everything:

I use Android Emulator setup with 16kb Support, so when you run the app and its not compatible, you get a popup lilke this.

1759836824067.png



EMULATOR WILL SHOW
1759838534366.png



I also analyze the script with ChatGPT, and it says,


B4X:
I see what’s happening. Your script is only checking the PT_LOAD alignment values from llvm-readobj, which is necessary but not sufficient for Android 16KB compatibility.
The emulator warning is likely triggered because Android 16’s dynamic linker (ld-android) also validates:
Segment alignment (PT_LOAD ≥ 16384) → your script covers this. ✅
ELF header field p_align and p_vaddr/p_offset consistency → not all segments pass just because p_align looks okay. ⚠️
Relocation sections (.rel/.rela) alignment.
Whether .note.gnu.property includes the ANDROID, 16K page size tag introduced in newer NDKs.
That’s why you see OK in your script but still get emulator warnings.
 
Last edited:
Upvote 0
Top