APP中一種在Java層實現的簡單守護進程方式
CB08F567-698E-46DF-970B-D178FB3BE55B154112-fbbdee0572ec27c6.gif
守護進程是一個黑色地帶的產物,無論是通過native的方式在linux中fork進程達到,還是在java層通過兩個service守護的方式,都是不太友好的做法,據很多人反應,總有一些實際的業務場景中,希望自己的應用保持live狀態, 一種是在native中做:
-
linux中多進程;
-
unix domain套接字實現跨進程通信;
-
linux的信號處理;
-
exec函數族的用法;
把他們組合起來實現了一個雙進程守護,幾個實現雙進程守護時的關鍵點:
父進程如何監視到子進程(監視進程)的死亡?很簡單,在linux中,子進程被終止時,會向父進程發送SIG_CHLD信號,于是我們可以安裝信號處理函數,并在此信號處理函數中重新啟動創建監視進程;
子進程(監視進程)如何監視到父進程死亡?當父進程死亡以后,子進程就成為了孤兒進程由Init進程領養,于是我們可以在一個循環中讀取子進程的父進程PID,當變為1就說明其父進程已經死亡,于是可以重啟父進程。這里因為采用了循環,所以就引出了之前提到的耗電量的問題。
父子進程間的通信有一種辦法是父子進程間建立通信通道,然后通過監視此通道來感知對方的存在,這樣不會存在之前提到的耗電量的問題,在本文的實現中,為了簡單,還是采用了輪詢父進程PID的辦法,但是還是留出了父子進程的通信通道,雖然暫時沒有用到,但可備不時之需!
今天介紹下用兩個service守護的方式作一完整的小案例。僅作學習交流之用。兩個進程互相監視對方,發現對方掛掉就立刻重啟!(實際就是在onDisconnected時,start另一個service)
假設我們的APP中開啟了兩個Service,分別是A和B,那么:如果A守護B,則B掛掉的同時,A就應該把B喚醒起來,反之亦然,也就是說A和B應該是互相守護,無論誰被殺掉,對方就把它喚醒起來。既然提到了兩個Service,那么這兩個Service就不能讓它們同處在一個進程中,否則就會被一次性雙殺。顯然不能在同一個進程中,在android中通常我們可以使用AIDL來實現IPC實現。
原理圖(簡單版):
226BBD66-B17C-4E9C-8849-AE8C6393BB37.png
-
MainActivity
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 啟動兩個守護服務 startService(new Intent(this, ServiceA.class)); startService(new Intent(this, ServiceB.class)); } }
-
manifest
<service android:name=".ServiceA"></service> <service android:name=".ServiceB" android:process="com.guardprocess.remote"></service>
-
aide
interface IBridgeInterface {
String getName();
}
-
ServiceA
public class ServiceA extends Service {
private static final String TAG = ServiceA.class.getSimpleName();
private MyBinder mBinder;
private PendingIntent mPendingIntent;
private MyServiceConnection mServiceConnection;
@Override
public void onCreate() {
super.onCreate();
if (mBinder == null) {
mBinder = new MyBinder();
}
mServiceConnection = new MyServiceConnection();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
this.bindService(new Intent(this, ServiceB.class), mServiceConnection, Context.BIND_IMPORTANT);
mPendingIntent = PendingIntent.getService(this, 0, intent, 0);
Notification.Builder builder = new Notification.Builder(this);
builder.setTicker("守護服務A啟動中")
.setContentText("我是來守護B不被殺的!")
.setContentTitle("守護服務A")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(mPendingIntent)
.setWhen(System.currentTimeMillis());
Notification notification = builder.build();
// 設置service為前臺進程,避免手機休眠時系統自動殺掉該服務
startForeground(startId, notification);
return START_STICKY;
}
class MyServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName componentName, IBinder binder) {
Log.i(TAG, "ServiceA連接成功");
Toast.makeText(ServiceA.this, "ServiceA連接成功", Toast.LENGTH_LONG).show();
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
// 連接出現了異常斷開了,RemoteService被殺掉了
Toast.makeText(ServiceA.this, "ServiceA被干掉", Toast.LENGTH_LONG).show();
// 啟動ServiceB
ServiceA.this.startService(new Intent(ServiceA.this, ServiceB.class));
ServiceA.this.bindService(new Intent(ServiceA.this, ServiceB.class),
mServiceConnection, Context.BIND_IMPORTANT);
}
}
class MyBinder extends IBridgeInterface.Stub {
@Override
public String getName() throws RemoteException {
return "ServiceA";
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
-
ServiceB
public class ServiceB extends Service {
private static final String TAG = ServiceB.class.getSimpleName();
private MyBinder mBinder;
private PendingIntent mPendingIntent;
private MyServiceConnection mServiceConnection;
@Override
public void onCreate() {
super.onCreate();
if (mBinder == null) {
mBinder = new MyBinder();
}
mServiceConnection = new MyServiceConnection();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
this.bindService(new Intent(this,ServiceA.class), mServiceConnection, Context.BIND_IMPORTANT);
mPendingIntent =PendingIntent.getService(this, 0, intent, 0);
Notification.Builder builder = new Notification.Builder(this);
builder.setTicker("守護服務B啟動中")
.setContentText("我是來守護A不被殺的!")
.setContentTitle("守護服務B")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(mPendingIntent)
.setWhen(System.currentTimeMillis());
Notification notification = builder.build();
//設置service為前臺進程,避免手機休眠時系統自動殺掉該服務
startForeground(startId, notification);
return START_STICKY;
}
class MyServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName componentName, IBinder binder) {
Log.i(TAG, "ServiceB連接成功");
Toast.makeText(ServiceB.this, "ServiceB連接成功", Toast.LENGTH_LONG).show();
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
// 連接出現了異常斷開了,LocalCastielService被殺死了
Toast.makeText(ServiceB.this, "ServiceB被干掉", Toast.LENGTH_LONG).show();
// 啟動ServiceA
ServiceB.this.startService(new Intent(ServiceB.this, ServiceA.class));
ServiceB.this.bindService(new Intent(ServiceB.this, ServiceA.class), mServiceConnection, Context.BIND_IMPORTANT);
}
}
class MyBinder extends IBridgeInterface.Stub {
@Override
public String getName() throws RemoteException {
return "ServiceB";
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
最后:如果系統干掉這個服務,還是難逃此劫的。向ROM廠商提出加白名單方式,才是終極最萬全方案。
來自:http://www.jianshu.com/p/b84efa4d6dc0