Laerdal / Laerdal.Dfu

Xamarin binding library around @NordicSemiconductor's DFU library.
BSD 3-Clause "New" or "Revised" License
18 stars 18 forks source link

DfuInstallation.Start() throws Bad notification for startForeground thrown on .Net MAUI (Android) #28

Open juniorsaraviao opened 10 months ago

juniorsaraviao commented 10 months ago

Describe the bug I'm implementing the functionality to upgrade a firmware using DFU but it throws an exception when executing DfuInstallation.Start().

I've declared the Foreground Service permission on AndroidManifest.xml and a Foreground service link but it's still throwing the error.

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

To Reproduce Steps to reproduce the behavior:

  1. Create a MAUI project (NET 8)
  2. Install the Laerdal.Dfu 1.27.8 NuGet package
  3. Include the Foreground Service permission on AndroidManifest.xml.
  4. Implement a Foreground service.
  5. Create a method to download or retrieve your firmware update file.
  6. Scan for the desired device to DFU.
  7. Create the DfuInstallation object and call Start().

Expected behavior Start and complete the DFU process with the BLE device.

Desktop:

Smartphone:

Additional context Logs:

[DfuBaseService] DFU service destroyed
[AndroidRuntime] Shutting down VM
[AndroidRuntime] FATAL EXCEPTION: main
[AndroidRuntime] Process: com.company, PID: 11852
[AndroidRuntime] android.app.RemoteServiceException$CannotPostForegroundServiceNotificationException: Bad notification for startForeground
[AndroidRuntime]    at android.app.ActivityThread.throwRemoteServiceException(ActivityThread.java:2222)
[AndroidRuntime]    at android.app.ActivityThread.-$$Nest$mthrowRemoteServiceException(Unknown Source:0)
[AndroidRuntime]    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2508)
[AndroidRuntime]    at android.os.Handler.dispatchMessage(Handler.java:106)
[AndroidRuntime]    at android.os.Looper.loopOnce(Looper.java:226)
[AndroidRuntime]    at android.os.Looper.loop(Looper.java:313)
[AndroidRuntime]    at android.app.ActivityThread.main(ActivityThread.java:8762)
[AndroidRuntime]    at java.lang.reflect.Method.invoke(Native Method)
[AndroidRuntime]    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:604)
[AndroidRuntime]    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
ISSPRO-Eng commented 9 months ago

Yeah I have been running into multiple issues with this repo in .NET Maui currently as well

mattalanskas commented 9 months ago

@juniorsaraviao Any updates on this issue? I am seeing this issue as well while migrating from Xamarin Forms to MAUI

juniorsaraviao commented 9 months ago

@mattalanskas not really, I was also thinking that this was related to the PostNotification permission but even declaring and allowing it the app still throws the exception.

<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

I remember while the firmware was upgrading, it appeared a notification to show the progress (Xamarin Android version).

schneifa commented 9 months ago

I had the same issue on Android. If you do not need the foreground notification, you can disable it in the DfuConfiguration. This worked for me:

_output = new DfuInstallation(address, file);   
_output.DfuErrorReceived += OnDfuErrorOccured;
_output.DfuStateChanged += OnDfuStateChanged;
_output.DfuProgressChanged += OnDfuProgressChanged;
var config = new DfuConfiguration() { DisableNotification = true };
_output.Start(config);
juniorsaraviao commented 9 months ago

The workaround to use DfuConfiguration worked for me too.

ISSPRO-Eng commented 8 months ago

Got the foreground issue done with the above workaround. I am now running into an invalid BT Address. I had been using this address in my Xamarin app but now it seems to be an issue. [AndroidRuntime] java.lang.IllegalArgumentException: 00000000-0000-0000-0000-cd196234d6e5 is not a valid Bluetooth address

I get this from here. string deviceID = _connection.LastConnectedDevice.Id.ToString(); vm.ConnectionInfoString = deviceInfo; DfuInstallationConfigurationPageViewModel.Instance.DeviceID = deviceID;

schneifa commented 8 months ago

