Merge "fs_mgr: overlayfs: fs_mgr_overlay_setup true if already mounted"
diff --git a/base/mapped_file.cpp b/base/mapped_file.cpp
index f7901af..faa845d 100644
--- a/base/mapped_file.cpp
+++ b/base/mapped_file.cpp
@@ -16,6 +16,8 @@
 
 #include "android-base/mapped_file.h"
 
+#include <errno.h>
+
 namespace android {
 namespace base {
 
@@ -50,7 +52,14 @@
       new MappedFile{static_cast<char*>(base), length, slop, handle});
 #else
   void* base = mmap(nullptr, file_length, prot, MAP_SHARED, fd, file_offset);
-  if (base == MAP_FAILED) return nullptr;
+  if (base == MAP_FAILED) {
+    // http://b/119818070 "app crashes when reading asset of zero length".
+    // mmap fails with EINVAL for a zero length region.
+    if (errno == EINVAL && length == 0) {
+      return std::unique_ptr<MappedFile>(new MappedFile{nullptr, 0, 0});
+    }
+    return nullptr;
+  }
   return std::unique_ptr<MappedFile>(new MappedFile{static_cast<char*>(base), length, slop});
 #endif
 }
diff --git a/base/mapped_file_test.cpp b/base/mapped_file_test.cpp
index 7e89723..cfde73c 100644
--- a/base/mapped_file_test.cpp
+++ b/base/mapped_file_test.cpp
@@ -25,7 +25,6 @@
 #include <string>
 
 #include "android-base/file.h"
-#include "android-base/unique_fd.h"
 
 TEST(mapped_file, smoke) {
   TemporaryFile tf;
@@ -37,3 +36,13 @@
   ASSERT_EQ('l', m->data()[0]);
   ASSERT_EQ('o', m->data()[1]);
 }
+
+TEST(mapped_file, zero_length_mapping) {
+  // http://b/119818070 "app crashes when reading asset of zero length".
+  // mmap fails with EINVAL for a zero length region.
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+
+  auto m = android::base::MappedFile::FromFd(tf.fd, 4096, 0, PROT_READ);
+  ASSERT_EQ(0u, m->size());
+}
diff --git a/init/README.md b/init/README.md
index 3a7c71c..f0e5d55 100644
--- a/init/README.md
+++ b/init/README.md
@@ -161,11 +161,13 @@
 Options are modifiers to services.  They affect how and when init
 runs the service.
 
-`capabilities <capability> [ <capability>\* ]`
+`capabilities [ <capability>\* ]`
 > Set capabilities when exec'ing this service. 'capability' should be a Linux
   capability without the "CAP\_" prefix, like "NET\_ADMIN" or "SETPCAP". See
   http://man7.org/linux/man-pages/man7/capabilities.7.html for a list of Linux
   capabilities.
+  If no capabilities are provided, then all capabilities are removed from this service, even if it
+  runs as root.
 
 `class <name> [ <name>\* ]`
 > Specify class names for the service.  All services in a
diff --git a/init/service.cpp b/init/service.cpp
index d64f2f3..2186a85 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -218,12 +218,12 @@
 
 Service::Service(const std::string& name, Subcontext* subcontext_for_restart_commands,
                  const std::vector<std::string>& args)
-    : Service(name, 0, 0, 0, {}, 0, 0, "", subcontext_for_restart_commands, args) {}
+    : Service(name, 0, 0, 0, {}, 0, "", subcontext_for_restart_commands, args) {}
 
 Service::Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid,
-                 const std::vector<gid_t>& supp_gids, const CapSet& capabilities,
-                 unsigned namespace_flags, const std::string& seclabel,
-                 Subcontext* subcontext_for_restart_commands, const std::vector<std::string>& args)
+                 const std::vector<gid_t>& supp_gids, unsigned namespace_flags,
+                 const std::string& seclabel, Subcontext* subcontext_for_restart_commands,
+                 const std::vector<std::string>& args)
     : name_(name),
       classnames_({"default"}),
       flags_(flags),
