3

There are dozens of questions around StackOverflow and guides across the internet, including Android's own documentation on getting this particular functionality working.

I believe I have followed all instruction and nuance to the letter, but here are some reference questions that I've used to try to tackle my problem:

AIDL interface between two applications
Service not binding
Android: Binding to a remote service

The issue I'm encountering is that the Service itself cannot be located. Whether it is already running or not, I encounter the following error:

Unable to start service Intent { cmp=com.example.dumpsterfire/.DumpsterService } U=0: not found

Here are the relevant configurations for the two apps

DumpsterFire (server/Service source)

build.gradle.kts

plugins {
    id("com.android.application")
    id("kotlin-android")
}

android {
    compileSdkVersion(30)
    buildToolsVersion = "30.0.3"

    defaultConfig {
        applicationId = "com.example.dumpsterfire"
        minSdkVersion(24)
        targetSdkVersion(30)
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        getByName("release") {
            isMinifyEnabled = false
            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = "1.8"
    }
}

dependencies {
    implementation(fileTree("/libs") { include("*.jar", "*.aar") })

    implementation("androidx.core:core-ktx:1.3.2")
    implementation("androidx.appcompat:appcompat:1.2.0")
    implementation("com.google.android.material:material:1.2.1")
    implementation("androidx.constraintlayout:constraintlayout:2.0.4")
    testImplementation("junit:junit:4.13.1")
    androidTestImplementation("androidx.test.ext:junit:1.1.2")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.3.0")
}

AndroidManifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.dumpsterfire">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.DumpsterFire">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service android:name=".DumpsterService"
            android:enabled="true"
            android:exported="true" />
    </application>

</manifest>

DumpsterService.kt

class DumpsterService : Service() {
    override fun onBind(intent: Intent?): IBinder {
        return object : IDemoAidl.Stub() {
            override fun printAcross(message: String?) {
                Log.d("chaser", "Hello, I've been instructed to say:\n$message")
            }
        }
    }
}

IDemoAidl.aidl

interface IDemoAidl {
    void printAcross(String message);
}

ClientDumpster (client/Service binder)

MainActivity.kt

//...
override fun onCreate(savedInstanceState: Bundle?) {
    //...
    bindService(
            Intent().setClassName("com.example.dumpsterfire", ".DumpsterService"),
            connection,
            BIND_AUTO_CREATE
    )
}

val connection = object : ServiceConnection {
    override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
        IDemoAidl.Stub.asInterface(service)
                .printAcross("Assuming direct control")
    }

    override fun onServiceDisconnected(name: ComponentName?) {
        Log.d("chaser", "host service terminated")
    }
}
//...

IDemoAidl.aidl

interface IDemoAidl {
    void printAcross(String message);
}

P.S. I have attempted to have the Service in question already running in the background, and verified its existence through the adb shell command dumpsys activity services. It doesn't change the error I receive.

P.P.S. I have also tried:

  • Reinstalling both apps from scratch.
  • Doing clean builds.
  • Invalidate caches/Restart.
nukeforum
  • 1,284
  • 3
  • 16
  • 38
  • Did you tried to use full class name? – Selvin Feb 02 '21 at 21:39
  • @Selvin Do you mean like `Intent().setClassName("com.example","com.example.DumpsterService")`? If so, yes, I have. It emits the same exact error. – nukeforum Feb 02 '21 at 21:42
  • Another idea is had you ever run any activity from "server" app before using client? I'm pretty sure that services and broadcast receivers are disabled before user run activity – Selvin Feb 02 '21 at 21:45
  • @Selvin Yes, the `DumpsterFire` app has an activity and has previously been installed/launched before `DumpsterClient` is installed/launched. – nukeforum Feb 02 '21 at 21:46
  • Are you sure that `com.example` is applicationId in `DumpsterFire`.. I mean you can have id `whatever.you.want` and "java" package `something.really.different`... I don't know maybe you have postfix in gradle – Selvin Feb 02 '21 at 21:59
  • I'm certain of the packages. But I can post the full manifests and `build.gradle` files if it will help. To be clear, I've explicitly run `DumpsterService` from `DumpsterFire` and actually verified its existence with `dumpsys activity services | grep com.example`. The output service package was in alignment with the package I've detailed here. – nukeforum Feb 02 '21 at 22:02
  • @Selvin I've updated the AndroidManifest in the `DumpsterFire` project and added the full contents of its build script. I did notice that I'd produced a typo in the package illustrated in the post, and I corrected it in both the project and here. Correcting the typo did not fix the issue. – nukeforum Feb 02 '21 at 22:30
  • I once had similar issue and I ended up using full component name, try `setClassName("com.example.dumpsterfire", "com.example.dumpsterfire.DumpsterService")` – Pawel Feb 02 '21 at 22:45
  • @Pawel Thanks for the suggestion, unfortunately, that produces the same result. – nukeforum Feb 02 '21 at 22:53

1 Answers1

2

If you are testing this on Android 11, your problem may be that your client app cannot see the service app. To get this sample service client to find this sample service on Android 11, I needed to add a <queries> element to my client's manifest, with the package of the service app:

<queries>
  <package android:name="com.commonsware.android.r.embed.server" />
</queries>
CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Mark, you're some kind of super hero when it comes to Android stuff. Thank you so much for this. This is exactly what I needed. – nukeforum Feb 02 '21 at 23:45
  • Here's a link to the Android documentation on this functionality, in case anyone was looking for it: https://developer.android.com/training/basics/intents/package-visibility#declare-other-apps – nukeforum Feb 02 '21 at 23:47
  • 1
    @nukeforum: Thanks for the kind words! I remembered banging my head against a wall for a couple of hours, wondering why the two apps couldn't see each other, when I was writing these samples. The behavior is seriously unintuitive. – CommonsWare Feb 02 '21 at 23:57
  • I guess this is exactly why I need to read *all* the docs whenever a new version of Android drops. :P – nukeforum Feb 02 '21 at 23:59
  • 1
    @nukeforum: I'm gonna just drop [this](https://commonsware.com/R/) right here. – CommonsWare Feb 03 '21 at 00:03