Les risques de charger des bibliothèques so natives sur Android

1_wwcfXXOuWXtCdIso2xit1Q.png

  • 原标题 : Les dangers du chargement de bibliothèques natives sur Android
  • Adresse d'origine :  medium.com/keepsafe-en…
  • Auteur original : Hilal Alsibai
  • Date de publication originale : 7 novembre 2015

L'auteur a rencontré un problème l'année dernière : une fois le projet empaqueté dans un apkfichier, l'installation s'est déroulée normalement. Une fois le projet empaqueté dans un fichier , il s'est écrasé après aabavoir été bundleToolanalysé dans un apkfichier , mais après avoir téléchargé le fichier , il a été analysé dans un fichier et téléchargé et installé normalement.MMKVaabgooglePlayapk

En lisant cet article, vous comprendrez pourquoi ce problème se produit et comment le résoudre.

Traduction

Dans les premières 2012années de KeepSafe , nous avons essayé d'implémenter un schéma de chiffrement pour notre Androidapplication. Grâce à de nombreuses itérations et prototypes, nous avons trouvé un point idéal en tirant parti de la puissance de JNI (Java Native Interface). Nous avons décidé d'écrire l'interface dans Javala bibliothèque de chiffrement que nous utilisons dans , en JNIappelant la bibliothèque à des fins de chiffrement et de déchiffrement uniquement. Nous avons opté pour une solution immédiate avec le moins d'impact possible sur l'expérience utilisateur. Une fois satisfaits de notre solution, nous avons décidé de la déployer sur notre application de production. Nous avons rigoureusement testé notre code et avons pensé que tout se passerait bien, cependant, les choses ont fini par échapper à notre contrôle.

UnsatisfiedLinkErrorÉmergence

Alors que nous mettions à jour avec impatience le rapport de plantage après le lancement, nous avons commencé à remarquer un bogue récurrent. L' utilisateur l'a rencontré UnsatisfiedLinkError, ce qui signifie qu'il y a deux possibilités : (1) la bibliothèque native que nous appelons n'existe pas ; (2) la méthode native que nous appelons n'existe pas. Étant donné que le second est presque toujours capturé par la compilation et les tests de base, nous sommes actuellement confus par le fait que l'installation de l'utilisateur ne dispose pas de APKla bibliothèque native que nous fournissons dans .so

Voici quelques fichiers journaux :

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)
复制代码

très rageant ça

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)
复制代码

Il n'y a pas de modèle clair auquel la bibliothèque est en faute, car il semble que toutes les sobibliothèques lèvent des exceptions. Ce Androidn'est pas spécifique à une version , cela ne se produit pas uniquement sur des appareils spécifiques. De plus, dans certains cas, certaines bibliothèques natives sont chargées correctement, mais pas toutes. À ce stade, nous cherchons frénétiquement sur Internet des réponses ou de l'aide, pour revenir les mains vides. Nous avons commencé à publier des correctifs, principalement des correctifs spéculatifs, des données de trace supplémentaires afin que nous puissions mieux comprendre l'environnement exact lorsque le plantage s'est produit, et un morceau de code qui vérifie spécifiquement les bibliothèques natives à l'emplacement d'installation prévu.

De plus, dans certains cas, certaines bibliothèques natives sont chargées correctement, mais pas toutes.

Les informations que nous avons recueillies montrent que la bibliothèque native n'existe pas. Une erreur de classe système ou de système de fichiers n'est pas un hasard étrange, mais l'appareil de cet utilisateur semble fonctionner correctement. Nous avons les idées suivantes :

(1) Espace insuffisant sur l'équipement de l'utilisateur

Lorsque nous avons réfléchi aux raisons possibles de cette exception, nous avons commencé à penser que les gens n'avaient peut-être tout simplement pas l'espace pour installer correctement la bibliothèque native, donc elle n'a jamais été installée. Une vérification diagnostique rapide avant d'essayer de charger la bibliothèque a rapidement prouvé que cette idée était fausse. Les utilisateurs disposent de suffisamment d'espace sur leurs appareils pour la bibliothèque que nous expédions.

