Merge "libsnapshot: Record COW size(s) in snapshot status file"
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index c91fbe4..f8c492d 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -426,7 +426,7 @@
     return true;
 }
 
-bool MetadataBuilder::AddGroup(const std::string& group_name, uint64_t maximum_size) {
+bool MetadataBuilder::AddGroup(std::string_view group_name, uint64_t maximum_size) {
     if (FindGroup(group_name)) {
         LERROR << "Group already exists: " << group_name;
         return false;
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index e3b591a..5ab42f5 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -91,7 +91,7 @@
     friend class MetadataBuilder;
 
   public:
-    explicit PartitionGroup(const std::string& name, uint64_t maximum_size)
+    explicit PartitionGroup(std::string_view name, uint64_t maximum_size)
         : name_(name), maximum_size_(maximum_size) {}
 
     const std::string& name() const { return name_; }
@@ -206,7 +206,7 @@
     // total space used by all partitions in the group.
     //
     // This can fail and return false if the group already exists.
-    bool AddGroup(const std::string& group_name, uint64_t maximum_size);
+    bool AddGroup(std::string_view group_name, uint64_t maximum_size);
 
     // Export metadata so it can be serialized to an image, to disk, or mounted
     // via device-mapper.
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index e685cad..7f37dc5 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -106,6 +106,10 @@
     return partition_name + "-base";
 }
 
+static std::string GetSnapshotExtraDeviceName(const std::string& snapshot_name) {
+    return snapshot_name + "-inner";
+}
+
 bool SnapshotManager::BeginUpdate() {
     auto file = LockExclusive();
     if (!file) return false;
@@ -302,7 +306,7 @@
     // and a linear target in the same table. Instead, we stack them, and give the
     // snapshot device a different name. It is not exposed to the caller in this
     // case.
-    auto snap_name = (linear_sectors > 0) ? name + "-inner" : name;
+    auto snap_name = (linear_sectors > 0) ? GetSnapshotExtraDeviceName(name) : name;
 
     DmTable table;
     table.Emplace<DmTargetSnapshot>(0, snapshot_sectors, base_device, cow_dev, mode,
@@ -1413,7 +1417,7 @@
 std::string SnapshotManager::GetSnapshotDeviceName(const std::string& snapshot_name,
                                                    const SnapshotStatus& status) {
     if (status.device_size != status.snapshot_size) {
-        return snapshot_name + "-inner";
+        return GetSnapshotExtraDeviceName(snapshot_name);
     }
     return snapshot_name;
 }
diff --git a/init/epoll.cpp b/init/epoll.cpp
index 01d8867..17d63fa 100644
--- a/init/epoll.cpp
+++ b/init/epoll.cpp
@@ -69,19 +69,24 @@
     return {};
 }
 
-Result<void> Epoll::Wait(std::optional<std::chrono::milliseconds> timeout) {
+Result<std::vector<std::function<void()>*>> Epoll::Wait(
+        std::optional<std::chrono::milliseconds> timeout) {
     int timeout_ms = -1;
     if (timeout && timeout->count() < INT_MAX) {
         timeout_ms = timeout->count();
     }
-    epoll_event ev;
-    auto nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd_, &ev, 1, timeout_ms));
-    if (nr == -1) {
+    const auto max_events = epoll_handlers_.size();
+    epoll_event ev[max_events];
+    auto num_events = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd_, ev, max_events, timeout_ms));
+    if (num_events == -1) {
         return ErrnoError() << "epoll_wait failed";
-    } else if (nr == 1) {
-        std::invoke(*reinterpret_cast<std::function<void()>*>(ev.data.ptr));
     }
-    return {};
+    std::vector<std::function<void()>*> pending_functions;
+    for (int i = 0; i < num_events; ++i) {
+        pending_functions.emplace_back(reinterpret_cast<std::function<void()>*>(ev[i].data.ptr));
+    }
+
+    return pending_functions;
 }
 
 }  // namespace init
diff --git a/init/epoll.h b/init/epoll.h
index ca84266..c32a661 100644
--- a/init/epoll.h
+++ b/init/epoll.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef _INIT_EPOLL_H
-#define _INIT_EPOLL_H
+#pragma once
 
 #include <stdint.h>
 #include <sys/epoll.h>
@@ -24,6 +23,7 @@
 #include <functional>
 #include <map>
 #include <optional>
+#include <vector>
 
 #include <android-base/unique_fd.h>
 
@@ -39,7 +39,8 @@
     Result<void> Open();
     Result<void> RegisterHandler(int fd, std::function<void()> handler, uint32_t events = EPOLLIN);
     Result<void> UnregisterHandler(int fd);
-    Result<void> Wait(std::optional<std::chrono::milliseconds> timeout);
+    Result<std::vector<std::function<void()>*>> Wait(
+            std::optional<std::chrono::milliseconds> timeout);
 
   private:
     android::base::unique_fd epoll_fd_;
@@ -48,5 +49,3 @@
 
 }  // namespace init
 }  // namespace android
-
-#endif
diff --git a/init/init.cpp b/init/init.cpp
index ce898de..d4cbb5f 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -787,8 +787,17 @@
             if (am.HasMoreCommands()) epoll_timeout = 0ms;
         }
 
-        if (auto result = epoll.Wait(epoll_timeout); !result) {
-            LOG(ERROR) << result.error();
+        auto pending_functions = epoll.Wait(epoll_timeout);
+        if (!pending_functions) {
+            LOG(ERROR) << pending_functions.error();
+        } else if (!pending_functions->empty()) {
+            // We always reap children before responding to the other pending functions. This is to
+            // prevent a race where other daemons see that a service has exited and ask init to
+            // start it again via ctl.start before init has reaped it.
+            ReapAnyOutstandingChildren();
+            for (const auto& function : *pending_functions) {
+                (*function)();
+            }
         }
     }
 
diff --git a/init/keychords_test.cpp b/init/keychords_test.cpp
index 33373d4..6e9b337 100644
--- a/init/keychords_test.cpp
+++ b/init/keychords_test.cpp
@@ -212,7 +212,11 @@
 }
 
 void TestFrame::RelaxForMs(std::chrono::milliseconds wait) {
-    epoll_.Wait(wait);
+    auto pending_functions = epoll_.Wait(wait);
+    ASSERT_TRUE(pending_functions) << pending_functions.error();
+    for (const auto& function : *pending_functions) {
+        (*function)();
+    }
 }
 
 void TestFrame::SetChord(int key, bool value) {
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
index 12144c1..0745148 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -91,22 +91,22 @@
         return false;
     }
 
