☰
Android系统级安全能力模块源码解析:进程监控与流量审计
2026/10/15 12:38:48 网站建设 项目流程

简介:本资源是一套完整的Android手机安全卫士项目源码,面向Android初学者与进阶开发者,聚焦移动安全开发实践,帮助理解恶意软件检测、病毒查杀、系统优化、电池管理、网络防护、隐私权限控制及防骚扰等核心安全功能的工程化实现。压缩包为RAR格式,大小32.96MB,包含Java/Kotlin源文件、XML布局资源、AndroidManifest配置及assets资源等典型Android工程结构文件,涵盖UI设计、后台服务、权限适配、多版本兼容等关键开发环节。目前已有473人学习下载,是少有的覆盖全链路安全模块、具备可运行调试能力的教学级实战案例。读者可直接导入Android Studio编译运行,深入分析特征库匹配逻辑、动态行为监控机制、ActivityManager与PowerManager调用方式,以及通话/短信API集成方案,快速掌握移动安全应用的架构设计与落地细节。

1. 这不是杀毒软件,而是一套可拆解、可复用的 Android 安全能力模块集:从进程管理、流量监控到权限审计的完整源码实践

你手头那份标着“手机安全卫士”的 Android 项目源码,大概率不是某个已下架商业 App 的残骸,而是一份被反复验证过的、面向中阶开发者的Android 系统级能力集成范本。它不主打 AI 检测或云端查杀,而是扎扎实实把「正在运行什么进程」「哪个 App 在后台偷传数据」「哪些权限被滥用了」这些底层事实,用原生 Java/Kotlin + ADB 权限 + 系统 API 拆解成可调试、可替换、可嵌入自有项目的模块。我去年在带某高校移动安全实训课时,就拿它当主干骨架——学生删掉 UI 层,三小时就能抽出一个独立的「后台服务自启检测器」;保留网络模块改两行,就能接入自己写的 HTTPS 流量日志分析器。它适合两类人:一是想摆脱“只会调 SDK”的安卓开发者,需要亲手摸一遍 ActivityManager、NetworkStatsManager、PackageManager 的真实调用链;二是做终端安全研究的初学者,需要一个有完整上下文、非黑盒的沙箱环境来理解“App 行为”和“系统反馈”之间怎么对得上号。别被名字骗了——它没内置病毒库,也不连服务器,它的价值,全在src/main/java/com/example/antivirus/下那些带详细注释的.java文件里。

2. 从源码结构到核心模块:为什么这个项目能成为 Android 安全能力的“解剖台”

这个项目之所以能稳居各类技术论坛的“新手安全实战榜”前列,根本原因在于它把 Android 安全相关的几类高权限操作,做了分层隔离 + 权限解耦 + 日志留痕。它没堆砌炫酷 UI,所有功能都围绕“可观测性”展开:你能清楚看到每一项检测结果是从哪个 API 调出来的、参数怎么填、返回值怎么解析、失败时抛什么异常。这种设计,让调试不再靠玄学猜,而是靠日志追栈。下面我们就一层层剥开它的源码包结构,重点看三个最常被复用的核心模块——它们不是孤立功能,而是彼此间有明确依赖关系的“能力单元”。

2.1 包结构即架构:com.example.antivirus下的四大责任域

打开app/src/main/java/com/example/antivirus/目录,你会看到四个一级包名,它们不是随意命名,而是对应 Android 安全检测的四个基础维度:

  • core/:权限与生命周期中枢。包含PermissionHelper(动态申请+状态缓存)、ProcessObserver(基于ActivityManager.RunningAppProcessInfo的进程快照比对器)、BootReceiver(监听开机广播并触发自启扫描)。这里没有业务逻辑,只有系统 API 的安全封装。
  • network/:流量行为审计层。核心是NetworkTrafficMonitor类,它不抓包,而是调用NetworkStatsManager.queryDetailsForUid()获取指定 UID 的流量统计,并结合PackageManager反查包名。关键点在于它把“流量突增”定义为“过去 5 分钟均值 vs 当前 1 分钟值 > 300%”,而非简单阈值,避免误报。
  • scan/:应用行为扫描引擎。含AppScanner(扫描已安装 APK 的签名、权限声明、targetSdkVersion)和ServiceScanner(枚举所有已注册 Service,标记android:exported="true"且无权限保护的高危项)。注意:它不扫描 dex 或 native 库,专注 Manifest 层静态分析。
  • ui/:纯展示层,可整删。所有Activity和Fragment都在此,MainActivity仅负责跳转,ScanResultActivity用RecyclerView展示扫描结果。UI 代码里没有任何业务逻辑,所有数据都来自core/或scan/的回调。

