Firefly开源社区

标题: 日志查看器logcat源码分享 [打印本页]

作者: Stephen    时间: 2014-10-24 19:21
标题: 日志查看器logcat源码分享
本帖最后由 ZZP 于 2014-10-25 10:12 编辑

     我们做程序开发的经常要调试查看打印信息,特别是android,最常用的就是用adb logcat命令,很多时候我们都是用数据线连接电脑,用终端或者Eclipse软件来查看,如果应用在测试时报错又一时找不到设备,就会错失捕抓到错误信息的机会了;可能这个错误是随机出现的,那就要费更多时间去测试才能重现刚才的错误了。
    很明显,我们需要一款能在安卓设备上查看logcat信息的应用,很幸运地是,电子市场上alogcat 就是这样的应用,它能显示出错误或异常的蛛丝马迹;alogcat 就是在代码里执行adb logcat 命令(详细的logcat命令说明请参考 Android的logcat用法),然后把它显示出来。但alogcat并不适合每个人,比如:alogcat必须打开才能显示出来;没有自动判断安卓设备是否root,如果你的机器没有root的话,你会发现选择root运行选项的话,一点信息都没有打印出来,也没有提示出来等等。但alogcat还是有其优点的,所以我参考了alogcat应用,在网上找来一些代码,修改整合成自己的日志查看器,和大家一起分享学习,希望对大家有帮助:

PS:自从安卓系统4.2或4.2以上的版本,查看其它应用的logcat 是需要root权限才能查看得到的所以如果你发现打印的信息和电脑上看到的信息不同的话,很可能就是你的安卓手机或开发板没有root。

判断安卓手机或平板是否root过代码:
  1. //判断有没有 root权限
  2. public boolean requestRoot() {
  3.         Process process = null;
  4.         try {
  5.                 // Preform su to get root privledges
  6.                 process = Runtime.getRuntime().exec("su");
  7.                 // confirm that we have root
  8.                 DataOutputStream outputStream = new DataOutputStream(process.getOutputStream());
  9.                 outputStream.writeBytes("echo hello\n");
  10.                 // Close the terminal
  11.                 outputStream.writeBytes("exit\n");
  12.                 outputStream.flush();
  13.                 process.waitFor();
  14.                 if (process.exitValue() != 0) {
  15.                         Toast.makeText(mContext, R.string.not_root, Toast.LENGTH_LONG).show();
  16.                         return false;
  17.                 } else {
  18.                         // success
  19.                         Toast.makeText(mContext, R.string.root_success, Toast.LENGTH_LONG).show();
  20.         return true;
  21.                 }
  22.         } catch (IOException e) {
  23.                 Log.w("root", "Cannot obtain root");
  24.                 Toast.makeText(mContext, R.string.not_root, Toast.LENGTH_LONG).show();
  25.                 return false;
  26.         } catch (InterruptedException e) {
  27.                 Toast.makeText(mContext, R.string.not_root, Toast.LENGTH_LONG).show();
  28.                 return false;
  29.         }
  30. }
复制代码


    Runtime.getRuntime().exec("su"); 这个是获取root权限,如果能获取得到root权限,我们可以用这个方法执行adb shell下的命令,随意修改系统文件,有root权限的安卓和开发板,请慎用这个方法,小心变砖!:lol


