如果自己的项目使用了tinker热补丁,那么,会发现,启动应用时的systrace图如下,会多出一坨的verifyclass片段,导致时间慢了很多。
这段verifyclass的代码如下
http://androidxref.com/7.1.1_r6/xref/art/runtime/verifier/method_verifier.cc#262
262MethodVerifier::FailureKind MethodVerifier::VerifyClass(Thread* self,
263 const DexFile* dex_file,
264 Handle dex_cache,
265 Handle class_loader,
266 const DexFile::ClassDef* class_def,
267 CompilerCallbacks* callbacks,
268 bool allow_soft_failures,
269 LogSeverity log_level,
270 std::string* error) {
271 DCHECK(class_def != nullptr);
272 ScopedTrace trace(__FUNCTION__);
273
274 // A class must not be abstract and final.
275 if ((class_def->access_flags_ & (kAccAbstract | kAccFinal)) == (kAccAbstract | kAccFinal)) {
276 *error = "Verifier rejected class ";
277 *error += PrettyDescriptor(dex_file->GetClassDescriptor(*class_def));
278 *error += ": class is abstract and final.";
279 return kHardFailure;
280 }
281
android 6.0也有这段代码,但是没有输出systrace
167MethodVerifier::FailureKind MethodVerifier::VerifyClass(Thread* self,
168 const DexFile* dex_file,
169 Handle dex_cache,
170 Handle class_loader,
171 const DexFile::ClassDef* class_def,
172 bool allow_soft_failures,
173 std::string* error) {
174 DCHECK(class_def != nullptr);
175
176 // A class must not be abstract and final.
177 if ((class_def->access_flags_ & (kAccAbstract | kAccFinal)) == (kAccAbstract | kAccFinal)) {
178 *error = "Verifier rejected class ";
179 *error += PrettyDescriptor(dex_file->GetClassDescriptor(*class_def));
180 *error += ": class is abstract and final.";
181 return kHardFailure;
182 }
183
184 const uint8_t* class_data = dex_file->GetClassData(*class_def);
185 if (class_data == nullptr) {
186 // empty class, probably a marker interface
187 return kNoFailure;
188 }
而且正常的base.apk是不会出现verifyclass的,原因是这里
http://androidxref.com/7.1.1_r6/xref/art/runtime/class_linker.cc#3945
3935 bool preverified = VerifyClassUsingOatFile(dex_file, klass.Get(), oat_file_class_status);
3936 // If the oat file says the class had an error, re-run the verifier. That way we will get a
3937 // precise error message. To ensure a rerun, test:
3938 // oat_file_class_status == mirror::Class::kStatusError => !preverified
3939 DCHECK(!(oat_file_class_status == mirror::Class::kStatusError) || !preverified);
3940
3941 verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure;
3942 std::string error_msg;
3943 if (!preverified) {
3944 Runtime* runtime = Runtime::Current();
3945 verifier_failure = verifier::MethodVerifier::VerifyClass(self,
3946 klass.Get(),
3947 runtime->GetCompilerCallbacks(),
3948 runtime->IsAotCompiler(),
3949 log_level,
3950 &error_msg);
3951 }
3952
这里,这里的条件是,
VerifyClassUsingOatFile
返回false才需要verifyclass,在010editor里,就是oat_class内的status的值,当这个值为10或者8时,就是dex2oat时已经verifyclass,并且把这个状态保存到了oat文件内。
base.apk在dex2oat时,就已经完成verifyclass,只有tinker的补丁classes2.dex classes3.dex在dex2oat时不能正常verifyclass,所以,启动时才需要verifyclass。
tinker在dex2oat时不能正常verifyclass的原因,是因为他是一个个dex文件进行dex2oat的,如果把它压缩成一整个apk,再进行dex2oat的话,就能完整verifyclass了。
此外,淘宝的插件化也存在这个问题,但是淘宝自己把自己的verify_标识置为0了。