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:
/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./data/data/com.example.myapp
and its subdirectories cache
and code_cache
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:
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.