dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
22.27k stars 1.76k forks source link

SecureStorage.GetAsync() hangs in Android devices with .NET 8 GA in VS 2022 17.8.0 - Demo REPO #18817

Open schlaman opened 1 year ago

schlaman commented 1 year ago

Description

When invoking SecureStorage.GetAsync in App.Xaml.cs in the constructor. This method will NEVER return. No exception thrown, it just never returns. It works fine in Windows and and iOS but hangs in Android.

I deployed to a physical Android tablet and phone both running Android 13. The Samsung S9 Ultra tablet (SM-X910) and the Samsung Galaxy S22.

I changed from SecureStorage.GetAsync() to Preferences.Get() and then it returns immediately. The sample is as simple as just trying to find a key that doesn't exist. I'm not sure if it matters if the key exists or not, but I am not working with thousands of bytes just literally. GetAsync("password").

There was a reference to this issue from RC1 I believe that said it was fixed but it is not! https://github.com/dotnet/maui/issues/18685

Steps to Reproduce

This REPO is just a new Hello World .NET Maui app with a single line added that causes the app to hang in the splash screen upon deployment to an Android device from VS 2022 17.8.0.

Public REPO - New hello world app with one line added to App.xaml.cs

Link to public reproduction project repository

https://github.com/schlaman/Net8SecureStorageHangsInAndroid

Version with bug

8.0.3

Is this a regression from previous behavior?

Not sure, did not test other versions

Last version that worked well

Unknown/Other

Affected platforms

Android

Affected platform versions

Android 13

Did you find any workaround?

My workaround for now is to use Preferences.Get() instead of SecureStorage.GetAsync(). I'm getting ready to go into beta so for now this is fine but need SecureStorage.GetAsync to work ultimately

Relevant log output

No response

jsuarezruiz commented 1 year ago

This issue should be fixed in the next release by https://github.com/dotnet/maui/pull/17928

ghost commented 1 year ago

We've added this issue to our backlog, and we will work to address it as time and resources allow. If you have any additional information or questions about this issue, please leave a comment. For additional info about issue management, please read our Triage Process.

phillippschmedt commented 1 year ago

@jsuarezruiz Can you please give an estimation on when this will be available? This is essential for our app and I consider this an absolute basic feature, .NET 8 Stable is not stable!

leonluc-dev commented 1 year ago

It seems to be planned for .NET 8 SR1. In the past a SR1 release went live about just over a month after the general release.

