对时效性要求不高的进程保活的实现
实现的基本原理
定义一个ServiceGuard, ServiceGuard继承自Service类,程序主进程启动后,启动ServiceGuard,ServiceGuard定义为在主进程外的单独进程中运行,比如,.remote进程。
主进程中定义一个普通的Service类,比如, Rservice, RService继承自Service类。
ServiceGuard对外提供远程调用接口, startAndRegisterService, 主进程通过bindService启动ServiceGuard, 拿到ServiceGuard的proxy对象后,通过调用startAndRegisterService来启动主进程中的RService。
startAndRegisterService中通过bindService启动主进程中的RService,启动成功后,ServiceGuard中永久保存RService的proxy对象。
ServiceGuard中会进行无限循环,每一次循环会检查RService是否存活,检查方式就是调用ping函数,如果主进程已经被杀死或者RService对象已经不存在,ping会返回false,ServiceGuard会对RService进行启动,随之主进程也会被启动,主进程中的后台的任务的初始化,可以放在RService的启动函数中。
ServiceGuard可能被系统杀死
可以将RService也定义成一个ServiceGuard,这样RService和ServiceGuard可以互相保护。
主进程和remote进程可能同时被系统杀死,或者很短的间隔内相继被杀死
remote进程是很轻量的进程,几乎不耗费资源,如果还是被杀死的话,可以注册一些系统的广播,广播产生时再次启动主进程。
关于调用proxy对象的pingBinder函数
在Service启动完成的回调onServiceConnected中,返回的是远端Service的句柄,一个IBinder类型的引用,需要将该句柄封装到一个proxy对象中,proxy对象的调用会传导到binger机制的native层,native层通过binder驱动调用到远端进程。IBinder句柄用来标识远端进程里的Service对象。
代码实现
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.IInterface;
import android.os.RemoteException;
import android.util.Log;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
public class ServiceGuard extends Service {
public class ServiceGuardBinder extends IServiceGuard.Stub {
public void startAndRegisterService(final String servicePath, final String serviceBinderPath) {
mMapPath.put(serviceBinderPath, servicePath);
Intent intent = new Intent(servicePath);
ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mMapBinder.put(serviceBinderPath, service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
}
public class ServiceThread extends Thread {
@Override
public void run() {
while (true) {
try {
sleep(500);
} catch (Exception e) {
}
Log.d("debug_log","start run ...");
Set<String> keys = mMapPath.keySet();
Iterator<String> it = keys.iterator();
while (it.hasNext()) {
String key = it.next();
String servicePath = mMapPath.get(key);
IBinder binder = mMapBinder.get(key);
Log.d("debug_log","service path is ..." + servicePath);
if (binder == null) {
Log.d("debug_log","binder is null ... start service");
startService(servicePath, key);
return;
}
IInterface iInterface = getBinderProxy(binder, key);
boolean ping = iInterface.asBinder().pingBinder();
Log.d("debug_log","ping is ....." + ping);
if (!ping) {
startService(servicePath, key);
return;
}
}
}
}
}
private HashMap<String, String> mMapPath = new HashMap<>();
private HashMap<String, IBinder> mMapBinder = new HashMap<>();
private final IBinder mBinder = new ServiceGuardBinder();
private ServiceThread mThread = new ServiceThread();
private void startService(final String servicePath, final String serviceBinderPath) {
Intent intent = new Intent(servicePath);
ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mMapBinder.put(serviceBinderPath, service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
private android.os.IInterface getBinderProxy(IBinder service, String serviceBinderPath) {
Class<?> clz = null;
try {
Method mStub = null;
clz = Class.forName(serviceBinderPath);
Class innner[] = clz.getDeclaredClasses();
for (Class cls : innner) {
if (cls.getName().equals("packagename.IRService$Stub")) { //此处将packagename替换为RService的包名
mStub = cls.getMethod("asInterface", IBinder.class);
}
}
IInterface binder = (IInterface)mStub.invoke(null, service);
if (binder != null) {
return binder;
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
return null;
}
public IBinder onBind(Intent arg0) {
if(mBinder != null) {
return mBinder;
}
return null;
}
public void onCreate() {
Log.d("debug_log", "ServiceGuard onCreate\n");
mThread.start();
}
public int onStartCommand (Intent intent, int flags, int startId) {
return START_NOT_STICKY;
//return START_REDELIVER_INTENT;
}
}
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class RService extends Service {
public class RServiceBinder extends IRService.Stub {
public void test() {
Log.w("debug_log","RemoteServiceBinder test ");
}
}
private final IBinder mBinder = new RServiceBinder();
public IBinder onBind(Intent arg0) {
if(mBinder != null) {
return mBinder;
}
return null;
}
public void onCreate() {
Log.d("debug_log", "TestService onCreate\n");
}
public int onStartCommand (Intent intent, int flags, int startId) {
return START_NOT_STICKY;
//return START_REDELIVER_INTENT;
}
}