Merge "__android_log_is_debuggable() shouldn't be an apex symbol"
diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp
index b8827ef..7e470e1 100644
--- a/adb/client/file_sync_client.cpp
+++ b/adb/client/file_sync_client.cpp
@@ -681,9 +681,7 @@
     if (sync) {
         struct stat st;
         if (sync_lstat(sc, rpath, &st)) {
-            // For links, we cannot update the atime/mtime.
-            if ((S_ISREG(mode & st.st_mode) && st.st_mtime == static_cast<time_t>(mtime)) ||
-                (S_ISLNK(mode & st.st_mode) && st.st_mtime >= static_cast<time_t>(mtime))) {
+            if (st.st_mtime == static_cast<time_t>(mtime)) {
                 sc.RecordFilesSkipped(1);
                 return true;
             }
@@ -921,12 +919,8 @@
         for (copyinfo& ci : file_list) {
             struct stat st;
             if (sc.FinishStat(&st)) {
-                if (st.st_size == static_cast<off_t>(ci.size)) {
-                    // For links, we cannot update the atime/mtime.
-                    if ((S_ISREG(ci.mode & st.st_mode) && st.st_mtime == ci.time) ||
-                        (S_ISLNK(ci.mode & st.st_mode) && st.st_mtime >= ci.time)) {
-                        ci.skip = true;
-                    }
+                if (st.st_size == static_cast<off_t>(ci.size) && st.st_mtime == ci.time) {
+                    ci.skip = true;
                 }
             }
         }
diff --git a/adb/daemon/file_sync_service.cpp b/adb/daemon/file_sync_service.cpp
index 9e1760d..70deb31 100644
--- a/adb/daemon/file_sync_service.cpp
+++ b/adb/daemon/file_sync_service.cpp
@@ -27,6 +27,7 @@
 #include <string.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
+#include <sys/time.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <utime.h>
@@ -242,10 +243,10 @@
     return SendSyncFail(fd, StringPrintf("%s: %s", reason.c_str(), strerror(errno)));
 }
 
-static bool handle_send_file(int s, const char* path, uid_t uid, gid_t gid, uint64_t capabilities,
-                             mode_t mode, std::vector<char>& buffer, bool do_unlink) {
+static bool handle_send_file(int s, const char* path, uint32_t* timestamp, uid_t uid, gid_t gid,
+                             uint64_t capabilities, mode_t mode, std::vector<char>& buffer,
+                             bool do_unlink) {
     syncmsg msg;
-    unsigned int timestamp = 0;
 
     __android_log_security_bswrite(SEC_TAG_ADB_SEND_FILE, path);
 
@@ -291,7 +292,7 @@
 
         if (msg.data.id != ID_DATA) {
             if (msg.data.id == ID_DONE) {
-                timestamp = msg.data.size;
+                *timestamp = msg.data.size;
                 break;
             }
             SendSyncFail(s, "invalid data message");
@@ -316,11 +317,6 @@
         goto fail;
     }
 
-    utimbuf u;
-    u.actime = timestamp;
-    u.modtime = timestamp;
-    utime(path, &u);
-
     msg.status.id = ID_OKAY;
     msg.status.msglen = 0;
     return WriteFdExactly(s, &msg.status, sizeof(msg.status));
@@ -360,9 +356,12 @@
 }
 
 #if defined(_WIN32)
-extern bool handle_send_link(int s, const std::string& path, std::vector<char>& buffer) __attribute__((error("no symlinks on Windows")));
+extern bool handle_send_link(int s, const std::string& path,
+                             uint32_t* timestamp, std::vector<char>& buffer)
+        __attribute__((error("no symlinks on Windows")));
 #else
-static bool handle_send_link(int s, const std::string& path, std::vector<char>& buffer) {
+static bool handle_send_link(int s, const std::string& path, uint32_t* timestamp,
+                             std::vector<char>& buffer) {
     syncmsg msg;
 
     if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false;
@@ -399,6 +398,7 @@
     if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false;
 
     if (msg.data.id == ID_DONE) {
+        *timestamp = msg.data.size;
         msg.status.id = ID_OKAY;
         msg.status.msglen = 0;
         if (!WriteFdExactly(s, &msg.status, sizeof(msg.status))) return false;
@@ -448,24 +448,40 @@
         adb_unlink(path.c_str());
     }
 
+    bool result;
+    uint32_t timestamp;
     if (S_ISLNK(mode)) {
-        return handle_send_link(s, path.c_str(), buffer);
+        result = handle_send_link(s, path.c_str(), &timestamp, buffer);
+    } else {
+        // Copy user permission bits to "group" and "other" permissions.
+        mode &= 0777;
+        mode |= ((mode >> 3) & 0070);
+        mode |= ((mode >> 3) & 0007);
+
+        uid_t uid = -1;
+        gid_t gid = -1;
+        uint64_t capabilities = 0;
+        if (should_use_fs_config(path)) {
+            unsigned int broken_api_hack = mode;
+            fs_config(path.c_str(), 0, nullptr, &uid, &gid, &broken_api_hack, &capabilities);
+            mode = broken_api_hack;
+        }
+
+        result = handle_send_file(s, path.c_str(), &timestamp, uid, gid, capabilities, mode, buffer,
+                                  do_unlink);
     }
 
-    // Copy user permission bits to "group" and "other" permissions.
-    mode &= 0777;
-    mode |= ((mode >> 3) & 0070);
-    mode |= ((mode >> 3) & 0007);
-
-    uid_t uid = -1;
-    gid_t gid = -1;
-    uint64_t capabilities = 0;
-    if (should_use_fs_config(path)) {
-        unsigned int broken_api_hack = mode;
-        fs_config(path.c_str(), 0, nullptr, &uid, &gid, &broken_api_hack, &capabilities);
-        mode = broken_api_hack;
+    if (!result) {
+      return false;
     }
-    return handle_send_file(s, path.c_str(), uid, gid, capabilities, mode, buffer, do_unlink);
+
+    struct timeval tv[2];
+    tv[0].tv_sec = timestamp;
+    tv[0].tv_usec = 0;
+    tv[1].tv_sec = timestamp;
+    tv[1].tv_usec = 0;
+    lutimes(path.c_str(), tv);
+    return true;
 }
 
 static bool do_recv(int s, const char* path, std::vector<char>& buffer) {
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 90f94ee..0c7b0b6 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -71,6 +71,7 @@
 const char* const kFeatureApex = "apex";
 const char* const kFeatureFixedPushMkdir = "fixed_push_mkdir";
 const char* const kFeatureAbb = "abb";
+const char* const kFeatureFixedPushSymlinkTimestamp = "fixed_push_symlink_timestamp";
 
 namespace {
 
@@ -1005,8 +1006,13 @@
 const FeatureSet& supported_features() {
     // Local static allocation to avoid global non-POD variables.
     static const FeatureSet* features = new FeatureSet{
-            kFeatureShell2,         kFeatureCmd,  kFeatureStat2,
-            kFeatureFixedPushMkdir, kFeatureApex, kFeatureAbb,
+            kFeatureShell2,
+            kFeatureCmd,
+            kFeatureStat2,
+            kFeatureFixedPushMkdir,
+            kFeatureApex,
+            kFeatureAbb,
+            kFeatureFixedPushSymlinkTimestamp,
             // Increment ADB_SERVER_VERSION when adding a feature that adbd needs
             // to know about. Otherwise, the client can be stuck running an old
             // version of the server even after upgrading their copy of adb.
diff --git a/adb/transport.h b/adb/transport.h
index 065c81f..a0174b8 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -67,6 +67,8 @@
 extern const char* const kFeatureFixedPushMkdir;
 // adbd supports android binder bridge (abb).
 extern const char* const kFeatureAbb;
+// adbd properly updates symlink timestamps on push.
+extern const char* const kFeatureFixedPushSymlinkTimestamp;
 
 TransportId NextTransportId();
 
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index e9dec12..8505e61 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -200,7 +200,7 @@
         cgroups.push_back(path);
     }
     if (CgroupGetControllerPath("memory", &path)) {
-        cgroups.push_back(path);
+        cgroups.push_back(path + "/apps");
     }
 
     for (std::string cgroup_root_path : cgroups) {
@@ -317,6 +317,7 @@
 
     CgroupGetControllerPath("cpuacct", &cpuacct_path);
     CgroupGetControllerPath("memory", &memory_path);
+    memory_path += "/apps";
 
     const char* cgroup =
             (!access(ConvertUidPidToPath(cpuacct_path.c_str(), uid, initialPid).c_str(), F_OK))
@@ -380,6 +381,7 @@
     std::string cgroup;
     if (isMemoryCgroupSupported() && (memControl || UsePerAppMemcg())) {
         CgroupGetControllerPath("memory", &cgroup);
+        cgroup += "/apps";
     } else {
         CgroupGetControllerPath("cpuacct", &cgroup);
     }
diff --git a/libprocessgroup/profiles/Android.bp b/libprocessgroup/profiles/Android.bp
new file mode 100644
index 0000000..15d0172
--- /dev/null
+++ b/libprocessgroup/profiles/Android.bp
@@ -0,0 +1,80 @@
+// 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.
+
+prebuilt_etc {
+    name: "cgroups.json",
+    src: "cgroups.json",
+}
+
+prebuilt_etc {
+    name: "cgroups.recovery.json",
+    filename: "cgroups.json",
+    recovery: true,
+    src: "cgroups.recovery.json",
+}
+
+prebuilt_etc {
+    name: "task_profiles.json",
+    src: "task_profiles.json",
+}
+
+cc_library_static {
+    name: "libprocessgroup_proto",
+    host_supported: true,
+    srcs: [
+        "cgroups.proto",
+        "task_profiles.proto",
+    ],
+    proto: {
+        type: "full",
+        export_proto_headers: true,
+    },
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+    ],
+}
+
+cc_test_host {
+    name: "libprocessgroup_proto_test",
+    srcs: [
+        "test.cpp",
+    ],
+    static_libs: [
+        "libbase",
+        "libgmock",
+        "liblog",
+        "libjsoncpp",
+        "libjsonpbverify",
+        "libjsonpbparse",
+        "libprocessgroup_proto",
+    ],
+    shared_libs: [
+        "libprotobuf-cpp-full",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+    ],
+    data: [
+        "cgroups.json",
+        "cgroups.recovery.json",
+        "task_profiles.json",
+    ],
+    test_suites: [
+        "general-tests",
+    ],
+}
diff --git a/libprocessgroup/profiles/TEST_MAPPING b/libprocessgroup/profiles/TEST_MAPPING
new file mode 100644
index 0000000..5ff4112
--- /dev/null
+++ b/libprocessgroup/profiles/TEST_MAPPING
@@ -0,0 +1,8 @@
+{
+  "presubmit": [
+    {
+      "name": "libprocessgroup_proto_test",
+      "host": true
+    }
+  ]
+}
diff --git a/rootdir/cgroups.json b/libprocessgroup/profiles/cgroups.json
similarity index 100%
rename from rootdir/cgroups.json
rename to libprocessgroup/profiles/cgroups.json
diff --git a/libprocessgroup/profiles/cgroups.proto b/libprocessgroup/profiles/cgroups.proto
new file mode 100644
index 0000000..f4070c5
--- /dev/null
+++ b/libprocessgroup/profiles/cgroups.proto
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+package android.profiles;
+
+// Next: 3
+message Cgroups {
+    repeated Cgroup cgroups = 1 [json_name = "Cgroups"];
+    Cgroups2 cgroups2 = 2 [json_name = "Cgroups2"];
+}
+
+// Next: 6
+message Cgroup {
+    string controller = 1 [json_name = "Controller"];
+    string path = 2 [json_name = "Path"];
+    string mode = 3 [json_name = "Mode"];
+    string uid = 4 [json_name = "UID"];
+    string gid = 5 [json_name = "GID"];
+}
+
+// Next: 5
+message Cgroups2 {
+    string path = 1 [json_name = "Path"];
+    string mode = 2 [json_name = "Mode"];
+    string uid = 3 [json_name = "UID"];
+    string gid = 4 [json_name = "GID"];
+}
diff --git a/rootdir/cgroups.recovery.json b/libprocessgroup/profiles/cgroups.recovery.json
similarity index 100%
rename from rootdir/cgroups.recovery.json
rename to libprocessgroup/profiles/cgroups.recovery.json
diff --git a/rootdir/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
similarity index 100%
rename from rootdir/task_profiles.json
rename to libprocessgroup/profiles/task_profiles.json
diff --git a/libprocessgroup/profiles/task_profiles.proto b/libprocessgroup/profiles/task_profiles.proto
new file mode 100644
index 0000000..578f0d3
--- /dev/null
+++ b/libprocessgroup/profiles/task_profiles.proto
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+package android.profiles;
+
+// Next: 3
+message TaskProfiles {
+    repeated Attribute attributes = 1 [json_name = "Attributes"];
+    repeated Profile profiles = 2 [json_name = "Profiles"];
+}
+
+// Next: 4
+message Attribute {
+    string name = 1 [json_name = "Name"];
+    string controller = 2 [json_name = "Controller"];
+    string file = 3 [json_name = "File"];
+}
+
+// Next: 3
+message Profile {
+    string name = 1 [json_name = "Name"];
+    repeated Action actions = 2 [json_name = "Actions"];
+}
+
+// Next: 3
+message Action {
+    string name = 1 [json_name = "Name"];
+    map<string, string> params = 2 [json_name = "Params"];
+}
diff --git a/libprocessgroup/profiles/test.cpp b/libprocessgroup/profiles/test.cpp
new file mode 100644
index 0000000..8ba14d6
--- /dev/null
+++ b/libprocessgroup/profiles/test.cpp
@@ -0,0 +1,135 @@
+/*
+ * 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 <string>
+
+#include <android-base/file.h>
+#include <gmock/gmock.h>
+#include <jsonpb/json_schema_test.h>
+
+#include "cgroups.pb.h"
+#include "task_profiles.pb.h"
+
+using namespace ::android::jsonpb;
+using ::android::base::GetExecutableDirectory;
+using ::testing::MatchesRegex;
+
+namespace android {
+namespace profiles {
+
+template <typename T>
+JsonSchemaTestConfigFactory MakeTestParam(const std::string& path) {
+    return jsonpb::MakeTestParam<T>(GetExecutableDirectory() + path);
+}
+
+TEST(LibProcessgroupProto, EmptyMode) {
+    EXPECT_EQ(0, strtoul("", nullptr, 8))
+            << "Empty mode string cannot be silently converted to 0; this should not happen";
+}
+
+class CgroupsTest : public JsonSchemaTest {
+  public:
+    void SetUp() override {
+        JsonSchemaTest::SetUp();
+        cgroups_ = static_cast<Cgroups*>(message());
+    }
+    Cgroups* cgroups_;
+};
+
+TEST_P(CgroupsTest, CgroupRequiredFields) {
+    for (int i = 0; i < cgroups_->cgroups_size(); ++i) {
+        auto&& cgroup = cgroups_->cgroups(i);
+        EXPECT_FALSE(cgroup.controller().empty())
+                << "No controller name for cgroup #" << i << " in " << file_path_;
+        EXPECT_FALSE(cgroup.path().empty()) << "No path for cgroup #" << i << " in " << file_path_;
+    }
+}
+
+TEST_P(CgroupsTest, Cgroup2RequiredFields) {
+    if (cgroups_->has_cgroups2()) {
+        EXPECT_FALSE(cgroups_->cgroups2().path().empty())
+                << "No path for cgroup2 in " << file_path_;
+    }
+}
+
+// "Mode" field must be in the format of "0xxx".
+static constexpr const char* REGEX_MODE = "(0[0-7]{3})?";
+TEST_P(CgroupsTest, CgroupMode) {
+    for (int i = 0; i < cgroups_->cgroups_size(); ++i) {
+        EXPECT_THAT(cgroups_->cgroups(i).mode(), MatchesRegex(REGEX_MODE))
+                << "For cgroup controller #" << i << " in " << file_path_;
+    }
+}
+
+TEST_P(CgroupsTest, Cgroup2Mode) {
+    EXPECT_THAT(cgroups_->cgroups2().mode(), MatchesRegex(REGEX_MODE))
+            << "For cgroups2 in " << file_path_;
+}
+
+class TaskProfilesTest : public JsonSchemaTest {
+  public:
+    void SetUp() override {
+        JsonSchemaTest::SetUp();
+        task_profiles_ = static_cast<TaskProfiles*>(message());
+    }
+    TaskProfiles* task_profiles_;
+};
+
+TEST_P(TaskProfilesTest, AttributeRequiredFields) {
+    for (int i = 0; i < task_profiles_->attributes_size(); ++i) {
+        auto&& attribute = task_profiles_->attributes(i);
+        EXPECT_FALSE(attribute.name().empty())
+                << "No name for attribute #" << i << " in " << file_path_;
+        EXPECT_FALSE(attribute.controller().empty())
+                << "No controller for attribute #" << i << " in " << file_path_;
+        EXPECT_FALSE(attribute.file().empty())
+                << "No file for attribute #" << i << " in " << file_path_;
+    }
+}
+
+TEST_P(TaskProfilesTest, ProfileRequiredFields) {
+    for (int profile_idx = 0; profile_idx < task_profiles_->profiles_size(); ++profile_idx) {
+        auto&& profile = task_profiles_->profiles(profile_idx);
+        EXPECT_FALSE(profile.name().empty())
+                << "No name for profile #" << profile_idx << " in " << file_path_;
+        for (int action_idx = 0; action_idx < profile.actions_size(); ++action_idx) {
+            auto&& action = profile.actions(action_idx);
+            EXPECT_FALSE(action.name().empty())
+                    << "No name for profiles[" << profile_idx << "].actions[" << action_idx
+                    << "] in " << file_path_;
+        }
+    }
+}
+
+// Test suite instantiations
+
+INSTANTIATE_TEST_SUITE_P(, JsonSchemaTest,
+                         ::testing::Values(MakeTestParam<Cgroups>("/cgroups.json"),
+                                           MakeTestParam<Cgroups>("/cgroups.recovery.json"),
+                                           MakeTestParam<TaskProfiles>("/task_profiles.json")));
+INSTANTIATE_TEST_SUITE_P(, CgroupsTest,
+                         ::testing::Values(MakeTestParam<Cgroups>("/cgroups.json"),
+                                           MakeTestParam<Cgroups>("/cgroups.recovery.json")));
+INSTANTIATE_TEST_SUITE_P(, TaskProfilesTest,
+                         ::testing::Values(MakeTestParam<TaskProfiles>("/task_profiles.json")));
+
+}  // namespace profiles
+}  // namespace android
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index b5e5a71..944554a 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -64,38 +64,6 @@
 include $(BUILD_PREBUILT)
 
 #######################################
-# cgroups.json
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := cgroups.json
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
-
-include $(BUILD_PREBUILT)
-
-#######################################
-# cgroups.json for recovery
-include $(CLEAR_VARS)
-LOCAL_MODULE := cgroups.recovery.json
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/system/etc
-LOCAL_MODULE_STEM := cgroups.json
-include $(BUILD_PREBUILT)
-
-#######################################
-# task_profiles.json
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := task_profiles.json
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
-
-include $(BUILD_PREBUILT)
-
-#######################################
 # asan.options
 ifneq ($(filter address,$(SANITIZE_TARGET)),)
 
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index 0e07b1b..2c6e01f 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -20,6 +20,13 @@
 dir.vendor = /data/benchmarktest/vendor
 dir.vendor = /data/benchmarktest64/vendor
 
+dir.unrestricted = /data/nativetest/unrestricted
+dir.unrestricted = /data/nativetest64/unrestricted
+
+# TODO(b/123864775): Ensure tests are run from /data/nativetest{,64} or (if
+# necessary) the unrestricted subdirs above. Then clean this up.
+dir.unrestricted = /data/local/tmp
+
 dir.system = /data/nativetest
 dir.system = /data/nativetest64
 dir.system = /data/benchmarktest
@@ -365,6 +372,109 @@
 namespace.runtime.link.default.allow_all_shared_libs = true
 
 ###############################################################################
+# Namespace config for native tests that need access to both system and vendor
+# libraries. This replicates the default linker config (done by
+# init_default_namespace_no_config in bionic/linker/linker.cpp), except that it
+# includes the requisite namespace setup for APEXes.
+###############################################################################
+[unrestricted]
+additional.namespaces = runtime,media,conscrypt,resolv
+
+namespace.default.search.paths  = /system/${LIB}
+namespace.default.search.paths += /odm/${LIB}
+namespace.default.search.paths += /vendor/${LIB}
+
+namespace.default.asan.search.paths  = /data/asan/system/${LIB}
+namespace.default.asan.search.paths +=           /system/${LIB}
+namespace.default.asan.search.paths += /data/asan/odm/${LIB}
+namespace.default.asan.search.paths +=           /odm/${LIB}
+namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
+namespace.default.asan.search.paths +=           /vendor/${LIB}
+
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.default.links = runtime,resolv
+namespace.default.visible = true
+
+namespace.default.link.runtime.shared_libs  = libart.so:libartd.so
+namespace.default.link.runtime.shared_libs += libdexfile_external.so
+namespace.default.link.runtime.shared_libs += libnativebridge.so
+namespace.default.link.runtime.shared_libs += libnativehelper.so
+namespace.default.link.runtime.shared_libs += libnativeloader.so
+namespace.default.link.runtime.shared_libs += libandroidicu.so
+
+# TODO(b/122876336): Remove libpac.so once it's migrated to Webview
+namespace.default.link.runtime.shared_libs += libpac.so
+
+namespace.default.link.resolv.shared_libs = libnetd_resolv.so
+
+###############################################################################
+# "runtime" APEX namespace
+#
+# This namespace exposes externally accessible libraries from the Runtime APEX.
+###############################################################################
+namespace.runtime.isolated = true
+namespace.runtime.visible = true
+
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.links = default
+# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
+# when it exists.
+namespace.runtime.link.default.allow_all_shared_libs = true
+
+###############################################################################
+# "media" APEX namespace
+#
+# This namespace is for libraries within the media APEX.
+###############################################################################
+namespace.media.isolated = true
+namespace.media.visible = true
+
+namespace.media.search.paths = /apex/com.android.media/${LIB}
+namespace.media.asan.search.paths = /apex/com.android.media/${LIB}
+
+namespace.media.links = default
+namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%
+namespace.media.link.default.shared_libs += libandroid.so
+namespace.media.link.default.shared_libs += libbinder_ndk.so
+namespace.media.link.default.shared_libs += libmediametrics.so
+namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+
+###############################################################################
+# "conscrypt" APEX namespace
+#
+# This namespace is for libraries within the conscrypt APEX.
+###############################################################################
+namespace.conscrypt.isolated = true
+namespace.conscrypt.visible = true
+
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
+namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
+namespace.conscrypt.links = runtime,default
+namespace.conscrypt.link.runtime.shared_libs  = libjavacore.so
+namespace.conscrypt.link.default.shared_libs  = libc.so
+namespace.conscrypt.link.default.shared_libs += libm.so
+namespace.conscrypt.link.default.shared_libs += libdl.so
+
+###############################################################################
+# "resolv" APEX namespace
+#
+# This namespace is for libraries within the resolv APEX.
+###############################################################################
+namespace.resolv.isolated = true
+namespace.resolv.visible = true
+
+namespace.resolv.search.paths = /apex/com.android.resolv/${LIB}
+namespace.resolv.asan.search.paths = /apex/com.android.resolv/${LIB}
+namespace.resolv.links = default
+namespace.resolv.link.default.shared_libs  = libc.so
+namespace.resolv.link.default.shared_libs += libm.so
+namespace.resolv.link.default.shared_libs += libdl.so
+namespace.resolv.link.default.shared_libs += libbinder_ndk.so
+
+###############################################################################
 # Namespace config for binaries under /postinstall.
 # Only default namespace is defined and default has no directories
 # other than /system/lib in the search paths. This is because linker calls