Analyse d'une exception Android
Suite a une mise à jour de mon Fairephone 5, j'ai rencontré un problème de plantage récurrent du processus "quickstep".
Avec l'aide de adb log
, j'ai pu capturer la stacktrace au moment de l'exception.
08-13 08:56:19.945 24611 24611 E AndroidRuntime: FATAL EXCEPTION: main
08-13 08:56:19.945 24611 24611 E AndroidRuntime: Process: com.android.launcher3, PID: 24611
08-13 08:56:19.945 24611 24611 E AndroidRuntime: java.lang.NullPointerException: Attempt to invoke virtual method ‘boolean java.lang.String.contains(java.lang.CharSequence)’ on a null object reference
08-13 08:56:19.945 24611 24611 E AndroidRuntime: at com.android.launcher3.uioverrides.QuickstepLauncher.isOrangeApp(QuickstepLauncher.java:1049)
08-13 08:56:19.945 24611 24611 E AndroidRuntime: at com.android.launcher3.uioverrides.QuickstepLauncher.onStateSetEnd(QuickstepLauncher.java:621)
08-13 08:56:19.945 24611 24611 E AndroidRuntime: at com.android.launcher3.uioverrides.QuickstepLauncher.onStateSetEnd(QuickstepLauncher.java:222)
08-13 08:56:19.945 24611 24611 E AndroidRuntime: at com.android.launcher3.statemanager.StateManager.onStateTransitionEnd(StateManager.java:426)
08-13 08:56:19.945 24611 24611 E AndroidRuntime: at com.android.launcher3.statemanager.StateManager.-$$Nest$monStateTransitionEnd(Unknown Source:0)
08-13 08:56:19.945 24611 24611 E AndroidRuntime: at com.android.launcher3.statemanager.StateManager$1.onAnimationSuccess(StateManager.java:402)
On peut voir ici que le problème provient de la comparaison d'une chaine avec un objet non initialisé null
, le tout localisé dans une méthode isOrangeApp().
En l'absence du code source, on ne peut pas aller plus loin dans le diagnostic.
Essayons de récupérer le bytecode java correspondant pour en savoir plus.
Creusons un peu
- Récupération du package
# Recherche du package
$ adb shell pm path com.android.launcher3
package:/system_ext/priv-app/SearchLauncherQuickStep/SearchLauncherQuickStep.apk
# Récupération du package
$ adb pull /system_ext/priv-app/SearchLauncherQuickStep/SearchLauncherQuickStep.apk
/system_ext/priv-app/SearchLauncherQuickStep/SearchLauncherQuickStep.apk: 1 file pulled, 0 skipped. 38.4 MB/s (34732758 bytes in 0.862s)
- Analyse
# Installation de la boite à outils
$ yay -S android-apktool-bin
# Décompilation...
$ apktool d SearchLauncherQuickStep.apk
Un petit grep pour trouver la fonction isOrangeApp:
.method private isOrangeApp()Z
...
const-string v1, "def_operator_applist"
invoke-static {v0, v1}, Landroid/provider/Settings$Secure;->getString(Landroid/content/ContentResolver;Ljava/lang/String;)Ljava/lang/String;
:cond_0
sget-object v3, Lcom/android/launcher3/uioverrides/QuickstepLauncher;->operatorAppPackageListForOrange:[[Ljava/lang/String;
const/4 v4, 0x0
aget-object v3, v3, v4
aget-object v3, v3, v4
invoke-virtual {v0, v3}, Ljava/lang/String;->contains(Ljava/lang/CharSequence;)Z <<<<<<<<<<<<<<<<<<<<<<------- ICI ???
Le lecture du pseudocode de la fonction indique l'utilisation de String.Contains sur une variable issue d'un Setting Secure GetString "def_operator_applist" ...
Quick and dirty fix
Idéalement, il faudrait comprendre pourquoi un objet n'est pas initialisé, et corriger le code de isOrangeApp() pour prendre en compte ce cas.
En attendant le correctif, je positionne cette valeur en attentant un correctif plus propre.
$ adb shell settings get secure def_operator_applist
null
$ adb shell settings put secure def_operator_applist "of.dummy.package"
$ adb shell settings get secure def_operator_applist
of.dummy.package
.. A voir les éventuels effets de bord si cette variable est utilisée par ailleurs.