这篇接着补。前面放的功能图多,实现讲得少,这次挑几条实际改过的调用链,把代码和处理顺序展开。
入口在 Agent。选好应用和环境后,可以分别配置机型、地区、定位、SIM、文件属性和容量信息。多环境、模块、代理和设备控制也在这里管理。下面的图来自手机实际界面,业务应用名称、设备标识、坐标和服务信息做了脱敏。Java 片段保留项目原代码;内核两处只摘关键分支,标为等价伪代码。

图1:实际的一键换机入口和配置项。选择应用、环境和机型后,按需启用对应项目;这里能看到文件属性、容量、内存等选项。
以型号为例,同一个应用既可以查 SystemProperties,也可以直接读 Build.MODEL。问题在于 Build 里已经初始化好的静态字段会保留旧值。所以我在应用启动流程里加了 updateBuild:先确定当前进程使用的环境,再把这一份属性同步到 Build。AppStart.updateBuild 中的这段负责厂商、品牌、型号和构建信息:
updateBuildByProp 和 updateBuildValue 的实现很短。前者通过 getString 取当前属性,后者用反射写入 Build 的静态字段。这一步更新的是当前进程中的对象;属性读取时已经需要选好该应用的环境。
deriveFingerprint 优先取 ro.build.fingerprint,非空就直接用;缺失时再按 brand/product/device:release/id/incremental:type/tags 拼接。Build.FINGERPRINT 只是构建信息中的一项。评论里提到的设备注册指纹范围更广,Android ID、电话信息、显示能力、传感器列表和文件属性还要接各自的读取入口。
这也是按应用保存整套配置的原因:应用再次启动时,要先选定这一份环境,再初始化与它有关的进程状态。只改配置文件而保留旧进程,Build、默认 Locale、TimeZone 等已经初始化过的对象不会主动重新走一遍启动流程。
这些读取入口通过 AOSP 中预留的钩子接到 ILTweaksBridge。Patcher 生成方法包装:检查 loader、创建 MethodParam、登记处理逻辑,然后决定走原方法还是回调。下面是 LTweaksImpl 中执行 before 的代码:
这里 hasResult() 的位置有实际含义:某个 before 设置了结果,后面的 before 就不再执行;外层包装也会检查 hasResult,决定是否直接返回。只改参数而不设置结果时,包装根据 isArgsModified 选择新参数调用原方法,取得结果后再执行 after。参数替换与提前返回是两种不同操作。
例如传感器注册,用 setArg 换掉监听器参数后,仍然让系统原注册函数执行。对于要直接给出结果的查询,则用 setResult 提前返回。这样具体功能只需要处理自己的参数和结果,调用顺序由包装层统一处理。
这部分基础数据是我拿真机实际采集后整理的。先看 SensorUpdater 里的加速度样本,六行分别是一组 x、y、z,单位为 m/s²。运行时围绕这些基础样本更新和过渡。
运行时保留 mCurrSet 和 mNextSet。MSG_UPDATE_IN_CURR 每次更新当前样本附近的值,然后按 200 ms 继续调度;到达 mNextMoveTime 后进入 MSG_UPDATE_TO_NEXT。切组时不是直接把三个坐标换成另一行,而是创建 3—5 秒的过渡,下一次切换时间安排在 10—15 秒之后。
move 使用 ValueAnimator,配 AccelerateDecelerateInterpolator。下面是其中三个分量的处理:加速度和方向根据 fraction 从起点过渡到终点;线性加速度在这一分支里单独取小幅随机值。
样本准备好后,还要送到应用注册的监听器。SystemSensorManager.registerListenerImpl 的钩子里用了两层 Map:先找原 listener,再按 Sensor 找包装对象。因为一个 listener 可以同时注册加速度和陀螺仪,两者需要分别保存。新注册走下面四行,param.setArg(0, myListener) 把原调用的第一个参数替换掉:
包装监听器收到 SensorEvent 后,根据 mSensor.getType() 选取 SensorUpdater 的对应数据。加速度还有 needMockShaking 文件开关:存在时取摇晃数据,否则取普通加速度数据。最后真正交付给应用的是这两行:
这两行复用了原 event,时间戳沿用收到的事件,只替换 values。SensorUpdater 的 200 ms 是后台数值更新周期,应用收到事件的节奏仍取决于回调链。注册之外,重复注册和注销也按这张对应表处理,否则应用拿原 listener 注销时,系统中实际登记的包装对象就可能遗留。
传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!
最后于 12小时前
被乐子编辑
,原因: