Merge "run-as: improve diagnostics on failure."
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 3286959..3d5d9db 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -222,7 +222,9 @@
         "     all,adb,sockets,packets,rwx,usb,sync,sysdeps,transport,jdwp\n"
         " $ADB_VENDOR_KEYS         colon-separated list of keys (files or directories)\n"
         " $ANDROID_SERIAL          serial number to connect to (see -s)\n"
-        " $ANDROID_LOG_TAGS        tags to be used by logcat (see logcat --help)\n");
+        " $ANDROID_LOG_TAGS        tags to be used by logcat (see logcat --help)\n"
+        " $ADB_LOCAL_TRANSPORT_MAX_PORT max emulator scan port (default 5585, 16 emus)\n"
+    );
     // clang-format on
 }
 
@@ -1003,7 +1005,8 @@
 #endif /* !defined(_WIN32) */
 }
 
-static bool wait_for_device(const char* service) {
+static bool wait_for_device(const char* service,
+                            std::optional<std::chrono::milliseconds> timeout = std::nullopt) {
     std::vector<std::string> components = android::base::Split(service, "-");
     if (components.size() < 3 || components.size() > 4) {
         fprintf(stderr, "adb: couldn't parse 'wait-for' command: %s\n", service);
@@ -1041,6 +1044,13 @@
     }
 
     std::string cmd = format_host_command(android::base::Join(components, "-").c_str());
+    if (timeout) {
+        std::thread([timeout]() {
+            std::this_thread::sleep_for(*timeout);
+            fprintf(stderr, "timeout expired while waiting for device\n");
+            _exit(1);
+        }).detach();
+    }
     return adb_command(cmd);
 }
 
@@ -1082,8 +1092,21 @@
     }
 
     // Wait for the device to go away.
+    TransportType previous_type;
+    const char* previous_serial;
+    TransportId previous_id;
+    adb_get_transport(&previous_type, &previous_serial, &previous_id);
+
     adb_set_transport(kTransportAny, nullptr, transport_id);
     wait_for_device("wait-for-disconnect");
+
+    // Wait for the device to come back.
+    // If we were using a specific transport ID, there's nothing we can wait for.
+    if (previous_id == 0) {
+        adb_set_transport(previous_type, previous_serial, 0);
+        wait_for_device("wait-for-device", 3000ms);
+    }
+
     return true;
 }
 
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index a44ff43..f4458a2 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -270,29 +270,15 @@
             bool started = false;
             bool running = true;
             while (running) {
-                int timeout = -1;
-                if (!bound || !started) {
-                    timeout = 5000 /*ms*/;
-                }
-
                 adb_pollfd pfd[2] = {
                   { .fd = control_fd_.get(), .events = POLLIN, .revents = 0 },
                   { .fd = monitor_event_fd_.get(), .events = POLLIN, .revents = 0 },
                 };
-                int rc = TEMP_FAILURE_RETRY(adb_poll(pfd, 2, timeout));
+                int rc = TEMP_FAILURE_RETRY(adb_poll(pfd, 2, -1));
                 if (rc == -1) {
                     PLOG(FATAL) << "poll on USB control fd failed";
                 } else if (rc == 0) {
-                    // Something in the kernel presumably went wrong.
-                    // Close our endpoints, wait for a bit, and then try again.
-                    StopWorker();
-                    aio_context_.reset();
-                    read_fd_.reset();
-                    write_fd_.reset();
-                    control_fd_.reset();
-                    std::this_thread::sleep_for(5s);
-                    HandleError("didn't receive FUNCTIONFS_ENABLE, retrying");
-                    return;
+                    LOG(FATAL) << "poll on USB control fd returned 0";
                 }
 
                 if (pfd[1].revents) {
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 9a74fb3..b9f738d 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -53,12 +53,27 @@
 
 // Android Wear has been using port 5601 in all of its documentation/tooling,
 // but we search for emulators on ports [5554, 5555 + ADB_LOCAL_TRANSPORT_MAX].
-// Avoid stomping on their port by limiting the number of emulators that can be
-// connected.
-#define ADB_LOCAL_TRANSPORT_MAX 16
+// Avoid stomping on their port by restricting the active scanning range.
+// Once emulators self-(re-)register, they'll have to avoid 5601 in their own way.
+static int adb_local_transport_max_port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT + 16 * 2 - 1;
 
 static std::mutex& local_transports_lock = *new std::mutex();
 
+static void adb_local_transport_max_port_env_override() {
+    const char* env_max_s = getenv("ADB_LOCAL_TRANSPORT_MAX_PORT");
+    if (env_max_s != nullptr) {
+        size_t env_max;
+        if (ParseUint(&env_max, env_max_s, nullptr) && env_max < 65536) {
+            // < DEFAULT_ADB_LOCAL_TRANSPORT_PORT harmlessly mimics ADB_EMU=0
+            adb_local_transport_max_port = env_max;
+            D("transport: ADB_LOCAL_TRANSPORT_MAX_PORT read as %d", adb_local_transport_max_port);
+        } else {
+            D("transport: ADB_LOCAL_TRANSPORT_MAX_PORT '%s' invalid or >= 65536, so ignored",
+              env_max_s);
+        }
+    }
+}
+
 // We keep a map from emulator port to transport.
 // TODO: weak_ptr?
 static auto& local_transports GUARDED_BY(local_transports_lock) =
@@ -110,7 +125,6 @@
             D("reconnect failed: %s", response.c_str());
             return ReconnectResult::Retry;
         }
-
         // This invokes the part of register_socket_transport() that needs to be
         // invoked if the atransport* has already been setup. This eventually
         // calls atransport->SetConnection() with a newly created Connection*
@@ -168,12 +182,10 @@
 #if ADB_HOST
 
 static void PollAllLocalPortsForEmulator() {
-    int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
-    int count = ADB_LOCAL_TRANSPORT_MAX;
-
     // Try to connect to any number of running emulator instances.
-    for ( ; count > 0; count--, port += 2 ) {
-        local_connect(port);
+    for (int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT; port <= adb_local_transport_max_port;
+         port += 2) {
+        local_connect(port);  // Note, uses port and port-1, so '=max_port' is OK.
     }
 }
 
@@ -289,6 +301,7 @@
 #if ADB_HOST
     D("transport: local client init");
     std::thread(client_socket_thread, port).detach();
+    adb_local_transport_max_port_env_override();
 #elif !defined(__ANDROID__)
     // Host adbd.
     D("transport: local server init");
@@ -371,10 +384,6 @@
         if (existing_transport != nullptr) {
             D("local transport for port %d already registered (%p)?", adb_port, existing_transport);
             fail = -1;
-        } else if (local_transports.size() >= ADB_LOCAL_TRANSPORT_MAX) {
-            // Too many emulators.
-            D("cannot register more emulators. Maximum is %d", ADB_LOCAL_TRANSPORT_MAX);
-            fail = -1;
         } else {
             local_transports[adb_port] = t;
         }
diff --git a/base/mapped_file.cpp b/base/mapped_file.cpp
index faa845d..7c65dc3 100644
--- a/base/mapped_file.cpp
+++ b/base/mapped_file.cpp
@@ -41,7 +41,14 @@
   HANDLE handle =
       CreateFileMapping(reinterpret_cast<HANDLE>(_get_osfhandle(fd)), nullptr,
                         (prot & PROT_WRITE) ? PAGE_READWRITE : PAGE_READONLY, 0, 0, nullptr);
-  if (handle == nullptr) return nullptr;
+  if (handle == nullptr) {
+    // http://b/119818070 "app crashes when reading asset of zero length".
+    // Return a MappedFile that's only valid for reading the size.
+    if (length == 0) {
+      return std::unique_ptr<MappedFile>(new MappedFile{nullptr, 0, 0, nullptr});
+    }
+    return nullptr;
+  }
   void* base = MapViewOfFile(handle, (prot & PROT_WRITE) ? FILE_MAP_ALL_ACCESS : FILE_MAP_READ, 0,
                              file_offset, file_length);
   if (base == nullptr) {
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index ed955ea..ea49798 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -293,6 +293,8 @@
     {"kernel_panic,dsps", 166},
     {"kernel_panic,wcnss", 167},
     {"kernel_panic,_sde_encoder_phys_cmd_handle_ppdone_timeout", 168},
+    {"recovery,quiescent", 169},
+    {"reboot,quiescent", 170},
 };
 
 // Converts a string value representing the reason the system booted to an
diff --git a/fs_mgr/libfiemap_writer/fiemap_writer.cpp b/fs_mgr/libfiemap_writer/fiemap_writer.cpp
index 99a1a2f..5b77280 100644
--- a/fs_mgr/libfiemap_writer/fiemap_writer.cpp
+++ b/fs_mgr/libfiemap_writer/fiemap_writer.cpp
@@ -501,12 +501,13 @@
         }
 
         if (!extents->empty() && block == last_block + 1) {
-            extents->back().fe_length++;
+            extents->back().fe_length += s.st_blksize;
         } else {
-            extents->push_back(fiemap_extent{.fe_logical = block_number,
-                                             .fe_physical = block,
-                                             .fe_length = 1,
-                                             .fe_flags = 0});
+            extents->push_back(
+                    fiemap_extent{.fe_logical = block_number,
+                                  .fe_physical = static_cast<uint64_t>(block) * s.st_blksize,
+                                  .fe_length = static_cast<uint64_t>(s.st_blksize),
+                                  .fe_flags = 0});
         }
         last_block = block;
     }
