java.lang.IncompatibleClassChangeError: retrofit2.converter.gson.GsonConverterFactory at dalvik.system.DexFile.defineClassNative(Native Method) at dalvik.system.DexFile.defineClass(DexFile.java:226) at dalvik.system.DexFile.loadClassBinaryName(DexFile.java:219) at dalvik.system.DexPathList.findClass(DexPathList.java:339) at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:54) at java.lang.ClassLoader.loadClass(ClassLoader.java:511) at java.lang.ClassLoader.loadClass(ClassLoader.java:469) at
安卓8.0机器:
java.lang.IncompatibleClassChangeError: Structural change of retrofit2.Converter$Factory is hazardous (/data/app/com.xxx.xx-2zz63J0ZnL47Rw6U5B3wfw==/oat/arm/base.odex at compile time, /data/app/com.xxx.tool-L0IRpZwtps6TiRfTUrRDAw==/oat/arm/base.odex at runtime): Direct method count off: 3 vs 1 Lretrofit2/Converter$Factory; (Compile time): Static fields: Instance fields: Direct methods: ()V getParameterUpperBound(ILjava/lang/reflect/ParameterizedType;)Ljava/lang/reflect/Type;
Adds a simple check to class-loading when the embedded dex file in an oat file and the dex file on the class path where we found the class do not match.
We require that the number of methods and fields do not change, as that will almost certainly mean that quickened and other compiled offsets are wrong now. This is a reasonably lightweight change, but we should investigate a full comparison including name and type of members.
This reverts commit fd9eb3923dcf417afcf5ed4ebb13867fd10f2de3.
Remove the simple structural check. Its naive expectations for resolution have been wrong since we introduced compiling APKs with a classpath for shared libraries and have never been updated.
所以,java.lang.IncompatibleClassChangeError: Structural change of ……. 这个错误波及范围是安卓5.1到安卓8.0。
// klass 表示当前加载的类 // dex_file 为当前加载的类所在的 dex 文件 // class_def 表示当前类在 dex 文件中的数据结构 // super_class 表示当前加载的父类,正常来说(app_image的场景除外)这个类是按照双亲委托模型加载的父类,而要校验的正是这个类 // Checks whether a the super-class changed from what we had at compile-time. This would // invalidate quickening. staticboolCheckSuperClassChange(Handle<mirror::Class> klass, const DexFile& dex_file, const DexFile::ClassDef& class_def, mirror::Class* super_class) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_){ // Check for unexpected changes in the superclass. // Quick check 1) is the super_class class-loader the boot class loader? This always has // precedence. if (super_class->GetClassLoader() != nullptr && // Quick check 2) different dex cache? Breaks can only occur for different dex files, // which is implied by different dex cache. klass->GetDexCache() != super_class->GetDexCache()) { // Now comes the expensive part: things can be broken if (a) the klass' dex file has a // definition for the super-class, and (b) the files are in separate oat files. The oat files // are referenced from the dex file, so do (b) first. Only relevant if we have oat files. const OatDexFile* class_oat_dex_file = dex_file.GetOatDexFile(); const OatFile* class_oat_file = nullptr; if (class_oat_dex_file != nullptr) { class_oat_file = class_oat_dex_file->GetOatFile(); } // class_oat_file不能为空 if (class_oat_file != nullptr) { const OatDexFile* loaded_super_oat_dex_file = super_class->GetDexFile().GetOatDexFile(); const OatFile* loaded_super_oat_file = nullptr; if (loaded_super_oat_dex_file != nullptr) { loaded_super_oat_file = loaded_super_oat_dex_file->GetOatFile(); }
if (loaded_super_oat_file != nullptr && class_oat_file != loaded_super_oat_file) { // Now check (a). const DexFile::ClassDef* super_class_def = dex_file.FindClassDef(class_def.superclass_idx_); if (super_class_def != nullptr) { // Uh-oh, we found something. Do our check. std::string error_msg; if (!SimpleStructuralCheck(dex_file, *super_class_def, super_class->GetDexFile(), *super_class->GetClassDef(), &error_msg)) { // Print a warning to the log. This exception might be caught, e.g., as common in test // drivers. When the class is later tried to be used, we re-throw a new instance, as we // only save the type of the exception. LOG(WARNING) << "Incompatible structural change detected: " << StringPrintf( "Structural change of %s is hazardous (%s at compile time, %s at runtime): %s", PrettyType(super_class_def->class_idx_, dex_file).c_str(), class_oat_file->GetLocation().c_str(), loaded_super_oat_file->GetLocation().c_str(), error_msg.c_str()); ThrowIncompatibleClassChangeError(klass.Get(), "Structural change of %s is hazardous (%s at compile time, %s at runtime): %s", PrettyType(super_class_def->class_idx_, dex_file).c_str(), class_oat_file->GetLocation().c_str(), loaded_super_oat_file->GetLocation().c_str(), error_msg.c_str()); returnfalse; } } } } } returntrue; }
std::vector<std::unique_ptr<const DexFile>> ClassLinker::OpenDexFilesFromOat( constchar* dex_location, constchar* oat_location, std::vector<std::string>* error_msgs) { CHECK(error_msgs != nullptr); ..... ..... // Check if we already have an up-to-date oat file open. //检查内存是否存在对应的oat文件 const OatFile* source_oat_file = nullptr; { ReaderMutexLock mu(Thread::Current(), dex_lock_); for (const OatFile* oat_file : oat_files_) { CHECK(oat_file != nullptr); if (oat_file_assistant.GivenOatFileIsUpToDate(*oat_file)) { source_oat_file = oat_file; break; } } }
// If we didn't have an up-to-date oat file open, try to load one from disk. //如果内存没有则从磁盘加载 if (source_oat_file == nullptr) { // Update the oat file on disk if we can. This may fail, but that's okay. // Best effort is all that matters here. // 关键地方:检查磁盘的oat文件是否需要更新 if (!oat_file_assistant.MakeUpToDate(&error_msg)) { LOG(WARNING) << error_msg; }
// Get the oat file on disk. // 从磁盘加载oat文件 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); if (oat_file.get() != nullptr) { // Take the file only if it has no collisions, or we must take it because of preopting. // 关键地方:检查待加载的oat文件是否和已经加载的存在类冲突 // 如果存在类冲突,考虑直接加载apk里面的dex文件 bool accept_oat_file = !HasCollisions(oat_file.get(), &error_msg); if (!accept_oat_file) { // Failed the collision check. Print warning. if (Runtime::Current()->IsDexFileFallbackEnabled()) { LOG(WARNING) << "Found duplicate classes, falling back to interpreter mode for " << dex_location; } else { LOG(WARNING) << "Found duplicate classes, dex-file-fallback disabled, will be failing to " " load classes for " << dex_location; } LOG(WARNING) << error_msg;
// However, if the app was part of /system and preopted, there is no original dex file // available. In that case grudgingly accept the oat file. // 系统应用大部分都会在编译服务器做dex优化,这时候apk里面就不会包含dex文件了。这种情况的话还是加载oat文件 if (!DexFile::MaybeDex(dex_location)) { accept_oat_file = true; LOG(WARNING) << "Dex location " << dex_location << " does not seem to include dex file. " << "Allow oat file use. This is potentially dangerous."; } }
// Load the dex files from the oat file. // 加载oat文件里面的dex文件 if (source_oat_file != nullptr) { dex_files = oat_file_assistant.LoadDexFiles(*source_oat_file, dex_location); if (dex_files.empty()) { error_msgs->push_back("Failed to open dex files from " + source_oat_file->GetLocation()); } }
// Fall back to running out of the original dex file if we couldn't load any // dex_files from the oat file. // 如果加载oat文件里面的dex文件失败,则直接尝试加载apk里面的dex文件。 if (dex_files.empty()) { if (oat_file_assistant.HasOriginalDexFiles()) { if (Runtime::Current()->IsDexFileFallbackEnabled()) { if (!DexFile::Open(dex_location, dex_location, &error_msg, &dex_files)) { LOG(WARNING) << error_msg; error_msgs->push_back("Failed to open dex files from " + std::string(dex_location)); } } else { error_msgs->push_back("Fallback mode disabled, skipping dex files."); } } else { error_msgs->push_back("No original dex files found for dex location " + std::string(dex_location)); } } return dex_files; }
// For b/21333911. // Only enabled for debug builds to prevent bit rot. There are too many performance regressions for // normal builds. staticconstexprbool kDuplicateClassesCheck = kIsDebugBuild;
06-24 16:56:07.393 21329 21384 I PackageManager.DexOptimizer: Running dexopt (dex2oat) on: /data/app/vmdl566966682.tmp/base.apk pkg=com.example.myapplication.myapplication isa=arm vmSafeMode=false debuggable=false oatDir = /data/app/vmdl566966682.tmp/oat 06-24 16:56:07.422 5953 5953 I dex2oat : Starting dex2oat. 06-24 16:56:07.874 5953 5958 I dex2oat : Skipping compilation of long com.alibaba.fastjson.parser.JSONLexer.longValue(): it contains a non natural loop 06-24 16:56:07.933 5953 5958 I dex2oat : Skipping compilation of double[] com.alibaba.fastjson.parser.JSONLexer.scanFieldDoubleArray(long): it contains a non natural loop 06-24 16:56:07.963 5953 5958 I dex2oat : Skipping compilation of float[] com.alibaba.fastjson.parser.JSONLexer.scanFieldFloatArray(long): it contains a non natural loop 06-24 16:56:09.083 5953 5953 I dex2oat : dex2oat took 1.659s (threads: 4) arena alloc=10MB java alloc=971KB native alloc=15MB free=600KB
06-24 16:11:56.975 24635 24635 W art : wesley GivenOatFileIsUpToDate is false, dex_location:/data/app/com.example.myapplication.myapplication-2/base.apk 06-24 16:11:56.975 24635 24635 W art : wesley source_oat_file is null 06-24 16:11:56.979 24635 24635 W art : wesley :GetDexOptNeeded: kNoDexOptNeeded 06-24 16:11:56.979 24635 24635 W art : wesley MakeUpToDate success 06-24 16:11:56.979 24635 24635 W art : wesley accept_oat_file:1 06-24 16:11:57.050 24635 24635 W art : wesley GivenOatFileIsUpToDate is false, dex_location:/data/app/plugin.platform-1/base.apk 06-24 16:11:57.050 24635 24635 W art : wesley GivenOatFileIsUpToDate is false, dex_location:/data/app/plugin.platform-1/base.apk 06-24 16:11:57.050 24635 24635 W art : wesley source_oat_file is null 06-24 16:11:57.053 24635 24635 W art : wesley :GetDexOptNeeded: kNoDexOptNeeded 06-24 16:11:57.053 24635 24635 W art : wesley MakeUpToDate success 06-24 16:11:57.053 24635 24635 W art : wesley accept_oat_file:1
06-24 16:11:57.063 24635 24635 W art : wesley GivenOatFileIsUpToDate is false, dex_location:/data/user/0/com.example.myapplication.myapplication/files/Plugin.apk 06-24 16:11:57.063 24635 24635 W art : wesley GivenOatFileIsUpToDate is false, dex_location:/data/user/0/com.example.myapplication.myapplication/files/Plugin.apk 06-24 16:11:57.063 24635 24635 W art : wesley GivenOatFileIsUpToDate is false, dex_location:/data/user/0/com.example.myapplication.myapplication/files/Plugin.apk 06-24 16:11:57.063 24635 24635 W art : wesley source_oat_file is null 06-24 16:11:57.063 24635 24635 W art : wesley :GetDexOptNeeded HasOriginalDexFiles: 1 06-24 16:11:57.107 24661 24661 E dex2oat : Failed to create oat file: /data/dalvik-cache/arm64/data@user@0@com.example.myapplication.myapplication@files@Plugin.apk@classes.dex: Permission denied 06-24 16:11:57.107 24661 24661 I dex2oat : dex2oat took 295.167us (threads: 4) 06-24 16:11:57.108 24635 24635 W art : wesley MakeUpToDate fail: Failed execv(/system/bin/dex2oat --runtime-arg -classpath --runtime-arg --instruction-set=arm64 --instruction-set-features=smp,a53 --runtime-arg -Xrelocate --boot-image=/system/framework/boot.art --runtime-arg -Xms64m --runtime-arg -Xmx512m --instruction-set-variant=generic --instruction-set-features=default --dex-file=/data/user/0/com.example.myapplication.myapplication/files/Plugin.apk --oat-file=/data/dalvik-cache/arm64/data@user@0@com.example.myapplication.myapplication@files@Plugin.apk@classes.dex) because non-0 exit status 06-24 16:11:57.108 24635 24635 W art : wesley oat_file is null: 06-24 16:11:57.108 24635 24635 W art : wesley :HasOriginalDexFiles true 06-24 16:11:57.121 24635 24635 W art : wesley :load OriginalDexFiles success