Got the foreground issue done with the above workaround. I am now running into an invalid BT Address. I had been using this address in my Xamarin app but now it seems to be an issue. [AndroidRuntime] java.lang.IllegalArgumentException: 00000000-0000-0000-0000-cd196234d6e5 is not a valid Bluetooth address

I get this from here. string deviceID = _connection.LastConnectedDevice.Id.ToString(); vm.ConnectionInfoString = deviceInfo; DfuInstallationConfigurationPageViewModel.Instance.DeviceID = deviceID;

The package expects the Bluetooth address in the format "XX:XX:XX:XX:XX:XX". I use this method to convert from the Guid:

private string DevIdToBleAddress(Guid id)
{
    var bytes = id.ToByteArray();
    var relevantBytes = new byte[6];
    Array.Copy(bytes, 10, relevantBytes, 0, 6);
    var str = BitConverter.ToString(relevantBytes);
    var result = str.Replace("-", ":");
    return result;
}

It's basically the last part of the Guid (in your case cd196234d6e5) in this format, which would be CD:19:62:34:D6:E5

WanftMoon commented 8 months ago

Got the foreground issue done with the above workaround. I am now running into an invalid BT Address. I had been using this address in my Xamarin app but now it seems to be an issue. [AndroidRuntime] java.lang.IllegalArgumentException: 00000000-0000-0000-0000-cd196234d6e5 is not a valid Bluetooth address I get this from here. string deviceID = _connection.LastConnectedDevice.Id.ToString(); vm.ConnectionInfoString = deviceInfo; DfuInstallationConfigurationPageViewModel.Instance.DeviceID = deviceID;

The package expects the Bluetooth address in the format "XX:XX:XX:XX:XX:XX". I use this method to convert from the Guid:

private string DevIdToBleAddress(Guid id)
{
    var bytes = id.ToByteArray();
    var relevantBytes = new byte[6];
    Array.Copy(bytes, 10, relevantBytes, 0, 6);
    var str = BitConverter.ToString(relevantBytes);
    var result = str.Replace("-", ":");
    return result;
}

It's basically the last part of the Guid (in your case cd196234d6e5) in this format, which would be CD:19:62:34:D6:E5

Yeah, confirmed for Android. It needs the Address, while for iOS, it is the GUID

ISSPRO-Eng commented 8 months ago

Thanks for the help all. Can probably close this issue.

siki411 commented 4 months ago

