Cannot start an external service from a boot_compl

2019-08-31 04:04发布

问题:

I'm trying to start an external service from my apk using as little code as necessary. Testing the package on a 4.0 AVD and verifying the response in logcat seems to give proper results; however, on the actual device it doesn't load. Actually, it doesn't even seem to be listed at all in logcat.

It is probably something that I'm overlooking and just need a second pair of eyes to confirm.

StartService.java:

package com.winca.service.start;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class StartService extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Intent i = new Intent();
        i.setClassName("com.winca.service", "com.winca.service.StartService");
        context.startService(i);
    }
}

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.winca.service.start"
    android:versionCode="13"
    android:versionName="1.3" >

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <uses-sdk android:targetSdkVersion="14" android:minSdkVersion="14"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <receiver android:name="com.winca.service.start.StartService">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>
    </application>
</manifest>

AVD response:

# getprop ro.build.fingerprint
generic/sdk/generic:4.0.2/ICS_MR0/229537:eng/test-keys
# logcat -c; sleep 1; am broadcast -a android.intent.action.BOOT_COMPLETED; sleep 20; logcat -d | grep winca
Broadcasting: Intent { act=android.intent.action.BOOT_COMPLETED }
Broadcast completed: result=0
W/ActivityManager(   80): Unable to start service Intent { cmp=com.winca.service/.StartService }: not found
#

I actually expect "not found" because the actual package that contains the service isn't installed on the AVD. I cannot install it because of the system SharedUserID. But, at least I can see it is attempting to load it with the AVD, while the actual device doesn't even list in the logcat messages.

To give a little background why, this particular Android device isn't loading "com.winca.service/.StartService" service when a third-party launcher is set to default. This prevents many of the audio services on the device to remain disabled until it is activated. So, I thought maybe whip up a quick package to do it; instead of using something like Tasker (which for some unknown reason force closes on this device).

回答1:

Your receiver will not work until one of your components responds to an explicit Intent. The typical way this works is by the user running one of your activities. Until then, on Android 3.1+, your app is in a "stopped state" where no manifest-registered receivers will respond to broadcasts.



回答2:

It turns out that moving the app to the /system/app directory bypassed the "stopped state" from a normal install. This was the intention anyways since the user is piecing together a custom ROM for this particular Android device. The problem is that we've been testing the app by installing it which causes the "stopped state" and prevents it to perform appropriately. However, moving the app into /system/app directory with the correct file permissions allowed the apk to work as intended.

I suppose this is solution is not practical for most third-party development situations, like distributing an app trough Google Play. For that you'll need to observe the convention of allowing the user to launch an intent at at least once while it is installed as pointed out by CommonsWare.

As for why it ran in the AVD, in retrospect I suspect it had something to do with initially installing it through Eclipse's Run > Debug (F11) mechanism. I guess that uses a different method of installation which marks the package as "stopped=false" according to "dumpsys package {package.name}".