App seems to be in background when activity onStart is called - android

Since Android Oreo you cannot start a service when the app is not in foreground. In my app I start a service in the activity's onStart-method. This works perfectly fine most of the times. However, from time to time an IllegalStateException is thrown saying that the application is trying to start a service while in the background:
java.lang.IllegalStateException: Not allowed to start service Intent { act=ui cmp=com.someapp/.services.ConnectionService }: app is in background uid UidRecord{8d70361 u0a255 TPSL bg:+3m12s948ms idle change:cached procs:1 proclist:20368, seq(0,0,0)}
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1666)
at android.app.ContextImpl.startService(ContextImpl.java:1611)
at android.content.ContextWrapper.startService(ContextWrapper.java:677)
at com.someapp.ui.SomeActivity.connectToBackend(SomeActivity.java:62)
at com.someapp.ui.SomeActivity.onStart(SomeActivity.java:55)
at com.someapp.ui.MainActivity.onStart(MainActivity.kt:228)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1391)
at android.app.Activity.performStart(Activity.java:7348)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3131)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:180)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:165)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:142)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1947)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7032)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:964)
I start the service as follows:
#Override
protected void onStart() {
if (BuildConfig.DEBUG_MODE) Log.d(TAG, "activity started");
super.onStart();
connectToBackend();
}
void connectToBackend() {
Intent intent = new Intent(this, ConnectionService.class);
intent.setAction("ui");
startService(intent);
getApplicationContext().bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
I noticed that this only happens when I lock and then unlock the phone while in the app. I cannot reproduce it consistently.
Does somebody have the same issue?
The device I'm using is a Samsung Galaxy S10e.

For post Nougat devices, use startForegroundService, and for pre Oreo devices, use startService
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent);
} else {
startService(intent);
}

Related

Fatal Exception: android.app.ForegroundServiceDidNotStartInTimeException

Fatal Exception: android.app.ForegroundServiceDidNotStartInTimeException: Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{294bdda u0 com.xyz.xyz/com.xyz.pushnotification.BookingProgressService}
at android.app.ActivityThread.throwRemoteServiceException(ActivityThread.java:1923)
at android.app.ActivityThread.access$2700(ActivityThread.java:247)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2148)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7839)
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)
I'm facing this crash inside my service and that i have wrote on below way
Start service:
if (Build.VERSION.SDK_INT >= 26)
mContext.startForegroundService(serviceIntent)
else
mContext.startService(serviceIntent)
Inside Time Tick update or create notification:
registerTimeTickReceiver() method called inside onStartCommand() of Service class
private fun registerTimeTickReceiver() {
if (timeTickReceiver != null)
unregisterTimeTickReceiver()
timeTickReceiver = object : BroadcastReceiver() {
override fun onReceive(
context: Context, intent: Intent
) { //trigger the callback on every minutes
Log.e("BookingProgressService", "Service registerTimeTickReceiver")
if (intent.action?.compareTo(Intent.ACTION_TIME_TICK) == 0)
fetchDataForNotification()
}
}
registerReceiver(timeTickReceiver, IntentFilter(Intent.ACTION_TIME_TICK))
}
Inside fetchDataForNotification() added:
startForeground(booking.id, notification)
Note: This crashes I can't able to reproduce from my device but it is reproduced on some of the devices
My requirement is update multiple booking progress notification on every minute If my app is running or not running(Background) Can anyone please help me? or If you know other best approach then very thankful to you guys

Getting a "Service not registered" error when trying to unbind a service

