Move ICU from ART APEX to i18n APEX am: 8419b82fa8

Change-Id: Ifaf81867eb07fddeb43c407f7c671adfba749149
diff --git a/Android.mk b/Android.mk
index 5ae5881..0228b86 100644
--- a/Android.mk
+++ b/Android.mk
@@ -503,7 +503,6 @@
 
 PRIVATE_ART_APEX_DEPENDENCY_LIBS := \
   lib/libadbconnection.so \
-  lib/libandroidicu.so \
   lib/libandroidio.so \
   lib/libartbase.so \
   lib/libart-compiler.so \
@@ -520,9 +519,6 @@
   lib/libdt_fd_forward.so \
   lib/libdt_socket.so \
   lib/libexpat.so \
-  lib/libicui18n.so \
-  lib/libicu_jni.so \
-  lib/libicuuc.so \
   lib/libjavacore.so \
   lib/libjdwp.so \
   lib/liblzma.so \
@@ -543,7 +539,6 @@
   lib/libziparchive.so \
   lib/libz.so \
   lib64/libadbconnection.so \
-  lib64/libandroidicu.so \
   lib64/libandroidio.so \
   lib64/libartbase.so \
   lib64/libart-compiler.so \
@@ -560,9 +555,6 @@
   lib64/libdt_fd_forward.so \
   lib64/libdt_socket.so \
   lib64/libexpat.so \
-  lib64/libicui18n.so \
-  lib64/libicu_jni.so \
-  lib64/libicuuc.so \
   lib64/libjavacore.so \
   lib64/libjdwp.so \
   lib64/liblzma.so \
@@ -591,6 +583,16 @@
   lib64/libjavacrypto.so \
   lib64/libssl.so \
 
+PRIVATE_I18N_APEX_DEPENDENCY_LIBS := \
+  lib/libandroidicu.so \
+  lib/libicui18n.so \
+  lib/libicu_jni.so \
+  lib/libicuuc.so \
+  lib64/libandroidicu.so \
+  lib64/libicui18n.so \
+  lib64/libicu_jni.so \
+  lib64/libicuuc.so \
+
 # Generate copies of Bionic bootstrap artifacts and ART APEX
 # libraries in the `system` (TARGET_OUT) directory. This is dangerous
 # as these files could inadvertently stay in this directory and be
@@ -610,7 +612,7 @@
 #   `$(TARGET_OUT)/../apex/com.android.art.debug` (the local
 #   directory under the build tree containing the (Debug) ART APEX
 #   artifacts, which is not sync'd to the target).
-# - Libraries from the Conscrypt APEX may be loaded during golem runs.
+# - Libraries from the Conscrypt and I18n APEX may be loaded during golem runs.
 #
 # This target is only used by Golem now.
 #
@@ -628,7 +630,8 @@
                        libm.bootstrap \
                        linker \
                        $(RELEASE_ART_APEX) \
-                       $(CONSCRYPT_APEX)
+                       $(CONSCRYPT_APEX) \
+                       $(I18N_APEX)
 	for f in $(PRIVATE_BIONIC_FILES); do \
 	  tf=$(TARGET_OUT)/$$f; \
 	  if [ -f $$tf ]; then cp -f $$tf $$(echo $$tf | sed 's,bootstrap/,,'); fi; \
@@ -660,6 +663,11 @@
 	  tf="$$conscrypt_apex_orig_dir/$$f"; \
 	  if [ -f $$tf ]; then cp -f $$tf $(TARGET_OUT)/$$f; fi; \
 	done; \
+	i18n_apex_orig_dir=$$apex_orig_dir/$(I18N_APEX); \
+	for f in $(PRIVATE_I18N_APEX_DEPENDENCY_LIBS); do \
+	  tf="$$i18n_apex_orig_dir/$$f"; \
+	  if [ -f $$tf ]; then cp -f $$tf $(TARGET_OUT)/$$f; fi; \
+	done; \
 
 ########################################################################
 # Phony target for only building what go/lem requires for pushing ART on /data.
