應用啟動時,tinker的verifyclass
阿新 • • 發佈:2018-11-01
如果自己的專案使用了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<mirror::DexCache> dex_cache, 265 Handle<mirror::ClassLoader> 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<mirror::DexCache> dex_cache, 170 Handle<mirror::ClassLoader> 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了。