I have a service receiver to take care of callbacks related to BLE GATT events (connecting, disconnecting, etc).
In situations where I kill the BLE device to simulate a dropout, the disconnect event fires, and my call to context.unbindService(serviceConnection) fails. I've checked for a few of the obvious errors (different contexts, null service connection, etc), and can't find the error. Why am I getting this exception?
Here's the trace:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.ktest, PID: 6372
java.lang.IllegalArgumentException: Service not registered: com.example.ktest.ble.BLEConnectionManager$serviceConnection$1#493960
at android.app.LoadedApk.forgetServiceDispatcher(LoadedApk.java:1602)
at android.app.ContextImpl.unbindService(ContextImpl.java:1710)
at android.content.ContextWrapper.unbindService(ContextWrapper.java:717)
at com.example.ktest.ble.BLEConnectionManager.unBindService(BLEConnectionManager.kt:81)
at com.example.ktest.foo.FooActivity.disconnect(FooActivity.kt:268)
at com.example.ktest.foo.FooActivity.access$disconnect(FooActivity.kt:47)
at com.example.ktest.foo.FooActivity$gattUpdateReceiver$1$onReceive$1.run(FooActivity.kt:190)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6863)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:537)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Here's the disconnect function that's called as per the trace:
private fun disconnect() {
BLEConnectionManager.unBindService(this#FooActivity) // FAILS HERE
unregisterServiceReceiver()
val intent = Intent(this, ConnectDeviceActivity::class.java)
startActivity(intent)
finish() // close activity
}
The service was bound using the same context (from FooActivity.onStart()):
BLEConnectionManager.bindService(this#FooActivity)
So there are no problems when BLEConnectionManager.bindService() is called:
fun bindService(context: Context) {
if (serviceConnection != null && isBound) {
Log.w(TAG, "Service is already bound")
} else {
val gattServiceIntent = Intent(context, BLEService::class.java)
if (context != null) {
isBound = context.bindService(
gattServiceIntent,
serviceConnection,
Context.BIND_AUTO_CREATE)
}
Log.i(TAG, "BLEService now bound, isBound is now $isBound")
}
}
Here's the BLEConnectionManager.unBindService()
fun unBindService(context: Context) {
// NOTE I've logged the service and connection here, they're non-null and BLE works fine in this Activity
if (serviceConnection != null && isBound) context.unbindService(serviceConnection)
}
So what have I missed, and what am I doing wrong that causes the exception?
I was calling unbind too many times (on a service that had previously unbound and hadn't been bound again since). This was because I had forgotten to set my BLEConnectionManager isBound flag in that class' unbind method. Whoops.

How to stop a foreground service before calling startForeground() method?

I am starting a foreground service using the following code
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent);
} else {
context.startService(intent);
}
This starts a foreground service. In Android Oreo and above, we must call startForeground() method within 5 seconds. Now in my service, we do some processing and if certain conditions are not met, then I don't call startForeground() method. Instead, I try to kill the service.
if (someConditionMet) {
startForeground(notificationId, notification)
} else {
stopSelf()
}
Now if someConditionMet variable is false, then my app crashes with the following crash log.
2019-04-10 16:57:25.695 19785-19785/com.awesomedroidapps.foregroundactivity E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.awesomedroidapps.foregroundactivity, PID: 19785
android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{e78d43f u0 com.awesomedroidapps.foregroundactivity/.ForegroundServiceTest}
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1835)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6863)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:537)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
I don't understand that when I am stopping the service then why is it necessary to call startForeground() method? Is there any way we can stop the foreground service without calling startForeground() method?
You can't. Period.
You can't stop a foreground service before the startForeground has been called and successfully executed. It is mandatory to finish this call before any action in the foreground service is taken.
No matter what combinations of stopSelf() and stopForeground() you use, it would not do what you desire to do.
Here is a really nice article about the same:
Foreground Service Pitfalls
If you want to stop service without creating actual notification you can just invoke startForeground with stub notification and cancel in right after stopSelf is invoked.
if (conditionMet)
startForeground(notificationId, notification)
} else {
startForeground(STUB_NOTIFICATION_ID, createStubNotification())
stopSelf()
cancelStubNotification()
}
private fun createStubNotification(): Notification {
val notificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) {
notificationManager.createNotificationChannel(
NotificationChannel(
STUB_NOTIFICATION_CHANNEL_ID,
STUB_NOTIFICATION_CHANNEL_NAME,
IMPORTANCE_LOW
).apply { setShowBadge(false) }
)
}
return with(NotificationCompat.Builder(this, STUB_NOTIFICATION_CHANNEL_ID)) {
setBadgeIconType(NotificationCompat.BADGE_ICON_NONE)
setOngoing(true)
setSmallIcon(R.drawable.ic_notification)
priority = NotificationCompat.PRIORITY_LOW
setShowWhen(false)
setSilent(true)
build()
}.also { notificationManager.notify(STUB_NOTIFICATION_ID, it) }
}
private fun cancelStubNotification() =
(getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager)
.cancel(STUB_NOTIFICATION_ID)
Try this: Use a static variable and track the state of your service i.e running or not running, then check the state before calling stopself(). When the service is started, update the boolean flag to true and when it stops, update the boolean flag to false.

Android GCM - WakefulBroadcastReceiver.startWakefulService crash due to IllegalStateException 8.0