diff --git a/build/Android.bp b/build/Android.bp
index 3bbeebd..6ac0f5b 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -251,7 +251,7 @@
 
 // A version of conscrypt only for enabling the "-hostdex" version to test ART on host.
 java_library {
-    // We need our own name to not class with the conscrypt library.
+    // We need our own name to not clash with the conscrypt library.
     name: "conscrypt-host",
     installable: true,
     hostdex: true,
@@ -268,3 +268,23 @@
         },
     },
 }
+
+// A version of core-icu4j only for enabling the "-hostdex" version to test ART on host.
+java_library {
+    // We need our own name to not clash with the core-icu4j library.
+    name: "core-icu4j-host",
+    installable: true,
+    hostdex: true,
+    static_libs: ["core-icu4j"],
+
+    // Tests and build files rely on this file to be installed as "core-icu4j-hostdex",
+    // therefore set a stem. Without it, the file would be installed as
+    // "core-icu4j-host-hostdex".
+    stem: "core-icu4j",
+    sdk_version: "core_platform",
+    target: {
+        hostdex: {
+            required: ["libicu_jni"],
+        },
+    },
+}
diff --git a/build/Android.common_path.mk b/build/Android.common_path.mk
index 1d67037..03a136c 100644
--- a/build/Android.common_path.mk
+++ b/build/Android.common_path.mk
@@ -74,7 +74,7 @@
 TARGET_CORE_IMG_LOCATION := $(ART_TARGET_TEST_OUT)/core.art
 
 # Modules to compile for core.art.
-CORE_IMG_JARS := core-oj core-libart core-icu4j okhttp bouncycastle apache-xml
+CORE_IMG_JARS := core-oj core-libart okhttp bouncycastle apache-xml
 HOST_CORE_IMG_JARS   := $(addsuffix -hostdex,$(CORE_IMG_JARS))
 TARGET_CORE_IMG_JARS := $(CORE_IMG_JARS)
 HOST_CORE_IMG_DEX_LOCATIONS   := $(foreach jar,$(HOST_CORE_IMG_JARS),  $(HOST_OUT_JAVA_LIBRARIES)/$(jar).jar)
@@ -93,14 +93,17 @@
 HOST_BOOT_IMAGE_JARS += $(HOST_OUT)/apex/com.android.conscrypt/javalib/conscrypt.jar
 $(HOST_OUT)/apex/com.android.conscrypt/javalib/conscrypt.jar : $(HOST_OUT_JAVA_LIBRARIES)/conscrypt-hostdex.jar
 	$(copy-file-to-target)
+HOST_BOOT_IMAGE_JARS += $(HOST_OUT)/apex/com.android.i18n/javalib/core-icu4j.jar
+$(HOST_OUT)/apex/com.android.i18n/javalib/core-icu4j.jar : $(HOST_OUT_JAVA_LIBRARIES)/core-icu4j-hostdex.jar
+	$(copy-file-to-target)
 
 HOST_CORE_IMG_OUTS += $(HOST_BOOT_IMAGE_JARS) $(HOST_BOOT_IMAGE) $(2ND_HOST_BOOT_IMAGE)
 
-HOST_TEST_CORE_JARS   := $(addsuffix -hostdex,$(CORE_IMG_JARS) conscrypt)
+HOST_TEST_CORE_JARS   := $(addsuffix -hostdex,$(CORE_IMG_JARS) core-icu4j conscrypt)
 ART_HOST_DEX_DEPENDENCIES := $(foreach jar,$(HOST_TEST_CORE_JARS),$(HOST_OUT_JAVA_LIBRARIES)/$(jar).jar)
-ART_TARGET_DEX_DEPENDENCIES := com.android.art.testing com.android.conscrypt
+ART_TARGET_DEX_DEPENDENCIES := com.android.art.testing com.android.conscrypt com.android.i18n
 
-ART_CORE_SHARED_LIBRARIES := libicu_jni libjavacore libopenjdk libopenjdkjvm libopenjdkjvmti
+ART_CORE_SHARED_LIBRARIES := libjavacore libopenjdk libopenjdkjvm libopenjdkjvmti
 ART_CORE_SHARED_DEBUG_LIBRARIES := libopenjdkd libopenjdkjvmd libopenjdkjvmtid
 ART_HOST_SHARED_LIBRARY_DEPENDENCIES := $(foreach lib,$(ART_CORE_SHARED_LIBRARIES), $(ART_HOST_OUT_SHARED_LIBRARIES)/$(lib)$(ART_HOST_SHLIB_EXTENSION))
 ART_HOST_SHARED_LIBRARY_DEBUG_DEPENDENCIES := $(foreach lib,$(ART_CORE_SHARED_DEBUG_LIBRARIES), $(ART_HOST_OUT_SHARED_LIBRARIES)/$(lib)$(ART_HOST_SHLIB_EXTENSION))
