安卓源码去掉混淆


前言

在编译安卓源码packages/services/Telecomm时,bp文件导入了其他静态链接库static_libs a,开机后报错,
Java AbstractMethodError,位置指定:Telecomm下java文件在执行静态链接库 a下的java文件方法。
通过参考链接与本地分析:混淆配置开启后,解压编译后的Telecomm.apk文件,发现a静态链接库下的部分文件丢失,
在去掉bp文件的混淆配置后正常。

修改前

   // Build the Telecom service.
android_app {
    name: "Telecom",
	......
    optimize: {
        proguard_flags_files: ["proguard.flags"],
    },
}

修改后

// Build the Telecom service.
android_app {
    name: "Telecom",
	......
    optimize: {
        enabled: false,
    },
}

顺便简单了解一下安卓源码中的static_libs和混淆配置。

一、static_libs 和 libs

在 Android.mk 或者 Android.bp 文件中,static_libs 和 libs 都是用来指定静态链接库或共享链接库的。它们的主要区别在于:

  • static_libs: static_libs 是指定目标模块的静态链接库,静态链接库会被链接到目标模块中,使得目标模块包含这个静态库的所有代码和数据。它适用于模块依赖的代码在编译期就已经确定,并且需要在编译时打包到目标模块中的情况。
  • libs: libs 是指定目标模块的共享链接库,共享链接库会在运行时动态加载,可以在运行时替换或者更新。它适用于需要在运行时动态加载依赖库的情况。

因此,当需要在编译期将一个静态链接库打包到目标模块中时,可以使用 static_libs;而当需要在运行时动态加载依赖库时,可以使用 libs。


二、安卓源码混淆配置

2.1 什么是混淆编译

ProGuard是一个免费的java类文件压缩,优化,混淆器.它探测并删除没有使用的类,字段,方法和属性.它删除没有用的说明并使用字节码得到最大优化.它使用无意义的名字来重命名类,字段和方法.
ProGuard的使用是为了:

1.创建紧凑的代码文档是为了更快的网络传输,快速装载和更小的内存占用.
2.创建的程序和程序库很难使用反向工程.
3.所以它能删除来自源文件中的没有调用的代码
4.充分利用java6的快速加载的优点来提前检测和返回java6中存在的类文件.

ProGuard支持哪些种类的优化?
除了在压缩操作删除的无用类,字段和方法外,ProGuard也能在字节码级提供性能优化,内部方法有:

1 常量表达式求值
2 删除不必要的字段存取
3 删除不必要的方法调用
4 删除不必要的分支
5 删除不必要的比较和instanceof验证
6 删除未使用的代码
7 删除只写字段
8 删除未使用的方法参数
9 像push/pop简化一样的各种各样的peephole优化
10 在可能的情况下为类添加static和final修饰符
11 在可能的情况下为方法添加private, static和final修饰符
12 在可能的情况下使get/set方法成为内联的
13 当接口只有一个实现类的时候,就取代它
14 选择性的删除日志代码

实际的优化效果是依赖于你的代码和执行代码的虚拟机的。简单的虚拟机比有复杂JIT编译器的高级虚拟机更有效。无论如何,你的字节码会变得更小。

2.2 启动android中的混淆功能

在需要混淆的工程目录下(package/apps/下的工程)添加proguard.flags文件,该文件即为网络传说中的proguard.cfg,只是命名不一样而已,然后再Android.mk中添加如下两句:
LOCAL_PROGUARD_ENABLED := full
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
上面的full 也可以是custom,如果不写这句,那还得添加如下一句:
TARGET_BUILD_VARIANT := user或者TARGET_BUILD_VARIANT := userdebug
这样后在工程目录下执行mm便可以看到在out目录下生成了形如proguard.classes.jar的东东,这就说明已在编译中启动proguard
但反编译一看,并未出现网络云说的abcd替代符号,其实代码并未真正混淆:
android在编译时默认关闭了混淆选项,有去研究build/core目录的同志会发现这里也有个proguard.flags文件,其实在proguard的过程中,编译器会调用包括本地目录下和系统定义了的多个proguard.flags文件,而在这个文件中混淆的选项被禁止了,故而编译出来的apk仍未混淆。因此将如下句子注释掉便可实现真正的混淆编译:
Don’t obfuscate. We only need dead code striping.-dontobfuscate(将该句加个#号注释掉)

full:使用编译系统默认的配置:压缩但不混淆和优化,默认的混淆配置文件是build/core/proguard.flags
custom:和full一样,但不包括aapt生成的resource相关的混淆配置。
nosystem:不使用系统的默认配置,但使用aapt生成的resource相关的混淆配置,其他混淆由模块自己负责。
disabled:关闭混淆
obfuscation:和full一样,并且开启混淆
optimization:和full一样,并且开启优化

不设置时,如果是app,默认为full,如果是library,则默认为disabled。
编译userdebug版本时,编译脚本会把app的obfuscation改成full,即不混淆;所以userdebug版本的app是不混淆的。想了解更多信息,可以自行阅读project_src/build/core/下的java.mk,package_internel.mk,java_library.mk,proguard.flags,proguard_base_keeps.flags等文件。

Android Studio:
项目目录下的build.gradle文件中minifyEnabled设置为true为开启,false为关闭;proguardFiles用来指定混淆配置文件。使用Build菜单下的Generate Signed APK进行打包即可。记得在Build Type:选项下选择release,否则只打包不会混淆。

2.3 如何书写proguard.flags文件

参数解释:

-include {filename} 从给定的文件中读取配置参数
-basedirectory {directoryname} 指定基础目录为以后相对的档案名称
-injars {class_path} 指定要处理的应用程序jar,war,ear和目录
-outjars {class_path} 指定处理完后要输出的jar,war,ear和目录的名称
-libraryjars {classpath} 指定要处理的应用程序jar,war,ear和目录所需要的程序库文件
-dontskipnonpubliclibraryclasses 指定不去忽略非公共的库类。
-dontskipnonpubliclibraryclassmembers 指定不去忽略包可见的库类的成员。

保留选项

-keep {Modifier} {class_specification} 保护指定的类文件和类的成员
-keepclassmembers {modifier} {class_specification} 保护指定类的成员,如果此类受到保护他们会保护的更好
-keepclasseswithmembers {class_specification} 保护指定的类和类的成员,但条件是所有指定的类和类成员是要存在。
-keepnames {class_specification} 保护指定的类和类的成员的名称(如果他们不会压缩步骤中删除)
-keepclassmembernames {class_specification} 保护指定的类的成员的名称(如果他们不会压缩步骤中删除)
-keepclasseswithmembernames {class_specification} 保护指定的类和类的成员的名称,如果所有指定的类成员出席(在压缩步骤之后)
-printseeds {filename} 列出类和类的成员-keep选项的清单,标准输出到给定的文件

压缩

-dontshrink 不压缩输入的类文件
-printusage {filename}
-whyareyoukeeping {class_specification}

优化

-dontoptimize 不优化输入的类文件
-assumenosideeffects {class_specification} 优化时假设指定的方法,没有任何副作用
-allowaccessmodification 优化时允许访问并修改有修饰符的类和类的成员

混淆

-dontobfuscate 不混淆输入的类文件
-printmapping {filename}
-applymapping {filename} 重用映射增加混淆
-obfuscationdictionary {filename} 使用给定文件中的关键字作为要混淆方法的名称
-overloadaggressively 混淆时应用侵入式重载
-useuniqueclassmembernames 确定统一的混淆类的成员名称来增加混淆
-flattenpackagehierarchy {package_name} 重新包装所有重命名的包并放在给定的单一包中
-repackageclass {package_name} 重新包装所有重命名的类文件中放在给定的单一包中
-dontusemixedcaseclassnames 混淆时不会产生形形色色的类名
-keepattributes {attribute_name,…} 保护给定的可选属性,例如LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and InnerClasses.
-renamesourcefileattribute {string} 设置源文件中给定的字符串常量

2.4 示例(Telecomm)

proguard.flags

-verbose
-keep @com.android.internal.annotations.VisibleForTesting class *
-keep public class * extends android.widget.ListView {
    public *;
}
-keep class com.android.server.telecom.TelecomSystem {
  *;
}
-keep class android.telecom.Log {
  *;
}

# Keep classes, annotations and members used by Lifecycle. Remove this once aapt2 is enabled
-keepattributes *Annotation*

-keep class * implements android.arch.lifecycle.LifecycleObserver {
}

-keep class * implements android.arch.lifecycle.GeneratedAdapter {
    <init>(...);
}

-keepclassmembers class ** {
    @android.arch.lifecycle.OnLifecycleEvent *;
}

参考链接:

Java AbstractMethodError 原因分析
java.lang.abstractMethodError遇到的情况及解决方法

android源码使用proguard混淆编译及错误总结
Android代码混淆

相关推荐

  1. 去掉混淆

    2024-05-14 13:36:06       11 阅读
  2. 环境下编译多module app

    2024-05-14 13:36:06       19 阅读
  3. flutter 项目开启混淆防止渗透

    2024-05-14 13:36:06       36 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-05-14 13:36:06       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-05-14 13:36:06       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-05-14 13:36:06       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-05-14 13:36:06       18 阅读

热门阅读

  1. Figma host相关设置

    2024-05-14 13:36:06       9 阅读
  2. 使用feign调用媒资服务完成静态页面的上传

    2024-05-14 13:36:06       10 阅读
  3. vue2 el-tree树形下拉框

    2024-05-14 13:36:06       9 阅读
  4. RateLimiter 限流算法使用

    2024-05-14 13:36:06       8 阅读
  5. Python学习-Numpy-2

    2024-05-14 13:36:06       9 阅读