开发一款抓取Android系统Log的APP(logcat, kernel, Memory, cpu)
近期项目需要一款抓取系统log的实用工具,具体的内容包括kernel中的log, cpu中的log, memory 中的log, 以及system中的log,在Android4.1之后 认为应用读取系统的log是不安全的,所以要对apk进行系统签名才能读取系统log,如果不能进行系统签名,那么就通过相应的adb命令进行读取.
通过功能分析,做的步骤分为如下大概几步:
1.工具可以开启自启动进行抓取
2,可通过广播控制开始和停止
3.界面不可显示无图标,但是可以通过特定广播打开一个操作activity
4.操作界面可以手动操作,可以其中某几个选择抓取,可以实现 copy到U盘,手动点击上传到服务器,手动点击清除log选项.
5.具体的log抓取实现
因项目中有敏感信息 仅仅用逻辑分析为主
先来说一下对应log adb 抓取的方法
kernel中的log
#会持续输出
adb shell cat /dev/kmsg
#不会持续输出
adb shell dmesg
#会持续输出
adb logcat -b kernelcpu中的log
#会持续输出
adb shell top -m 5memory 中的log
#不会持续输出
adb shell dumpsys meminfo以及system中的log
#会持续输出
adb logcat
实现原理就是 使用 Runtime.getRuntime()方法执行 adb命令,但是通过如下命令是不会执行成功的,因为 exec不支持重定向功能
Runtime run = Runtime.getRuntime();
Process proc = run.exec("adb shell top -m 5 > my.txt");
关于如上方法我们可以使用ProcessBuilder 拿到process 而 process可以通过 process.getInputStream() 可以持续读对应的流,方便IO操作. 具体的细节在下面讲.
ProcessBuilder pBuilder = new ProcessBuilder(new String[]{"sh", "-c", "adb shell top -m 5"});pBuilder.redirectErrorStream(true);pr = pBuilder.start();
1.工具可以开启自启动今行抓取,通过build.prop 配置信息进行控制 通过底层配置的好处是不同项目只需要在build.prop中配置不同的值 就能决定是否开启开机抓取功能,只需要一个apk应用即可实现全部兼容
1.1放到广播里面监听 android.intent.action.BOOT_COMPLETED
<receiver android:name=".broadcastreceiver.BootBroadcastReceiver"><intent-filter><action android:name="android.intent.action.BOOT_COMPLETED"/><category android:name="android.intent.category.LAUNCHER" /></intent-filter></receiver>
1.2 AndroidManifest.xml 权限添加
<uses-permission android:name="android.permission.READ_LOGS"/><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/><uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/><uses-permission android:name="android.permission.DUMP"/><uses-permission android:name="android.permission.INTERNET"/>
1.3在接收到开机广播 之后 读取底层配置信息 是否开启log抓取服务 ,读取buil.prop可用如下反射方法进行读取
/*** 读取底层配置 配置是否开机自启动抓取log* @param context* @return false 开机不启动 , true标示开机启动*/private boolean isStartLogUtis(Context context) {String sn = null;try {ClassLoader cl = context.getClassLoader();Class SystemProperties = cl.loadClass("android.os.SystemProperties");Class[] paramTypes = new Class[1];paramTypes[0] = String.class;Method get = SystemProperties.getMethod("get", paramTypes);sn = (String) get.invoke(SystemProperties, new Object[]{"xxxx.logtool.start"});if (TextUtils.isEmpty(sn.trim())) {return false;}LogUtils.d(" isStartLogUtis " + sn.trim());return !TextUtils.isEmpty(sn.trim());} catch (Exception e) {e.printStackTrace();}return false;}
1.4具体的广播实现
static final String ACTION = "android.intent.action.BOOT_COMPLETED";@Overridepublic void onReceive(Context context, Intent intent) {// isStartLogUtis(context) 读取底层配置的值if (intent.getAction() == ACTION && isStartLogUtis(context)) {Intent service = new Intent(context, XXXXService.class);context.startService(service);}}
2.可通过广播进行抓取和停止通过自定义的广播可以实现发送广播进行抓取操作,当服务开启时禁止重复开启,当服务未开启时候禁止停止服务
2.1查询服务的核心代码如下:
/*** 判断服务是否开启* @param context* @param ServiceName 服务的完整路径(例:com.zhidao.logtools.service)* @return*/public boolean isServiceRunning(Context context, String ServiceName) {if (TextUtils.isEmpty(ServiceName)) {return false;}ActivityManager myManager =(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);ArrayList<ActivityManager.RunningServiceInfo> runningService =(ArrayList<ActivityManager.RunningServiceInfo>)myManager.getRunningServices(100);for (int i = 0; i < runningService.size(); i++) {if (runningService.get(i).service.getClassName().toString().equals(ServiceName)) {return true;}}return false;}
3.界面不可显示无图标,但是可以通过特定广播打开一个操作activity
3.1隐藏桌面图标可以使用在AndroidManifest.xml 将所有的activity标签中的android.intent.category.LAUNCHER注释掉即可
<activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><!--<category android:name="android.intent.category.LAUNCHER" />--></intent-filter></activity>
注释掉上面的内容 Android Studio会报错,那是应为Android Studio找不到 主Activity所导致,两个方法解决
3.1.1 在Androidstudio 点击 app--> edit configurations...--> Launch Options --> Launch 选着 Specified Activity ,下面的 Activity 选择你进入的activity就行
3.1.2 使用gradle命令 在跟目录执行 ./gradlew assembleDebug 即可打包
3.2使用 adb命令打开Activity: adb shell am start -n 包名/.XXXActivity
4.功能的UI搭建,不在这里细讲
5.具体的log抓取实现
5,1抓取log是一个耗时操作,需要在后台运行,因此将抓取动作放到后台运行 但是又因为其属于耗时操作 放到子线程
服务类不再介绍要是想看服务相关的文章可以点这里
5.2 子线程的具体实现
5.2.1 抓取 cpu的log cpu的log是持续输出的
mProcess = Runtime.getRuntime().exec("top -m 5");InputStreamReader inputStreamReader = new InputStreamReader(mProcess.getInputStream());BufferedReader bufferedReader = new BufferedReader(inputStreamReader);String line = null;if ((line = bufferedReader.readLine()) != null) {mCpuInfoWriter.write(line);mCpuInfoWriter.write("\n");if (line.startsWith("User")) {mCpuInfoWriter.write(mDateFormat.format(new Date()));mCpuInfoWriter.write("\n");}mCpuInfoWriter.flush();}
5.2.2 抓取kenel实现
List<String> commandList = new ArrayList<String>();commandList.add("logcat");commandList.add("-b");commandList.add("kernel");process = Runtime.getRuntime().exec(commandList.toArray(new String[commandList.size()]));InputStreamReader inputStreamReader = new InputStreamReader(process.getInputStream());BufferedReader bufferedReader = new BufferedReader(inputStreamReader);String line = null;mKenelInfoWriter.write(mDateFormat.format(new Date()));mKenelInfoWriter.write("\n");while ((line = bufferedReader.readLine()) != null) {mKenelInfoWriter.write(line);mKenelInfoWriter.write("\n");mKenelInfoWriter.flush();}
5.2.3抓取 mainlog
try {process = Runtime.getRuntime().exec("logcat");InputStreamReader inputStreamReader = new InputStreamReader(process.getInputStream());BufferedReader bufferedReader = new BufferedReader(inputStreamReader);String line = null;mMainInfoWriter.write(mDateFormat.format(new Date()));mMainInfoWriter.write("\n");while ((line = bufferedReader.readLine()) != null) {mMainInfoWriter.write(line);mMainInfoWriter.write("\n");mMainInfoWriter.flush();}
5.2.4抓取Memorylog 因为 Memorydums信息不是一直等待,每次只有一次输出,因此五秒钟循环一次
while (true) {process = Runtime.getRuntime().exec("dumpsys meminfo");InputStreamReader inputStreamReader = new InputStreamReader(process.getInputStream());BufferedReader bufferedReader = new BufferedReader(inputStreamReader);String line = null;mMemoryInfoWriter.write(mDateFormat.format(new Date()));mMemoryInfoWriter.write("\n");while ((line = bufferedReader.readLine()) != null) {mMemoryInfoWriter.write(line);mMemoryInfoWriter.write("\n");mMemoryInfoWriter.flush();}Thread.sleep(5000);//}
5.2.5具体的Thread实现 将上述的方法直接替换到如下类中即可
/*** 录制 System 线程类* @author chencl*/
public class RecordSystemLogcatTask extends Thread {private Process process = null;private OutputStreamWriter mSystemInfoWriter = null;private static SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd-HHmmss");public static final String LOG_SDCARD_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator+ "LogInfo" +File.separator+ mDateFormat.format(new Date());public RecordSystemLogcatTask() {// TODO Auto-generated constructor stubif (mSystemInfoWriter == null) {try {mSystemInfoWriter = new OutputStreamWriter(new FileOutputStream(LOG_SDCARD_PATH + File.separator + mDateFormat.format(new Date()) + "_system.log"));} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}@Overridepublic void run() {// TODO Auto-generated method stubsuper.run();try {//TODO//将上述方法放到本处}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}
开发一款抓取Android系统Log的APP(logcat, kernel, Memory, cpu)相关推荐
- 30分钟开发一款抓取网站图片资源的浏览器插件
前言 由于业务需求, 笔者要为公司开发几款实用的浏览器插件,所以大致花了一天的时间,看完了谷歌浏览器插件开发文档,在这里特地总结一下经验, 并通过一个实际案例来复盘插件开发的流程和注意事项. 你将收获 ...
- 华为抓取错误日志在哪里_抓取android手机log的介绍
本篇文章只是本人的工作经验总结,如有错误,欢迎指正!未经许可,不得转载. 首选需要有debug版本的android手机哈,否则是没有root权限的~ 1.抓取AP log的命令: adb logcat ...
- 从零开始开发一个自动抓取教务系统课表等信息并动态显示的安卓课程表APP,原理分析及功能实现完美教程
前言 之前写过一篇JAVA使用HttpClient模拟登录正方教务系统,爬取学籍信息和课程表成绩等,超详细登录分析和代码注解的教程,在移植到移动平台时候,发现了如下问题: 抓取课表偶尔会不完全,出现全 ...
- Android抓取正方系统课程——实现自己的课程表
Android抓取正方系统课程--实现自己的课程表 上一篇博客讲解了如何使用http协议模拟登陆正方系统,今天继续实现如何抓取课程表并显示在Android界面上,效果如图: 由于偷懒,在界面上没下太多 ...
- 在Mac下使用Charles抓取Android 7.0以上的Https请求
文章目录 一.Charles 设置 1. 第一步 2. 第二步 3. 第三步 3. 第四步开启SSL代理功能 二.手机安装证书 三.APP 网络安全配置 四.另一种抓包方式 因为开发需求,需要抓取 ...
- 抓包工具Fidder详解(主要来抓取Android中app的请求)
$*********************************************************************************************$ 博主推荐 ...
- 制作bat脚本,抓取Android设备logcat
::bat制作抓取Android设备的logcat,并保存以时间命名的txt文件至设备目录 1 @ECHO off 2 adb wait-for-device 3 ECHO 正在连接设备 4 adb ...
- 开发一个基于 Android系统车载智能APP
很久之前就想做一个车载相关的app.需要实现如下功能: (1)每0.2秒更新一次当前车辆的最新速度值. (2)可控制性记录行驶里程. (3)不连接网络情况下获取当前车辆位置.如(北京市X区X路X号) ...
- Wireshark抓取Android数据包
用Wireshark来抓取Android应用中的数据包.有服务和客户端的源码. Wireshark Wireshark是非常流行的网络封包分析软件,功能十分强大.可以截取各种网络封包,显示网络封包的详 ...
最新文章
- 人工神经网络是如何实现存算一体的
- 如何在asp.net页面使用css和js
- SimpleRAR-攻防世界-Misc(图文详解),文件块和子块,图片的隐写二维码
- Qt Creator造型Modeling
- php获取当前整点时间_8.PHP的日期和时间
- ASP.NET Session详解
- SQL Server定期自动备份
- Android 获取CellId以及IMEI 获取基站id
- 企业资源计划软件 业务知识点汇编整理
- 破解keil 2k限制,注册码生成
- 【codevs1225】八数码难题,如何精确地搜索
- 第3章 FOR命令中的变量
- python threading thread_Python: 关于thread模块和threading模块的选择
- java经常用到的英文_Java中用到的英文单词,你知道多少?
- hustoj 服务器配置
- 抛不开我执的老罗,长不大的周伯通
- java awt addMouseListener 双击事件
- docker oxidized时区问题,时间显示不是北京时间问题的解决办法
- oracle闪回ddl,Oracle闪回详解
- Android中导航栏之自定义导航布局