1. 程式人生 > >應用啟動時,tinker的verifyclass

應用啟動時,tinker的verifyclass

如果自己的專案使用了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檔案內。




當status<=6時,表示該class是沒有verify的,需要在啟動時verifyclass

base.apk在dex2oat時,就已經完成verifyclass,只有tinker的補丁classes2.dex classes3.dex在dex2oat時不能正常verifyclass,所以,啟動時才需要verifyclass。


tinker在dex2oat時不能正常verifyclass的原因,是因為他是一個個dex檔案進行dex2oat的,如果把它壓縮成一整個apk,再進行dex2oat的話,就能完整verifyclass了。

此外,淘寶的外掛化也存在這個問題,但是淘寶自己把自己的verify_標識置為0了。