I've already tried to build Essentials from more recent .NET 8 source code to test fix #17928. While it fixed the SecureStorage.GetAsync() call in some cases, there are also a few cases where it still doesn't work properly on Android (I've opened a seperate issue for that here a little while ago: #18685)

Hopefully by the time SR1 releases these issues are all fully resolved.

phillippschmedt commented 1 year ago

@leonluc-dev Thanks for the update! I had issues in .NET 7.0 with GetAsync() and had a workaround in place. Now with .NET 8.0 my workaround doesn't work anymore and the whole thing became unusable. It really bothers me that some people still call this production ready.

gerhartz commented 9 months ago

@phillippschmedt what is your workaround for GetAsync() issue in .NET 7? We are stuck using 7 for now. Thanks in advance!

phillippschmedt commented 9 months ago

@gerhartz We had to turn all the calls to the SecureStorage into synchronous calls: Microsoft.Maui.Storage.SecureStorage.Default.GetAsync(key).GetAwaiter().GetResult() I know at one other point in time we also had to execute the calls in Task.Run to make it work.

mr5z commented 9 months ago

This issue should be fixed in the next release by #17928

@jsuarezruiz the fix isn't actually working. I think it would be better to include a unit test where it's operating with and without async/await.

ChristopherStephan commented 8 months ago

Still reproducible with Microsoft.Maui.Essentials v8.0.10.

jonpryor commented 8 months ago

It is extremely important to note that one of the fundamental changes between Xamarin (.Android/.iOS/.Forms) and .NET (Android/iOS/MAUI) is that the BCL implementation changed from Mono (parts of which were based on open-sourced .NET Framework, parts of which are re-implementations) to CoreCLR. This change has lots of compatibility implications, from the "obvious" (AppDomain.CreateDomain() throws an exception on .NET) to the "subtle" (Behavior changes when comparing strings on .NET 5+).

It would not surprise me at all that Task behavior is one of the areas impacted.

Furthermore, there is quite a lot of advice and design guidelines around how to use async/await, including Asynchronous programming scenarios, which states:

  • Write code that awaits Tasks in a non-blocking manner Blocking the current thread as a means to wait for a Task to complete can result in deadlocks and blocked context threads and can require more complex error-handling. …
Use this… Instead of this… When wishing to do this…
await Task.Wait or Task.Result Retrieving the result of a background task

The only reliable fix is to update your code so that async/await is properly used. Using Task.Result or equivalents directly is courting deadlocks. Just because your code works "now" without deadlocks does not mean it will continue to do so, and the Xamarin to .NET migration is a perfect example of that.

Kaibaer commented 8 months ago

I am currently using await _httpClient.GetAsync(endpoint) in my project. The whole app freezes to death right on that line.

I have built the same app as a standard cmdline tool before and it works flawlessly.

MAUI messes this up in no way I can see why it does it.

RobDaytona commented 7 months ago

Still broken! Microsoft.Maui.Essentials v8.0.14

    public async Task<string> Get_Secure_Preference(string key)
    {
        //use .Result to get the string
        string returnString = "";
        string? pref = await SecureStorage.GetAsync(key); //<--HANGING HERE EVERY TIME
        if (pref != null)
        {
            returnString = pref;
        }
        return returnString;
    }

Note the key value its trying to find does not exist in the storage in my calling scenario, and I expect to get "" returned from this, but we just hang on the await call endlessly.

leonluc-dev commented 7 months ago

Still broken! Microsoft.Maui.Essentials v8.0.14

    public async Task<string> Get_Secure_Preference(string key)
    {
        //use .Result to get the string
        string returnString = "";
        string? pref = await SecureStorage.GetAsync(key); //<--HANGING HERE EVERY TIME
        if (pref != null)
        {
            returnString = pref;
        }
        return returnString;
    }

Note the key value its trying to find does not exist in the storage in my calling scenario, and I expect to get "" returned from this, but we just hang on the await call endlessly.

For now the only workaround is to wrap the SecureStorage calls in Task.Run (which executes the wrapped code on a different thread). Top-of-the-head example in your case:

public Task<string> Get_Secure_Preference(string key)
{   
    return Task.Run(async delegate {
        string returnString = "";
        string? pref = await SecureStorage.GetAsync(key);
        if (pref != null)
        {
            returnString = pref;
        }
        return returnString;
    });
 }
RobDaytona commented 7 months ago

@leonluc-dev - Great thank you for your quick reply!

alexgavru commented 7 months ago

Still happening to me as well.

BoungSeokKim commented 7 months ago

using maui 8.0.7 and vs 2022 17.9.2 , it operates normally.

ghood97 commented 7 months ago

This is also happening to me in a .NET Maui Blazor Hybrid app. None of the above suggestions worked for my use case so I just swapped out SecureStorage for Preferences. I know this doesn't provide any security around the storage but it's a nice workaround if you are just developing locally.

askariya commented 7 months ago

I noticed this has labels "fixed in 8.0.14 and 8.0.10". Is it possible for us to get these versions in VS 2022 or VS 2022 Preview?

MartinLichtblau commented 6 months ago

Not solved in 8.0.20!

thomasgalliker commented 6 months ago

Not solved in 8.0.21.

npostma commented 6 months ago

I never had any issues with this in Xamarin, moving over to maui .NET8 seems to be totally different story. I use the latest updates. I am on MAUI 8.0.40 and every string key= await SecureStorage.GetAsync("app_key"); like call takes about 1+ to 2 seconds. Pages that get 3 keys from the secure storage in the OnAppearing (that need some security validation) takes +6 seconds to load. For the sake of testing, i went back to 8.0.21, and that is also slow.

[edit 27-5] It is not slow in the Android emulators only on real devices

askariya commented 2 months ago

Appears to not be fixed in 8.0.82; any call to SecureStorage.GetAsync() hangs indefinitely and freezes the whole app.

lobbo232 commented 2 weeks ago

Appears to not be fixed in 8.0.82; any call to SecureStorage.GetAsync() hangs indefinitely and freezes the whole app.

I'm getting a weird issue where the first time I call the method it returns fine (in OnAppearing event), the second time I call it it will hang and not return (in a button Command). Both times I call the exact same method that contains await SecureStorage.GetAsync("key").

Is this the same issue?

justin-darmody commented 1 week ago

@gerhartz We had to turn all the calls to the SecureStorage into synchronous calls: Microsoft.Maui.Storage.SecureStorage.Default.GetAsync(key).GetAwaiter().GetResult() I know at one other point in time we also had to execute the calls in Task.Run to make it work.

I came upon the same issue using SecureStorage.SetAsync(key, value) and this solution worked for me i.e. SecureStorage.SetAsync(key, value).GetAwaiter().GetResult().

It was only a problem on application start up as part of the migration of Xamarin secure data to MAUI. I use await SecureStorage.SetAsync/GetAsync without issues elsewhere.

Testing on Samsung Galaxy S22. MAUI 8.0.83