为了对APK体积进行优化,引入了微信资源混淆打包工具。版本上线不久便收到很多线上crash报告,大部分是华为手机。经分析是混淆了华为推送的资源文件导致的crash,本篇是分析过程。
问题出现
APM监测到线上集中爆发华为手机crash,日志如下:
Caused by:
android.content.res.Resources$NotFoundException:String resource ID #0x0
android.content.res.Resources.getText(Resources.java:410)
android.content.res.HwResources.getText(HwResources.java:465)
android.content.res.Resources.getString(Resources.java:504)
com.huawei.hms.c.h.e(ResourceLoaderUtil.java:73)
com.huawei.hms.update.e.p.a(SilentUpdateWizard.java:126)
com.huawei.hms.update.e.p.a(SilentUpdateWizard.java:90)
com.huawei.hms.activity.BridgeActivity.b(BridgeActivity.java:169)
com.huawei.hms.activity.BridgeActivity.onCreate(BridgeActivity.java:57)
android.app.Activity.performCreate(Activity.java:7372)
android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1218)
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3150)
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3305)
android.app.ActivityThread.-wrap12(Unknown Source:0)
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1894)
android.os.Handler.dispatchMessage(Handler.java:108)
从关键日志Resources$NotFoundException
、com.huawei.hms
初步推测是混淆了资源文件导致华为推送出了问题。实际hms是指华为移动服务(Huawei Mobile Services,缩写HMS)
问题定位
很多问题的分析即使追踪到源码,也要锲而不舍的追踪下去,才能真正了解问题所以从而解决问题。从华为推送的HMSSdkBase_2.5.3.305.jar包中找到com.huawei.hms.c.h和com.huawei.hms.update.e.p两个类。
com.huawei.hms.c.h.java这个类为普通的工具类,根据名称获取资源ID
package com.huawei.hms.c;
import android.content.Context;
public class h {
private static Context a;
private static String b;
public static Context a() {
return a;
}
public static void a(Context var0) {
a = var0;
b = var0.getPackageName();
}
public static int a(String var0) {
return a.getResources().getIdentifier(var0, "layout", b);
}
public static int b(String var0) {
return a.getResources().getIdentifier(var0, "id", b);
}
public static int c(String var0) {
return a.getResources().getIdentifier(var0, "drawable", b);
}
public static int d(String var0) {
return a.getResources().getIdentifier(var0, "string", b);
}
public static String e(String var0) {
String var1 = a.getResources().getString(d(var0));
var1 = var1 == null ? "" : var1;
return var1;
}
public static String a(String var0, Object... var1) {
String var2 = a.getResources().getString(d(var0), var1);
var2 = var2 == null ? "" : var2;
return var2;
}
}
com.huawei.hms.update.e.p.java这个类的a函数是关键,在此函数内获取了一些资源,通过getIdentifier的方式。一旦资源的名称被改变(混淆)将会找不到该资源而报错。
字符串名称 | 字符串值 |
---|---|
hms_install | “安装” |
hms_cancel | “取消” |
hms_update_message_new | “该服务需安装以下应用的最新版本才能使用:\n\n·%1$s” |
private void a(Activity var1) {
Intent var2 = new Intent("com.huawei.appmarket.intent.action.ThirdUpdateAction");
var2.setPackage("com.huawei.appmarket");
Intent var3 = var1.getIntent();
if (var3 != null) {
r var4 = (r)var3.getSerializableExtra("intent.extra.update.info");
if (var4 != null) {
this.h = var4.b();
JSONArray var5 = new JSONArray();
JSONObject var6 = new JSONObject();
try {
var6.put("pkgName", var4.b());
var6.put("versioncode", var4.c());
} catch (JSONException var9) {
com.huawei.hms.support.log.a.d("SilentUpdateWizard", "create hmsJsonObject fail" + var9.getMessage());
return;
}
var5.put(var6);
var2.putExtra("params", var5.toString());
var2.putExtra("isHmsOrApkUpgrade", var4.a());
var2.putExtra("buttonDlgY", com.huawei.hms.c.h.e("hms_install"));
var2.putExtra("buttonDlgN", com.huawei.hms.c.h.e("hms_cancel"));
var2.putExtra("upgradeDlgContent", com.huawei.hms.c.h.a("hms_update_message_new", new Object[]{"%P"}));
try {
var1.startActivityForResult(var2, 2000);
} catch (ActivityNotFoundException var8) {
com.huawei.hms.support.log.a.d("SilentUpdateWizard", "ActivityNotFoundException");
}
}
}
}
问题复现
从字符串的值可以得知,场景应该是:华为移动服务版本太低,在华为推送初始化时系统进行提示升级。费了一些时间在华为mate8上进行了问题复现。
- 卸载华为移动服务即可回退到出厂时的版本
- 集成华为推送SDK后启动App即会提示华为移动服务的升级
效果 | ![]() |
机型 | 华为mate8、EMUI5.0.1、Android7.0 |
华为移动服务版本 | 2.3.3.323 |
华为推送版本 | 2.5.3.305 |
问题修复
既然已经明确华为推送Sdk中的资源不可以混淆,那么将其全部加入微信资源混淆打包工具的白名单即可。
白名单配置如下:
whiteList = [//所有使用getIdentifier访问的资源都需要加入白名单
//HUAWEI Push
"R.string.hms_*",
"R.string.connect_server_fail_prompt_toast",
"R.string.getting_message_fail_prompt_toast",
"R.string.no_available_network_prompt_toast",
"R.string.third_app_*",
"R.string.upsdk_*",
"R.style.upsdkDlDialog",
"R.style.AppTheme",
"R.style.AppBaseTheme",
"R.dimen.upsdk_dialog_*",
"R.color.upsdk_*",
"R.layout.upsdk_*",
"R.drawable.upsdk_*",
"R.drawable.hms_*",
"R.layout.hms_*",
"R.id.hms_*",
]
问题反思
- AndResGuard的WhiteList.md其实已经给出了华为推送的白名单,但是不全面。引入该打包工具时应该再次全面的检测是否对App有影响,避免不必要的损失。
- 分析问题应该要深入源码,结合一些库原理进行全面分析,结合关键日志快速定位问题,无法复现的bug都是复现条件未找到。