admin管理员组文章数量:1418302
I have written and published an app “Sensor Recording” which reads out and displays the measured values of some sensors (position, acceleration, orientation, microphone, etc.). The app records sensor data continuously in the background, even if the display is switched OFF (standby mode). For this feature, I have established a Service, which is started by user interaction (button click). As of Android version 12, there must be some kind of prerequisites in the code and in the Manifest, which I have fulfilled. Here is a code snippet from “SensorService.java”:
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
// ...
// ...
String channelId = "4711"; // arbitrary
Intent notificationIntent = new Intent(this, SensorService.class);
int flag = PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE;
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, flag);
Notification notification;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) // O = OREO = 26
{
NotificationChannel channel = new NotificationChannel(channelId,
getString(R.string.app_name),
NotificationManager.IMPORTANCE_HIGH);
notMan = getSystemService(NotificationManager.class);
if (notMan != null)
{
notMan.createNotificationChannel(channel);
Notification.Builder builder = new Notification.Builder(this, channelId);
builder.setSmallIcon(R.drawable.vector3d_bg_transp)
.setContentTitle(text0)
.setContentText(text1)
.setTicker(text1)
.setSubText("Start Service")
.setShowWhen(true)
.setAutoCancel(true)
.setTimeoutAfter(500)
.setChannelId(channelId)
.setDefaults(Notification.DEFAULT_ALL)
.setPriority(Notification.PRIORITY_HIGH)
.setCategory(Notification.CATEGORY_MESSAGE)
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setContentIntent(pendingIntent);
notification = builder.build();
int serviceType = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) // Q = Quince Tart = 29
serviceType |= ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) // R = Red Velvet Cake = 30
serviceType |= ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE;
ServiceCompat.startForeground(this, id, notification, serviceType);
}
}
else
{
// ...
}
return START_REDELIVER_INTENT;
}
and an extract from “AndroidManifest.xml”:
<manifest ...>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE"/>
<!--
...
...
-->
<service android:name=".SensorService"
android:foregroundServiceType="location|microphone"
android:exported="false" />
</application>
</manifest>
This works fine on the four devices / Android versions which I have tested:
- Samsung Galaxy A14 (Android 13)
- Google Pixel 6a (Android 15)
- Samsung Galaxy Tab A 10.5 (Android 10)
- Huawei P10 Lite (Android 8.0)
However, in the Google Developer Console (Section Android Vitals, Crashes and ANRs), I get frequent error messages from other devices (with Android 14 or 15), on which I have no physical access:
- Google tangorpro
- T-Mobile CypressPoint
- Safaricom Neon_Smarta_2
- Goggle oriole
- Samsung a06
- Samsung a15
The error always occurs in the line
ServiceCompat.startForeground(this, id, notification, serviceType);
and is either “SecurityException“ or “ForegroundServiceStartNotAllowedException”. How can I locate the source of the errors?
Here is an example Stacktrace for "SecurityException":
Exception java.lang.RuntimeException: at android.app.ActivityThread.handleServiceArgs (ActivityThread.java:4952) at android.app.ActivityThread.-$$Nest$mhandleServiceArgs (Unknown Source) at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2381) 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:8376) at java.lang.reflect.Method.invoke at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:640) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:982) Caused by java.lang.SecurityException: at android.os.Parcel.createExceptionOrNull (Parcel.java:3057) at android.os.Parcel.createException (Parcel.java:3041) at android.os.Parcel.readException (Parcel.java:3024) at android.os.Parcel.readException (Parcel.java:2966) at android.app.IActivityManager$Stub$Proxy.setServiceForeground (IActivityManager.java:6842) at android.app.Service.startForeground (Service.java:862) at androidx.core.app.ServiceCompat$Api34Impl.startForeground (ServiceCompat.java:241) at androidx.core.app.ServiceCompat.startForeground (ServiceCompat.java:172) at net.braun_home.sensorrecording.SensorService.onStartCommand (SensorService.java:549) at android.app.ActivityThread.handleServiceArgs (ActivityThread.java:4934) Caused by android.os.RemoteException: Remote stack trace: at com.android.server.am.ActiveServices.validateForegroundServiceType (ActiveServices.java:2690) at com.android.server.am.ActiveServices.setServiceForegroundInnerLocked (ActiveServices.java:2401) at com.android.server.am.ActiveServices.setServiceForegroundLocked (ActiveServices.java:1748) at com.android.server.am.ActivityManagerService.setServiceForeground (ActivityManagerService.java:13460) at android.app.IActivityManager$Stub.onTransact (IActivityManager.java:3422)
and a Stacktrace for "ForegroundServiceStartNotAllowedException":
Exception java.lang.RuntimeException: at android.app.ActivityThread.handleServiceArgs (ActivityThread.java:5286) at android.app.ActivityThread.-$$Nest$mhandleServiceArgs (Unknown Source) at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2531) at android.os.Handler.dispatchMessage (Handler.java:106) at android.os.Looper.loopOnce (Looper.java:230)
at android.os.Looper.loop (Looper.java:319) at android.app.ActivityThread.main (ActivityThread.java:8919) at java.lang.reflect.Method.invoke at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:578) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1103) Caused by android.app.ForegroundServiceStartNotAllowedException: at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel (ForegroundServiceStartNotAllowedException.java:54) at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel (ForegroundServiceStartNotAllowedException.java:50) at android.os.Parcel.readParcelableInternal (Parcel.java:4882) at android.os.Parcel.readParcelable (Parcel.java:4864) at android.os.Parcel.createExceptionOrNull (Parcel.java:3064) at android.os.Parcel.createException (Parcel.java:3053) at android.os.Parcel.readException (Parcel.java:3036) at android.os.Parcel.readException (Parcel.java:2978) at android.app.IActivityManager$Stub$Proxy.setServiceForeground (IActivityManager.java:7234) at android.app.Service.startForeground (Service.java:862) at androidx.core.app.ServiceCompat$Api34Impl.startForeground (ServiceCompat.java:241) at androidx.core.app.ServiceCompat.startForeground (ServiceCompat.java:172) at net.braun_home.sensorrecording.SensorService.onStartCommand (SensorService.java:549) at android.app.ActivityThread.handleServiceArgs (ActivityThread.java:5268)
I have written and published an app “Sensor Recording” which reads out and displays the measured values of some sensors (position, acceleration, orientation, microphone, etc.). The app records sensor data continuously in the background, even if the display is switched OFF (standby mode). For this feature, I have established a Service, which is started by user interaction (button click). As of Android version 12, there must be some kind of prerequisites in the code and in the Manifest, which I have fulfilled. Here is a code snippet from “SensorService.java”:
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
// ...
// ...
String channelId = "4711"; // arbitrary
Intent notificationIntent = new Intent(this, SensorService.class);
int flag = PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE;
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, flag);
Notification notification;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) // O = OREO = 26
{
NotificationChannel channel = new NotificationChannel(channelId,
getString(R.string.app_name),
NotificationManager.IMPORTANCE_HIGH);
notMan = getSystemService(NotificationManager.class);
if (notMan != null)
{
notMan.createNotificationChannel(channel);
Notification.Builder builder = new Notification.Builder(this, channelId);
builder.setSmallIcon(R.drawable.vector3d_bg_transp)
.setContentTitle(text0)
.setContentText(text1)
.setTicker(text1)
.setSubText("Start Service")
.setShowWhen(true)
.setAutoCancel(true)
.setTimeoutAfter(500)
.setChannelId(channelId)
.setDefaults(Notification.DEFAULT_ALL)
.setPriority(Notification.PRIORITY_HIGH)
.setCategory(Notification.CATEGORY_MESSAGE)
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setContentIntent(pendingIntent);
notification = builder.build();
int serviceType = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) // Q = Quince Tart = 29
serviceType |= ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) // R = Red Velvet Cake = 30
serviceType |= ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE;
ServiceCompat.startForeground(this, id, notification, serviceType);
}
}
else
{
// ...
}
return START_REDELIVER_INTENT;
}
and an extract from “AndroidManifest.xml”:
<manifest ...>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE"/>
<!--
...
...
-->
<service android:name=".SensorService"
android:foregroundServiceType="location|microphone"
android:exported="false" />
</application>
</manifest>
This works fine on the four devices / Android versions which I have tested:
- Samsung Galaxy A14 (Android 13)
- Google Pixel 6a (Android 15)
- Samsung Galaxy Tab A 10.5 (Android 10)
- Huawei P10 Lite (Android 8.0)
However, in the Google Developer Console (Section Android Vitals, Crashes and ANRs), I get frequent error messages from other devices (with Android 14 or 15), on which I have no physical access:
- Google tangorpro
- T-Mobile CypressPoint
- Safaricom Neon_Smarta_2
- Goggle oriole
- Samsung a06
- Samsung a15
The error always occurs in the line
ServiceCompat.startForeground(this, id, notification, serviceType);
and is either “SecurityException“ or “ForegroundServiceStartNotAllowedException”. How can I locate the source of the errors?
Here is an example Stacktrace for "SecurityException":
Exception java.lang.RuntimeException: at android.app.ActivityThread.handleServiceArgs (ActivityThread.java:4952) at android.app.ActivityThread.-$$Nest$mhandleServiceArgs (Unknown Source) at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2381) 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:8376) at java.lang.reflect.Method.invoke at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:640) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:982) Caused by java.lang.SecurityException: at android.os.Parcel.createExceptionOrNull (Parcel.java:3057) at android.os.Parcel.createException (Parcel.java:3041) at android.os.Parcel.readException (Parcel.java:3024) at android.os.Parcel.readException (Parcel.java:2966) at android.app.IActivityManager$Stub$Proxy.setServiceForeground (IActivityManager.java:6842) at android.app.Service.startForeground (Service.java:862) at androidx.core.app.ServiceCompat$Api34Impl.startForeground (ServiceCompat.java:241) at androidx.core.app.ServiceCompat.startForeground (ServiceCompat.java:172) at net.braun_home.sensorrecording.SensorService.onStartCommand (SensorService.java:549) at android.app.ActivityThread.handleServiceArgs (ActivityThread.java:4934) Caused by android.os.RemoteException: Remote stack trace: at com.android.server.am.ActiveServices.validateForegroundServiceType (ActiveServices.java:2690) at com.android.server.am.ActiveServices.setServiceForegroundInnerLocked (ActiveServices.java:2401) at com.android.server.am.ActiveServices.setServiceForegroundLocked (ActiveServices.java:1748) at com.android.server.am.ActivityManagerService.setServiceForeground (ActivityManagerService.java:13460) at android.app.IActivityManager$Stub.onTransact (IActivityManager.java:3422)
and a Stacktrace for "ForegroundServiceStartNotAllowedException":
Share Improve this question edited Jan 30 at 9:33 Michael Braun asked Jan 29 at 16:22 Michael BraunMichael Braun 1616 bronze badges 2Exception java.lang.RuntimeException: at android.app.ActivityThread.handleServiceArgs (ActivityThread.java:5286) at android.app.ActivityThread.-$$Nest$mhandleServiceArgs (Unknown Source) at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2531) at android.os.Handler.dispatchMessage (Handler.java:106) at android.os.Looper.loopOnce (Looper.java:230)
at android.os.Looper.loop (Looper.java:319) at android.app.ActivityThread.main (ActivityThread.java:8919) at java.lang.reflect.Method.invoke at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:578) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1103) Caused by android.app.ForegroundServiceStartNotAllowedException: at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel (ForegroundServiceStartNotAllowedException.java:54) at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel (ForegroundServiceStartNotAllowedException.java:50) at android.os.Parcel.readParcelableInternal (Parcel.java:4882) at android.os.Parcel.readParcelable (Parcel.java:4864) at android.os.Parcel.createExceptionOrNull (Parcel.java:3064) at android.os.Parcel.createException (Parcel.java:3053) at android.os.Parcel.readException (Parcel.java:3036) at android.os.Parcel.readException (Parcel.java:2978) at android.app.IActivityManager$Stub$Proxy.setServiceForeground (IActivityManager.java:7234) at android.app.Service.startForeground (Service.java:862) at androidx.core.app.ServiceCompat$Api34Impl.startForeground (ServiceCompat.java:241) at androidx.core.app.ServiceCompat.startForeground (ServiceCompat.java:172) at net.braun_home.sensorrecording.SensorService.onStartCommand (SensorService.java:549) at android.app.ActivityThread.handleServiceArgs (ActivityThread.java:5268)
- what does the full error log say, please post it – tyczj Commented Jan 29 at 16:27
- See the two example Stacktraces above. – Michael Braun Commented Jan 30 at 9:33
1 Answer
Reset to default 0After many days of investigations and tests without success, I decided to ask ChatGPT. And guess what? It came up with an error analysis:
The reason for the exceptions was not the device or Android version. The problem was the following: Some users obviously did not always grant the required permissions, e.g. for location or microphone. In Android 14+ this leads to the exceptions mentioned above, if the missing permissions are not handled properly. Solution:
Code snippet SensorService.java:
// handling of permissions
int serviceType = FOREGROUND_SERVICE_TYPE_NONE; // = 0
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) // = 34 (Android 14)
{
// a) location
if ((checkSelfPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED) ||
(checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) ||
(checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED))
{
serviceType |= ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION;
}
// b) microphone
if (checkSelfPermission(Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED)
{
serviceType |= ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE;
}
if (serviceType == FOREGROUND_SERVICE_TYPE_NONE) // nothing granted?
{
serviceType = FOREGROUND_SERVICE_TYPE_SPECIAL_USE; // substitute
}
}
// now start the service
ServiceCompat.startForeground(this, id, notification, serviceType);
Code snippet AndroidManifest.xml:
<manifest ...>
<application
<!--
...
...
-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE"/>
<!--
...
...
-->
<service android:name=".SensorService"
android:foregroundServiceType="location|microphone|specialUse"
android:exported="false">
<property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
android:value=
"This app records data from all smartphone sensors - including location and microphone.
These two sensors require the related permission from the user.
The method startForeground() is then started with the corresponding serviceType.
If none of these two permissions is granted, the serviceType would be 0, which would lead to an Exception.
To avoid this, the FOREGROUND_SERVICE_TYPE_SPECIAL_USE is taken as a substitute."/>
</service>
</application>
</manifest>
If the user does not grant the permissions for neither LOCATION nor MICROPHONE, there has to be a placeholder SPECIAL_USE to avoid exceptions. By the way: Its use must be justified to Google before publication in the Play Store (see AndroidManifest.xml, section property).
Google doesn't make life easy for developers (sigh!), does it? And a meaningful error message (such as MissingPermissionsException) would have helped to quickly find the cause.
本文标签: Android startForeground() causes Exceptions on some DevicesStack Overflow
版权声明:本文标题:Android startForeground() causes Exceptions on some Devices - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1745290621a2651770.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论