Upon checking the question comments and in which devices this issue occurs, it appears it is specific to a subset of devices, such as OnePlus devices, and Samsung J series. The common part is for them to be Android 9 devices. I've examined the source code for Android 9 (here is the method call which is at line 5750 and here is the method itself which is at line 5520) and I can say this code is not related to configuration changes. While the links' line numbers are not exactly the same, they are related in the distance (e.g. 5750 - 5520 = 280 which is from the source code, and 6127 - 5892 = 285 which is from the stack trace. Quite close but not exact) so I am assuming the framework is calling that part. The method, ActivityThread.handleBindApplication
is called at first launch, and configuration changes happen only with activity recreations, the app's configuration does not change. At least, the given method is not called again.
I can also say that the method updateLocaleListFromAppContext
was successfully called and the code crashed inside the method, not at the start.
Here is the relevant part of the code:
/**
* The LocaleList set for the app's resources may have been shuffled so that the preferred
* Locale is at position 0. We must find the index of this preferred Locale in the
* original LocaleList.
*/
private void updateLocaleListFromAppContext(Context context, LocaleList newLocaleList) {
final Locale bestLocale = context.getResources().getConfiguration().getLocales().get(0);
final int newLocaleListSize = newLocaleList.size();
for (int i = 0; i < newLocaleListSize; i++) {
if (bestLocale.equals(newLocaleList.get(i))) {
LocaleList.setDefault(newLocaleList, i);
return;
}
}
// The app may have overridden the LocaleList with its own Locale
// (not present in the available list). Push the chosen Locale
// to the front of the list.
LocaleList.setDefault(new LocaleList(bestLocale, newLocaleList));
}
Now, there are a couple of things to consider,
- This is taken from AOSP (Open source project) and device manufacturers usually modify these core classes. The method inside the devices may have been modified, but it is a low possibility.
- Google Play Console can sometimes trim out the information about the stack trace.
- If the stack trace is exact, this method can only crash at
newLocaleList.size()
and bestLocale.equals(newLocaleList.get(i))
calls. The reason for that is: that when the stack traces are generated, their exception always contains the last code, and other lines would've left another stack trace.
- Another possibility is: that because of the for loop and the usage of
newLocaleListSize
, the newLocaleList
variable's size could've been changed while the code was iterating, causing the crash at newLocaleList.get(i)
. This one is a bit more unlikely though, since the get(i)
method would've been visible on crash, assuming the data is complete.
Based on the info, the most likely culprits are the variables bestLocale
and newLocaleList
in the method. Upon examining the source code more, the newLocaleList
variable which is passed, is created via AppBindData
which is passed down via a handler, and its information is updated in handleBindApplication
. The method calls specific information updates using Android's PackageManager, which is used to query information about the APK / loaded app, such as its info, manifest data, metadata, activities, etc...
This information is usually delivered from the system to the app using IPC (or AIDL) and that information can sometimes get corrupt, causing this error. Thus, it may be possible that newLocaleList
variable is null.
Since this is a problem in the system, to possibly avoid it I can only suggest a couple of things:
- Analyze the devices themselves if possible and see if the app crashes in the debug build,
- Ensure your strings are completely converted in all languages and you do not rely on the default language (a.k.a primary language that has all the strings but the specific configurations do not have them unless they are marked with
translatable=false
in the strings.xml
file)
- Check if a similar report exists in Firebase Crashlytics if it is used (it may not be there since the app is crashing before the app is properly created but Firebase services can still upload sometimes. It can also contain more info about the stack trace.)
- Check if the crash occurs in Android 9 Emulator (the official emulator and a Genymotion emulator)
- You can also use an online Samsung device from Samsung Test Lab (albeit for a short time) and see if the crash is observable. You might get a complete stack trace and it could point you in the right direction.
These are my findings, hopefully, they are useful in some way.