7

I am newbie Android developer who is trying to debug why our app is crashing. We are experiencing crashes when we attempt to send push notifications to an Android device. This is an onboarding ticket that I need to solve .I don't know what is causing this issue which can be reproduced in Android N, O and P. Our stack trace from Fabric is given below

Caused by java.lang.SecurityException: UID 10243 does not have permission to content://media/external/audio/media/5927 [user 0]
       at android.os.Parcel.createException + 1966(Parcel.java:1966)
       at android.os.Parcel.readException + 1934(Parcel.java:1934)
       at android.os.Parcel.readException + 1884(Parcel.java:1884)
       at android.app.INotificationManager$Stub$Proxy.enqueueNotificationWithTag + 1653(INotificationManager.java:1653)
       at android.app.NotificationManager.notifyAsUser + 429(NotificationManager.java:429)
       at android.app.NotificationManager.notify + 379(NotificationManager.java:379)
       at android.app.NotificationManager.notify + 355(NotificationManager.java:355)
       at com.myproject.mobile.notifications.NotificationHelper.process + 66(NotificationHelper.java:66)
       at com.myproject.mobile.notifications.NotificationService.constructNotification + 709(NotificationService.java:709)
       at com.myproject.mobile.notifications.NotificationService.processNotification + 173(NotificationService.java:173)
       at com.myproject.mobile.notifications.PushJobIntentService.onHandleWork + 24(PushJobIntentService.java:24)
       at androidx.core.app.JobIntentService$CommandProcessor.doInBackground + 392(JobIntentService.java:392)
       at androidx.core.app.JobIntentService$CommandProcessor.doInBackground + 383(JobIntentService.java:383)
       at android.os.AsyncTask$2.call + 333(AsyncTask.java:333)
       at java.util.concurrent.FutureTask.run + 266(FutureTask.java:266)
       at java.util.concurrent.ThreadPoolExecutor.runWorker + 1167(ThreadPoolExecutor.java:1167)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run + 641(ThreadPoolExecutor.java:641)
       at java.lang.Thread.run + 764(Thread.java:764)

The block of code that calls NotificationManager

public void process()
    {
        NotificationPayload payload = getPayload(); # Helper function to create a payload object. The object is a Java Bean.
        final NotificationHelper helper = new NotificationHelper(context, payloadObject);
        if (helper != null)
        {

            // Notification channels set up.
            setupChannels(context); // IntentService context.

            Notification notification = helper.buildNotification(payload); // to set up notifications.
            if (notification != null)
             NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
                notificationManager.notify(payload.getNotificationId(), notification);
        }
    }

File Provider XML file file_provider_paths.xml.

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <cache-path
        name="photos"
        path="images/" />
</paths>

File Provider definition in Android Manifest

<provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.fileProvider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_provider_paths" />
        </provider>

More stack traces from Fabric

Caused by android.os.RemoteException: Remote stack trace:
    at com.android.server.am.ActivityManagerService.checkGrantUriPermissionLocked(ActivityManagerService.java:12738)
    at com.android.server.am.ActivityManagerService.checkGrantUriPermission(ActivityManagerService.java:12755)
    at com.android.server.notification.NotificationRecord.visitGrantableUri(NotificationRecord.java:1147)
    at com.android.server.notification.NotificationRecord.calculateGrantableUris(NotificationRecord.java:1123)
    at com.android.server.notification.NotificationRecord.<init>(NotificationRecord.java:208)

My proposed PR would have added the following entry to file_provider_paths.xml, but my PR was closed because the reviewer's comment was

sound files are packages resources and not saved in external storage

<external-path
        name="external_files"
        path="." />

UPDATE

Builder function to build the notification

public Notification buildNotification(NotificationPayload payload)
    {
        final NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "channelId");

        final RemoteViews collapsedView = new RemoteViews(context.getPackageName(), R.layout.expanded_notification)


        if (payload.getTitle() != null)
            builder.setContentTitle(payload.getTitle());
        if (payload.getBody() != null)
            builder.setContentText(payload.getBody());

            builder.setContentIntent(payload.getClickIntent(context));

            builder.setDeleteIntent(payload.getDeleteIntent(context));


        builder.setCustomContentView(collapsedView);

        builder.setAutoCancel(true);

         builder.setSound(Uri.parse("android.resource://" + BuildConfig.APPLICATION_ID + "/" + R.raw.notif_general));
        return builder.build();
    }