-    // Special casing for the runtime APEX
-    constexpr const char kRuntimeApexMountPath[] = "/system/apex/com.android.runtime";
-    static const std::vector<std::string> kRuntimeApexDirNames = {"com.android.runtime.release",
-                                                                  "com.android.runtime.debug"};
+    // Special casing for the ART APEX
+    constexpr const char kArtApexMountPath[] = "/system/apex/com.android.art";
+    static const std::vector<std::string> kArtApexDirNames = {"com.android.art.release",
+                                                              "com.android.art.debug"};
     bool success = false;
-    for (const auto& name : kRuntimeApexDirNames) {
+    for (const auto& name : kArtApexDirNames) {
         std::string path = std::string(kSystemApex) + "/" + name;
         if (access(path.c_str(), F_OK) == 0) {
-            if (mount(path.c_str(), kRuntimeApexMountPath, nullptr, MS_BIND, nullptr) == 0) {
+            if (mount(path.c_str(), kArtApexMountPath, nullptr, MS_BIND, nullptr) == 0) {
                 success = true;
                 break;
             }
         }
     }
     if (!success) {
-        PLOG(ERROR) << "Failed to bind mount the runtime APEX to " << kRuntimeApexMountPath;
+        PLOG(ERROR) << "Failed to bind mount the ART APEX to " << kArtApexMountPath;
     }
     return success;
 }
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 6842820..4852cd0 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -439,7 +439,8 @@
     bool is_enforcing = IsEnforcing();
     if (kernel_enforcing != is_enforcing) {
         if (security_setenforce(is_enforcing)) {
-            PLOG(FATAL) << "security_setenforce(%s) failed" << (is_enforcing ? "true" : "false");
+            PLOG(FATAL) << "security_setenforce(" << (is_enforcing ? "true" : "false")
+                        << ") failed";
         }
     }
 
diff --git a/init/service.cpp b/init/service.cpp
index 9537843..7a20966 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -116,9 +116,10 @@
     return execv(c_strings[0], c_strings.data()) == 0;
 }
 
-static bool IsRuntimeApexReady() {
+static bool AreRuntimeApexesReady() {
     struct stat buf;
-    return stat("/apex/com.android.runtime/", &buf) == 0;
+    return stat("/apex/com.android.art/", &buf) == 0 &&
+           stat("/apex/com.android.runtime/", &buf) == 0;
 }
 
 unsigned long Service::next_start_order_ = 1;
@@ -406,11 +407,11 @@
         scon = *result;
     }
 