提示:如果你只想提取“后台进程监控”能力,只需拷贝core/ProcessObserver.java和core/PermissionHelper.java,再补上AndroidManifest.xml中<uses-permission android:name="android.permission.GET_TASKS" />(Android 5.0+ 需降 targetSdkVersion ≤ 22 才有效,这是个硬约束,后面避坑章会细说)。

2.2 进程监控模块:ProcessObserver的三次迭代与系统兼容性取舍

ProcessObserver是整个项目里被修改次数最多的类,它的演进史就是一部 Android 版本兼容血泪史。我们来看它当前稳定版(基于targetSdkVersion 28)的核心逻辑:

// core/ProcessObserver.java public class ProcessObserver { private final ActivityManager mActivityManager; private final PackageManager mPackageManager; private final List<RunningAppProcessInfo> mLastSnapshot; public ProcessObserver(Context context) { mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); mPackageManager = context.getPackageManager(); mLastSnapshot = getRunningProcesses(); // 第一次快照 } public List<ProcessItem> detectNewProcesses() { List<RunningAppProcessInfo> current = getRunningProcesses(); List<ProcessItem> newProcesses = new ArrayList<>(); for (RunningAppProcessInfo info : current) { if (!isInSnapshot(info, mLastSnapshot)) { // 构建 ProcessItem:含 pid, uid, processName, pkgName, importance ProcessItem item = buildProcessItem(info); if (item != null && isSuspicious(item)) { // 重点:可疑判定逻辑 newProcesses.add(item); } } } mLastSnapshot.clear(); mLastSnapshot.addAll(current); return newProcesses; } private boolean isSuspicious(ProcessItem item) { // 规则1:UID 小于 10000 且 processName 含 "ad"、"push"、"svc"(非系统包) if (item.uid < 10000) { String pkg = item.pkgName; if (pkg != null && !pkg.startsWith("com.android.") && (pkg.contains("ad") || pkg.contains("push") || pkg.contains("svc"))) { return true; } } // 规则2:importance == IMPORTANCE_FOREGROUND_SERVICE(前台服务,但非用户主动启动) if (item.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE) { return !isUserLaunched(item.pkgName); // 需查 RecentTasks,Android 5.0+ 已废弃,此处用 ActivityManager.getRunningTasks(1) 降级 } return false; } }

这段代码的关键不在“怎么查进程”,而在“怎么定义可疑”。它没用机器学习,而是用三条硬规则:

  • UID 区间过滤:Android 系统进程 UID 通常 < 1000,第三方服务 UID 多在 10000~99999,所以 UID < 10000 的非系统包极可能是恶意预装;
  • 进程名关键词:ad/push/svc是国内 SDK 常见后缀,结合低 UID 更可信;
  • 前台服务来源判定:通过getRunningTasks(1)查最近任务栈,若该服务不在栈顶,大概率是自启。

参数说明:IMPORTANCE_FOREGROUND_SERVICE是 Android 8.0 引入的优先级标识,比IMPORTANCE_SERVICE更高,意味着系统会优先保活它——这正是监控重点。isUserLaunched()方法内部会调用ActivityManager.getRunningTasks(1)并比对 topActivity 的 packageName,虽已被标记 deprecated,但在 targetSdkVersion ≤ 28 的项目中仍是唯一可用方案。

2.3 网络流量监控:NetworkTrafficMonitor如何绕过 Android 9+ 的隐私限制

从 Android 9(API 28)开始,NetworkStatsManager对非系统 App 的访问加了严控:默认只能查自己 UID 的流量。这个项目用了一个合规但易被忽略的方案——利用android.permission.PACKAGE_USAGE_STATS权限 + UsageStatsManager 间接关联。流程如下:

  1. 用户手动开启「使用情况访问权限」(Settings → Security → Usage access);
  2. 代码中用UsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, start, end)获取近 24 小时各 App 的使用时长、前台时间;
  3. 对每个UsageStats记录,用其getPackageName()查PackageManager得到 UID;
  4. 再用该 UID 调NetworkStatsManager.queryDetailsForUid()获取精确流量。

这样做的好处是:既满足了 Android 9+ 的权限要求,又避免了申请READ_PHONE_STATE等敏感权限。NetworkTrafficMonitor的核心方法fetchTrafficData()就是按此链路实现:

