前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android/Java 混淆中使用-assumenosideeffects删除日志代码遇到的问题

Android/Java 混淆中使用-assumenosideeffects删除日志代码遇到的问题

作者头像
sickworm
发布2019-02-27 17:04:06
4.1K2
发布2019-02-27 17:04:06
举报
文章被收录于专栏:sickwormsickworm

今天发包给客户,发现混淆后的库时序有点问题。再三调试,发现锁失效了。wait()没有任何阻塞就跳过了。

ok,90%情况就是在哪里触发了notify/notifyAll咯。但找了很久,notify确实没有被调用。我就纳闷了。

最后我把我的库反编译出来看,发现我的锁的wait()语句被删了!源代码:EsLock.java

public void lock() { synchronized (this) { setLocked(true); try { Log.e("wtf", "" + 1); wait(); Log.e("wtf", "" + 2); } catch (Exception e) { e.printStackTrace(); LogUtil.w(TAG, e.getLocalizedMessage()); } setLocked(false); } }

12345678910111213141516

public void lock(){    synchronized (this) {        setLocked(true);        try {            Log.e("wtf", "" + 1);            wait();            Log.e("wtf", "" + 2);        } catch (Exception e) {            e.printStackTrace();            LogUtil.w(TAG, e.getLocalizedMessage());        }        setLocked(false);    }}

混淆后代码:

http://sickworm.com/wp-content/uploads/2016/11/tmp6d1fa6b6.png
http://sickworm.com/wp-content/uploads/2016/11/tmp6d1fa6b6.png
https://i2.wp.com/sickworm.com/wp-content/uploads/2016/11/tmp6d1fa6b6.png?w=600
https://i2.wp.com/sickworm.com/wp-content/uploads/2016/11/tmp6d1fa6b6.png?w=600

我翻了一下我CI上的库记录,发现前两个月的库是没问题的,看来是中间某段时间修改混淆脚本出了问题。

一番定位,找到了元凶:

-assumenosideeffects class com.excelsecu.driver.util.LogUtil { public *; }

1234

-assumenosideeffects class com.excelsecu.driver.util.LogUtil {    public *;}

我使用了assumenosideeffects,并尝试将所有com.excelsecu.driver.util.LogUtil的调用删除。官方有关assumenosideeffects的介绍:http://proguard.sourceforge.net/manual/usage.html

assumenosideeffects需要你自己保证你所选择的类的方法没有边界效应(简单来说就是删掉也不会影响程序运行),然后proguard会帮你删掉这些方法的调用。典型例子就是打包时删掉日志输出。官方例子:http://proguard.sourceforge.net/manual/examples.html#logging

需要注意的是:他只会删除这个方法的调用,但是你如何构建你的日志内容(表现形式为StringBuilder)仍然会保留下来。你无法通过这个方法完全删掉你日志的痕迹,以用于保护代码。为什么这样做?因为如果有个傻子图方便直接在log参数里面调用了有边界效应的方法(也就是流程中必不可缺的方法),那你删掉就要出事了。

回到正题:官方给出的示例其实是没有这样的用法,只有填写特定方法的用法。但是这个标签也是支持通配符的,官方对其定义是“-assumenosideeffects class_specification”,class_specification描述了你可以如何描述这个class中的方法。和-keepclass是一样的。这个用法我是在http://stackoverflow.com/questions/6408574/how-to-use-assumenosideeffects-class-android-util-log-in-my-app最下面看到的。

我用回官方的写法:

-assumenosideeffects class com.excelsecu.driver.util.LogUtil { public static void v(...); public static void i(...); public static void w(...); public static void d(...); public static void e(...); }

12345678

-assumenosideeffects class com.excelsecu.driver.util.LogUtil {    public static void v(...);    public static void i(...);    public static void w(...);    public static void d(...);    public static void e(...);}

问题没有出现。

所以问题就在于:使用了通配符“public *”之后,proguard把LogUtil之外的方法删了,例如我的EsLock.java中的wait()的调用。(因为这个调用没有返回值,proguard认为是没有边界效应的)

综合来说,我觉得依然是个bug,因为无论如何它不应该把LogUtil之外的方法也删掉。我在https://sourceforge.net/p/proguard/bugs/629/上提交了bug(语法错误好多。。),暂时没有回复。


提交bug后第二天就收到了回复。项目人员给出了相关解释,大概结论就是:这不是bug,proguard是设计成这个样子的。

项目人员提供的相关内容:

http://proguard.sourceforge.net/中:Troubleshooting > “Note: the configuration specifies that none of the methods of class ‘…’ have any side effects”。

简单解释一下: proguard的混淆是需要往上寻找父类的方法的,所以通配符*也会包括父类的方法。而所有的类都继承与Object,自然Object.wait()和Object.notify()也会在检测列表中。所以当你使用了统配符的时候,这两个方法也是会被影响的。

那么问题来了,为什么不是LogUtil.wait()这样的调用才会被删除,而是EsLock.wait()的方法也会被删除?我猜测proguard采用的是一种展开的方式去处理的,当你配置了LogUtil的所有方法时,他会同时产生一个Object的所有方法的配置。这样处理起来会高效很多。

class specifications是一个统一的定义,-keep等配置也会用到。所以可能很难兼顾所有配置项的使用场景。

官方文档也明确说明了,最好别在assumenosideeffects中使用通配符,这样会影响到wait和notify。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年11月30日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档