手机卫士day12

来源:互联网 发布:中科院自动化所 知乎 编辑:程序博客网 时间:2024/06/04 18:12

day12

- 看门狗    - 看门狗原理介绍    - 创建服务WatchDogService    - 设置页面增加启动服务的开关    - 看门狗轮询检测任务栈            打印当前最顶上的activity            /**             * 看门狗服务 需要权限: android.permission.GET_TASKS             *              * @author Kevin             *              */            public class WathDogService extends Service {                private boolean isRunning;// 表示线程是否正在运行                private ActivityManager mAM;                @Override                public IBinder onBind(Intent intent) {                    return null;                }                @Override                public void onCreate() {                    super.onCreate();                    mAM = (ActivityManager) getSystemService(ACTIVITY_SERVICE);                    isRunning = true;                    new Thread() {                        public void run() {                            while (isRunning) {// 看门狗每隔100毫秒巡逻一次                                List<RunningTaskInfo> runningTasks = mAM.getRunningTasks(1);// 获取正在运行的任务栈                                String packageName = runningTasks.get(0).topActivity                                        .getPackageName();// 获取任务栈最上层activity的包名                                System.out.println("top Activity=" + packageName);                                try {                                    Thread.sleep(100);                                } catch (InterruptedException e) {                                    e.printStackTrace();                                }                            }                        };                    }.start();                }                @Override                public void onDestroy() {                    super.onDestroy();                    isRunning = false;// 结束线程                }            }- 轮询获取最近的task, 如果发现是加锁的,跳EnterPwdActivity        if (mDao.find(packageName)) {// 查看当前页面是否在加锁的数据库中            Intent intent = new Intent(WatchDogService.this,                    EnterPwdActivity.class);            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);            intent.putExtra("packageName", packageName);            startActivity(intent);        }        -----------------------------------        /**         * 加锁输入密码页面         *          * @author Kevin         *          */        public class EnterPwdActivity extends Activity {            private TextView tvName;            private ImageView ivIcon;            private EditText etPwd;            private Button btnOK;            @Override            protected void onCreate(Bundle savedInstanceState) {                super.onCreate(savedInstanceState);                setContentView(R.layout.activity_enter_pwd);                tvName = (TextView) findViewById(R.id.tv_name);                ivIcon = (ImageView) findViewById(R.id.iv_icon);                etPwd = (EditText) findViewById(R.id.et_pwd);                btnOK = (Button) findViewById(R.id.btn_ok);                Intent intent = getIntent();                String packageName = intent.getStringExtra("packageName");                PackageManager pm = getPackageManager();                try {                    ApplicationInfo info = pm.getApplicationInfo(packageName, 0);// 根据包名获取应用信息                    Drawable icon = info.loadIcon(pm);// 加载应用图标                    ivIcon.setImageDrawable(icon);                    String name = info.loadLabel(pm).toString();// 加载应用名称                    tvName.setText(name);                } catch (NameNotFoundException e) {                    e.printStackTrace();                }                btnOK.setOnClickListener(new OnClickListener() {                    @Override                    public void onClick(View v) {                        String pwd = etPwd.getText().toString().trim();                        if (!TextUtils.isEmpty(pwd)) {// 密码校验                            if (pwd.equals("123")) {                                finish();                            } else {                                Toast.makeText(EnterPwdActivity.this, "密码错误",                                        Toast.LENGTH_LONG).show();                            }                        } else {                            Toast.makeText(EnterPwdActivity.this, "请输入密码",                                    Toast.LENGTH_LONG).show();                        }                    }                });            }        }- 重写返回事件,跳转到主页面        //查看系统Launcher源码,确定跳转逻辑        @Override        public void onBackPressed() {            // 跳转主页面            Intent intent = new Intent();            intent.setAction(Intent.ACTION_MAIN);            intent.addCategory(Intent.CATEGORY_HOME);            startActivity(intent);            finish();//销毁当前页面        }- 发送广播,看门狗跳过检测        认证成功后,发送广播        EnterPwdActivity.java        // 发送广播,通知看门狗不要再拦截当前应用        Intent intent = new Intent();        intent.setAction("com.itheima.mobilesafeteach.ACTION_STOP_PROTECT");        intent.putExtra("packageName", packageName);        sendBroadcast(intent);        -------------------------------------------        WatchDogService.java        class InnerReceiver extends BroadcastReceiver {            @Override            public void onReceive(Context context, Intent intent) {                // 看门狗得到了消息,临时的停止对某个应用程序的保护                mSkipPackageName = intent.getStringExtra("packageName");            }        }        if (packageName.equals(mSkipPackageName)) {// 用过已经认证通过了,需跳过验证                System.out.println("无需验证...");                continue;        }- 相关优化        知识拓展:看门狗后台一直在运行,这样是比较耗电的。        我们要优化的的话怎么做呢?        在看门狗服务里,监听锁屏事件,如果锁屏了我就把看门狗停止(flag = false;);屏幕开启了,我就让看门狗开始工作启动服务并且flag = true;;        避免一次输入密码了不再输入;防止别人在我使用的时候,接着使用不用输入密码的情形;        也可以在锁屏的时候把mSkipPackageName赋值为空就行了。- 利用activity启动模式修复密码输入bug        1. 演示bug(进入手机卫士,按home退到后台,然后再打开加锁app,进入后发现跳转到手机卫士页面)        2. 画图分析,正常情况下的任务栈和bug时的任务栈图;        3. 解决问题;在功能清单文件EnterPwdActivity加上字段        <activity android:name="com.itheima.mobilesafe.EnterPwdActivity" android:launchMode="singleInstance"/>        4. 然后再画图分析正确的任务栈;- 隐藏最近打开的activity        长按小房子键:弹出历史记录页面,就会列出最近打开的Activity;        1. 演示由于最近打开的Activity导致的Bug;        2. 容易暴露用户的隐私          最近打开的Activity,是为了用户可以很快打开最近打开的应用而设计的;2.2、2.3普及后就把问题暴露出来了,很容易暴露用户的隐私。比如你玩一些日本开发的游戏:吹裙子、扒衣服这类游戏。你正在玩这些有些,这个时候,爸妈或者大学女辅导员过来了,赶紧按小房子,打开背单词的应用,这时大学女辅导员走过来说,干嘛呢,把手机交出来,长按一下小房子键,这个时候很尴尬的事情就产生了。            A:低版本是无法移除的。低版本记录最近8个;想要隐藏隐私,打开多个挤出去;            B:4.0以后高版本就可以直接移除了。考虑用户呼声比较高。        3. 设置不在最近任务列表显示activity            <activity                    android:excludeFromRecents="true"                        android:name="com.itheima.mobilesafe.EnterPwdActivity"                        android:launchMode="singleInstance" />        4. 在装有腾讯管家的模拟器演示腾讯管理的程序锁功能;也没用现实最近的Activity,它也是这样做的。        知识拓展,以后开发带有隐私的软件,或者软件名称不好听的应用,就可以加载在最近打开列表不包括字段.- 腾讯管家和手机卫士同时加锁,谁更快?        腾讯管家会更快一些, 所以需要再进一步优化- 提高性能    - 缩短每次巡逻时间            //将100改为20            try {                Thread.sleep(20);            } catch (InterruptedException e) {                    e.printStackTrace();            }    - 不频繁调用数据库            从数据库中读取所有已加锁应用列表,每次从集合中查询判断            mLockedPackages = mDao.getInstance(this).findAll();// 查询所有已加锁的应用列表            // if (mDao.find(packageName)) {// 查看当前页面是否在加锁的数据库中            if (mLockedPackages.contains(packageName)) {}    - 重新和腾讯管家比拼速度    - 监听数据库变化, 更新集合        - 增加另外一款软件进入程序锁。打开看看,是无法打开输入密码页面的;解析原因;            这个时候就需要根据数据库的数据变化而改变集合的信息了,就用到了观察者;        - 联想监听来电拦截时,监听通话日志变化的逻辑,解释原理        - 具体实现                AppLockDao.java                // 数据库改变后发送通知                mContext.getContentResolver().notifyChange(                        Uri.parse("content://com.itheima.mobilesafe/applockdb"), null);                                 -------------------------------------                WatchDogService.java                    // 监听程序锁数据库内容变化                mObserver = new MyContentObserver(new Handler());                getContentResolver().registerContentObserver(                        Uri.parse("content://com.itheima.mobilesafe/applockdb"), true,                        mObserver);                     getContentResolver().unregisterContentObserver(mObserver);// 注销观察者                      class MyContentObserver extends ContentObserver {                    public MyContentObserver(Handler handler) {                        super(handler);                    }                    @Override                    public void onChange(boolean selfChange) {                        System.out.println("数据变化了...");                        mLockedPackages = mDao.findAll();// 查询所有已加锁的应用列表                    }                }

- 手机杀毒
- 什么是病毒?

        计算机病毒是一个程序,一段可执行码。就像生物病毒一样,具有自我繁殖、互相传染以及激活再生等生物病毒特征。计算机病毒有独特的复制能力,它们能够快速蔓延,又常常难以根除。它们能把自身附着在各种类型的文件上,当文件被复制或从一个用户传送到另一个用户时,它们就随同文件一起蔓延开来。- 计算机第一个病毒        诞生于麻省理工大学- 蠕虫病毒        熊猫烧香,蠕虫病毒的一种,感染电脑上的很多文件;exe文件被感染,html文件被感染。        主要目的:证明技术有多牛。写这种病毒的人越来越少了- 木马        盗窃信息,盗号、窃取隐私、偷钱,玩了一个游戏,买了很多装备,监听你的键盘输入,下次进入的话,装备全部没了。        主要目目的:挣钱,产生利益;- 灰鸽子        主要特征,控制别人电脑,为我所有。比如挖金矿游戏挣钱的,控制几十万台机器为你干活。        总会比银河处理器快的多。        特点是:不知情情况下安装下的。- 所有的病毒,都是执行后才有危害,如果病毒下载了,没有安装运行,是没有危害的。    - 杀毒原理介绍        定位出特殊的程序,把程序的文件给删除。        王江民, 江民杀毒软件        Kv300        Kv300 干掉300个病毒        开发kv300后很多人用盗版的。        江民炸弹- 病毒怎么找到?-收集病毒的样本        电信 网络运营商主节点 部署服务器集群(蜜罐)        一组没有防火墙 没有安全软件 没有补丁的服务器, 主动联网,下载一些软件运行。这样情况下,特别容易中病毒。        工作原理相当于:苍蝇纸- 360互联网云安全计划        所有的用户都是你的蜜罐;        收集的数据量就大大提高了;        国内安全厂商,有些没有职业道德。        收集一些个人隐私,或者商业机密的文件也收集过去 3Q大战- 传统杀毒软件的缺陷        目前卡巴斯基病毒库已经有了2千多万病毒        传统杀毒软件的缺陷: 病毒数据库越来越大;        只能查杀已知的病毒,不能查杀未知病毒;        360免杀        写了一个木马,在加一个壳,加壳后360就识别不了了- 主动防御        检查软件        1.检查开机启动项        2.检查注册表;        3.检查进程列表        病毒特征:        1、开启启动        2、隐藏自身        3、监视键盘        4、联网发邮件        启发式扫描-扫描单个文件        拷贝文件到虚拟机-相当于精简版的系统, 运行后检测是否具备病毒特点- 杀毒引擎        优化后的数据库查询算法,优先扫描当下最常见的病毒, 速度快- Android上的杀毒软件        大多数停留在基于数据库方式杀毒        LBE主动防御方式杀毒。敏感权限扫描,敏感操作提示,和小米深度合作        金山手机卫士病毒库
  • 手机杀毒模块开发

    • 创建AntiVirusActivity
    • 布局文件开发

      <LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:padding="10dp" ><FrameLayout    android:layout_width="80dp"    android:layout_height="80dp" >    <ImageView        android:id="@+id/imageView1"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:src="@drawable/ic_scanner_malware" />    <ImageView        android:id="@+id/iv_scanning"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:src="@drawable/act_scanning_03" /></FrameLayout><LinearLayout    android:layout_width="match_parent"    android:layout_height="match_parent"    android:gravity="center"    android:orientation="vertical" >    <TextView        android:id="@+id/tv_scan_status"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:singleLine="true"        android:text="正在初始化8核杀毒引擎"        android:textColor="#000"        android:textSize="18sp" />    <ProgressBar        android:id="@+id/progressBar1"        style="?android:attr/progressBarStyleHorizontal"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginLeft="10dp"        android:layout_marginRight="10dp" /></LinearLayout>

    • 扫描动画

      RotateAnimation anim = new RotateAnimation(0, 360,    Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,    0.5f);anim.setDuration(1000);//间隔时间anim.setRepeatCount(Animation.INFINITE);//无限循环anim.setInterpolator(new LinearInterpolator());//匀速循环,不停顿ivScanning.startAnimation(anim);
    • 自定义进度条样式

      1. 查看android系统对Progressbar样式的定义开发环境\platforms\android-16\data\res\values\styles.xml,搜索Widget.Holo.ProgressBar.Horizontal->progress_horizontal_holo_light2. 拷贝xml文件,修改成自己的图片<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >    <item        android:id="@android:id/background"        android:drawable="@drawable/security_progress_bg"/>    <item        android:id="@android:id/secondaryProgress"        android:drawable="@drawable/security_progress">    </item>    <item        android:id="@android:id/progress"        android:drawable="@drawable/security_progress">    </item></layer-list>3. 将xml文件设置给Progressbar<ProgressBar    android:id="@+id/progressBar1"    style="?android:attr/progressBarStyleHorizontal"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:layout_marginLeft="10dp"    android:layout_marginRight="10dp"    android:progress="50"    android:layout_marginTop="5dp"    android:progressDrawable="@drawable/custom_progress" />4. 进度更新    // 更新进度条    new Thread() {        public void run() {            pbProgress.setMax(100);            for (int i = 0; i <= 100; i++) {                pbProgress.setProgress(i);                try {                    Thread.sleep(30);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        };    }.start();
  • 获取系统安装包的MD5

    PackageManager pm = getPackageManager();// 获取所有已安装/未安装的包的安装包信息// GET_UNINSTALLED_PACKAGES代表已删除,但还有安装目录的List<PackageInfo> packages = pm            .getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);for (PackageInfo packageInfo : packages) {    //apk安装路径    String apkPath = packageInfo.applicationInfo.sourceDir;    //计算apk的md5    String md5 = MD5Utils.getFileMd5(apkPath);}-------------------------------------------------/** * 获取某个文件的md5 * @param path * @return */public static String getFileMd5(String path) {    try {        MessageDigest digest = MessageDigest.getInstance("MD5");        FileInputStream in = new FileInputStream(path);        int len = 0;        byte[] buffer = new byte[1024];        while ((len = in.read(buffer)) != -1) {            digest.update(buffer, 0, len);        }        byte[] result = digest.digest();        StringBuffer sb = new StringBuffer();        for (byte b : result) {            int i = b & 0xff;// 将字节转为整数            String hexString = Integer.toHexString(i);// 将整数转为16进制            if (hexString.length() == 1) {                hexString = "0" + hexString;// 如果长度等于1, 加0补位            }            sb.append(hexString);        }        System.out.println(sb.toString());// 打印得到的md5        return sb.toString();    } catch (Exception e) {        e.printStackTrace();    }    return "";}
  • 扫描病毒数据库

    AntiVirusDao.java/** * 病毒数据库的封装 *  * @author Kevin *  */public class AntiVirusDao {    public static final String PATH = "data/data/com.itheima.mobilesafeteach/files/antivirus.db";        /**         * 根据签名的md5判断是否是病毒         *          * @param md5         * @return 返回病毒描述,如果不是病毒,返回null         */        public static String isVirus(String md5) {            SQLiteDatabase db = SQLiteDatabase.openDatabase(PATH, null,                    SQLiteDatabase.OPEN_READONLY);            Cursor cursor = db.rawQuery("select desc from datable where md5=? ",                    new String[] { md5 });            String desc = null;            if (cursor.moveToFirst()) {                desc = cursor.getString(0);            }            cursor.close();            db.close();            return desc;        }}
  • 扫描安装包并更新进度条

    int progress = 0;Random random = new Random();for (PackageInfo packageInfo : packages) {    String name = packageInfo.applicationInfo.loadLabel(pm)            .toString();    String apkPath = packageInfo.applicationInfo.sourceDir;    String md5 = MD5Utils.getFileMd5(apkPath);    String desc = AntiVirusDao.isVirus(md5);    if (desc != null) {        // 是病毒        System.out.println("是病毒....");    } else {        // 不是病毒        System.out.println("不是病毒....");    }    progress++;    pbProgress.setProgress(progress);    try {        Thread.sleep(50 + random.nextInt(50));//随机休眠一段时间    } catch (InterruptedException e) {        e.printStackTrace();    }}
  • 扫描过程中,更新扫描状态文字

    - 扫描前,强制休眠2秒,展示"正在初始化8核杀毒引擎"- 使用handler发送消息,更新TextView为:正在扫描:应用名称- 扫描结束后, 发送消息,更新TextView为:扫描完毕- 扫描结束后,关闭扫描的动画
  • 扫描过程中,更新扫描文件列表

    - 布局文件中添加空的LinearLayout(竖直方向),动态给线性布局添加TextView- 使用ScrollView包裹线性布局,保证可以上下滑动     <ScrollView        android:layout_width="match_parent"        android:layout_height="match_parent" >        <LinearLayout            android:id="@+id/ll_scanning"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:orientation="vertical" >        </LinearLayout>    </ScrollView>- 如果发现是病毒, TextView需要展示为红色, 为了区分是不是病毒,可以把扫描的文件封装成一个对象ScanInfo    class ScanInfo {        public String packageName;        public String desc;        public String name;        public boolean isVirus;    }    private Handler mHandler = new Handler() {        public void handleMessage(android.os.Message msg) {            switch (msg.what) {            case SCANNING:                ScanInfo info = (ScanInfo) msg.obj;                tvScanStatus.setText("正在扫描:" + info.name);                TextView tvScan = new TextView(AntiVirusActivity.this);                if (info.isVirus) {                    tvScan.setText("发现病毒:" + info.name);                    tvScan.setTextColor(Color.RED);                } else {                    tvScan.setText("扫描安全:" + info.name);                }                llScanning.addView(tvScan);                break;            case SCANNING_FINISHED:                tvScanStatus.setText("扫描完毕");                ivScanning.clearAnimation();// 清除扫描的动画                break;            default:                break;            }        };    };
  • 制作病毒

    制作两个apk文件,并将这两个apk文件的md5加入到病毒数据库中,这样的话就可以测试扫出病毒的情况了注意: 将原来的antivirus.db替换为新的文件后,一定要把app的数据清除后再运行,重新进行拷贝数据库的操作, 否则app仍找的是data/data目录下的旧版数据库!
  • 创建病毒集合

  • 发现病毒后,提示用户删除病毒

    if (mVirusList.isEmpty()) {    Toast.makeText(getApplicationContext(), "你的手机很安全了,继续加油哦!",            Toast.LENGTH_SHORT).show();} else {    showAlertDialog();}----------------------------/** * 发现病毒后,弹出警告弹窗 */protected void showAlertDialog() {    AlertDialog.Builder builder = new AlertDialog.Builder(this);    builder.setTitle("警告!");    builder.setMessage("发现" + mVirusList.size() + "个病毒, 非常危险,赶紧清理!");    builder.setPositiveButton("立即清理",            new DialogInterface.OnClickListener() {                @Override                public void onClick(DialogInterface dialog, int which) {                    for (ScanInfo info : mVirusList) {                        // 卸载apk                        Intent intent = new Intent(Intent.ACTION_DELETE);                        intent.setData(Uri.parse("package:"                                + info.packageName));                        startActivity(intent);                    }                }            });    builder.setNegativeButton("下次再说", null);    AlertDialog dialog = builder.create();    dialog.setCanceledOnTouchOutside(false);// 点击弹窗外面,弹窗不消失    dialog.show();}
  • 处理横竖屏切换

    fn+ctrl+f11 切换模拟器横竖屏后, Activity的onCreate方法会从新走一次, 可以通过清单文件配置,Activity强制显示竖屏<activity    android:name=".activity.AntiVirusActivity"    android:screenOrientation="portrait" />或者, 可以显示横屏, 通过此配置可以不重新创建Activity<activity    android:name=".activity.AntiVirusActivity"    android:configChanges="orientation|screenSize|keyboardHidden" />
0 0