How to grant an app a permission that isn't in its manifest for audio recording?


Question

Non rooted Moto G6 Play running Android 9.



I'm using Termux and would like to use Sox's rec command to record audio from the terminal. Unfortunately, since Termux doesn't request the mic permission, it just records silence. I can't grant Termux the permission in Settings because...well, it doesn't request it. It's not in the app manifest, therefore Android (understandably) assumes it wouldn't know what to do with the permission if it had it and doesn't list "record audio" as an option.



Is there a way I can force Android to grant an app a permission it never asked for?


Answer

Not possible without root but even with root SoX recording might not work.






Android Manifest Permissions



Android permission system has different Protection Levels (1, 2); Normal permissions are granted to any app without user interaction while Signature|Privileged (SignatureOrSystem) permissions (whitelisted in /etc/permissions/privapp-permissions-*.xml) are granted only to system apps. Both are granted when app is installed or on first startup (if system app) and configuration is saved in /data/system/packages.xml file. Some signature permissions can be granted to non-system apps after user's approval using appops.



Dangerous permissions are those which require user's approval to be granted or denied. User's choice is saved in /data/system/users/<User_ID>/runtime-permissions.xml where device owner's User_ID is 0 (don't confuse it with UNIX DAC's UID).



Most of the manifest permissions are enforced by Android framework (system_server) but some are mapped to GIDs; hence enforced by kernel. Permission to GID mapping is stored in /data/system/packages.list.



How to Grant an App Unrequested Permission



You can modify above mentioned files to grant a permission which isn't requested by an app in its Manifest. I haven't tested with all permissions but this trick works (at least up to Pie) because Android framework doesn't verify the saved permission configuration vs. apps manifest files on every reboot (may be the changes are reverted back to actual during a scheduled maintenance task or when some app is installed or updated; I'm not sure).



In our case we want to grant android.permission.RECORD_AUDIO to Termux which is a dangerous permission, so this is how you should edit your runtime-permissions.xml followed by an immediate reboot:



<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<runtime-permissions fingerprint="...">
...
<shared-user name="com.termux">
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="0" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="0" />
<item name="android.permission.RECORD_AUDIO" granted="true" flags="0" />
</shared-user>
...
</runtime-permissions>


To confirm:



~$ pm dump com.termux | grep -A3 'runtime permissions:'
runtime permissions:
android.permission.READ_EXTERNAL_STORAGE: granted=true
android.permission.WRITE_EXTERNAL_STORAGE: granted=true
android.permission.RECORD_AUDIO: granted=true





Why SoX won't work?



That said, still SoX won't be able to record audio because (AFAIK) it's not using Android's Java APIs (android.media) or native APIs (aaudio/opensles). It uses ALSA/OSS driver directly or through PulseAudio which needs direct access to device interfaces in /dev/snd/ or /dev/{ audio,dsp* } and proc tree in /proc/asound/. For details see Android Audio Architecture.



However direct kernel level access isn't a norm on Android, so you need root access. Apps with android.permission.MANAGE_VOICE_KEYPHRASES are allowed to read /dev/snd/* devices. It's a privileged signature level permission which is mapped to GID audio (1005). You can edit packages.xml to get this permission granted:




 <package name="com.termux" ... >
<perms>
<item name="android.permission.MANAGE_VOICE_KEYPHRASES" granted="true" flags="0" />
</perms>
</package>

<shared-user name="com.termux" ...>
<perms>
<item name="android.permission.MANAGE_VOICE_KEYPHRASES" granted="true" flags="0" />
</perms>
</shared-user>


And packages.list:



com.termux ... 0 /data/user/0/com.termux default:targetSdkVersion=28... 1005,3003


But SELinux allows only privileged apps (having context priv_app) to read files in /dev/snd while /proc/asound/ isn't readable by apps at all, so you need to patch sepolicy as well.



And even after that, configuring SoX to use ALSA/OSS/PA is up to you.






Non-Root Solutions



Instead of using ALSA directly, PulseAudio can also be configured to stream audio over TCP or UDP or UNIX sockets. That's how media playback works on Termux. See this issue. However capturing audio only work through Android APIs. You can install termux-api package to use termux-microphone-record command for audio recording. It uses MediaRecorder class of Java API, or you may consider modifying SoX source to use Android's native APIs.






RELATED




Topics


2D Engines   3D Engines   9-Patch   Action Bars   Activities   ADB   Advertisements   Analytics   Animations   ANR   AOP   API   APK   APT   Architecture   Audio   Autocomplete   Background Processing   Backward Compatibility   Badges   Bar Codes   Benchmarking   Bitmaps   Bluetooth   Blur Effects   Bread Crumbs   BRMS   Browser Extensions   Build Systems   Bundles   Buttons   Caching   Camera   Canvas   Cards   Carousels   Changelog   Checkboxes   Cloud Storages   Color Analysis   Color Pickers   Colors   Comet/Push   Compass Sensors   Conferences   Content Providers   Continuous Integration   Crash Reports   Credit Cards   Credits   CSV   Curl/Flip   Data Binding   Data Generators   Data Structures   Database   Database Browsers   Date &   Debugging   Decompilers   Deep Links   Dependency Injections   Design   Design Patterns   Dex   Dialogs   Distributed Computing   Distribution Platforms   Download Managers   Drawables   Emoji   Emulators   EPUB   Equalizers &   Event Buses   Exception Handling   Face Recognition   Feedback &   File System   File/Directory   Fingerprint   Floating Action   Fonts   Forms   Fragments   FRP   FSM   Functional Programming   Gamepads   Games   Geocaching   Gestures   GIF   Glow Pad   Gradle Plugins   Graphics   Grid Views   Highlighting   HTML   HTTP Mocking   Icons   IDE   IDE Plugins   Image Croppers   Image Loaders   Image Pickers   Image Processing   Image Views   Instrumentation   Intents   Job Schedulers   JSON   Keyboard   Kotlin   Layouts   Library Demos   List View   List Views   Localization   Location   Lock Patterns   Logcat   Logging   Mails   Maps   Markdown   Mathematics   Maven Plugins   MBaaS   Media   Menus   Messaging   MIME   Mobile Web   Native Image   Navigation   NDK   Networking   NFC   NoSQL   Number Pickers   OAuth   Object Mocking   OCR Engines   OpenGL   ORM   Other Pickers   Parallax List   Parcelables   Particle Systems   Password Inputs   PDF   Permissions   Physics Engines   Platforms   Plugin Frameworks   Preferences   Progress Indicators   ProGuard   Properties   Protocol Buffer   Pull To   Purchases   Push/Pull   QR Codes   Quick Return   Radio Buttons   Range Bars   Ratings   Recycler Views   Resources   REST   Ripple Effects   RSS   Screenshots   Scripting   Scroll Views   SDK   Search Inputs   Security   Sensors   Services   Showcase Views   Signatures   Sliding Panels   Snackbars   SOAP   Social Networks   Spannable   Spinners   Splash Screens   SSH   Static Analysis   Status Bars   Styling   SVG   System   Tags   Task Managers   TDD &   Template Engines   Testing   Testing Tools   Text Formatting   Text Views   Text Watchers   Text-to   Toasts   Toolkits For   Tools   Tooltips   Trainings   TV   Twitter   Updaters   USB   User Stories   Utils   Validation   Video   View Adapters   View Pagers   Views   Watch Face   Wearable Data   Wearables   Weather   Web Tools   Web Views   WebRTC   WebSockets   Wheel Widgets   Wi-Fi   Widgets   Windows   Wizards   XML   XMPP   YAML   ZIP Codes