restart service at boot 8.1 problems

786 Views Asked by At

first off thanks for the responses. :)

I've been working on a number of background logging app for android for the last few months. They are for academic research. Since android 8.1 has come out, I've found a number of problems with running foreground services, but the biggest problem is that the foreground services do not restart on boot. This works for every preceding SDK.

I've built an app to get around this problem. I'm simply trying to confirm that the job scheduler was activated from the broadcast receiver. So the data is stored internally in the file 'data.txt'.

Here is my code for restarting a foreground service at boot.

public class startServiceOnBoot extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
    if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
        Intent serviceIntent = new Intent();
        serviceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        serviceIntent.setAction("geyer.sensorlab.jobschedulepractice.StartMyActivityAtBootReceiver");

        Bundle b=new Bundle();
        b.putBoolean("from main", true);
        serviceIntent.putExtras(b);

        Worker.enqueueWork(context, serviceIntent);
    }
}

}

the job Intent Service

public class Worker extends JobIntentService {

private static final String TAG = "Worker";
public static final int SHOW_RESULT = 123;
static final int DOWNLOAD_JOB_ID = 1000;

public static void enqueueWork(Context context, Intent intent) {
    enqueueWork(context, Worker.class, DOWNLOAD_JOB_ID, intent);
}

@Override
protected void onHandleWork(@NonNull Intent intent) {
    Log.d(TAG, "onHandleWork() called with: intent = [" + intent + "]");
    if(Objects.requireNonNull(intent.getExtras()).getBoolean("from main")){
        storeInternally("from main");
    }else{
        storeInternally("from restart");
    }
}

private void storeInternally(String result) {
    long timestamp = System.currentTimeMillis()/1000;
    String dataEntry = result + " - " + timestamp + ": ";
    try {
        File path = this.getFilesDir();
        File file = new File(path, "data.txt");
        FileOutputStream fos = new FileOutputStream(file, true);
        fos.write(dataEntry.getBytes());
        fos.close();
        Log.i("from screen service", dataEntry);
    } catch (Exception e) {
        Log.d("Main - issue writing", "Exception: " + e);
    }
}

}

and the manifest:

<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/AppTheme">
    <activity android:name=".MainActivity">

        <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

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

    <receiver android:name=".startServiceOnBoot"
        android:label="StartMyServiceAtBootReceiver">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED"/>
            <action android:name="android.intent.action.QUICKBOOT_POWERON"/>
        </intent-filter>
    </receiver>

    <service android:name=".Worker"
        android:permission="android.permission.BIND_JOB_SERVICE"/>
    <service android:name=".target"/>
</application>

So can anyone see what I'm missing?

2

There are 2 best solutions below

1
On

Since Oreo, it is not allowed to start a service from the background, which would be the case with a boot receiver. Luckily, you could do it by postponing it with the JobIntent API, which would launch a little bit later, but it is still guaranteed to launch sooner or later.

public class BootReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
            MyService.enqueueWork(context, new Intent());
        }
    }

}

Have a look at this medium post for a more detailed answer and code.

0
On

I faced kind of same problem. And when I gave my app Auto start permission it worked..

The code snippet given below will route you to the Auto Start Permission Screen where you can give that permission manually.

try
{
    //Open the specific App Info page:
    Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
    intent.setData(Uri.parse("package:" + context.getPackageName()));
    context.startActivity(intent);
}
catch ( ActivityNotFoundException e )
{
    //Open the generic Apps page:
    Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS);
    context.startActivity(intent);
}