@@ -232,7 +232,6 @@
       uid_(uid),
       gid_(gid),
       supp_gids_(supp_gids),
-      capabilities_(capabilities),
       namespace_flags_(namespace_flags),
       seclabel_(seclabel),
       onrestart_(false, subcontext_for_restart_commands, "<Service '" + name + "' onrestart>", 0,
@@ -289,7 +288,7 @@
         }
     }
     // Keep capabilites on uid change.
-    if (capabilities_.any() && uid_) {
+    if (capabilities_ && uid_) {
         // If Android is running in a container, some securebits might already
         // be locked, so don't change those.
         unsigned long securebits = prctl(PR_GET_SECUREBITS);
@@ -328,8 +327,8 @@
             PLOG(FATAL) << "setpriority failed for " << name_;
         }
     }
-    if (capabilities_.any()) {
-        if (!SetCapsForExec(capabilities_)) {
+    if (capabilities_) {
+        if (!SetCapsForExec(*capabilities_)) {
             LOG(FATAL) << "cannot set capabilities for " << name_;
         }
     } else if (uid_) {
@@ -420,7 +419,7 @@
     }
 
     unsigned int last_valid_cap = GetLastValidCap();
-    if (last_valid_cap >= capabilities_.size()) {
+    if (last_valid_cap >= capabilities_->size()) {
         LOG(WARNING) << "last valid run-time capability is larger than CAP_LAST_CAP";
     }
 
@@ -435,7 +434,7 @@
             return Error() << StringPrintf("capability '%s' not supported by the kernel",
                                            arg.c_str());
         }
-        capabilities_[cap] = true;
+        (*capabilities_)[cap] = true;
     }
     return Success();
 }
@@ -796,7 +795,7 @@
     // clang-format off
     static const Map option_parsers = {
         {"capabilities",
-                        {1,     kMax, &Service::ParseCapabilities}},
+                        {0,     kMax, &Service::ParseCapabilities}},
         {"class",       {1,     kMax, &Service::ParseClass}},
         {"console",     {0,     1,    &Service::ParseConsole}},
         {"critical",    {0,     0,    &Service::ParseCritical}},
@@ -1268,7 +1267,6 @@
     std::string name = "exec " + std::to_string(exec_count) + " (" + Join(str_args, " ") + ")";
 
     unsigned flags = SVC_ONESHOT | SVC_TEMPORARY;
-    CapSet no_capabilities;
     unsigned namespace_flags = 0;
 
     std::string seclabel = "";
@@ -1303,8 +1301,8 @@
         }
     }
 
-    return std::make_unique<Service>(name, flags, *uid, *gid, supp_gids, no_capabilities,
-                                     namespace_flags, seclabel, nullptr, str_args);
+    return std::make_unique<Service>(name, flags, *uid, *gid, supp_gids, namespace_flags, seclabel,
+                                     nullptr, str_args);
 }
 
 // Shutdown services in the opposite order that they were started.
diff --git a/init/service.h b/init/service.h
index c29723a..c42a5a3 100644
--- a/init/service.h
+++ b/init/service.h
@@ -68,9 +68,9 @@
             const std::vector<std::string>& args);
 
     Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid,
-            const std::vector<gid_t>& supp_gids, const CapSet& capabilities,
-            unsigned namespace_flags, const std::string& seclabel,
-            Subcontext* subcontext_for_restart_commands, const std::vector<std::string>& args);
+            const std::vector<gid_t>& supp_gids, unsigned namespace_flags,
+            const std::string& seclabel, Subcontext* subcontext_for_restart_commands,
+            const std::vector<std::string>& args);
 
     static std::unique_ptr<Service> MakeTemporaryOneshotService(const std::vector<std::string>& args);
 
@@ -192,7 +192,7 @@
     uid_t uid_;
     gid_t gid_;
     std::vector<gid_t> supp_gids_;