diff --git a/init/service.cpp b/init/service.cpp
index 2186a85..cba42c4 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -1059,7 +1059,7 @@
         std::string oom_str = std::to_string(oom_score_adjust_);
         std::string oom_file = StringPrintf("/proc/%d/oom_score_adj", pid);
         if (!WriteStringToFile(oom_str, oom_file)) {
-            PLOG(ERROR) << "couldn't write oom_score_adj: " << strerror(errno);
+            PLOG(ERROR) << "couldn't write oom_score_adj";
         }
     }
 
diff --git a/libasyncio/Android.bp b/libasyncio/Android.bp
index 0fd2a3a..4ab439d 100644
--- a/libasyncio/Android.bp
+++ b/libasyncio/Android.bp
@@ -27,7 +27,6 @@
     name: "libasyncio",
     defaults: ["libasyncio_defaults"],
     vendor_available: true,
-    double_loadable: true,
     recovery_available: true,
     host_supported: true,
     srcs: [
diff --git a/libcutils/include/cutils/native_handle.h b/libcutils/include/cutils/native_handle.h
index 10f5bc0..f6cae36 100644
--- a/libcutils/include/cutils/native_handle.h
+++ b/libcutils/include/cutils/native_handle.h
@@ -23,6 +23,9 @@
 extern "C" {
 #endif
 
+#define NATIVE_HANDLE_MAX_FDS 1024
+#define NATIVE_HANDLE_MAX_INTS 1024
+
 /* Declare a char array for use with native_handle_init */
 #define NATIVE_HANDLE_DECLARE_STORAGE(name, maxFds, maxInts) \
     alignas(native_handle_t) char (name)[                            \
diff --git a/libcutils/native_handle.cpp b/libcutils/native_handle.cpp
index 66f7a3d..b409e5b 100644
--- a/libcutils/native_handle.cpp
+++ b/libcutils/native_handle.cpp
@@ -22,9 +22,6 @@
 #include <string.h>
 #include <unistd.h>
 
-static const int kMaxNativeFds = 1024;
-static const int kMaxNativeInts = 1024;
-
 native_handle_t* native_handle_init(char* storage, int numFds, int numInts) {
     if ((uintptr_t) storage % alignof(native_handle_t)) {
         errno = EINVAL;
@@ -39,7 +36,8 @@
 }
 
 native_handle_t* native_handle_create(int numFds, int numInts) {
-    if (numFds < 0 || numInts < 0 || numFds > kMaxNativeFds || numInts > kMaxNativeInts) {
+    if (numFds < 0 || numInts < 0 || numFds > NATIVE_HANDLE_MAX_FDS ||
+        numInts > NATIVE_HANDLE_MAX_INTS) {
         errno = EINVAL;
         return NULL;
     }
diff --git a/libkeyutils/Android.bp b/libkeyutils/Android.bp
index e816926..dda491a 100644
--- a/libkeyutils/Android.bp
+++ b/libkeyutils/Android.bp
@@ -19,13 +19,14 @@
 
 cc_binary {
     name: "mini-keyctl",
-    srcs: ["mini_keyctl.cpp"],
-
+    srcs: [
+        "mini_keyctl.cpp",
+        "mini_keyctl_utils.cpp"
+    ],
     shared_libs: [
         "libbase",
         "libkeyutils",
         "liblog",
     ],
-
-    cflags: ["-Werror", "-Wall", "-Wextra"],
+    cflags: ["-Werror", "-Wall", "-Wextra", "-fexceptions"],
 }
diff --git a/libkeyutils/mini_keyctl.cpp b/libkeyutils/mini_keyctl.cpp
index abc8f82..4fe4c3c 100644
--- a/libkeyutils/mini_keyctl.cpp
+++ b/libkeyutils/mini_keyctl.cpp
@@ -18,159 +18,57 @@
  * A tool loads keys to keyring.
  */
 
-#include <dirent.h>
-#include <errno.h>
-#include <sys/types.h>
+#include "mini_keyctl_utils.h"
+
 #include <unistd.h>
 
-#include <fstream>
-#include <iostream>
-#include <iterator>
-#include <sstream>
-#include <string>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <android-base/strings.h>
-#include <keyutils.h>
-
-static constexpr int kMaxCertSize = 4096;
-
-// Add all the certs from directory path to keyring with keyring_id. Returns the number of keys
-// added.
-int AddKeys(const std::string& path, const key_serial_t keyring_id, const std::string& keyring_desc,
-            int start_index) {
-  std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(path.c_str()), closedir);
-  if (!dir) {
-    PLOG(WARNING) << "Failed to open directory " << path;
-    return 0;
-  }
-  int keys_added = 0;
-  struct dirent* dp;
-  while ((dp = readdir(dir.get())) != NULL) {
-    if (dp->d_type != DT_REG) {
-      continue;
-    }
-    std::string cert_path = path + "/" + dp->d_name;
-    std::string cert_buf;
-    if (!android::base::ReadFileToString(cert_path, &cert_buf, false /* follow_symlinks */)) {
-      LOG(ERROR) << "Failed to read " << cert_path;
-      continue;
-    }
-
-    if (cert_buf.size() > kMaxCertSize) {
-      LOG(ERROR) << "Certficate size too large: " << cert_path;
-      continue;
-    }
-
-    // Add key to keyring.
-    int key_desc_index = keys_added + start_index;
-    std::string key_desc = keyring_desc + "-key" + std::to_string(key_desc_index);
-    key_serial_t key =
-        add_key("asymmetric", key_desc.c_str(), &cert_buf[0], cert_buf.size(), keyring_id);
-    if (key < 0) {
-      PLOG(ERROR) << "Failed to add key to keyring: " << cert_path;
-      continue;
-    }
-    keys_added++;
-  }
-  return keys_added;
-}
-
-std::vector<std::string> SplitBySpace(const std::string& s) {
-  std::istringstream iss(s);
-  return std::vector<std::string>{std::istream_iterator<std::string>{iss},
-                                  std::istream_iterator<std::string>{}};
-}
-
-// Find the keyring id. Because request_key(2) syscall is not available or the key is
-// kernel keyring, the id is looked up from /proc/keys. The keyring description may contain other
-// information in the descritption section depending on the key type, only the first word in the
-// keyring description is used for searching.
-bool GetKeyringId(const std::string& keyring_desc, key_serial_t* keyring_id) {
-  if (!keyring_id) {
-    LOG(ERROR) << "keyring_id is null";
-    return false;
-  }
-
-  // Only keys allowed by SELinux rules will be shown here.
-  std::ifstream proc_keys_file("/proc/keys");
-  if (!proc_keys_file.is_open()) {
-    PLOG(ERROR) << "Failed to open /proc/keys";
-    return false;
-  }
-
-  std::string line;
-  while (getline(proc_keys_file, line)) {
-    std::vector<std::string> tokens = SplitBySpace(line);
-    if (tokens.size() < 9) {
-      continue;
-    }
-    std::string key_id = tokens[0];
-    std::string key_type = tokens[7];
-    // The key description may contain space.
-    std::string key_desc_prefix = tokens[8];
-    // The prefix has a ":" at the end
-    std::string key_desc_pattern = keyring_desc + ":";
-    if (key_type != "keyring" || key_desc_prefix != key_desc_pattern) {
-      continue;
-    }
-    *keyring_id = std::stoi(key_id, nullptr, 16);
-    return true;
-  }
-  return false;
-}
-
 static void Usage(int exit_code) {
-  fprintf(stderr, "usage: mini-keyctl -c PATHS -s DESCRIPTION\n");
-  fprintf(stderr, "\n");
-  fprintf(stderr, "-c, --cert_dirs     the certificate locations, separated by comma\n");
-  fprintf(stderr, "-k, --keyring       the keyring description\n");
+  fprintf(stderr, "usage: mini-keyctl <action> [args,]\n");
+  fprintf(stderr, "       mini-keyctl add <type> <desc> <data> <keyring>\n");
+  fprintf(stderr, "       mini-keyctl padd <type> <desc> <keyring>\n");
+  fprintf(stderr, "       mini-keyctl dadd <type> <desc_prefix> <cert_dir> <keyring>\n");
+  fprintf(stderr, "       mini-keyctl unlink <key> <keyring>\n");
+  fprintf(stderr, "       mini-keyctl restrict_keyring <keyring>\n");
   _exit(exit_code);
 }
 
-int main(int argc, char** argv) {
-  if (argc < 5) Usage(1);
+int main(int argc, const char** argv) {
+  if (argc < 2) Usage(1);
+  const std::string action = argv[1];
 
-  std::string arg_cert_dirs;
-  std::string arg_keyring_desc;
-
-  for (int i = 1; i < argc; i++) {
-    std::string option = argv[i];
-    if (option == "-c" || option == "--cert_dirs") {
-      if (i + 1 < argc) arg_cert_dirs = argv[++i];
-    } else if (option == "-k" || option == "--keyring") {
-      if (i + 1 < argc) arg_keyring_desc = argv[++i];
-    }
-  }
-
-  if (arg_cert_dirs.empty() || arg_keyring_desc.empty()) {
-    LOG(ERROR) << "Missing cert_dirs or keyring desc";
+  if (action == "add") {
+    if (argc != 6) Usage(1);
+    std::string type = argv[2];
+    std::string desc = argv[3];
+    std::string data = argv[4];
+    std::string keyring = argv[5];
+    return Add(type, desc, data, keyring);
+  } else if (action == "dadd") {
+    if (argc != 6) Usage(1);
+    std::string type = argv[2];
+    // The key description contains desc_prefix and an index.
+    std::string desc_prefix = argv[3];
+    std::string cert_dir = argv[4];
+    std::string keyring = argv[5];
+    return AddCertsFromDir(type, desc_prefix, cert_dir, keyring);
+  } else if (action == "padd") {
+    if (argc != 5) Usage(1);
+    std::string type = argv[2];
+    std::string desc = argv[3];
+    std::string keyring = argv[4];
+    return Padd(type, desc, keyring);
+  } else if (action == "restrict_keyring") {
+    if (argc != 3) Usage(1);
+    std::string keyring = argv[2];
+    return RestrictKeyring(keyring);
+  } else if (action == "unlink") {
+    if (argc != 4) Usage(1);
+    key_serial_t key = std::stoi(argv[2], nullptr, 16);
+    const std::string keyring = argv[3];
+    return Unlink(key, keyring);
+  } else {
     Usage(1);
   }
 
-  // Get the keyring id
-  key_serial_t key_ring_id;
-  if (!GetKeyringId(arg_keyring_desc, &key_ring_id)) {
-    PLOG(ERROR) << "Can't find keyring with " << arg_keyring_desc;
-    return 1;
-  }
-
-  std::vector<std::string> cert_dirs = android::base::Split(arg_cert_dirs, ",");
-  int start_index = 0;
-  for (const auto& cert_dir : cert_dirs) {
-    int keys_added = AddKeys(cert_dir, key_ring_id, arg_keyring_desc, start_index);
-    start_index += keys_added;
-  }
-
-  // Prevent new keys to be added.
-  if (!android::base::GetBoolProperty("ro.debuggable", false) &&
-      keyctl_restrict_keyring(key_ring_id, nullptr, nullptr) < 0) {
-    PLOG(ERROR) << "Failed to restrict key ring " << arg_keyring_desc;
-    return 1;
-  }
-
   return 0;
 }
diff --git a/libkeyutils/mini_keyctl_utils.cpp b/libkeyutils/mini_keyctl_utils.cpp
new file mode 100644
index 0000000..c4fc96c
--- /dev/null
+++ b/libkeyutils/mini_keyctl_utils.cpp
@@ -0,0 +1,212 @@
+/*
+ * 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 <mini_keyctl_utils.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <fstream>
+#include <iostream>
+#include <iterator>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <keyutils.h>
+
+static constexpr int kMaxCertSize = 4096;
+
+std::vector<std::string> SplitBySpace(const std::string& s) {
+  std::istringstream iss(s);
+  return std::vector<std::string>{std::istream_iterator<std::string>{iss},
+                                  std::istream_iterator<std::string>{}};
+}
+
+int AddCertsFromDir(const std::string& type, const std::string& desc_prefix,
+                    const std::string& cert_dir, const std::string& keyring) {
+  key_serial_t keyring_id;
+  if (!GetKeyringId(keyring, &keyring_id)) {
+    LOG(ERROR) << "Can not find keyring id";
+    return 1;
+  }
+
+  std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(cert_dir.c_str()), closedir);
+  if (!dir) {
+    PLOG(WARNING) << "Failed to open directory " << cert_dir;
+    return 1;
+  }
+  int keys_added = 0;
+  struct dirent* dp;
+  while ((dp = readdir(dir.get())) != NULL) {
+    if (dp->d_type != DT_REG) {
+      continue;
+    }
+    std::string cert_path = cert_dir + "/" + dp->d_name;
+    std::string cert_buf;
+    if (!android::base::ReadFileToString(cert_path, &cert_buf, false /* follow_symlinks */)) {
+      LOG(ERROR) << "Failed to read " << cert_path;
+      continue;
+    }
+
+    if (cert_buf.size() > kMaxCertSize) {
+      LOG(ERROR) << "Certficate size too large: " << cert_path;
+      continue;
+    }
+
+    // Add key to keyring.
+    int key_desc_index = keys_added;
+    std::string key_desc = desc_prefix + std::to_string(key_desc_index);
+    key_serial_t key =
+        add_key(type.c_str(), key_desc.c_str(), &cert_buf[0], cert_buf.size(), keyring_id);
+    if (key < 0) {
+      PLOG(ERROR) << "Failed to add key to keyring: " << cert_path;
+      continue;
+    }
+    LOG(INFO) << "Key " << cert_path << " added to " << keyring << " with key id 0x" << std::hex
+              << key;
+    keys_added++;
+  }
+  return 0;
+}
+
+bool GetKeyringId(const std::string& keyring_desc, key_serial_t* keyring_id) {
+  if (!keyring_id) {
+    LOG(ERROR) << "keyring_id is null";
+    return false;
+  }
+
+  // If the keyring id is already a hex number, directly convert it to keyring id
+  try {
+    key_serial_t id = std::stoi(keyring_desc, nullptr, 16);
+    *keyring_id = id;
+    return true;
+  } catch (const std::exception& e) {
+    LOG(INFO) << "search /proc/keys for keyring id";
+  }
+
+  // Only keys allowed by SELinux rules will be shown here.
+  std::ifstream proc_keys_file("/proc/keys");
+  if (!proc_keys_file.is_open()) {
+    PLOG(ERROR) << "Failed to open /proc/keys";
+    return false;
+  }
+
+  std::string line;
+  while (getline(proc_keys_file, line)) {
+    std::vector<std::string> tokens = SplitBySpace(line);
+    if (tokens.size() < 9) {
+      continue;
+    }
+    std::string key_id = tokens[0];
+    std::string key_type = tokens[7];
+    // The key description may contain space.
+    std::string key_desc_prefix = tokens[8];
+    // The prefix has a ":" at the end
+    std::string key_desc_pattern = keyring_desc + ":";
+    if (key_type != "keyring" || key_desc_prefix != key_desc_pattern) {
+      continue;
+    }
+    *keyring_id = std::stoi(key_id, nullptr, 16);
+    return true;
+  }
+  return false;
+}
+
+int Unlink(key_serial_t key, const std::string& keyring) {
+  key_serial_t keyring_id;
+  if (!GetKeyringId(keyring, &keyring_id)) {
+    LOG(ERROR) << "Can't find keyring " << keyring;
+    return 1;
+  }
+
+  if (keyctl_unlink(key, keyring_id) < 0) {
+    PLOG(ERROR) << "Failed to unlink key 0x" << std::hex << key << " from keyring " << keyring_id;
+    return 1;
+  }
+  return 0;
+}
+
+int Add(const std::string& type, const std::string& desc, const std::string& data,
+        const std::string& keyring) {
+  if (data.size() > kMaxCertSize) {
+    LOG(ERROR) << "Certificate too large";
+    return 1;
+  }
+
+  key_serial_t keyring_id;
+  if (!GetKeyringId(keyring, &keyring_id)) {
+    LOG(ERROR) << "Can not find keyring id";
+    return 1;
+  }
+
+  key_serial_t key = add_key(type.c_str(), desc.c_str(), data.c_str(), data.size(), keyring_id);
+
+  if (key < 0) {
+    PLOG(ERROR) << "Failed to add key";
+    return 1;
+  }
+
+  LOG(INFO) << "Key " << desc << " added to " << keyring << " with key id: 0x" << std::hex << key;
+  return 0;
+}
+
+int Padd(const std::string& type, const std::string& desc, const std::string& keyring) {
+  key_serial_t keyring_id;
+  if (!GetKeyringId(keyring, &keyring_id)) {
+    LOG(ERROR) << "Can not find keyring id";
+    return 1;
+  }
+
+  // read from stdin to get the certificates
+  std::istreambuf_iterator<char> begin(std::cin), end;
+  std::string data(begin, end);
+
+  if (data.size() > kMaxCertSize) {
+    LOG(ERROR) << "Certificate too large";
+    return 1;
+  }
+
+  key_serial_t key = add_key(type.c_str(), desc.c_str(), data.c_str(), data.size(), keyring_id);
+
+  if (key < 0) {
+    PLOG(ERROR) << "Failed to add key";
+    return 1;
+  }
+
+  LOG(INFO) << "Key " << desc << " added to " << keyring << " with key id: 0x" << std::hex << key;
+  return 0;
+}
+
+int RestrictKeyring(const std::string& keyring) {
+  key_serial_t keyring_id;
+  if (!GetKeyringId(keyring, &keyring_id)) {
+    LOG(ERROR) << "Cannot find keyring id";
+    return 1;
+  }
+
+  if (keyctl_restrict_keyring(keyring_id, nullptr, nullptr) < 0) {
+    PLOG(ERROR) << "Cannot restrict keyring " << keyring;
+    return 1;
+  }
+  return 0;
+}
diff --git a/libkeyutils/mini_keyctl_utils.h b/libkeyutils/mini_keyctl_utils.h
new file mode 100644
index 0000000..3c69611
--- /dev/null
+++ b/libkeyutils/mini_keyctl_utils.h
@@ -0,0 +1,48 @@
+/*
+ * 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 "include/keyutils.h"
+
+#include <string>
+
+// Add all files in a directory as certificates to a keyring. |keyring| could be the keyring
+// description or keyring id in hex.
+int AddCertsFromDir(const std::string& type, const std::string& desc_prefix,
+                    const std::string& cert_dir, const std::string& keyring);
+
+// Add all the certs from directory path to keyring with keyring_id. Returns the number of keys
+// added. Returns non-zero if any error happens.
+int AddKeys(const std::string& path, const key_serial_t keyring_id, const std::string& type,
+            const std::string& desc, int start_index);
+
+// Add key to a keyring. Returns non-zero if error happens.
+int Add(const std::string& type, const std::string& desc, const std::string& data,
+        const std::string& keyring);
+
+// Add key from stdin to a keyring. Returns non-zero if error happens.
+int Padd(const std::string& type, const std::string& desc, const std::string& keyring);
+
+// Removes the link from a keyring to a key if exists. Return non-zero if error happens.
+int Unlink(key_serial_t key, const std::string& keyring);
+
+// Apply key-linking to a keyring. Return non-zero if error happens.
+int RestrictKeyring(const std::string& keyring);
+
+// Find the keyring id. Because request_key(2) syscall is not available or the key is
+// kernel keyring, the id is looked up from /proc/keys. The keyring description may contain other
+// information in the descritption section depending on the key type, only the first word in the
+// keyring description is used for searching.
+bool GetKeyringId(const std::string& keyring_desc, key_serial_t* keyring_id);
diff --git a/libmemtrack/Android.bp b/libmemtrack/Android.bp
index 320b851..4e4554a 100644
--- a/libmemtrack/Android.bp
+++ b/libmemtrack/Android.bp
@@ -6,7 +6,6 @@
     vndk: {
         enabled: true,
     },
-    double_loadable: true,
     srcs: ["memtrack.cpp"],
     export_include_dirs: ["include"],
     local_include_dirs: ["include"],
diff --git a/libnativeloader/include/nativeloader/native_loader.h b/libnativeloader/include/nativeloader/native_loader.h
index 260f655..51fb875 100644
--- a/libnativeloader/include/nativeloader/native_loader.h
+++ b/libnativeloader/include/nativeloader/native_loader.h
@@ -36,14 +36,9 @@
 __attribute__((visibility("default")))
 void InitializeNativeLoader();
 
-__attribute__((visibility("default")))
-jstring CreateClassLoaderNamespace(JNIEnv* env,
-                                   int32_t target_sdk_version,
-                                   jobject class_loader,
-                                   bool is_shared,
-                                   bool is_for_vendor,
-                                   jstring library_path,
-                                   jstring permitted_path);
+__attribute__((visibility("default"))) jstring CreateClassLoaderNamespace(
+    JNIEnv* env, int32_t target_sdk_version, jobject class_loader, bool is_shared, jstring dex_path,
+    jstring library_path, jstring permitted_path);
 
 __attribute__((visibility("default"))) void* OpenNativeLibrary(
     JNIEnv* env, int32_t target_sdk_version, const char* path, jobject class_loader,
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 043f038..1c2581f 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -31,6 +31,7 @@
 #include <list>
 #include <memory>
 #include <mutex>
+#include <regex>
 #include <string>
 #include <vector>
 
@@ -140,10 +141,24 @@
 
 #if defined(__LP64__)
 static constexpr const char* kRuntimeApexLibPath = "/apex/com.android.runtime/lib64";
+static constexpr const char* kVendorLibPath = "/vendor/lib64";
+static constexpr const char* kProductLibPath = "/product/lib64:/system/product/lib64";
 #else
 static constexpr const char* kRuntimeApexLibPath = "/apex/com.android.runtime/lib";
+static constexpr const char* kVendorLibPath = "/vendor/lib";
+static constexpr const char* kProductLibPath = "/product/lib:/system/product/lib";
 #endif
 
+static const std::regex kVendorDexPathRegex("(^|:)/vendor/");
+static const std::regex kProductDexPathRegex("(^|:)(/system)?/product/");
+
+// Define origin of APK if it is from vendor partition or product partition
+typedef enum {
+  APK_ORIGIN_DEFAULT = 0,
+  APK_ORIGIN_VENDOR = 1,
+  APK_ORIGIN_PRODUCT = 2,
+} ApkOrigin;
+
 static bool is_debuggable() {
   bool debuggable = false;
 #ifdef __BIONIC__
@@ -179,7 +194,7 @@
   LibraryNamespaces() : initialized_(false) { }
 
   NativeLoaderNamespace* Create(JNIEnv* env, uint32_t target_sdk_version, jobject class_loader,
-                                bool is_shared, bool is_for_vendor, jstring java_library_path,
+                                bool is_shared, jstring dex_path, jstring java_library_path,
                                 jstring java_permitted_path, std::string* error_msg) {
     std::string library_path; // empty string by default.
 
@@ -188,6 +203,8 @@
       library_path = library_path_utf_chars.c_str();
     }
 
+    ApkOrigin apk_origin = GetApkOriginFromDexPath(env, dex_path);
+
     // (http://b/27588281) This is a workaround for apps using custom
     // classloaders and calling System.load() with an absolute path which
     // is outside of the classloader library search path.
@@ -234,31 +251,50 @@
     std::string system_exposed_libraries = system_public_libraries_;
     const char* namespace_name = kClassloaderNamespaceName;
     android_namespace_t* vndk_ns = nullptr;
-    if (is_for_vendor && !is_shared) {
-      LOG_FATAL_IF(is_native_bridge, "Unbundled vendor apk must not use translated architecture");
+    if ((apk_origin == APK_ORIGIN_VENDOR ||
+         (apk_origin == APK_ORIGIN_PRODUCT && target_sdk_version > 29)) &&
+        !is_shared) {
+      LOG_FATAL_IF(is_native_bridge,
+                   "Unbundled vendor / product apk must not use translated architecture");
 
-      // For vendor apks, give access to the vendor lib even though
+      // For vendor / product apks, give access to the vendor / product lib even though
       // they are treated as unbundled; the libs and apks are still bundled
-      // together in the vendor partition.
-#if defined(__LP64__)
-      std::string vendor_lib_path = "/vendor/lib64";
-#else
-      std::string vendor_lib_path = "/vendor/lib";
-#endif
-      library_path = library_path + ":" + vendor_lib_path.c_str();
-      permitted_path = permitted_path + ":" + vendor_lib_path.c_str();
+      // together in the vendor / product partition.
+      const char* origin_partition;
+      const char* origin_lib_path;
+
+      switch (apk_origin) {
+        case APK_ORIGIN_VENDOR:
+          origin_partition = "vendor";
+          origin_lib_path = kVendorLibPath;
+          break;
+        case APK_ORIGIN_PRODUCT:
+          origin_partition = "product";
+          origin_lib_path = kProductLibPath;
+          break;
+        default:
+          origin_partition = "unknown";
+          origin_lib_path = "";
+      }
+
+      LOG_FATAL_IF(is_native_bridge, "Unbundled %s apk must not use translated architecture",
+                   origin_partition);
+
+      library_path = library_path + ":" + origin_lib_path;
+      permitted_path = permitted_path + ":" + origin_lib_path;
 
       // Also give access to LLNDK libraries since they are available to vendors
       system_exposed_libraries = system_exposed_libraries + ":" + system_llndk_libraries_.c_str();
 
       // Give access to VNDK-SP libraries from the 'vndk' namespace.
       vndk_ns = android_get_exported_namespace(kVndkNamespaceName);
-      LOG_ALWAYS_FATAL_IF(vndk_ns == nullptr,
-                          "Cannot find \"%s\" namespace for vendor apks", kVndkNamespaceName);
+      LOG_ALWAYS_FATAL_IF(vndk_ns == nullptr, "Cannot find \"%s\" namespace for %s apks",
+                          kVndkNamespaceName, origin_partition);
 
       // Different name is useful for debugging
       namespace_name = kVendorClassloaderNamespaceName;
-      ALOGD("classloader namespace configured for unbundled vendor apk. library_path=%s", library_path.c_str());
+      ALOGD("classloader namespace configured for unbundled %s apk. library_path=%s",
+            origin_partition, library_path.c_str());
     } else {
       // oem and product public libraries are NOT available to vendor apks, otherwise it
       // would be system->vendor violation.
@@ -660,6 +696,28 @@
     return nullptr;
   }
 
+  ApkOrigin GetApkOriginFromDexPath(JNIEnv* env, jstring dex_path) {
+    ApkOrigin apk_origin = APK_ORIGIN_DEFAULT;
+
+    if (dex_path != nullptr) {
+      ScopedUtfChars dex_path_utf_chars(env, dex_path);
+
+      if (std::regex_search(dex_path_utf_chars.c_str(), kVendorDexPathRegex)) {
+        apk_origin = APK_ORIGIN_VENDOR;
+      }
+
+      if (std::regex_search(dex_path_utf_chars.c_str(), kProductDexPathRegex)) {
+        LOG_ALWAYS_FATAL_IF(apk_origin == APK_ORIGIN_VENDOR,
+                            "Dex path contains both vendor and product partition : %s",
+                            dex_path_utf_chars.c_str());
+
+        apk_origin = APK_ORIGIN_PRODUCT;
+      }
+    }
+
+    return apk_origin;
+  }
+
   bool initialized_;
   std::list<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
   std::string system_public_libraries_;
@@ -690,31 +748,20 @@
 #endif
 }
 
-jstring CreateClassLoaderNamespace(JNIEnv* env,
-                                   int32_t target_sdk_version,
-                                   jobject class_loader,
-                                   bool is_shared,
-                                   bool is_for_vendor,
-                                   jstring library_path,
+jstring CreateClassLoaderNamespace(JNIEnv* env, int32_t target_sdk_version, jobject class_loader,
+                                   bool is_shared, jstring dex_path, jstring library_path,
                                    jstring permitted_path) {
 #if defined(__ANDROID__)
   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
 
   std::string error_msg;
-  bool success = g_namespaces->Create(env,
-                                      target_sdk_version,
-                                      class_loader,
-                                      is_shared,
-                                      is_for_vendor,
-                                      library_path,
-                                      permitted_path,
-                                      &error_msg) != nullptr;
+  bool success = g_namespaces->Create(env, target_sdk_version, class_loader, is_shared, dex_path,
+                                      library_path, permitted_path, &error_msg) != nullptr;
   if (!success) {
     return env->NewStringUTF(error_msg.c_str());
   }
 #else
-  UNUSED(env, target_sdk_version, class_loader, is_shared, is_for_vendor,
-         library_path, permitted_path);
+  UNUSED(env, target_sdk_version, class_loader, is_shared, dex_path, library_path, permitted_path);
 #endif
   return nullptr;
 }
@@ -779,8 +826,7 @@
     // In this case we create an isolated not-shared namespace for it.
     std::string create_error_msg;
     if ((ns = g_namespaces->Create(env, target_sdk_version, class_loader, false /* is_shared */,
-                                   false /* is_for_vendor */, library_path, nullptr,
-                                   &create_error_msg)) == nullptr) {
+                                   nullptr, library_path, nullptr, &create_error_msg)) == nullptr) {
       *error_msg = strdup(create_error_msg.c_str());
       return nullptr;
     }