We just migrated app's target api to Android API 27 (8.1) and it keeps on crashing when notification arrives specially when the app is in the background.
java.lang.RuntimeException: Unable to start receiver <package>.service.GCMBroadcastReceiver: java.lang.IllegalStateException: Not allowed to start service Intent { act=com.google.android.c2dm.intent.RECEIVE flg=0x1000010 pkg=<package> cmp=<package>/.service.GCMIntentService (has extras) }: app is in background uid UidRecord{b248a9d u0a85 RCVR bg:+1m4s53ms idle change:uncached procs:1 seq(0,0,0)}
at android.app.ActivityThread.handleReceiver(ActivityThread.java:3194)
at android.app.ActivityThread.-wrap17(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1672)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Caused by: java.lang.IllegalStateException: Not allowed to start service Intent { act=com.google.android.c2dm.intent.RECEIVE flg=0x1000010 pkg=<package> cmp=<package>/.service.GCMIntentService (has extras) }: app is in background uid UidRecord{b248a9d u0a85 RCVR bg:+1m4s53ms idle change:uncached procs:1 seq(0,0,0)}
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1521)
at android.app.ContextImpl.startService(ContextImpl.java:1477)
at android.content.ContextWrapper.startService(ContextWrapper.java:650)
at android.support.v4.content.WakefulBroadcastReceiver.startWakefulService(WakefulBroadcastReceiver.java:99)
at <package>.service.GCMBroadcastReceiver.onReceive(GCMBroadcastReceiver.java:32)
at android.app.ActivityThread.handleReceiver(ActivityThread.java:3187)
at android.app.ActivityThread.-wrap17(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1672)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
This is how I fix the issue:
Why this issue happens?
Due to the new Background Execution Limits of Android 8 and you should
not start services background.
How I fixed it
Migrate your GCMIntetService to JobIntentService instead of IntentService.
Please follow this steps:
1) Add the BIND_JOB_SERVICE permission to your service:
<service android:name=".service.GCMIntentService"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE"/>
2) In your GCMIntentService, instead extending the IntentService, use android.support.v4.app.JobIntentService and override onHandleWork
then remove the override in you onHandleIntent.
public class GCMIntentService extends JobIntentService {
// Service unique ID
static final int SERVICE_JOB_ID = 50;
// Enqueuing work in to this service.
public static void enqueueWork(Context context, Intent work) {
enqueueWork(context, GCMIntentService.class, SERVICE_JOB_ID, work);
}
#Override
protected void onHandleWork(#NonNull Intent intent) {
onHandleIntent(intent);
}
private void onHandleIntent(Intent intent) {
//Handling of notification goes here
}
}
Then finally, in your GCMBroadcastReceiver, enqueue your GCMIntentService.
public class GCMBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Explicitly specify that GcmIntentService will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(),
GCMIntentService.class.getName());
// Start the service, keeping the device awake while it is launching.
// startWakefulService(context, (intent.setComponent(comp)));
//setResultCode(Activity.RESULT_OK);
GCMIntentService.enqueueWork(context, (intent.setComponent(comp)));
}
}
This implementation work for me after we update our target sdk to 27 and I hope it works for you.

Context.startForegroundService did not then call Service.startForeground

It's mine BroadcastReciever class. The class working on Boot phone status.
Code ;
public class BroadCastRecieverBoot extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent ıntent) {
if(Intent.ACTION_BOOT_COMPLETED.equals(ıntent.getAction()))
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(new Intent(context, MyService.class));
context.startForegroundService(new Intent(context, GPSTracker.class));
} else {
context.startService(new Intent(context, MyService.class));
context.startService(new Intent(context, GPSTracker.class));
}
}
}
}
I get This Error ;
android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1792)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6523)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:857)
It doesn't work on Android Oreo now. I don't know what is the mistake of that.
According to official document of Android 8.0 Background Execution Limits
Android 8.0 introduces the new method
startForegroundService() to start a new service in the foreground.
After the system has created the service, the app has five seconds to
call the service's startForeground() method to show the new service's
user-visible notification. If the app does not call startForeground()
within the time limit, the system stops the service and declares the
app to be ANR.
So, make sure you have started ongoing notification by calling startForeground (int id, Notification notification) in the onCreate() method of your service.
Note: Apps targeting API Build.VERSION_CODES.P or later must request the permission Manifest.permission.FOREGROUND_SERVICE in order to use this API.

Categories

Resources