- 原标题: Die Gefahren des Ladens nativer Bibliotheken auf Android
- Ursprüngliche Adresse: medium.com/keepsafe-en…
- Ursprünglicher Autor: Hilal Alsibai
- Zeitpunkt der Erstveröffentlichung: 7. November 2015
Der Autor stieß letztes Jahr auf ein Problem: Nachdem das Projekt in eine apk
Datei gepackt wurde, verlief die Installation normal. Nachdem das Projekt in eine Datei gepackt wurde, stürzte es nach aab
dem bundleTool
Parsen in eine apk
Datei ab, aber nach dem Hochladen der Datei wurde es geparst eine Datei und normal heruntergeladen und installiert.MMKV
aab
googlePlay
apk
Wenn Sie diesen Artikel lesen, können Sie verstehen, warum dieses Problem auftritt und wie Sie dieses Problem lösen können.
Übersetzung
In den Anfangsjahren 2012
von KeepSafe haben wir versucht, ein Verschlüsselungsschema für unsere Android
Anwendung zu implementieren. Durch viele Iterationen und Prototypen haben wir einen idealen Punkt gefunden, indem wir die Leistungsfähigkeit von JNI (Java Native Interface) genutzt haben. Java
Wir haben uns entschieden, die Schnittstelle in die Verschlüsselungsbibliothek zu schreiben, die wir in verwenden, indem wir JNI
die Bibliothek nur für Verschlüsselungs- und Entschlüsselungszwecke aufrufen. Wir haben uns für eine sofortige Lösung mit möglichst geringen Auswirkungen auf die Benutzererfahrung entschieden. Nachdem wir mit unserer Lösung zufrieden waren, entschieden wir uns, sie in unserer Produktionsanwendung bereitzustellen. Wir haben unseren Code rigoros getestet und glaubten, dass alles glatt gehen würde, aber die Dinge endeten außerhalb unserer Kontrolle.
UnsatisfiedLinkError
Entstehung
Als wir den Absturzbericht nach dem Start ängstlich aktualisierten, bemerkten wir einen wiederkehrenden Fehler. Der Benutzer ist darauf gestoßen UnsatisfiedLinkError
, was bedeutet, dass es zwei Möglichkeiten gibt: (1) die native Bibliothek, die wir aufrufen, existiert nicht; (2) die native Methode, die wir aufrufen, existiert nicht. Da die zweite fast immer durch das Kompilieren und grundlegende Testen abgefangen wird, sind wir im Moment verwirrt darüber, dass die Installation des Benutzers nicht über APK
die native Bibliothek verfügt, die wir in .so
Hier sind einige Protokolldateien:
java.lang.UnsatisfiedLinkError: Couldn’t load stlport_shared from loader dalvik.system.PathClassLoader[dexPath=/data/app/com.kii.safe-1.apk,libraryPath=/data/app-lib/com.kii.safe-1]: findLibrary returned null\
at java.lang.Runtime.loadLibrary(Runtime.java:365)\
at java.lang.System.loadLibrary(System.java:535)\
at com.kii.safe.Native.<clinit>(Native.java:16)\
… 63 more
Caused by: java.lang.UnsatisfiedLinkError: Library stlport_shared not found\
at java.lang.Runtime.loadLibrary(Runtime.java:461)\
at java.lang.System.loadLibrary(System.java:557)\
at com.kii.safe.Native.<clinit>(Native.java:16)\
… 5 more
Caused by: java.lang.UnsatisfiedLinkError: Cannot load library: get_lib_extents[760]: 1305 — /mnt/asec/com.kii.safe-1/lib/libstlport_shared.so is not a valid ELF object\
at java.lang.Runtime.loadLibrary(Runtime.java:434)\
at java.lang.System.loadLibrary(System.java:554)\
at com.kii.safe.Native.<clinit>(Native.java:15)
Caused by: java.lang.UnsatisfiedLinkError: Library cryptopp not found\
at java.lang.Runtime.loadLibrary(Runtime.java:461)\
at java.lang.System.loadLibrary(System.java:557)\
at com.kii.safe.Native.<clinit>(Native.java:17)
复制代码
sehr ärgerlich das
Caused by: java.lang.UnsatisfiedLinkError: Cannot load library: reloc_library[1286]: 1748 cannot locate ‘쯰ҷЦf1Ϙ˗˞ք0Ⱉض夘Ϛ.͏闑㥁ج뭫ර⓻в^ӎ3c`+W#Ҽ?-Bַˌ֕꼠’…\
at java.lang.Runtime.loadLibrary(Runtime.java:370)\
at java.lang.System.loadLibrary(System.java:535)\
at com.kii.safe.Native.<clinit>(Native.java:17)
Caused by: java.lang.UnsatisfiedLinkError: Cannot load library: reloc_library[1312]: 1327 cannot locate ‘Pܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭXߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭXߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#\
at java.lang.Runtime.loadLibrary(Runtime.java:434)\
at java.lang.System.loadLibrary(System.java:554)\
at com.kii.safe.Native.<clinit>(Native.java:17)
复制代码
Es gibt kein klares Muster, an dem die Bibliothek schuld ist, da anscheinend alle so
Bibliotheken Ausnahmen auslösen. Es Android
ist nicht versionsspezifisch , es passiert nicht nur auf bestimmten Geräten. Außerdem werden in einigen Fällen einige native Bibliotheken korrekt geladen, aber nicht alle. An diesem Punkt suchen wir fieberhaft im Internet nach Antworten oder Hilfe, nur um mit leeren Händen zurückzukommen. Wir haben damit begonnen, Fixes zu veröffentlichen, hauptsächlich spekulative Fixes, zusätzliche Trace-Daten, damit wir die genaue Umgebung besser verstehen konnten, als der Absturz auftrat, und einen Code, der speziell nach nativen Bibliotheken am erwarteten Installationsort sucht.
Außerdem werden in einigen Fällen einige native Bibliotheken korrekt geladen, aber nicht alle.
Die von uns gesammelten Informationen zeigen, dass die native Bibliothek nicht existiert. Ein Systemklassen- oder Dateisystemfehler ist kein seltsamer Zufall, aber das Gerät dieses Benutzers scheint in Ordnung zu sein. Wir haben folgende Ideen:
(1) Unzureichender Platz auf der Benutzerausrüstung
Als wir über die möglichen Gründe für diese Ausnahme nachdachten, begannen wir zu denken, dass die Leute vielleicht einfach nicht den Platz hatten, um die native Bibliothek richtig zu installieren, also wurde sie nie installiert. Eine schnelle Diagnoseprüfung vor dem Versuch, die Bibliothek zu laden, hat diese Idee schnell als falsch erwiesen. Benutzer haben genügend Speicherplatz auf ihren Geräten für die Bibliothek, die wir versenden.
(2) so
Die Bibliothek ist nicht im Update enthalten
造成我们问题的第二个可能原因是Google Play
在向用户设备提供APK
时破坏了我们的APK
。在阅读了诸如此类的报告后,我们对这个想法有了一些支持,详细说明Google Play
应该向所有受问题影响的应用程序开发人员发出通知,该问题导致用户在更新后无法启动他们的应用程序,因为本地库安装不正确。唯一的问题是这份报告是在8
月发布的,而我们在几个月后才开始处理这个问题。我们也从未收到来自Google Play
的通知,提到他们有任何错误。当然,这是很难验证的。
(3)直接与真实用户一起调试问题
由于我们无法在手头的10
多种不同设备上重现该问题,因此我们决定联系遇到问题的用户。一位用户慷慨地决定帮助我们,并指出该应用程序在最新更新之前运行良好。这里的问题是,用户注意到的应用程序版本是一个包含我们的加密代码和本机库的版本,这只是为了增加我们的困惑和总体难题。我们决定直接向用户提供一个APK
文件,我们在其中验证了所有本机库都存在于APK
文件中。用户安装了APK
,启动了应用程序,然后又直接遇到了同样的UnsatisfiedLinkError
异常。这证实了不是Google Play
的问题,问题在于Android
的PackageManager
安装过程。
找到解决方案
由于我们发现问题出在安装过程中,因此我们决定复制安装过程中提取应用程序代码中的本机库的部分。幸运的是,您可以通过以下方式轻松获取设备上应用程序APK
文件的引用
Context.getApplicationInfo().sourceDir;
复制代码
Wir werden dies dann verwenden, um die native Bibliothek an einen internen Speicherort zu extrahieren. Da APK
Dateien nur ZIP
Dateien sind, schreiben Sie einfach einen ZIP
Extraktionscode. Wir konnten den Code abrufen und schnell versenden, was zu einem enormen Rückgang der Anzahl der Abstürze führte! Die Gesamtzahl der jeden Tag ausgelösten UnsatisfiedLinkError
Ausnahmen in der Abbildung dargestellt:
Um unsere APK
Größe zu reduzieren und sicherzustellen, dass unsere Anwendung auf allen möglichen Geräten ausgeführt werden kann, haben wir unsere Anwendung für x86
, , undArmv7
entwickelt. Arm
Jede Variante enthält nur die native Bibliothek, die ihrer jeweiligen Architektur entspricht, sodass es durchaus möglich ist, dass jemand etwas installiert, das nicht für seine Gerätearchitektur entwickelt wurde APK
.
Wir begannen, Installationspaketnamen bei Abstürzen zu protokollieren und stellten schnell fest, dass Benutzer Apps aus verschiedenen Quellen installierten und jede neue UnsatisfiedLinkError
von einer manuell installierten App stammte, die der Benutzer versehentlich für die falsche abi
Architektur seines Geräts installiert hatte. Dies ist der letzte „Fallfang“, und wir sind erleichtert, dass es eine sehr einfache Erklärung gibt.
einführenReLinker
Wir haben uns entschieden, den Extraktionscode in eine kleine Bibliothek zu packen, die jeder verwenden kann. Niemand sollte jemals den Debugging-Prozess durchlaufen, den wir durchlaufen, insbesondere wenn es sich um eine sehr grundlegende Android
Funktion handelt, die außerhalb der App
Kontrolle des Entwicklers liegt.
Die Verwendung ReLinker
ist so einfach wie das Ersetzen des Standards
System.loadLibrary(“mylibrary”);
复制代码
Rückruf nutzen
ReLinker.loadLibrary(context, “mylibrary”)
复制代码
Epilog
Zum Zeitpunkt der Veröffentlichung des Fixes erreichte die Zahl der Personen, die diesen Absturz erlebten, weiterhin ca. 100,000
. Wir hoffen, dass Sie ReLinker
es nützlich finden und ihm nie wieder zufällig begegnen werden UnsatisfiedLinkerError
.