hi everyone i hope you are doing fine and best of your health actually i am stuck in dfu plus i am new to maui as well as andriod development. i have downloaded 1.27.8 NuGet package and then select file as initiate the dfu but it doesnt work for me and dfu service destroyed after few secondi am sharing the log as well private async Task StartDfuProcess(string filePath) { try { //string Device_address = "C2:08:51:5F:5F:C0"; string Device_address = "D8:12:F2:92:46:8B"; var fileExists = File.Exists(filePath); Debug.WriteLine($"File path exists: {fileExists}");

    if (!fileExists)
    {
        Debug.WriteLine("File does not exist, aborting DFU process.");
        return;
    }
    Debug.WriteLine("DFU process is about to start.");
    var _output = new DfuInstallation(Device_address, filePath);

    _output.Start();
    Debug.WriteLine("DFU process started successfully.");
}
catch (Exception ex)
{
    Debug.WriteLine($"Error during DFU process: {ex.Message}");
}

} and logs are DOTNET] File selected: /data/data/com.companyname.bluetoothcourse/cache/2203693cc04e0be7f4f024d5f9499e13/53f9c563f2c64434802f68ded273b562/dfu_application.zip [0:] File path exists: True [0:] DFU process is about to start. [0:] DFU process started successfully. [ViewRootImpl@ef052e8[IntermediateActivity]] stopped(false) old=true [DfuBaseService] DFU service created. Version: 2.3.0 [ViewRootImpl@ef052e8[IntermediateActivity]] stopped(false) old=false [DfuBaseService] Starting DFU service in foreground [SurfaceControl] assignNativeObject: nativeObject = 0 Surface(name=null)/@0x27983d / android.view.SurfaceControl.readFromParcel:1121 android.view.IWindowSession$Stub$Proxy.relayout:1830 android.view.ViewRootImpl.relayoutWindow:9005 android.view.ViewRootImpl.performTraversals:3360 android.view.ViewRootImpl.doTraversal:2618 android.view.ViewRootImpl$TraversalRunnable.run:9971 android.view.Choreographer$CallbackRecord.run:1010 android.view.Choreographer.doCallbacks:809 android.view.Choreographer.doFrame:744 android.view.Choreographer$FrameDisplayEventReceiver.run:995 [SurfaceControl] assignNativeObject: nativeObject = 0 Surface(name=null)/@0xd062d01 / android.view.SurfaceControl.readFromParcel:1121 android.view.IWindowSession$Stub$Proxy.relayout:1840 android.view.ViewRootImpl.relayoutWindow:9005 android.view.ViewRootImpl.performTraversals:3360 android.view.ViewRootImpl.doTraversal:2618 android.view.ViewRootImpl$TraversalRunnable.run:9971 android.view.Choreographer$CallbackRecord.run:1010 android.view.Choreographer.doCallbacks:809 android.view.Choreographer.doFrame:744 android.view.Choreographer$FrameDisplayEventReceiver.run:995 [ViewRootImpl@ef052e8[IntermediateActivity]] Relayout returned: old=(0,0,1080,2340) new=(0,0,1080,2340) req=(1080,2340)4 dur=10 res=0x1 s={false 0} ch=false fn=-1 Thread started: #26 [ViewRootImpl@2cac53e[MainActivity]] stopped(false) old=true [ViewRootImpl@2cac53e[MainActivity]] stopped(false) old=false [SurfaceControl] assignNativeObject: nativeObject = 0 Surface(name=null)/@0x88124b5 / android.view.SurfaceControl.readFromParcel:1121 android.view.IWindowSession$Stub$Proxy.relayout:1840 android.view.ViewRootImpl.relayoutWindow:9005 android.view.ViewRootImpl.performTraversals:3360 android.view.ViewRootImpl.doTraversal:2618 android.view.ViewRootImpl$TraversalRunnable.run:9971 android.view.Choreographer$CallbackRecord.run:1010 android.view.Choreographer.doCallbacks:809 android.view.Choreographer.doFrame:744 android.view.Choreographer$FrameDisplayEventReceiver.run:995 [ViewRootImpl@2cac53e[MainActivity]] Relayout returned: old=(0,0,1080,2340) new=(0,0,1080,2340) req=(1080,2340)0 dur=15 res=0x7 s={true 488279658496} ch=true fn=-1 [DfuArchiveInputStream] Manifest failed to be parsed. Did you add [DfuArchiveInputStream] -keep class no.nordicsemi.android.dfu.* { ; } [DfuArchiveInputStream] to your proguard rules? [DfuBaseService] An exception occurred while calculating file size [DfuBaseService] java.io.IOException: The ZIP file must contain an Application, a Soft Device and/or a Bootloader. [DfuBaseService] at no.nordicsemi.android.dfu.internal.ArchiveInputStream.(ArchiveInputStream.java:269) [DfuBaseService] at no.nordicsemi.android.dfu.DfuBaseService.openInputStream(DfuBaseService.java:1457) [DfuBaseService] at no.nordicsemi.android.dfu.DfuBaseService.onHandleIntent(DfuBaseService.java:1201) [DfuBaseService] at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:77) [DfuBaseService] at android.os.Handler.dispatchMessage(Handler.java:106) [DfuBaseService] at android.os.Looper.loop(Looper.java:246) [DfuBaseService] at android.os.HandlerThread.run(HandlerThread.java:67) Thread finished: #26 [DfuBaseService] DFU service destroyed [SurfaceControl] assignNativeObject: nativeObject = 0 Surface(name=null)/@0x27983d / android.view.SurfaceControl.readFromParcel:1121 android.view.IWindowSession$Stub$Proxy.relayout:1830