usuario924
Noté una excepción (Firebase Crashlytics) para Pixel 5 y Pixel 4a (ambos en Android 12), ningún otro dispositivo, sucedió solo dos veces, una vez para cada dispositivo.
¿Qué significa? Android 11 y 12 tienen las mismas reglas para trabajar con servicios en primer plano, pero no hay problemas con Android 11. ¿Es un error de Pixel?
Desde Firebase Crashlytics:
Fatal Exception: android.app.ForegroundServiceStartNotAllowedException
startForegroundService() not allowed due to mAllowStartForeground false: service com.*.*/.service.RecorderService
android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel (ForegroundServiceStartNotAllowedException.java:54)
androidx.core.content.ContextCompat.startForegroundService (ContextCompat.java:6)
MyAppPackageHidden.service.RecorderService$Companion.startService (RecorderService.java:2)
MyAppPackageHidden.ui.rec.RecActivity$getConnectionRecorderService$1.onServiceConnected (RecActivity.java:4)
android.app.LoadedApk$ServiceDispatcher.doConnected (LoadedApk.java:2077)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1003)
Fatal Exception: android.app.ForegroundServiceStartNotAllowedException: startForegroundService() not allowed due to mAllowStartForeground false: service MyAppPackageHidden/.service.RecorderService
at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel(ForegroundServiceStartNotAllowedException.java:54)
at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel(ForegroundServiceStartNotAllowedException.java:50)
at android.os.Parcel.readParcelable(Parcel.java:3333)
at android.os.Parcel.createExceptionOrNull(Parcel.java:2420)
at android.os.Parcel.createException(Parcel.java:2409)
at android.os.Parcel.readException(Parcel.java:2392)
at android.os.Parcel.readException(Parcel.java:2334)
at android.app.IActivityManager$Stub$Proxy.startService(IActivityManager.java:5971)
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1847)
at android.app.ContextImpl.startForegroundService(ContextImpl.java:1823)
at android.content.ContextWrapper.startForegroundService(ContextWrapper.java:779)
at androidx.core.content.ContextCompat$Api26Impl.startForegroundService(ContextCompat.java)
at androidx.core.content.ContextCompat.startForegroundService(ContextCompat.java:6)
at MyAppPackageHidden.service.RecorderService$Companion.startService(RecorderService.java:2)
at MyAppPackageHidden.ui.rec.RecActivity$getConnectionRecorderService$1.onServiceConnected(RecActivity.java:4)
at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:2077)
at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:2110)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7838)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
Caused by android.os.RemoteException: Remote stack trace:
at com.android.server.am.ActiveServices.startServiceLocked(ActiveServices.java:691)
at com.android.server.am.ActiveServices.startServiceLocked(ActiveServices.java:616)
at com.android.server.am.ActivityManagerService.startService(ActivityManagerService.java:11839)
at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:2519)
at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2498)
Las aplicaciones destinadas a Android 12 (nivel de API 31) o superior no pueden iniciar servicios en primer plano mientras se ejecutan en segundo plano, excepto en algunos casos especiales. Si una aplicación intenta iniciar un servicio en primer plano mientras se ejecuta en segundo plano y el servicio en primer plano no satisface uno de los casos excepcionales, el sistema genera una excepción ForegroundServiceStartNotAllowedException.
Exenciones de las restricciones de inicio en segundo plano
En las siguientes situaciones, su aplicación puede iniciar servicios en primer plano incluso mientras se ejecuta en segundo plano:
- Su aplicación pasa de un estado visible al usuario, como una actividad.
- Su aplicación puede iniciar una actividad desde el fondo, excepto en el caso de que la aplicación tenga una actividad en la pila de actividades de una tarea existente.
- Su aplicación recibe un mensaje de alta prioridad mediante Firebase Cloud Messaging.
- El usuario realiza una acción en un elemento de la interfaz de usuario relacionado con su aplicación. Por ejemplo, pueden interactuar con una burbuja, notificación, widget o actividad.
- Su aplicación invoca una alarma exacta para completar una acción que solicita el usuario.
- Su aplicación es el método de entrada actual del dispositivo.
- Su aplicación recibe un evento relacionado con la transición del reconocimiento de actividad o geoperimetraje.
- Después de que el dispositivo se reinicia y recibe la acción de intención ACTION_BOOT_COMPLETED, ACTION_LOCKED_BOOT_COMPLETED o ACTION_MY_PACKAGE_REPLACED en un receptor de transmisión.
Para obtener más información, consulte enlace1 enlace2
-
Buena explicación, pero ¿cuál es la solución?
– Shailendra Madda
14/04/2022 a las 17:23
-
Tengo
foregroundServiceType="mediaPlayback"
declarado en mi manifiesto, y el servicio solo se inicia después de hacer clic en la notificación o en los botones de reproducción en mi aplicación, por lo que espero que funcione. Sin embargo, todavía tengo un par de cientos de fallas cada mes, esta es una de las áreas más misteriosas que hay en Android.– avalancha
4 de agosto de 2022 a las 8:02
-
@avalancha, ¿alguna vez te diste cuenta de esto? Tengo una situación similar.
– casolorz
8 oct 2022 a las 14:24
-
Absolutamente no. Esta es una de las áreas donde Google nos deja pasar el rato para secarnos por completo.
– avalancha
15 oct 2022 a las 16:12
-
Descubrí que si su aplicación intenta iniciar su servicio FG, pero se interrumpe y se pone en segundo plano debido a la acción del usuario, como responder una llamada (básicamente cualquier cosa que haga BG su aplicación), se encontrará con este mismo error. porque estaba ejecutando
startForeground(notificationId, notification);
dentro del servicio, se eliminó todo el proceso.– Dan Davis
13 de noviembre de 2022 a las 17:11
Anteriormente estábamos usando Service
para ejecutar tareas en segundo plano, como la copia de seguridad de datos, la configuración de notificaciones de recordatorio, etc. Y el código para invocar el servicio antes será el siguiente
Intent serviceIntent = new Intent ( context, BackupService.class );
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService ( serviceIntent );
} else {
context.startService ( serviceIntent );
}
Pero, debido a Android 12 - Foreground service launch restrictions
, no podremos invocar el Servicio para realizar tareas en segundo plano. Para obtener más información sobre esta restricción, consulte Cambios de comportamiento de Android 12.
Entonces, de ahora en adelante, (es decir) desde targetSdk 31 / Android 12+, Service
solo se puede invocar cuando la aplicación está en primer plano. Cuando se cierra la aplicación o cuando la aplicación pasa a segundo plano, invocando Service
usando startForegroundService
causará ForegroundServiceStartNotAllowedException
. Entonces, para realizar tareas en segundo plano en Android 12 y superior, necesitamos usar Worker
en lugar de Service
. Para aprender más sobre Worker
por favor refiérase a Solicitudes de trabajo.
Entonces, para aplicaciones destinadas a SDK 31/Android 12+, el código para invocar la tarea en segundo plano será el siguiente:
Intent serviceIntent = new Intent ( context, BackupService.class );
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
OneTimeWorkRequest request = new OneTimeWorkRequest.Builder ( BackupWorker.class ).addTag ( "BACKUP_WORKER_TAG" ).build ();
WorkManager.getInstance ( context ).enqueue ( request );
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService ( serviceIntent );
} else {
context.startService ( serviceIntent );
}
Código de muestra para BackupService
(Existente).
public class BackupService extends Service {
private static final String TAG = "BackupService";
@Nullable
@Override
public IBinder onBind ( Intent intent ) {
return null;
}
@Override
public int onStartCommand ( Intent intent, int flags, int startId ) {
Log.d ( TAG, "onStartCommand" );
startForeground ( BACKUP_SERVICE_NOTIFICATION_ID, createServiceNotification () );
//call methods to perform background task
return super.onStartCommand ( intent, flags, startId );
}
}
Código de muestra para BackupWorker
(Agregado recientemente).
public class BackupWorker extends Worker {
private static final String TAG = "BackupWorker";
public BackupWorker ( @NonNull Context context, @NonNull WorkerParameters workerParams ) {
super ( context, workerParams );
}
@NonNull
@Override
public Result doWork () {
//call methods to perform background task
return Result.success ();
}
}
Asegúrese de agregar las siguientes dependencias en el nivel de módulo gradle
archivo
implementation 'androidx.work:work-runtime:2.7.1'
implementation 'com.google.guava:guava:27.0.1-android'
He probado el código anterior trabajando con Android 5, Android 8, Android 11 y Android 12. Funciona como se esperaba en mi caso.
Espero que esta solución ayude a alguien que tiene como objetivo su aplicación para SDK 31/Android 12+.
-
Entonces, ¿qué sucede si es importante que la aplicación siempre ejecute el servicio en primer plano, por lo tanto, no solo para algunas tareas?
– Lars
31 de mayo de 2022 a las 14:37
-
¡Hola @Lars! Para Target SDK 31 y superior, la aplicación puede usar el servicio de primer plano solo para algunas tareas, como la reproducción de medios, la proyección de medios, las llamadas telefónicas y otras pocas. Entonces, para otras tareas, necesitamos usar cualquier proceso en segundo plano como un
Worker
. Puede consultar esta página para encontrar más información sobre el mismo 🙂 desarrollador.android.com/guide/components/foreground-services– niranj1997
1 de junio de 2022 a las 5:45
-
Gracias, tenía miedo de eso. Supongo que exigir a los usuarios que deshabiliten la optimización de la batería es mi camino a seguir entonces. ¡Gracias por su respuesta rápida!
– Lars
1 de junio de 2022 a las 13:19
-
No tengo ningún problema con esta excepción en Android 12 Google Pixel, pero Samsung es una historia diferente. ¿Por qué?
– Cangrejo kebab
8 oct 2022 a las 10:55
-
No es necesario seguir usando BackupService para versiones inferiores de Android. También puedes usar un Worker allí.
– Malachiasz
22 de noviembre de 2022 a las 8:20
Guss
[Note: The first part is not relevant for Android 12 and later]
En mi caso, usamos un servicio que realiza comunicaciones SIP (VoIP) y estamos iniciando un servicio en primer plano para realizar operaciones sensibles al tiempo (como el registro) o cuando se ejecutan llamadas SIP. Estas tareas no se pueden ejecutar en un Worker
.
Para manejar este caso de uso, Android le permite declarar su servicio “foregroundServiceType
“, y algunos tipos pueden crear servicios en primer plano desde el fondo. El otro caso de uso notable para el que esto tiene sentido es la reproducción multimedia.
Para Android 12 y posteriores
Como se indica en los comentarios, el foregroundServiceType
El atributo ya no es compatible con Android 12. Mi solución actual es capturar la excepción lanzada desde startForegroundService()
(como una forma de detectar que estamos en Android 12) y luego usar un AlarmManager
para iniciar el servicio de primer plano, como se explica en esta respuesta.
Tenga en cuenta que AlarmManager
ofrece varios modos de alarma, algunos no despertarán el dispositivo del “sueño profundo”. Si necesita poder activar el dispositivo desde el “sueño profundo” para iniciar el servicio, intente setAlarmClock()
o setAndAllowWhileIdle()
. Hay algunas otras opciones discutidas en el Mantenga el dispositivo activo artículo sobre desarrolladores de Android y en esta respuesta.
-
He declarado mi así
android:foregroundServiceType="mediaPlayback"
pero sigo teniendo este bloqueo. Tengo una notificación de medios asociada con el servicio. ¿Algunas ideas?– casolorz
8 oct 2022 a las 14:30
-
Después de trabajar un poco más en esto, me di cuenta de que esta respuesta es incorrecta: a partir de Android 12, no hay
foregroundServiceType
que puede configurar que le permitirán iniciar un servicio en primer plano, donde la aplicación de lo contrario estaría excluida de hacerlo: las heurísticas de Android 12 para permitir servicios en primer plano son complicadas pero no se ven afectadas por el uso deforegroundServiceType
.– Guss
8 oct 2022 a las 16:04
-
Mi implementación actual ahora es intentar iniciar el servicio de primer plano usando
startForgroundService()
luego, si falla, debido al error OP, para capturar la excepción lanzada y usar unAlarmManager
para respaldo, como se explica aquí: stackoverflow.com/a/53759060/53538– Guss
8 oct 2022 a las 16:05
-
Hola, @Guss, implementé lo mismo, pero el administrador de alarmas no activa el intento pendiente si la aplicación está en modo de suspensión. Mientras que la depuración funciona bien.
– AndroidStud
6 de febrero a las 2:01
-
@androidStud el vinculado
AlarmManager
respuesta mostró el uso deset()
que no es lo que realmente uso, usosetAlarmClock()
que despierta un dispositivo del sueño profundo. He agregado más detalles en mi respuesta.– Guss
6 de febrero a las 9:04
Timur Panzhiev
Hasta Android 12
es suficiente usar el android:foregroundServiceType=”suTipo” atributo de servicio en el AndroidManifest
para iniciar su servicio desde el fondo (supongo que debe omitir este paso si no encuentra un tipo de servicio adecuado. Desafortunadamente, no he encontrado información sobre esto en los documentos). En Android 12 y superior: si su tarea le permite usar WorkManager
entonces debe reemplazar su servicio con Worker
, por ejemplo, para descargar/cargar un archivo o para una sincronización periódica. Si su tarea es más extensa y requiere que el servicio se ejecute constantemente en segundo plano, por ejemplo, reproducir audio, entonces todavía necesita usar el servicio en primer plano, pero ejecútelo usando el AlarmManager
. Si su servicio debe iniciarse de inmediato, debe usar la alarma exacta para iniciar su servicio. Para ello debe estar seguro de que el usuario ha concedido SCHEDULE_EXACT_ALARM
permiso. Es otorgado por el sistema automáticamente, pero puede ser revocado por el usuario o por el sistema en cualquier momento.
digamos que usamos PlaybackService
para reproducir audio. Entonces mi solución es la siguiente:
- Agregar
android:foregroundServiceType="mediaPlayback"
para ustedAndroidManifest.xml
archivo:
<service
android:name=".data.playback.PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="false"
/>
- En un lugar donde desea iniciar su servicio:
private suspend fun startPlaybackService(state: PlaybackState) {
withContext(Dispatchers.Main) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val operation = PendingIntent.getForegroundService(
context,
REQUEST_CODE,
Intent(context, PlaybackService::class.java),
FLAG_UPDATE_CURRENT_COMPAT
)
val alarmManager = context.getSystemService<AlarmManager>()
if (state in PlaybackStateSets.ACTIVE) {
logi { "Starting playback service with exact alarm" }
startPlaybackServiceWithAlarm(alarmManager, operation)
} else {
logi { "Cancelling exact alarm operation" }
alarmManager.cancel(operation)
}
} else {
if (state in PlaybackStateSets.ACTIVE) {
logi { "Starting playback service" }
ContextCompat.startForegroundService(
context,
Intent(context, PlaybackService::class.java)
)
}
}
}
}
- Para pedirle a su usuario que otorgue permiso para iniciar una alarma exacta, debe explicar al usuario por qué necesita que se le otorgue este permiso y redirigir al usuario a la sección de configuración del sistema
Alarms & reminders
:
fun navigateToAlarmSettings(context: Context) {
context.startActivity(
Intent().apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
action = Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM
} else {
loge { "Attempt to create Alarm settings section intent on Android sdk version < 31" }
}
}
)
}
- Cuando el
SCHEDULE_EXACT_ALARM
se otorga permiso a su aplicación, el sistema le envía elACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED
transmisión. Puede implementar un receptor de transmisión para manejar este cambio.
Enlaces:
La mejor solución que he encontrado es iniciar el servicio desde el fondo o después de que el dispositivo se reinicie a través de AlarmManager
en Android O+
.
val mgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val i = Intent(context, Service::class.java)
val pi = PendingIntent.getForegroundService(context, 0, i, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
val calendar: Calendar = Calendar.getInstance()
calendar.timeInMillis = System.currentTimeMillis()
calendar.add(Calendar.SECOND, 3)
mgr.set(AlarmManager.RTC_WAKEUP, calendar.timeInMillis ,pi)
Además, en NotificationBuilder agregó:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
notificationBuilder.foregroundServiceBehavior = FOREGROUND_SERVICE_IMMEDIATE
}
notificationBuilder.setPriority(NotificationCompat.PRIORITY_MAX)
-
¿cuál es la diferencia?
– usuario924
8 dic 2022 a las 10:36
-
La diferencia es que Android parece permitir iniciar el servicio desde el fondo después de que el dispositivo se reinicia de esta manera.
– EQUIPO EAK
8 dic 2022 a las 18:16
-
interesante, gracias, lo intentare. pero si funciona, sigue siendo un truco y es posible que se elimine una aplicación de Google Play 🙂
– usuario924
3 de febrero a las 17:44
-
por lo tanto, es mejor pedirle a un usuario que deshabilite la optimización de la batería si desea funciones tales como el inicio automático del servicio en primer plano desde el fondo en el arranque/reinicio del dispositivo.
– usuario924
3 de febrero a las 17:45
Shailendra Madda
Para solucionar este problema en Android 12 o superior, actualice la lógica de su aplicación:
Si descubre que su aplicación inicia servicios en primer plano mientras se ejecuta en segundo plano, actualice la lógica de su aplicación para usar administrador de trabajo. Para ver un ejemplo de cómo actualizar su aplicación, mire a través de la WorkManagerMuestra en GitHub.
-
¿cuál es la diferencia?
– usuario924
8 dic 2022 a las 10:36
-
La diferencia es que Android parece permitir iniciar el servicio desde el fondo después de que el dispositivo se reinicia de esta manera.
– EQUIPO EAK
8 dic 2022 a las 18:16
-
interesante, gracias, lo intentare. pero si funciona, sigue siendo un truco y es posible que se elimine una aplicación de Google Play 🙂
– usuario924
3 de febrero a las 17:44
-
por lo tanto, es mejor pedirle a un usuario que deshabilite la optimización de la batería si desea funciones tales como el inicio automático del servicio en primer plano desde el fondo en el arranque/reinicio del dispositivo.
– usuario924
3 de febrero a las 17:45
th3hamm0r
Tuvimos el mismo problema con nuestras aplicaciones de reproducción multimedia. En nuestro caso, la causa raíz fue que hemos usado stopForeground(false)
cada vez que el reproductor ha sido pausado y startForeground(...)
cuando se haya reanudado la reproducción. Esto era necesario en API
Comenzando con Android 12 (API 31), esto condujo al problema de que cuando la aplicación detuvo la reproducción (por ejemplo, debido a una pérdida transitoria del enfoque de audio), la siguiente reanudación (por ejemplo, en la ganancia de enfoque de audio) falló con el bloqueo anterior cuando intentamos llamar startForeground(...)
.
Nuestra solución fue llamar stopForeground(false)
solo cuando la aplicación perdió el foco de audio por completo o el usuario la cerró.
Nuestro único cambio en la aplicación es que cuando la reproducción se detiene, ahora usamos algo como esto:
if (isNotificationActive) {
// update notification
notificationManager.notify(...);
// Starting with Android 12 (API 31), we cannot stop the foreground service on pause, otherwise we won't be able to resume later.
if (Build.VERSION.SDK_INT < 31) {
stopForeground(false);
}
}
Tal vez
RecActivity
estaba en segundo plano en el momento en que llamastestartForegroundService()
.– CommonsWare
20 de noviembre de 2021 a las 13:11
@CommonsWare Supongo que sí. La actividad tiene
bindService
el cual tomaServiceConnection
objeto como devolución de llamada y enonServiceConnected
método pongo el servicio en primer plano. Supongo que necesito usarlifecycleScope.launchWhenStarted { /* start foreground */ }
– usuario924
20 de noviembre de 2021 a las 23:22
Consulte también esta pregunta relacionada y las posibles soluciones con respecto a
ForegroundServiceStartNotAllowedException
aquí– Jadent
16 de diciembre de 2021 a las 11:59
@ user924 ¿Cómo resuelve este problema? También estoy enfrentando el mismo problema con audio_service. ¿Puedes compartir la solución?
– Alex Aung
11 de julio de 2022 a las 18:57