diff --git a/libnativeloader/native_loader_lazy.cpp b/libnativeloader/native_loader_lazy.cpp
index 11ecc43..2eb1203 100644
--- a/libnativeloader/native_loader_lazy.cpp
+++ b/libnativeloader/native_loader_lazy.cpp
@@ -50,10 +50,10 @@
 }
 
 jstring CreateClassLoaderNamespace(JNIEnv* env, int32_t target_sdk_version, jobject class_loader,
-                                   bool is_shared, bool is_for_vendor, jstring library_path,
+                                   bool is_shared, jstring dex_path, jstring library_path,
                                    jstring permitted_path) {
   static auto f = GET_FUNC_PTR(CreateClassLoaderNamespace);
-  return f(env, target_sdk_version, class_loader, is_shared, is_for_vendor, library_path,
+  return f(env, target_sdk_version, class_loader, is_shared, dex_path, library_path,
            permitted_path);
 }
 
diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp
index 26d0754..9951621 100644
--- a/libprocessgroup/cgroup_map.cpp
+++ b/libprocessgroup/cgroup_map.cpp
@@ -117,7 +117,7 @@
     std::string json_doc;
 
     if (!android::base::ReadFileToString(file_name, &json_doc)) {
-        LOG(ERROR) << "Failed to read task profiles from " << file_name;
+        PLOG(ERROR) << "Failed to read task profiles from " << file_name;
         return false;
     }
 
@@ -185,7 +185,7 @@
 
     // mkdir <path> [mode] [owner] [group]
     if (!Mkdir(controller->path(), descriptor.mode(), descriptor.uid(), descriptor.gid())) {
-        PLOG(ERROR) << "Failed to create directory for " << controller->name() << " cgroup";
+        LOG(ERROR) << "Failed to create directory for " << controller->name() << " cgroup";
         return false;
     }
 
@@ -289,7 +289,7 @@
     std::string file_name = StringPrintf("/proc/%d/cgroup", tid);
     std::string content;
     if (!android::base::ReadFileToString(file_name, &content)) {
-        LOG(ERROR) << "Failed to read " << file_name;
+        PLOG(ERROR) << "Failed to read " << file_name;
         return false;
     }
 
@@ -323,7 +323,7 @@
 
 CgroupMap::CgroupMap() : cg_file_data_(nullptr), cg_file_size_(0) {
     if (!LoadRcFile()) {
-        PLOG(ERROR) << "CgroupMap::LoadRcFile called for [" << getpid() << "] failed";
+        LOG(ERROR) << "CgroupMap::LoadRcFile called for [" << getpid() << "] failed";
     }
 }
 
@@ -360,27 +360,42 @@
         return false;
     }
 