@@ -156,5 +159,7 @@
 
 # Conscrypt APEX
 CONSCRYPT_APEX := com.android.conscrypt
+# i18n APEX
+I18N_APEX := com.android.i18n
 
 endif # ART_ANDROID_COMMON_PATH_MK
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 910d7f9..ab9d594 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -628,7 +628,7 @@
 ifeq ($(ART_BUILD_TARGET),true)
   $(foreach name,$(ART_TARGET_GTEST_NAMES), $(eval $(call add-art-gtest-dependencies,$(name),)))
   ART_TEST_TARGET_GTEST_DEPENDENCIES += \
-    libicu_jni.com.android.art.testing \
+    libicu_jni.com.android.i18n \
     libjavacore.com.android.art.testing \
     libopenjdkd.com.android.art.testing \
     com.android.art.testing \
diff --git a/build/apex/Android.bp b/build/apex/Android.bp
index 706fa96..a1112b7 100644
--- a/build/apex/Android.bp
+++ b/build/apex/Android.bp
@@ -141,7 +141,6 @@
 libcore_java_libs = [
     "core-oj",
     "core-libart",
-    "core-icu4j",
     "okhttp",
     "bouncycastle",
     "apache-xml",
@@ -160,14 +159,10 @@
 // the ART APEX.
 libcore_native_shared_libs = [
     // External API (having APEX stubs).
-    "libandroidicu",
     "libandroidio",
     // TODO(b/124476339): Clean up the following libraries once "required"
     // dependencies work with APEX libraries.
     "libexpat",
-    "libicui18n",
-    "libicuuc",
-    "libicu_jni",
     "libjavacore",
     "libopenjdk",
 ]
@@ -175,12 +170,6 @@
     "libopenjdkd",
 ]
 