-    if (!IsRuntimeApexReady() && !pre_apexd_) {
-        // If this service is started before the runtime APEX gets available,
-        // mark it as pre-apexd one. Note that this marking is permanent. So
-        // for example, if the service is re-launched (e.g., due to crash),
-        // it is still recognized as pre-apexd... for consistency.
+    if (!AreRuntimeApexesReady() && !pre_apexd_) {
+        // If this service is started before the Runtime and ART APEXes get
+        // available, mark it as pre-apexd one. Note that this marking is
+        // permanent. So for example, if the service is re-launched (e.g., due
+        // to crash), it is still recognized as pre-apexd... for consistency.
         pre_apexd_ = true;
     }
 
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 6d3c057..60d462f 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -63,6 +63,10 @@
     LOG_ALWAYS_FATAL_IF((dot_index == std::string::npos),
                         "Error finding namespace of apex: no dot in apex name %s", caller_location);
     std::string name = location.substr(dot_index + 1, slash_index - dot_index - 1);
+    // TODO(b/139408016): Rename the runtime namespace to "art".
+    if (name == "art") {
+      name = "runtime";
+    }
     android_namespace_t* boot_namespace = android_get_exported_namespace(name.c_str());
     LOG_ALWAYS_FATAL_IF((boot_namespace == nullptr),
                         "Error finding namespace of apex: no namespace called %s", name.c_str());
diff --git a/libnativeloader/public_libraries.cpp b/libnativeloader/public_libraries.cpp
index 3694360..93df1d0 100644
--- a/libnativeloader/public_libraries.cpp
+++ b/libnativeloader/public_libraries.cpp
@@ -49,12 +49,12 @@
 constexpr const char* kLlndkLibrariesFile = "/system/etc/llndk.libraries.txt";
 constexpr const char* kVndkLibrariesFile = "/system/etc/vndksp.libraries.txt";
 
-const std::vector<const std::string> kRuntimePublicLibraries = {
+const std::vector<const std::string> kArtApexPublicLibraries = {
     "libicuuc.so",
     "libicui18n.so",
 };
 
-constexpr const char* kRuntimeApexLibPath = "/apex/com.android.runtime/" LIB;
+constexpr const char* kArtApexLibPath = "/apex/com.android.art/" LIB;
 
 constexpr const char* kNeuralNetworksApexPublicLibrary = "libneuralnetworks.so";
 
@@ -182,8 +182,8 @@
   // For example, libicuuc.so is exposed to classloader namespace from runtime 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 : kRuntimePublicLibraries) {
-    std::string path(kRuntimeApexLibPath);
+  for (const std::string& lib_name : kArtApexPublicLibraries) {
+    std::string path(kArtApexLibPath);
     path.append("/").append(lib_name);
 
     struct stat s;
@@ -207,9 +207,9 @@
   return android::base::Join(*sonames, ':');
 }
 
-static std::string InitRuntimePublicLibraries() {
-  CHECK(sizeof(kRuntimePublicLibraries) > 0);
-  std::string list = android::base::Join(kRuntimePublicLibraries, ":");
+static std::string InitArtPublicLibraries() {
+  CHECK(sizeof(kArtApexPublicLibraries) > 0);
+  std::string list = android::base::Join(kArtApexPublicLibraries, ":");
 
   std::string additional_libs = additional_public_libraries();
   if (!additional_libs.empty()) {
@@ -277,7 +277,7 @@
 }
 
 const std::string& runtime_public_libraries() {
-  static std::string list = InitRuntimePublicLibraries();
+  static std::string list = InitArtPublicLibraries();
   return list;
 }
 
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 73237e6..14246ae 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -211,6 +211,7 @@
         "tests/UnwindOfflineTest.cpp",
         "tests/UnwindTest.cpp",
         "tests/UnwinderTest.cpp",
+        "tests/VerifyBionicTerminationTest.cpp",
     ],
 
     cflags: [
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 7556482..0b9b85c 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -309,7 +309,7 @@
   }
 }
 
-std::string Unwinder::FormatFrame(const FrameData& frame) {
+std::string Unwinder::FormatFrame(const FrameData& frame) const {
   std::string data;
   if (regs_->Is32Bit()) {
     data += android::base::StringPrintf("  #%02zu pc %08" PRIx64, frame.num, frame.rel_pc);
@@ -355,7 +355,7 @@
   return data;
 }
 
-std::string Unwinder::FormatFrame(size_t frame_num) {
+std::string Unwinder::FormatFrame(size_t frame_num) const {
   if (frame_num >= frames_.size()) {
     return "";
   }
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 52b3578..11ad9de 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -77,7 +77,7 @@
   void Unwind(const std::vector<std::string>* initial_map_names_to_skip = nullptr,
               const std::vector<std::string>* map_suffixes_to_ignore = nullptr);
 
-  size_t NumFrames() { return frames_.size(); }
+  size_t NumFrames() const { return frames_.size(); }
 
   const std::vector<FrameData>& frames() { return frames_; }
 
@@ -87,8 +87,8 @@
     return frames;
   }
 
-  std::string FormatFrame(size_t frame_num);
-  std::string FormatFrame(const FrameData& frame);
+  std::string FormatFrame(size_t frame_num) const;
+  std::string FormatFrame(const FrameData& frame) const;
 
   void SetJitDebug(JitDebug* jit_debug, ArchEnum arch);
 
diff --git a/libunwindstack/tests/VerifyBionicTerminationTest.cpp b/libunwindstack/tests/VerifyBionicTerminationTest.cpp
new file mode 100644
index 0000000..6a3e91a
--- /dev/null
+++ b/libunwindstack/tests/VerifyBionicTerminationTest.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE 1
+#include <stdint.h>
+#include <string.h>
+
+#include <string>
+
+#if defined(__BIONIC__)
+
+#include <gtest/gtest.h>
+
+#include <unwindstack/DwarfSection.h>
+#include <unwindstack/Elf.h>
+#include <unwindstack/ElfInterface.h>
+#include <unwindstack/Regs.h>
+#include <unwindstack/RegsGetLocal.h>
+#include <unwindstack/Unwinder.h>
+
+// This test is specific to bionic to verify that __libc_init is
+// properly setting the return address to undefined so that the
+// unwind properly terminates.
+
+namespace unwindstack {
+
+static std::string DumpFrames(const UnwinderFromPid& unwinder) {
+  std::string unwind;
+  for (size_t i = 0; i < unwinder.NumFrames(); i++) {
+    unwind += unwinder.FormatFrame(i) + '\n';
+  }
+  return unwind;
+}
+
+static DwarfLocationEnum GetReturnAddressLocation(uint64_t rel_pc, DwarfSection* section) {
+  if (section == nullptr) {
+    return DWARF_LOCATION_INVALID;
+  }
+
+  const DwarfFde* fde = section->GetFdeFromPc(rel_pc);
+  if (fde == nullptr || fde->cie == nullptr) {
+    return DWARF_LOCATION_INVALID;
+  }
+  dwarf_loc_regs_t regs;
+  if (!section->GetCfaLocationInfo(rel_pc, fde, &regs)) {
+    return DWARF_LOCATION_INVALID;
+  }
+
+  auto reg_entry = regs.find(fde->cie->return_address_register);
+  if (reg_entry == regs.end()) {
+    return DWARF_LOCATION_INVALID;
+  }
+  return reg_entry->second.type;
+}
+
+static void VerifyReturnAddress(const FrameData& frame) {
+  // Now go and find information about the register data and verify that the relative pc results in
+  // an undefined register.
+  Elf elf(Memory::CreateFileMemory(frame.map_name, 0).release());
+  ASSERT_TRUE(elf.Init()) << "Failed to init elf object from " << frame.map_name;
+  ASSERT_TRUE(elf.valid()) << "Elf " << frame.map_name << " is not valid.";
+  ElfInterface* interface = elf.interface();
+
+  // Only check the eh_frame and the debug_frame since the undefined register
+  // is set using a cfi directive.
+  // Check debug_frame first, then eh_frame since debug_frame always
+  // contains the most specific data.
+  DwarfLocationEnum location = GetReturnAddressLocation(frame.rel_pc, interface->debug_frame());
+  if (location == DWARF_LOCATION_UNDEFINED) {
+    return;
+  }
+
+  location = GetReturnAddressLocation(frame.rel_pc, interface->eh_frame());
+  ASSERT_EQ(DWARF_LOCATION_UNDEFINED, location);
+}
+
+// This test assumes that it starts from the main thread, and that the
+// libc.so on device will include symbols so that function names can
+// be resolved.
+TEST(VerifyBionicTermination, local_terminate) {
+  std::unique_ptr<Regs> regs(Regs::CreateFromLocal());
+
+  UnwinderFromPid unwinder(512, getpid());
+  ASSERT_TRUE(unwinder.Init(regs->Arch()));
+  unwinder.SetRegs(regs.get());
+
+  RegsGetLocal(regs.get());
+  unwinder.Unwind();
+  ASSERT_LT(0U, unwinder.NumFrames());
+
+  SCOPED_TRACE(DumpFrames(unwinder));
+
+  // Look for the frame that includes __libc_init, there should only
+  // be one and it should be the last.
+  bool found = false;
+  const std::vector<FrameData>& frames = unwinder.frames();
+  for (size_t i = 0; i < unwinder.NumFrames(); i++) {
+    const FrameData& frame = frames[i];
+    if (frame.function_name == "__libc_init" && !frame.map_name.empty() &&
+        std::string("libc.so") == basename(frame.map_name.c_str())) {
+      ASSERT_EQ(unwinder.NumFrames(), i + 1) << "__libc_init is not last frame.";
+      ASSERT_NO_FATAL_FAILURE(VerifyReturnAddress(frame));
+      found = true;
+    }
+  }
+  ASSERT_TRUE(found) << "Unable to find libc.so:__libc_init frame\n";
+}
+
+}  // namespace unwindstack
+
+#endif
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 30798dd..8be4dd0 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -205,7 +205,6 @@
         "Mutex_test.cpp",
         "SharedBuffer_test.cpp",
         "String8_test.cpp",
-        "String16_test.cpp",
         "StrongPointer_test.cpp",
         "Unicode_test.cpp",
         "Vector_test.cpp",
diff --git a/libutils/SharedBuffer.cpp b/libutils/SharedBuffer.cpp
index 3e703db..7910c6e 100644
--- a/libutils/SharedBuffer.cpp
+++ b/libutils/SharedBuffer.cpp
@@ -41,7 +41,6 @@
         // The following is OK on Android-supported platforms.
         sb->mRefs.store(1, std::memory_order_relaxed);
         sb->mSize = size;
-        sb->mClientMetadata = 0;
     }
     return sb;
 }
diff --git a/libutils/SharedBuffer.h b/libutils/SharedBuffer.h
index 476c842..fdf13a9 100644
--- a/libutils/SharedBuffer.h
+++ b/libutils/SharedBuffer.h
@@ -102,12 +102,7 @@
         // Must be sized to preserve correct alignment.
         mutable std::atomic<int32_t>        mRefs;
                 size_t                      mSize;
-                uint32_t                    mReserved;
-public:
-        // mClientMetadata is reserved for client use.  It is initialized to 0
-        // and the clients can do whatever they want with it.  Note that this is
-        // placed last so that it is adjcent to the buffer allocated.
-                uint32_t                    mClientMetadata;
+                uint32_t                    mReserved[2];
 };
 
 static_assert(sizeof(SharedBuffer) % 8 == 0
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index 5c3cf32..818b171 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -24,21 +24,21 @@
 
 namespace android {
 
-static const StaticString16 emptyString(u"");
 static inline char16_t* getEmptyString() {
-    return const_cast<char16_t*>(emptyString.string());
+    static SharedBuffer* gEmptyStringBuf = [] {
+        SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t));
+        char16_t* str = static_cast<char16_t*>(buf->data());
+        *str = 0;
+        return buf;
+    }();
+
+    gEmptyStringBuf->acquire();
+    return static_cast<char16_t*>(gEmptyStringBuf->data());
 }
 
 // ---------------------------------------------------------------------------
 
-void* String16::alloc(size_t size)
-{
-    SharedBuffer* buf = SharedBuffer::alloc(size);
-    buf->mClientMetadata = kIsSharedBufferAllocated;
-    return buf;
-}
-
-char16_t* String16::allocFromUTF8(const char* u8str, size_t u8len)
+static char16_t* allocFromUTF8(const char* u8str, size_t u8len)
 {
     if (u8len == 0) return getEmptyString();
 
@@ -49,7 +49,7 @@
         return getEmptyString();
     }
 
-    SharedBuffer* buf = static_cast<SharedBuffer*>(alloc(sizeof(char16_t) * (u16len + 1)));
+    SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t)*(u16len+1));
     if (buf) {
         u8cur = (const uint8_t*) u8str;
         char16_t* u16str = (char16_t*)buf->data();
@@ -66,13 +66,13 @@
     return getEmptyString();
 }
 
