Alen.Toma
Alen.Toma

Reputation: 4870

Android sometimes throw fatal error when creating Notification

Im very new to xamarin and created download Notification. It works for the most time but sometime the app get a fetal error and shutdown after the creation of the Notification.

I only get this rapport, which i have no idee how to trace.

=================================================================
    Native Crash Reporting
=================================================================
Got a SIGSEGV while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries 
used by your application.
=================================================================
06-02 05:39:28.296 E/mono-rt (16761): /proc/self/maps:
06-02 05:39:28.296 E/mono-rt (16761): 12c00000-16f40000 rw-p 00000000 00:01 25459                              /dev/ashmem/dalvik-main space (region space)_4473_4473 (deleted)
06-02 05:39:28.296 E/mono-rt (16761): 16f40000-172c0000 rw-p 04340000 00:01 25459                              /dev/ashmem/dalvik-main space (region space)_4473_4473 (deleted)
06-02 05:39:28.296 E/mono-rt (16761): 172c0000-17340000 ---p 046c0000 00:01 25459                              /dev/ashmem/dalvik-main space (region space)_4473_4473 (deleted)
06-02 05:39:28.296 E/mono-rt (16761): 17340000-173c0000 rw-p 04740000 00:01 25459                              /dev/ashmem/dalvik-main space (region space)_4473_4473 (deleted)
06-02 05:39:28.296 E/mono-rt (16761): 173c0000-18380000 ---p 047c0000 00:01 25459                              /dev/ashmem/dalvik-main space (region space)_4473_4473 (deleted)
06-02 05:39:28.296 E/mono-rt (16761): 18380000-183c0000 rw-p 05780000 00:01 25459                              /dev/ashmem/dalvik-main space (region space)_4473_4473 (deleted)
06-02 05:39:28.297 E/mono-rt (16761): 183c0000-18400000 ---p 057c0000 00:01 25459                              /dev/ashmem/dalvik-main space (region space)_4473_4473 (deleted)

=================================================================
    Basic Fault Adddress Reporting