-libcore_native_device_only_shared_libs = [
-    // TODO(b/122876336): Remove libpac.so once it's migrated to Webview.
-    // libpac is used by frameworks, not by ART host.
-    "libpac",
-]
-
 // Temporary library includes for b/123591866 as all libraries are moved into the main art-apex.
 art_runtime_libraries_zipapex = [
     "libnativebridge",
@@ -208,7 +197,6 @@
     java_libs: libcore_java_libs,
     native_shared_libs: art_runtime_base_native_shared_libs +
         art_runtime_base_native_device_only_shared_libs +
-        libcore_native_device_only_shared_libs +
         libcore_native_shared_libs,
     multilib: {
         both: {
diff --git a/build/apex/art_apex_test.py b/build/apex/art_apex_test.py
index 6bccdf5..aa95eb7 100755
--- a/build/apex/art_apex_test.py
+++ b/build/apex/art_apex_test.py
@@ -542,7 +542,6 @@
     # Check java libraries for Managed Core Library.
     self._checker.check_java_library('apache-xml')
     self._checker.check_java_library('bouncycastle')
-    self._checker.check_java_library('core-icu4j')
     self._checker.check_java_library('core-libart')
     self._checker.check_java_library('core-oj')
     self._checker.check_java_library('okhttp')
@@ -586,7 +585,6 @@
     self._checker.check_dexpreopt('boot')
     self._checker.check_dexpreopt('boot-apache-xml')
     self._checker.check_dexpreopt('boot-bouncycastle')
-    self._checker.check_dexpreopt('boot-core-icu4j')
     self._checker.check_dexpreopt('boot-core-libart')
     self._checker.check_dexpreopt('boot-okhttp')
     if isEnvTrue('EMMA_INSTRUMENT_FRAMEWORK'):
@@ -615,16 +613,11 @@
     self._checker.check_native_library('libperfetto_hprof')
 
     # Check exported native libraries for Managed Core Library.
-    self._checker.check_native_library('libandroidicu')
     self._checker.check_native_library('libandroidio')
 
     # Check internal native library dependencies.
     self._checker.check_native_library('libcrypto')
     self._checker.check_native_library('libexpat')
-    self._checker.check_native_library('libicui18n')
-    self._checker.check_native_library('libicuuc')
-    self._checker.check_native_library('libicu_jni')
-    self._checker.check_native_library('libpac')
     self._checker.check_native_library('libz')
 
     # TODO(b/139046641): Fix proper 2nd arch checks. For now, just ignore these
@@ -653,9 +646,6 @@
 
     # Check internal libraries for Managed Core Library.
     self._checker.check_native_library('libexpat-host')
-    self._checker.check_native_library('libicui18n-host')
-    self._checker.check_native_library('libicuuc-host')
-    self._checker.check_native_library('libicu_jni')
     self._checker.check_native_library('libz-host')
 
 
diff --git a/build/apex/manifest-art.json b/build/apex/manifest-art.json
index b1d4e99..dc4e48a 100644
--- a/build/apex/manifest-art.json
+++ b/build/apex/manifest-art.json
@@ -1,11 +1,11 @@
 {
   "name": "com.android.art",
   "version": 1,
-  "provideNativeLibs": [
-    "libicui18n.so",
-    "libicuuc.so"
-  ],
   "requireNativeLibs": [
+    "libandroidicu.so",
+    "libicuuc.so",
+    "libicui18n.so",
+    "libicu_jni.so",
     "libneuralnetworks.so"
   ]
 }
diff --git a/dex2oat/dex2oat_image_test.cc b/dex2oat/dex2oat_image_test.cc
index d01b64f..71e9b1b 100644
--- a/dex2oat/dex2oat_image_test.cc
+++ b/dex2oat/dex2oat_image_test.cc
@@ -184,13 +184,11 @@
   }
   // Compile only a subset of the libcore dex files to make this test shorter.
   std::vector<std::string> libcore_dex_files = GetLibCoreDexFileNames();
-  // The primary image must contain at least core-oj and core-libart to initialize the runtime
-  // and we also need the core-icu4j if we want to compile these with full profile.
+  // The primary image must contain at least core-oj and core-libart to initialize the runtime.
   ASSERT_NE(std::string::npos, libcore_dex_files[0].find("core-oj"));
   ASSERT_NE(std::string::npos, libcore_dex_files[1].find("core-libart"));
-  ASSERT_NE(std::string::npos, libcore_dex_files[2].find("core-icu4j"));
   ArrayRef<const std::string> dex_files =
-      ArrayRef<const std::string>(libcore_dex_files).SubArray(/*pos=*/ 0u, /*length=*/ 3u);
+      ArrayRef<const std::string>(libcore_dex_files).SubArray(/*pos=*/ 0u, /*length=*/ 2u);
 
   ImageSizes base_sizes = CompileImageAndGetSizes(dex_files, {});
   ImageSizes everything_sizes;
@@ -274,19 +272,17 @@
 
   ArrayRef<const std::string> full_bcp(libcore_dex_files);
   size_t total_dex_files = full_bcp.size();
-  ASSERT_GE(total_dex_files, 5u);  // 3 for "head", 1 for "tail", at least one for "mid", see below.
+  ASSERT_GE(total_dex_files, 4u);  // 2 for "head", 1 for "tail", at least one for "mid", see below.
 
-  // The primary image must contain at least core-oj and core-libart to initialize the runtime
-  // and we also need the core-icu4j if we want to compile these with full profile.
+  // The primary image must contain at least core-oj and core-libart to initialize the runtime.
   ASSERT_NE(std::string::npos, full_bcp[0].find("core-oj"));
   ASSERT_NE(std::string::npos, full_bcp[1].find("core-libart"));
-  ASSERT_NE(std::string::npos, full_bcp[2].find("core-icu4j"));
-  ArrayRef<const std::string> head_dex_files = full_bcp.SubArray(/*pos=*/ 0u, /*length=*/ 3u);
+  ArrayRef<const std::string> head_dex_files = full_bcp.SubArray(/*pos=*/ 0u, /*length=*/ 2u);
   // Middle part is everything else except for conscrypt.
   ASSERT_NE(std::string::npos, full_bcp[full_bcp.size() - 1u].find("conscrypt"));
   ArrayRef<const std::string> mid_bcp =
       full_bcp.SubArray(/*pos=*/ 0u, /*length=*/ total_dex_files - 1u);
-  ArrayRef<const std::string> mid_dex_files = mid_bcp.SubArray(/*pos=*/ 3u);
+  ArrayRef<const std::string> mid_dex_files = mid_bcp.SubArray(/*pos=*/ 2u);
   // Tail is just the conscrypt.
   ArrayRef<const std::string> tail_dex_files =
       full_bcp.SubArray(/*pos=*/ total_dex_files - 1u, /*length=*/ 1u);
diff --git a/libartbase/base/common_art_test.cc b/libartbase/base/common_art_test.cc
index 62535a4..46ac227 100644
--- a/libartbase/base/common_art_test.cc
+++ b/libartbase/base/common_art_test.cc
@@ -400,9 +400,9 @@
 
 static std::string GetDexFileName(const std::string& jar_prefix, bool host) {
   std::string prefix(host ? GetAndroidRoot() : "");
-  const char* apexPath = (jar_prefix == "conscrypt")
-    ? kAndroidConscryptApexDefaultPath
-    : kAndroidArtApexDefaultPath;
+  const char* apexPath = (jar_prefix == "conscrypt") ? kAndroidConscryptApexDefaultPath
+    : (jar_prefix == "core-icu4j" ? kAndroidI18nApexDefaultPath
+    : kAndroidArtApexDefaultPath);
   return StringPrintf("%s%s/javalib/%s.jar", prefix.c_str(), apexPath, jar_prefix.c_str());
 }
 
@@ -414,11 +414,11 @@
       // CORE_IMG_JARS modules.
       "core-oj",
       "core-libart",
-      "core-icu4j",
       "okhttp",
       "bouncycastle",
       "apache-xml",
       // Additional modules.
+      "core-icu4j",
       "conscrypt",
   };
 }
