TL;DR

If you want to use bindService() with external application services built with API 30 and above, add the attribute with the service package name to the client app manifest. More info in the documentation. Without it, bindService() will return False and the logs will tell you that an Intent-compatible service has not been found.

My repo with a working example

Problem

I am recently working on communication between applications in Android. Overall, there are 3 ways to achieve this: Broadcasts, AIDL, and Messenger. Without going into details, Messenger seems to be the most suitable for my case. It is quite simple to use, on the basis of the Bound Service, more info here.

I already had a Proof of Concept project ready that I wanted to show to someone at work, so I cleaned it up a bit, bumped target and compileSdk version to the API 30 and… it stopped working.

The call to the bindService() method returned False, which usually means the Service is not present in the Manifest - but it was. Back to API 29 - and everything works again, so it wasn’t a typo in service package or something.

#The reason After a while of googling, digging through StackOverflow, ritual cleaning of the project and Android Studio cache, I found the cause. It is described in more detail in the documentation, but in general it is about improving the security of the application. Before Android 11 (API 30), any application could check all other applications installed on the system using the queryIntentActivities() method. It could be a violation of the user’s privacy… or something, more info here. Anyway, Android decided to do something about it, and from API 30, applications only have access to the 3rd party packages listed in their own Manifest inside <queries> attribute.

The absence of this entry in the Manifest make 3rd party application services invisible and bindService() returns False. This can be seen in the Logcat logs, without filtering for only selected application:

I/AppFilter: Interaction: PackageSetting {<client.app.package/PID> -> <server.app.package/PID>} Blocked
W/ActivityManager: Unable to start service Intent { act=<action> pkg=<server.app.package>} U=0: not found

To make it funnier, the Service can be easily started with from adb and the same intent - there is no error :)

This change in Android does not affect the launch of internal Services, it is only about 3rd party Services, outside the application.

The solution

All you need is to add <queries> in client app Manifest, where you want tu bind 3rd party app Service. With the same package name you set in the Intent:

val intent = Intent("example_action")
intent.`package` = "io.github.asvid.services.server"
bindService(intent, connection, Context.BIND_AUTO_CREATE)

Manifest:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="io.github.asvid.services.client">
    <queries>
        <package android:name="io.github.asvid.services.server" />
    </queries>
	...
</manifest>

My repo with a working example

Alternatively you can stay with compileSdk 29 but I don’t recommend that :)

Rant over Android

It took me far too long to find the cause of this problem… The bindService() method only returns True / False with no specific error message, although it can throw a SecurityException in the absence of permissions. I had to engrave in logs without an application filter. Even this does not help much, because the information “service not found”, and which can be launched with the same Intent with adb, only intensifies the confusion. Blogpost with an explanation of the changes, does not mention bindService() at all, and I haven’t found a clear answer to my problem anywhere.

Only painstaking work through the documentation of the changes introduced by API 30 led me to the solution. My guess is that there are some security reasons to prevent malicious applications from trying to launch other application Services and not to make it easier to use them… but come on. I just bumped the compileSdk, and without any warning or explanation my app stopped working as expected.

There is so many API changes from version to version in Android that a single change can easily escape, even despite following the news. It is also difficult to remember the impact of each change on elements of the application that are not currently in use. And finding a solution can take a long time if the problem is unusual and the development tools are not helping.


share on:



share on: