In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/01 Report--
In the case analysis of UnsatisfiedLinkError caused by zipflinger, it is believed that many inexperienced people are at a loss about it. Therefore, this paper summarizes the causes and solutions of the problem. Through this article, I hope you can solve this problem.
The author does some development work in the Android source environment. A few days ago, I encountered a strange problem. The pre-installed APP suddenly reported the collapse of a UnsatisfiedLinkError. Check the record of recent changes, but upgrade AGP (Androidd gradle plugin) from version 3.6.1 to version 4.1.0.
The source code environment is Android 9.0 so app pre-installed under / system/priv-app, and so is included in the app. To simplify the problem, a minimalist Demo app is written, and the app is pre-installed under / system/priv-app. It is normal to use AGP 4.0 or below. Once you use an apk package typed out by AGP 4.1or above, you will report an error in UnsatisfiedLinkError.
App pre-installed configuration
Include $(CLEAR_VARS) LOCAL_MODULE: = MyTestApp.apkLOCAL_SRC_FILES: = $(LOCAL_MODULE). ApkLOCAL_MODULE_CLASS: = APPSLOCAL_MODULE_TAGS: = optionalLOCAL_MODULE_SUFFIX: = $(COMMON_ANDROID_PACKAGE_SUFFIX) LOCAL_CERTIFICATE: = PRESIGNEDLOCAL_PRIVILEGED_MODULE: = trueLOCAL_DEX_PREOPT: = nostrippinginclude $(BUILD_PREBUILT)
Error message
E AndroidRuntime: java.lang.UnsatisfiedLinkError: dlopen failed: library "/ not foundE AndroidRuntime: at java.lang.Runtime.loadLibrary0 (Runtime.java:1016) E AndroidRuntime: at java.lang.System.loadLibrary (System.java:1669).
The cause of the problem is obviously due to the upgrade of AGP to 4.1, but a look at the official changelog shows that there are no obvious changes related to the problem. Analysis of log found that so loading failed, but decompressed MyTestApp.apk pull, found that the so file exists, the path is not a problem, then where is the problem? at this time, we can only analyze the process of loading so in the system to see what the problem is.
There are many online articles loaded by So, so we will not analyze them one by one. Here is a list of call stacks.
Ojluni/src/main/java/java/lang/System.java-> System.loadLibraryojluni/src/main/java/java/lang/Runtime.java-- > Runtime.loadLibrary0-- > nativeLoadojluni/src/main/native/Runtime.c-- > Runtime_nativeLoadart/openjdkjvm/OpenjdkJvm.cc-- > JVM_NativeLoadart/runtime/java_vm_ext.cc-- > JavaVMExt::LoadNativeLibrarysystem/core/libnativeloader/native_loader.cpp-- > OpenNativeLibrarybionic/libdl/libdl.cpp-- > android_dlopen_ Extbionic/linker/dlfcn.cpp-- > _ _ loader_android_dlopen_extbionic/linker/dlfcn.cpp-- > dlopen_extbionic/linker/linker.cpp-- > do_dlopenbionic/linker/linker.cpp-- > find_librarybionic/linker/linker.cpp-- > find_librariesbionic/linker/linker.cpp-- > find_library_internalbionic/linker/linker.cpp-- > load_librarybionic/linker/linker.cpp-- > open_librarybionic/linker/linker.cpp-- > open_library_in_zipfile
After a large number of debug, it is finally found that the system will use the delimiter "! /" to separate the path / system account privashApp name MyTestApp. ApkApp * This part of the logic is in bionic/linker/linker.cpp-- > open_library_in_zipfile. The following condition entry.offset% PAGE_SIZE! = 0 caused the load to fail
If (entry.method! = kCompressStored | | (entry.offset% PAGE_SIZE)! = 0) {close (fd); return-1;}
From this we can infer that the problem should be related to zipalign. According to the official documentation, the purpose of zipalign is to ensure that the beginning of all uncompressed data performs a specific alignment relative to the beginning of the file. Specifically, it aligns all uncompressed data in APK, such as pictures or raw files, on a 4-byte boundary. In this way, you can use mmap () to access all parts directly, even if it contains binary data with alignment restrictions. The advantage of this is that you can reduce the RAM capacity consumed when running the application.
Obviously, the alignment of / system/priv-app/MyTestApp/MyTestApp.apk this apk should be problematic, let's do some verification. Get the apk pull out, execute the following command, and find that there is a problem.
Xxx@debian:~/workspace$ zipalign-c-v-p 4 MyTestApp.apk Verifying alignment of out.apk (4). 3964 lib/armeabi-v7a/libmytest.so (BAD-3964) 108038 META-INF/CERT.SF (OK-compressed) 108568 AndroidManifest.xml (OK-compressed) 109583 META-INF/CERT.RSA (OK-compressed) 110676 res/layout/activity_main.xml (OK-compressed) 111012 res/mipmap-xhdpi-v4/ic_launcher.png (OK) 115704 resources.arsc (OK) 116722 META-INF/MANIFEST.MF (OK-compressed) 117196 classes.dex (OK) Verification FAILED
So whether there is a problem with the apk generated by gradle packaging, let's verify the source file in the same way and find that it is no problem! Then the problem is obvious. Android must have done something to deal with the apk when compiling, resulting in a problem. So we need to look at the compilation-related processing.
The script for the BUILT_PREBUILT corresponding to the Android system is in build/core/prebuilt_internal.mk, where
Ifeq (true, $(LOCAL_UNCOMPRESS_DEX)) $(uncompress-dexs) endif # LOCAL_UNCOMPRESS_DEX
That is to say, if LOCAL_UNCOMPRESS_DEX is true, then apk will be processed by a uncompress-dexs, and uncompress-dexs is defined in build/core/definitions.mk.
# Uncompress dex files embedded in an apk.#define uncompress-dexs$ (hide) if (zipinfo $@'* .dex'2 > / dev/null | grep-v 'stor' > / dev/null); then\ tmpdir=$@.tmpdir;\ rm-rf $$tmpdir & & mkdir $$tmpdir;\ unzip-Q $@'* .dex'- d $tmpdir & &\ zip-qd $@'* .dex'& &\ (cd $tmpdir & & find. -type f | sort | zip-qD-X-0.. / $(notdir $@)-@) & &\ rm-rf $$tmpdir;\ fiendef
Analysis found that this process is to determine whether the dex suffix file in apk is compressed storage, if not compressed storage then do nothing, if compressed storage, then change it into uncompressed storage mode. (the storage methods of file items in zip files are divided into uncompressed storage (stored) and compressed storage (deflated))
After further analysis, it is found that after uncompress-dexs, the compiler also performs an align-package operation on the apk, and the definition is still in build/core/definitions.mk.
# Align STORED entries of a package on 4-byte boundaries to make them easier to mmap.#define align-package$ (hide) if! $(ZIPALIGN)-c $(ZIPALIGN_PAGE_ALIGN_FLAGS) 4 $@ > / dev/null; then\ mv $@ $@ .unchecked;\ $(ZIPALIGN)\-f\ $(ZIPALIGN_PAGE_ALIGN_FLAGS)\ 4\ $@ .unchecked $@ .ZIPALIGN;\ mv $@ .unlimited $@;\ fiendef
Now the problem is more obvious, that is, for the apk package typed by AGP4.1, after the uncompress-dexs operation, and then re-execute zipalign, there is a problem with the alignment of the generated apk file. In order to facilitate debug, a shell script uncompress-dexs is written for the corresponding operation of uncompress-dexs
So why does the system do this to apk? we don't seem to have defined the parameter LOCAL_UNCOMPRESS_DEX. Check the definition and usage of the parameter LOCAL_UNCOMPRESS_DEX in build/core/dex_preopt_odex_install.mk.
# We explicitly uncompress APKs of privileged apps, and used by# privileged appsLOCAL_UNCOMPRESS_DEX: = falseifneq (true,$ (DONT_UNCOMPRESS_PRIV_APPS_DEXS)) ifeq (true,$ (LOCAL_PRIVILEGED_MODULE)) LOCAL_UNCOMPRESS_DEX: = trueelse ifneq (, $(filter $(PRODUCT_LOADED_BY_PRIVILEGED_MODULES), $(LOCAL_MODULE)) LOCAL_UNCOMPRESS_DEX: = true endif # PRODUCT_LOADED_BY_PRIVILEGED_MODULESendif # LOCAL_PRIVILEGED_MODULEendif # DONT_UNCOMPRESS_PRIV_APPS_DEXS
The analysis shows that if DONT_UNCOMPRESS_PRIV_APPS_DEXS is the default value of false, then the system will uncompress-dexs privileged app, that is, app under / system/priv-app/.
So now we need to investigate what changes have been made to AGP4.1, so that the operation of uncompress-dexs will have an impact on zipalign.
After some search, it turns out that google has added a new packaging tool, zipflinger, since AGP version 3.6, but it only takes effect when building a debug version, but starting with AGP4.1, building a release version also enables zipflinger by default. You can disable zipflinger by adding the following attributes to gradle.properties
Android.useNewApkCreator=false
We used AGP4.1 to join this configuration packaging test and found that the problem was solved.
Although the problem is solved, can't we integrate apk packaged with zipflinger tools when the system is integrated? Now that google has launched this tool, it must have been fully tested. Since we are currently using the source code of Android 9.0, let's take a look at how this part of the code on the latest master is handled, and the code does find some changes. In the latest aosp source code, the implementation of uncompress-dexs is linked as follows
# Uncompress dex files embedded in an apk.#define uncompress-dexs if (zipinfo $@'* .dex'2 > / dev/null | grep-v 'stor' > / dev/null); then\ $(ZIP2ZIP)-I $@-o $@ .tmp-0 "classes*.dex" & &\ mv-f $@ .tmp $@;\ fiendef
We found that google uses a new tool, zip2zip, to handle the extraction of dex files in apk. We found the source code of this tool, which is actually a separate file, zip2zip.go written in go language. We downloaded the source code and compiled it into an executable file using the go build command. Here I compiled a zip2zip, and we used this tool to test the apk generated by zipflinger, and found that there was no problem.
Zip2zip-I MyTestApp.apk-o out.apk-0 classes.dexzipalign-f-p 4 out.apk MyTestApp.apkzipalign-c-v-p 4 MyTest.apk
At this point, the problem is finally solved. To sum up, it is a problem that an old version of AOSP is not compatible with the new zipflinger packaging tool. According to the analysis process, there are several solutions as follows:
Solution 1
Declare in the BoardConfig.mk file
DONT_UNCOMPRESS_PRIV_APPS_DEXS: = true
(this method is not recommended. This property will be declared only if there is not enough space in the partition, sacrificing a little bit of dex loading speed in exchange for space.)
Solution 2
Do not set it to privileged app when preloading APP
LOCAL_PRIVILEGED_MODULE: = false
This method of handling is not universal. Some app must be privileged.
Solution 3
Modify the uncompress-dexs method in build/core/definitions.mk and use the new zip2zip scheme to adapt
This method is feasible, but there are a lot of areas that need to be modified, and it is troublesome to update a lot of new AOSP code in the past.
Solution 4
Roll back the AGP version to 4. 0 or below (obviously this is not a good idea)
Solution 5 (recommended method)
Declare that zipflinger is disabled in the gradle.properties of app project
Android.useNewApkCreator=false
After reading the above, have you mastered the method of case analysis of UnsatisfiedLinkError caused by zipflinger? If you want to learn more skills or want to know more about it, you are welcome to follow the industry information channel, thank you for reading!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.