Android Service保活探索

发布时间:2023-05-20

一、前言

随着Android应用市场的飞速发展,如何保障应用的用户体验一直是开发者热议的话题。然而长期运行后台服务却面临着系统杀进程和省电等问题。如何保证服务长时间的运行,无疑是保障应用运行稳定性的关键。本文将从多个方面进行探索android service保活的方法。

二、Foreground Service保活

Foreground Service被定义为一种前台服务,其在拉通知栏通知的同时具备了持续性和稳定性的特点。使用Foreground Service保活的方式需要调用startForeground方法,将服务设置为前台运行状态。

public class MyService extends Service {
    private static final int NOTIFICATION_ID = 1;
    @Override
    public void onCreate() {
        super.onCreate();
        Notification notification = new Notification.Builder(this, CHANNEL_ID)
            .setContentTitle(getText(R.string.notification_title))
            .setContentText(getText(R.string.notification_message))
            .setSmallIcon(R.drawable.icon)
            .build();
        startForeground(NOTIFICATION_ID, notification);
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        stopForeground(true);
    }
}

保活效果:前台服务优先级较高,可以在后台保持长时间运行。

三、相互唤醒保活

相互唤醒保活是一种互相唤醒的方式,通过广播、定时器等手段来实现服务的重启,从而达到保持服务一直运行的效果。

1. 定时器唤醒

利用定时器唤醒服务的方式比较简单,可以通过创建一个定时器,每隔一段时间就发送一个广播,唤醒服务。在服务中重置定时器,达到前后互相唤醒的效果。

public class MyService extends Service {
    private static final String ACTION_ALARM =
        "com.example.androidservice.KEEP_ALIVE_ALARM";
    private static final int INTERVAL = 5 * 60 * 1000;
    private PendingIntent mPendingIntent;
    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent != null && ACTION_ALARM.equals(intent.getAction())) {
                // do something to keep the service alive
                // ...
                // reset the alarm
                AlarmManager alarmManager =
                    (AlarmManager) getSystemService(Context.ALARM_SERVICE);
                alarmManager.setExact(
                    AlarmManager.ELAPSED_REALTIME_WAKEUP, 
                    SystemClock.elapsedRealtime() + INTERVAL, 
                    mPendingIntent);
                return;
            }
        }
    };
    @Override
    public void onCreate() {
        super.onCreate();
        Intent intent = new Intent(ACTION_ALARM);
        mPendingIntent = PendingIntent.getBroadcast(
            this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        AlarmManager alarmManager =
            (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        alarmManager.setExact(
            AlarmManager.ELAPSED_REALTIME_WAKEUP, 
            SystemClock.elapsedRealtime() + INTERVAL, 
            mPendingIntent);
        registerReceiver(mReceiver, new IntentFilter(ACTION_ALARM));
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(mReceiver);
        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        alarmManager.cancel(mPendingIntent);
    }
}

保活效果:通过定时器唤醒服务,让服务可以在一定时间内保持运行。

2. 监听系统广播唤醒

监听系统广播,利用系统事件唤醒服务也是一种不错的方法。如果开启了网络、屏幕、电源等系统事件监听,当这些事件发生时可以通过回调函数重新启动服务。

public class MyService extends Service {
    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) {
                // do something to keep the service alive
                // ...
                return;
            }
            if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
                // do something to keep the service alive
                // ...
                return;
            }
            if (Intent.ACTION_POWER_CONNECTED.equals(intent.getAction())) {
                // do something to keep the service alive
                // ...
                return;
            }
            if (Intent.ACTION_POWER_DISCONNECTED.equals(intent.getAction())) {
                // do something to keep the service alive
                // ...
                return;
            }
        }
    };
    @Override
    public void onCreate() {
        super.onCreate();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
        intentFilter.addAction(Intent.ACTION_USER_PRESENT);
        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        intentFilter.addAction(Intent.ACTION_POWER_CONNECTED);
        intentFilter.addAction(Intent.ACTION_POWER_DISCONNECTED);
        registerReceiver(mReceiver, intentFilter);
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(mReceiver);
    }
}

保活效果:通过监听系统广播,唤醒服务,让服务可以在特定的系统事件触发时保持运行。

四、双进程守护保活

双进程守护保活是一种通过创建另一个进程来保障主进程和服务运行的方法。当主进程或服务被杀死时,另一个进程依旧可以运行,并在适当的时候将主进程和服务重启。

public class RemoteService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        startForeground(1, new Notification());
        stopForeground(true);
        Intent intent1 = new Intent(this, LocalService.class);
        startService(intent1);
        return super.onStartCommand(intent, flags, startId);
    }
}
public class LocalService extends Service {
    private static final String TAG = "LocalService";
    private MyBinder mBinder = new MyBinder();
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        startForeground(2, new Notification());
        stopForeground(true);
        startRemoteService();
        return super.onStartCommand(intent, flags, startId);
    }
    private void startRemoteService() {
        Intent intent = new Intent(this, RemoteService.class);
        startService(intent);
    }
    @Override
    public void onTaskRemoved(Intent rootIntent) {
        // restart the service when it is killed
        startRemoteService();
        super.onTaskRemoved(rootIntent);
    }
    public static class MyBinder extends Binder {
        public LocalService getService() {
            return LocalService.this;
        }
        public void wakeUp() {
            Log.i(TAG, "wake up by local binder");
            startRemoteService();
        }
    }
}

保活效果:启动另一个进程,使主进程和服务能够相互唤醒,达到保证服务一直运行的效果。

五、JNI保活

JNI保活是一种通过C/C代码调用java虚拟机,执行java代码来保证进程运行。由于C/C是一种底层语言,较少会被系统杀死,因此可以利用这一点实现保活效果。

jint JNI_OnLoad(JavaVM* vm, void* reserved) {
    JNIEnv* env;
    if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_6) != JNI_OK) {
        return JNI_ERR;
    }
    jclass clazz = (*env)->FindClass(env, "com.example.androidservice.MyService");
    if (clazz == NULL) return JNI_ERR;
    jmethodID methodID = (*env)->GetMethodID(env, clazz, "onAlive", "()V");
    if (methodID == NULL) return JNI_ERR;
    jobject obj = (*env)->AllocObject(env, clazz);
    if (obj == NULL) return JNI_ERR;
    (*env)->CallVoidMethod(env, obj, methodID);
    return JNI_VERSION_1_6;
}

保活效果:通过JNI的方式调用java虚拟机,执行java代码,达到保证进程一直运行的效果。