(2) soLa bibliothèque n'est pas incluse dans la mise à jour

造成我们问题的第二个可能原因是Google Play在向用户设备提供APK时破坏了我们的APK。在阅读了诸如此类的报告后,我们对这个想法有了一些支持,详细说明Google Play应该向所有受问题影响的应用程序开发人员发出通知,该问题导致用户在更新后无法启动他们的应用程序,因为本地库安装不正确。唯一的问题是这份报告是在8月发布的,而我们在几个月后才开始处理这个问题。我们也从未收到来自Google Play的通知,提到他们有任何错误。当然,这是很难验证的。

(3)直接与真实用户一起调试问题

由于我们无法在手头的10多种不同设备上重现该问题,因此我们决定联系遇到问题的用户。一位用户慷慨地决定帮助我们,并指出该应用程序在最新更新之前运行良好。这里的问题是,用户注意到的应用程序版本是一个包含我们的加密代码和本机库的版本,这只是为了增加我们的困惑和总体难题。我们决定直接向用户提供一个APK文件,我们在其中验证了所有本机库都存在于APK文件中。用户安装了APK,启动了应用程序,然后又直接遇到了同样的UnsatisfiedLinkError异常。这证实了不是Google Play的问题,问题在于AndroidPackageManager安装过程

找到解决方案

由于我们发现问题出在安装过程中,因此我们决定复制安装过程中提取应用程序代码中的本机库的部分。幸运的是,您可以通过以下方式轻松获取设备上应用程序APK文件的引用

Context.getApplicationInfo().sourceDir;
复制代码

Nous l'utiliserons ensuite pour extraire la bibliothèque native vers un emplacement de stockage interne. Comme APKles fichiers ne sont que ZIPdes fichiers, écrivez simplement du ZIPcode d'extraction. Nous avons pu extraire le code et l'expédier rapidement, ce qui a entraîné une énorme baisse du nombre de plantages ! Le nombre total d' UnsatisfiedLinkErrorexceptions dans la figure :

1_QDcE8GYO_YVJrzrjBUg94A.png

Afin de réduire notre APKtaille et de nous assurer que notre application peut fonctionner sur tous les appareils possibles, nous avons conçu notre application pour les x86, etArmv7 . ArmChaque saveur ne contient que la bibliothèque native correspondant à son architecture respective, il est donc tout à fait possible que quelqu'un puisse installer quelque chose qui n'est pas conçu pour l'architecture de son appareil APK.

Nous avons commencé à consigner les noms des packages d'installation dans les plantages et avons rapidement découvert que oui, les utilisateurs installaient des applications à partir de diverses sources, et chaque nouvelle provenait UnsatisfiedLinkErrord'une application installée manuellement que l'utilisateur a installée par erreur pour la mauvaise abiarchitecture de son appareil. C'est le "gotcha" final, et nous sommes soulagés qu'il y ait une explication très simple.

présenterReLinker

Nous avons décidé de regrouper le code d'extraction dans une petite bibliothèque que tout le monde peut utiliser. Personne ne devrait jamais passer par le processus de débogage que nous traversons, en particulier lorsqu'il s'agit d'une Androidfonction très basique qui échappe au Appcontrôle du développeur.

Utilisation ReLinkeraussi simple que le remplacement de la norme

System.loadLibrary(“mylibrary”);
复制代码

utiliser le rappel

ReLinker.loadLibrary(context, “mylibrary”)
复制代码

Code source du ReLinker

Épilogue

Au moment de la publication du correctif, le nombre de personnes confrontées à ce crash continuait d'atteindre environ 100,000. Nous espérons que vous le trouverez ReLinkerutile et que vous ne le rencontrerez plus jamais par hasard UnsatisfiedLinkerError.

Je suppose que tu aimes

Origine juejin.im/post/7078905989591728158
conseillé
Classement