Android: Chrome crashes on startup due to system language selection. |
|||||
Issue description
Chromium might crash at startup, when it is built as an app bundle with language-based configuration splits. This happens once the user has changed the device's current system locale, and that the corresponding split APK is not installed yet.
This entry is to prevent the issue by ensuring that all Chromium code can deal with this case by using the right fallback Java resources and .pak files. Until it is fixed, language-based splits cannot be enabled!
Now, for a more detailed explanation of the situation:
Android app bundles can generate APK splits where all locale-dependent Java resources and .pak files are stored in language-specific splits (e.g. config_en.apk for English, config_fr.apk for French, etc), separate from the main application split (base.apk).
When this feature is enabled, only the splits corresponding to the current device's configuration are installed. For example, if the device is currently using a French locale, installing the application will actually only install base.apk and config_fr.apk to the device.
Note that:
- There is *always* at least one language split installed (matching the current device's language at install time),
- Once a split is installed, it cannot be removed, except by uninstalling the application as a whole.
- Once a split is installed, any application update will actually update the base.apk and all installed splits at the same time.
A problem arises when the user later decides to change the device's locale (Settings > System > Languages on N). For example, when changing the locale to Spanish, the next Chromium launch will *not* have the config_es.apk split installed yet, and won't be able to use any related Java resources or .pak files.
At the moment, Chromium will crash at runtime due to this, resulting in an unacceptable user experience (crash dialog, and no way to start the browser or understand what's happening). The only solution is to revert to the previous system language, which is not obvious.
IMPORTANT NOTE: *All* system webview locale resources and .pak files are already always stored in the base.apk, thus this issue will never happen for applications using a Webview, only Chromium-based apps like the browser.
If the application was installed through the Play Store, the Google Play Services library will detect the system-wide locale change and try to download the new split as soon as possible. However, this may not be immediate or even possible (e.g. airplane mode).
This means that Chrome needs to fallback to a locale it has resources and .pak files for when this happens.
This entry is to track the issue and provide an adequate solution.
A proposed solution for now is the following:
- Add a new org.chromium.base.LocaleUtils.getCurrentLocale() method
to return the current Locale that all of Chromium should use. This
should be called instead of Locale.getDefault() which returns the
current system default.
Also adjust all callers of Locale.getDefault() to use
getCurrentLocale()
- Ensure the value returned by getCurrentLocale() matches either
the current system locale, iff the corresponding config split is
installed.
Otherwise, it should match a fallback locale which *has* its
config split installed.
Since for Java resources (localized UI strings) this issue is not
specific to Chromium, see how the Play Store client library, which
manages splits, deals with this. Hopefully, there would be a simple
API that returns the corresponding value.
Note that the getCurrentLocale() value is needed *very* early during
Chromium startup, which means it may not be possible to call this
API so soon, even if it is provided. Alternative schemes would be
to store the previously-used locale in a small persistent property
or data file and use this instead.
- Chromium-specific locale .pak files are stored in the following
directory for regular (non-app-bundle) APKs:
chrome.apk!/assets/locales/<locale>.pak
Where <locale> is a Chromium-specific locale name.
When using app bundles, however, the path changes to:
<split>.apk!/assets/locales#lang_<lang>/<locale>.pak
where <lang> is a 2-char Android-specific country name, and
<locale> is a Chromium-specific locale name.
Note that the '#lang_<lang>' part of the sub-directory is not
removed from the split APKs and must be used explicitly when
accessing the files through AssetManager.open() or equivalent.
These files are extracted from the APK on very early startup into
the app data directory. See the ResourceExtractor class for details.
The latter must be updated to deal with the new format.
,
May 25 2018
This article suggests that it might be more complicated than that: https://gunhansancar.com/change-language-programmatically-in-android/
,
Jun 6 2018
Thanks for the link Andrew, very interesting. I think our use case is slightly simpler, in the end, because we won't necessarily need to change to a different locale.
I'm renaming this issue to "Chrome crashes on startup due to system language selection", because the problem appears to not be to APK splits.
Let me explain with a simple experiment:
- Use an Android N device, and go to system Settings to change the current
language to "Furlan", *removing* any other language from the list. This
matches the "Friulian" language spoken in nothern part of Italy [1],
identified with the "fur-rIT" locale on Android.
- Note that just after the switch, the Settings application still displays
everything in English. But the Home screen is properly localized.
- Notice that most applications also display in English as well. The reason for
that is that the Android framework will fallback to en-rUS when trying to
display localized strings for the "fur-rIT" or "fur" locale, when the
application doesn't have any resources for it. This is the way the system
is designed.
- Now try to start Chrome, and see it crash immediately on startup.
The reason for the crash is that the C++ code needs to access the .pak file
corresponding to the current locale, and cannot find one / open one, since
Chrome does not support Furlan (i.e. there is no fur.pak or fur-IT.pak file
under assets/locales/ or listed in [2]).
This problem is similar to the one described in the initial description for this bug: the .pak file for the current locale is missing, hence Chrome crashes on startup.
So my goal now is to fix the issue, by ensuring that the native code uses the same fallback locale as the Java side. Apparently, how the Android framework selects the actual localized strings is pretty complex, varies by platform release, depends heavily on the set of of asset files loaded in the process, and overlays, and whatnot. In other words, Chrome shall not try to duplicate this logic.
Unfortunately, there is no API to ask the framework directly for a fallback locale (and in the general case, different subsets of an application's strings can be localized differently).
But I think there is way to get something adequate by doing the following:
- Create a set of resource directories matching the Chrome-supported locales
that contain string definitions, e.g.:
res/values/strings.xml
res/values-am/strings.xml
res/values-ar/strings.xml
...
res/values-en-rUS/strings.xml
...
Where each strings.xml contains the definition of a single string
named "current_locale", and whose value will be the corresponding
Chromium-specific locale name.
I.e. values-en-rUS/strings.xml defines 'current_locale' as 'en-US',
or values-tl/strings.xml defines it as 'fil'.
Then we can query at runtime the string value using something like:
ContextUtils.getApplicationContext().getResources().getString(
org.chromium.base.ui_locale.R.string.current_locale);
And this should give us the locale used to display the UI, as decided by
the framework. This will work because we always localize all our strings
for all our supported locales.
By doing this, native code should be able to match the locale used by the UI, and in the example above, Chrome should start using English as the UI language when the system is set to "Furlan".
[1] https://en.wikipedia.org/wiki/Friulian_language
[2] https://cs.chromium.org/chromium/src/build/config/locales.gni?q=locales.gni&sq=package:chromium&dr
,
Jun 6 2018
,
Jun 6 2018
There is existing logic that is supposed to handle this case: Extracting fallback pak: https://cs.chromium.org/chromium/src/base/android/java/src/org/chromium/base/ResourceExtractor.java?rcl=324138ca59bab8c60c2a641f8530073934785423&l=218 Choosing fallback pak: https://cs.chromium.org/chromium/src/ui/base/l10n/l10n_util.cc?rcl=324138ca59bab8c60c2a641f8530073934785423&l=509 What you describe sounds more robust, but I think it's also worth figuring out why the existing logic isn't working.
,
Jun 6 2018
Fwiw, the current language logic cannot be used for the edge case where an APK split isn't installed yet. I already tested that the system may use a different fallback that en-US for Java strings if an appropriate split is already installed.
,
Jun 7 2018
Certainly agree that your approach is more robust and will work well for splits. Just curious why it's crashing.
,
Jun 11 2018
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/88f72c27376cffbe654307274c5df9db56fe77ea commit 88f72c27376cffbe654307274c5df9db56fe77ea Author: David 'Digit' Turner <digit@google.com> Date: Mon Jun 11 09:53:24 2018 android: Move native library extraction to LibraryLoader Some constants and methods related to extracted native libraries from the Chrome APK into a private application data directory are moved from the ResourceExtractor.java class to LibraryLoader.java instead. This is a more logical place, since ResourceExtractor.java is going to be moved out of //base and into //ui/base/ since it is now mostly related to UI resources. See referring bug for more context. BUG= 846633 R=agrieve@chromium.org, pasko@chromium.org Change-Id: I7ff442930ee80dfe9230021ce8e099393d51beca Reviewed-on: https://chromium-review.googlesource.com/1090926 Commit-Queue: David Turner <digit@chromium.org> Reviewed-by: agrieve <agrieve@chromium.org> Reviewed-by: Egor Pasko <pasko@chromium.org> Cr-Commit-Position: refs/heads/master@{#565951} [modify] https://crrev.com/88f72c27376cffbe654307274c5df9db56fe77ea/base/android/java/src/org/chromium/base/FileUtils.java [modify] https://crrev.com/88f72c27376cffbe654307274c5df9db56fe77ea/base/android/java/src/org/chromium/base/ResourceExtractor.java [modify] https://crrev.com/88f72c27376cffbe654307274c5df9db56fe77ea/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java [modify] https://crrev.com/88f72c27376cffbe654307274c5df9db56fe77ea/base/android/java/src/org/chromium/base/library_loader/Linker.java
,
Jun 12 2018
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/d58d7c9826b9a941dc837c04dc1d8cef8667a4a8 commit d58d7c9826b9a941dc837c04dc1d8cef8667a4a8 Author: David 'Digit' Turner <digit@google.com> Date: Tue Jun 12 12:44:02 2018 android: Move ResourceExtractor from base to ui This prepares for a future CL that will ensure the set of PAK files extracted by this class match the UI language used by the Android framework to display localized strings. BUG= 846633 R=agrieve@chromium.org, astevenson@chromium.org Change-Id: I316dc53b23f3fc9139af845c1f9fad7e5b4138a6 Reviewed-on: https://chromium-review.googlesource.com/1091310 Reviewed-by: agrieve <agrieve@chromium.org> Reviewed-by: David Trainor <dtrainor@chromium.org> Reviewed-by: Ted Choc <tedchoc@chromium.org> Commit-Queue: David Turner <digit@chromium.org> Cr-Commit-Position: refs/heads/master@{#566391} [modify] https://crrev.com/d58d7c9826b9a941dc837c04dc1d8cef8667a4a8/base/BUILD.gn [modify] https://crrev.com/d58d7c9826b9a941dc837c04dc1d8cef8667a4a8/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java [modify] https://crrev.com/d58d7c9826b9a941dc837c04dc1d8cef8667a4a8/content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java [modify] https://crrev.com/d58d7c9826b9a941dc837c04dc1d8cef8667a4a8/content/public/test/android/javatests/src/org/chromium/content/browser/test/NativeLibraryTestRule.java [modify] https://crrev.com/d58d7c9826b9a941dc837c04dc1d8cef8667a4a8/ui/android/BUILD.gn [rename] https://crrev.com/d58d7c9826b9a941dc837c04dc1d8cef8667a4a8/ui/android/java/src/org/chromium/ui/resources/ResourceExtractor.java
,
Jun 19 2018
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/5111ff4bca35f8a1dd89aa9a7ea2f96fdc4055e6 commit 5111ff4bca35f8a1dd89aa9a7ea2f96fdc4055e6 Author: David 'Digit' Turner <digit@google.com> Date: Tue Jun 19 11:22:38 2018 android: Add android_generated_resources GN template This CL adds a new GN template to specify a set of Android resource files generated by another target's action. The generated files must be stored by the action into a zip archive, with a layout similar to standard Android res/ folder (but note that the archive should not have a top-level res/ directory). + Update java_strings_grd(), java_strings_grd_prebuilt() and jinja_template_resources() to use it. BUG= 846633 R=agrieve@chromium.org, estevenson@chromium.org, jbudorick@chromium.org Change-Id: Ibb0ec100d0922ac1ec3155f4577f40136f233b0b Reviewed-on: https://chromium-review.googlesource.com/1104355 Commit-Queue: David Turner <digit@chromium.org> Reviewed-by: John Budorick <jbudorick@chromium.org> Reviewed-by: agrieve <agrieve@chromium.org> Reviewed-by: Eric Stevenson <estevenson@chromium.org> Cr-Commit-Position: refs/heads/master@{#568402} [modify] https://crrev.com/5111ff4bca35f8a1dd89aa9a7ea2f96fdc4055e6/build/config/android/rules.gni
,
Jun 19 2018
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/f0154cc103b927a15ed8224b2e42026b7c95226c commit f0154cc103b927a15ed8224b2e42026b7c95226c Author: David 'Digit' Turner <digit@google.com> Date: Tue Jun 19 17:22:36 2018 android: Small LocaleUtils cleanup This CL removes un-necessary allocations in LocaleUtils.java and moves the matching Python CHROME_TO_ANDROID_LANGUAGE_MAP variable to resource_utils.py, in preparation of a future CL where it will be used by another Python script as well. BUG= 846633 R=agrieve@chromium.org, jbudorick@chromium.org, estevenson@chromium.org Change-Id: Ie6eba71b259c2fef410afe526b7478dc56866887 Reviewed-on: https://chromium-review.googlesource.com/1106162 Reviewed-by: agrieve <agrieve@chromium.org> Commit-Queue: David Turner <digit@chromium.org> Cr-Commit-Position: refs/heads/master@{#568507} [modify] https://crrev.com/f0154cc103b927a15ed8224b2e42026b7c95226c/base/android/java/src/org/chromium/base/LocaleUtils.java [modify] https://crrev.com/f0154cc103b927a15ed8224b2e42026b7c95226c/build/android/gyp/compile_resources.py [modify] https://crrev.com/f0154cc103b927a15ed8224b2e42026b7c95226c/build/android/gyp/util/resource_utils.py
,
Jun 21 2018
,
Jun 22 2018
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/26d969cf89623e4c76f6bf5a11549fc1689324da commit 26d969cf89623e4c76f6bf5a11549fc1689324da Author: David 'Digit' Turner <digit@google.com> Date: Fri Jun 22 19:49:11 2018 android: Fix Chrome startup crash due to system language choice. Chrome currently crashes on startup on Android if the system locale is set to something that it doesn't support. For example, set the system locale to 'Furlan': regular Android applications will fallback to display English strings as a fallback, but Chrome crashes on startup immediately. This CL fixes the issue, by detecting which locale the Android framework uses to display strings effectively, then using this value to extract the corresponding .pak file, instead of trying to find one that matches the current system setting. + Move compressed locale file detection to background thread. Since this now requires I/O access when accessing the resources, this operation can no longer be performed on the UI thread. For more details, see associated bug entry. BUG= 846633 R=agrieve@chromium.org,astevenson@chromium.org,dtrainor@chromium.org,tedchoc@chromium.org Change-Id: If2db6136367081ad50b2b80c85b4cc0e1c2c276f Reviewed-on: https://chromium-review.googlesource.com/1088708 Commit-Queue: David Turner <digit@chromium.org> Reviewed-by: agrieve <agrieve@chromium.org> Reviewed-by: Ted Choc <tedchoc@chromium.org> Cr-Commit-Position: refs/heads/master@{#569738} [modify] https://crrev.com/26d969cf89623e4c76f6bf5a11549fc1689324da/build/android/gyp/util/build_utils.py [modify] https://crrev.com/26d969cf89623e4c76f6bf5a11549fc1689324da/ui/android/BUILD.gn [add] https://crrev.com/26d969cf89623e4c76f6bf5a11549fc1689324da/ui/android/build/create_ui_locale_resources.py [modify] https://crrev.com/26d969cf89623e4c76f6bf5a11549fc1689324da/ui/android/java/src/org/chromium/ui/base/LocalizationUtils.java [modify] https://crrev.com/26d969cf89623e4c76f6bf5a11549fc1689324da/ui/android/java/src/org/chromium/ui/resources/ResourceExtractor.java
,
Jul 12
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/dc6d74d7b8c120d3d8d90ab8c68c5285e384a7f8 commit dc6d74d7b8c120d3d8d90ab8c68c5285e384a7f8 Author: David 'Digit' Turner <digit@google.com> Date: Thu Jul 12 17:07:14 2018 android: Update bundletool binary to 0.5.0 This release contains a bugfix required to generate Android app bundle APKs archives that can be installed on all devices. For more context, see: https://buganizer.corp.google.com/issues/110777526 BUG= 846633 , 820459 R=agrieve@chromium.org, bensmason@chromium.org, yfriedman@chromium.org Change-Id: Ic71445f49a4548c8610f5d18598cdd3d3d5692c4 Reviewed-on: https://chromium-review.googlesource.com/1135127 Reviewed-by: agrieve <agrieve@chromium.org> Commit-Queue: David Turner <digit@chromium.org> Cr-Commit-Position: refs/heads/master@{#574608} [modify] https://crrev.com/dc6d74d7b8c120d3d8d90ab8c68c5285e384a7f8/DEPS [modify] https://crrev.com/dc6d74d7b8c120d3d8d90ab8c68c5285e384a7f8/build/android/gyp/bundletool.py [modify] https://crrev.com/dc6d74d7b8c120d3d8d90ab8c68c5285e384a7f8/third_party/android_build_tools/bundletool/README.chromium
,
Jul 13
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/bdb7c6bf6d378e95ddeb81014e30bb19cdd87c86 commit bdb7c6bf6d378e95ddeb81014e30bb19cdd87c86 Author: David 'Digit' Turner <digit@google.com> Date: Fri Jul 13 12:54:36 2018 android: Enable language-based splits for app bundles. This is done by adding a new |enable_language_splits| variable to the android_app_bundle GN template. Note that splitting by screen_density or ABI currently doesn't make sense for Chromium, but could be added in the future. Only the chrome_public_bundle target uses language-based splits in this CL. BUG= 846633 , 820459 R=agrieve@chromium.org, yfriedman@chromium.org TBR=twellington@chromium.org,tedchoc@chromium.org Change-Id: Ic89f9dd4b8c78e8b2127bb19208db18bc8027eab Reviewed-on: https://chromium-review.googlesource.com/1125934 Commit-Queue: David Turner <digit@chromium.org> Reviewed-by: agrieve <agrieve@chromium.org> Cr-Commit-Position: refs/heads/master@{#574888} [modify] https://crrev.com/bdb7c6bf6d378e95ddeb81014e30bb19cdd87c86/build/android/gyp/create_app_bundle.py [modify] https://crrev.com/bdb7c6bf6d378e95ddeb81014e30bb19cdd87c86/build/android/gyp/util/resource_utils.py [modify] https://crrev.com/bdb7c6bf6d378e95ddeb81014e30bb19cdd87c86/build/config/android/rules.gni [modify] https://crrev.com/bdb7c6bf6d378e95ddeb81014e30bb19cdd87c86/chrome/android/BUILD.gn [modify] https://crrev.com/bdb7c6bf6d378e95ddeb81014e30bb19cdd87c86/ui/android/java/src/org/chromium/ui/base/LocalizationUtils.java [modify] https://crrev.com/bdb7c6bf6d378e95ddeb81014e30bb19cdd87c86/ui/android/java/src/org/chromium/ui/resources/ResourceExtractor.java
,
Aug 6
|
|||||
►
Sign in to add a comment |
|||||
Comment 1 by digit@chromium.org
, May 25 2018