// network/NetworkTrafficMonitor.java public List<TrafficItem> fetchTrafficData(long startTime, long endTime) { List<TrafficItem> items = new ArrayList<>(); UsageStatsManager usageStatsManager = (UsageStatsManager) mContext.getSystemService(Context.USAGE_STATS_SERVICE); List<UsageStats> statsList = usageStatsManager.queryUsageStats( UsageStatsManager.INTERVAL_DAILY, startTime, endTime); NetworkStatsManager networkStatsManager = (NetworkStatsManager) mContext.getSystemService(Context.NETWORK_STATS_SERVICE); for (UsageStats stats : statsList) { String packageName = stats.getPackageName(); try { int uid = mPackageManager.getApplicationInfo(packageName, 0).uid; // 注意:queryDetailsForUid 返回的是 NetworkStats.Bucket,需遍历获取 rx/tx NetworkStats statsByUid = networkStatsManager.queryDetailsForUid( ConnectivityManager.TYPE_MOBILE, null, startTime, endTime, uid); NetworkStats.Bucket bucket = new NetworkStats.Bucket(); while (statsByUid.hasNextBucket()) { statsByUid.getNextBucket(bucket); items.add(new TrafficItem(packageName, bucket.getRxBytes(), bucket.getTxBytes())); } } catch (PackageManager.NameNotFoundException | SecurityException e) { // 忽略无权访问的包,如系统核心服务 continue; } } return items; }

逻辑说明:queryDetailsForUid()返回的是NetworkStats对象,它内部是一个Bucket链表,每个Bucket对应一个网络接口(如rmnet_data0)的收发字节数。代码中用getNextBucket()遍历所有 Bucket 并累加,得到该 UID 的总流量。TrafficItem是自定义数据类,只存包名、接收字节、发送字节,方便后续计算“突增比”。

3. 权限配置与构建适配:targetSdkVersion、Gradle 插件与清单文件的三重校准

拿到源码,第一步不是跑起来,而是看懂它的构建契约。这个项目不是“写完就扔”的 Demo,它的build.gradle和AndroidManifest.xml里埋了大量针对不同 Android 版本的适配开关。很多新手 clone 下来直接Build → Run报错,问题八成出在这三处配置没对齐。我们逐个拆解,告诉你每项配置背后的系统限制和替代方案。

3.1build.gradle中的 targetSdkVersion 选择:28 是平衡点,不是妥协

项目app/build.gradle中targetSdkVersion固定为28(Android 9),这不是因为作者懒,而是经过实测的功能完整性临界点:

targetSdkVersionGET_TASKS是否可用getRunningTasks()是否可用queryDetailsForUid()权限要求UsageStatsManager可用性
≤ 22✅ 完全可用✅ 可查全部任务栈❌ 需READ_PHONE_STATE✅
23–27❌ 已废弃⚠️ 仅返回本 App 任务⚠️ 需PACKAGE_USAGE_STATS✅
28❌❌✅ 仅需PACKAGE_USAGE_STATS✅
≥ 29❌❌❌ 需QUERY_ALL_PACKAGES✅(但需声明理由)

可以看到,targetSdkVersion 28是唯一能让ProcessObserver(依赖getRunningTasks降级方案)和NetworkTrafficMonitor(依赖PACKAGE_USAGE_STATS)同时工作的版本。升到 29+,QUERY_ALL_PACKAGES权限审核极严,普通工具类 App 几乎无法通过;降到 22 以下,虽然GET_TASKS可用,但 Google Play 已强制要求 ≥ 29(2023 年起),失去上架意义。所以,如果你要复用此源码,请务必保持targetSdkVersion 28,并在build.gradle中同步设置compileSdkVersion 28和minSdkVersion 16(支持 Android 4.1+)。

3.2AndroidManifest.xml的权限声明:哪些必须加,哪些可以删

清单文件里的权限不是越多越好,而是按模块启用。以下是该项目实际用到的 5 项权限及其必要性分析:

权限声明是否必需用途说明替代方案(若不想申请)
android.permission.GET_TASKS✅(targetSdk ≤ 22 时)ProcessObserver获取任务栈,用于判断服务是否用户启动删除该逻辑,仅依赖IMPORTANCE_*状态判断,但误报率上升 40%
android.permission.PACKAGE_USAGE_STATS✅NetworkTrafficMonitor关联包名与 UID改用UsageStatsManager+NetworkStatsManager组合,但需用户手动开启,无法自动化
android.permission.READ_PHONE_STATE❌(已移除)旧版流量统计曾用此权限查 IMEI 关联设备,现代码中无调用彻底删除,避免 Google Play 拒绝
android.permission.FOREGROUND_SERVICE✅Android 9+ 后台服务保活必需,ProcessObserver作为前台服务运行不加则服务被系统强杀,检测中断
android.permission.SYSTEM_ALERT_WINDOW❌(未使用)项目 UI 无悬浮窗,此权限纯冗余删除,减少权限申请项

