手机卫士day12

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
    • 布局文件开发

      <LinearLayout
      android: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_light
      
      2. 拷贝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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值