-
深入解析:Android热修复技术选择和原理
2020-09-11 15:04:29热修复就是通过下发补丁包,让已安装的客户端动态更新,用户不用重新安装APP,就能够修复软件缺陷。 热修复技术对比 1.公司角度 大致可以分为阿里系和腾讯系和其他,如下: 阿里系 Dexposed 开源,实时修复 AndFix ...背景
想要成为一名优秀的Android开发,你需要一份完备的 知识体系,在这里,让我们一起成长为自己所想的那样~。
热修复就是通过下发补丁包,让已安装的客户端动态更新,用户不用重新安装APP,就能够修复软件缺陷。
热修复技术对比
1.公司角度
大致可以分为阿里系和腾讯系和其他,如下:
- 阿里系
Dexposed 开源,实时修复
AndFix 开源,实时生效
HotFix 阿里百川,未开源,免费、实时修复
Sophix 未开源,商业收费,实时生效/冷启动修复
HotFix是AndFix的优化版本,Sophix是HotFix的优化版本。目前阿里系主推是Sophix。 - 腾讯系
Qzone超级补丁 QQ空间,未开源,冷启动修复
QFix 手Q团队,开源,冷启动修复
Tinker 微信团队,开源,冷启动修复。提供分发管理,基础版免费 - 其他
Robust 美团, 开源,实时修复
Nuwa 大众点评,开源,冷启动修复
Amigo 饿了么,开源,冷启动修复
RocooFix 百度金融,开源,冷启动修复
Aceso 美丽说蘑菇街,开源,实时修复
2.技术角度
1.代码修复的角度
2.代码修复,资源修复,so修复这三个角度
3.已开源的热修复框架数据对比
框架名称和github地址 star数量 最后一次更新 版本 Dexposed 4.3k 5 years ago 0.1.8 AndFix 6.8k 4 years ago 0.5.0 QFix 8 3 years ago 无 Nuwa 2.9k 5 years ago 1.0.0 Tinker 15.2k 29 days ago 1.9.14.7 Robust 3.7k 4 months ago 0.4.99 Aceso 791 3 years ago 0.0.3 Amigo 1.3k 3 years ago 0.6.* RicooFix 1.6k 4 years ago 无 可以看到,近期还在更新的有Tinker和Robust,其他的都是至少三年之前的更新。
如何选择热修复框架
三个方面进行考虑
1.项目需求
方法级别修复,资源修复,so库的修复
对平台兼容性要求和成功率要求
有需求对分发进行控制,对监控数据进行统计,补丁包进行管理
是否付费
2.学习,使用成本
学习成本
代码侵入性
调试维护成本
3.技术保障,稳定性
比如GitHub Star,大公司技术保障,专人维护
热度高,社区活跃
小结
从这三个方面考虑,最后筛选出三个比较优秀的热修复库,Sophix,Tinker,Robust
如果考虑付费,Sophix和Tinker付费版(云服务),我支持Sophix,性能消耗低,支持即时生效,对代码无侵入,免费阈值的支持更好。
如果不考虑付费,只需要支持方法级别的Bug修复,不支持资源以及so库,推荐使用Robust,否则使用Tinker免费版。
当然如果公司实力够牛逼,可以考虑自研,灵活性以及可控性最强。
代码、资源、so库修复
AndroidManifest出现Bug是无法修复的,因为它是由系统进行解析的,系统会直接获取安装包里唯一的AndroidMainfest.xml文件,在解析过程不会访问补丁包信息。
代码修复:任何的热修复方案,想要改变代码逻辑,都需要在补丁包里包含一个新逻辑的dex文件。
资源修复:有些资源,比如桌面图标,通知栏图标以及RemoteView之类的资源,是由系统直接解析安装包里的资源得到的,因此对于这类资源,任何热修复方案都无法进行资源替换和修复。
so库修复:so库的修复思路应该是最明确的。在Android系统中,所有的so库都是由System.load进行加载的,因此只要找到办法在加载的时候优先加载补丁包的so库,而不是加载原有安装包的so库,就能够进行完整的底层代码替换了。
代码修复
代码修复主要有三大主要方案,阿里系的底层替换和腾讯系的类加载方案以及美团的javaHook方案(Instant Run原理)。
-
底层替换方案限制颇多,但是时效性最好,加载轻快,立即见效。
传统的底层替换方案(Dexposed,AndFix),依赖直接修改虚拟机方法实体的具体字段实现的。不同厂商/版本对ArtMethod结构体的结构修改带来的问题。每个Java方法在art中都对应着一个ArtMethod,ArtMethod记录了这个Java方法的所有信息,包括所属类,访问权限,代码执行地址等等。
实现一种不修改底层具体结构的替换方式,解决兼容性问题,代码量大大减少。native层面替换,把ArtMethod方法作为整体进行替换。
-
类加载方案时效性差,需要重新类启动才能见效,但修复范围广,限制少。
类加载方案的原理是在App重新启动后让Classloader去加载新的类。
QQ空间方案会入侵打包流程,并且为hack添加一些无用的信息,不优雅。
QFix方案需要获取底层虚拟机的函数,稳定性不够,无法新增public函数
Tinker方案是完整的全量的dex文件加载,将补丁合成的方案做到了极致,从dex的方法和指令维度进行全量合成,对于dex内容的比较粒度过细,实现较为复杂,性能消耗比较严重,时空转换性价比不高。
dex比较的最佳粒度,应该是类的维度,采用全量合成dex的技术,这个技术方案是从手机淘宝插件化框架Atlas汲取的。直接利用Android原有的类查找与合成机制,快速合成新的的全量dex文件。这样既不需要处理合成时的方法数超过原有方法数的情况,也不会对dex的结构进行破坏性重构。
我们重新编排了包中dex文件的顺序。这样虚拟机在查找类的时候,会优先找到classes.dex中的类,然后才是classes2.dex,classes3.dex,也可以看作是dex文件级别的类插桩方案。这个方式十分巧妙,它对旧包与补丁包中的classes.dex顺序进行了打破和重组,最终使系统可以自然的识别到这个顺序,以实现类覆盖的目的,大大减少合成补丁的开销。
Sophix使用了两者的结合,自动选择,小修改,在底层替换方案限制范围内的,直接采用底层替换热修复,可以做到及时生效。其他采用类加载替换方案。
-
Robust的JavaHook方案的原理与Instant Run的代码插桩原理一致,优点是实时生效,不需要重新启动,高兼容性(Robust只是在正常的使用DexClassLoader),高稳定性,修复成功率高达99%。支持方法级别的修复,包括静态方法。支持增加方法和类。支持ProGuard的混淆,内联优化等操作。
缺点是代码是侵入式的,会在原有的类中加入相关代码,so库和资源的替换暂时不支持。会增大apk的体积,平均一个函数会比原来增加17.47个字节,10万个函数会增加1.67M。
Sophix方案
热部署(及时生效)
在native层面替换,把ArtMethod方法作为整体进行替换,实时生效,但同时也会带来诸多限制:
访问权限的问题
- 方法调用时的权限检查
- 同名包下的权限问题(设置新类的ClassLoader为原来类就可以了,通过反射进行设置)
- 反射调用非静态方法产生的问题
及时生效带来的限制
以下两种情况是不适用的:
- 引起了原有的类中发生结构变化的修改(字段,方法增加减少),改成以冷启动支持
- 修复了的非静态方法会被反射调用,改成以冷启动方式支持
编译期和语言特性的影响
1. 内部类编译
-
静态内部类/非静态内部类的区别
-
内部类和外部类互相访问
外/内部类为了访问内/外部类私有的域/方法,编译器会自动为内部类生成access$数字编号相关方法,JVM规范,好像是提供了一个静态方法
-
热部署解决方案
一个外部类如果有内部类,把所有的method/field的私有访问权限改成protected或public或者默认访问权限。
同时把内部类所有的method/field的私有访问权限改成protected或public或者默认访问权限。
2. 匿名内部类编译
-
匿名内部类编译命名规则(access$**)
-
热部署解决方案
应该极力避免插入一个新的匿名内部类。当然如果匿名内部类是插入到外部类的末尾,那么是允许的。
3. 有趣的域编译
-
静态field,非静态field
-
静态field初始化,静态代码块(不支持
<clinit>
方法的热部署,只能冷启动生效)静态代码块和静态域初始化在clinit中的先后关系就是两者出现在源码中的先后关系
以下三种情况都会尝试去加载一个类:
- 创建一个类的对象(new-instance指令)
- 调用类的静态方法(invoke-static指令)
- 获取类的静态域的值(sget指令)
-
非静态field初始化,非静态代码块
-
热部署解决方案
clinit只能冷启动,init无影响
4. final static预编译规则
final static修饰的基本类型或String常量类型,没有被编译到clinit方法中
-
final static域编译规则
final static修饰的原始类型和String类型域(非引用类型),并不会被编译在clinit方法中,而是在初始化执行initSFields方法时得到了初始化赋值。
final static修饰引用类型,初始化仍在clinit方法中
-
final static域优化原理
final static引用类型没有得到优化,只是基本数据类型和String类型域(非引用类型)
-
热部署解决方案
修改 final static 基本类型或者 String 类型域(非引用类型域),由于在编译期间引用到基本类型的地方被立即数替换,引用到 String 类型(非引用类型)的地方被常量池索引 ID 替换,所以在热部署模式下,最终所有引用到该 final static 域的方法都会被替换。实际上此时仍然可以执行热部署万案。
修改 final static 引用类型域,是不允许的,因为这个 field 的初始化会被编译到 clinit 万法中,所以此时没法走热部署 。
5. 有趣的方法编译
-
应用混淆方法编译
项目如果应用了混淆方法编译,可能导致方法内联和裁剪,最后可能导致method的新增或减少。
-
方法内联
以下几种可能导致方法被内联掉:
- 方法没有被其他任何地方引用
- 方法足够简单,比如一个方法的实现就只有一行代码
- 方法只被一个地方引用
可能导致只能走冷启动方案
-
方法裁剪
可能导致只能走冷启动方案
如果让该参数不被裁剪,不让编译器在优化的时候认为引用了一个无用的参数就好了,这里介绍一种最有效的方法:
public static void test(Context context){ if(Boolean.FALSE.booleanValue()){ context.getApplicationContext(); } Log.d("BaseBug","test") }
这里不能使用基本类型,必须使用包装类Boolean,因为如果使用基本数据类型if语句可能也会被优化掉。
-
热部署解决方案
混淆配置文件加上-dontoptimize项就不会去做方法内联和裁剪,proguard-android-optimize.txt 或者 proguard-android.txt,两者的区别就是后者应用了 -dontoptimize 这一项配置而前者没有应用。
混淆库给热部署带来的影响主要在optimization阶段
optimzation step: -dontoptimize(热补丁模式下)
preverification step: -dontpreverify
混淆库对反射的处理(proguard.jar),shrinking阶段,obfuscation阶段
6. switch case语句编译
packed-switch,sparse-switch指令
可能导致资源替换不全
热部署解决方案:反编译->资源ID->替换->回编译
7. 泛型编译
泛型擦除,类型擦除与多态的冲突和解决,泛型类型转换
热部署解决方案
如果由
B extends A 变成了 B extends A<Number>
,那么就可能会新增对应的桥接方法 ,此时新增了方法,只能走冷 部署,如果要避免,那就避免类似上面的那种修复。 泛型的系统注解
8. Lambda表达式编译
Lambda表达式可能导致方法的新增或减少
-
Lambda表达式的编译规则
函数式接口具有两个主要特征:**它是一个接口,这个接口具有唯一的抽象方法;我们将同时满足这两个特性的接口称为函数式接口。**比如java.lang.Runnable和java.util.Comparator,函数式接口和匿名内部类的区别如下:
- 关键字this,匿名类的this关键字指向匿名内部类,而Lambda表达式的this关键字指向包围Lambda表达式的类。
- 编译方式,Java编译器将Lambda表达式编译成类的私有方法,使用Java7的invokeddynnamic字节码指令来动态绑定这个方法。Java编译器将匿名内部类编译成外部类$数字编号的新类。
编译器间自动生成私有静态的
lambda$main$**(*)
方法,这个方法的实现其实就是Lambda表达式里面的逻辑。invokedynamic指令执行Lambda表达式
比较与匿名内部类的区别,发现并没有在磁盘上生成外部类$数字编号的新类
invokedynamic指令执行时实际上回去调用java/lang/invoke/LambdaMetafactory的metafactory静态方法。**这个静态方法实际上会在运行时生成一个函数式接口的具体类。**然后具体类会调用Test的私有静态
lambda$main$**(*)
方法。我们可以通过添加- Djdk.internal . lambda .dumpProxyClasses 这个虚拟机运行参数,那么运行时会将生成的新类的 .class 内窑输出到一个文件中。
Sun/Oracle Hotspot VM和Android虚拟机解释Lambda表达式的异同点
上面的方式是Sun/Oracle Hotspot VM解释.class文件中lambda表达式的方式,**Android虚拟机首先通过javac把源代码编译成.class,然后再通过dx工具优化成适合移动设备的dex字节码文件。**Android中如果要使用Java8的语言特性,需要使用新的Jack工具类来替换掉就的工具类编译。细节见书籍。
很明显可以看到.dex字节码文件和.class字节码文件对Lambda表达式处理的异同点:
共同点:编译期间都会为外部类合成一个static辅助方法,该方法内部逻辑实现Lambda表达式。
不同点:
-
.class字节码通过invoke-dynamic指令执行Lambda表达式。而.dex字节码中执行Lambda表达式跟普通方法调用没有任何区别。
-
.class字节码中运行时生成新类,.dex字节码中编译期间生成新类。
-
热部署解决方案
打补丁是通过反编译为smail然后跟新APK跟基线APK进行差异对比,得到最后的补丁包。
新增一Lambda表达式,会导致外部类新增一个辅助方法,所以此时不支持走热部署方案。如果Lambda表达式中访问非静态field/method,就会持有外部类的引用。
增加或减少一个Lambda表达式会导致类方法比较错乱,所以会导致热部署失败。
修改一个Lambda表达式,可能导致新增field,所以此时也导致热部署失败。
9. 访问权限检查对热替换的影响
-
类加载阶段父类/实现接口访问权限检查
一个类的加载过程,必须经历resolve,link,init三个阶段,父类或实现接口权限控制检查主要发生在link阶段。
-
类校验阶段访问权限检查
10.
<clinit>
方法由于补丁热部署的特殊性,不允许类结构变更以及不允许变更
<clinit>
方法,所以补丁工具如果发现了以上几种限制情况,只能走冷启动。可能有时候在源码层上来看并没有新增或减少method和 field,但是实际上由于要满足 Java 各种语法特性的需求,所以编译器会在编译期间自动合成一些method 和 field时,最后就有可能触发了这几个限制情况。小结
重点讲解了影响热替换热修复的一些重要的编译器问题。但是热修复还有个比较大的问题,由于是在运行期发生了变动,如果我们修改了某个方法的逻辑,就会导致它在修复前后的逻辑不一致,这就会引发一些诡异的错误。**因此热替换方式的热修复只适用于修复一些简单的BUG,如果要做一些功能方面的更新,不建议采用。**热部署修复方案的根本原理是基于native层方法的替换,所以当类结构变化时,如新增减少类method/field在热部署模式下会受到限制,修复了的非静态方法会被反射调用也会受到限制。
冷启动代码修复
现有的一些冷启动实现方案
Tinker QQ空间 原理 提供dex差量包,整体替换dex的方案。差量的方式给出patch.dex,然后将patch.dex与应用的class.dex合并成一个完整的dex,完整的dex加载得到dexFile对象作为参数构建一个Element对象然后整体替换掉旧的dex Element数组。 为了解决Dalvik下的unexpected dex problem异常而采用插桩的方式,单独放一个帮助类在独立的dex中让其他类调用,阻止了类被打上CLASS_ISPREVERIFIED标志从而规避问题的出现。最后加载补丁dex得到dexFile对象作为参数构建一个Element对象插入到dex Elements数组的最前面 优点 自研dex差异算法,补丁包很小,dex merge成完整的dex,Dalvik不影响类加载性能,Art下也不存在必须包含父类/引用类的情况 没有合成整包,产物比较小,比较灵活 缺点 dex合并内存消耗在vm heap上,容易导致OOM,最后导致dex合成失败 Dalvik下影响类加载性能,Art下类地址写死,导致必须包含父类/引用类,最后补丁包很大 Tinker的dex merge操作是在Java层面进行的,所有对象的分配都是在java heap上完成的,可能发生申请的java heap超过vm heap规定的大小,进程发生OOM导致进程被杀死合成失败,如果在JNI层面进行C++ new/malloc申请的内存,分配在native heap,native heap的增长并不受vm heap大小的限制,只受限于RAM,如果RAM不足,也会导致进程被杀死导致闪退。在JNI层面进行dex merge,从而避免OOM提高合并成功率。
QQ空间的解决方案
问题来源
如果我们把要修复的QzoneActivityManager类打包成一个dex文件,插入到所有的dex文件的最前面,
1. ModuleManager在classes.dex中
2. QzoneActivityManager在patch.dex
ModuleManager引用了QzoneActivityManager,但是发现这两个类不在同一个dex文件中,于是问题就出现了
解决方案
dex在转换为odex(dexopt)的代码中的一段,在安装apk的时候,class.dex会被虚拟机(dexopt)优化成odex文件,然后才拿去执行
//DexPrepare.cpp /* * First, try to verify it. */ if (doVerify) { if (dvmVerifyClass(clazz)) { /* * Set the "is preverified" flag in the DexClassDef. We * do it here, rather than in the ClassObject structure, * because the DexClassDef is part of the odex file. */ assert((clazz->accessFlags & JAVA_FLAGS_MASK) == pClassDef->accessFlags); ((DexClassDef*)pClassDef)->accessFlags |= CLASS_ISPREVERIFIED; verified = true; } else { // TODO: log when in verbose mode ALOGV("DexOpt: '%s' failed verification", classDescriptor); } }
虚拟机在启动的时候,会有许多的启动参数,其中一项就是verify选项,当verify选项被打开的时候,上面doVerify变量为true,那么就会执行dvmVerifyClass进行类的校验,如果dvmVerifyClass校验类成功,那么这个类会被打上CLASS_ISPREVERIFIED的标志,那么具体的校验过程是什么样子的呢?
//DexVerify.cpp bool dvmVerifyClass(ClassObject* clazz) { int i; if (dvmIsClassVerified(clazz)) { ALOGD("Ignoring duplicate verify attempt on %s", clazz->descriptor); return true; } for (i = 0; i < clazz->directMethodCount; i++) { if (!verifyMethod(&clazz->directMethods[i])) { LOG_VFY("Verifier rejected class %s", clazz->descriptor); return false; } } for (i = 0; i < clazz->virtualMethodCount; i++) { if (!verifyMethod(&clazz->virtualMethods[i])) { LOG_VFY("Verifier rejected class %s", clazz->descriptor); return false; } } return true; }
-
验证clazz->dvmIsClassVerified方法,directMethods包含了以下方法:
- static方法
- private方法
- 构造函数
-
clazz->virtualMethods
- 虚函数=override方法
概括一下就是如果以上方法中直接引用到的类(第一层级关系,不会递归进行搜索)和clazz都在同一个dex中的话,那么这个类就会被打上CLASS_ISPREVERIFIED
因为dex在优化的过程中会进行class的校验,给每一个class打上了一个CLASS_ISPREVERIFIED的标签,在调用的时候会根据该标签判断所在的class是否是同一个dex如果不是会抛出异常导致程序停止。所以我们需要防止类被打上CLASS_ISPREVERIFIED。
g)
最终的解决方案是在所有类的构造函数里面插入了一段代码:代码如下
if (ClassVerifier.PREVENT_VERIFY) { System.out.println(AntilazyLoad.class); }
其中AntilazyLoad类会被打包成单独的hack.dex,这样当安装apk的时候,classes.dex内的类都会引用一个在不相同dex中的AntilazyLoad类,这样就防止了类被打上CLASS_ISPREVERIFIED的标志了,只要没被打上这个标志的类都可以进行打补丁操作。
然后在应用启动的时候加载进来.AntilazyLoad类所在的dex包必须被先加载进来,不然AntilazyLoad类会被标记为不存在,即使后续加载了hack.dex包,那么他也是不存在的,这样屏幕就会出现茫茫多的类AntilazyLoad找不到的log。
所以Application作为应用的入口不能插入这段代码。(因为载入hack.dex的代码是在Application中onCreate中执行的,如果在Application的构造函数里面插入了这段代码,那么就是在hack.dex加载之前就使用该类,该类一次找不到,会被永远的打上找不到的标志)
其中
class ClassVerifier{ public static boolean PREVENT_VERIFY=false;//false防止代码被执行,提高性能 }
之所以选择构造函数是因为他不增加方法数,一个类即使没有显式的构造函数,也会有一个隐式的默认构造函数。
空间使用的是在字节码插入代码,而不是源代码插入,使用的是javaassist库来进行字节码插入的。
虚拟机在安装期间为类打上CLASS_ISPREVERIFIED标志是为了提高性能的,我们强制防止类被打上标志会影响性能.(5.0以下)
但是插桩会给类加载效率带来比较严重的影响,熟悉Dalvik虚拟机开发的都知道,一个类的加载阶段通常有三个阶段:
-
dvmResolveClass
-
dvmLinkClass
-
dvmInitClass:在类解析完并尝试初始化类的时候执行,这个方法主要完成父类的初始化,当前类的初始化,静态变量的初始化赋值等操作。
可以看到如果类没被打上CLASS ISPREVERIFIED/CLASS ISOPTIMIZED 的标志,那么类的校验和优化都在类的初始化阶段进行。那么类的校验和优化都将在类的初始化阶段进行。正常情况下类的校验和优化都仅在 APK 第一次安装执行 dexopt 操作的时候进行 , 类的校验任务实际上是很重的,因为会对类的所有方法中的所有指令都进行校验,单个类加载时类校验耗时并不多,但是如果是在同一时间点加载大量类的情况下,这种耗时就会被放大 。
性能影响
插桩导致所有的类都非preverify,从而导致校验和优化操作都会在类加载时触发,平均每个类的校验和优化的耗时并不长,但是应用刚启动的时候一般会同时加载大量的类,容易导致用户白屏。
QFix的解决方案
与QQ空间采用的native hook方式不同,不会去hook某个系统方法,而是从navie层直接调用,有如下注意点:
-
dvmResolveClass的第三个参数fromUnverifiedConstant必须为true。
-
在APK多dex的情况下,dvmResolveClass第一个参数referrer类必须跟需要打包的类在同一个dex中,但是它们两个类不需要存在任何引用关系,任何一个在同一个dex中的类作为referrer都可以。
-
referrer类必须提前加载。
但是QFix的方案有它独特的缺陷,由于是在dexopt后绕过的,dexopt会改变原有的很多逻辑,许多odex层面的优化会固定字段和方法的访问偏移,这会导致比较严重的bug。比如可能导致方法调用错乱。
但是上面两种方案都是侵入应用打包,我们的需求是冷启动模式是热部署模式的补充方案,所以这两种方案使用的应该是同一套补丁,我们的需求是无侵入打包又能做热部署模式的补充解决方案。
如何解决Dalvik虚拟机下类的pre-verify问题,如果一个类中直接引用到的所有非系统类都和该类在同一个dex中的话,那么这个类就会被打上CLASS_ISPAREVERIFIED标志,具体判定代码可见虚拟机中的verifyAndOptimizeClass函数。
腾讯三大热修复方案如何解决该问题:
-
QQ空间的处理方式是在每个类中插入一个来自其他dex的hack.class,由此让所有类都无法满足pre-verified条件。
缺点:入侵打包流程,添加臃肿代码,不优雅,无法新增public函数。
-
Tinker的方式是合成全量的dex文件,这样所有类都在全量dex中解决,从而消除类重复而带来的冲突。
粒度过细,实现起来较为复杂,性能消耗比较严重,时空代价转换的性价比不高(dex占apk比例不高)
-
QFix的方式是获取虚拟机中的某些底层函数,提前解析所有补丁类。以此绕过Pre-verify检查。
需要获取底层虚拟机函数,不够稳定可靠,无法新增public函数。
Robust解决方案(实时生效)
在打基础包时插桩,在每一个方法前插入一段ChangeQuickRedirect静态变量的逻辑,插入过程对业务开发完全透明。加载补丁时,从补丁包中读取要替换的类以及具体替换的方法实现,新建ClassLoader加载补丁dex。当changeQuickRedirect不为null的时候,可能会执行到accessDispatch从而替换掉之前老的逻辑,达到fix的目的。
public static ChangeQuickRedirect u; protected void onCreate(Bundle bundle) { //为每个方法自动插入修复逻辑代码,如果ChangeQuickRedirect为空则不执行 if (u != null) { if (PatchProxy.isSupport(new Object[]{bundle}, this, u, false, 78)) { PatchProxy.accessDispatchVoid(new Object[]{bundle}, this, u, false, 78); return; } } super.onCreate(bundle); ... }
Robust的核心修复源码如下:
public class PatchExecutor extends Thread { @Override public void run() { ... applyPatchList(patches); ... } /** * 应用补丁列表 */ protected void applyPatchList(List<Patch> patches) { ... for (Patch p : patches) { ... currentPatchResult = patch(context, p); ... } } /** * 核心修复源码 */ protected boolean patch(Context context, Patch patch) { ... //新建ClassLoader DexClassLoader classLoader = new DexClassLoader(patch.getTempPath(), context.getCacheDir().getAbsolutePath(), null, PatchExecutor.class.getClassLoader()); patch.delete(patch.getTempPath()); ... try { patchsInfoClass = classLoader.loadClass(patch.getPatchesInfoImplClassFullName()); patchesInfo = (PatchesInfo) patchsInfoClass.newInstance(); } catch (Throwable t) { ... } ... //通过遍历其中的类信息进而反射修改其中 ChangeQuickRedirect 对象的值 for (PatchedClassInfo patchedClassInfo : patchedClasses) { ... try { oldClass = classLoader.loadClass(patchedClassName.trim()); Field[] fields = oldClass.getDeclaredFields(); for (Field field : fields) { if (TextUtils.equals(field.getType().getCanonicalName(), ChangeQuickRedirect.class.getCanonicalName()) && TextUtils.equals(field.getDeclaringClass().getCanonicalName(), oldClass.getCanonicalName())) { changeQuickRedirectField = field; break; } } ... try { patchClass = classLoader.loadClass(patchClassName); Object patchObject = patchClass.newInstance(); changeQuickRedirectField.setAccessible(true); changeQuickRedirectField.set(null, patchObject); } catch (Throwable t) { ... } } catch (Throwable t) { ... } } return true; } }
其实我感觉Robust的方案虽然有侵入性,增加代码体积等的缺点,但是感觉这种方式是兼容率最好的方案。也不会受Android版本的更新影响。
Sophix的解决方案
新的全量dex方案(Dalvik)
在原先基线包里的dex中,去掉补丁包dex中也有的类,这样基线包dex里就只包含不变的类了。而这些不变的类在要用拿到补丁中的新类会自动找到补丁dex,补丁包中的新类在需要用到不变的类时也会找到基线包dex的类。基线包里面不使用补丁类的类仍旧可以按原来的逻辑做odex,最大程度的保证了dexopt的效果。对dex的结构也不用进行破坏性重构。
所以问题就变成了如何在基线包dex中去掉补丁包中包含的所有类,dalvik中dex的文件结构可以查看这里
解决方法
我们要做的并不是把某个类的所有信息都从你dex移除,因为这么做,可能会导致dex的各个部分都发送变化,从而需要调整大量的offset,这么就变得费时费力了。我们需要做的仅仅是使得解析这个dex的时候找不到这个类的定义就可以了。因此只需要移除定义的入口,对于类的具体内容不进行删除,这样可以最大限度的减少offset的修改。
-
Dalvik下采用自行研发的全量dex方案
-
在Art下本质上虚拟机已经支持多dex的加载,我们要做的仅仅是把补丁dex作为dex(classes.dex)加载而已。
Art模式下虚拟机默认支持多dex压缩文件的加载。Art下面最终冷启动解决方案:我们只要把补丁dex命名为classes.dex。原APK中dex依次命名为class(2,3,4…).dex就可以了,然后一起打包进一个压缩文件。在通过DexFile.loadDex得到DexFile对象,最后用该DexFile整体替换旧的dexElements就可以了。
不得不说的其他点
DexFile.loadDex尝试把一个dex文件解析并加载到native内存中,在加载到内存之前,如果dex不存在对应的odex,那么Dalvik下会执行dexopt,Art下会执行dexoat,最后得到的都是一个优化后的odex。实际上最后虚拟机执行的是这个odex而不是dex。如果dex足够大,dexopt/dexoat的操作是很耗时的,在Dalvik下面的影响比较小,因为loadDex的仅仅是补丁包。但是在Art下影响非常大。因为loadDex是补丁dex和Apk中原dex合并成一个完整补丁压缩包,所以dexoat操作非常耗时,所以优化后的所以如果优化后的 odex 文件没生成或者不完整,那么 loadDex 便不能在应用启动的时候进行,因为会 阻塞 loadDex 线程, 一般是主线程 。 所以为了解决这个问题,我们]把 loadDex 当作一个事务来看,如果中途被打断,那么就删除odex 文件,重启的时候如果发现存在odex 文件,loadDex 完之后,反射注入 /替换dexElernents 数组,实现打包。如 果不存在odex文件,那么重启另一个子线程loadDex,重启之后再生效。
另外一方面,为了补丁包的安全性,虽然对补丁包进行签名校验,这个时候能够防止整个补丁包被篡改,但是实际上因为虚拟机执行的是 odex 而不是 dex,还需要对odex文件进行 MD5 完整性校验,如果匹配,则直接加载,如果不匹配,则重新生成odex文件,防止odex文件被篡改 。
注意:
- 补丁dex必须命名为classes.dex
- 用loadDex得到的DexFile完整替换掉dexElements数组而不是插入。
对于Application的处理
现在已经实现了完成的dex合成,所有完整的dex替换方案都会遇到,对Application的处理问题。由于Application是整个App的入口,因此在进入到替换的完整的dex之前,一定会通过Appliation代码,而Application必然是加载在原来的dex里面的。只有在补丁加载后使用的类,会在新的完整dex里面找到。如果替换掉Application,也会遇到这个问题。
因此,加载补丁后,如果Application类使用其他新dex里的类,由于在不同dex里,如果Application被打上了pre-verified标志,就会抛出异常。
Sophix在JNI层清除掉pre-verified(CLASS_ISPREVERIFIED)的标志,这样在dvmResolveClass中找到新的dex里的类后,由于CLASS_VERIFIED标志被清空,就不会判断所在dex是否相同,从而成功的避免抛出异常。这样对Application既没有侵入编译过程,也不需要进行反射替换,所有兼容操作都在运行期间自动做好,极其顺滑。
在处理标志的过程会遇到dvmOptResolveClass的问题,有两种处理方式,第一种方式是Android官方的multi-dex机制会自动将Application用到的类都自动打包到住dex中,所以只要把热修复初始化放在attachBaseContext的最前面,一般都没有问题。
入口类与初始化时机
Application.attachBaseContext → ContentProvide.oncreate → Application.onCreate → Activity.onCreate
attachBaseContext是Application中最早被执行的代码,但是需要注意的是,在attachBaseContext里面有很多限制,此时的App申请权限还没有被授予完成,所以会遇到无法访问网络之类的问题。因此在attachBaseContext里面可以初始化,但不可以进行网络请求下载新补丁。如果要使热修复类之前使用其他类最少,最好放在attachBaseContext()中。
防不胜防的细节错误
错误示范:
- Crash的注册早于Sophix的初始化是不可以的,Sophix的初始化不可以包装在其他类中,否则会导致提前引入类。
- BuildConfig类是Android编译期间动态生成的,也属于非系统类,如果在这里使用就会有提前引入的问题。建议使用PackageManager来获取版本号。
- Sophix的回调类load中使用的自定义的Logger,在回调状态的时候可能热修复还未初始化完毕,需要替换成系统Log类。
- LocalStroageUtil直接在声明处赋值了它的实例,这个赋值其实是隐式发生在对象的构造函数中的,这个时候甚至是早于attachBaseContext的,因此也是不行的,需要在初始化之后才能赋值。
- MultiDex.install(this)放在热修复之后,可能会导致后面的热修复框架初始化的时候找不到其他不在主dex中的热修复框架内部类,因此需要放在热修复初始化之前。
- 不要遗漏super.attachBaseContext(base)
入口类带来的修复限制
如果获取某个类的某个方法,是根据这个方法在类里面的方法索引来取得的,这个索引是这个万法在类里面的序号,那么 , 如果在这个类里面新增或者减少万法, 就会导致这个类中的方法索引与原有的不一致 。 而在 Application 入口类中,仍然是处于安装包的 oat 文件里,是原有的索引,所以如果用这个索引去类中获取方法,将可能不再是原来的万法,从而引发崩溃。 同理,对于类里面的字段, 也存在索引,因此也有类似的问题 。
不过,触发这个问题需要使得 Application 中使用的类的方法索引发生变化。 如果对这些使用的类,不增加或者减少方法数或者字段的话 , 就没关系 。 即使发生了增减的情况,如果在 Application 里面直接使用到的这些方法或者字段索引没有受到影响,那也是没问题的 。 例如插入的方法正好是在所用方法之后,那就影响不到这个方法的索引。 保险起见,还是需要注意这类情况,并尽量避免。
开发者使用这种万式进行初始化的时候 , 只需要复制这个 SophixStubApplication 类到自己的项目中,然后把 AndroidManifest 里面的 Application 指定为它,再设置 SophixEntry 为 SampleApplication 就可以了 。
使用SophixApplication,Sophix在运行的时候,会先执行初始化逻辑,当初始化完成后, 通过反射得到SophixStubApplication 的静态内部类 RealApplicationStub,最终通过它的类注解SophixEntry得到真正的 Application 即 SampleApplication。然后调用 SampleApplication 的生命周期函数 attachBaseContext、 onCreate 等 ,再进行替换 。 后续,所有使用 Application 的地方都能够找到这个换回来的 SampleApplication。
其他方案
Tinker的方案是在AndroidManifest.xml什么中就要求开发者将自己的Application直接替换成TinkerApplcation。而对于真正的Application,要在初始化TinkerApplcation时作为参数传入,在生命周期回调时通过反射的方式调用实际的Applicationn的相关逻辑。这么做确实很好地将入口Application和用户代码隔开,不过需要改造原有的Application,如果对Application有更多扩展,接入成本也是比较高的。Tinker中的sample如下:
@SuppressWarnings("unused") @DefaultLifeCycle(application = "tinker.sample.android.app.SampleApplication", flags = ShareConstants.TINKER_ENABLE_ALL, loadVerifyFlag = false) public class SampleApplicationLike extends DefaultApplicationLike { private static final String TAG = "Tinker.SampleApplicationLike"; public SampleApplicationLike(Application application, int tinkerFlags, boolean tinkerLoadVerifyFlag, long applicationStartElapsedTime, long applicationStartMillisTime, Intent tinkerResultIntent) { super(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime, applicationStartMillisTime, tinkerResultIntent); } /** * install multiDex before install tinker * so we don't need to put the tinker lib classes in the main dex * * @param base */ @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Override public void onBaseContextAttached(Context base) { super.onBaseContextAttached(base); //you must install multiDex whatever tinker is installed! MultiDex.install(base); SampleApplicationContext.application = getApplication(); SampleApplicationContext.context = getApplication(); TinkerManager.setTinkerApplicationLike(this); TinkerManager.initFastCrashProtect(); //should set before tinker is installed TinkerManager.setUpgradeRetryEnable(true); //optional set logIml, or you can use default debug log TinkerInstaller.setLogIml(new MyLogImp()); //installTinker after load multiDex //or you can put com.tencent.tinker.** to main dex TinkerManager.installTinker(this); Tinker tinker = Tinker.with(getApplication()); } @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) public void registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks callback) { getApplication().registerActivityLifecycleCallbacks(callback); } }
Amigo的方案是在编译过程中,用Amigo自定义的gradle插件将App的Application替换成Amigo自己的一个Application,并将原来的Application的name保存起来,该修复的问题都修复完成后再调用之前保存的Application的attch(context),然后将它回调到loadApk中,最后调用它的onCreate(),执行原有的Application中的逻辑,这种方式是在编译期帮用户做替换,这种对系统做方式替换本身也是有一定风险的。
多态对冷启动类加载的影响
多态一般是指非静态非私有方法的多态,field和静态方法不具有多态性。
首先new B()的执行会尝试加载类B,方法调用链dvmResolveClass->dvmLinkClass->createVtable,此时会为类B创建一个vtable,其实在虚拟机中加载每个类都会为这个类生成一张vtable表,vtable表就是当前类的所有virtual方法的一个数组,当前类和所有继承父类的public/protected/default方法就是virtual方法,因为public/protected/default方法是可以被继承的。private/static方法不属于这个范畴,因为不能被继承。
子类vtable的大小等于子类virtual方法数+父类vtable的大小。
- 整体复制父类vtable到子类的vtable
- 遍历子类的virtual方法集合,如果方法原型一致,说明是重写父类方法,那么在相同索引位置处,子类重写方法覆盖掉vtable中父类的方法;
- 若方法原型不一致,那么把该烦恼规范添加到vtable的末尾。
field/static方法为什么不具有多态性,简单来讲,**是从当前变量的引用类型而不是实际类型中查找,如果查不到,再去父类中递归查找。**所以field和static方法不具备多态性。
冷启动方案限制
方法调用错乱问题:
dex文件第一次加载的时候,会进行dexopt,dexopt有verify和optimize两个过程:
-
dvmVerifyClass:类校验,简单来说,类校验的目的就是为了防止类被篡改而校验类的合法性。此时会对类的每个方法进行校验,这里我们只需要知道如果类的所有方法中直接引用到的类(第一层级关系,不会进行递归搜索)和当前类都在同一个dex中的话,dvmVerifyClass就返回true。
-
dvmOptimizeClass:类优化,简单来说,这个过程会把部分指令优化成虚拟机的内部指令,比如方法调用指令invoke-virtual-quick,quick指令会从类的vtable表中直接获取,vtable简单来说就是类的所有方法的一张大表(包括继承自父类的方法)。因此提升了方法的执行速率。
Invoke-virtual-quick效率明显比invoke-virtual更高,直接从实际类型的vtable中获取调用方法的指针,而省略了dvmResolveMethod从变量的引用类型获取该方法在vtable索引ID的步骤,所以更高效。(例子:new B()的执行会尝试加载类B,方法调用链dvmResolveClass->dvmLinkClass->createVtable)
资源修复
Instant Run中的资源热修复分为两步
- 构造一个新的AssetManager,通过反射调用addAssetPath函数,然后把完整的新资源包加载到AssetManager中。这样就得到了一个含有所有新资源的AssetManager。
- 找到所有之前引用到原有的AssetManager的地方,通过反射,把引用处替换为新的AssetManager
没有直接参考Instant Run的技术,而是另辟蹊径构造一个package id为0x66的资源包,这个包里面只需要包含需要改变的资源项,然后直接在原有AssetManger中通过addAssetPath函数添加这个包就可以了。由于补丁包的package id为0x66,不与目前的已经加载的地址为0x7f的包冲突,因此直接加载到已有的AssetManager中就可以直接使用了。
补丁包里面的只有新增的资源和需要替换的资源。并且,我们采用了更加优雅的替换方式,直接在原有的AssetManager对象上进行解析和重构,这样所有原有对AssetManager对象的引用是没有发生改变的,不需要想Instant Run那样进行繁琐的修改了。
Instant Run团队和Android Framework不是一个团队,他们对系统源码了解也不是很深,所以做的也并不是很好,我们只要仔细阅读源码,也能搞出更好的方案。
Sophix的修改方案
- 不修改AssetManger的引用处,替换资源更快更完整(对比Instant Run以及所有CopyCat的实现)
- 不必下发完整包,补丁包中只包含变动的资源(对比Instant Run,Amigo等方式的实现)
- 不需要在运行时合成包,不占用运行时计算和内存资源(对比Tinker实现)
so库修复
so库的修复本质是对native方法的修复和替换
采用类似类修复反射反射注入方式。把补丁so库的路径插入到nativeLibraryDirectories数组的最前面,就能够达到加载so库的时候是补丁so库的目录,从而达到修复bug的目的。不像某些方案需要手动替换系统的System.load来实现替换功能。
区别于所谓的黑科技(类似保活),实际上是改善了Android的生态环境。
Android与iOS热修复的不同
- 谷歌和苹果在中国的地位不同,控制能力不同
- Android和iOS的开放性不同
热修复的必要性
热修复不是简单的客户端SDK,它还包含了安全机制和服务端的控制逻辑,整条链路也不是短时间可以快速完成的。
专业的事是交给专业的人去做。开发者应该把更多的时间精力放到自己的核心业务之中。
总结
想要深入了解热修复,需要了解类加载机制,Instant Run,multidex以及java底层实现细节,JNI,AAPT和虚拟机的知识,需要庞大的知识贮备才能进行深入理解,当然Android Framwork的实现细节是非常重要的。熟悉热修复的原理有助于我们提供自己的编程水平,提升自己解决问题的能力,最后热修复不是简单的客户端SDK,它还包含了安全机制和服务端的控制逻辑,整条链路也不是短时间可以快速完成的。还是这句话,专业的事是交给专业的人去做。开发者应该把更多的时间精力放到自己的核心业务之中。
本文在开源项目:https://github.com/Android-Alvin/Android-LearningNotes 中已收录,里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…
作者:伤心的猪大肠
链接:https://juejin.im/post/6870510331228717063 - 阿里系
-
a2sd+状态下应用程序丢失的解决方法详细解析
2021-01-05 01:31:03这种情况,十有八九是SD存储卡的ext分区出错了,修复错误后重新开机即可重新启用a2...刷机完以后开机之后最好关机然后再开(不管你刷了什么包或者补丁,是否wipe),没有这个操作,容易出现安装软件时导致系统重启,ex -
链接语法:CMU链接语法自然语言解析器-源码
2021-02-03 18:19:39该版本的解析器是上一个官方CMU版本的扩展,扩展版本,并包含许多不同开发人员创建的许多增强功能和修复程序。 该代码是根据LGPL许可发布的,因此几乎不受任何限制,可免费供私人和商业使用。 许可的条款在此软件... -
曲奇智能DNS解析系统(CookyDNS) r11.zip
2019-07-03 21:28:33曲奇智能DNS解析系统(CookyDNS)(以下简称CookyDNS)提供域名授权解析服务,他是完全自主开发的DNS服务器软件,不是BIND或这NSD之类的DNS软件的修改产品,可以快速简单安装,配置简单、并且有设置向导和安装程序、... -
云搜网盘助手1.5(网盘搜索、去重、解析+磁力搜索)
2016-03-21 08:17:38云搜网盘助手是一款网盘类辅助软件,包含了百度云搜索、新浪微盘搜索、磁力搜索、网盘直链解析以及云盘工具五个大...这是对之前程序的升级,主要修复了磁力搜索无结果的Bug和360云盘无法正常解析的Bug以及其他一些小Bug -
Nvidia TensorRT开源软件
2020-12-02 07:23:43这些开源软件组件是TensorRT General Availability(GA)发行版的一个子集,其中包含一些扩展和错误修复。 对于TensorRT OSS的代码贡献,请参阅我们的贡献指南和编码指南。 有关TensorRT OSS发行版附带的新添加和...TensorRT开源软件
此存储库包含NVIDIA TensorRT的开源软件(OSS)组件。其中包括TensorRT插件和解析器(Caffe和ONNX)的源代码,以及演示TensorRT平台使用和功能的示例应用程序。这些开源软件组件是TensorRT General Availability(GA)发行版的一个子集,其中包含一些扩展和错误修复。
对于TensorRT OSS的代码贡献,请参阅我们的贡献指南和编码指南。
有关TensorRT OSS发行版附带的新添加和更新的摘要,请参阅变更日志。
Build
Prerequistites
要构建TensorRT OSS组件,首先需要以下软件包。
参考链接:https://github.com/NVIDIA/TensorRT
TensorRT GA build
TensorRT v7.2.1
See Downloading TensorRT Builds for details
System Packages
CUDA
Recommended versions:
cuda-11.1 + cuDNN-8.0
cuda-11.0 + cuDNN-8.0
cuda-10.2 + cuDNN-8.0GNU make >= v4.1
cmake >= v3.13
python >= v3.6.5
pip >= v19.0
Essential utilitiesgit, pkg-config, wget, zlib
Optional Packages
Containerized build
Docker >= 19.03
NVIDIA Container ToolkitToolchains and SDKs
(Cross compilation for Jetson platform) NVIDIA JetPack
>= 4.4
(For Windows builds) Visual
Studio 2017 Community or Enterprise edition
(Cross compilation for QNX platform) QNX ToolchainPyPI packages (for demo applications/tests)
numpy
onnx 1.6.0
onnxruntime >= 1.3.0
pytest
tensorflow-gpu 1.15.4Code formatting tools (for contributors)
Clang-format
Git-clang-formatNOTE: onnx-tensorrt,
cub, and protobuf packages
are downloaded along with TensorRT OSS, and not required to be installed.Downloading TensorRT Build
- Download TensorRT OSS
On Linux: Bash
git clone -b master https://github.com/nvidia/TensorRT TensorRTcd TensorRTgit submodule update --init --recursiveexport TRT_SOURCE=
pwd
On Windows: Powershell
git clone -b master https://github.com/nvidia/TensorRT TensorRTcd TensorRTgit submodule update --init --recursive$Env:TRT_SOURCE = $(Get-Location)
- Download TensorRT GA
To build TensorRT OSS, obtain the corresponding TensorRT GA build from NVIDIA Developer Zone.
Example: Ubuntu 18.04 on x86-64 with cuda-11.1
Download and extract the latest TensorRT 7.2.1 GA package for Ubuntu 18.04 and CUDA 11.1
cd ~/Downloadstar -xvzf TensorRT-7.2.1.6.Ubuntu-18.04.x86_64-gnu.cuda-11.1.cudnn8.0.tar.gzexport TRT_RELEASE=
pwd
/TensorRT-7.2.1.6Example: Ubuntu 18.04 on PowerPC with cuda-11.0
Download and extract the latest TensorRT 7.2.1 GA package for Ubuntu 18.04 and CUDA 11.0
cd ~/Downloadstar -xvzf TensorRT-7.2.1.6.Ubuntu-18.04.powerpc64le-gnu.cuda-11.0.cudnn8.0.tar.gzexport TRT_RELEASE=
pwd
/TensorRT-7.2.1.6Example: CentOS/RedHat 7 on x86-64 with cuda-11.0
Download and extract the TensorRT 7.2.1 GA for CentOS/RedHat 7 and CUDA 11.0 tar package
cd ~/Downloadstar -xvzf TensorRT-7.2.1.6.CentOS-7.6.x86_64-gnu.cuda-11.0.cudnn8.0.tar.gzexport TRT_RELEASE=
pwd
/TensorRT-7.2.1.6Example: Ubuntu18.04 Cross-Compile for QNX with cuda-10.2
Download and extract the TensorRT 7.2.1 GA for QNX and CUDA 10.2 tar package
cd ~/Downloadstar -xvzf TensorRT-7.2.1.6.Ubuntu-18.04.aarch64-qnx.cuda-10.2.cudnn7.6.tar.gzexport TRT_RELEASE=
pwd
/TensorRT-7.2.1.6export QNX_HOST=//host/linux/x86_64export QNX_TARGET=//target/qnx7Example: Windows on x86-64 with cuda-11.0
Download and extract the TensorRT 7.2.1 GA for Windows and CUDA 11.0 zip package and add msbuild
to PATHcd ~\DownloadsExpand-Archive .\TensorRT-7.2.1.6.Windows10.x86_64.cuda-11.0.cudnn8.0.zip(Get-Location)\TensorRT-7.2.1.6’$Env:PATH += ‘C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin’
- (Optional) JetPack SDK for Jetson builds
Using the JetPack SDK manager, download the host components. Steps:
i. Download and launch the SDK manager. Login with your developer account.
ii. Select the platform and target OS (example: Jetson AGX Xavier, Linux Jetpack 4.4), and click Continue.
iii. Under Download & Install Options change the download folder and select Download now, Install later. Agree to the license terms and click Continue.
iv. Move the extracted files into the $TRT_SOURCE/docker/jetpack_files folder.
Setting Up The Build Environment
For native builds, install the prerequisite System Packages.
Alternatively (recommended for non-Windows builds), install Docker and generate a build container as described below:- Generate the TensorRT-OSS build container.
The TensorRT-OSS build container can be generated using the Dockerfiles and build script included with TensorRT-OSS. The build container is bundled with packages and environment required for building TensorRT OSS.
Example: Ubuntu 18.04
on x86-64 with cuda-11.1./docker/build.sh --file docker/ubuntu.Dockerfile --tag tensorrt-ubuntu --os 18.04 --cuda 11.1
Example: Ubuntu 18.04 on PowerPC with cuda-11.0
./docker/build.sh --file docker/ubuntu-cross-ppc64le.Dockerfile --tag tensorrt-ubuntu-ppc --os 18.04 --cuda 11.0
Example: CentOS/RedHat 7 on x86-64 with cuda-11.0
./docker/build.sh --file docker/centos.Dockerfile --tag tensorrt-centos --os 7 --cuda 11.0
Example: Ubuntu 18.04 Cross-Compile for Jetson (arm64) with cuda-10.2 (JetPack)
./docker/build.sh --file docker/ubuntu-cross-aarch64.Dockerfile --tag tensorrt-cross-jetpack --os 18.04 --cuda 10.2
- Launch the TensorRT-OSS build container.
Example: Ubuntu 18.04 build container
./docker/launch.sh --tag tensorrt-ubuntu --gpus all --release $TRT_RELEASE --source $TRT_SOURCE
NOTE:
i. Use the tag
corresponding to the build container you generated inii. To run TensorRT/CUDA
programs in the build container, install NVIDIA Container
Toolkit. Docker versions < 19.03 require nvidia-docker2 and --runtime=nvidia flag for docker run commands. On versions >= 19.03, you need the nvidia-container-toolkit package and --gpus all flag.Building TensorRT-OSS
· Generate Makefiles or VS project (Windows) and build.
Example: Linux (x86-64) build with default cuda-11.1
cd KaTeX parse error: Expected 'EOF', got '&' at position 27: …mkdir -p build &̲& cd build cmak…TRT_RELEASE/lib -DTRT_OUT_DIR=
pwd
/out make -j$(nproc)Example: Native build on Jetson (arm64) with cuda-10.2
cd KaTeX parse error: Expected 'EOF', got '&' at position 26: …mkdir -p build &̲& cd buildcmake…TRT_RELEASE/lib -DTRT_OUT_DIR=
pwd
/out -DTRT_PLATFORM_ID=aarch64 -DCUDA_VERSION=10.2make -j$(nproc)Example: Ubuntu 18.04 Cross-Compile for Jetson (arm64) with cuda-10.2 (JetPack)
cd KaTeX parse error: Expected 'EOF', got '&' at position 27: …mkdir -p build &̲& cd build cmak…TRT_RELEASE/lib -DTRT_OUT_DIR=
pwd
/out -DCMAKE_TOOLCHAIN_FILE=(nproc)Example: Cross-Compile for QNX with cuda-10.2
cd KaTeX parse error: Expected 'EOF', got '&' at position 27: …mkdir -p build &̲& cd build cmak…TRT_RELEASE/lib -DTRT_OUT_DIR=
pwd
/out -DCMAKE_TOOLCHAIN_FILE=(nproc)Example: Windows (x86-64) build in Powershell
cd Env:TRT_RELEASE\lib -DTRT_OUT_DIR=’$(Get-Location)\out’ -DCMAKE_TOOLCHAIN_FILE=…\cmake\toolchains\cmake_x64_win.toolchain msbuild ALL_BUILD.vcxproj
NOTE:
The default CUDA version used by CMake is 11.1. To override this, for example to 10.2, append -DCUDA_VERSION=10.2 to the cmake command.
If samples fail to link on CentOS7, create this symbolic link: ln -s $TRT_OUT_DIR/libnvinfer_plugin.so $TRT_OUT_DIR/libnvinfer_plugin.so.7·
Required CMake build arguments are:TRT_LIB_DIR: Path to the TensorRT installation directory containing libraries.
TRT_OUT_DIR: Output directory where generated build artifacts will be copied.·
Optional CMake build
arguments:CMAKE_BUILD_TYPE: Specify if binaries generated are for release or debug (contain debug symbols). Values consists of [Release] | Debug
CUDA_VERISON: The version of CUDA to target, for example [11.1].
CUDNN_VERSION: The version of cuDNN to target, for example [8.0].
NVCR_SUFFIX: Optional nvcr/cuda image suffix. Set to
“-rc” for CUDA11 RC builds until general availability. Blank by default.
PROTOBUF_VERSION: The version of Protobuf to use, for example [3.0.0]. Note: Changing this will not configure CMake to use a system version of Protobuf, it will configure CMake to download and try building that version.
CMAKE_TOOLCHAIN_FILE: The path to a toolchain file for cross compilation.
BUILD_PARSERS: Specify if the parsers should be built, for example [ON] | OFF. If turned OFF, CMake will try to find precompiled versions of the parser libraries to use in compiling samples. First in ${TRT_LIB_DIR}, then on the system. If the build type is Debug, then it will prefer debug builds of the libraries before release versions if available.
BUILD_PLUGINS: Specify if the plugins should be built, for
example [ON] | OFF. If turned OFF, CMake will try to find a
precompiled version of the plugin library to use in compiling samples.
First in ${TRT_LIB_DIR}, then on the system. If the build type is Debug, then it will prefer debug builds of the libraries before release versions if available.
BUILD_SAMPLES: Specify if the samples should be built, for example [ON] | OFF. CUB_VERSION: The version of CUB to use, for example [1.8.0].
GPU_ARCHS: GPU (SM) architectures to target. By default we generate CUDA code for all major SMs. Specific SM versions can be specified here as a quoted space-separated list to reduce compilation time and binary size. Table of compute capabilities of NVIDIA GPUs can be found here.
Examples:NVidia A100: -DGPU_ARCHS=“80”
Tesla T4, GeForce RTX 2080: -DGPU_ARCHS=“75”
Titan V, Tesla V100: -DGPU_ARCHS=“70”
Multiple SMs: -DGPU_ARCHS=“80 75”TRT_PLATFORM_ID: Bare-metal build (unlike containerized cross-compilation) on non Linux/x86 platforms must explicitly specify the target platform. Currently supported options: x86_64 (default), aarch64
(Optional) Install TensorRT python bindings
·
The TensorRT python API bindings must be installed for running TensorRT python applicationsExample: install TensorRT wheel for python 3.6
pip3 install $TRT_RELEASE/python/tensorrt-7.2.1.6-cp36-none-linux_x86_64.whl
References
TensorRT Resources
TensorRT Homepage TensorRT
Developer Guide TensorRT
Sample Support Guide
TensorRT Discussion Forums
TensorRT Release Notes.Known Issues
TensorRT 7.2.1
None
-
持续交付--发布可靠软件的系统方法.pdf
2014-02-10 10:37:19《持续交付--发布可靠软件的系统方法》,英文名《Continuous Delivery: Reliable Software Releases through Build, Test, and Deployment Automation》,原作者:(英)Jez Humble、(英)David Farley,翻译:乔梁,... -
最新飞天侠6.0仿折800完美破解升级版(已修复采集价格为0)
2014-11-02 23:03:58软件名称:最新飞天侠6.0仿折800完美升级版(已修复采集价格为0) 开发语言:PHP/Mysql 软件类别:国产软件|电子商务 软件授权:破解版 软件简介: 一.安装说明: 1、上传程序包——在线解压程序——安装程序... -
xcap v1.0.2发包工具最新版.zip
2019-09-02 18:07:57通过它你可以很轻松地构造和发送各种以太网报文,本版本为当前最新版本了,修复了之前版本中存在的的一些BUG问题。新版本还支持多任务同时进行同时发送的功能。内置报文生成及解析器,以及一些非常实用的网络小工具... -
英伟达jetpack和tensorrt_Nvidia TensorRT开源软件
2020-12-29 07:01:16TensorRT开源软件此存储库包含NVIDIA TensorRT的开源软件(OSS)...这些开源软件组件是TensorRT General Availability(GA)发行版的一个子集,其中包含一些扩展和错误修复。对于TensorRT OSS的代码贡献,请参阅我们的贡...TensorRT开源软件
此存储库包含NVIDIA TensorRT的开源软件(OSS)组件。其中包括TensorRT插件和解析器(Caffe和ONNX)的源代码,以及演示TensorRT平台使用和功能的示例应用程序。这些开源软件组件是TensorRT General Availability(GA)发行版的一个子集,其中包含一些扩展和错误修复。
对于TensorRT OSS的代码贡献,请参阅我们的贡献指南和编码指南。
有关TensorRT OSS发行版附带的新添加和更新的摘要,请参阅变更日志。
Build
Prerequistites
要构建TensorRT OSS组件,首先需要以下软件包。
TensorRT GA build
System PackagesRecommended versions:
cuda-11.1 + cuDNN-8.0
cuda-11.0 + cuDNN-8.0
cuda-10.2 + cuDNN-8.0
cmake >= v3.13
python >= v3.6.5
pip >= v19.0
Essential utilities
Optional PackagesContainerized build
Toolchains and SDKs(Cross compilation for Jetson platform) NVIDIA JetPack >= 4.4
(For Windows builds) Visual Studio 2017 Community or Enterprise edition
(Cross compilation for QNX platform) QNX Toolchain
PyPI packages (for demo applications/tests)
Code formatting tools (for contributors)
NOTE: onnx-tensorrt, cub, and protobuf packages are downloaded along with TensorRT OSS, and not required to be installed.
Downloading TensorRT Build
1. Download TensorRT OSS
On Linux: Bash
git clone -b master https://github.com/nvidia/TensorRT TensorRT
cd TensorRT
git submodule update --init --recursive
export TRT_SOURCE=`pwd`
On Windows: Powershell
git clone -b master https://github.com/nvidia/TensorRT TensorRT
cd TensorRT
git submodule update --init --recursive
$Env:TRT_SOURCE = $(Get-Location)
2. Download TensorRT GA
To build TensorRT OSS, obtain the corresponding TensorRT GA build from NVIDIA Developer Zone.
Example: Ubuntu 18.04 on x86-64 with cuda-11.1
Download and extract the latest TensorRT 7.2.1 GA package for Ubuntu 18.04 and CUDA 11.1
cd ~/Downloads
tar -xvzf TensorRT-7.2.1.6.Ubuntu-18.04.x86_64-gnu.cuda-11.1.cudnn8.0.tar.gz
export TRT_RELEASE=`pwd`/TensorRT-7.2.1.6
Example: Ubuntu 18.04 on PowerPC with cuda-11.0
Download and extract the latest TensorRT 7.2.1 GA package for Ubuntu 18.04 and CUDA 11.0
cd ~/Downloads
tar -xvzf TensorRT-7.2.1.6.Ubuntu-18.04.powerpc64le-gnu.cuda-11.0.cudnn8.0.tar.gz
export TRT_RELEASE=`pwd`/TensorRT-7.2.1.6
Example: CentOS/RedHat 7 on x86-64 with cuda-11.0
Download and extract the TensorRT 7.2.1 GA for CentOS/RedHat 7 and CUDA 11.0 tar package
cd ~/Downloads
tar -xvzf TensorRT-7.2.1.6.CentOS-7.6.x86_64-gnu.cuda-11.0.cudnn8.0.tar.gz
export TRT_RELEASE=`pwd`/TensorRT-7.2.1.6
Example: Ubuntu18.04 Cross-Compile for QNX with cuda-10.2
Download and extract the TensorRT 7.2.1 GA for QNX and CUDA 10.2 tar package
cd ~/Downloads
tar -xvzf TensorRT-7.2.1.6.Ubuntu-18.04.aarch64-qnx.cuda-10.2.cudnn7.6.tar.gz
export TRT_RELEASE=`pwd`/TensorRT-7.2.1.6
export QNX_HOST=//host/linux/x86_64
export QNX_TARGET=//target/qnx7
Example: Windows on x86-64 with cuda-11.0
Download and extract the TensorRT 7.2.1 GA for Windows and CUDA 11.0 zip package and add msbuild to PATH
cd ~\Downloads
Expand-Archive .\TensorRT-7.2.1.6.Windows10.x86_64.cuda-11.0.cudnn8.0.zip
$Env:TRT_RELEASE = '$(Get-Location)\TensorRT-7.2.1.6'
$Env:PATH += 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\'
3. (Optional) JetPack SDK for Jetson builds
Using the JetPack SDK manager, download the host components. Steps:
i. Download and launch the SDK manager. Login with your developer account.
ii. Select the platform and target OS (example: Jetson AGX Xavier, Linux Jetpack 4.4), and click Continue.
iii. Under Download & Install Options change the download folder and select Download now, Install later. Agree to the license terms and click Continue.
iv. Move the extracted files into the $TRT_SOURCE/docker/jetpack_files folder.
Setting Up The Build Environment
For native builds, install the prerequisite System Packages. Alternatively (recommended for non-Windows builds), install Docker and generate a build container as described below:
1. Generate the TensorRT-OSS build container.
The TensorRT-OSS build container can be generated using the Dockerfiles and build script included with TensorRT-OSS. The build container is bundled with packages and environment required for building TensorRT OSS.
Example: Ubuntu 18.04 on x86-64 with cuda-11.1
./docker/build.sh --file docker/ubuntu.Dockerfile --tag tensorrt-ubuntu --os 18.04 --cuda 11.1
Example: Ubuntu 18.04 on PowerPC with cuda-11.0
./docker/build.sh --file docker/ubuntu-cross-ppc64le.Dockerfile --tag tensorrt-ubuntu-ppc --os 18.04 --cuda 11.0
Example: CentOS/RedHat 7 on x86-64 with cuda-11.0
./docker/build.sh --file docker/centos.Dockerfile --tag tensorrt-centos --os 7 --cuda 11.0
Example: Ubuntu 18.04 Cross-Compile for Jetson (arm64) with cuda-10.2 (JetPack)
./docker/build.sh --file docker/ubuntu-cross-aarch64.Dockerfile --tag tensorrt-cross-jetpack --os 18.04 --cuda 10.2
2. Launch the TensorRT-OSS build container.
Example: Ubuntu 18.04 build container
./docker/launch.sh --tag tensorrt-ubuntu --gpus all --release $TRT_RELEASE --source $TRT_SOURCE
NOTE:
i. Use the tag corresponding to the build container you generated in
ii. To run TensorRT/CUDA programs in the build container, install NVIDIA Container Toolkit. Docker versions < 19.03 require nvidia-docker2 and --runtime=nvidia flag for docker run commands. On versions >= 19.03, you need the nvidia-container-toolkit package and --gpus all flag.
Building TensorRT-OSS
· Generate Makefiles or VS project (Windows) and build.
Example: Linux (x86-64) build with default cuda-11.1
cd $TRT_SOURCE
mkdir -p build && cd build
cmake .. -DTRT_LIB_DIR=$TRT_RELEASE/lib -DTRT_OUT_DIR=`pwd`/out
make -j$(nproc)
Example: Native build on Jetson (arm64) with cuda-10.2
cd $TRT_SOURCE
mkdir -p build && cd build
cmake .. -DTRT_LIB_DIR=$TRT_RELEASE/lib -DTRT_OUT_DIR=`pwd`/out -DTRT_PLATFORM_ID=aarch64 -DCUDA_VERSION=10.2
make -j$(nproc)
Example: Ubuntu 18.04 Cross-Compile for Jetson (arm64) with cuda-10.2 (JetPack)
cd $TRT_SOURCE
mkdir -p build && cd build
cmake .. -DTRT_LIB_DIR=$TRT_RELEASE/lib -DTRT_OUT_DIR=`pwd`/out -DCMAKE_TOOLCHAIN_FILE=$TRT_SOURCE/cmake/toolchains/cmake_aarch64.toolchain -DCUDA_VERSION=10.2
make -j$(nproc)
Example: Cross-Compile for QNX with cuda-10.2
cd $TRT_SOURCE
mkdir -p build && cd build
cmake .. -DTRT_LIB_DIR=$TRT_RELEASE/lib -DTRT_OUT_DIR=`pwd`/out -DCMAKE_TOOLCHAIN_FILE=$TRT_SOURCE/cmake/toolchains/cmake_qnx.toolchain -DCUDA_VERSION=10.2
make -j$(nproc)
Example: Windows (x86-64) build in Powershell
cd $Env:TRT_SOURCE
mkdir -p build ; cd build
cmake .. -DTRT_LIB_DIR=$Env:TRT_RELEASE\lib -DTRT_OUT_DIR='$(Get-Location)\out' -DCMAKE_TOOLCHAIN_FILE=..\cmake\toolchains\cmake_x64_win.toolchain
msbuild ALL_BUILD.vcxproj
NOTE:The default CUDA version used by CMake is 11.1. To override this, for example to 10.2, append -DCUDA_VERSION=10.2 to the cmake command.
If samples fail to link on CentOS7, create this symbolic link: ln -s $TRT_OUT_DIR/libnvinfer_plugin.so $TRT_OUT_DIR/libnvinfer_plugin.so.7
· Required CMake build arguments are:TRT_LIB_DIR: Path to the TensorRT installation directory containing libraries.
TRT_OUT_DIR: Output directory where generated build artifacts will be copied.
· Optional CMake build arguments:CMAKE_BUILD_TYPE: Specify if binaries generated are for release or debug (contain debug symbols). Values consists of [Release] | Debug
CUDA_VERISON: The version of CUDA to target, for example [11.1].
CUDNN_VERSION: The version of cuDNN to target, for example [8.0].
NVCR_SUFFIX: Optional nvcr/cuda image suffix. Set to "-rc" for CUDA11 RC builds until general availability. Blank by default.
PROTOBUF_VERSION: The version of Protobuf to use, for example [3.0.0]. Note: Changing this will not configure CMake to use a system version of Protobuf, it will configure CMake to download and try building that version.
CMAKE_TOOLCHAIN_FILE: The path to a toolchain file for cross compilation.
BUILD_PARSERS: Specify if the parsers should be built, for example [ON] | OFF. If turned OFF, CMake will try to find precompiled versions of the parser libraries to use in compiling samples. First in ${TRT_LIB_DIR}, then on the system. If the build type is Debug, then it will prefer debug builds of the libraries before release versions if available.
BUILD_PLUGINS: Specify if the plugins should be built, for example [ON] | OFF. If turned OFF, CMake will try to find a precompiled version of the plugin library to use in compiling samples. First in ${TRT_LIB_DIR}, then on the system. If the build type is Debug, then it will prefer debug builds of the libraries before release versions if available.
BUILD_SAMPLES: Specify if the samples should be built, for example [ON] | OFF.
CUB_VERSION: The version of CUB to use, for example [1.8.0].
GPU_ARCHS: GPU (SM) architectures to target. By default we generate CUDA code for all major SMs. Specific SM versions can be specified here as a quoted space-separated list to reduce compilation time and binary size. Table of compute capabilities of NVIDIA GPUs can be found here. Examples:NVidia A100: -DGPU_ARCHS="80"
Tesla T4, GeForce RTX 2080: -DGPU_ARCHS="75"
Titan V, Tesla V100: -DGPU_ARCHS="70"
Multiple SMs: -DGPU_ARCHS="80 75"
TRT_PLATFORM_ID: Bare-metal build (unlike containerized cross-compilation) on non Linux/x86 platforms must explicitly specify the target platform. Currently supported options: x86_64 (default), aarch64
(Optional) Install TensorRT python bindings
· The TensorRT python API bindings must be installed for running TensorRT python applications
Example: install TensorRT wheel for python 3.6
pip3 install $TRT_RELEASE/python/tensorrt-7.2.1.6-cp36-none-linux_x86_64.whl
References
TensorRT Resources
Known Issues
TensorRT 7.2.1None
-
283、修复ContentProvider.getCallingPackage返回Host包名的BUG 282、修复uid虚拟化的BUG,解决部分app权限检查失败的问题 281、重写PendingIntent, IntentSender的实现 280、优化进程管理,修复长期存在的概率性...
-
禅道项目管理软件6.1.stable版
2014-08-11 11:05:42二、集成运行环境下载:切勿下载下面的软件进行升级,仅适用于新安装 windows一键安装包(适用于windows系列) 下载站点1:http://sourceforge.net/projects/zentao/files/6.1/ZenTaoPMS.6.1.stable.exe/download ... -
700个批处理打包下载.rar
2013-08-12 17:45:52IE修复.cmd install.CMD jacksi.bat list.ini lmod.com OptimizeXp.bat QQ精简.bat QQ精简.cmd readme.txt RUN.bat set.txt shell.bat SHELL.PIF Shell.reg svc2kxp.cmd svc2kxp深山红叶汉化版本.cmd sxs.exe 的查杀... -
2020美容师(初级)模拟考试题库及美容师(初级)考试软件
2020-08-11 21:17:082020美容师(初级)模拟考试题库及美容师(初级)考试软件,包含美容师(初级)模拟考试题库答案解析及美容师(初级)考试软件练习。由安全生产模拟考试一点通公众号结合国家美容师(初级)考试最新大纲及美容师...题库来源:安全生产模拟考试一点通公众号小程序
2020美容师(初级)模拟考试题库及美容师(初级)考试软件,包含美容师(初级)模拟考试题库答案解析及美容师(初级)考试软件练习。由安全生产模拟考试一点通公众号结合国家美容师(初级)考试最新大纲及美容师(初级)考试真题出具,有助于美容师(初级)怎么考考前练习。
1、【判断题】()美容按不同的方法和手段可分为医学美容与生活美容。( √ )
2、【判断题】()结缔组织具有支持、分隔、营养、吞噬和修复等功能。( × )
3、【判断题】()美容师在接待顾客时应语气坚定、声音洪亮,给顾客留下清晰深刻的印象。( × )
4、【判断题】()根据肌肉运动特点可以把肌肉分为随意肌和不随意肌。( √ )
5、【判断题】()美容师不做违法乱纪的事,是美容师职业守则中遵纪守法的具体要求。( × )
6、【判断题】()面部皮肤护理操作前,美容师应根据顾客消费情况将仪器设备的配件、附属用品配齐就位。( × )
7、【判断题】()美容师对待顾客应礼貌、热情,服务细致、周到、耐心。( √ )
8、【判断题】()我国颁布并实施的化妆品卫生标准、化妆品卫生监督条例及化妆品卫生规范,可以据此识别产品质量的优劣。( √ )
9、【判断题】()烫睫毛是通过化学试剂使蛋白质变性,同时改变睫毛的形状。( √ )
10、【判断题】()拍叩、切叩的手法适合用于干性和衰老的皮肤按摩。( × )
11、【判断题】()表情肌收缩时使面部皮肤拉紧,改善各种皱纹。( × )
12、【判断题】()面部皮肤护理,是运用科学的方法、专业的美容手段及相应的美容护肤产品,来维护和改善面部皮肤,延缓其衰老进程。( √ )
13、【判断题】()负责接待的美容师在接待前必须做到形象得体,熟悉业务。( √ )
14、【判断题】()不同的脱毛膏(霜)使用方法不同,但在皮肤上停留的时间基本相同。( × )
15、【判断题】()引导是明确顾客的兴趣爱好后将其引领至护理区域接受美容师的护理服务过程。( × )
16、【判断题】()防火基本措施包括控制可燃物,消除着火源,隔绝助燃物和阻止火势蔓延。( √ )
17、【判断题】()正常皮肤每月去角质2-3次。( × )
18、【判断题】()眼线画得适当,能改变脸型,使脸型更加迷人。( × )
19、【单选题】正确的皮肤护理可以保持毛孔畅通,(),减少细小皱纹。( D )
A、控制皮脂分泌
B、消除定性皱纹
C、淡化痤疮
D、淡化色斑
20、【单选题】去除()时,应请客人做微笑状,以便皮肤与模体脱离。( D )
A、面贴
B、软膜
C、胶原膜
D、硬模
21、【单选题】美容师在每次使用仪器(),要对仪器与皮肤接触的部分进行消毒。( C )
A、前
B、后
C、前后
D、过程中
22、【单选题】优质化妆品接触皮肤后,应有()、自然、舒适感觉。( A )
A、滑爽
B、收敛
C、美白
D、紧绷
23、【单选题】用朱砂点唇出现在()时期。( B )
A、春秋
B、商周
C、战国
D、上古三代
24、【单选题】面部皮肤护理,可以使面部皮肤在结构、形态和()上保持良好的健康状态。( B )
A、效果
B、功能
C、作用
D、防御
25、【单选题】眼部红肿或患有()者不宜烫睫毛。( B )
A、高血压
B、眼睛疾病
C、视力减退
D、感冒
26、【单选题】方形的修整方法是()修磨指甲前缘。( A )
A、单方向平直
B、单方向垂直
C、双方向平直
D、双方向垂直
27、【单选题】油性皮肤的形成与()有关。( A )
A、雄性激素分泌过多
B、雄性激素分泌过少
C、雌性激素分泌过多
D、雌性激素分泌过少
28、【单选题】根据采用的方法和()的不同,生活美容和医学美容统称为美容。( A )
A、手段
B、形式
C、认定
D、修饰
29、【单选题】中华人民共和国第一部《美容师职业技能鉴定教材》(初、中、高),出版于()年9月。( C )
A、1990
B、1993
C、1995
D、2000
30、【单选题】负责接待的美容师在接待前应做到配戴署有()的工作牌。( D )
A、英文姓名
B、编号
C、中英文姓名
D、姓名、编号
31、【单选题】眉毛的疏密状态为:眉头和眉峰淡,眉腰()。( B )
A、轻
B、深
C、淡
D、暗
32、【单选题】画眉梢时,应()描画。( B )
A、向下、向外侧
B、斜向下
C、由内向外
D、横向外
33、【单选题】因皮肤向周围辐射(),所以辐射是机体散热方式之一。( A )
A、红外线
B、紫外线
C、光线
D、光波
34、【单选题】干性皮肤按摩时,以()法为主进行深层按摩10—15min。( B )
A、捏按
B、按抚
C、揉捏
D、打圈
35、【单选题】用磨砂膏做面部脱屑,()部位时间可以稍长一些。( D )
A、两颊
B、口周
C、颈及耳后
D、“T”字区
36、【单选题】美容师为顾客介绍前,除熟悉业务,还要了解美容院的()( C )
A、店面设计
B、室内装潢
C、服务流程
D、组织结构
37、【单选题】“自我享受化妆的乐趣”是对画()妆型的建议。( D )
A、创意
B、个性
C、新娘
D、日妆
38、【单选题】面膜可以起到其他化妆品起不到的作用,但与()又有严格的区别。( D )
A、膏霜
B、凝胶
C、香脂
D、药品
39、【单选题】人体细胞具有()的功能。( B )
A、无性繁殖和能量转换
B、繁殖再生和新陈代谢
C、有丝分裂和分解转运
D、无丝分裂和能量代谢
40、【单选题】油性皮肤日常护理的重点是()。( A )
A、保湿
B、美白
C、滋润
D、抗敏
41、【单选题】仪器设备的检查是美容师在()时需要完成的工作。( D )
A、制定护理方案
B、店堂清洁
C、操作过程
D、护理准备
42、【单选题】人体毛发除唇红、手掌、()、乳头等部位外遍布全身皮肤。( D )
A、乳房
B、眼周
C、口周
D、指(趾)末节侧
43、【单选题】护肤类化妆品不能阻挡()对皮肤的伤害。( C )
A、环境温度变化
B、紫外线
C、致病菌
D、空气污染
44、【单选题】()纤维是真皮中的纤维结缔组织。( C )
A、肌
B、神经
C、弹力
D、感觉
45、【单选题】敷蜡膜前,应先将蜡膜融化,使其温度保持在()℃之间。( C )
A、20~30
B、25~35
C、42~45
D、50~70
46、【单选题】冷蜡脱腋毛时,应先将腋毛()再进行脱毛操作。( D )
A、消毒
B、梳顺
C、固定
D、剪短
47、【单选题】甲油胶在卸除时要打磨掉(),再用卸甲剂卸除。( C )
A、亮油
B、彩色胶
C、封层胶
D、底胶
48、【单选题】在服务工作中()是符合美容师礼貌待客的具体表现。( B )
A、多加恭维
B、周到耐心
C、投其所好
D、大加赞赏
49、【单选题】用美目贴粘出的双重睑一定要符合()型及眼睛生理活动规律。( C )
A、脸
B、妆
C、眼
D、眉
50、【单选题】美容师在接待顾客前应做到(),化淡妆,着工服,带工牌。( D )
A、涂指甲油
B、发型时尚
C、多喷香水
D、仪表整洁
以上是2020美容师(初级)模拟考试题库及美容师(初级)考试软件。支持全国各地区精准美容师(初级)考试试题,支持安全资格证,特种作业操作证,职业技能鉴定等工种题库练习。
-
安卓aide开发教程!各种风格的Android面试题进来了解一下,成功入职腾讯
2021-02-27 21:18:19热修复就是通过下发补丁包,让已安装的客户端动态更新,用户不用重新安装APP,就能够修复软件缺陷。 2、热修复的优势和不足? 优势: 无需重新发布版本;用户无感知修复,代价小;修复成功率高,把损失降到最低。 ... -
2020设备方向-岗位技能(质量员)考试题及设备方向-岗位技能(质量员)模拟考试软件
2020-09-02 14:58:312020设备方向-岗位技能(质量员)考试题及设备方向-岗位技能(质量员)模拟考试软件,包含设备方向-岗位技能(质量员)考试题答案解析及设备方向-岗位技能(质量员)模拟考试软件练习。由安全生产模拟考试一点通公众号结合... -
【tensorrt】——相关库的说明
2020-11-06 16:54:30这些开放源码软件组件是TensorRT通用可用性(GA)发行版的一个子集,带有一些扩展和错误修复。简单来说,该仓库就是tensorrt GA的子集+拓展+例子,不能脱离 tensorrt GA tensorrt GA 这才是tenso.. -
beckett:Beckett是一个基于约定的框架,用于围绕HTTP API构建Python客户端-源码
2021-03-02 13:10:51:dizzy: 贝克特 超媒体API客户端框架 Beckett是基于约定的框架,用于围绕HTTP API构建Python接口。 :books: 文献资料 :open_book: 特征 ...该程序包是使用创建的。 我们使用来谈论HTTP。 免费软件:ISC -
Android技术背后涉及到了多少知识点?
2020-08-17 22:30:52热修复就是通过下发补丁包,让已安装的客户端动态更新,用户不用重新安装APP,就能够修复软件缺陷。 本文将从以下方面为大家详解热修复技术: 什么是热修复? 热修复的优势和不足? 热修复框架分类 技术原理... -
H5智能内核-基于MVC架构的全新Zoomla!逐浪CMS2 x3.8发布
2016-11-16 13:58:04北京时间2016年11月16日,国内领先的WEB与移动内核软件研发厂商-Zoomla!逐浪CMS团队发布其年度最后一个大作,也是目前国内首个基于MVC架构的厂商级dotNET框架CMS- Zoomla!逐浪2 x3.8 众所周知,目前面向云与... -
从零开始学数据结构和算法:从外包月薪5K到阿里月薪15K,先收藏了
2021-02-03 16:01:38努力的人,应该像好色那样好学 做Android开发的同学,对Gradle肯定不陌生,我们用它配置、构建工程,可能...热修复就是通过下发补丁包,让已安装的客户端动态更新,用户不用重新安装APP,就能够修复软件缺陷。 2、热. -
TensorRT:TensorRT是一个C ++库,用于在NVIDIA GPU和深度学习加速器上进行高性能推理-源码
2021-02-05 09:38:16这些开源软件组件是TensorRT General Availability(GA)版本的子集,具有某些扩展和错误修复。 有关对TensorRT-OSS的代码贡献,请参阅我们的和。 有关TensorRT-OSS版本附带的新增功能和更新的摘要,请参阅 。 ... -
工程硕士学位论文 基于Android+HTML5的移动Web项目高效开发探究
2017-02-28 21:22:19优雅降级 一开始就构建站点的完整功能,然后针对浏览器测试和修复。认为应该针对那些最高级、最完善的浏览器来开发网站。而将那些被认为“过时”或有功能缺失的浏览器下的测试工作安排在开发周期的最后阶段 渐进增强... -
libev :功能齐全,高性能的时间循环,轻微地仿效libevent,但是不再像libevent一样有局限性,也修复了它的一些bug。 libevent :事件通知库。 libhv:跨平台的事件循环库。 libuv :跨平台异步I/O。 promise-...
-
Foxit Mobile PDF Reader v2.2.0.0616.zip
2019-07-13 16:55:10运行稳定、响应速度快、界面简洁易用,并包含步进式解析/显示、内存不足自动修复等功能,大大提升最终用户的阅读体验。 更新日志 1. 新功能:支持带有压感效果的铅笔注释 2. 修复:公有云服务登录的问题 3. 修复... -
foxitbanner_GA_FoxitInst.exe
2019-11-20 15:04:10它包含了SDK开发包的所有重要功能例如步进式解析/显示、内存不足(Out-of-memory)自动修复功能。凭借这些新技术,新版本与以前的版本相比更加趋于稳定、响应速度更快、界面更加简洁易用。 1.1版本新增功能 ... -
DirectShow分离器和音视解码器(LAV Filters) v0.60.1.rar
2019-07-10 02:56:16DirectShow分离器和音视解码器(LAV Filters)汉化版是一组基于 ffmpeg 项目中的 libavformat/libavcodec 库的 DirectShow 分离器...- 修复一处可能会导致音频偶尔卡顿的 DTS 解析问题 - 改进对 Opus 音频预跳的支持 -
Url重写篇视频------本讲将通过实例比较ASP.NET下的三种典型URL重写方案
2009-04-22 08:15:51我们知道,IIS可以忽略对链接的虚拟目录是否存在的检测,但是,却无法检测非ASP.NET支持的文件扩展名的链接(我们固然可以在IIS中将所有类型的扩展名都映射到ASP.NET解析器,但是,如果我们有设置IIS的权限,为什么... -
Zabbix v3.4.5.zip
2019-07-06 13:18:38[ZBX-13024]修正了没有输入参数(Sasha)的URL解析“请求”; [ZBX-13153]修复了在缓存重新加载(vso)期间代理最后访问更新丢失的可能性; [ZBX-13149]在处理删除项目(雨刮器)时修复了历史同步器中可能发生的故障。 ...