-    CapSet capabilities_;
+    std::optional<CapSet> capabilities_;
     unsigned namespace_flags_;
     // Pair of namespace type, path to namespace.
     std::vector<std::pair<int, std::string>> namespaces_to_enter_;
diff --git a/init/service_test.cpp b/init/service_test.cpp
index 194aa2b..4bfaa6b 100644
--- a/init/service_test.cpp
+++ b/init/service_test.cpp
@@ -57,7 +57,7 @@
     }
 
     Service* service_in_old_memory2 = new (old_memory) Service(
-        "test_old_memory", 0U, 0U, 0U, std::vector<gid_t>(), CapSet(), 0U, "", nullptr, dummy_args);
+            "test_old_memory", 0U, 0U, 0U, std::vector<gid_t>(), 0U, "", nullptr, dummy_args);
 
     EXPECT_EQ(0U, service_in_old_memory2->flags());
     EXPECT_EQ(0, service_in_old_memory2->pid());
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 0dbbc3f..fab4b4e 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -172,7 +172,10 @@
         }
     },
 
-    shared_libs: ["liblog"],
+    shared_libs: [
+        "liblog",
+        "libbase",
+    ],
     header_libs: [
         "libbase_headers",
         "libcutils_headers",
diff --git a/libcutils/ashmem-dev.cpp b/libcutils/ashmem-dev.cpp
index f65dc8b..e35b91a 100644
--- a/libcutils/ashmem-dev.cpp
+++ b/libcutils/ashmem-dev.cpp
@@ -29,17 +29,34 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <linux/ashmem.h>
+#include <linux/memfd.h>
+#include <log/log.h>
 #include <pthread.h>
+#include <stdio.h>
 #include <string.h>
 #include <sys/ioctl.h>
+#include <sys/mman.h>
 #include <sys/stat.h>
+#include <sys/syscall.h>
 #include <sys/sysmacros.h>
 #include <sys/types.h>
 #include <unistd.h>
-#include <log/log.h>
+
+#include <android-base/properties.h>
+#include <android-base/unique_fd.h>
 
 #define ASHMEM_DEVICE "/dev/ashmem"
 
+/* Will be added to UAPI once upstream change is merged */
+#define F_SEAL_FUTURE_WRITE 0x0010
+
+/*
+ * The minimum vendor API level at and after which it is safe to use memfd.
+ * This is to facilitate deprecation of ashmem.
+ */
+#define MIN_MEMFD_VENDOR_API_LEVEL 29
+#define MIN_MEMFD_VENDOR_API_LEVEL_CHAR 'Q'
+
 /* ashmem identity */
 static dev_t __ashmem_rdev;
 /*
@@ -72,6 +89,130 @@
 }
 #endif
 
+/*
+ * has_memfd_support() determines if the device can use memfd. memfd support
+ * has been there for long time, but certain things in it may be missing.  We
+ * check for needed support in it. Also we check if the VNDK version of
+ * libcutils being used is new enough, if its not, then we cannot use memfd
+ * since the older copies may be using ashmem so we just use ashmem. Once all
+ * Android devices that are getting updates are new enough (ex, they were
+ * originally shipped with Android release > P), then we can just use memfd and
+ * delete all ashmem code from libcutils (while preserving the interface).
+ *
+ * NOTE:
+ * The sys.use_memfd property is set by default to false in Android
+ * to temporarily disable memfd, till vendor and apps are ready for it.
+ * The main issue: either apps or vendor processes can directly make ashmem
+ * IOCTLs on FDs they receive by assuming they are ashmem, without going
+ * through libcutils. Such fds could have very well be originally created with
+ * libcutils hence they could be memfd. Thus the IOCTLs will break.
+ *
+ * Set default value of sys.use_memfd property to true once the issue is
+ * resolved, so that the code can then self-detect if kernel support is present
+ * on the device. The property can also set to true from adb shell, for
+ * debugging.
+ */
+
+static bool debug_log = false;            /* set to true for verbose logging and other debug  */
+static bool pin_deprecation_warn = true; /* Log the pin deprecation warning only once */
+
+/* Determine if vendor processes would be ok with memfd in the system:
+ *
+ * If VNDK is using older libcutils, don't use memfd. This is so that the
+ * same shared memory mechanism is used across binder transactions between
+ * vendor partition processes and system partition processes.
+ */
+static bool check_vendor_memfd_allowed() {
+    std::string vndk_version = android::base::GetProperty("ro.vndk.version", "");
+
+    if (vndk_version == "") {
+        ALOGE("memfd: ro.vndk.version not defined or invalid (%s), this is mandated since P.\n",
+              vndk_version.c_str());
+        return false;
+    }
+
+    /* No issues if vendor is targetting current Dessert */
+    if (vndk_version == "current") {
+        return false;
+    }
+
+    /* Check if VNDK version is a number and act on it */
+    char* p;
+    long int vers = strtol(vndk_version.c_str(), &p, 10);
+    if (*p == 0) {
+        if (vers < MIN_MEMFD_VENDOR_API_LEVEL) {
+            ALOGI("memfd: device VNDK version (%s) is < Q so using ashmem.\n",
+                  vndk_version.c_str());
+            return false;
+        }
+
+        return true;
+    }
+
+    /* If its not a number, assume string, but check if its a sane string */
+    if (tolower(vndk_version[0]) < 'a' || tolower(vndk_version[0]) > 'z') {
+        ALOGE("memfd: ro.vndk.version not defined or invalid (%s), this is mandated since P.\n",
+              vndk_version.c_str());
+        return false;
+    }
+
+    if (tolower(vndk_version[0]) < tolower(MIN_MEMFD_VENDOR_API_LEVEL_CHAR)) {
+        ALOGI("memfd: device is using VNDK version (%s) which is less than Q. Use ashmem only.\n",
+              vndk_version.c_str());
+        return false;
+    }
+
+    return true;
+}
+
+
+/* Determine if memfd can be supported. This is just one-time hardwork
+ * which will be cached by the caller.
+ */
+static bool __has_memfd_support() {
+    if (check_vendor_memfd_allowed() == false) {
+        return false;
+    }
+
+    /* Used to turn on/off the detection at runtime, in the future this
+     * property will be removed once we switch everything over to ashmem.
+     * Currently it is used only for debugging to switch the system over.
+     */
+    if (!android::base::GetBoolProperty("sys.use_memfd", false)) {
+        if (debug_log) {
+            ALOGD("sys.use_memfd=false so memfd disabled\n");
+        }
+        return false;
+    }
+
+    /* Check if kernel support exists, otherwise fall back to ashmem */
+    android::base::unique_fd fd(
+            syscall(__NR_memfd_create, "test_android_memfd", MFD_ALLOW_SEALING));
+    if (fd == -1) {
+        ALOGE("memfd_create failed: %s, no memfd support.\n", strerror(errno));
+        return false;
+    }
+
+    if (fcntl(fd, F_ADD_SEALS, F_SEAL_FUTURE_WRITE) == -1) {
+        ALOGE("fcntl(F_ADD_SEALS) failed: %s, no memfd support.\n", strerror(errno));
+        return false;
+    }
+
+    if (debug_log) {
+        ALOGD("memfd: device has memfd support, using it\n");
+    }
+    return true;
+}
+
+static bool has_memfd_support() {
+    /* memfd_supported is the initial global per-process state of what is known
+     * about memfd.
+     */
+    static bool memfd_supported = __has_memfd_support();
+
+    return memfd_supported;
+}
+
 /* logistics of getting file descriptor for ashmem */
 static int __ashmem_open_locked()
 {
@@ -177,11 +318,49 @@
     return result;
 }
 
+static bool memfd_is_ashmem(int fd) {
+    static bool fd_check_error_once = false;
+
+    if (__ashmem_is_ashmem(fd, 0) == 0) {
+        if (!fd_check_error_once) {
+            ALOGE("memfd: memfd expected but ashmem fd used - please use libcutils.\n");
+            fd_check_error_once = true;
+        }
+
+        return true;
+    }
+
+    return false;
+}
+
 int ashmem_valid(int fd)
 {
+    if (has_memfd_support() && !memfd_is_ashmem(fd)) {
+        return 1;
+    }
+
     return __ashmem_is_ashmem(fd, 0) >= 0;
 }
 
+static int memfd_create_region(const char* name, size_t size) {
+    android::base::unique_fd fd(syscall(__NR_memfd_create, name, MFD_ALLOW_SEALING));
+
+    if (fd == -1) {
+        ALOGE("memfd_create(%s, %zd) failed: %s\n", name, size, strerror(errno));
+        return -1;
+    }
+
+    if (ftruncate(fd, size) == -1) {
+        ALOGE("ftruncate(%s, %zd) failed for memfd creation: %s\n", name, size, strerror(errno));
+        return -1;
+    }
+
+    if (debug_log) {
+        ALOGE("memfd_create(%s, %zd) success. fd=%d\n", name, size, fd.get());
+    }
+    return fd.release();
+}
+
 /*
  * ashmem_create_region - creates a new ashmem region and returns the file
  * descriptor, or <0 on error
@@ -193,6 +372,10 @@
 {
     int ret, save_errno;
 
+    if (has_memfd_support()) {
+        return memfd_create_region(name ? name : "none", size);
+    }
+
     int fd = __ashmem_open();
     if (fd < 0) {
         return fd;
@@ -222,28 +405,78 @@
     return ret;
 }
 
+static int memfd_set_prot_region(int fd, int prot) {
+    /* Only proceed if an fd needs to be write-protected */
+    if (prot & PROT_WRITE) {
+        return 0;
+    }
+
+    if (fcntl(fd, F_ADD_SEALS, F_SEAL_FUTURE_WRITE) == -1) {
+        ALOGE("memfd_set_prot_region(%d, %d): F_SEAL_FUTURE_WRITE seal failed: %s\n", fd, prot,
+              strerror(errno));
+        return -1;
+    }
+
+    return 0;
+}
+
 int ashmem_set_prot_region(int fd, int prot)
 {
+    if (has_memfd_support() && !memfd_is_ashmem(fd)) {
+        return memfd_set_prot_region(fd, prot);
+    }
+
     return __ashmem_check_failure(fd, TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_PROT_MASK, prot)));
 }
 
 int ashmem_pin_region(int fd, size_t offset, size_t len)
 {
+    if (!pin_deprecation_warn || debug_log) {
+        ALOGE("Pinning is deprecated since Android Q. Please use trim or other methods.\n");
+        pin_deprecation_warn = true;
+    }
+
+    if (has_memfd_support() && !memfd_is_ashmem(fd)) {
+        return 0;
+    }
+
     // TODO: should LP64 reject too-large offset/len?
     ashmem_pin pin = { static_cast<uint32_t>(offset), static_cast<uint32_t>(len) };
-
     return __ashmem_check_failure(fd, TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_PIN, &pin)));
 }
 
 int ashmem_unpin_region(int fd, size_t offset, size_t len)
 {
+    if (!pin_deprecation_warn || debug_log) {
+        ALOGE("Pinning is deprecated since Android Q. Please use trim or other methods.\n");
+        pin_deprecation_warn = true;
+    }
+
+    if (has_memfd_support() && !memfd_is_ashmem(fd)) {
+        return 0;
+    }
+
     // TODO: should LP64 reject too-large offset/len?
     ashmem_pin pin = { static_cast<uint32_t>(offset), static_cast<uint32_t>(len) };
-
     return __ashmem_check_failure(fd, TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_UNPIN, &pin)));
 }
 
 int ashmem_get_size_region(int fd)
 {
+    if (has_memfd_support() && !memfd_is_ashmem(fd)) {
+        struct stat sb;
+
+        if (fstat(fd, &sb) == -1) {
+            ALOGE("ashmem_get_size_region(%d): fstat failed: %s\n", fd, strerror(errno));
+            return -1;
+        }
+
+        if (debug_log) {
+            ALOGD("ashmem_get_size_region(%d): %d\n", fd, static_cast<int>(sb.st_size));
+        }
+
+        return sb.st_size;
+    }
+
     return __ashmem_check_failure(fd, TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_GET_SIZE, NULL)));
 }
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index 59cbbc5..c95868d 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -88,6 +88,9 @@
     { 00755, AID_ROOT,         AID_ROOT,         0, "system/etc/ppp" },
     { 00755, AID_ROOT,         AID_SHELL,        0, "system/vendor" },
     { 00751, AID_ROOT,         AID_SHELL,        0, "system/xbin" },