diff --git a/libartbase/base/file_utils.h b/libartbase/base/file_utils.h
index b1d044a..a521c97 100644
--- a/libartbase/base/file_utils.h
+++ b/libartbase/base/file_utils.h
@@ -29,6 +29,7 @@
 
 static constexpr const char* kAndroidArtApexDefaultPath = "/apex/com.android.art";
 static constexpr const char* kAndroidConscryptApexDefaultPath = "/apex/com.android.conscrypt";
+static constexpr const char* kAndroidI18nApexDefaultPath = "/apex/com.android.i18n";
 
 // These methods return the Android Root, which is the historical location of
 // the Android "system" directory, containing the built Android artifacts. On
diff --git a/libnativeloader/README.md b/libnativeloader/README.md
index 57b9001..c5ace61 100644
--- a/libnativeloader/README.md
+++ b/libnativeloader/README.md
@@ -34,7 +34,7 @@
 [APEX](https://android.googlesource.com/platform/system/apex/+/refs/heads/master/docs/README.md),
 some libraries are no longer provided from platform, but from the APEXes which
 have their own linker namespaces. For example, ICU libraries `libicuuc.so` and
-`libicui18n.so` are from the runtime APEX.
+`libicui18n.so` are from the I18n APEX.
 
 The list of public native libraries is not static. The default set of libraries
 are defined in AOSP, but partners can extend it to include their own libraries.
diff --git a/libnativeloader/library_namespaces.cpp b/libnativeloader/library_namespaces.cpp
index d42a4b5..14ba721 100644
--- a/libnativeloader/library_namespaces.cpp
+++ b/libnativeloader/library_namespaces.cpp
@@ -51,6 +51,7 @@
 constexpr const char* kVndkNamespaceName = "vndk";
 constexpr const char* kVndkProductNamespaceName = "vndk_product";
 constexpr const char* kArtNamespaceName = "com_android_art";
+constexpr const char* kI18nNamespaceName = "com_android_i18n";
 constexpr const char* kNeuralNetworksNamespaceName = "com_android_neuralnetworks";
 constexpr const char* kStatsdNamespaceName = "com_android_os_statsd";
 
@@ -272,6 +273,15 @@
     }
   }
 
