What does the microphone need from Android 17 to keep capturing? #81
Labels
No labels
needs-info
needs-triage
ready-for-agent
ready-for-human
v2
wayfinder:grilling
wayfinder:map
wayfinder:prototype
wayfinder:research
wayfinder:task
wayfinder:ticket
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
aiko/denpa#81
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Question
What foreground service, permissions and runtime dance does the microphone actually need on Android 17 / SDK 37, on the Pixel 7 Pro, for a held push-to-talk capture that survives the screen going off?
Graduated from the fog on the wayfinder map: "What foreground service the microphone actually needs, on Android 17." With the overlay pal ruled out by #47 and screen capture deferred to v2 by #45, the mic is the only foreground service v1 needs — nothing competes for the process. What is not known is what the platform now demands of it.
The phone runs SDK 37, newer than any source #44 could reach, and every release since 14 has tightened these rules:
foregroundServiceType, theFOREGROUND_SERVICE_MICROPHONEpermission, the while-in-use restrictions on starting one from the background, and the rules about which capture can continue once the app is not visible.Answer at least:
android:foregroundServiceTypevalues a mic capture needs on SDK 37, and which permissions each one now demands in the manifest.AudioRecordwhen the screen turns off without one.denpa's existing manifest, which already declares a service for the disabled overlay (#23).This is a research ticket: the answer is documentation and platform behaviour, not a change to this repo. Record it as a resolution comment with sources; the build work it implies gets its own ticket.
Direct answer: a held push-to-talk capture on SDK 37 needs one service with
foregroundServiceType="microphone", declaringFOREGROUND_SERVICE+FOREGROUND_SERVICE_MICROPHONEon top of theRECORD_AUDIOalready there, and it must be started while the app is visible. The on-screen key satisfies that; a global hardware key from a backgrounded app does not.No foreground service is needed to capture while the app is visible. It exists entirely to survive the screen going off — and it can never be started once the screen is already off.
1. Type and permissions
android:foregroundServiceType="microphone"is the only type capture needs (service types):FOREGROUND_SERVICE_MICROPHONE, plus the baseFOREGROUND_SERVICEevery foreground service needs (declare)startForeground()constant:FOREGROUND_SERVICE_TYPE_MICROPHONERECORD_AUDIOgrantedA type passed to
startForeground()that disagrees with the manifest throwsMissingForegroundServiceTypeException; missingRECORD_AUDIOat service creation throwsSecurityException.No
specialUse, nomediaPlayback. Themicrophonetype carries no runtime timeout — Android 15's six-hour cap covers onlydataSyncandmediaProcessing(timeouts). A long hold is not the problem.2. Required while visible?
No.
RECORD_AUDIOis a while-in-use permission and a visible activity satisfies while-in-use. That matches what this repo already observes:MicRecorder.startCaptureopensAudioRecordwith no service at all and works, as long as the screen is on.3. What may legally start it
Two gates, and the second is the one that bites.
Background-start restrictions have a long exemption list — transitioning from user-visible, notification or widget interaction, high-priority FCM, exact alarm,
SYSTEM_ALERT_WINDOW, and more (bg-start).While-in-use restrictions override them. From the same page: an app wanting a foreground service that needs while-in-use permissions "cannot create the service while the app is in the background, even if the app falls into one of the exemptions from background start restrictions." That second list is short: a system component, app-widget interaction, notification interaction, a
PendingIntentfrom another visible app, a device-owner DPC, aVoiceInteractionServiceprovider, orSTART_ACTIVITIES_FROM_BACKGROUND.The trap named explicitly on that page:
checkSelfPermission()returnsPERMISSION_GRANTEDfor a while-in-use permission even when backgrounded — it means "granted while in use", not "usable now". TheContextCompat.checkSelfPermissionguard inMicRecorder.startCapturehas exactly this shape: it will pass, and thestartForegroundafter it will still throw.A global hardware-key press while backgrounded is on neither list. Media buttons reach a backgrounded app only through
MediaSession(media buttons), and media keys are absent from the while-in-use exemptions. See Unverified.4. Screen off, no service, capture in flight
It does not throw, does not short-read, does not stop. It returns full buffers of zeros — digital silence indistinguishable from a quiet room.
RECORD_AUDIOis a foreground app-op, so losing visibility loses the op; Android 11's page says a background-started foreground service "cannot access the microphone or camera" (foreground services privacy) without saying what arrives instead.The zeros are this repo's own Pixel 7 Pro measurement —
docs/android-build.md's app-op section, andMicRecorder'saudit, which logs a one-shot verdict on the opening seconds precisely so nobody rediscovers it.adb shell cmd appops get works.aiko.ollvt.debug RECORD_AUDIOshowsforegroundwith a freshrejectTimewhen it happens.5. Behaviour changes that break an older-targeting build
SYSTEM_ALERT_WINDOWexempts a background start only with a currently visible overlay;BOOT_COMPLETEDreceivers can no longer launch some foreground service types.SHORT_SERVICE" for background audio interaction; apps targeting 37 additionally need that service to hold while-in-use capability (bg-audio, behavior changes 17). Scope is playback, audio focus and volume — not capture. Failures are silent by design: playback silenced with no exception,requestAudioFocus()returningAUDIOFOCUS_REQUEST_FAILED. That is her output path, not the mic. Diagnostics:adb shell cmd audio set-enable-hardening throwturns the silent failures into exceptions, andadb dumpsys audioreportslevel: full(service present but no while-in-use) orlevel: partial(no service).AudioRecord, themicrophonetype, orRECORD_AUDIO.build.gradle.ktshastargetSdk = 36and is compliant; moving to 37 is what would switch on the stricter audio bar.What this implies for Denpa
The manifest does not conflict, but it is incomplete. It declares
RECORD_AUDIO,FOREGROUND_SERVICE,FOREGROUND_SERVICE_SPECIAL_USE,SYSTEM_ALERT_WINDOW,POST_NOTIFICATIONSand one<service>—.overlay.OverlayService,specialUse, from#23. A second<service>with typemicrophonesits alongside it with no interaction. Missing:FOREGROUND_SERVICE_MICROPHONEand the service element.Do not merge
microphoneontoOverlayServiceasspecialUse|microphone. With the overlay ruled out by #47 that resurrects a component whose point is gone, and ties the mic's lifetime to overlay code paths that stop the service on permission revocation.The start path is nearly right already.
use-receiver-chrome.tsdrives push-to-talk from an on-screen key in the receiver chrome, so the press happens while the activity is visible — the one condition under which amicrophoneservice may be created, and the one that grants it while-in-use. The change is: start the service before openingAudioRecord, stop it on release.MicRecorder.startCapture/stopCaptureis the seam;mic_startinsrc-tauri/src/audio/android.rsalready routes both throughwith_recorderand already treats a refusal as a visible error rather than a log, which is what aSecurityExceptionfromstartForegroundneeds.A backgrounded global-hotkey push-to-talk is not reachable on this platform as designed. The sanctioned shape is the foreground-service notification carrying the action — notification interaction is on both exemption lists.
OverlayService's own design comment already articulates that idea ("the notification as a surface rather than a tax"). Its own ticket.#44's silent-zeros failure gains a second cause. Once a service exists, a capture reading zeros means the service failed to start or lacks while-in-use, not that the screen is off.MicRecorder.audit's warning text will want revisiting then.Unverified
AudioRecordreturns when visibility is lost. No primary source states it; the zeros are this repo's own measurement, corroborated only by secondary sources.MediaSessionmedia-button event can start amicrophoneservice from the background. The bg-audio page lists media key events among things granting while-in-use to a background-started service; the bg-start page's exemption list does not include them. The two appear to disagree, and the bg-audio list is framed around playback. Untested.microphonetype orAudioRecord. Neither behaviour-change page mentions them. Absence of a documented change is not proof; AOSP release notes were not read.POST_NOTIFICATIONSdenial blocks the service from starting, as opposed to hiding its notification.