Android看门狗

        近期在开发过程中遇到几个问题,应用B在初始化的时候,需要通过Android板子的芯片加密验证,但是现在加密芯片不稳定,有时候能够初始化通过,有时候整个应用会直接崩溃掉,出现“程序已经停止运行“的Dialog,需要人为的点击确定,然后去打开应用。这是问题一问题二:程序在跑的过程中,有时也会遇到因为加密芯片不稳定而造成的程序崩溃。问题三:加密芯片在初始化的过程中,不会崩溃掉,这种情况下应用没办法正常工作;但是现在我们的板子是需要挂在公交车上面,进行视频采集的,因为这种场景下是无屏幕,无声音,人是不可能进行操作。因此,必须要有一种实现方式,务必确保程序能够始终运行在后台。说的更加直白一点就是必须要有一个守护的进程,对其进行守护,那要实现这个功能,最简单的想法就是:做一个守护的APP,开启监听开机广播,然后在广播中启动一个服务,在该服务中将查看当前运行的进程,如果发现B应用还未启动,那么我们通过隐士意图的方式启动应用B。 

       此外,这里还有一个关键性的问题!我们的应用在崩溃的时候,android的系统会提示”运行停止“,这个时候,我们的应用进程还在后台,只有当我们点击确定的时候,这个进程才被回收掉。那么,怎么解决这个问题呢?我们需要自定义一个异常CrashHandler继承自UncaughtExceptionHandler,并Thread.setDefaultUncaughtExceptionHandler()方法将异常处理类设置到线程上。在异常的处理上,我们直接干掉这个进程,这样我们的看门狗就可以发现了。这个可以解决问题一以及问题二。但是问题三没得到解决,本来想着在遇到情况三时,直接自己杀结束自己进程,但是现在由于芯片以及库的原因不允许这么干。所以怎么办?这里我想到了给看门狗发消息的方式。我们在进入程序的时候使用AIDL技术给看门狗发一条消息msg1,在初始化成功以后,会给看门狗再发一条消息msg2。这样,当看门狗收不到消息msg2的时候就该重启这个应用B了(注意使用AIDL文件务必确保他所在的包路径一样!!!)。下面是看门狗的Manifest文件


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.vechicledog"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="19" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        
   		<activity
            android:name="com.reconova.vechicledog.activity.MainActivity"
            android:label="@string/app_name"
            android:theme="@android:style/Theme.NoDisplay">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>  
        
        <!-- 看门狗服务 -->
        <service android:name="com.reconova.vechicledog.service.VechicleDogService" >
            <intent-filter>
                <action android:name="com.reconova.VECHICLE_DOG_SERVICE" />
            </intent-filter>
        </service>

    	<!-- 开机监听 -->
        <receiver android:name="com.reconova.vechicledog.receiver.MyBooCompleteReceiver" >
            <intent-filter>           
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
      
<!--            	<!– 开机监听 –>
        <receiver android:name="com.reconova.vechicledog.receiver.MyReceiver" >
            <intent-filter>           
                <action android:name="MYRECEIVER" />
            </intent-filter>
        </receiver>-->
        
    </application>

</manifest>

     对于AIDL技术,使用的时候,我的理解是,他就像一个服务器,客户端给他发消息,他接收到消息以后就进行处理。下面是Service服务

package com.reconova.vechicledog.service;

import java.util.List;

import com.reconova.aidl.IVechicleControl;

import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.media.audiofx.AudioEffect.OnEnableStatusChangeListener;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

/**
 * 使用AIDL实现类似看门狗的程序
 * @author GuanYangYi
 *
 */
public class VechicleDogService extends Service {

