真机打包后的包,在 vivo 某台手机上频繁出现卡死无响应。
经过多次实验后,发现每次卡死前都会出现一条固定日志(在 Android 上表现为 ANR,应用失去响应)。
nativeBatteryEvent(stat = xxx
这条日志是“非充分但必要条件”:出现它不一定会卡死,但发生卡死时一定会出现它。
仔细看了这段代码后,发现这里的 printf 存在未定义行为:
struct FBatteryReceiver: Java::Lang::FObject
{
static constexpr FAnsiStringView ClassName = "com/epicgames/unreal/BatteryReceiver";
static void JNICALL dispatchEvent(JNIEnv * jni, jclass clazz, jint status, jint level, jint temperature)
{
FPlatformMisc::LowLevelOutputDebugStringf(TEXT("nativeBatteryEvent(stat = %i, lvl = %i %, temp = %3.2f \u00B0C)"), status, level, float(temperature)/10.f);
ReceiversLock.Lock();
const bool bWasInLowPowerMode = CurrentBatteryState.Level <= GAndroidLowPowerBatteryThreshold;
FAndroidMisc::FBatteryState state;
这里在 %i % 后面试图打印一个百分号,但正确写法应该是 %%。因此这里构造了一个错误的格式化字符串,可能导致 printf 在运行时出现异常行为(例如读到错误内存,甚至卡死)。
修复这个格式化字符串后,真机上的卡死问题消失。
PS: 截至目前,UE 最新主线仍未修复这个问题。