shinyorg / shiny

.NET Framework for Backgrounding & Device Hardware Services (iOS, Android, & Catalyst)
https://shinylib.net
MIT License
1.43k stars 227 forks source link

[Bug]: System.ObjectDisposedException: ObjectDisposed_Generic ObjectDisposed_ObjectName_Name, Android.OS.PowerManager #1465

Closed mattgagnon2 closed 4 months ago

mattgagnon2 commented 4 months ago

Component/Nuget

Jobs (Shiny.Jobs)

What operating system(s) are effected?

Version(s) of Operation Systems

13

Hosting Model

Steps To Reproduce

  1. Start the app
  2. Unplug the usb cable
  3. Wait for the battery info to change

Expected Behavior

App should not crash

Actual Behavior

App crashes getting the energy saver status

Exception or Log output

05-06 15:41:14.602 882 882 E AndroidRuntime: FATAL EXCEPTION: main 05-06 15:41:14.602 882 882 E AndroidRuntime: Process: com.companyname.objectdisposedsample, PID: 882 05-06 15:41:14.602 882 882 E AndroidRuntime: android.runtime.JavaProxyThrowable: [System.ObjectDisposedException]: Cannot access a disposed object. 05-06 15:41:14.602 882 882 E AndroidRuntime: Object name: 'Android.OS.PowerManager'. 05-06 15:41:14.602 882 882 E AndroidRuntime: at Java.Interop.JniPeerMembers.AssertSelf(/Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.cs:153) 05-06 15:41:14.602 882 882 E AndroidRuntime: at Java.Interop.JniPeerMembers+JniInstanceMethods.InvokeVirtualBooleanMethod(/Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.cs:146) 05-06 15:41:14.602 882 882 E AndroidRuntime: at Android.OS.PowerManager.get_IsPowerSaveMode(/Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/net8.0/android-34/mcw/Android.OS.PowerManager.cs:934) 05-06 15:41:14.602 882 882 E AndroidRuntime: at Microsoft.Maui.Devices.BatteryImplementation.get_EnergySaverStatus(D:\a_work\1\s\src\Essentials\src\Battery\Battery.android.cs:45) 05-06 15:41:14.602 882 882 E AndroidRuntime: at ObjectDisposedSample.MainViewModel.Battery_BatteryInfoChanged(/Users/t004490/Projects/ObjectDisposedSample/ObjectDisposedSample/MainViewModel.cs:33) 05-06 15:41:14.602 882 882 E AndroidRuntime: at Microsoft.Maui.Devices.BatteryImplementation.OnBatteryInfoChanged(D:\a_work\1\s\src\Essentials\src\Battery\Battery.shared.cs:167) 05-06 15:41:14.602 882 882 E AndroidRuntime: at Microsoft.Maui.Devices.BatteryImplementation.OnBatteryInfoChanged(D:\a_work\1\s\src\Essentials\src\Battery\Battery.shared.cs:157) 05-06 15:41:14.602 882 882 E AndroidRuntime: at Microsoft.Maui.Devices.BatteryImplementation.OnBatteryInfoChanged(D:\a_work\1\s\src\Essentials\src\Battery\Battery.shared.cs:160) 05-06 15:41:14.602 882 882 E AndroidRuntime: at Microsoft.Maui.Devices.BatteryBroadcastReceiver.OnReceive(D:\a_work\1\s\src\Essentials\src\Battery\Battery.android.cs:167) 05-06 15:41:14.602 882 882 E AndroidRuntime: at Android.Content.BroadcastReceiver.n_OnReceive_Landroid_content_Context_Landroid_contentIntent(/Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/net8.0/android-34/mcw/Android.Content.BroadcastReceiver.cs:480) 05-06 15:41:14.602 882 882 E AndroidRuntime: at Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PPLL_V(/Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs:198) 05-06 15:41:14.602 882 882 E AndroidRuntime: at crc640a8d9a12ddbf2cf2.BatteryBroadcastReceiver.n_onReceive(Native Method) 05-06 15:41:14.602 882 882 E AndroidRuntime: at crc640a8d9a12ddbf2cf2.BatteryBroadcastReceiver.onReceive(BatteryBroadcastReceiver.java:30) 05-06 15:41:14.602 882 882 E AndroidRuntime: at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$android-app-LoadedApk$ReceiverDispatcher$Args(LoadedApk.java:1790) 05-06 15:41:14.602 882 882 E AndroidRuntime: at android.app.LoadedApk$ReceiverDispatcher$Args$$ExternalSyntheticLambda0.run(Unknown Source:2) 05-06 15:41:14.602 882 882 E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:942) 05-06 15:41:14.602 882 882 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:99) 05-06 15:41:14.602 882 882 E AndroidRuntime: at android.os.Looper.loopOnce(Looper.java:201) 05-06 15:41:14.602 882 882 E AndroidRuntime: at android.os.Looper.loop(Looper.java:288) 05-06 15:41:14.602 882 882 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:7918) 05-06 15:41:14.602 882 882 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method) 05-06 15:41:14.602 882 882 E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) 05-06 15:41:14.602 882 882 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)

