Comments (12)
@rahul-kumawat-vts can you please share two things:
- Any entry in your AndroidManifest.xml that refers to "BeaconService". Below is what it might look like:
<service
android:name=".service.BeaconService"
android:enabled="true"
android:exported="false"
android:isolatedProcess="false"
android:foregroundServiceType="location"
android:label="beacon"
/>
- The code that configures the foreground service and starts ranging or monitoring. Below is what the official Kotlin reference app does to set this up to give you a clue what we are looking to see. The key part is the code that calls
enableForegroundServiceScanning
and thenstartRangingBeacons
orstartMonitoring
.
val builder = Notification.Builder(this, "BeaconReferenceApp")
builder.setSmallIcon(R.drawable.ic_launcher_background)
builder.setContentTitle("Scanning for Beacons")
val intent = Intent(this, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(
this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABLE
)
builder.setContentIntent(pendingIntent);
val channel = NotificationChannel("beacon-ref-notification-id",
"My Notification Name", NotificationManager.IMPORTANCE_DEFAULT)
channel.setDescription("My Notification Channel Description")
val notificationManager = getSystemService(
Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel);
builder.setChannelId(channel.getId());
Log.d(TAG, "Calling enableForegroundServiceScanning")
BeaconManager.getInstanceForApplication(this).enableForegroundServiceScanning(builder.build(), 456);
Log.d(TAG, "Back from enableForegroundServiceScanning")
beaconManager.startMonitoring(region)
beaconManager.startRangingBeacons(region)
from android-beacon-library.
Thanks for this report.
We added the code below to prevent that in #1162 released in October in 2.20.1, but it looks like it will not work in your case:
try {
this.startForeground(notificationId, notification);
}
catch (SecurityException exception) {
// https://issuetracker.google.com/issues/294408576
LogManager.w(TAG, "Call to service startForeground() threw a SecurityException. The Foreground Service for beacon scanning may have started anyway, but this behavior might change in different conditions or a future Android version.");
}
The reason is because you are getting a android.app.ForegroundServiceStartNotAllowedException which does not inherit from SecurityException, it inherits from IllegalStateException.
We probably ned to add another catch here for that exception. This will prevent the crash reports, but it won't change the fact that we won't be able to start the foreground service in these cases.
@stephenruda any thoughts here?
from android-beacon-library.
Hi! Yes I have some thoughts.
ForegroundServiceStartNotAllowedException
actually dates back to Android 12. After re-reading the Android 14 docs, I don't think there was anything new in Android 14 that would have caused this exception that wasn't already happening in Android 12 and 13.
This exception is actually a child of ServiceStartNotAllowedException
which you are already catching here.
Catching the exception using the parent class should be sufficient in Java. It should catch both the ServiceStartNotAllowedException
and ForegroundServiceStartNotAllowedException
.
My understanding was that this exception was only ever thrown in calls to startForegroundService()
and not calls to startForeground()
like we are seeing in the mentioned stacktrace.
I have other foreground services in my app (unrelated to the android-beacon-library
) that catches this exception. Just like in the BeaconManager
, I am catching this exception on startForegroundService()
and not on startForeground()
. I have never had an issue with it.
I finally just shipped my Android 14 changes for my app last week. I have not noticed this exception yet in my app but I will keep my eye out for it.
My conclusion would be...
- Maybe something has changed in Android 14 and now this exception is being thrown from calls to
startForeground()
as well asstartForegroundService()
. I haven't experienced that yet myself so maybe we should wait until we can collect more data. My app has 4 other foreground services alongside theBeaconService
so if this is the case it shouldn't take me too long before I see it. If that ends up being the case, we will have to fallback to the job scheduler just like we would when catching the exception from theBeaconManager
. I don't think we could just "eat" the error and act like nothing happened like we do with theSecurityException
. - Maybe this user has the library implemented in a unique way. For example, maybe they are calling
startForegroundService()
themselves rather than allowing theBeaconManager
to do it for them? If this is something they can recreate consistently, it would be great to see some code or have them recreate the problem in the reference application.
from android-beacon-library.
Looking a bit more into this issue, my leading theory is that there is something new in Android 14 that is causing this.
Because the BeaconService
is sticky, it will attempt to restart itself if it is ever killed. This is likely why we are seeing calls to startForeground()
without any calls from the BeaconManager
.
The docs say that it does not restrict restarting a sticky foreground service. Maybe that is an undocumented change or bug in Android 14?
Finally, the reason that I have not seen this in my app is due to the fact that I force users to turn off battery optimizations for my app prior to using my foreground services. This allows me to start foreground services from the background and therefore my app would never throw an exception when this scenario occurs.
I am not suggesting that the Beacon Library should force users to turn this setting off - I am just explaining why I haven't seen the exception in my app.
Ultimately, what do we do about this issue? I am not really sure. To me it does feel like an Android 14 bug but I doubt that it will be fixed any time soon. I suppose falling back to the job scheduler is better than crashing? It would be nice if we could get more data/reports from other users to see how often this is occurring. Like I mentioned, it will not occur in my app so I don't have a good way to gauge how common the issue is.
from android-beacon-library.
Yes, I agree that falling back to the JobScheduler is probably the solution in this case, but it would be good to understand the specific sequence that triggers it. @stephenruda do you think you might be able to re-enable background optimizations on your app on a test phone and let it run for a day or so to see if you can reproduce a crash?
I am going to try running the reference app on the latest Android 14 to see if I can reproduce, but I may not be able to, because I suspect the foreground service will just keep running for days. I wonder if I can force a crash of the foreground service somehow to test your sticky restart theory.
from android-beacon-library.
Yes, I can do that.
I am unsure how to consistently reproduce the problem. I don't think there is a way we can manually trigger 'killing' the service in the same way that the OS does. I think the OS kills the service when system resources get low. As you suggested, it might take some time before we actually see the problem occur.
from android-beacon-library.
I was unable to reproduce the problem running the Kotlin reference app (configured to use a foreground service) on a Pixel 6a on the latest Android 14 (Security update January 5, 2014), then crashing the app connected to adb
on my workstation with this command:
adb shell am crash org.altbeacon.beaconreference
The app crashed, then restarted as expected, and the foreground service started successfully as shown in the logs below.
2024-01-20 23:04:51.338 24146-24146 AndroidRuntime org.altbeacon.beaconreference D Shutting down VM
2024-01-20 23:04:51.342 24146-24146 AndroidRuntime org.altbeacon.beaconreference E FATAL EXCEPTION: main
Process: org.altbeacon.beaconreference, PID: 24146
android.app.RemoteServiceException$CrashedByAdbException: shell-induced crash
at android.app.ActivityThread.throwRemoteServiceException(ActivityThread.java:2115)
at android.app.ActivityThread.-$$Nest$mthrowRemoteServiceException(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2394)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:294)
at android.app.ActivityThread.main(ActivityThread.java:8248)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
2024-01-20 23:04:51.371 24146-24146 Process org.altbeacon.beaconreference I Sending signal. PID: 24146 SIG: 9
---------------------------- PROCESS ENDED (24146) for package org.altbeacon.beaconreference ----------------------------
---------------------------- PROCESS STARTED (24626) for package org.altbeacon.beaconreference ----------------------------
2024-01-20 23:04:51.510 24626-24626 Compatibil...geReporter org.altbeacon.beaconreference D Compat change id reported: 242716250; UID 10244; state: ENABLED
2024-01-20 23:04:51.520 24626-24626 nativeloader org.altbeacon.beaconreference D Configuring clns-4 for other apk /data/app/~~Jv2bdx7ebRgX_okn7mVOOw==/org.altbeacon.beaconreference-fJ-Z1Z_BvOyOuJs1M4fQaA==/base.apk. target_sdk_version=34, uses_libraries=, library_path=/data/app/~~Jv2bdx7ebRgX_okn7mVOOw==/org.altbeacon.beaconreference-fJ-Z1Z_BvOyOuJs1M4fQaA==/lib/arm64, permitted_path=/data:/mnt/expand:/data/user/0/org.altbeacon.beaconreference
2024-01-20 23:04:51.529 24626-24626 GraphicsEnvironment org.altbeacon.beaconreference V Currently set values for:
2024-01-20 23:04:51.529 24626-24626 GraphicsEnvironment org.altbeacon.beaconreference V angle_gl_driver_selection_pkgs=[]
2024-01-20 23:04:51.529 24626-24626 GraphicsEnvironment org.altbeacon.beaconreference V angle_gl_driver_selection_values=[]
2024-01-20 23:04:51.529 24626-24626 GraphicsEnvironment org.altbeacon.beaconreference V ANGLE GameManagerService for org.altbeacon.beaconreference: false
2024-01-20 23:04:51.530 24626-24626 GraphicsEnvironment org.altbeacon.beaconreference V org.altbeacon.beaconreference is not listed in per-application setting
2024-01-20 23:04:51.530 24626-24626 GraphicsEnvironment org.altbeacon.beaconreference V Neither updatable production driver nor prerelease driver is supported.
2024-01-20 23:04:51.535 24626-24626 BeaconParser org.altbeacon.beaconreference D Parsing beacon layout: m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24
2024-01-20 23:04:51.546 24626-24626 BeaconManager org.altbeacon.beaconreference I BeaconManager started up on pid 24626 named 'org.altbeacon.beaconreference' for application package 'org.altbeacon.beaconreference'. isMainProcess=true
2
from android-beacon-library.
App also restarted fine automatically after reboot with foreground service
from android-beacon-library.
@davidgyoung We got so many crash on over firebase. i have tried to replicate but not able to replicate.
In our app we are running a service to handle the beacon. Please check the code we are using in our app.
<service
android:name=".MyAppBeaconService"
android:enabled="true"
android:exported="false"
android:foregroundServiceType="location" />
import android.app.*
import android.content.Intent
import android.content.pm.ServiceInfo
import android.os.Build
import android.os.IBinder
import android.os.RemoteException
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import dagger.hilt.android.AndroidEntryPoint
import org.altbeacon.beacon.*
import timber.log.Timber
@AndroidEntryPoint
class MyAppBeaconService : Service(), InternalBeaconConsumer, MonitorNotifier, RangeNotifier {
private var beaconManager: BeaconManager? = null
private val region = Region("backgroundRegion", null, null, null)
private var lastShownNotificationId = 0
private var builder: NotificationCompat.Builder? = null
companion object {
const val IBEACON_LAYOUT = "IBEACON_LAYOUT_ACTUAL_VALUE"
const val EDDYSTONE_UID_LAYOUT = BeaconParser.EDDYSTONE_UID_LAYOUT
const val EDDYSTONE_URL_LAYOUT = BeaconParser.EDDYSTONE_URL_LAYOUT
const val EDDYSTONE_TLM_LAYOUT = BeaconParser.EDDYSTONE_TLM_LAYOUT
}
override fun onCreate() {
super.onCreate()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startBeaconForegroundService(NOTIFICATION_ID)
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Timber.d("MyAppBeaconService onStartCommand")
if (intent?.action == STOP_BEACON_FOREGROUND_ACTION) {
stopForeground(true)
stopSelf()
} else {
try {
beaconManager = BeaconManager.getInstanceForApplication(this)
beaconManager?.beaconParsers?.add(BeaconParser().setBeaconLayout(IBEACON_LAYOUT))
beaconManager?.beaconParsers?.add(BeaconParser().setBeaconLayout(EDDYSTONE_UID_LAYOUT))
beaconManager?.beaconParsers?.add(BeaconParser().setBeaconLayout(EDDYSTONE_URL_LAYOUT))
beaconManager?.beaconParsers?.add(BeaconParser().setBeaconLayout(EDDYSTONE_TLM_LAYOUT))
beaconManager?.backgroundBetweenScanPeriod = 1000L
beaconManager?.foregroundBetweenScanPeriod = 1000L
beaconManager?.enableForegroundServiceScanning(builder?.build(), NOTIFICATION_ID)
beaconManager?.setEnableScheduledScanJobs(false)
beaconManager?.backgroundScanPeriod = 1100L
beaconManager?.bindInternal(this)
beaconManager?.updateScanPeriods()
} catch (e: Exception) {
e.printStackTrace()
}
}
return START_STICKY
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onTaskRemoved(rootIntent: Intent?) {
// start MyAppBeaconService if not running.
startBeaconService()
super.onTaskRemoved(rootIntent)
}
@RequiresApi(Build.VERSION_CODES.O)
private fun startBeaconForegroundService(notificationId: Int) {
builder = getNotificationBuilder("CHANNEL_ID",
NotificationManagerCompat.IMPORTANCE_LOW)
builder?.let { builder ->
builder.setOngoing(true)
.setContentTitle(applicationContext.resources.getString(R.string.background_service_message))
.setSmallIcon(R.drawable.ic_icon)
.setPriority(NotificationManager.IMPORTANCE_MAX)
.setCategory(Notification.CATEGORY_SERVICE)
.addAction(1001, applicationContext.resources.getString(R.string.action),
beaconStopPendingIntent())
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
builder.foregroundServiceBehavior = Notification.FOREGROUND_SERVICE_IMMEDIATE
}
val notification = builder.build()
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
this.startForeground(notificationId, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION)
} else {
this.startForeground(notificationId, notification)
}
} catch (e: Exception) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
&& e is ForegroundServiceStartNotAllowedException) {
Timber.d("MyAppBeaconService - startBeaconForegroundService - ForegroundServiceStartNotAllowedException: ${e.message}")
}
e.printStackTrace()
}
if (notificationId != lastShownNotificationId) {
// Cancel previous notification
val nm = this.getSystemService(Activity.NOTIFICATION_SERVICE) as NotificationManager
nm.cancel(lastShownNotificationId)
}
lastShownNotificationId = notificationId
}
}
@RequiresApi(Build.VERSION_CODES.O)
fun getNotificationBuilder(channelId: String, importance: Int): NotificationCompat.Builder {
prepareChannel(channelId, importance)
return NotificationCompat.Builder(this, channelId)
}
@RequiresApi(Build.VERSION_CODES.O)
private fun prepareChannel(id: String, importance: Int) {
val appName = resources.getString(R.string.app_name)
val notificationManager = this.getSystemService(Activity.NOTIFICATION_SERVICE) as NotificationManager
var notificationChannel = notificationManager.getNotificationChannel(id)
if (notificationChannel == null) {
notificationChannel = NotificationChannel(id, appName, importance)
notificationManager.createNotificationChannel(notificationChannel)
}
}
private fun beaconStopPendingIntent(): PendingIntent {
val intent = Intent(this, this.javaClass)
intent.action = Constants.STOP_BEACON_FOREGROUND_ACTION
return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_CANCEL_CURRENT)
}
override fun didRangeBeaconsInRegion(beacons: Collection<Beacon>, region: Region) {
//Timber.d(" MyAppBeaconService - didRangeBeaconsInRegion - $beacons , Size - ${beacons.size}")
}
override fun onDestroy() {
super.onDestroy()
Timber.d("MyAppBeaconService, onDestroy ")
beaconManager?.stopRangingBeacons(this.region)
beaconManager?.removeAllMonitorNotifiers()
beaconManager?.removeAllRangeNotifiers()
beaconManager?.unbindInternal(this)
beaconManager?.disableForegroundServiceScanning()
}
override fun didDetermineStateForRegion(state: Int, region: Region) {
beaconManager?.startRangingBeacons(region)
Timber.d("MyAppBeaconService - didDetermineStateForRegion - I have just switched from seeing/not seeing beacons: $state, region: $region")
}
override fun didEnterRegion(region: Region) {
beaconManager?.startRangingBeacons(region)
Timber.d("MyAppBeaconService - didEnterRegion - I just saw an beacon for the first time!")
}
override fun didExitRegion(region: Region) {
try {
beaconManager?.stopRangingBeacons(region)
} catch (e: RemoteException) {
Timber.d("MyAppBeaconService - didExitRegion - RemoteException: ${e.printStackTrace()}")
e.printStackTrace()
}
Timber.d("MyAppBeaconService - didExitRegion - I no longer see an beacon")
}
override fun onBeaconServiceConnect() {
Timber.d("MyAppBeaconService - onBeaconServiceConnect - beacon service connect")
beaconManager?.removeAllMonitorNotifiers()
beaconManager?.removeAllRangeNotifiers()
beaconManager?.addMonitorNotifier(this)
beaconManager?.addRangeNotifier(this)
try {
beaconManager?.startMonitoring(region)
beaconManager?.startRangingBeacons(region)
} catch (e: RemoteException) {
e.printStackTrace()
Timber.d("MyAppBeaconService - onBeaconServiceConnect - errStartMonitoringRanging: ${e.message}, exception: ${e.printStackTrace()}")
}
}
private fun startBeaconService() {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(Intent(context, MyAppBeaconService::class.java))
} else {
context.startService(Intent(context, MyAppBeaconService::class.java))
}
} catch (exception: Exception) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
&& exception is ForegroundServiceStartNotAllowedException) {
Timber.d("MyAppBeaconService - startBeaconService - ForegroundServiceStartNotAllowedException: ${exception.message}")
}
}
}
}
from android-beacon-library.
from android-beacon-library.
Over the weekend, I was not able to reproduce the crash in my app after re-enabling battery optimizations.
I agree that this is an interesting approach. I have never done anything exactly like this. In my app, I do have instances where I start a foreground service from within another foreground service. My understanding of foreground services is that it should work. But there are so many intricacies and every new Android update adds more.
I am having a hard time wrapping my head around every possible scenario and how this situation might have occurred.
My best guess is that you are trying to start the BeaconService
when it is not allowed - just as the exception states. You cannot start a foreground service while the app is in the background.
Is it possible that you are trying to start the service after sending the STOP_BEACON_FOREGROUND_ACTION
flag?
You are also catching a lot of exceptions in the MyAppBeaconService
. It is possible that you catch an exception within this service so it never makes it into the foreground - but then you try starting the BeaconService
which will fail because nothing was in the foreground?
Here are some links that might be helpful:
https://developer.android.com/develop/background-work/services/foreground-services#bg-access-restrictions
https://developer.android.com/develop/background-work/services/foreground-services#wiu-restrictions
https://developer.android.com/develop/background-work/services/fg-service-types#location
Due to the amount of crashes you are seeing, I am guessing this issue is related to your unique set up.
from android-beacon-library.
@rahul-kumawat-vts, as suggested by @stephenruda, I suspect that the core issue here may be that Android 14 simply does not support your unusual foreground service use case. I would suggest you do one of two things:
- Remove the catch of the exceptions inside
startBeaconForegroundService
method and see if you get exception reports (indicating your foreground service is also being blocked from starting by Android.)
- or -
- Add a new member variable to
MyForegroundService
calledforegroundServiceStartFailed
that gets set to true if any of the above exceptions insidestartBeaconForegroundService
get caught, and if this flag is true, do not do any of the call any of theBeaconManager
setup which causes a secondary exception to crash the app. Then see if the crash reports go away.
If you choose option (2) above, I'd suggest you also add something to send stack traces or more detailed logs to a server so you can debug why your foreground service is not being allowed by Andorid to start, as option 2 may otherwise make your service start failures silent.
I am going to close this issue for now, as I do not believe there is anything the library can do to resolve these Android 14 restrictions. However, if you find evidence to the contrary in the above tests, feel free to re-open this issue.
from android-beacon-library.
Related Issues (20)
- Range beacons when app is terminating HOT 7
- Beacons ranging not working on android 13 HOT 1
- App stops scanning right after screen is locked and starts giving the results right after unlocked HOT 1
- Android beacon library - multiple regions monitoring - unable remove regions HOT 2
- startForeground Exception when app is not in foreground HOT 3
- StartupBroadcastReceiver throws NullPointerException HOT 2
- No beacons after locked screen HOT 19
- Cannot parse iBeacons HOT 3
- TargetSdk 34 (android 14) Beacon foreground service no longer working due to new Google restriction HOT 1
- Do we have sample app to implement the library including the operation running in Background HOT 4
- Only a maximum of 2 beacons can be received at a time HOT 1
- java.io.FileNotFoundException android-distance.json HOT 3
- android-distance.json database not found
- Crash when parsing _lengthy_ beacon data fields HOT 3
- Custom Distance calculator is being overwritten HOT 6
- Samsung devices not detecting beacons by intent after first screen off
- Can we use this with tauri mobile? HOT 3
- Main thread can be blocked sometimes
- Android 14 didDetermineStateForRegion no beacon is detected or scanned HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from android-beacon-library.