-    cg_file_size_ = sb.st_size;
-    if (cg_file_size_ < sizeof(CgroupFile)) {
-        PLOG(ERROR) << "Invalid file format " << cgroup_rc_path;
+    size_t file_size = sb.st_size;
+    if (file_size < sizeof(CgroupFile)) {
+        LOG(ERROR) << "Invalid file format " << cgroup_rc_path;
         return false;
     }
 
-    cg_file_data_ = (CgroupFile*)mmap(nullptr, cg_file_size_, PROT_READ, MAP_SHARED, fd, 0);
-    if (cg_file_data_ == MAP_FAILED) {
+    CgroupFile* file_data = (CgroupFile*)mmap(nullptr, file_size, PROT_READ, MAP_SHARED, fd, 0);
+    if (file_data == MAP_FAILED) {
         PLOG(ERROR) << "Failed to mmap " << cgroup_rc_path;
         return false;
     }
 
-    if (cg_file_data_->version_ != CgroupFile::FILE_CURR_VERSION) {
-        PLOG(ERROR) << cgroup_rc_path << " file version mismatch";
+    if (file_data->version_ != CgroupFile::FILE_CURR_VERSION) {
+        LOG(ERROR) << cgroup_rc_path << " file version mismatch";
+        munmap(file_data, file_size);
         return false;
     }
 
+    if (file_size != sizeof(CgroupFile) + file_data->controller_count_ * sizeof(CgroupController)) {
+        LOG(ERROR) << cgroup_rc_path << " file has invalid size";
+        munmap(file_data, file_size);
+        return false;
+    }
+
+    cg_file_data_ = file_data;
+    cg_file_size_ = file_size;
+
     return true;
 }
 
-void CgroupMap::Print() {
+void CgroupMap::Print() const {
+    if (!cg_file_data_) {
+        LOG(ERROR) << "CgroupMap::Print called for [" << getpid()
+                   << "] failed, RC file was not initialized properly";
+        return;
+    }
     LOG(INFO) << "File version = " << cg_file_data_->version_;
     LOG(INFO) << "File controller count = " << cg_file_data_->controller_count_;
 
@@ -397,7 +412,7 @@
 
     // load cgroups.json file
     if (!ReadDescriptors(&descriptors)) {
-        PLOG(ERROR) << "Failed to load cgroup description file";
+        LOG(ERROR) << "Failed to load cgroup description file";
         return false;
     }
 
@@ -412,7 +427,7 @@
 
     // mkdir <CGROUPS_RC_DIR> 0711 system system
     if (!Mkdir(CGROUPS_RC_DIR, 0711, "system", "system")) {
-        PLOG(ERROR) << "Failed to create directory for <CGROUPS_RC_FILE> file";
+        LOG(ERROR) << "Failed to create directory for <CGROUPS_RC_FILE> file";
         return false;
     }
 
@@ -428,7 +443,7 @@
     std::string cgroup_rc_path = StringPrintf("%s/%s", CGROUPS_RC_DIR, CGROUPS_RC_FILE);
     // chmod 0644 <cgroup_rc_path>
     if (fchmodat(AT_FDCWD, cgroup_rc_path.c_str(), 0644, AT_SYMLINK_NOFOLLOW) < 0) {
-        LOG(ERROR) << "fchmodat() failed";
+        PLOG(ERROR) << "fchmodat() failed";
         return false;
     }
 
@@ -437,6 +452,8 @@
 
 const CgroupController* CgroupMap::FindController(const std::string& name) const {
     if (!cg_file_data_) {
+        LOG(ERROR) << "CgroupMap::FindController called for [" << getpid()
+                   << "] failed, RC file was not initialized properly";
         return nullptr;
     }
 
diff --git a/libprocessgroup/cgroup_map.h b/libprocessgroup/cgroup_map.h
index ba2caf7..1c355cd 100644
--- a/libprocessgroup/cgroup_map.h
+++ b/libprocessgroup/cgroup_map.h
@@ -92,5 +92,5 @@
     ~CgroupMap();
 
     bool LoadRcFile();
-    void Print();
+    void Print() const;
 };
diff --git a/libprocessgroup/sched_policy.cpp b/libprocessgroup/sched_policy.cpp
index 026c011..1eefada 100644
--- a/libprocessgroup/sched_policy.cpp
+++ b/libprocessgroup/sched_policy.cpp
@@ -167,7 +167,7 @@
     if (!controller) return -1;
 
     if (!controller->GetTaskGroup(tid, &subgroup)) {
-        PLOG(ERROR) << "Failed to find cgroup for tid " << tid;
+        LOG(ERROR) << "Failed to find cgroup for tid " << tid;
         return -1;
     }
     return 0;
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index fded417..dcf53f9 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -119,7 +119,7 @@
     std::string path;
 
     if (!attribute_->GetPathForTask(tid, &path)) {
-        PLOG(ERROR) << "Failed to find cgroup for tid " << tid;
+        LOG(ERROR) << "Failed to find cgroup for tid " << tid;
         return false;
     }
 
@@ -174,7 +174,7 @@
     if (TEMP_FAILURE_RETRY(write(fd, value.c_str(), value.length())) < 0) {
         // If the thread is in the process of exiting, don't flag an error
         if (errno != ESRCH) {
-            PLOG(ERROR) << "JoinGroup failed to write '" << value << "'; fd=" << fd;
+            PLOG(ERROR) << "AddTidToCgroup failed to write '" << value << "'; fd=" << fd;
             return false;
         }
     }
@@ -187,7 +187,7 @@
     if (fd_ >= 0) {
         // fd is cached, reuse it
         if (!AddTidToCgroup(pid, fd_)) {
-            PLOG(ERROR) << "Failed to add task into cgroup";
+            LOG(ERROR) << "Failed to add task into cgroup";
             return false;
         }
         return true;
@@ -206,7 +206,7 @@
         return false;
     }
     if (!AddTidToCgroup(pid, tmp_fd)) {
-        PLOG(ERROR) << "Failed to add task into cgroup";
+        LOG(ERROR) << "Failed to add task into cgroup";
         return false;
     }
 
@@ -219,7 +219,7 @@
         return true;
     }
     if (!AddTidToCgroup(pid, tmp_fd)) {
-        PLOG(ERROR) << "Failed to add task into cgroup";
+        LOG(ERROR) << "Failed to add task into cgroup";
         return false;
     }
 
@@ -232,7 +232,7 @@
     if (fd_ >= 0) {
         // fd is cached, reuse it
         if (!AddTidToCgroup(tid, fd_)) {
-            PLOG(ERROR) << "Failed to add task into cgroup";
+            LOG(ERROR) << "Failed to add task into cgroup";
             return false;
         }
         return true;
@@ -244,7 +244,7 @@
     }
 
     // application-dependent path can't be used with tid
-    PLOG(ERROR) << "Application profile can't be applied to a thread";
+    LOG(ERROR) << "Application profile can't be applied to a thread";
     return false;
 #else
     std::string tasks_path = controller_->GetTasksFilePath(path_);
@@ -254,7 +254,7 @@
         return true;
     }
     if (!AddTidToCgroup(tid, tmp_fd)) {
-        PLOG(ERROR) << "Failed to add task into cgroup";
+        LOG(ERROR) << "Failed to add task into cgroup";
         return false;
     }
 
diff --git a/libprocinfo/Android.bp b/libprocinfo/Android.bp
index 27cda93..15f03d0 100644
--- a/libprocinfo/Android.bp
+++ b/libprocinfo/Android.bp
@@ -31,7 +31,6 @@
     vndk: {
         enabled: true,
     },
-    double_loadable: true,
     host_supported: true,
     srcs: [
         "process.cpp",
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index a49fd9e..b7650a1 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -248,6 +248,7 @@
         "tests/files/offline/offset_arm/*",
         "tests/files/offline/shared_lib_in_apk_arm64/*",
         "tests/files/offline/shared_lib_in_apk_memory_only_arm64/*",
+        "tests/files/offline/shared_lib_in_apk_single_map_arm64/*",
         "tests/files/offline/straddle_arm/*",
         "tests/files/offline/straddle_arm64/*",
     ],
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 89a6a79..a38236c 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -88,6 +88,7 @@
   // Check if the start of this map is an embedded elf.
   uint64_t max_size = 0;
   if (Elf::GetInfo(memory.get(), &max_size)) {
+    elf_start_offset = offset;
     if (max_size > map_size) {
       if (memory->Init(name, offset, max_size)) {
         return memory.release();
@@ -96,6 +97,7 @@
       if (memory->Init(name, offset, map_size)) {
         return memory.release();
       }
+      elf_start_offset = 0;
       return nullptr;
     }
     return memory.release();
diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
index dba41d1..b3beb6e 100644
--- a/libunwindstack/include/unwindstack/Memory.h
+++ b/libunwindstack/include/unwindstack/Memory.h
@@ -101,7 +101,7 @@
 
   size_t Size() { return size_; }
 
-  void Clear();
+  void Clear() override;
 
  protected:
   size_t size_ = 0;
diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h
index 878ced3..1c2a81c 100644
--- a/libunwindstack/include/unwindstack/Regs.h
+++ b/libunwindstack/include/unwindstack/Regs.h
@@ -18,6 +18,7 @@
 #define _LIBUNWINDSTACK_REGS_H
 
 #include <stdint.h>
+#include <unistd.h>
 
 #include <functional>
 #include <string>
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
index a66685a..2ddadef 100644
--- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -178,7 +178,7 @@
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
   ASSERT_EQ(0U, info.elf_offset);
-  EXPECT_EQ(0U, info.elf_start_offset);
+  EXPECT_EQ(0x1000U, info.elf_start_offset);
 
   // Read the valid part of the file.
   std::vector<uint8_t> buffer(0x100);
@@ -202,7 +202,7 @@
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
   ASSERT_EQ(0U, info.elf_offset);
-  EXPECT_EQ(0U, info.elf_start_offset);
+  EXPECT_EQ(0x1000U, info.elf_start_offset);
 
   // Verify the memory is a valid elf.
   uint8_t e_ident[SELFMAG + 1];
@@ -219,7 +219,7 @@
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
   ASSERT_EQ(0U, info.elf_offset);
-  EXPECT_EQ(0U, info.elf_start_offset);
+  EXPECT_EQ(0x2000U, info.elf_start_offset);
 
   // Verify the memory is a valid elf.
   uint8_t e_ident[SELFMAG + 1];
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index b5feb38..86bc465 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -1372,4 +1372,56 @@
   // Ignore top frame since the test code was modified to end in __libc_init.
 }
 
+TEST_F(UnwindOfflineTest, shared_lib_in_apk_single_map_arm64) {
+  ASSERT_NO_FATAL_FAILURE(Init("shared_lib_in_apk_single_map_arm64/", ARCH_ARM64));
+
+  Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+  unwinder.Unwind();
+
+  std::string frame_info(DumpFrames(unwinder));
+  ASSERT_EQ(13U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+  EXPECT_EQ(
+      "  #00 pc 00000000000814bc  libc.so (syscall+28)\n"
+      "  #01 pc 00000000008cdf5c  test.apk (offset 0x5000)\n"
+      "  #02 pc 00000000008cde9c  test.apk (offset 0x5000)\n"
+      "  #03 pc 00000000008cdd70  test.apk (offset 0x5000)\n"
+      "  #04 pc 00000000008ce408  test.apk (offset 0x5000)\n"
+      "  #05 pc 00000000008ce8d8  test.apk (offset 0x5000)\n"
+      "  #06 pc 00000000008ce814  test.apk (offset 0x5000)\n"
+      "  #07 pc 00000000008bcf60  test.apk (offset 0x5000)\n"
+      "  #08 pc 0000000000133024  test.apk (offset 0x5000)\n"
+      "  #09 pc 0000000000134ad0  test.apk (offset 0x5000)\n"
+      "  #10 pc 0000000000134b64  test.apk (offset 0x5000)\n"
+      "  #11 pc 00000000000e406c  libc.so (__pthread_start(void*)+36)\n"
+      "  #12 pc 0000000000085e18  libc.so (__start_thread+64)\n",
+      frame_info);
+
+  EXPECT_EQ(0x7cbe0b14bcULL, unwinder.frames()[0].pc);
+  EXPECT_EQ(0x7be4f077d0ULL, unwinder.frames()[0].sp);
+  EXPECT_EQ(0x7be6715f5cULL, unwinder.frames()[1].pc);
+  EXPECT_EQ(0x7be4f077d0ULL, unwinder.frames()[1].sp);
+  EXPECT_EQ(0x7be6715e9cULL, unwinder.frames()[2].pc);
+  EXPECT_EQ(0x7be4f07800ULL, unwinder.frames()[2].sp);
+  EXPECT_EQ(0x7be6715d70ULL, unwinder.frames()[3].pc);
+  EXPECT_EQ(0x7be4f07840ULL, unwinder.frames()[3].sp);
+  EXPECT_EQ(0x7be6716408ULL, unwinder.frames()[4].pc);
+  EXPECT_EQ(0x7be4f07860ULL, unwinder.frames()[4].sp);
+  EXPECT_EQ(0x7be67168d8ULL, unwinder.frames()[5].pc);
+  EXPECT_EQ(0x7be4f07880ULL, unwinder.frames()[5].sp);
+  EXPECT_EQ(0x7be6716814ULL, unwinder.frames()[6].pc);
+  EXPECT_EQ(0x7be4f078f0ULL, unwinder.frames()[6].sp);
+  EXPECT_EQ(0x7be6704f60ULL, unwinder.frames()[7].pc);
+  EXPECT_EQ(0x7be4f07910ULL, unwinder.frames()[7].sp);
+  EXPECT_EQ(0x7be5f7b024ULL, unwinder.frames()[8].pc);
+  EXPECT_EQ(0x7be4f07950ULL, unwinder.frames()[8].sp);
+  EXPECT_EQ(0x7be5f7cad0ULL, unwinder.frames()[9].pc);
+  EXPECT_EQ(0x7be4f07aa0ULL, unwinder.frames()[9].sp);
+  EXPECT_EQ(0x7be5f7cb64ULL, unwinder.frames()[10].pc);
+  EXPECT_EQ(0x7be4f07ce0ULL, unwinder.frames()[10].sp);
+  EXPECT_EQ(0x7cbe11406cULL, unwinder.frames()[11].pc);
+  EXPECT_EQ(0x7be4f07d00ULL, unwinder.frames()[11].sp);
+  EXPECT_EQ(0x7cbe0b5e18ULL, unwinder.frames()[12].pc);
+  EXPECT_EQ(0x7be4f07d20ULL, unwinder.frames()[12].sp);
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/libc.so b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/libc.so
new file mode 100644
index 0000000..cac1dd9
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/maps.txt b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/maps.txt
new file mode 100644
index 0000000..2c5ca62
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/maps.txt
@@ -0,0 +1,3 @@
+7be5e48000-7be6b2b000 r-xp 5000 00:00 0   test.apk
+7cbe030000-7cbe070000 r--p 0 00:00 0   libc.so
+7cbe070000-7cbe11a000 r-xp 40000 00:00 0   libc.so
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/regs.txt b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/regs.txt
new file mode 100644
index 0000000..090aeda
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/regs.txt
@@ -0,0 +1,33 @@
+x0: 7c326f6568
+x1: 80
+x2: 0
+x3: 0
+x4: 0
+x5: 0
+x6: 0
+x7: 7f7f7f7f7f7f7f7f
+x8: 62
+x9: 1
+x10: 1
+x11: 0
+x12: ffffffffc4653600
+x13: 17645696f
+x14: 2742ed97ca77a3
+x15: 3ab49084
+x16: 7be6b6bdb8
+x17: 7cbe0b14a0
+x18: 7c2b02a000
+x19: 0
+x20: 7c326f6568
+x21: 7be69c827c
+x22: 7be69c8272
+x23: 1
+x24: 7be74f7100
+x25: 881
+x26: 7be4f07a00
+x27: c479c000
+x28: 7be4f07998
+x29: 7be4f079b4
+sp: 7be4f077d0
+lr: 7be6715f60
+pc: 7cbe0b14bc
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/stack.data b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/stack.data
new file mode 100644
index 0000000..27d5bf3
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/test.apk b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/test.apk
new file mode 100644
index 0000000..70a9c71
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/test.apk
Binary files differ
diff --git a/libusbhost/Android.bp b/libusbhost/Android.bp
index 39bf3a5..fc6f305 100644
--- a/libusbhost/Android.bp
+++ b/libusbhost/Android.bp
@@ -20,7 +20,6 @@
     vndk: {
         enabled: true,
     },
-    double_loadable: true,
     host_supported: true,
     srcs: ["usbhost.c"],
     cflags: ["-Werror"],
diff --git a/libvndksupport/linker.c b/libvndksupport/linker.c
index 821940a..84c2132 100644
--- a/libvndksupport/linker.c
+++ b/libvndksupport/linker.c
@@ -20,6 +20,8 @@
 
 #define LOG_TAG "vndksupport"
 #include <log/log.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 __attribute__((weak)) extern struct android_namespace_t* android_get_exported_namespace(const char*);
 __attribute__((weak)) extern void* android_dlopen_ext(const char*, int, const android_dlextinfo*);
@@ -46,6 +48,11 @@
 }
 
 int android_is_in_vendor_process() {
+    // Special case init, since when init runs, ld.config.<ver>.txt hasn't been
+    // loaded (sysprop service isn't up for init to know <ver>).
+    if (getpid() == 1) {
+        return 0;
+    }
     if (android_get_exported_namespace == NULL) {
         ALOGD("android_get_exported_namespace() not available. Assuming system process.");
         return 0;
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 18421e8..2d3fbfc 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -110,7 +110,7 @@
  */
 #define PSI_WINDOW_SIZE_MS 1000
 /* Polling period after initial PSI signal */
-#define PSI_POLL_PERIOD_MS 200
+#define PSI_POLL_PERIOD_MS 40
 /* Poll for the duration of one window after initial PSI signal */
 #define PSI_POLL_COUNT (PSI_WINDOW_SIZE_MS / PSI_POLL_PERIOD_MS)
 
diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in
index 5d6cd2d..455c9a8 100644
--- a/rootdir/init.environ.rc.in
+++ b/rootdir/init.environ.rc.in
@@ -6,6 +6,7 @@
     export ANDROID_DATA /data
     export ANDROID_STORAGE /storage
     export ANDROID_RUNTIME_ROOT /apex/com.android.runtime
+    export ANDROID_TZDATA_ROOT /apex/com.android.tzdata
     export EXTERNAL_STORAGE /sdcard
     export ASEC_MOUNTPOINT /mnt/asec
     export BOOTCLASSPATH %BOOTCLASSPATH%
diff --git a/rootdir/init.rc b/rootdir/init.rc
index f2e7a7c..7cac972 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -389,6 +389,8 @@
     chmod 0700 /metadata/vold
     mkdir /metadata/password_slots 0771 root system
 
+    mkdir /metadata/apex 0700 root system
+    mkdir /metadata/apex/sessions 0700 root system
 on late-fs
     # Ensure that tracefs has the correct permissions.
     # This does not work correctly if it is called in post-fs.
@@ -586,7 +588,10 @@
     restorecon --recursive --skip-ce /data
 
     # load fsverity keys
-    exec -- /system/bin/mini-keyctl -c /product/etc/security/cacerts_fsverity,/vendor/etc/security/cacerts_fsverity -k .fs-verity
+    exec -- /system/bin/mini-keyctl dadd asymmetric product_cert /product/etc/security/cacerts_fsverity .fs-verity
+    exec -- /system/bin/mini-keyctl dadd asymmetric vendor_cert /vendor/etc/security/cacerts_fsverity .fs-verity
+    # Prevent future key links to fsverity keyring
+    exec -- /system/bin/mini-keyctl restrict_keyring .fs-verity
 
     # Check any timezone data in /data is newer than the copy in the runtime module, delete if not.
     exec - system system -- /system/bin/tzdatacheck /apex/com.android.runtime/etc/tz /data/misc/zoneinfo