| Index: ui/base/resource/resource_bundle_android.cc | 
| diff --git a/ui/base/resource/resource_bundle_android.cc b/ui/base/resource/resource_bundle_android.cc | 
| index 9b0ae24bfce1146d80cddf462e25d9ff7e84bcce..68c8c47fffb64cbd771ca1fdf45cd9f7e81615cf 100644 | 
| --- a/ui/base/resource/resource_bundle_android.cc | 
| +++ b/ui/base/resource/resource_bundle_android.cc | 
| @@ -8,6 +8,7 @@ | 
| #include "base/android/jni_android.h" | 
| #include "base/android/jni_string.h" | 
| #include "base/logging.h" | 
| +#include "base/memory/ptr_util.h" | 
| #include "base/path_service.h" | 
| #include "jni/ResourceBundle_jni.h" | 
| #include "ui/base/l10n/l10n_util.h" | 
| @@ -20,36 +21,63 @@ namespace ui { | 
| namespace { | 
|  | 
| bool g_locale_paks_in_apk = false; | 
| +bool g_load_secondary_locale_paks = false; | 
| // It is okay to cache and share these file descriptors since the | 
| // ResourceBundle singleton never closes the handles. | 
| int g_chrome_100_percent_fd = -1; | 
| int g_resources_pack_fd = -1; | 
| int g_locale_pack_fd = -1; | 
| +int g_secondary_locale_pack_fd = -1; | 
| base::MemoryMappedFile::Region g_chrome_100_percent_region; | 
| base::MemoryMappedFile::Region g_resources_pack_region; | 
| base::MemoryMappedFile::Region g_locale_pack_region; | 
| +base::MemoryMappedFile::Region g_secondary_locale_pack_region; | 
|  | 
| bool LoadFromApkOrFile(const char* apk_path, | 
| const base::FilePath* disk_path, | 
| -                       int* fd_out, | 
| -                       base::MemoryMappedFile::Region* region_out) { | 
| -  DCHECK_EQ(*fd_out, -1) << "Attempt to load " << apk_path << " twice."; | 
| +                       int* out_fd, | 
| +                       base::MemoryMappedFile::Region* out_region) { | 
| +  DCHECK_EQ(*out_fd, -1) << "Attempt to load " << apk_path << " twice."; | 
| if (apk_path != nullptr) { | 
| -    *fd_out = base::android::OpenApkAsset(apk_path, region_out); | 
| +    *out_fd = base::android::OpenApkAsset(apk_path, out_region); | 
| } | 
| // For unit tests, the file exists on disk. | 
| -  if (*fd_out < 0 && disk_path != nullptr) { | 
| +  if (*out_fd < 0 && disk_path != nullptr) { | 
| int flags = base::File::FLAG_OPEN | base::File::FLAG_READ; | 
| -    *fd_out = base::File(*disk_path, flags).TakePlatformFile(); | 
| -    *region_out = base::MemoryMappedFile::Region::kWholeFile; | 
| +    *out_fd = base::File(*disk_path, flags).TakePlatformFile(); | 
| +    *out_region = base::MemoryMappedFile::Region::kWholeFile; | 
| } | 
| -  bool success = *fd_out >= 0; | 
| +  bool success = *out_fd >= 0; | 
| if (!success) { | 
| LOG(ERROR) << "Failed to open pak file: " << apk_path; | 
| } | 
| return success; | 
| } | 
|  | 
| +int LoadLocalePakFromApk(const std::string& app_locale, | 
| +                         base::MemoryMappedFile::Region* out_region) { | 
| +  std::string locale_path_within_apk = | 
| +      GetPathForAndroidLocalePakWithinApk(app_locale); | 
| +  if (locale_path_within_apk.empty()) { | 
| +    LOG(ERROR) << "locale_path_within_apk.empty() for locale " | 
| +                 << app_locale; | 
| +    return -1; | 
| +  } | 
| +  return base::android::OpenApkAsset(locale_path_within_apk, out_region); | 
| +} | 
| + | 
| +std::unique_ptr<DataPack> LoadDataPackFromLocalePak( | 
| +    int locale_pack_fd, | 
| +    const base::MemoryMappedFile::Region& region) { | 
| +  auto data_pack = base::MakeUnique<DataPack>(SCALE_FACTOR_100P); | 
| +  if (!data_pack->LoadFromFileRegion(base::File(locale_pack_fd), region)) { | 
| +    LOG(ERROR) << "failed to load locale.pak"; | 
| +    NOTREACHED(); | 
| +    return nullptr; | 
| +  } | 
| +  return data_pack; | 
| +} | 
| + | 
| }  // namespace | 
|  | 
| void ResourceBundle::LoadCommonResources() { | 
| @@ -74,22 +102,18 @@ bool ResourceBundle::LocaleDataPakExists(const std::string& locale) { | 
|  | 
| std::string ResourceBundle::LoadLocaleResources( | 
| const std::string& pref_locale) { | 
| -  DCHECK(!locale_resources_data_.get()) << "locale.pak already loaded"; | 
| +  DCHECK(!locale_resources_data_.get() && | 
| +         !secondary_locale_resources_data_.get()) | 
| +             << "locale.pak already loaded"; | 
| if (g_locale_pack_fd != -1) { | 
| LOG(WARNING) | 
| << "Unexpected (outside of tests): Loading a second locale pak file."; | 
| } | 
| std::string app_locale = l10n_util::GetApplicationLocale(pref_locale); | 
| + | 
| +  // Load primary locale .pak file. | 
| if (g_locale_paks_in_apk) { | 
| -    std::string locale_path_within_apk = | 
| -        GetPathForAndroidLocalePakWithinApk(app_locale); | 
| -    if (locale_path_within_apk.empty()) { | 
| -      LOG(WARNING) << "locale_path_within_apk.empty() for locale " | 
| -                   << app_locale; | 
| -      return std::string(); | 
| -    } | 
| -    g_locale_pack_fd = base::android::OpenApkAsset(locale_path_within_apk, | 
| -                                                   &g_locale_pack_region); | 
| +    g_locale_pack_fd = LoadLocalePakFromApk(app_locale, &g_locale_pack_region); | 
| } else { | 
| base::FilePath locale_file_path = GetOverriddenPakPath(); | 
| if (locale_file_path.empty()) | 
| @@ -105,15 +129,27 @@ std::string ResourceBundle::LoadLocaleResources( | 
| g_locale_pack_region = base::MemoryMappedFile::Region::kWholeFile; | 
| } | 
|  | 
| -  std::unique_ptr<DataPack> data_pack(new DataPack(SCALE_FACTOR_100P)); | 
| -  if (!data_pack->LoadFromFileRegion(base::File(g_locale_pack_fd), | 
| -                                     g_locale_pack_region)) { | 
| -    LOG(ERROR) << "failed to load locale.pak"; | 
| -    NOTREACHED(); | 
| +  locale_resources_data_ = LoadDataPackFromLocalePak( | 
| +      g_locale_pack_fd, g_locale_pack_region); | 
| + | 
| +  if (!locale_resources_data_.get()) | 
| return std::string(); | 
| + | 
| +  // Load secondary locale .pak file if it exists. For debug build monochrome, | 
| +  // a secondary locale pak will always be loaded; however, it should be | 
| +  // unnecessary for loading locale resources because the primary locale pak | 
| +  // would have a copy of all the resources in the secondary locale pak. | 
| +  if (g_load_secondary_locale_paks) { | 
| +    g_secondary_locale_pack_fd = LoadLocalePakFromApk( | 
| +        app_locale, &g_secondary_locale_pack_region); | 
| + | 
| +    secondary_locale_resources_data_ = LoadDataPackFromLocalePak( | 
| +        g_secondary_locale_pack_fd, g_secondary_locale_pack_region); | 
| + | 
| +    if (!secondary_locale_resources_data_.get()) | 
| +      return std::string(); | 
| } | 
|  | 
| -  locale_resources_data_ = std::move(data_pack); | 
| return app_locale; | 
| } | 
|  | 
| @@ -125,6 +161,10 @@ void SetLocalePaksStoredInApk(bool value) { | 
| g_locale_paks_in_apk = value; | 
| } | 
|  | 
| +void SetLoadSecondaryLocalePaks(bool value) { | 
| +  g_load_secondary_locale_paks = value; | 
| +} | 
| + | 
| void LoadMainAndroidPackFile(const char* path_within_apk, | 
| const base::FilePath& disk_file_path) { | 
| if (LoadFromApkOrFile(path_within_apk, | 
| @@ -155,6 +195,11 @@ int GetLocalePackFd(base::MemoryMappedFile::Region* out_region) { | 
| return g_locale_pack_fd; | 
| } | 
|  | 
| +int GetSecondaryLocalePackFd(base::MemoryMappedFile::Region* out_region) { | 
| +  *out_region = g_secondary_locale_pack_region; | 
| +  return g_secondary_locale_pack_fd; | 
| +} | 
| + | 
| std::string GetPathForAndroidLocalePakWithinApk(const std::string& locale) { | 
| JNIEnv* env = base::android::AttachCurrentThread(); | 
| base::android::ScopedJavaLocalRef<jstring> ret = | 
|  |