在代码中执行adb logcat 命令的核心代码:
  1. public void start() {
  2.         // Log.d("alogcat", "starting ...");
  3.         stop(); // stop EX
  4.         mRunning = true;
  5.         // command:执行线程 initialDelay:初始化延时 period:前一次执行结束到下一次执行开始的间隔时间(间隔执行延迟时间) unit:计时单位
  6.         EX = Executors.newScheduledThreadPool(1);
  7.         EX.scheduleAtFixedRate(catRunner, CAT_DELAY, CAT_DELAY,TimeUnit.SECONDS);
  8.         try {
  9.                 Message m = Message.obtain(mHandler, LogActivity.CLEAR_WHAT);
  10.                 mHandler.sendMessage(m);
  11.                 List<String> progs = new ArrayList<String>();
  12.                 // logcat的命令参数
  13.                 if (TLogcatApplication.getRoot()) {
  14.                         Log.v("zxxroot", ">>>>>>>>root");
  15.                         progs.add("su");
  16.                         progs.add("-c");
  17.                 }
  18.                 progs.add("logcat");
  19.                 progs.add("-v");
  20.                 progs.add(mFormat.getValue());
  21.                 if (mBuffer != Buffer.MAIN) {
  22.                         progs.add("-b");
  23.                         progs.add(mBuffer.getValue());
  24.                 }
  25.                 progs.add("-s");
  26.                 progs.add("*:" + mLevel);
  27.                 logcatProc = Runtime.getRuntime().exec(progs.toArray(new String[progs.size()]));
  28.                            mReader = new BufferedReader(new InputStreamReader(logcatProc.getInputStream()), 1024);
  29.                 String line;
  30.                 // 不停在这里执行 会读出空的line 但也不为全空,还会有前面的标签zxxr tag 主要还是控制mRunning
  31.                 while (mRunning && ((line = mReader.readLine()) != null)) {
  32.                         if (!mRunning) {
  33.                                 break;
  34.                         }
  35.                         if (line.length() == 0) {
  36.                                 continue;
  37.                         }
  38.                         if (mIsFilterPattern) {
  39.                                 if (mFilterPattern != null&& !mFilterPattern.matcher(line).find()) {
  40.                                         continue;
  41.                                 }
  42.                         } else {
  43.                                 if (mFilter != null&& !line.toLowerCase().contains(mFilter.toLowerCase())) {
  44.                                         continue;
  45.                                 }
  46.                         }
  47.                         // 思路就是不停读出每一行数据,符合条件的就加入一个mLogCache,每隔一秒如果mLogCache有内容,就打印出来
  48.                         synchronized (mLogCache) {
  49.                                 mLogCache.add(line);
  50.                         }
  51.                 }
  52.         } catch (IOException e) {
  53.                 Log.e("alogcat", "error reading log", e);
  54.                 return;
  55.         } finally {
  56.                 if (logcatProc != null) {
  57.                         logcatProc.destroy();
  58.                         logcatProc = null;
  59.                 }
  60.                 if (mReader != null) {
  61.                         try {
  62.                                 mReader.close();
  63.                                 mReader = null;
  64.                         } catch (IOException e) {
  65.                                 Log.e("alogcat", "error closing stream", e);
  66.                         }
  67.                 }
  68.         }
  69. }
复制代码


注意:这里要单独开一个线程来执行adb logcat命令,不然读到的数据和系统反馈的数据不同步;
EX会周期地读取mLogCache里面的内容,并通过handler发送消息更新listView;显示出来一行一行的日志其实就是一个listView。
后台日志记录用到前台服务的方法:
  1. try {
  2.     mStartForeground = getClass().getMethod("startForeground", int.class, Notification.class);
  3.     mStopForeground = getClass().getMethod("stopForeground", boolean.class);
复制代码



    我们听歌的时候经常可以见到,音乐应用关闭之后,在通知栏出现可以控制音乐停播放的消息。在后台日志记录中我也用到类似这种方法,获得这个方法要用反射,反射不理解的请参考这个贴java代码映射

在安卓手机或平板上测试的效果图如附件:
       listView是每一行是由textView组成的,textView根据adb logcat的不同级别显示不同颜色。后台日志保存记录可以通过点击通知栏停止,即使应用关闭,后台日志保存还是在运行的。





apk下载如附件: HiLogcat_firefly.apk.tar.gz (163.59 KB, 下载次数: 45)






作者: Stephen    时间: 2014-10-24 19:53
本帖最后由 Stephen 于 2014-10-24 19:56 编辑

发不了链接,只能自己沙发了;P
Android的logcat用法:http://   jack22.iteye.com/blog/1123096

java映射 :http://    developer.t-firefly.com/thread-189-1-1.html



源码下载链接 http://   download.csdn.net/detail/hawk_flying/8078465
作者: ZZP    时间: 2014-10-25 09:14
这个小功能挺实用的,特别是后台抓取logcat功能。
至于Android4.3\4.4可以依靠superUser Apk 或者其它工具 进行root
作者: ZZP    时间: 2014-10-25 10:14
Stephen 发表于 2014-10-24 19:53
发不了链接,只能自己沙发了
Android的logcat用法:http://   jack22.iteye.com/blog/1123096

楼主小兄弟,原文已经帮你把链接补上,手痒顺便帮你排了下版。
作者: Stephen    时间: 2014-10-27 09:38
ZZP 发表于 2014-10-25 10:14
楼主小兄弟,原文已经帮你把链接补上,手痒顺便帮你排了下版。

好看 了许多,谢谢版主!
作者: hyp    时间: 2016-11-23 21:27
谢谢分享啊




欢迎光临 Firefly开源社区 (https://dev.t-firefly.com/) Powered by Discuz! X3.1