报告口径本页直接渲染本地报告真源;静态能力、动态观察、推断和线上未验证项不得互相替代。
Smart PDF Reader v1.2.5 保活、拉活与通知逆向报告#
竞品包名:com.smartpdf.viewer
APK versionName / versionCode:1.2.5 / 26
静态样本、真机观察日期:2026-08-20
结论口径:静态 APK 与本次测试机状态;服务端 FCM、远端配置和真实重启均未操作,不外推为全量线上策略。
1. 结论先行#
- Smart PDF 是本批样本中已真机确认常驻前台服务的一款:启动后
com.cell.document.nKhGkwcc 以 specialUse 类型运行,startForegroundCount=1,常驻通知 ID 为 1;从最近任务划掉后 10 秒,进程、FGS 与常驻通知仍存在。
- 它有两类本地召回:
- 高优先级 FCM 到达后:从 APK 内置 9 组模板随机选一组,发布本地通知;
- 本地定时路径:
AlarmManager → PibuBCOOqe → l82.d(...) → 本地通知,随机范围为上述 9 组加 1 组 AI 摘要文案。
- 实机已捕获一条真实普通提醒:
⏲️ 是時候完成了!(是时候完成了)/ 您的 PDF 轉換正在等待完成。 🔃(您的 PDF 转换正在等待完成),ID 8194。约 4 秒后它以同一 ID 更新到静默提醒渠道,证明“连续提醒”代码在当前机上实际走通。
- 所有普通提醒点击先进入
OutOpenActivity,取消连续提醒并记录 action,再转交 SplashActivity;静态未能把 notify_fcm_* / notify_timing_* 精确还原为最终工具页,不能写成“直接打开某功能”。
- 这不是 Force Stop 绕过:二次连续验证强停后 0、5、20 秒均为
stopped=true,进程、服务、活跃通知、闹钟和 Job 均未列出。前台服务只能解释“划掉任务后仍在”,不能解释“强停后自恢复”。
2. 样本与验证边界#
| 项目 |
值 |
| 基础 APK |
smart-pdf-reader-v1.2.5/apk/base.apk(94,483,219 bytes) |
| SHA-256 |
1d5c17b8840ce30f65606cf1e731ebd924beb4c54d1cc3d18c1de4ca60f4d01e |
| 运行时 minSdk / targetSdk |
32 / 36 |
| 静态工具 |
apkanalyzer、JADX 1.5.5 |
| 动态操作 |
已授权测试机的冷启动、退后台、任务划除、Force Stop 与 adb dumpsys;未清数据、未更改通知/文件权限、未发送 FCM |
本次复查时测试机的 POST_NOTIFICATIONS 已是 granted=true;这不是本轮修改的结果,因此能够观察到实际通知。文件访问权限仍未授权,未读取或写入任何用户文件。
3. 总体机制图(静态 + 动态)#
FCM 高优先级消息 本地计划时间
│ │
▼ ▼
wHByvi(FirebaseMessagingService) AlarmManager(ELAPSED_REALTIME_WAKEUP)
│ │
└── 随机内置模板 ────────────► PibuBCOOqe → l82.d(...)
│
▼
s11.u / s11.t → notify(8194)
│
4 秒连续静默更新 ───────┘
│
点击 / 划除分别取消连续提醒
▼
OutOpenActivity → SplashActivity
启动、开机/升级广播、Job 失败兜底 ─► nKhGkwcc 前台服务 → notify(1)
4. 普通通知:触发、频控、文案与点击#
4.1 两条普通提醒路径#
| 路径 |
静态事实 |
可以确认 |
不可外推 |
| FCM 高优先级 |
wHByvi 继承 FirebaseMessagingService。仅当 RemoteMessage 的 delivered/original priority 为 high 时,选本地 NotifyItem 并调用 s11.u(...) |
高优先级 FCM 可以作为“触发信号”,正文不必来自服务端 |
未发送真实 FCM,未知服务端何时推、面向谁推、是否所有消息都为高优先级 |
| 本地定时 |
rg8.a(...) 用请求码 18488 建立显式 PibuBCOOqe 广播;Receiver 调用 l82.d(...) 发通知后重排下一次 |
APK 有独立于 FCM 的本地计时通知路径 |
未等待未来闹钟实际触发,未证明当前线上配置的时间值 |
4.2 展示门槛与频控(静态事实)#
l82.d(...) 和 FCM 路径都会进入 zv2.a(...) 一类展示判断。其可核验条件如下:
| 条件 |
代码行为 |
边界 |
| 通知权限 |
NotificationManager.areNotificationsEnabled() / Android 13+ 权限校验 |
本机已授权;关闭后不应把代码路径误写为“通知一定展示” |
| 首装冷却 |
首次安装不足 300 秒时拦截(除非特定调用绕过) |
只确认代码条件 |
| 全局展示间隔 |
is_nation=true 的内置默认下为 3,600,000 ms(1 小时);该偏好为 false 时为 50 秒 |
这是本地偏好的默认/分支,不是线上承诺频率 |
| 时段 |
当对应开关启用时,仅 07:00–22:59 |
开关的线上/本地实际值未核验 |
| 设备状态 |
锁屏、横屏(受开关控制)或 App 在前台时拦截 |
真机本次退到后台、未锁屏且竖屏,满足展示环境 |
| 本地目标时刻 |
计划时间来自配置对象;缺失/无效时回退 10:00。使用 AlarmManager.set(ELAPSED_REALTIME_WAKEUP, ...) |
是可唤醒的非精确 Alarm;未见 setAndAllowWhileIdle / exact alarm,Doze 下可延后 |
4.3 内置正文模板(默认语言)#
FCM 和定时路径均从本地 NotifyItem 列表随机选取。下表 01–09 为两条路径共用的功能/文件话术;10 仅加入本地定时路径。英文后紧跟中文释义。
| ID |
标题(原文 / 中文) |
正文(原文 / 中文) |
CTA(原文 / 中文) |
| 01 |
📷 Ready to Scan Files! / 准备扫描文件! |
Scan, adjust, and save as PDF with ease. 👉 / 轻松扫描、调整并保存为 PDF。 |
Scan / 扫描 |
| 02 |
📂 Convert Files Instantly! / 即刻转换文件! |
One tap to turn any file into a PDF. 👉 / 一键把任意文件转为 PDF。 |
Convert / 转换 |
| 03 |
✏️ PDF Editing Available! / 可编辑 PDF! |
Quickly edit and update your PDFs. 👉 / 快速编辑和更新 PDF。 |
Edit / 编辑 |
| 04 |
📂 Library Just Refreshed / 文件库刚刚刷新 |
Your file list has been updated. 👉 / 您的文件列表已更新。 |
Check / 查看 |
| 05 |
🧾 New File Detected / 检测到新文件 |
Tap to explore your latest documents. 👉 / 点击查看最新文档。 |
View / 查看 |
| 06 |
🔃 Sync Your File List / 同步文件列表 |
Update to get the latest file view. 👉 / 更新以获取最新的文件视图。 |
Update / 更新 |
| 07 |
📌 Important File Waiting / 重要文件正在等待 |
There's a key document ready to open. 👉 / 有一份关键文档已可打开。 |
Check / 查看 |
| 08 |
🧪 Try Our Latest Tools! / 试试最新工具! |
New features just landed in your PDF app.👉 / PDF 应用刚加入新功能。 |
Try / 试用 |
| 09 |
⚠️ Update Recommended / 建议更新 |
Your current version is outdated.👉 / 当前版本已过时。 |
Update / 更新 |
| 10(仅定时) |
✨Your 1-min briefing is ready / 1 分钟摘要已准备好 |
Skip the 10-min read. AI has summarized the core points for you. / 跳过 10 分钟阅读,AI 已为您总结核心要点。 |
Click / 点击 |
这些文案存在于 APK,不代表文件库真的更新、发现了新文件、存在待处理转换,或用户版本一定过时;它们是留存召回话术,真实业务状态未做绑定证据。
4.4 通知构建与连续提醒#
| 项目 |
静态 / 真机证据 |
结论 |
| 普通提醒 ID |
NotificationManager.notify(8194, ...);真机已见 ID 8194 |
同一 ID 后发会更新前一条,不会无限堆叠 |
| 样式 |
自定义 small / middle / big RemoteViews,普通通知分组为 com.supper.pdf.normal |
并非系统默认文本样式 |
| 初次渠道 |
channel_id_remind(remind),importance 4,开灯/开振动、无 channel 声音 |
静态渠道配置与真机记录一致 |
| 连续渠道 |
channel_id_remind_silence(remind_silence),importance 4,关灯/关振动、无声音 |
本机约 4 秒后,ID 8194 已切到该静默渠道 |
| 重复节奏 |
初次通知后启动内存协程;非 Samsung 分支最多进行 3 次、每次间隔 4 秒的重复尝试,Samsung 分支为 1 次 |
它是进程内连续提醒,不是 AlarmManager 长期重发;进程结束/强停后不能依赖它继续执行 |
| 取消 |
点击 OutOpenActivity 或删除通知的 NotifyRepeatReceiver 均取消协程 |
“划除/点击停止连续提醒”有明确代码和删除 Intent |
| 真机正文 |
⏲️ 是時候完成了! / 您的 PDF 轉換正在等待完成。 🔃 |
已真实展示中文本地文案;由于未捕获调用栈,不把这一次展示唯一归因给 FCM 或计划闹钟 |
4.5 点击拉活 / 路由边界#
通知 ContentIntent
→ OutOpenActivity(读取 action,取消连续提醒,记录点击)
→ SplashActivity(携带 action;可能携带 filePath)
→ 后续由 Splash 初始化与混淆分发决定
| action 前缀 |
来源 |
已确认 |
未确认 |
notify_fcm_01 … notify_fcm_09 |
FCM 高优先级本地模板 |
可追溯到 FCM 选中模板编号 |
Splash 后最终工具页未静态还原 |
notify_timing_01 … notify_timing_10 |
本地定时模板 |
可追溯到本地随机模板编号 |
同上 |
resident_merge / resident_view / resident_extra / resident_convert |
常驻通知的 4 个 RemoteViews 操作 |
点击会经 OutOpenActivity 进入 Splash |
实际功能映射待点击真机验证 |
因此它是“通知点击启动应用并传入归因 action”,不是可确认的某功能页深链,也没有证明后台静默拉起可见页面。
5. 前台服务、开机和 Job 兜底#
5.1 常驻前台服务#
| 项目 |
静态事实 |
真机结果 |
| 服务 |
com.cell.document.nKhGkwcc,foregroundServiceType=specialUse |
已运行,isForeground=true、foregroundId=1、types=0x40000000 |
| 常驻通知 |
i85.b(...) 构建 channel_id_resident,ID 1,自定义 4 个入口(Merge / View / Extract / Convert) |
已见 `ONGOING_EVENT |
| 启动返回值 |
Android 34+ 返回 2(START_NOT_STICKY);低版本返回 1 |
表明系统杀进程后不应仅靠 sticky 自动重启;与“有 FGS”是两件事 |
| 任务划除 |
onTaskRemoved() 调用 fk7.a();服务本身仍在 |
最近任务移除后 10 秒,PID、FGS 和 ID 1 常驻通知均仍在 |
| 强停 |
无代码可绕过系统 Force Stop |
连续 0/5/20 秒验证均 stopped=true,无 PID、服务、活跃通知、闹钟或 Job |
**正确结论:**它在用户划掉任务后确有 FGS 持续运行证据;但不应把这写成“永久保活”或“强停可恢复”。
5.2 开机/升级与 Job#
| 机制 |
可核验证据 |
边界 |
| 开机/升级 Receiver |
TPJzFGN 接收 BOOT_COMPLETED、MY_PACKAGE_REPLACED,声明了 RECEIVE_BOOT_COMPLETED 权限 |
Receiver 会进入 fk7.a() 与通知相关逻辑,但未做真实重启;不可写成“已验证自启” |
| FGS 启动失败兜底 |
fk7.a() 先尝试 startForegroundService(nKhGkwcc);异常时以 Job ID 889、最短 5 秒/截止 7 秒、persisted、高优先级登记 BGupiXhKaP |
是失败兜底代码,不是已经动态证明的每次重启结果 |
| 计划 Job |
kHeUCCf 也使用 ID 889、persisted、高优先级,并按配置分钟数自行重排 |
同一 Job ID 的不同服务不是并行双保险,后一次登记会覆盖前一次;真机当前是 kHeUCCf,最早约 9 分钟后 |
| 本地通知 Alarm |
真机有 PibuBCOOqe 的 ELAPSED_REALTIME_WAKEUP,当时最早约 17 小时后,系统窗口 +1 小时 |
可唤醒设备执行 Receiver,但没有 idle 绕过/精准执行证据 |
| WorkManager / DataTransport |
真机另有 1 个混淆 WorkManager Job 与 Google DataTransport Job |
未反编译出与通知/FGS 的直接业务关系,不能混作保活结论 |
6. 真机观察摘要#
| 场景 |
观察到的状态 |
结论 |
| 冷启动 → 退后台 |
POST_NOTIFICATIONS: granted=true;普通 ID 8194、FGS ID 1 同时存在 |
这台测试机实际满足通知展示和 FGS 启动条件 |
| 普通提醒持续约 4 秒后 |
ID 8194 由 channel_id_remind 更新为 channel_id_remind_silence,正文仍在 |
连续静默提醒在当前环境实际发生 |
| 划掉最近任务 |
最近任务不再列出该包;PID 仍在,nKhGkwcc 仍为 foreground,ID 1 与 8194 仍在 |
任务划除不等于杀进程;这款的 FGS 确实撑住了运行态 |
| Force Stop,T+0 / T+5 / T+20 秒 |
均 stopped=true,无 PID、产品服务、活跃普通/常驻通知、活跃 Alarm 和 Job |
强停是硬边界;未见自恢复或绕过强停 |
7. 对我方的可借鉴与避坑#
- 将三件事分开设计与验收: FCM 触发、定时提醒、FGS 持续任务不能混称“保活”。每一条都要有授权、频控、点击路由、取消和 Force Stop 验收。
- 如果通知采用本地模板,必须绑定真实状态。 本样本中“文件已更新”“新文件已检测到”“转换等待完成”是内置召回话术,未看到与真实文件状态的绑定;我方不应在无证据时做这类暗示。
- FGS 只服务于可见且持续的用户任务。 该样本使用
specialUse 并以常驻通知呈现功能按钮;是否合规、是否能过审核和能否长期存活仍依设备/系统约束,不能照抄为通用后台方案。
- 点击不要只落在初始化页。 这里 action 在
OutOpenActivity → SplashActivity 中转;更稳妥的我方方案是对 action 做白名单,并最终落到可完成的具体任务,未知 action 回首页。
8. 未验证项#
- 未发送真实 FCM、未抓取 Firebase/远端配置网络请求;FCM 服务端受众、频次、消息 TTL 和真实优先级未知。
- 未真实重启设备、未测
MY_PACKAGE_REPLACED、Doze、OEM 省电限制或系统杀进程后的 Job/FGS 恢复。
- 未点击普通/常驻通知,因此
notify_fcm_*、notify_timing_*、resident_* 的最终工具落点未确认。
- 未验证用户关闭通知、关闭单独渠道、拒绝文件权限时 FGS/定时提醒的完整降级表现。
- 未评价 OCR、编辑、AI、广告或订阅能力;本报告仅覆盖保活、拉活与通知证据。