Code Sample

https://github.com/mattgagnon2/ObjectDisposedSample

Code of Conduct

aritchie commented 4 months ago

There is not a single thing in the exception that shows Shiny is even involved. Your crash shows the MAUI battery implementation which I don't touch

mattgagnon2 commented 4 months ago

I understand that the exception doesn't show Shiny involved. You can confirm with the sample app attached that the exception is thrown when the energy saver status changes and if you comment out the line that registers the job to run, the exception doesn't happen.

The BatteryImplementation of maui gets a reference to the power manager with

static PowerManager? powerManager;

static PowerManager? PowerManager =>
    powerManager ??= Application.Context.GetSystemService(Context.PowerService) as PowerManager;

and when the EnergySaverStatus is retrieved, PowerManager ends up being a disposed object

public EnergySaverStatus EnergySaverStatus
{
    get
    {
        var status = PowerManager?.IsPowerSaveMode ?? false;
        return status ? EnergySaverStatus.On : EnergySaverStatus.Off;
    }
}

Line 59 of Shiny.Jobs/Platforms/Android/JobManager.cs has the line using var pm = this.platform.GetSystemService<Android.OS.PowerManager>(Context.PowerService); and I thought it possible that is getting disposed of there.

aritchie commented 4 months ago

I just ran your sample on Android 10, 13, & 14 without issue.

Update your workloads and MAUI version.

mattgagnon2 commented 4 months ago

What workload are you running? I have maui 8.0.21 referenced in my project and my workload is

m131925:android-sdk-macosx t004490$ dotnet workload --info
 Workload version: 8.0.200-manifests.a39c3a9c
 [maui]
   Installation Source: SDK 8.0.200
   Manifest Version:    8.0.7/8.0.100
   Manifest Path:       /usr/local/share/dotnet/sdk-manifests/8.0.100/microsoft.net.sdk.maui/8.0.7/WorkloadManifest.json
   Install Type:        FileBased
aritchie commented 4 months ago

That's what I'm running

mattgagnon2 commented 4 months ago

When you ran the app, did you have the usb cable unplugged? I forgot to list that in my reproduction steps.

aritchie commented 4 months ago

It could be a race condition. MAUI is pinning their instances of Android services which you're not suppose to do.

In any case, this is not a Shiny bug. The path you've listed out only runs if wake locks are in the manifest and you're running a foreground service.

mattgagnon2 commented 4 months ago

Do you have any other suggestions because like I said, if I don't register the job, the exception doesn't occur.

aritchie commented 4 months ago

Don't use a foreground service, use shiny's battery implementation, don't use shiny or submit a fix to MAUI

RsZoli commented 2 months ago

@aritchie Hey Allen! I have a very similar problem to this:

Error setting up task - getsts_process

System.ObjectDisposedException: ObjectDisposed_Generic ObjectDisposed_ObjectName_Name, Android.OS.PowerManager+WakeLock ?, in void JniPeerMembers.AssertSelf(IJavaPeerable) ?, in void JniInstanceMethods.InvokeVirtualVoidMethod(string, IJavaPeerable, JniArgumentValue*) ?, in void WakeLock.Release() File "JobManager.cs", line 72, in async void JobManager.RunTask(string taskName, Func<CancellationToken, Task> task) wakeLock.Release();

I'm using your solution like this:

Shiny.Hosting.Host.GetService<IJobManager>().RunTask("getsts_process", async (c) => { await RestoreStsAsync(); });

Is this not related as well? Thank you!

aritchie commented 2 months ago

Probably. It's the same mechanism. The bug in MAUI and I sent a fix already. It came out I believe as part of 8.0.60

RsZoli commented 2 months ago

@aritchie Well, thats a problem! :(

image

aritchie commented 2 months ago

You can update the version of MAUI in your csproj

<PropertyGroup>
    <MauiVersion>8.0.60</MauiVersion>
</PropertyGroup>