-char16_t* String16::allocFromUTF16(const char16_t* u16str, size_t u16len) {
+static char16_t* allocFromUTF16(const char16_t* u16str, size_t u16len) {
     if (u16len >= SIZE_MAX / sizeof(char16_t)) {
         android_errorWriteLog(0x534e4554, "73826242");
         abort();
     }
 
-    SharedBuffer* buf = static_cast<SharedBuffer*>(alloc((u16len + 1) * sizeof(char16_t)));
+    SharedBuffer* buf = SharedBuffer::alloc((u16len + 1) * sizeof(char16_t));
     ALOG_ASSERT(buf, "Unable to allocate shared buffer");
     if (buf) {
         char16_t* str = (char16_t*)buf->data();
@@ -97,8 +97,8 @@
     // having run. In this case we always allocate an empty string. It's less
     // efficient than using getEmptyString(), but we assume it's uncommon.
 
-    SharedBuffer* buf = static_cast<SharedBuffer*>(alloc(sizeof(char16_t)));
-    char16_t* data = static_cast<char16_t*>(buf->data());
+    char16_t* data = static_cast<char16_t*>(
+            SharedBuffer::alloc(sizeof(char16_t))->data());
     data[0] = 0;
     mString = data;
 }
@@ -106,7 +106,7 @@
 String16::String16(const String16& o)
     : mString(o.mString)
 {
-    acquire();
+    SharedBuffer::bufferFromData(mString)->acquire();
 }
 
 String16::String16(const String16& o, size_t len, size_t begin)
@@ -136,30 +136,26 @@
 
 String16::~String16()
 {
-    release();
+    SharedBuffer::bufferFromData(mString)->release();
 }
 
 size_t String16::size() const
 {
-    if (isStaticString()) {
-        return staticStringSize();
-    } else {
-        return SharedBuffer::sizeFromData(mString) / sizeof(char16_t) - 1;
-    }
+    return SharedBuffer::sizeFromData(mString)/sizeof(char16_t)-1;
 }
 
 void String16::setTo(const String16& other)
 {
-    release();
+    SharedBuffer::bufferFromData(other.mString)->acquire();
+    SharedBuffer::bufferFromData(mString)->release();
     mString = other.mString;
-    acquire();
 }
 
 status_t String16::setTo(const String16& other, size_t len, size_t begin)
 {
     const size_t N = other.size();
     if (begin >= N) {
-        release();
+        SharedBuffer::bufferFromData(mString)->release();
         mString = getEmptyString();
         return OK;
     }
@@ -188,7 +184,8 @@
         abort();
     }
 
-    SharedBuffer* buf = static_cast<SharedBuffer*>(editResize((len + 1) * sizeof(char16_t)));
+    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+        ->editResize((len+1)*sizeof(char16_t));
     if (buf) {
         char16_t* str = (char16_t*)buf->data();
         memmove(str, other, len*sizeof(char16_t));
@@ -215,8 +212,8 @@
         abort();
     }
 
-    SharedBuffer* buf =
-            static_cast<SharedBuffer*>(editResize((myLen + otherLen + 1) * sizeof(char16_t)));
+    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+        ->editResize((myLen+otherLen+1)*sizeof(char16_t));
     if (buf) {
         char16_t* str = (char16_t*)buf->data();
         memcpy(str+myLen, other, (otherLen+1)*sizeof(char16_t));
@@ -241,8 +238,8 @@
         abort();
     }
 
-    SharedBuffer* buf =
-            static_cast<SharedBuffer*>(editResize((myLen + otherLen + 1) * sizeof(char16_t)));
+    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+        ->editResize((myLen+otherLen+1)*sizeof(char16_t));
     if (buf) {
         char16_t* str = (char16_t*)buf->data();
         memcpy(str+myLen, chrs, otherLen*sizeof(char16_t));
@@ -276,8 +273,8 @@
            len, myLen, String8(chrs, len).string());
     #endif
 
-    SharedBuffer* buf =
-            static_cast<SharedBuffer*>(editResize((myLen + len + 1) * sizeof(char16_t)));
+    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+        ->editResize((myLen+len+1)*sizeof(char16_t));
     if (buf) {
         char16_t* str = (char16_t*)buf->data();
         if (pos < myLen) {
@@ -341,87 +338,23 @@
     return strstr16(mString, chrs) != nullptr;
 }
 
-void* String16::edit() {
-    SharedBuffer* buf;
-    if (isStaticString()) {
-        buf = static_cast<SharedBuffer*>(alloc((size() + 1) * sizeof(char16_t)));
-        if (buf) {
-            buf->acquire();
-            memcpy(buf->data(), mString, (size() + 1) * sizeof(char16_t));
-        }
-    } else {
-        buf = SharedBuffer::bufferFromData(mString)->edit();
-        buf->mClientMetadata = kIsSharedBufferAllocated;
-    }
-    return buf;
-}
-
-void* String16::editResize(size_t newSize) {
-    SharedBuffer* buf;
-    if (isStaticString()) {
-        size_t copySize = (size() + 1) * sizeof(char16_t);
-        if (newSize < copySize) {
-            copySize = newSize;
-        }
-        buf = static_cast<SharedBuffer*>(alloc(newSize));
-        if (buf) {
-            buf->acquire();
-            memcpy(buf->data(), mString, copySize);
-        }
-    } else {
-        buf = SharedBuffer::bufferFromData(mString)->editResize(newSize);
-        buf->mClientMetadata = kIsSharedBufferAllocated;
-    }
-    return buf;
-}
-
-void String16::acquire()
-{
-    if (!isStaticString()) {
-        SharedBuffer::bufferFromData(mString)->acquire();
-    }
-}
-
-void String16::release()
-{
-    if (!isStaticString()) {
-        SharedBuffer::bufferFromData(mString)->release();
-    }
-}
-
-bool String16::isStaticString() const {
-    // See String16.h for notes on the memory layout of String16::StaticData and
-    // SharedBuffer.
-    static_assert(sizeof(SharedBuffer) - offsetof(SharedBuffer, mClientMetadata) == 4);
-    const uint32_t* p = reinterpret_cast<const uint32_t*>(mString);
-    return (*(p - 1) & kIsSharedBufferAllocated) == 0;
-}
-
-size_t String16::staticStringSize() const {
-    // See String16.h for notes on the memory layout of String16::StaticData and
-    // SharedBuffer.
-    static_assert(sizeof(SharedBuffer) - offsetof(SharedBuffer, mClientMetadata) == 4);
-    const uint32_t* p = reinterpret_cast<const uint32_t*>(mString);
-    return static_cast<size_t>(*(p - 1));
-}
-
 status_t String16::makeLower()
 {
     const size_t N = size();
     const char16_t* str = string();
-    char16_t* edited = nullptr;
+    char16_t* edit = nullptr;
     for (size_t i=0; i<N; i++) {
         const char16_t v = str[i];
         if (v >= 'A' && v <= 'Z') {
-            if (!edited) {
-                SharedBuffer* buf = static_cast<SharedBuffer*>(edit());
+            if (!edit) {
+                SharedBuffer* buf = SharedBuffer::bufferFromData(mString)->edit();
                 if (!buf) {
                     return NO_MEMORY;
                 }
-                edited = (char16_t*)buf->data();
-                mString = str = edited;
+                edit = (char16_t*)buf->data();
+                mString = str = edit;
             }
-            edited[i] = tolower((char)v);
+            edit[i] = tolower((char)v);
         }
     }
     return OK;
@@ -431,18 +364,18 @@
 {
     const size_t N = size();
     const char16_t* str = string();
-    char16_t* edited = nullptr;
+    char16_t* edit = nullptr;
     for (size_t i=0; i<N; i++) {
         if (str[i] == replaceThis) {
-            if (!edited) {
-                SharedBuffer* buf = static_cast<SharedBuffer*>(edit());
+            if (!edit) {
+                SharedBuffer* buf = SharedBuffer::bufferFromData(mString)->edit();
                 if (!buf) {
                     return NO_MEMORY;
                 }
-                edited = (char16_t*)buf->data();
-                mString = str = edited;
+                edit = (char16_t*)buf->data();
+                mString = str = edit;
             }
-            edited[i] = withThis;
+            edit[i] = withThis;
         }
     }
     return OK;
@@ -452,7 +385,7 @@
 {
     const size_t N = size();
     if (begin >= N) {
-        release();
+        SharedBuffer::bufferFromData(mString)->release();
         mString = getEmptyString();
         return OK;
     }
@@ -462,7 +395,8 @@
     }
 
     if (begin > 0) {
-        SharedBuffer* buf = static_cast<SharedBuffer*>(editResize((N + 1) * sizeof(char16_t)));
+        SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+            ->editResize((N+1)*sizeof(char16_t));
         if (!buf) {
             return NO_MEMORY;
         }
@@ -470,7 +404,8 @@
         memmove(str, str+begin, (N-begin+1)*sizeof(char16_t));
         mString = str;
     }
-    SharedBuffer* buf = static_cast<SharedBuffer*>(editResize((len + 1) * sizeof(char16_t)));
+    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+        ->editResize((len+1)*sizeof(char16_t));
     if (buf) {
         char16_t* str = (char16_t*)buf->data();
         str[len] = 0;
diff --git a/libutils/String16_test.cpp b/libutils/String16_test.cpp
deleted file mode 100644
index f1f24c3..0000000
--- a/libutils/String16_test.cpp
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <utils/String16.h>
-#include <utils/String8.h>
-
-#include <gtest/gtest.h>
-
-namespace android {
-
-::testing::AssertionResult Char16_tStringEquals(const char16_t* a, const char16_t* b) {
-    if (strcmp16(a, b) != 0) {
-        return ::testing::AssertionFailure()
-               << "\"" << String8(a).c_str() << "\" not equal to \"" << String8(b).c_str() << "\"";
-    }
-    return ::testing::AssertionSuccess();
-}
-
-#define EXPECT_STR16EQ(a, b) EXPECT_TRUE(Char16_tStringEquals(a, b))
-
-TEST(String16Test, FromChar16_t) {
-    String16 tmp(u"Verify me");
-    EXPECT_STR16EQ(u"Verify me", tmp);
-}
-
-TEST(String16Test, FromChar16_tSized) {
-    String16 tmp(u"Verify me", 7);
-    EXPECT_STR16EQ(u"Verify ", tmp);
-}
-
-TEST(String16Test, FromChar) {
-    String16 tmp("Verify me");
-    EXPECT_STR16EQ(u"Verify me", tmp);
-}
-
-TEST(String16Test, FromCharSized) {
-    String16 tmp("Verify me", 7);
-    EXPECT_STR16EQ(u"Verify ", tmp);
-}
-
-TEST(String16Test, Copy) {
-    String16 tmp("Verify me");
-    String16 another = tmp;
-    EXPECT_STR16EQ(u"Verify me", tmp);
-    EXPECT_STR16EQ(u"Verify me", another);
-}
-
-TEST(String16Test, Move) {
-    String16 tmp("Verify me");
-    String16 another(std::move(tmp));
-    EXPECT_STR16EQ(u"Verify me", another);
-}
-
-TEST(String16Test, Size) {
-    String16 tmp("Verify me");
-    EXPECT_EQ(9U, tmp.size());
-}
-
-TEST(String16Test, setTo) {
-    String16 tmp("Verify me");
-    tmp.setTo(u"New content");
-    EXPECT_EQ(11U, tmp.size());
-    EXPECT_STR16EQ(u"New content", tmp);
-}
-
-TEST(String16Test, Append) {
-    String16 tmp("Verify me");
-    tmp.append(String16("Hello"));
-    EXPECT_EQ(14U, tmp.size());
-    EXPECT_STR16EQ(u"Verify meHello", tmp);
-}
-
-TEST(String16Test, Insert) {
-    String16 tmp("Verify me");
-    tmp.insert(6, u"Insert");
-    EXPECT_EQ(15U, tmp.size());
-    EXPECT_STR16EQ(u"VerifyInsert me", tmp);
-}
-
-TEST(String16Test, Remove) {
-    String16 tmp("Verify me");
-    tmp.remove(2, 6);
-    EXPECT_EQ(2U, tmp.size());
-    EXPECT_STR16EQ(u" m", tmp);
-}
-
-TEST(String16Test, MakeLower) {
-    String16 tmp("Verify Me!");
-    tmp.makeLower();
-    EXPECT_EQ(10U, tmp.size());
-    EXPECT_STR16EQ(u"verify me!", tmp);
-}
-
-TEST(String16Test, ReplaceAll) {
-    String16 tmp("Verify verify Verify");
-    tmp.replaceAll(u'r', u'!');
-    EXPECT_STR16EQ(u"Ve!ify ve!ify Ve!ify", tmp);
-}
-
-TEST(String16Test, Compare) {
-    String16 tmp("Verify me");
-    EXPECT_EQ(String16(u"Verify me"), tmp);
-}
-
-TEST(String16Test, StaticString) {
-    String16 nonStaticString("NonStatic");
-    StaticString16 staticString(u"Static");
-
-    EXPECT_TRUE(staticString.isStaticString());
-    EXPECT_FALSE(nonStaticString.isStaticString());
-}
-
-TEST(String16Test, StaticStringCopy) {
-    StaticString16 tmp(u"Verify me");
-    String16 another = tmp;
-    EXPECT_STR16EQ(u"Verify me", tmp);
-    EXPECT_STR16EQ(u"Verify me", another);
-    EXPECT_TRUE(tmp.isStaticString());
-    EXPECT_TRUE(another.isStaticString());
-}
-
-TEST(String16Test, StaticStringMove) {
-    StaticString16 tmp(u"Verify me");
-    String16 another(std::move(tmp));
-    EXPECT_STR16EQ(u"Verify me", another);
-    EXPECT_TRUE(another.isStaticString());
-}
-
-TEST(String16Test, StaticStringSize) {
-    StaticString16 tmp(u"Verify me");
-    EXPECT_EQ(9U, tmp.size());
-}
-
-TEST(String16Test, StaticStringSetTo) {
-    StaticString16 tmp(u"Verify me");
-    tmp.setTo(u"New content");
-    EXPECT_EQ(11U, tmp.size());
-    EXPECT_STR16EQ(u"New content", tmp);
-    EXPECT_FALSE(tmp.isStaticString());
-}
-
-TEST(String16Test, StaticStringAppend) {
-    StaticString16 tmp(u"Verify me");
-    tmp.append(String16("Hello"));
-    EXPECT_EQ(14U, tmp.size());
-    EXPECT_STR16EQ(u"Verify meHello", tmp);
-    EXPECT_FALSE(tmp.isStaticString());
-}
-
-TEST(String16Test, StaticStringInsert) {
-    StaticString16 tmp(u"Verify me");
-    tmp.insert(6, u"Insert");
-    EXPECT_EQ(15U, tmp.size());
-    EXPECT_STR16EQ(u"VerifyInsert me", tmp);
-    EXPECT_FALSE(tmp.isStaticString());
-}
-
-TEST(String16Test, StaticStringRemove) {
-    StaticString16 tmp(u"Verify me");
-    tmp.remove(2, 6);
-    EXPECT_EQ(2U, tmp.size());
-    EXPECT_STR16EQ(u" m", tmp);
-    EXPECT_FALSE(tmp.isStaticString());
-}
-
-TEST(String16Test, StaticStringMakeLower) {
-    StaticString16 tmp(u"Verify me!");
-    tmp.makeLower();
-    EXPECT_EQ(10U, tmp.size());
-    EXPECT_STR16EQ(u"verify me!", tmp);
-    EXPECT_FALSE(tmp.isStaticString());
-}
-
-TEST(String16Test, StaticStringReplaceAll) {
-    StaticString16 tmp(u"Verify verify Verify");
-    tmp.replaceAll(u'r', u'!');
-    EXPECT_STR16EQ(u"Ve!ify ve!ify Ve!ify", tmp);
-    EXPECT_FALSE(tmp.isStaticString());
-}
-
-TEST(String16Test, StaticStringCompare) {
-    StaticString16 tmp(u"Verify me");
-    EXPECT_EQ(String16(u"Verify me"), tmp);
-}
-
-TEST(String16Test, StringSetToStaticString) {
-    StaticString16 tmp(u"Verify me");
-    String16 another(u"nonstatic");
-    another = tmp;
-    EXPECT_STR16EQ(u"Verify me", tmp);
-    EXPECT_STR16EQ(u"Verify me", another);
-}
-
-TEST(String16Test, StringMoveFromStaticString) {
-    StaticString16 tmp(u"Verify me");
-    String16 another(std::move(tmp));
-    EXPECT_STR16EQ(u"Verify me", another);
-}
-
-TEST(String16Test, EmptyStringIsStatic) {
-    String16 tmp("");
-    EXPECT_TRUE(tmp.isStaticString());
-}
-
-}  // namespace android
diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h
index adc3e7d..afbc2ed 100644
--- a/libutils/include/utils/String16.h
+++ b/libutils/include/utils/String16.h
@@ -37,17 +37,13 @@
 
 class String8;
 
-template <size_t N>
-class StaticString16;
-
 // DO NOT USE: please use std::u16string
 
 //! This is a string holding UTF-16 characters.
 class String16
 {
 public:
-    /*
-     * Use String16(StaticLinkage) if you're statically linking against
+    /* use String16(StaticLinkage) if you're statically linking against
      * libutils and declaring an empty static String16, e.g.:
      *
      *   static String16 sAStaticEmptyString(String16::kEmptyString);
@@ -127,76 +123,8 @@
 
     inline                      operator const char16_t*() const;
 
-    // Static and non-static String16 behave the same for the users, so
-    // this method isn't of much use for the users. It is public for testing.
-            bool                isStaticString() const;
-
-  private:
-    /*
-     * A flag indicating the type of underlying buffer.
-     */
-    static constexpr uint32_t kIsSharedBufferAllocated = 0x80000000;
-
-    /*
-     * alloc() returns void* so that SharedBuffer class is not exposed.
-     */
-    static void* alloc(size_t size);
-    static char16_t* allocFromUTF8(const char* u8str, size_t u8len);
-    static char16_t* allocFromUTF16(const char16_t* u16str, size_t u16len);
-
-    /*
-     * edit() and editResize() return void* so that SharedBuffer class
-     * is not exposed.
-     */
-    void* edit();
-    void* editResize(size_t new_size);
-
-    void acquire();
-    void release();
-
-    size_t staticStringSize() const;
-
-    const char16_t* mString;
-
-protected:
-    /*
-     * Data structure used to allocate static storage for static String16.
-     *
-     * Note that this data structure and SharedBuffer are used interchangably
-     * as the underlying data structure for a String16.  Therefore, the layout
-     * of this data structure must match the part in SharedBuffer that is
-     * visible to String16.
-     */
-    template <size_t N>
-    struct StaticData {
-        // The high bit of 'size' is used as a flag.
-        static_assert(N - 1 < kIsSharedBufferAllocated, "StaticString16 too long!");
-        constexpr StaticData() : size(N - 1), data{0} {}
-        const uint32_t size;
-        char16_t data[N];
-
-        constexpr StaticData(const StaticData<N>&) = default;
-    };
-
-    /*
-     * Helper function for constructing a StaticData object.
-     */
-    template <size_t N>
-    static constexpr const StaticData<N> makeStaticData(const char16_t (&s)[N]) {
-        StaticData<N> r;
-        // The 'size' field is at the same location where mClientMetadata would
-        // be for a SharedBuffer.  We do NOT set kIsSharedBufferAllocated flag
-        // here.
-        for (size_t i = 0; i < N - 1; ++i) r.data[i] = s[i];
-        return r;
-    }
-
-    template <size_t N>
-    explicit constexpr String16(const StaticData<N>& s) : mString(s.data) {}
-
-public:
-    template <size_t N>
-    explicit constexpr String16(const StaticString16<N>& s) : mString(s.mString) {}
+private:
+            const char16_t*     mString;
 };
 
 // String16 can be trivially moved using memcpy() because moving does not
@@ -204,42 +132,6 @@
 ANDROID_TRIVIAL_MOVE_TRAIT(String16)
 
 // ---------------------------------------------------------------------------
-
-/*
- * A StaticString16 object is a specialized String16 object.  Instead of holding
- * the string data in a ref counted SharedBuffer object, it holds data in a
- * buffer within StaticString16 itself.  Note that this buffer is NOT ref
- * counted and is assumed to be available for as long as there is at least a
- * String16 object using it.  Therefore, one must be extra careful to NEVER
- * assign a StaticString16 to a String16 that outlives the StaticString16
- * object.
- *
- * THE SAFEST APPROACH IS TO USE StaticString16 ONLY AS GLOBAL VARIABLES.
- *
- * A StaticString16 SHOULD NEVER APPEAR IN APIs.  USE String16 INSTEAD.
- */
-template <size_t N>
-class StaticString16 : public String16 {
-public:
-    constexpr StaticString16(const char16_t (&s)[N]) : String16(mData), mData(makeStaticData(s)) {}
-
-    constexpr StaticString16(const StaticString16<N>& other)
-        : String16(mData), mData(other.mData) {}
-
-    constexpr StaticString16(const StaticString16<N>&&) = delete;
-
-    // There is no reason why one would want to 'new' a StaticString16.  Delete
-    // it to discourage misuse.
-    static void* operator new(std::size_t) = delete;
-
-private:
-    const StaticData<N> mData;
-};
-
-template <typename F>
-StaticString16(const F&)->StaticString16<sizeof(F) / sizeof(char16_t)>;
-
-// ---------------------------------------------------------------------------
 // No user servicable parts below.
 
 inline int compare_type(const String16& lhs, const String16& rhs)
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 4559050..2fa110b 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -214,7 +214,7 @@
 LOCAL_MODULE_CLASS := ETC
 LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
 
-# Start of runtime APEX compatibility.
+# Start of i18n and ART APEX compatibility.
 #
 # Meta-comment:
 # The placing of this section is somewhat arbitrary. The LOCAL_POST_INSTALL_CMD
@@ -226,7 +226,7 @@
 # come to rely on them.
 
 # http://b/121248172 - create a link from /system/usr/icu to
-# /apex/com.android.runtime/etc/icu so that apps can find the ICU .dat file.
+# /apex/com.android.i18n/etc/icu so that apps can find the ICU .dat file.
 # A symlink can't overwrite a directory and the /system/usr/icu directory once
 # existed so the required structure must be created whatever we find.
 LOCAL_POST_INSTALL_CMD = mkdir -p $(TARGET_OUT)/usr && rm -rf $(TARGET_OUT)/usr/icu
@@ -248,10 +248,10 @@
 LOCAL_POST_INSTALL_CMD += && mkdir -p $(TARGET_OUT)/bin
 $(foreach b,$(ART_BINARIES), \
   $(eval LOCAL_POST_INSTALL_CMD += \
-    && ln -sf /apex/com.android.runtime/bin/$(b) $(TARGET_OUT)/bin/$(b)) \
+    && ln -sf /apex/com.android.art/bin/$(b) $(TARGET_OUT)/bin/$(b)) \
 )
 
-# End of runtime APEX compatibilty.
+# End of i18n and ART APEX compatibilty.
 
 ifeq ($(_enforce_vndk_at_runtime),true)
 
diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt
index f0b1fd2..e598f05 100644
--- a/rootdir/etc/ld.config.legacy.txt
+++ b/rootdir/etc/ld.config.legacy.txt
@@ -85,8 +85,11 @@
 # android_link_namespaces in libnativeloader.
 namespace.runtime.visible = true
 
-namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
-namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
+# TODO(b/139408016): Split the namespaces for the ART and Runtime APEXes
+namespace.runtime.search.paths  = /apex/com.android.art/${LIB}
+namespace.runtime.search.paths += /apex/com.android.runtime/${LIB}
+namespace.runtime.asan.search.paths  = /apex/com.android.art/${LIB}
+namespace.runtime.asan.search.paths += /apex/com.android.runtime/${LIB}
 namespace.runtime.links = default
 # Need allow_all_shared_libs because libart.so can dlopen oat files in
 # /system/framework and /data.
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index a603be2..c8c6387 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -166,8 +166,11 @@
 # android_link_namespaces in libnativeloader.
 namespace.runtime.visible = true
 
-namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
-namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
+# TODO(b/139408016): Split the namespaces for the ART and Runtime APEXes
+namespace.runtime.search.paths  = /apex/com.android.art/${LIB}
+namespace.runtime.search.paths += /apex/com.android.runtime/${LIB}
+namespace.runtime.asan.search.paths  = /apex/com.android.art/${LIB}
+namespace.runtime.asan.search.paths += /apex/com.android.runtime/${LIB}
 namespace.runtime.links = default
 # Need allow_all_shared_libs because libart.so can dlopen oat files in
 # /system/framework and /data.
@@ -488,8 +491,11 @@
 ###############################################################################
 namespace.runtime.isolated = true
 
-namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
-namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
+# TODO(b/139408016): Split the namespaces for the ART and Runtime APEXes
+namespace.runtime.search.paths  = /apex/com.android.art/${LIB}
+namespace.runtime.search.paths += /apex/com.android.runtime/${LIB}
+namespace.runtime.asan.search.paths  = /apex/com.android.art/${LIB}
+namespace.runtime.asan.search.paths += /apex/com.android.runtime/${LIB}
 namespace.runtime.links = system
 # TODO(b/130340935): Use a dynamically created linker namespace similar to
 # classloader-namespace for oat files, and tighten this up.
@@ -695,8 +701,11 @@
 # android_link_namespaces in libnativeloader.
 namespace.runtime.visible = true
 
-namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
-namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
+# TODO(b/139408016): Split the namespaces for the ART and Runtime APEXes
+namespace.runtime.search.paths  = /apex/com.android.art/${LIB}
+namespace.runtime.search.paths += /apex/com.android.runtime/${LIB}
+namespace.runtime.asan.search.paths  = /apex/com.android.art/${LIB}
+namespace.runtime.asan.search.paths += /apex/com.android.runtime/${LIB}
 namespace.runtime.links = default
 # TODO(b/130340935): Use a dynamically created linker namespace similar to
 # classloader-namespace for oat files, and tighten this up.
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index 2e213ec..4beabd6 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -105,8 +105,11 @@
 # android_link_namespaces in libnativeloader.
 namespace.runtime.visible = true
 
-namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
-namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
+# TODO(b/139408016): Split the namespaces for the ART and Runtime APEXes
+namespace.runtime.search.paths  = /apex/com.android.art/${LIB}
+namespace.runtime.search.paths += /apex/com.android.runtime/${LIB}
+namespace.runtime.asan.search.paths  = /apex/com.android.art/${LIB}
+namespace.runtime.asan.search.paths += /apex/com.android.runtime/${LIB}
 namespace.runtime.links = default
 # Need allow_all_shared_libs because libart.so can dlopen oat files in
 # /system/framework and /data.
@@ -419,8 +422,11 @@
 ###############################################################################
 namespace.runtime.isolated = true
 
-namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
-namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
+# TODO(b/139408016): Split the namespaces for the ART and Runtime APEXes
+namespace.runtime.search.paths  = /apex/com.android.art/${LIB}
+namespace.runtime.search.paths += /apex/com.android.runtime/${LIB}
+namespace.runtime.asan.search.paths  = /apex/com.android.art/${LIB}
+namespace.runtime.asan.search.paths += /apex/com.android.runtime/${LIB}
 namespace.runtime.links = default
 # TODO(b/130340935): Use a dynamically created linker namespace similar to
 # classloader-namespace for oat files, and tighten this up.
@@ -503,8 +509,11 @@
 # android_link_namespaces in libnativeloader.
 namespace.runtime.visible = true
 
-namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
-namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
+# TODO(b/139408016): Split the namespaces for the ART and Runtime APEXes
+namespace.runtime.search.paths  = /apex/com.android.art/${LIB}
+namespace.runtime.search.paths += /apex/com.android.runtime/${LIB}
+namespace.runtime.asan.search.paths  = /apex/com.android.art/${LIB}
+namespace.runtime.asan.search.paths += /apex/com.android.runtime/${LIB}
 namespace.runtime.links = default
 # TODO(b/130340935): Use a dynamically created linker namespace similar to
 # classloader-namespace for oat files, and tighten this up.
diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in
index 93b7f43..17f6596 100644
--- a/rootdir/init.environ.rc.in
+++ b/rootdir/init.environ.rc.in
@@ -5,7 +5,7 @@
     export ANDROID_ASSETS /system/app
     export ANDROID_DATA /data
     export ANDROID_STORAGE /storage
-    export ANDROID_RUNTIME_ROOT /apex/com.android.runtime
+    export ANDROID_RUNTIME_ROOT /apex/com.android.art
     export ANDROID_I18N_ROOT /apex/com.android.i18n
     export ANDROID_TZDATA_ROOT /apex/com.android.tzdata
     export EXTERNAL_STORAGE /sdcard