	private RemoteControl remoteControl = new RemoteControl();
	private Context context ;
	private ActivityManager manager ;
	private boolean initSecondSuccess;
	
	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		Log.v("pos","onBind");
		if (context==null) {
			context = getApplicationContext();
			manager = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
			watchAfterInitSuccess();
		}		
		return remoteControl;
	}

	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.onCreate();
		Log.v("pos","onCreate");
		context = getApplicationContext();
		manager = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
		watchAfterInitSuccess();
	}
	
	
	
	/**
	 * 启动汽车
	 */
	private void startVechicele(){
		if (context!=null){
			Intent mainIntent = new Intent();
			mainIntent.setAction(Intent.ACTION_MAIN);
			mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);		
			mainIntent.setClassName("com.reconova.vehicle2", "com.reconova.activity.RecoFaceActivity2");	
		    mainIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			context.startActivity(mainIntent);
		}
	}
	
	
	/**
	 * 初始化成功以后进行监控
	 */
	private void watchAfterInitSuccess() {
		//开启线程开始检测
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				while(true){
					boolean isSafe = false;		
					 List<RunningAppProcessInfo> infos = manager.getRunningAppProcesses();
					 for (RunningAppProcessInfo info:infos){						 
						 if ("com.reconova.vehicle".equals(info.processName)){				
							 Log.v("pos","Name==="+info.processName);
							 isSafe = true;
							 continue;
						 }
					 }			 
					 if (!isSafe){
						 startVechicele();
					 }
				}
			}
		}).start();	
	}


	/**
	 * @author GuanYangYi
	 * 实现对远方消息的监控
	 */
	private final class RemoteControl extends IVechicleControl.Stub implements IVechicleControl{

		@Override
		public void enterInit(int msgCount) throws RemoteException {
			// TODO Auto-generated method stub
			Log.v("pos","enterInit");
			onEnterInit();
		}

		@Override
		public void successInit(int msgCount) throws RemoteException {
			// TODO Auto-generated method stub
			Log.v("pos","successInit");
			initSecondSuccess = true;
		}
		
		/**
		 * 开启就开始检测
		 */
		private void onEnterInit() {
			new Thread(new Runnable() {
				
				@Override
				public void run() {
					// TODO Auto-generated method stub
					while (true){
						long startTime = System.currentTimeMillis();
						long end = System.currentTimeMillis();
						while ( (end-startTime)<=5000 ){
							if (initSecondSuccess){ //5秒以内收到初始化成功的消息
								watchAfterInitSuccess();
								initSecondSuccess = false;
								return;
							}else{
								end = System.currentTimeMillis();
							}
						}
						startVechicele();
						return ;
					}
				}
			}).start();
			
		}

		@Override
		public void test(String msg) throws RemoteException {
			// TODO Auto-generated method stub
			Log.v("pos",msg);
		}
		
	}
}


package com.reconova.vechicledog.activity;


import com.reconova.vechicledog.service.VechicleDogService;


import android.R;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;


public class MainActivity extends Activity {


	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		
		startService(new Intent(MainActivity.this,VechicleDogService.class));
	} 


}

客户端:

     客户端也也有一个监听开机广播,然后在广播中自己启动自己,只不过很遗憾的是,这个过程很快。快到以至于我们的远程服务都没绑定,所以消息到达不了看门狗,怎么办?延时加载?可是这可是在广播中啊,这个时候我采取的办法是直接把进程给结束掉,让看门狗看得到,让看门狗来启动!那么问题来了,为什么不让看门狗来启动应用B呢?看门狗不是自己都有启动应用B的功能吗?是的,的确是有的!但是很可惜,这个这样子的启动方式会出现”停止运行“的提示,进程没被干掉。究其根本原因,应该是代码中线程运转太快,重复start应用B的原因。以下是开机监听广播

package com.reconova.receiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.sax.StartElementListener;
import android.widget.Toast;

public class MyBooCompleteReceiver extends BroadcastReceiver {

