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":

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)

Share Improve this question edited Jan 30 at 9:33 Michael Braun asked Jan 29 at 16:22 Michael BraunMichael Braun 1616 bronze badges 2
  • 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
Add a comment  | 

1 Answer 1

Reset to default 0

After 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