Search code examples
androidandroid-intentserviceapk

Service registration during APK installation


Lately I've been messing around with Android internals. To better understand the way APKs are installed, I decided to make a testing APK and install it manually with the help of root ADB shell:

  • I create an application directory /data/app/com.example.myapp-y6zjC4JYhJKOph-sl-G5QA== and copy the APK there (as base.apk). The directory suffix is copied from "proper" installation on another device, even though I think it might be anything, since it is a base64 encoded random string.
  • I create directory /data/data/com.example.myapp and its subdirectories cache and code_cache
  • I modify packages.xml and packages.list and into each of them I add an entry about my application (again, copied from another "proper" installation).

After I reboot the device, I can verify that the application is installed using adb shell pm list packages | grep myapp, which finds my package. I can successfully run the application using adb shell am start -n com.example.myapp/.MainActivity.

However, when I wanted to implement a service in my application (started automatically from MainActivity.onStart), the service does not start and prints an error message into the log:

ActivityManager: Unable to start service Intent { cmp=com.example.myapp/.MyService } U=0: not found

The service is not displayed in dumpsys either:

# adb shell dumpsys activity service com.example.myapp
No services match: com.example.myapp

The way I call startService is the following:

Log.e("MYAPP", "About to start the service"); // This is printed to the log
Intent intent = new Intent(getApplicationContext(), MyService.class);
startService(intent);

I have tried to change getApplicationContext() for this in the Intent argument, but it didn't help. The service is properly registered in AndroidManifest.xml:

<application ... >
 ...
    <activity android:name="com.example.myapp.MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <service android:name="com.example.myapp.MyService" android:enabled="true"></service>
</application>

Again, I have tried altering a few things in the Manifest: changing com.example.myapp.MyService for .MyService, removing the enabled flag and using one line tag (ending with />) instead of <service>...</service>. None of those helped.

My questions are:

  • Why does the system not see my service?
  • Is there any way the services are "registered" during APK installation? Do I need to modify some other configuration file?

Solution

  • Nevermind, I discovered a solution a day after I asked the question.

    If you ever encounter such a problem, for some reason you need to start the service like this:

    Intent intent = new Intent(getApplicationContext(), MyService.class);
    intent.setClassName("com.example.myapp", "com.example.myapp.MyService"); // add this line
    startService(intent);
    

    I don't know why this happens, the intent seems to be identical. When I print intent.toString() to the log before and after I call intent.setClassName, both lines look like this:

    Intent { cmp=com.example.myapp/.MyService }
    

    If anyone knows the reason for this behavior, please share it with me, as I have no idea why this happens.