UPDATE # 2*

This is how the sounds are set for notification channels.

@RequiresApi(Build.VERSION_CODES.O)
@VisibleForTesting()
void setSound(Context context, NotificationChannel channel, String soundUri)
{
    AudioAttributes audioAttribute = new AudioAttributes.Builder()
        .setUsage(AudioAttributes.USAGE_NOTIFICATION)
        .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
        .build();

    channel.setSound(Uri.parse(soundUri), audioAttribute);
}

Creation of NotificationChannel

@TargetApi(26)
void registerChannel(Context context, NotificationManager notificationManager, String id, String name, String soundUri)
{
    if (notificationManager.getNotificationChannel(id) != null)
        return;

    NotificationChannel channel = new NotificationChannel(id, name, NotificationManager.IMPORTANCE_DEFAULT);

    channel.enableLights(true);
    channel.setLightColor(Color.BLUE);
    channel.enableVibration(false);

    if (soundUri != null)
    {
        setSound(context, channel, soundUri);
    }
    notificationManager.createNotificationChannel(channel);
}

My question is how do I resolve this crash.

Kartik
  • 2,541
  • 2
  • 37
  • 59
  • Your problem appears to lie in `buildNotification()`, where you are using a `Uri` that you do not have rights to. – CommonsWare Aug 29 '19 at 21:33
  • @CommonsWare updated the post with the helper function. – Kartik Aug 29 '19 at 22:22
  • The stack trace shows a different sort of `Uri`, one from `MediaStore`. It is neither `android.resource` nor one from your `FileProvider`. You are going to need to identify where that `MediaStore` `Uri` is coming from. – CommonsWare Aug 30 '19 at 00:01
  • @CommonsWare Updated the post. – Kartik Aug 30 '19 at 00:24
  • I've seen this issue occur mostly on Samsung Galaxy phones running Android 9. Not sure what exactly is causing it, and I haven't been able to reproduce it myself. The strangest thing is that this happens on notifications that don't have any sound assigned to them. Are you changing the notification settings of the app on the OS? How are you reproducing this issue? – Pablo Baxter Nov 01 '19 at 19:31
  • @PabloBaxter I have not been able to reproduce this issue, and you are right, in that it is reproduced on Samsung devices. – Kartik Nov 01 '19 at 19:49
  • Did you rename/remove/add resources to your project before this began happening? – Pablo Baxter Nov 01 '19 at 19:52
  • @PabloBaxter I did not do anything. – Kartik Nov 01 '19 at 20:01
  • @Kartik, does this also crash on all other notifications? I'm seeing this occur for any notification that comes up when a phone gets into this state (example, foreground notification). I don't see this happening for all the users we have, but whatever triggers it, seems to break notifications for the affected users. – Pablo Baxter Nov 01 '19 at 21:57
  • @PabloBaxter I don't know how to reproduce this issue. – Kartik Nov 01 '19 at 22:42
  • @Kartik have you found valid solution for this? – Artur Latoszewski Mar 10 '20 at 13:32
  • @Kartik, I am also facing the same issue. Based on the crashlytics report, the issue happened in the Samsung as well Xiaomi devices. Were you able to find the cause of the issue? – Raghul Vaikundam Jan 28 '21 at 06:03
  • 2
    For us, this is happening exclusively on Android 9.0+ (API level 28+), and only when targeting API level 28+, but across all manufacturers. Also, in *our* case, it does *not* matter whether the storage permission has been granted or not. Anyway, it appears that it happens because `NotificationChannel#setSound` has initially been called with a `content://` URI on devices upgraded from API level 27 and below. Calling `NotificationCompat.Builder#setSound` later or changing the sound in the channel manually (via the UI) does not cause problems. See also: https://stackoverflow.com/q/54120745 – caw Apr 29 '21 at 01:15

1 Answers1

0

Please check you manifest File or FileProvider

 File outputFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "Spirals"+namensss+".pdf");
                    Uri imageUri = FileProvider.getUriForFile(
                            ZoomPdf.this,
                            ".FileProvider", //(use your app signature + ".provider" )
                            outputFile);