=================================================================
Memory around native instruction pointer (0x6f51ecb678):0x6f51ecb668  00 1c 40 b9 c0 03 5f d6 fd 7b bf a9 fd 03 00 91  ..@..._..{......
0x6f51ecb678  08 20 40 b9 a8 00 c8 37 88 01 e0 37 00 00 40 f9  . @....7...7..@.
0x6f51ecb688  fd 7b c1 a8 c0 03 5f d6 60 08 00 b0 01 0a 00 f0  .{...._.`.......
0x6f51ecb698  03 0a 00 f0 00 24 06 91 21 80 08 91 63 8c 0a 91  .....$..!...c...

No native Android stacktrace (see debuggerd output).

Here is how i start the service

  Methods.OnVideoDownload += new Action<Manager.Models.Container.YoutubeFileDownloadItem>((video) =>
    {
        if (!ObjectCacher.DownloadingFiles.ContainsKey(video.VideoId))
        {
            ObjectCacher.DownloadingFiles.Add(video.VideoId, video);
            var intent = new Intent(this, typeof(FileService));
            intent.PutExtra(FileService.URL, new AppManager().GetVideoStreamUrl(video.VideoId, 18));
            intent.PutExtra(FileService.Title, video.Title);
            intent.PutExtra(FileService.DirectoryName, Path.Combine(Methods.LocalMusicFolder, video.Playlist));
            intent.PutExtra(FileService.FileName, video.GenerateLocalPath());

            if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
            {
                var servive = this.StartForegroundService(intent);
            }
            else
            {
                this.StartService(intent);
            }
        }
    });

And here is onstartCommand which after the return of return StartCommandResult.Sticky; the application shut down

 public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
    {
        PendingIntent pendingIntent = PendingIntent.GetActivity(MainActivity.Current, 0, intent, 0);
        var url = intent.GetStringExtra(URL);
        var fileName = intent.GetStringExtra(FileName);
        var directory = intent.GetStringExtra(DirectoryName);
        var title = intent.GetStringExtra(Title);

        intent.AddFlags(ActivityFlags.ClearTop);
        var nb = NotificationHelper.GetNotification1(GetString(Resource.String.Downloading) + " " + title, GetString(Resource.String.DownloadProgress), pendingIntent);


        if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
        {
            StartForeground(NotificationId, nb.Build());
        }


        var _downlodFile = new DownlodFile(url, directory, fileName, new Action<int>((procent) =>
        {
            nb.SetContentText("")
            .SetContentTitle(GetString(Resource.String.Downloading) + $" ({procent}%) " + title)
            .SetProgress(100, procent, false);
            NotificationHelper.Notify(NotificationId, nb);
        }), new Action(async () =>
        {
            try
            {
                await Methods.DownloadCompleted(fileName);
            }
            catch (Exception ex)
            {
            }
            nb.SetOnlyAlertOnce(false).SetProgress(0, 0, false)
            .SetContentText(GetString(Resource.String.Finished));
            await Task.Delay(100);
            NotificationHelper.Notify(NotificationId, nb);
            ObjectCacher.RandomIdCacher.Remove(NotificationId);
            nb.Dispose();
            NotificationHelper.Dispose();
            if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
            {
                StopForeground(true);
            }

        }), new Action<Exception>((e) =>
        {
            nb.SetProgress(0, 0, false).SetContentText("Error: Something went wrong.\n Please try agen later.");
            NotificationHelper.Notify(NotificationId, nb);
            ObjectCacher.RandomIdCacher.Remove(NotificationId);
            nb.Dispose();
            NotificationHelper.Dispose();
            if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
            {
                StopForeground(true);
            }
        }));
        _downlodFile.Download();
        NotificationHelper.Notify(NotificationId, nb);
        return StartCommandResult.Sticky;
    }
}

Here is DownloadFile object

public class DownlodFile : IDisposable
{
    private readonly WebClient _client;
    private readonly Action<int> _onProgress;
    private readonly Action<Exception> _onError;
    private readonly Action _onComplete;
    private readonly Uri _url;
    private readonly string _fileName;
    private readonly string _directoryName;

    public bool Downloading { get; private set; }
    // this will be true when the complete event trigger or an error trigger
    public bool FileCompleted { get; private set; }

    /// <summary>
    /// DownlodFile
    /// </summary>
    /// <param name="url">File Url</param>
    /// <param name="filelocation">Where file will e saved on the system</param>
    /// <param name="progressChanged">Get the ProgressPercentage</param>
    /// <param name="error">When an error accord</param>
    public DownlodFile(string url, string directoryName, string fileName, Action<int> progressChanged = null, Action completed = null, Action<Exception> error = null)
    {
        _client = new WebClient();
        _onProgress = progressChanged;
        _fileName = fileName;
        _directoryName = directoryName;
        _onComplete = completed;
        _onError = error;
        _url = url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) ? new Uri(url) : new Uri("http://" + url);

        var proc = 0;
        _client.DownloadProgressChanged += new DownloadProgressChangedEventHandler((o, e) =>
        {
            if (proc != e.ProgressPercentage)
                _onProgress?.Invoke(e.ProgressPercentage);
            proc = e.ProgressPercentage;

        });
        _client.DownloadDataCompleted += new DownloadDataCompletedEventHandler((o, e) =>
        {
            try
            {
                File.WriteAllBytes(Path.Combine(_directoryName, _fileName), e.Result);
                _onComplete?.Invoke();
                this.Dispose();
            }
            catch
            {
                this.Dispose();
            }

        });



    }


    public void Download()
    {
        try
        {
            if (!Directory.Exists(_directoryName))
                Directory.CreateDirectory(_directoryName);

            if (!FileCompleted)
            {
                Downloading = true;
                // Start downloading the file
                _client.DownloadDataAsync(_url);
            }
            else throw new Exception("DownlodFile is already disposed, please Create a new one");
        }
        catch (Exception ex)
        {
            FileCompleted = true;
            this.Dispose();
            _onError?.Invoke(ex);

        }

    }


    public void Dispose()
    {
        if (!FileCompleted)
            _client.Dispose();
        FileCompleted = true;
        Downloading = false;
    }
}

}

Any idee of what causing this problem or even how to trace it.

Update New error Log

Time    Device Name Type    PID Tag Message
06-02 14:40:50.354  Samsung SM-G960F    Error   22222   ActivityThread  android.app.IntentReceiverLeaked: Service com.google.android.youtube.api.service.YouTubeService has leaked IntentReceiver ahmr@b5a2701 that was originally registered here. Are you missing a call to unregisterReceiver()?
    at android.app.LoadedApk$ReceiverDispatcher.<init>(LoadedApk.java:1538)
    at android.app.LoadedApk.getReceiverDispatcher(LoadedApk.java:1277)
    at android.app.ContextImpl.registerReceiverInternal(ContextImpl.java:1555)
    at android.app.ContextImpl.registerReceiver(ContextImpl.java:1528)
    at android.app.ContextImpl.registerReceiver(ContextImpl.java:1516)
    at android.content.ContextWrapper.registerReceiver(ContextWrapper.java:636)
    at ajgx.<init>(SourceFile:42)
    at ajic.get(SourceFile:30)
    at baxz.get(SourceFile:9)
    at baxw.get(SourceFile:4)
    at mlt.F(SourceFile:23)
    at ahlo.a(SourceFile:5)
    at ahlo.get(SourceFile:7)
    at baxz.get(SourceFile:9)
    at mma.a(SourceFile:3)
    at mkr.<init>(SourceFile:11)
    at com.google.android.apps.youtube.embeddedplayer.service.service.jar.ApiPlayerService.<init>(SourceFile:46)
    at com.google.android.apps.youtube.embeddedplayer.service.service.jar.ApiPlayerFactoryService$1.run(SourceFile:4)
    at android.os.Handler.handleCallback(Handler.java:873)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:214)
    at android.app.ActivityThread.main(ActivityThread.java:6981)
    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:1445)

Upvotes: 1

Views: 167

Answers (1)

Saamer
Saamer

Reputation: 5109

There could be several reasons depending on what device you are running (phone/emulator, Android version, was the error before/after giving the permission from the user, have permissions been denied).

The reason I suspect is that you are not handling Permissions properly, and the other probable cause could be that you are not running the file download work in the UI thread. So update the line to something like this

this.Activity.RunOnUiThread(() =>
{
    _downlodFile.Download();
});

You could

  1. Create a System Catchpoint exception,
  2. Launch a profiler to track the error,
  3. (and should) Use try-catch statements, to basically figure out exactly what line the code is crashing on, & what's the internal stack trace.

Upvotes: 1

Related Questions