	@Override
	public void onReceive(Context context, Intent intent) {
		// TODO Auto-generated method stub
		
		try {
			Thread.sleep(1000);  //leave some time for watch dog 
			android.os.Process.killProcess(android.os.Process.myPid());
			System.exit(1);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}<span style="color: rgb(255, 0, 0);">
</span>

然后是客户端的MainActivity:

package com.reconova.activity;

import java.io.File;
import java.io.FileOutputStream;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;

import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.FeatureInfo;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Rect;
import android.hardware.Camera;
import android.media.MediaRecorder;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.TextView;

import com.reconova.aidl.IVechicleControl;
import com.reconova.data.ImageStruct.ImageResult.FaceRect;
import com.reconova.jnuit.SFHCameraCallback3;
import com.reconova.model.FaceVerification;
import com.reconova.model.FrameDataQueue;
import com.reconova.model.MyQueue;
import com.reconova.model.TempFrameData;
import com.reconova.processor.EyeDetectorProcessor2;
import com.reconova.processor.FaceDetectorProcessor;
import com.reconova.processor.FaceProcessorWrapper;
import com.reconova.processor.ImageHolder;
import com.reconova.processor.NativeFaceProcessor;
import com.reconova.processor.InfoHolder.RecoParams;
import com.reconova.processor.NativeImageCapture;
import com.reconova.processor.ProcessorManager;
import com.reconova.processor.RecoProcessor;
import com.reconova.processor.RecoProcessor.ExtractResult;
import com.reconova.processor.RecoProcessor.FaceData;
import com.reconova.strategy.TiredStrategy;
import com.reconova.task.TaskQueue;
import com.reconova.task.WorkThread;
import com.reconova.ui.base.FaceCanvasView;
import com.reconova.utils.CaptureImage;
import com.reconova.utils.CrashHandler;
import com.reconova.utils.DateInfoUtils;
import com.reconova.utils.FileTool;
import com.reconova.utils.ImageHelper;
import com.reconova.utils.LogUtils;
import com.reconova.utils.MyPreviewCallBack;
import com.reconova.utils.PlaySoundPool;
import com.reconova.utils.SFHCameraCallback;
import com.reconova.vehicle2.R;

/**
 * @author guluxixi 
 * 人脸检测、注册、识别、疲劳检测界面。
 */
/*public class RecoFaceActivity extends BaseActivity implements
		Camera.PreviewCallback {*/
public class RecoFaceActivity2 extends BaseActivity implements
MyPreviewCallBack {
	public static final String TAG = "RecoFaceActivity";	
	private SFHCameraCallback3 myCallback;


	@Override
	protected void onResume() {
		super.onResume();		
		setUpParameters();
		if (!isInitSuccess()) {			
			requestInitNativeLibTask();			
		}
	}
	
	
	/**
	 * 相关算法是否初始化成功
	 */
	private boolean isInitSuccess() {
		return mEyeDetectorProcessor.isInitSuccess()
				&& FaceDetectorProcessor.getInstance().isInitSuccess()
				&& RecoProcessor.getInstance().isFaceInitSuccess();
		
	}



	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		//ShellUtils.execCommand("mount -o remount -o rw /system", true);		
	
		myIntent.setAction("com.reconova.VECHICLE_DOG_SERVICE");
		bindService(myIntent, conn , Context.BIND_AUTO_CREATE);	
		
		CrashHandler.getInstance().init(getApplicationContext());
		context = getApplicationContext();	
		
		setContentView(R.layout.activity_reco_face);	

	}
	
	private void beforeEnterInit() {
		// TODO Auto-generated method stub
		if (mServiceControl!=null){
			try {
				mServiceControl.enterInit(1);
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			};
		}
	}
	
	
	/**
	 * 	请求初始化算法库。
	 */
	private void requestInitNativeLibTask() {
		InitNativeLibTask task = new InitNativeLibTask();
		task.execute();
	}

	private class InitNativeLibTask extends AsyncTask<Object, Object, Boolean> {
		ProgressDialog dialog;
		
		@Override
		public void onPreExecute() {
			if (dialog == null) {
				dialog = new ProgressDialog(RecoFaceActivity2.this);
				dialog.setTitle("初始化资源库");
				dialog.setMessage("初始化中请耐心等待");
				dialog.setCancelable(false);
			}
			dialog.show();
		}

		@Override
		protected Boolean doInBackground(Object... arg0) {
			try {
				Thread.sleep(3000);
				beforeEnterInit();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			
			boolean eyeInit = mEyeDetectorProcessor.Init(
					getApplicationContext(), fileDir);

			if (!eyeInit) {
				Log.e(TAG, "EyeInit Failed!");
				return false;
			}
			
			
			boolean faceInit = RecoProcessor.getInstance().faceInit(
					getApplicationContext(), fileDir);
			if (!faceInit) {
				Log.e(TAG, "FaceInit Failed!");
			} else {
				RecoProcessor.getInstance().configFaceSize(80, 512);
			}

			return faceInit;
		}

		protected void onPostExecute(Boolean result) {
			dialog.dismiss();
			if (result) {
				onInitSuccess();
			} else {
				//onInitFailed();	
				//在这里改成初始化失败以后将自动进行初始化(针对无屏幕的情况)
				requestInitNativeLibTask();
			}
		}
		
		private void onInitSuccess() {
			// TODO: Nothing to do now.
			if (mServiceControl!=null){
				try {
					mServiceControl.successInit(2);		
			
					//自动启动
					onVehicleStart();
					realStart = true;
					needToStop = false;
				} catch (RemoteException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				//throw new NullPointerException();
			}
		}
		
		private void onInitFailed() {
			if  (mRetryInitDialog == null) {
				AlertDialog.Builder builder = new AlertDialog.Builder(RecoFaceActivity2.this);
				builder.setCancelable(false)
					.setTitle("初始化失败!")
					.setPositiveButton("重试", new DialogInterface.OnClickListener() {

						@Override
						public void onClick(DialogInterface dialog, int which) {
							mRetryInitDialog.dismiss();
							requestInitNativeLibTask();
						}

					})
					.setNegativeButton("退出程序", new DialogInterface.OnClickListener() {
						
						@Override
						public void onClick(DialogInterface dialog, int which) {
							mRetryInitDialog.dismiss();
							RecoFaceActivity2.this.finish();
						}
					});
				mRetryInitDialog = builder.create();
			}
			mRetryInitDialog.show();
		}

	}	
	
	/*AIDL实现看门狗的实现方式*/
	private MyServiceConnection conn = new MyServiceConnection();
	private IVechicleControl mServiceControl;
	private Intent myIntent = new Intent();
	
	private final class MyServiceConnection implements ServiceConnection{

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			// TODO Auto-generated method stub
			mServiceControl = IVechicleControl.Stub.asInterface(service);		
		}

		@Override
		public void onServiceDisconnected(ComponentName name) {
			// TODO Auto-generated method stub
			getApplicationContext().stopService(myIntent);
		}
		
	}
	
}

整理的比较乱,希望能帮助到大家!


  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值