From f705805843796dc87c8f3f3de06d2a7e1e69b566 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Fri, 17 Oct 2025 10:36:40 +0200 Subject: [PATCH 1/6] fix foreground service permission crash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit when record_audio permission was not granted, this crash appeared because foreground service must only be started with the granted permission: 2025-10-17 09:56:01.459 14445-14445 AndroidRuntime com.nextcloud.talk2 E FATAL EXCEPTION: main (Ask Gemini) Process: com.nextcloud.talk2, PID: 14445 java.lang.RuntimeException: Unable to start service com.nextcloud.talk.services.CallForegroundService@a9cff99 with Intent { cmp=com.nextcloud.talk2/com.nextcloud.talk.services.CallForegroundService (has extras) }: java.lang.SecurityException: Starting FGS with type microphone callerApp=ProcessRecord{1b5bf24 14445:com.nextcloud.talk2/u0a397} targetSDK=35 requires permissions: all of the permissions allOf=true [android.permission.FOREGROUND_SERVICE_MICROPHONE] any of the permissions allOf=false [android.permission.CAPTURE_AUDIO_HOTWORD, android.permission.CAPTURE_AUDIO_OUTPUT, android.permission.CAPTURE_MEDIA_OUTPUT, android.permission.CAPTURE_TUNER_AUDIO_INPUT, android.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT, android.permission.RECORD_AUDIO] and the app must be in the eligible state/exemptions to access the foreground only permission at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:5295) at android.app.ActivityThread.-$$Nest$mhandleServiceArgs(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2580) at android.os.Handler.dispatchMessage(Handler.java:112) at android.os.Looper.loopOnce(Looper.java:268) at android.os.Looper.loop(Looper.java:384) at android.app.ActivityThread.main(ActivityThread.java:8921) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:907) Caused by: java.lang.SecurityException: Starting FGS with type microphone callerApp=ProcessRecord{1b5bf24 14445:com.nextcloud.talk2/u0a397} targetSDK=35 requires permissions: all of the permissions allOf=true [android.permission.FOREGROUND_SERVICE_MICROPHONE] any of the permissions allOf=false [android.permission.CAPTURE_AUDIO_HOTWORD, android.permission.CAPTURE_AUDIO_OUTPUT, android.permission.CAPTURE_MEDIA_OUTPUT, android.permission.CAPTURE_TUNER_AUDIO_INPUT, android.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT, android.permission.RECORD_AUDIO] and the app must be in the eligible state/exemptions to access the foreground only permission at android.os.Parcel.createExceptionOrNull(Parcel.java:3242) at android.os.Parcel.createException(Parcel.java:3226) at android.os.Parcel.readException(Parcel.java:3209) at android.os.Parcel.readException(Parcel.java:3151) at android.app.IActivityManager$Stub$Proxy.setServiceForeground(IActivityManager.java:7326) at android.app.Service.startForeground(Service.java:863) at com.nextcloud.talk.services.CallForegroundService.onStartCommand(CallForegroundService.kt:38) at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:5277) at android.app.ActivityThread.-$$Nest$mhandleServiceArgs(Unknown Source:0)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2580)  at android.os.Handler.dispatchMessage(Handler.java:112)  at android.os.Looper.loopOnce(Looper.java:268)  at android.os.Looper.loop(Looper.java:384)  at android.app.ActivityThread.main(ActivityThread.java:8921)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:907)  Caused by: android.os.RemoteException: Remote stack trace: at com.android.server.am.ActiveServices.validateForegroundServiceType(ActiveServices.java:2921) at com.android.server.am.ActiveServices.setServiceForegroundInnerLocked(ActiveServices.java:2605) at com.android.server.am.ActiveServices.setServiceForegroundLocked(ActiveServices.java:1859) at com.android.server.am.ActivityManagerService.setServiceForeground(ActivityManagerService.java:14552) at android.app.IActivityManager$Stub.onTransact$setServiceForeground$(IActivityManager.java:12183) Signed-off-by: Marcel Hibbe --- .../main/java/com/nextcloud/talk/activities/CallActivity.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt index 7f914c2feb8..3155fd9a777 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt @@ -387,8 +387,6 @@ class CallActivity : CallBaseActivity() { setContentView(binding!!.root) hideNavigationIfNoPipAvailable() processExtras(intent.extras!!) - CallForegroundService.start(applicationContext, conversationName, intent.extras) - conversationUser = currentUserProvider.currentUser.blockingGet() credentials = ApiUtils.getCredentials(conversationUser!!.username, conversationUser!!.token) @@ -1039,6 +1037,7 @@ class CallActivity : CallBaseActivity() { checkRecordingConsentAndInitiateCall() if (permissionUtil!!.isMicrophonePermissionGranted()) { + CallForegroundService.start(applicationContext, conversationName, intent.extras) if (!microphoneOn) { onMicrophoneClick() } From 78adb4ee627045d605b3416f3008ad4fd574f133 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Mon, 20 Oct 2025 15:48:30 +0200 Subject: [PATCH 2/6] remove FOREGROUND_SERVICE_TYPE_PHONE_CALL to resolveForegroundServiceType This should resolve the (misleading?) lint error: To call Service.startForeground(), the element of manifest file must have the foregroundServiceType attribute specified and FOREGROUND_SERVICE_TYPE_PHONE_CALL is only for default dialer apps which is not needed in our case. Also, avoid android version complains regarding service types: Field requires API level 30 (current min is 26): android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_CAMERA Signed-off-by: Marcel Hibbe --- app/src/main/AndroidManifest.xml | 2 +- .../talk/services/CallForegroundService.kt | 23 +++++++++++-------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4cf4bc0ed67..14b80432d83 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -306,7 +306,7 @@ + android:foregroundServiceType="microphone|camera" /> = Build.VERSION_CODES.R) { + serviceType = serviceType or ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE + + val isVoiceOnlyCall = callExtras?.getBoolean(KEY_CALL_VOICE_ONLY, false) ?: false + val canPublishVideo = callExtras?.getBoolean( + KEY_PARTICIPANT_PERMISSION_CAN_PUBLISH_VIDEO, + false + ) ?: false + + if (!isVoiceOnlyCall && canPublishVideo) { + serviceType = serviceType or ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA + } } - return serviceType } From b2c506fc4ea3453c82037a5bff19c33b3a11b81f Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Mon, 20 Oct 2025 15:50:44 +0200 Subject: [PATCH 3/6] change analysis jvmargs=-Xmx5g to jvmargs=-Xmx1g just a test if this fixes the "Error: The operation was canceled." Signed-off-by: Marcel Hibbe --- .github/workflows/analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/analysis.yml b/.github/workflows/analysis.yml index ae87a05fd15..9d14570f44b 100644 --- a/.github/workflows/analysis.yml +++ b/.github/workflows/analysis.yml @@ -71,7 +71,7 @@ jobs: run: | mkdir -p "$HOME/.gradle" { - echo "org.gradle.jvmargs=-Xmx5g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -XX:+UseParallelGC -XX:MaxMetaspaceSize=1g" + echo "org.gradle.jvmargs=-Xmx1g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -XX:+UseParallelGC -XX:MaxMetaspaceSize=1g" echo "org.gradle.configureondemand=true" echo "kapt.incremental.apt=true" } > "$HOME/.gradle/gradle.properties" From 705ba89d984fa85c340d2bf984822c7f2a89457f Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Wed, 22 Oct 2025 10:08:06 +0200 Subject: [PATCH 4/6] change analysis jvmargs=-Xmx5g to jvmargs=-Xmx3g just a test if this fixes the "Error: The operation was canceled." Signed-off-by: Marcel Hibbe --- .github/workflows/analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/analysis.yml b/.github/workflows/analysis.yml index 9d14570f44b..bbe92b1104b 100644 --- a/.github/workflows/analysis.yml +++ b/.github/workflows/analysis.yml @@ -71,7 +71,7 @@ jobs: run: | mkdir -p "$HOME/.gradle" { - echo "org.gradle.jvmargs=-Xmx1g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -XX:+UseParallelGC -XX:MaxMetaspaceSize=1g" + echo "org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -XX:+UseParallelGC -XX:MaxMetaspaceSize=1g" echo "org.gradle.configureondemand=true" echo "kapt.incremental.apt=true" } > "$HOME/.gradle/gradle.properties" From 633cfb0ae6c619cb94d37867e35e29a32dc00f7f Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Wed, 22 Oct 2025 13:38:10 +0200 Subject: [PATCH 5/6] modify foregroundServiceType to be analyzable for lint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To devs it's the same, but the change appeases Lint because it fits the analyzer’s limited static-flow model If this does not work out again, last quite bad option here may be to suppress Also remove useless check for version Q Signed-off-by: Marcel Hibbe --- .../nextcloud/talk/services/CallForegroundService.kt | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/services/CallForegroundService.kt b/app/src/main/java/com/nextcloud/talk/services/CallForegroundService.kt index 7e44c7d02b4..f8cea7fd9db 100644 --- a/app/src/main/java/com/nextcloud/talk/services/CallForegroundService.kt +++ b/app/src/main/java/com/nextcloud/talk/services/CallForegroundService.kt @@ -35,11 +35,8 @@ class CallForegroundService : Service() { val notification = buildNotification(conversationName, callExtras) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - startForeground( - NOTIFICATION_ID, - notification, - resolveForegroundServiceType(callExtras) - ) + val foregroundServiceType = resolveForegroundServiceType(callExtras) + startForeground(NOTIFICATION_ID, notification, foregroundServiceType) } else { startForeground(NOTIFICATION_ID, notification) } @@ -90,10 +87,6 @@ class CallForegroundService : Service() { } private fun resolveForegroundServiceType(callExtras: Bundle?): Int { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { - return 0 - } - var serviceType = 0 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { serviceType = serviceType or ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE From cb458bce5141787632e511fbd81cb978b00c6501 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Wed, 22 Oct 2025 14:01:55 +0200 Subject: [PATCH 6/6] suppress ForegroundServiceType warning for now i give up to understand the warning "To call Service.startForeground(), the element of manifest file must have the foregroundServiceType attribute specified" From my pov everything is correct! Signed-off-by: Marcel Hibbe --- .../java/com/nextcloud/talk/services/CallForegroundService.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/nextcloud/talk/services/CallForegroundService.kt b/app/src/main/java/com/nextcloud/talk/services/CallForegroundService.kt index f8cea7fd9db..f6a53d84871 100644 --- a/app/src/main/java/com/nextcloud/talk/services/CallForegroundService.kt +++ b/app/src/main/java/com/nextcloud/talk/services/CallForegroundService.kt @@ -29,6 +29,7 @@ class CallForegroundService : Service() { override fun onBind(intent: Intent?): IBinder? = null + @Suppress("ForegroundServiceType") override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { val conversationName = intent?.getStringExtra(EXTRA_CONVERSATION_NAME) val callExtras = intent?.getBundleExtra(EXTRA_CALL_INTENT_EXTRAS)