+  auto i18n_ns = NativeLoaderNamespace::GetExportedNamespace(kI18nNamespaceName, is_bridged);
+  // i18n APEX does not exist on host, and under certain build conditions.
+  if (i18n_ns.ok()) {
+    linked = app_ns->Link(*i18n_ns, i18n_public_libraries());
+    if (!linked.ok()) {
+      return linked.error();
+    }
+  }
+
   // Give access to NNAPI libraries (apex-updated LLNDK library).
   auto nnapi_ns =
       NativeLoaderNamespace::GetExportedNamespace(kNeuralNetworksNamespaceName, is_bridged);
diff --git a/libnativeloader/native_loader_test.cpp b/libnativeloader/native_loader_test.cpp
index 66d7531..e64e1a5 100644
--- a/libnativeloader/native_loader_test.cpp
+++ b/libnativeloader/native_loader_test.cpp
@@ -97,7 +97,7 @@
 static std::unordered_map<std::string, Platform::mock_namespace_handle> namespaces = {
     {"system", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("system"))},
     {"default", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("default"))},
-    {"com_android_art", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("com_android_art"))},
+    {"com_android_i18n", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("com_android_i18n"))},
     {"sphal", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("sphal"))},
     {"vndk", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("vndk"))},
     {"vndk_product", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("vndk_product"))},
@@ -355,6 +355,7 @@
   std::string expected_parent_namespace = "system";
   bool expected_link_with_platform_ns = true;
   bool expected_link_with_art_ns = true;
+  bool expected_link_with_i18n_ns = true;
   bool expected_link_with_sphal_ns = !vendor_public_libraries().empty();
   bool expected_link_with_vndk_ns = false;
   bool expected_link_with_vndk_product_ns = false;
@@ -363,6 +364,7 @@
   bool expected_link_with_statsd_ns = true;
   std::string expected_shared_libs_to_platform_ns = default_public_libraries();
   std::string expected_shared_libs_to_art_ns = art_public_libraries();
+  std::string expected_shared_libs_to_i18n_ns = i18n_public_libraries();
   std::string expected_shared_libs_to_sphal_ns = vendor_public_libraries();
   std::string expected_shared_libs_to_vndk_ns = vndksp_libraries_vendor();
   std::string expected_shared_libs_to_vndk_product_ns = vndksp_libraries_product();
@@ -393,6 +395,11 @@
                                               StrEq(expected_shared_libs_to_art_ns)))
           .WillOnce(Return(true));
     }
+    if (expected_link_with_i18n_ns) {
+      EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("com_android_i18n"),
+                                              StrEq(expected_shared_libs_to_i18n_ns)))
+          .WillOnce(Return(true));
+    }
     if (expected_link_with_sphal_ns) {
       EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("sphal"),
                                               StrEq(expected_shared_libs_to_sphal_ns)))
diff --git a/libnativeloader/public_libraries.cpp b/libnativeloader/public_libraries.cpp
index 7bb5a1f..575ce2d 100644
--- a/libnativeloader/public_libraries.cpp
+++ b/libnativeloader/public_libraries.cpp
@@ -57,12 +57,15 @@
 constexpr const char* kVndkLibrariesFile = "/apex/com.android.vndk.v{}/etc/vndksp.libraries.{}.txt";
 
 const std::vector<const std::string> kArtApexPublicLibraries = {
-    "libicuuc.so",
-    "libicui18n.so",
     "libnativehelper.so",
 };
 
-constexpr const char* kArtApexLibPath = "/apex/com.android.art/" LIB;
+const std::vector<const std::string> ki18nApexPublicLibraries = {
+    "libicuuc.so",
+    "libicui18n.so",
+};
+
+constexpr const char* kI18nApexLibPath = "/apex/com.android.i18n/" LIB;
 
 constexpr const char* kNeuralNetworksApexPublicLibrary = "libneuralnetworks.so";
 
@@ -195,14 +198,14 @@
     return android::base::Join(*sonames, ':');
   }
 
-  // Remove the public libs in the art namespace.
+  // Remove the public libs in the i18n namespace.
   // These libs are listed in public.android.txt, but we don't want the rest of android
   // in default namespace to dlopen the libs.
   // For example, libicuuc.so is exposed to classloader namespace from art namespace.
   // Unfortunately, it does not have stable C symbols, and default namespace should only use
   // stable symbols in libandroidicu.so. http://b/120786417
