[mobilesafe] 03_开启看门狗服务的优化及问题

Android 4.0

开启看门狗服务的优化及问题

问题1:在打开要被保护的应用时,有一瞬间是可以看到应用的界面
分析:这是因为开启看门狗睡眠了300ms,Thread.sleep(300);
如果刚好,看门狗服务正在睡眠,此时打开要被保护的应用,就会出现上面的问题
原始
/**
 * 4、开启看门狗服务在子线程
 */
private void startWatchDogInThread() {
    new Thread() {
        public void run() {
            flag = true;
            while (flag) {

                // 2)获取最近运行的3个Task
                List<RunningTaskInfo> runningTasks = activityManager.getRunningTasks(3);

                // 3)新打开的Activity在第一个task里面
                RunningTaskInfo runningTaskInfo = runningTasks.get(0);

                // 4)然后取栈顶,就是刚打开的Activity
                ComponentName topActivity = runningTaskInfo.topActivity;
                String packageName = topActivity.getPackageName();
                boolean isLock = appLockDao.find(packageName);
                if (isLock) {// 如果锁上了,进入输入密码Activity界面
                    if (!tempNoProtectAppPackageName.contains(packageName)) {// 如果临时不保护的集合不包含当前应用的包名,那么就要保护
                        Log.i(TAG, packageName + "锁上了~");
                        // 将要保护的packagename传递过去
                        intent.putExtra("packagename", packageName);
                        startActivity(intent);
                    }
                } else {// 没有锁上
                    Log.i(TAG, packageName + "没有锁上~");
                }
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(packageName);
            }
        }
    }.start();
}
问题1解决:3个优化
优化后:
/**
 * 数据库里面的所有的保护的程序的集合
 */
private List<String> protectedPackageNames;  
 
/**
 * 4、开启看门狗服务在子线程
 */
private void startWatchDogInThread() {
    new Thread() {
        public void run() {
            flag = true;
            while (flag) {
                // 2)获取最近运行的3个Task
                //List<RunningTaskInfo> runningTasks = activityManager.getRunningTasks(3);
                // 看门狗优化2:只需要获取第一个就行了
                List<RunningTaskInfo> runningTasks = activityManager.getRunningTasks(1);
                // 3)新打开的Activity在第一个task里面
                RunningTaskInfo runningTaskInfo = runningTasks.get(0);
                // 4)然后取栈顶,就是刚打开的Activity
                ComponentName topActivity = runningTaskInfo.topActivity;
                String packageName = topActivity.getPackageName();

                    //boolean isLock = appLockDao.find(packageName);
                    //if (isLock) {// 如果锁上了,进入输入密码Activity界面,// 查询内存中保存的加锁的应用的包名
                    // 看门狗优化3:上面查询数据库是一个非常耗时的操作,应该先将其查询到内存一个集合protectedPackageNames,
                                 然后查询内存,效率高10倍左右
                    boolean isContains = protectedPackageNames.contains(packageName);
                    if (isContains) {
                        if (!tempNoProtectAppPackageName.contains(packageName)) {
                        // 如果临时不保护的集合不包含当前应用的包名,那么就要保护
                            Log.i(TAG, packageName + "进行保护,输入密码~");
                            intent.putExtra("packagename", packageName);// 将要保护的packagename传递过去
                            startActivity(intent);
                        }
                    } else {// 没有锁上
                        Log.i(TAG, packageName + "没有锁上~");
                    }

                // 看门狗优化1:睡眠时间不宜过长,但必须要睡,否则cpu和内存资源消耗很厉害
                try {
                    // Thread.sleep(300);//优化前
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(packageName);
            }
        }
    }.start();
}

问题2:先将数据查询到内存,然后再从里面读取,就是服务一开启,那么里面的监听的要保护的应用名,就不会变换了,如何解决呢?
解决:使用内容观察者

a) 在dao层,当底层数据库数据变化时,大喊一声,数据变化了
内容观察者,大喊一声notify(),数据变化了~~~
/**
 * 1、往数据库中插入加锁应用名
 * 
 * @param packagename  要插入的加锁应用的包名
 * @return  返回插入到数据库哪一行,
 */
public long add(String packagename) {
    // 1、获取数据库
    SQLiteDatabase database = helper.getWritableDatabase();
    // 2、插入数据到数据库
    ContentValues values = new ContentValues();
    values.put("packagename", packagename);
    long insert = database.insert(TABLEnull, values);// 返回插入数据的行号
    // 3、关闭数据库
    database.close();
    // 4、数据库内容变化时,大喊一声,数据变化了
    Uri uri = Uri.parse("content://cn.zengfansheng.applock.change");
    context.getContentResolver().notifyChange(uri, null);
    return insert;
}
/**
 * 2、从数据库中删除加锁应用
 * @param packagename 要删除的加锁应用的包名
 * @return 返回受影响的行数
 */
public long delete(String packagename) {
    SQLiteDatabase database = helper.getWritableDatabase();
    int delete = database.delete(TABLE"packagename=?"new String[]{packagename});
    database.close();
    Uri uri = Uri.parse("content://cn.zengfansheng.applock.change");
    context.getContentResolver().notifyChange(uri, null);
    return delete;
}
b) 在看门狗服务里面,注册一个内容观察者,当收到内容改变时,及时更新数据
/**
 * 7、内容观察者,观察到数据库中数据变化时,及时更新保存着要保护的应用名的List中的数据
 * @author hacket
 */
private class MyContentObserver extends ContentObserver {
    public MyContentObserver(Handler handler) {
        super(handler);
    }
    // 数据库中数据变化,集合数据也要变化
    @Override
    public void onChange(boolean selfChange, Uri uri) {
        super.onChange(selfChange);
        // 当观察到数据变化时,就重新获取数据
        protectedPackageNames = appLockDao.findAll();
    }
}