当前位置:操作系统 > 安卓/Android >>

Android 4.0 中由ProGuard引发的一场血案

案件还原:
        修改Android 4.0源码中的Setting,添加一项功能之后,在eng模式下编译,一切正常,遂提交代码到服务器。第二天,传来噩耗,Setting上新添加的功能无法使用,一点击则报错。

案件分析:
        上传代码之前,已经在本地编译测试过,咋会有错呢??!!管它三七二十一,操起adb logcat抓取log进行分析。不看不知道,一看吓一跳,log中显示的错误信息竟然是ClassNotFound,也就是找不到相应的类,难道我上传的时候遗漏了吗(有这种可能)?马上查看提交记录,逐个检查提交的文件,全部提交了啊!咋会出现ClassNotFound呢?这时候咋办呢?冷静下来分析后可以知道,本地测试一般是在eng模式下编译的,而这次报错的是服务器在usr模式下编译处出来的。难道eng编译和usr编译出来的结果不一致??!!

案件进一步分析:
        在本地选择usr编译模式,编译代码进行测试,果然出现了与服务器一样的错误,即ClassNotFound。

        1.既然eng模式编译的代码能够正常运行,证明代码逻辑以及功能都是OK的。

        2.usr编译出来出现ClassNotFound的问题,证明usr和eng编译模式不同导致编译结果差异。

        3.比较eng模式和usr模式编译出来的Settings.apk,发现大小竟然不一致,用apktool反解后对比发现,usr模式下编译的Settings.apk中的确少了一个类(后文用lostClass.java代替)。

案件调查:
假设一:
        难道是编译过程中没有将lostClass.java编译进去?

验证一:
        查看编译过程中是否有对lostClass.java进行编译。

1.第一种查看方法。
        打开源码中Settings文件夹下的Android.mk文件我们可以发现以下代码:

        LOCAL_SRC_FILES := $(call all-java-files-under, src)


        我们在这句代码后添加以下内容:

        $(warning SevenTest LOCAL_SRC_FILES : $(LOCAL_SRC_FILES))


        保存后终端中执行编译,我们可以看到src文件信息输出在终端上。复制到文件中查找lostClass.java,可以找到,因此可以推翻4的假设。

2.第二种查看方法。
        查看APK的编译打包流程,如图1:

 \


        根据以上流程,我们可以找到每一步对应的mk文件,这里我们找到AndroidSouceCode/build/core/definitons.mk中注释以下代码:


[plain]
define compile-java 
$(hide) rm -f $@ 
$(hide) rm -rf $(PRIVATE_CLASS_INTERMEDIATES_DIR) 
$(hide) mkdir -p $(dir $@) 
$(hide) mkdir -p $(PRIVATE_CLASS_INTERMEDIATES_DIR) 
$(call unzip-jar-files,$(PRIVATE_STATIC_JAVA_LIBRARIES),$(PRIVATE_CLASS_INTERMEDIATES_DIR)) 
$(call dump-words-to-file,$(PRIVATE_JAVA_SOURCES),$(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list) 
$(hide) if [ -d "$(PRIVATE_SOURCE_INTERMEDIATES_DIR)" ]; then \ 
        find $(PRIVATE_SOURCE_INTERMEDIATES_DIR) -name '*.java' >> $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list; \ 
fi 
$(hide) tr ' ' '\n' < $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list \ 
    | sort -u > $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list-uniq 
$(hide) $(1) -encoding UTF-8 \ 
    $(strip $(PRIVATE_JAVAC_DEBUG_FLAGS)) \ 
    $(if $(findstring true,$(LOCAL_WARNINGS_ENABLE)),$(xlint_unchecked),) \ 
    $(2) \ 
    $(addprefix -classpath ,$(strip \ 
        $(call normalize-path-list,$(PRIVATE_ALL_JAVA_LIBRARIES)))) \ 
    $(if $(findstring true,$(LOCAL_WARNINGS_ENABLE)),$(xlint_unchecked),) \ 
    -extdirs "" -d $(PRIVATE_CLASS_INTERMEDIATES_DIR) \ 
    $(PRIVATE_JAVACFLAGS) \ 
    \@$(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list-uniq \ 
    || ( rm -rf $(PRIVATE_CLASS_INTERMEDIATES_DIR) ; exit 41 ) 
#Seven注释 
#$(hide) rm -f $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list 
#$(hide) rm -f $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list-uniq 
$(hide) jar $(if $(strip $(PRIVATE_JAR_MANIFEST)),-cfm,-cf) \ 
    $@ $(PRIVATE_JAR_MANIFEST) -C $(PRIVATE_CLASS_INTERMEDIATES_DIR) . 
endef 
 
define transform-java-to-classes.jar 
@echo "target Java: $(PRIVATE_MODULE) ($(PRIVATE_CLASS_INTERMEDIATES_DIR))" 
$(call compile-java,$(TARGET_JAVAC),$(PRIVATE_BOOTCLASSPATH)) 
#Seven注释 
#$(hide) rm -rf $(PRIVATE_CLASS_INTERMEDIATES_DIR) 
endef 

define compile-java
$(hide) rm -f $@
$(hide) rm -rf $(PRIVATE_CLASS_INTERMEDIATES_DIR)
$(hide) mkdir -p $(dir $@)
$(hide) mkdir -p $(PRIVATE_CLASS_INTERMEDIATES_DIR)
$(call unzip-jar-files,$(PRIVATE_STATIC_JAVA_LIBRARIES),$(PRIVATE_CLASS_INTERMEDIATES_DIR))
$(call dump-words-to-file,$(PRIVATE_JAVA_SOURCES),$(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list)
$(hide) if [ -d "$(PRIVATE_SOURCE_INTERMEDIATES_DIR)" ]; then \
     find $(PRIVATE_SOURCE_INTERMEDIATES_DIR) -name '*.java' >> $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list; \
fi
$(hide) tr ' ' '\n' < $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list \
    | sort -u > $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list-uniq
$(hide) $(1) -encoding UTF-8 \
    $(strip $(PRIVATE_JAVAC_DEBUG_FLAGS)) \
    $(if $(findstring true,$(LOCAL_WARNINGS_ENABLE)),$(xlint_unchecked),) \
    $(2) \
    $(addprefix -classpath ,$(strip \
        $(call normalize-path-list,$(PRIVATE_ALL_JAVA_LIBRARIES)))) \
    $(if $(findstring true,$(LOCAL_WARNINGS_ENABLE)),$(xlint_unchecked),) \
    -extdirs "" -d $(PRIVATE_CLASS_INTERMEDIATES_DIR) \
    $(PRIVATE_JAVACFLAGS) \
    \@$(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list-uniq \
    || ( rm -rf $(PRIVATE_CLASS_INTERMEDIATES_DIR) ; exit 41 )
#Seven注释
#$(hide) rm -f $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list
#$(hide) rm -f $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list-uniq
$(hide) jar $(if $(strip $(PRIVATE_JAR_MANIFEST)),-cfm,-cf) \
    $@ $(PRIVATE_JAR_MANIFEST) -C $(PRIVATE_CLASS_INTERMEDIATES_DIR) .
endef

define transform-java-to-classes.jar
@echo "target Java: $(PRIVATE_MODULE) ($(PRIVATE_CLASS_INTERMEDIATES_DIR))"
$(call compile-java,$(TARGET_JAVAC),$(PRIVATE_BOOTCLASSPATH))
#Seven注释
#$(hide) rm -rf $(PRIVATE_CLASS_INTERMEDIATES_DIR)
endef
        这样我们在终端中执行编译命令后,可以在路径:AndroidSourceCode/out/target/common/obj/APPS/Settings_intermediates/classes找到以下两个文件:

        java-source-list和java-source-list-uniq,在其中搜索lostClass.java即可以找到。


        通过以上查看可以知道,lostClass.java在是被编译了的,最后为了验证,我们可以通过jd-gui这个工具来查看AndroidSourceCode/out/target/common/obj/APPS/Settings_intermediates/classes.jar

补充:移动开发 , Android ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,