-  for (const std::string& lib_name : kArtApexPublicLibraries) {
-    std::string path(kArtApexLibPath);
+  for (const std::string& lib_name : ki18nApexPublicLibraries) {
+    std::string path(kI18nApexLibPath);
     path.append("/").append(lib_name);
 
     struct stat s;
@@ -237,6 +240,12 @@
   return list;
 }
 
+static std::string InitI18nPublicLibraries() {
+  static_assert(sizeof(ki18nApexPublicLibraries) > 0, "ki18nApexPublicLibraries is empty");
+  std::string list = android::base::Join(ki18nApexPublicLibraries, ":");
+  return list;
+}
+
 static std::string InitVendorPublicLibraries() {
   // This file is optional, quietly ignore if the file does not exist.
   auto sonames = ReadConfig(kVendorPublicLibrariesFile, always_true);
@@ -349,6 +358,11 @@
   return list;
 }
 
+const std::string& i18n_public_libraries() {
+  static std::string list = InitI18nPublicLibraries();
+  return list;
+}
+
 const std::string& vendor_public_libraries() {
   static std::string list = InitVendorPublicLibraries();
   return list;
diff --git a/libnativeloader/public_libraries.h b/libnativeloader/public_libraries.h
index 9b8b2a4..b60a2ef 100644
--- a/libnativeloader/public_libraries.h
+++ b/libnativeloader/public_libraries.h
@@ -36,6 +36,7 @@
 const std::string& statsd_public_libraries();
 const std::string& vendor_public_libraries();
 const std::string& extended_public_libraries();
+const std::string& i18n_public_libraries();
 const std::string& neuralnetworks_public_libraries();
 const std::string& llndk_libraries_product();
 const std::string& llndk_libraries_vendor();
diff --git a/runtime/gc/space/image_space_test.cc b/runtime/gc/space/image_space_test.cc
index b08c680..efd82d9 100644
--- a/runtime/gc/space/image_space_test.cc
+++ b/runtime/gc/space/image_space_test.cc
@@ -60,13 +60,17 @@
   int mkdir_result = mkdir(image_dir.c_str(), 0700);
   ASSERT_EQ(0, mkdir_result);
 
-  // Prepare boot class path variables, exclude conscrypt which is not in the primary boot image.
+  // Prepare boot class path variables, exclude core-icu4j and conscrypt
+  // which are not in the primary boot image.
   std::vector<std::string> bcp = GetLibCoreDexFileNames();
   std::vector<std::string> bcp_locations = GetLibCoreDexLocations();
   CHECK_EQ(bcp.size(), bcp_locations.size());
   ASSERT_NE(std::string::npos, bcp.back().find("conscrypt"));
   bcp.pop_back();
   bcp_locations.pop_back();
+  ASSERT_NE(std::string::npos, bcp.back().find("core-icu4j"));
+  bcp.pop_back();
+  bcp_locations.pop_back();
   std::string base_bcp_string = android::base::Join(bcp, ':');
   std::string base_bcp_locations_string = android::base::Join(bcp_locations, ':');
   std::string base_image_location = GetImageLocation();
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 97bb396..141aab7 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -711,7 +711,7 @@
 # Note: This must start with the CORE_IMG_JARS in Android.common_path.mk
 # because that's what we use for compiling the core.art image.
 # It may contain additional modules from TEST_CORE_JARS.
-bpath_modules="core-oj core-libart core-icu4j okhttp bouncycastle apache-xml conscrypt"
+bpath_modules="core-oj core-libart okhttp bouncycastle apache-xml core-icu4j conscrypt"
 bpath=""
 bpath_locations=""
 bpath_separator=""
@@ -736,6 +736,8 @@
       apex_module="com.android.art"
       if [ "${bpath_module}" = "conscrypt" ]; then
         apex_module="com.android.conscrypt"
+      elif [ "${bpath_module}" = "core-icu4j" ]; then
+        apex_module="com.android.i18n"
       fi
       bpath+="${bpath_separator}/apex/${apex_module}/javalib/${bpath_module}.jar"
       bpath_locations+="${bpath_separator}/apex/${apex_module}/javalib/${bpath_module}.jar"
diff --git a/tools/bootjars.sh b/tools/bootjars.sh
index bb840b0..d6882a5 100755
--- a/tools/bootjars.sh
+++ b/tools/bootjars.sh
@@ -75,15 +75,19 @@
   # Note: This must start with the CORE_IMG_JARS in Android.common_path.mk
   # because that's what we use for compiling the core.art image.
   # It may contain additional modules from TEST_CORE_JARS.
-  core_jars_list="core-oj core-libart core-icu4j okhttp bouncycastle apache-xml"
-  core_jars_suffix=
-  if [[ $mode == host ]]; then
-    core_jars_suffix=-hostdex
-  fi
+  core_jars_list="core-oj core-libart okhttp bouncycastle apache-xml core-icu4j"
   boot_jars_list=""
   boot_separator=""
   for boot_module in ${core_jars_list}; do
-    boot_jars_list+="${boot_separator}${boot_module}${core_jars_suffix}"
+    jar_suffix=
+    if [[ $mode == host ]]; then
+      if [[ $boot_module == core-icu4j ]]; then
+        jar_suffix="-host-hostdex"
+      else
+        jar_suffix="-hostdex"
+      fi
+    fi
+    boot_jars_list+="${boot_separator}${boot_module}${jar_suffix}"
     boot_separator=" "
   done
 else
@@ -108,6 +112,8 @@
   for jar in $boot_jars_list; do
     if [[ $jar == "conscrypt" ]]; then
       echo "$intermediates_dir/JAVA_LIBRARIES/${jar}.com.android.conscrypt_intermediates/classes.jar"
+    elif [[ $jar == "core-icu4j" ]]; then
+      echo "$intermediates_dir/JAVA_LIBRARIES/${jar}.com.android.i18n_intermediates/classes.jar"
     else
       echo "$intermediates_dir/JAVA_LIBRARIES/${jar}.com.android.art.testing_intermediates/classes.jar"
     fi
diff --git a/tools/run-jdwp-tests.sh b/tools/run-jdwp-tests.sh
index f67e46d..062db09 100755
--- a/tools/run-jdwp-tests.sh
+++ b/tools/run-jdwp-tests.sh
@@ -42,6 +42,8 @@
   do
     if [ "$var" = "conscrypt" ] && [ "$mode" = "target" ]; then
       printf -- "${separator}/apex/com.android.conscrypt/javalib/conscrypt.jar";
+    elif [ "$var" = "core-icu4j" ] && [ "$mode" = "target" ]; then
+      printf -- "${separator}/apex/com.android.i18n/javalib/core-icu4j.jar";
     else
       printf -- "${separator}${dir}/${var}${suffix}.jar";
     fi
@@ -52,7 +54,7 @@
 # Note: This must start with the CORE_IMG_JARS in Android.common_path.mk
 # because that's what we use for compiling the core.art image.
 # It may contain additional modules from TEST_CORE_JARS.
-BOOT_CLASSPATH_JARS="core-oj core-libart core-icu4j okhttp bouncycastle apache-xml conscrypt"
+BOOT_CLASSPATH_JARS="core-oj core-libart okhttp bouncycastle apache-xml core-icu4j conscrypt"
 
 vm_args=""
 art="$android_root/bin/art"
diff --git a/tools/run-libcore-tests.sh b/tools/run-libcore-tests.sh
index 7140b13..ff3c433 100755
--- a/tools/run-libcore-tests.sh
+++ b/tools/run-libcore-tests.sh
@@ -52,7 +52,7 @@
   do
     printf -- ":${dir}/${var}.jar";
   done
-  printf -- ":/apex/com.android.conscrypt/javalib/conscrypt.jar";
+  printf -- ":/apex/com.android.i18n/javalib/core-icu4j.jar:/apex/com.android.conscrypt/javalib/conscrypt.jar";
 }
 
 function usage {
@@ -147,7 +147,7 @@
 # Note: This must start with the CORE_IMG_JARS in Android.common_path.mk
 # because that's what we use for compiling the core.art image.
 # It may contain additional modules from TEST_CORE_JARS.
-BOOT_CLASSPATH_JARS="core-oj core-libart core-icu4j okhttp bouncycastle apache-xml"
+BOOT_CLASSPATH_JARS="core-oj core-libart okhttp bouncycastle apache-xml"
 
 DEPS="core-tests jsr166-tests mockito-target"