+    // TODO(b/123743953): eliminate the APEX name with better pattern matching
+    { 00755, AID_ROOT,         AID_SHELL,        0, "system/apex/com.android.runtime.debug/bin" },
+    { 00755, AID_ROOT,         AID_SHELL,        0, "system/apex/com.android.runtime.release/bin" },
     { 00751, AID_ROOT,         AID_SHELL,        0, "vendor/bin" },
     { 00755, AID_ROOT,         AID_SHELL,        0, "vendor" },
     { 00755, AID_ROOT,         AID_ROOT,         0, 0 },
@@ -214,6 +217,9 @@
     { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib/valgrind/*" },
     { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib64/valgrind/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/xbin/*" },
+    // TODO(b/123743953): eliminate the APEX name with better pattern matching
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system/apex/com.android.runtime.debug/bin/*" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system/apex/com.android.runtime.release/bin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/bin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/xbin/*" },
     { 00644, AID_ROOT,      AID_ROOT,      0, 0 },
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index a4e00bd..5394d7e 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -118,7 +118,16 @@
 
 static constexpr const char* kRuntimeNamespaceName = "runtime";
 
+// classloader-namespace is a linker namespace that is created for the loaded
+// app. To be specific, it is created for the app classloader. When
+// System.load() is called from a Java class that is loaded from the
+// classloader, the classloader-namespace namespace associated with that
+// classloader is selected for dlopen. The namespace is configured so that its
+// search path is set to the app-local JNI directory and it is linked to the
+// default namespace with the names of libs listed in the public.libraries.txt.
+// This way an app can only load its own JNI libraries along with the public libs.
 static constexpr const char* kClassloaderNamespaceName = "classloader-namespace";
+// Same thing for vendor APKs.
 static constexpr const char* kVendorClassloaderNamespaceName = "vendor-classloader-namespace";
 
 // (http://b/27588281) This is a workaround for apps using custom classloaders and calling
diff --git a/libpixelflinger/tests/Android.bp b/libpixelflinger/tests/Android.bp
index 820a84d..e20dd93 100644
--- a/libpixelflinger/tests/Android.bp
+++ b/libpixelflinger/tests/Android.bp
@@ -8,6 +8,7 @@
 
     header_libs: ["libpixelflinger_internal"],
     static_libs: [
+        "libbase",
         "libcutils",
         "liblog",
         "libpixelflinger",
diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp
index 12cfb7e..cd8ef94 100644
--- a/libprocessgroup/cgroup_map.cpp
+++ b/libprocessgroup/cgroup_map.cpp
@@ -19,6 +19,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <grp.h>
 #include <pwd.h>
 #include <sys/mman.h>
 #include <sys/mount.h>
@@ -72,26 +73,28 @@
         }
     }
 
-    passwd* uid_pwd = nullptr;
-    passwd* gid_pwd = nullptr;
-
-    if (!uid.empty()) {
-        uid_pwd = getpwnam(uid.c_str());
-        if (!uid_pwd) {
-            PLOG(ERROR) << "Unable to decode UID for '" << uid << "'";
-            return false;
-        }
-
-        if (!gid.empty()) {
-            gid_pwd = getpwnam(gid.c_str());
-            if (!gid_pwd) {
-                PLOG(ERROR) << "Unable to decode GID for '" << gid << "'";
-                return false;
-            }
-        }
+    if (uid.empty()) {
+        return true;
     }
 
-    if (uid_pwd && lchown(path.c_str(), uid_pwd->pw_uid, gid_pwd ? gid_pwd->pw_uid : -1) < 0) {
+    passwd* uid_pwd = getpwnam(uid.c_str());
+    if (!uid_pwd) {
+        PLOG(ERROR) << "Unable to decode UID for '" << uid << "'";
+        return false;
+    }
+
+    uid_t pw_uid = uid_pwd->pw_uid;
+    gid_t gr_gid = -1;
+    if (!gid.empty()) {
+        group* gid_pwd = getgrnam(gid.c_str());
+        if (!gid_pwd) {
+            PLOG(ERROR) << "Unable to decode GID for '" << gid << "'";
+            return false;
+        }
+        gr_gid = gid_pwd->gr_gid;
+    }
+
+    if (lchown(path.c_str(), pw_uid, gr_gid) < 0) {
         PLOG(ERROR) << "lchown() failed for " << path;
         return false;
     }
@@ -128,7 +131,8 @@
         std::string name = cgroups[i]["Controller"].asString();
         descriptors->emplace(std::make_pair(
                 name,
-                CgroupDescriptor(1, name, cgroups[i]["Path"].asString(), cgroups[i]["Mode"].asInt(),
+                CgroupDescriptor(1, name, cgroups[i]["Path"].asString(),
+                                 std::strtoul(cgroups[i]["Mode"].asString().c_str(), 0, 8),
                                  cgroups[i]["UID"].asString(), cgroups[i]["GID"].asString())));
     }
 
@@ -136,8 +140,8 @@
     descriptors->emplace(std::make_pair(
             CGROUPV2_CONTROLLER_NAME,
             CgroupDescriptor(2, CGROUPV2_CONTROLLER_NAME, cgroups2["Path"].asString(),
-                             cgroups2["Mode"].asInt(), cgroups2["UID"].asString(),
-                             cgroups2["GID"].asString())));
+                             std::strtoul(cgroups2["Mode"].asString().c_str(), 0, 8),
+                             cgroups2["UID"].asString(), cgroups2["GID"].asString())));
 
     return true;
 }
diff --git a/libutils/FileMap.cpp b/libutils/FileMap.cpp
index 5feb2aa..1202c15 100644
--- a/libutils/FileMap.cpp
+++ b/libutils/FileMap.cpp
@@ -174,12 +174,6 @@
         return false;
     }
 #else // !defined(__MINGW32__)
-    int     prot, flags, adjust;
-    off64_t adjOffset;
-    size_t  adjLength;
-
-    void* ptr;
-
     assert(fd >= 0);
     assert(offset >= 0);
     assert(length > 0);
@@ -193,20 +187,23 @@
         }
     }
 
-    adjust = offset % mPageSize;
-    adjOffset = offset - adjust;
-    adjLength = length + adjust;
+    int adjust = offset % mPageSize;
+    off64_t adjOffset = offset - adjust;
+    size_t adjLength = length + adjust;
 
-    flags = MAP_SHARED;
-    prot = PROT_READ;
-    if (!readOnly)
-        prot |= PROT_WRITE;
+    int flags = MAP_SHARED;
+    int prot = PROT_READ;
+    if (!readOnly) prot |= PROT_WRITE;
 
-    ptr = mmap(nullptr, adjLength, prot, flags, fd, adjOffset);
+    void* ptr = mmap(nullptr, adjLength, prot, flags, fd, adjOffset);
     if (ptr == MAP_FAILED) {
-        ALOGE("mmap(%lld,%zu) failed: %s\n",
-            (long long)adjOffset, adjLength, strerror(errno));
-        return false;
+        if (errno == EINVAL && length == 0) {
+            ptr = nullptr;
+            adjust = 0;
+        } else {
+            ALOGE("mmap(%lld,%zu) failed: %s\n", (long long)adjOffset, adjLength, strerror(errno));
+            return false;
+        }
     }
     mBasePtr = ptr;
 #endif // !defined(__MINGW32__)
@@ -217,8 +214,6 @@
     mDataPtr = (char*) mBasePtr + adjust;
     mDataLength = length;
 
-    assert(mBasePtr != NULL);
-
     ALOGV("MAP: base %p/%zu data %p/%zu\n",
         mBasePtr, mBaseLength, mDataPtr, mDataLength);
 
diff --git a/libutils/tests/Android.bp b/libutils/tests/Android.bp
index 1390552..62f5acb 100644
--- a/libutils/tests/Android.bp
+++ b/libutils/tests/Android.bp
@@ -22,6 +22,7 @@
 
     srcs: [
         "BitSet_test.cpp",
+        "FileMap_test.cpp",
         "LruCache_test.cpp",
         "Mutex_test.cpp",
         "Singleton_test.cpp",
diff --git a/libutils/tests/FileMap_test.cpp b/libutils/tests/FileMap_test.cpp
new file mode 100644
index 0000000..576d89b
--- /dev/null
+++ b/libutils/tests/FileMap_test.cpp
@@ -0,0 +1,34 @@
+/*
+ * 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/FileMap.h"
+
+#include <gtest/gtest.h>
+
+#include "android-base/file.h"
+
+TEST(FileMap, zero_length_mapping) {
+    // http://b/119818070 "app crashes when reading asset of zero length".
+    // mmap fails with EINVAL for a zero length region.
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+
+    android::FileMap m;
+    ASSERT_TRUE(m.create("test", tf.fd, 4096, 0, true));
+    ASSERT_STREQ("test", m.getFileName());
+    ASSERT_EQ(0u, m.getDataLength());
+    ASSERT_EQ(4096, m.getDataOffset());
+}
diff --git a/rootdir/cgroups.json b/rootdir/cgroups.json
index 6eb88c9..aa71956 100644
--- a/rootdir/cgroups.json
+++ b/rootdir/cgroups.json
@@ -3,40 +3,40 @@
     {
       "Controller": "cpu",
       "Path": "/dev/cpuctl",
-      "Mode": 0755,
+      "Mode": "0755",
       "UID": "system",
       "GID": "system"
     },
     {
       "Controller": "cpuacct",
       "Path": "/acct",
-      "Mode": 0555
+      "Mode": "0555"
     },
     {
       "Controller": "cpuset",
       "Path": "/dev/cpuset",
-      "Mode": 0755,
+      "Mode": "0755",
       "UID": "system",
       "GID": "system"
     },
     {
       "Controller": "memory",
       "Path": "/dev/memcg",
-      "Mode": 0700,
+      "Mode": "0700",
       "UID": "root",
       "GID": "system"
     },
     {
       "Controller": "schedtune",
       "Path": "/dev/stune",
-      "Mode": 0755,
+      "Mode": "0755",
       "UID": "system",
       "GID": "system"
     }
   ],
   "Cgroups2": {
     "Path": "/dev/cg2_bpf",
-    "Mode": 0600,
+    "Mode": "0600",
     "UID": "root",
     "GID": "root"
   }
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 59ed47a..370bc1c 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -593,6 +593,11 @@
     # Set indication (checked by vold) that we have finished this action
     #setprop vold.post_fs_data_done 1
 
+    # sys.memfd_use set to false by default, which keeps it disabled
+    # until it is confirmed that apps and vendor processes don't make
+    # IOCTLs on ashmem fds any more.
+    setprop sys.use_memfd false
+
 # It is recommended to put unnecessary data/ initialization from post-fs-data
 # to start-zygote in device's init.rc to unblock zygote start.
 on zygote-start && property:ro.crypto.state=unencrypted