A permission cannot be added to an installed app quietly. It lives in AndroidManifest.xml, inside the APK, and it is one of the few things about a package you can audit without running it. That makes the manifest the cheapest useful check available: one command, no install, no account, no emulator.
This walkthrough uses aapt2 and adb against the current Hesgoal build, package com.vvstreams.app, version 3.3. The commands work on any APK. The risk table applies specifically to this one.
Get the tools
aapt2 ships with the Android SDK build tools. If you have Android Studio, the binary is under build-tools/<version>/aapt2.exe on Windows or build-tools/<version>/aapt2 on macOS and Linux. Add that directory to PATH, or call the binary by full path.
adb ships with the platform tools. You only need it for the on-device checks; the manifest checks run entirely offline. Verify both are available:
aapt2 version
adb version
If you do not want to install the SDK, the command-line tools package from Android Developers includes both aapt2 and adb, and is smaller than the full IDE.
Read the declared permissions
aapt2 dump permissions hesgoal.apk
The output is a flat list:
package: com.vvstreams.app
uses-permission: name='android.permission.INTERNET'
uses-permission: name='android.permission.ACCESS_NETWORK_STATE'
uses-permission: name='android.permission.SYSTEM_ALERT_WINDOW'
uses-permission: name='android.permission.REQUEST_INSTALL_PACKAGES'
uses-permission: name='android.permission.FOREGROUND_SERVICE'
uses-permission: name='android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK'
uses-permission: name='android.permission.WAKE_LOCK'
uses-permission: name='com.google.android.finsky.permission.BIND_GET_INSTALL_REFERRER_SERVICE'
uses-permission: name='com.google.android.gms.permission.AD_ID'
uses-permission: name='android.permission.ACCESS_ADSERVICES_ATTRIBUTION'
uses-permission: name='android.permission.ACCESS_ADSERVICES_AD_ID'
That is eleven declarations. Anything more in a file you downloaded is a difference worth explaining.
Read the rest of the manifest
aapt2 dump badging prints the package identity and the features the package expects:
aapt2 dump badging hesgoal.apk
Look for these lines:
package: name='com.vvstreams.app' versionName='3.3'sdkVersion:'24'andtargetSdkVersion:'37'application-label:'Hesgoal'launchable-activity:for the entry pointnative-code:for the ABIs includeduses-permission:repeated for each declaration
badging also reports application-debuggable when the flag is set. It should not appear; a debuggable release build allows run-as access to app data and is a genuine finding.
For attributes that badging omits, dump the binary XML directly:
aapt2 dump xmltree --file AndroidManifest.xml hesgoal.apk
Filter the output for the values that matter:
aapt2 dump xmltree --file AndroidManifest.xml hesgoal.apk | Select-String "debuggable|allowBackup|usesCleartextTraffic|exported"
On macOS or Linux, replace Select-String with grep -E. The interesting attributes are android:debuggable, android:allowBackup, android:usesCleartextTraffic, and android:exported on every component with an intent filter. This build sets usesCleartextTraffic=true and has no networkSecurityConfig, which is why HTTP sources can load.
Check what was actually granted
The manifest says what the app asks for. The device says what it got. With a phone connected and USB debugging enabled:
adb shell dumpsys package com.vvstreams.app
Search the output for granted=true and requested permissions. Normal permissions are granted at install with no prompt. Dangerous permissions show as denied until the user approves them. This build declares no dangerous permissions, so the runtime permission screen will be empty or nearly so.
For the two appop-gated capabilities, query the appops service directly:
adb shell appops get com.vvstreams.app SYSTEM_ALERT_WINDOW
adb shell appops get com.vvstreams.app REQUEST_INSTALL_PACKAGES
The result is allow, deny, default or ignore. A default for overlay usually means the user has never been asked and the app cannot draw over other apps. Settings screens can lag behind the actual appop state; the query does not.
You can revoke either without touching the app:
adb shell appops set com.vvstreams.app SYSTEM_ALERT_WINDOW deny
adb shell appops set com.vvstreams.app REQUEST_INSTALL_PACKAGES deny
Revoking overlay does not break playback. Revoking install-packages only removes the ability to prompt for another APK, which matters if an in-app updater is part of your reason for installing.
Three classes of permission
The count is misleading on its own. Android permissions fall into three groups, and each is granted through a different mechanism.
| Class | Grant mechanism | User prompt | Example |
|---|---|---|---|
| Normal | Automatic at install | None | INTERNET, WAKE_LOCK |
| Dangerous (runtime) | User dialog, revocable in Settings | Yes | CAMERA, READ_CONTACTS |
| Appop / special | Settings toggle or adb, checked per operation | Sometimes | SYSTEM_ALERT_WINDOW |
A package with forty normal permissions produces zero prompts. A package with one appop permission can draw over your bank app. Counting prompts is not a security metric.
Risk table for the eleven declarations
| Permission | Class | What it enables | Risk | Recommendation |
|---|---|---|---|---|
INTERNET | Normal | Open sockets to any host | Low | Required |
ACCESS_NETWORK_STATE | Normal | Detect connectivity before playback | Low | Allow |
WAKE_LOCK | Normal | Keep CPU awake during playback | Low | Allow |
FOREGROUND_SERVICE | Normal | Keep a service running in background | Low | Allow |
FOREGROUND_SERVICE_MEDIA_PLAYBACK | Normal | Declare that service as media playback | Low | Allow |
BIND_GET_INSTALL_REFERRER_SERVICE | Normal, granted by Play | Read install attribution value | Low | Allow; ad-related |
AD_ID | Normal | Read the resettable advertising ID | Medium | Reset or opt out in Settings |
ACCESS_ADSERVICES_ATTRIBUTION | Normal | Privacy Sandbox attribution API | Medium | Tied to ad SDK |
ACCESS_ADSERVICES_AD_ID | Normal | Privacy Sandbox ad ID API | Medium | Tied to ad SDK |
REQUEST_INSTALL_PACKAGES | Appop | Prompt installation of another APK | Medium | Deny |
SYSTEM_ALERT_WINDOW | Appop | Draw over other apps | High | Deny |
The table is not a verdict on intent. It is a mapping from declaration to capability. SYSTEM_ALERT_WINDOW is high risk because the capability itself is dangerous in any package, including one you trust today.
What the permission list does not tell you
A manifest audit is a boundary check, not a behaviour report. It cannot tell you:
- which hosts the app contacts, or over which protocol;
- what the ad SDK does with the advertising ID after it reads it;
- whether a server-side configuration changes the interface after install;
- whether a bundled third-party library contains vulnerable code.
For those questions you need traffic inspection, an SDK inventory or a code review, and each has limits. The security page states which of these checks were performed on this build and which were not. The app privacy page covers Firebase Analytics, AdMob and the cleartext-traffic finding in detail.
Diff the list across versions
The most useful audit habit is comparison. Save the permission output for each version you install:
aapt2 dump permissions hesgoal-3.3.apk > permissions-3.3.txt
When a new build arrives, run the same command and diff the files. A new dangerous permission or a new appop request in an update is more informative than any absolute count, because it shows what changed in capability rather than what changed in marketing copy.
Record the version code alongside the list. A file claiming version 3.3 with a different code is a different artifact.
Where to go next
Confirm the file before you audit it. The hash guide covers the SHA-256 comparison, and the signature explainer covers the certificate check. Both are prerequisites: auditing the permissions of an unidentified file tells you about a package you may not want.
The full permission walkthrough with plain-language explanations is on the safety page. Installation steps, including when each prompt appears, are in the install guide. The verified file and its published values are on the download page.