dotnet / android

.NET for Android provides open-source bindings of the Android SDK for use with .NET managed languages such as C#
MIT License
1.92k stars 526 forks source link

Android Service does not start if process name is specified in Service attribute #9132

Open jfichtner opened 3 months ago

jfichtner commented 3 months ago

Description

In a .NET 8 MAUI app, when I attempt to create an Android service that starts in a private process using the Service attribute, and specifying a process name with a colong as the first character as such: [Service(Process = ":test")] public class TestService : Service

The service simply does not start when attempting to start by calling: context.StartService(new Intent(context, typeof(TestService)));

In addition, if I remove the colon from the process string I get the following error when attempting to deploy the project: ADB0010: Mono.AndroidTools.InstallFailedException: Unexpected install output: Failure [INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: Failed parse during installPackageLI: Failed to read manifest from /data/app/vmdl699026415.tmp/base.apk: com.android.server.pm.pkg.component.ParsedServiceImpl cannot be cast to java.lang.String]

Steps to Reproduce

Create a new .NET MAUI application from the template in VS2022 and add the following class to the MauiApplication file:

    [Service(Process = ":test")]
    public class TestService : Service
    {
        public override IBinder? OnBind(Intent? intent)
        {
            return null;
        }

        public static void start(Context context)
        {
            context.StartService(new Intent(context, typeof(TestService)));
        }

        public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags startCommandFlags, int startId)
        {
            return StartCommandResult.Sticky;
        }
    }

Then in the MainApplication constructor add:

TestService.start(this);

I deployed this to a Pixel 5 emulator for my testing.

When attempting to deploy and run this application, note the following:

Link to public reproduction project repository

No response

Version with bug

8.0.3 GA

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

No response

Did you find any workaround?

No response

Relevant log output

No response

jfichtner commented 3 months ago

I assume the version specified above is close enough, but here is the exact output from the dotnet workload list command:

Welcome to .NET 8.0!

SDK Version: 8.0.303

ninachen03 commented 2 months ago

This issue has been verified using Visual Studio 17.11.0 Preview 3 (8.0.70 & 8.0.3). Can repro it. MauiApp24.zip

jfichtner commented 2 months ago

Any chance for a workaround here? If not I'll have to split my service out to a separate, native Java/Kotlin apk, which I'd really rather not do.

dellis1972 commented 2 months ago

I'm not sure we can support this. Running a service in a seperate process would require the runtime to be initialised I think, I'm not sure we have the hooks in place for that? @jonpryor am I mis remembering this? I seem to remember seperate processes for services was a no go at this time?

jfichtner commented 2 months ago

@dellis1972, @jonpryor thank you for looking into this. Would you have any advice on how to move forward? Is my only option to create and install a separate apk for the service to run in? Thanks...

jfichtner commented 2 months ago

Sorry to be a nuisance, @dellis1972 and @jonpryor, but getting an answer on this would help me tremendously in moving forward with my project. Thanks...

jonpryor commented 1 month ago

@dellis1972: you're thinking of isolated processes, which we don't support:

"Normal" android:process should work, or at least used to work:

jonpryor commented 1 month ago

@jfichtner: it works for me?

Start with MauiApp24.zip, and apply this patch:

diff --git a/Platforms/Android/MainApplication.cs b/Platforms/Android/MainApplication.cs
index 0fee904..de5faf1 100644
--- a/Platforms/Android/MainApplication.cs
+++ b/Platforms/Android/MainApplication.cs
@@ -21,8 +21,14 @@ namespace MauiApp24
     [Service(Process = ":test")]
     public class TestService : Service
     {
+        public TestService ()
+        {
+            Console.WriteLine ("# jonp: TestService is created!");
+        }
+
         public override IBinder? OnBind(Intent? intent)
         {
+            Console.WriteLine ($"# jonp: TestService.OnBind! intent={intent}");
             return null;
         }

@@ -33,6 +39,7 @@ namespace MauiApp24

         public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags startCommandFlags, int startId)
         {
+            Console.WriteLine ($"# jonp: TestService.OnStartCommand! intent={intent} startCommandFlags={startCommandFlags} startId={startId}");
             return StartCommandResult.Sticky;
         }
     }

Start capturing adb logcat:

adb logcat > log.txt &

Build, install, run:

dotnet build -f net8.0-android
dotnet build -f net8.0-android -t:Install
dotnet build -f net8.0-android -t:StartAndroidActivity

log.txt contains:

 1710  1823 I ActivityManager: Start proc 25425:com.companyname.mauiapp24/u0a416 for next-top-activity {com.companyname.mauiapp24/crc64df52bd7414134cd4.MainActivity}
25448 25448 …
 1710  1823 I ActivityManager: Start proc 25448:com.companyname.mauiapp24:test/u0a416 for service {com.companyname.mauiapp24/crc64df52bd7414134cd4.TestService}
25448 25448 …
25448 25448 I .mauiapp24:test: Late-enabling -Xcheck:jni
25448 25448 …
25448 25448 W debug-app-helper: Using runtime path: /data/app/~~iIy8UMzfnGMql_W42HYxzw==/com.companyname.mauiapp24-ZoXFZutkzgyakcaj6FUy8g==/lib/arm64
25448 25448 …
25448 25448 I DOTNET  : JNI_OnLoad: JNI_OnLoad in pal_jni.c
25448 25448 D DOTNET  : GetOptionalClassGRef: optional class com/android/org/conscrypt/OpenSSLEngineImpl was not found
25448 25448 …
25448 25448 I DOTNET  : # jonp: TestService is created!
25448 25448 I DOTNET  : # jonp: TestService.OnStartCommand! intent=Intent { cmp=com.companyname.mauiapp24/crc64df52bd7414134cd4.TestService } startCommandFlags=0 startId=1
25448 25448 I DOTNET  : # jonp: TestService.OnStartCommand! intent=Intent { cmp=com.companyname.mauiapp24/crc64df52bd7414134cd4.TestService } startCommandFlags=0 startId=2

The first line is the initial launch of MainActivity. Note that it's created on PID 25425.

Later, we see Start proc 25448; this is creating the :test process, and please note that 25448 is a different PID from 25425.

Finally, we see the added Console.WriteLine() messages from the Service, showing that TestService is indeed created, and that TestService.OnStartCommand() is invoked. Also note the PID that these messages are coming from: 25448, the PID of the :test service.

Perhaps it's debugging this app which doesn't work as expected? (I have not tried using the debugger.) It certainly appears to work as expected for me

jonpryor commented 1 month ago

@jfichtner: I would not expect the debugger to work in this scenario, as if I recall correctly, the debugger only wants to deal with one process, and this setup involves two: the process with the Activity, and the process with the Service. Debugging multi-process scenarios is beyond my knowledge.

jfichtner commented 1 month ago

@jonpryor Ah, I see! So, my test was flawed in that I was expecting the debugger to hit the breakpoint, but since the service is running in a different process the breakpoint won't be hit. I didn't even consider that, so thank you for taking the time!

This does address my issue, because I only need to run in a separate process. However, there still seems to be an issue with specifying a process that does not start with a colon, as this results in a deployment error.