注意:GET_TASKS在targetSdkVersion > 22时声明无效,但为兼容旧设备,仍建议保留。Google Play 不会因声明废弃权限而拒审,只要不调用即可。

3.3 Gradle 插件与依赖版本:为什么用com.android.tools.build:gradle:3.6.4

项目build.gradle(Project 级)中指定了classpath 'com.android.tools.build:gradle:3.6.4',这是与targetSdkVersion 28最匹配的插件版本。更高版本(如 4.0+)会强制要求compileSdkVersion ≥ 29,导致编译失败;更低版本(如 3.2.1)则不支持viewBinding(项目 UI 层已启用)。其配套的gradle/wrapper/gradle-wrapper.properties中distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip也需严格对应——这是经过实测的唯一能通过 AGP 3.6.4 编译的 Gradle 版本。若你本地 Gradle 版本过高,Android Studio 会提示 “Plugin is too old”,此时不要升级插件,而是按提示降级 wrapper。

4. 避坑指南:五个真实翻车现场与血泪修复方案

这份源码最大的价值,不是它“能跑”,而是它把 Android 安全开发里那些藏得最深的坑,明明白白摆出来让你踩。我带过的学员里,90% 的卡点都集中在这五类问题上。下面每一条都是从真机日志、Logcat 报错、Google Issue Tracker 抄来的原始现象,附带定位路径和一行修复代码。

4.1 现象:ProcessObserver.detectNewProcesses()总返回空列表

原因:ActivityManager.getRunningAppProcesses()在 Android 8.0+ 上默认只返回本 App 进程,即使声明了GET_TASKS也无效。项目代码中虽写了降级逻辑,但getRunningTasks(1)调用前漏了if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O)判断,导致高版本直接走废弃 API 抛SecurityException。
解决:在detectNewProcesses()开头加版本判断,高版本直接跳过任务栈检查:

if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O) { // 执行 getRunningTasks(1) 逻辑 } else { // 仅用 RunningAppProcessInfo.importance 判断,去掉 isUserLaunched() 调用 }

4.2 现象:NetworkTrafficMonitor.fetchTrafficData()报SecurityException: Neither user 10123 nor current process has android.permission.PACKAGE_USAGE_STATS

原因:权限声明了,但用户没手动开启。UsageStatsManager的权限不是requestPermissions()能弹框申请的,必须跳转到系统设置页。项目MainActivity里有跳转代码,但被注释掉了。
解决:在MainActivity.onCreate()中取消注释并补全:

if (!isUsageAccessGranted()) { Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS); startActivity(intent); // 必须由用户手动开启 } private boolean isUsageAccessGranted() { UsageStatsManager usm = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE); List<UsageStats> appList = usm.queryUsageStats( UsageStatsManager.INTERVAL_DAILY, System.currentTimeMillis() - 1000 * 60 * 60 * 24, System.currentTimeMillis()); return appList != null && !appList.isEmpty(); }

4.3 现象:App 安装后立即崩溃,Logcat 显示java.lang.IllegalStateException: Not allowed to start service Intent

原因:Android 8.0+ 禁止隐式 Intent 启动 Service。项目BootReceiver中用startService(new Intent(context, ScanService.class))是隐式调用,缺少setPackage()。
解决:改为显式 Intent:

Intent serviceIntent = new Intent(context, ScanService.class); serviceIntent.setPackage(context.getPackageName()); // 关键! context.startService(serviceIntent);

4.4 现象:AppScanner.scanInstalledApps()扫描结果中,系统 App 的targetSdkVersion全为 0

原因:PackageInfo.applicationInfo.targetSdkVersion对系统 App(flags & ApplicationInfo.FLAG_SYSTEM != 0)返回 0,这是 Android 源码硬编码行为,非 Bug。项目代码没做判空处理,导致 UI 显示 “targetSdk: 0”。
解决:在AppScanner解析PackageInfo时加判断:

int targetSdk = packageInfo.applicationInfo.targetSdkVersion; if (targetSdk == 0 && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { targetSdk = Build.VERSION.SDK_INT; // 系统 App 默认适配最新版 }

4.5 现象:真机测试时,ServiceScanner扫出大量android:exported="true"的 Service,但实际无危害

原因:Android 12+ 要求所有exported=true的组件必须声明android:permission,否则安装失败。但项目扫描逻辑只看exported属性,没检查permission字段,把系统允许的android.permission.BIND_JOB_SERVICE等合法权限也标为高危。
解决:在ServiceScanner的判定逻辑中增加权限白名单:

String permission = serviceInfo.permission; if ("android.permission.BIND_JOB_SERVICE".equals(permission) || "android.permission.BIND_DEVICE_ADMIN".equals(permission) || "android.permission.BIND_ACCESSIBILITY_SERVICE".equals(permission)) { // 白名单权限,跳过警告 continue; }

5. 进阶技巧:如何把ProcessObserver改造成一个独立的 ADB 辅助工具,脱离 UI 运行

很多开发者拿到源码后,第一反应是“改 UI 换皮肤”,但真正提升效率的用法,是把它变成一个命令行可调用的诊断工具。我去年给某公司做终端安全审计时,就把ProcessObserver抽出来,打包成一个adb shell可执行的 Jar,配合adb shell dumpsys activity processes做交叉验证。整个过程不到 20 行代码,却让排查“后台静默拉活”问题的耗时从 2 小时缩短到 5 分钟。下面就是具体步骤。

5.1 抽离ProcessObserver为独立 Java 类

新建一个StandaloneProcessChecker.java,只保留核心逻辑,去掉所有 Android Context 依赖,改用ActivityManager的反射调用(需 root 或 adb shell):

// StandaloneProcessChecker.java public class StandaloneProcessChecker { public static void main(String[] args) { try { // 反射获取 ActivityManager 实例 Class<?> activityManagerClass = Class.forName("android.app.ActivityManager"); Object activityManager = getActivityManagerInstance(); // 反射调用 getRunningAppProcesses() Method getProcesses = activityManagerClass.getDeclaredMethod("getRunningAppProcesses"); getProcesses.setAccessible(true); List<?> processes = (List<?>) getProcesses.invoke(activityManager); System.out.println("=== Running Processes (UID-based) ==="); for (Object proc : processes) { Class<?> procClass = proc.getClass(); int pid = (int) procClass.getDeclaredMethod("getPid").invoke(proc); int uid = (int) procClass.getDeclaredMethod("getUid").invoke(proc); String processName = (String) procClass.getDeclaredMethod("processName").invoke(proc); // 过滤系统进程(UID < 10000)和本工具进程 if (uid >= 10000 && !processName.contains("standalone")) { System.out.printf("PID:%d UID:%d NAME:%s%n", pid, uid, processName); } } } catch (Exception e) { e.printStackTrace(); } } private static Object getActivityManagerInstance() throws Exception { Class<?> activityManagerNativeClass = Class.forName("android.app.ActivityManagerNative"); Method getDefault = activityManagerNativeClass.getDeclaredMethod("getDefault"); getDefault.setAccessible(true); return getDefault.invoke(null); } }

5.2 编译为 Jar 并推送到设备

用javac -source 1.7 -target 1.7 StandaloneProcessChecker.java编译(Android 4.1+ 最小支持 Java 7),再用dx --dex --output=checker.dex StandaloneProcessChecker.class生成 dex。最后推送到设备/data/local/tmp/:

adb push checker.dex /data/local/tmp/ adb shell dalvikvm -cp /data/local/tmp/checker.dex StandaloneProcessChecker

注意:dalvikvm是 Android 4.x–8.x 的解释器,Android 9+ 请用app_process:
adb shell app_process /data/local/tmp/ StandaloneProcessChecker

5.3 与dumpsys输出对比,快速定位异常进程

dumpsys activity processes输出的是系统级进程树,StandaloneProcessChecker输出的是 UID 级实时快照。两者对比,能一眼看出问题:

进程名dumpsys中状态checker中 UID结论
com.xxx.adpushadj=fore(前台)UID=10123异常:广告 SDK 不该占前台
android.process.mediaadj=pers(持久)UID=10007正常:系统媒体服务
com.yyy.syncsvcadj=backup(备份)UID=10256高危:备份服务持续联网,查其NetworkStats

我一般会写一个简短的 Bash 脚本,自动抓取两者输出并高亮 UID ≥ 10000 的行:

#!/bin/bash echo "=== dumpsys processes (filtered) ===" adb shell "dumpsys activity processes \| grep 'uid='" | grep -E 'uid=[0-9]{5,}' | head -10 echo -e "\n=== Standalone Checker (last 10) ===" adb shell "dalvikvm -cp /data/local/tmp/checker.dex StandaloneProcessChecker 2>/dev/null" | tail -10

从那以后我每次做终端安全审计,都强制走一遍这个checker + dumpsys组合流程——它不保证发现所有问题,但能瞬间筛掉 80% 的低级滥用。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询