Merge "Add C++ thread annotations support to core." into nyc-dev
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index ee56a5e..d5a7e06 100644
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -86,18 +86,34 @@
 libbacktrace_offline_src_files := \
 	BacktraceOffline.cpp \
 
+# Use shared llvm library on device to save space.
 libbacktrace_offline_shared_libraries := \
 	libbacktrace \
+	libbase \
 	liblog \
 	libunwind \
-
-# Use shared llvm library on device to save space.
-libbacktrace_offline_shared_libraries_target := \
+	libutils \
 	libLLVM \
 
+libbacktrace_offline_static_libraries := \
+	libziparchive \
+	libz \
+
+module := libbacktrace_offline
+build_type := target
+build_target := SHARED_LIBRARY
+include $(LOCAL_PATH)/Android.build.mk
+
+libbacktrace_offline_shared_libraries := \
+	libbacktrace \
+	libbase \
+	liblog \
+	libunwind \
+	libziparchive-host \
+
 # Use static llvm libraries on host to remove dependency on 32-bit llvm shared library
 # which is not included in the prebuilt.
-libbacktrace_offline_static_libraries_host := \
+libbacktrace_offline_static_libraries := \
 	libLLVMObject \
 	libLLVMBitReader \
 	libLLVMMC \
@@ -106,10 +122,6 @@
 	libLLVMSupport \
 
 module := libbacktrace_offline
-module_tag := optional
-build_type := target
-build_target := SHARED_LIBRARY
-include $(LOCAL_PATH)/Android.build.mk
 build_type := host
 libbacktrace_multilib := both
 include $(LOCAL_PATH)/Android.build.mk
diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp
index dc3ed67..9a4f622 100644
--- a/libbacktrace/BacktraceOffline.cpp
+++ b/libbacktrace/BacktraceOffline.cpp
@@ -29,11 +29,14 @@
 #include <ucontext.h>
 #include <unistd.h>
 
+#include <memory>
 #include <string>
 #include <vector>
 
+#include <android-base/file.h>
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
+#include <ziparchive/zip_archive.h>
 
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wunused-parameter"
@@ -641,15 +644,103 @@
   return memcmp(buf, elf_magic, 4) == 0;
 }
 
+static bool IsValidApkPath(const std::string& apk_path) {
+  static const char zip_preamble[] = {0x50, 0x4b, 0x03, 0x04};
+  struct stat st;
+  if (stat(apk_path.c_str(), &st) != 0 || !S_ISREG(st.st_mode)) {
+    return false;
+  }
+  FILE* fp = fopen(apk_path.c_str(), "reb");
+  if (fp == nullptr) {
+    return false;
+  }
+  char buf[4];
+  if (fread(buf, 4, 1, fp) != 1) {
+    fclose(fp);
+    return false;
+  }
+  fclose(fp);
+  return memcmp(buf, zip_preamble, 4) == 0;
+}
+
+class ScopedZiparchiveHandle {
+ public:
+  ScopedZiparchiveHandle(ZipArchiveHandle handle) : handle_(handle) {
+  }
+
+  ~ScopedZiparchiveHandle() {
+    CloseArchive(handle_);
+  }
+
+ private:
+  ZipArchiveHandle handle_;
+};
+
+llvm::object::OwningBinary<llvm::object::Binary> OpenEmbeddedElfFile(const std::string& filename) {
+  llvm::object::OwningBinary<llvm::object::Binary> nothing;
+  size_t pos = filename.find("!/");
+  if (pos == std::string::npos) {
+    return nothing;
+  }
+  std::string apk_file = filename.substr(0, pos);
+  std::string elf_file = filename.substr(pos + 2);
+  if (!IsValidApkPath(apk_file)) {
+    BACK_LOGW("%s is not a valid apk file", apk_file.c_str());
+    return nothing;
+  }
+  ZipArchiveHandle handle;
+  int32_t ret_code = OpenArchive(apk_file.c_str(), &handle);
+  if (ret_code != 0) {
+    CloseArchive(handle);
+    BACK_LOGW("failed to open archive %s: %s", apk_file.c_str(), ErrorCodeString(ret_code));
+    return nothing;
+  }
+  ScopedZiparchiveHandle scoped_handle(handle);
+  ZipEntry zentry;
+  ret_code = FindEntry(handle, ZipString(elf_file.c_str()), &zentry);
+  if (ret_code != 0) {
+    BACK_LOGW("failed to find %s in %s: %s", elf_file.c_str(), apk_file.c_str(),
+              ErrorCodeString(ret_code));
+    return nothing;
+  }
+  if (zentry.method != kCompressStored || zentry.compressed_length != zentry.uncompressed_length) {
+    BACK_LOGW("%s is compressed in %s, which doesn't support running directly", elf_file.c_str(),
+              apk_file.c_str());
+    return nothing;
+  }
+  auto buffer_or_err = llvm::MemoryBuffer::getOpenFileSlice(GetFileDescriptor(handle), apk_file,
+                                                            zentry.uncompressed_length,
+                                                            zentry.offset);
+  if (!buffer_or_err) {
+    BACK_LOGW("failed to read %s in %s: %s", elf_file.c_str(), apk_file.c_str(),
+              buffer_or_err.getError().message().c_str());
+    return nothing;
+  }
+  auto binary_or_err = llvm::object::createBinary(buffer_or_err.get()->getMemBufferRef());
+  if (!binary_or_err) {
+    BACK_LOGW("failed to create binary for %s in %s: %s", elf_file.c_str(), apk_file.c_str(),
+              binary_or_err.getError().message().c_str());
+    return nothing;
+  }
+  return llvm::object::OwningBinary<llvm::object::Binary>(std::move(binary_or_err.get()),
+                                                          std::move(buffer_or_err.get()));
+}
+
 static DebugFrameInfo* ReadDebugFrameFromFile(const std::string& filename) {
-  if (!IsValidElfPath(filename)) {
-    return nullptr;
+  llvm::object::OwningBinary<llvm::object::Binary> owning_binary;
+  if (filename.find("!/") != std::string::npos) {
+    owning_binary = OpenEmbeddedElfFile(filename);
+  } else {
+    if (!IsValidElfPath(filename)) {
+      return nullptr;
+    }
+    auto binary_or_err = llvm::object::createBinary(llvm::StringRef(filename));
+    if (!binary_or_err) {
+      return nullptr;
+    }
+    owning_binary = std::move(binary_or_err.get());
   }
-  auto owning_binary = llvm::object::createBinary(llvm::StringRef(filename));
-  if (owning_binary.getError()) {
-    return nullptr;
-  }
-  llvm::object::Binary* binary = owning_binary.get().getBinary();
+  llvm::object::Binary* binary = owning_binary.getBinary();
   auto obj = llvm::dyn_cast<llvm::object::ObjectFile>(binary);
   if (obj == nullptr) {
     return nullptr;
diff --git a/liblog/logd_writer.c b/liblog/logd_writer.c
index 696237d..059f170 100644
--- a/liblog/logd_writer.c
+++ b/liblog/logd_writer.c
@@ -105,12 +105,6 @@
     if (logId > LOG_ID_SECURITY) {
         return -EINVAL;
     }
-    if (logId == LOG_ID_SECURITY) {
-        uid_t uid = __android_log_uid();
-        if ((uid != AID_LOG) && (uid != AID_ROOT) && (uid != AID_SYSTEM)) {
-            return -EPERM;
-        }
-    }
     if (logdLoggerWrite.context.sock < 0) {
         if (access("/dev/socket/logdw", W_OK) == 0) {
             return 0;
diff --git a/liblog/logger.h b/liblog/logger.h
index 61bc396..5d031d7 100644
--- a/liblog/logger.h
+++ b/liblog/logger.h
@@ -40,6 +40,7 @@
 struct android_log_transport_write {
   struct listnode node;
   const char *name;
+  unsigned logMask; /* cache of available success */
   union android_log_context context; /* Initialized by static allocation */
 
   int (*available)(log_id_t logId);
diff --git a/liblog/logger_read.c b/liblog/logger_read.c
index f15c7cd..0d6ba08 100644
--- a/liblog/logger_read.c
+++ b/liblog/logger_read.c
@@ -26,6 +26,7 @@
 #include <cutils/list.h>
 #include <log/log.h>
 #include <log/logger.h>
+#include <private/android_filesystem_config.h>
 
 #include "config_read.h"
 #include "log_portability.h"
@@ -91,6 +92,10 @@
         logger_for_each(logger, logger_list) {
             log_id_t logId = logger->logId;
 
+            if ((logId == LOG_ID_SECURITY) &&
+                    (__android_log_uid() != AID_SYSTEM)) {
+                continue;
+            }
             if (transport->read &&
                     (!transport->available ||
                         (transport->available(logId) >= 0))) {
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index a4155e9..b802ed7 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -49,20 +49,85 @@
     kLogUninitialized, kLogNotAvailable, kLogAvailable
 } g_log_status = kLogUninitialized;
 
+static int check_log_uid_permissions()
+{
+#if defined(__BIONIC__)
+    uid_t uid = __android_log_uid();
+
+    /* Matches clientHasLogCredentials() in logd */
+    if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
+        uid = geteuid();
+        if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
+            gid_t gid = getgid();
+            if ((gid != AID_SYSTEM) &&
+                    (gid != AID_ROOT) &&
+                    (gid != AID_LOG)) {
+                gid = getegid();
+                if ((gid != AID_SYSTEM) &&
+                        (gid != AID_ROOT) &&
+                        (gid != AID_LOG)) {
+                    int num_groups;
+                    gid_t *groups;
+
+                    num_groups = getgroups(0, NULL);
+                    if (num_groups <= 0) {
+                        return -EPERM;
+                    }
+                    groups = calloc(num_groups, sizeof(gid_t));
+                    if (!groups) {
+                        return -ENOMEM;
+                    }
+                    num_groups = getgroups(num_groups, groups);
+                    while (num_groups > 0) {
+                        if (groups[num_groups - 1] == AID_LOG) {
+                            break;
+                        }
+                        --num_groups;
+                    }
+                    free(groups);
+                    if (num_groups <= 0) {
+                        return -EPERM;
+                    }
+                }
+            }
+        }
+    }
+#endif
+    return 0;
+}
+
+static void __android_log_cache_available(
+        struct android_log_transport_write *node)
+{
+    size_t i;
+
+    if (node->logMask) {
+        return;
+    }
+
+    for (i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
+        if (node->write &&
+                (i != LOG_ID_KERNEL) &&
+                ((i != LOG_ID_SECURITY) ||
+                    (check_log_uid_permissions() == 0)) &&
+                (!node->available || ((*node->available)(i) >= 0))) {
+            node->logMask |= 1 << i;
+        }
+    }
+}
+
 LIBLOG_ABI_PUBLIC int __android_log_dev_available()
 {
     struct android_log_transport_write *node;
-    size_t i;
 
     if (list_empty(&__android_log_transport_write)) {
         return kLogUninitialized;
     }
-    for (i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
-        write_transport_for_each(node, &__android_log_transport_write) {
-            if (node->write &&
-                    (!node->available || ((*node->available)(i) >= 0))) {
-                return kLogAvailable;
-            }
+
+    write_transport_for_each(node, &__android_log_transport_write) {
+        __android_log_cache_available(node);
+        if (node->logMask) {
+            return kLogAvailable;
         }
     }
     return kLogNotAvailable;
@@ -77,6 +142,11 @@
 
     __android_log_config_write();
     write_transport_for_each_safe(transport, n, &__android_log_transport_write) {
+        __android_log_cache_available(transport);
+        if (!transport->logMask) {
+            list_remove(&transport->node);
+            continue;
+        }
         if (!transport->open || ((*transport->open)() < 0)) {
             if (transport->close) {
                 (*transport->close)();
@@ -87,6 +157,11 @@
         ++ret;
     }
     write_transport_for_each_safe(transport, n, &__android_log_persist_write) {
+        __android_log_cache_available(transport);
+        if (!transport->logMask) {
+            list_remove(&transport->node);
+            continue;
+        }
         if (!transport->open || ((*transport->open)() < 0)) {
             if (transport->close) {
                 (*transport->close)();
@@ -127,50 +202,13 @@
 
 #if defined(__BIONIC__)
     if (log_id == LOG_ID_SECURITY) {
-        uid_t uid;
-
         if (vec[0].iov_len < 4) {
             return -EINVAL;
         }
 
-        uid = __android_log_uid();
-        /* Matches clientHasLogCredentials() in logd */
-        if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
-            uid = geteuid();
-            if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
-                gid_t gid = getgid();
-                if ((gid != AID_SYSTEM) &&
-                        (gid != AID_ROOT) &&
-                        (gid != AID_LOG)) {
-                    gid = getegid();
-                    if ((gid != AID_SYSTEM) &&
-                            (gid != AID_ROOT) &&
-                            (gid != AID_LOG)) {
-                        int num_groups;
-                        gid_t *groups;
-
-                        num_groups = getgroups(0, NULL);
-                        if (num_groups <= 0) {
-                            return -EPERM;
-                        }
-                        groups = calloc(num_groups, sizeof(gid_t));
-                        if (!groups) {
-                            return -ENOMEM;
-                        }
-                        num_groups = getgroups(num_groups, groups);
-                        while (num_groups > 0) {
-                            if (groups[num_groups - 1] == AID_LOG) {
-                                break;
-                            }
-                            --num_groups;
-                        }
-                        free(groups);
-                        if (num_groups <= 0) {
-                            return -EPERM;
-                        }
-                    }
-                }
-            }
+        ret = check_log_uid_permissions();
+        if (ret < 0) {
+            return ret;
         }
         if (!__android_log_security()) {
             /* If only we could reset downstream logd counter */
@@ -262,8 +300,9 @@
 #endif
 
     ret = 0;
+    i = 1 << log_id;
     write_transport_for_each(node, &__android_log_transport_write) {
-        if (node->write) {
+        if (node->logMask & i) {
             ssize_t retval;
             retval = (*node->write)(log_id, &ts, vec, nr);
             if (ret >= 0) {
@@ -273,7 +312,7 @@
     }
 
     write_transport_for_each(node, &__android_log_persist_write) {
-        if (node->write) {
+        if (node->logMask & i) {
             (void)(*node->write)(log_id, &ts, vec, nr);
         }
     }
@@ -343,12 +382,12 @@
     }
 #endif
 
-    vec[0].iov_base   = (unsigned char *) &prio;
-    vec[0].iov_len    = 1;
-    vec[1].iov_base   = (void *) tag;
-    vec[1].iov_len    = strlen(tag) + 1;
-    vec[2].iov_base   = (void *) msg;
-    vec[2].iov_len    = strlen(msg) + 1;
+    vec[0].iov_base = (unsigned char *)&prio;
+    vec[0].iov_len  = 1;
+    vec[1].iov_base = (void *)tag;
+    vec[1].iov_len  = strlen(tag) + 1;
+    vec[2].iov_base = (void *)msg;
+    vec[2].iov_len  = strlen(msg) + 1;
 
     return write_to_log(bufID, vec, 3);
 }
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index e6b37ed..ec7a941 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -21,6 +21,7 @@
 #ifdef __ANDROID__
 #include <android/dlext.h>
 #include "cutils/properties.h"
+#define LOG_TAG "libnativeloader"
 #include "log/log.h"
 #endif
 
@@ -38,6 +39,10 @@
 #if defined(__ANDROID__)
 static constexpr const char* kPublicNativeLibrariesConfig = "/system/etc/public.libraries.txt";
 
+static bool namespace_workaround_enabled(int32_t target_sdk_version) {
+  return target_sdk_version <= 23;
+}
+
 class LibraryNamespaces {
  public:
   LibraryNamespaces() : initialized_(false) { }
@@ -54,6 +59,14 @@
     if (java_permitted_path != nullptr) {
       ScopedUtfChars path(env, java_permitted_path);
       permitted_path = path.c_str();
+    } else {
+      // (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.
+      //
+      // This part effectively allows such a classloader to access anything
+      // under /data
+      permitted_path = "/data";
     }
 
     if (!initialized_ && !InitPublicNamespace(library_path.c_str(), target_sdk_version)) {
@@ -74,7 +87,7 @@
                                   nullptr,
                                   library_path.c_str(),
                                   namespace_type,
-                                  java_permitted_path != nullptr ?
+                                  !permitted_path.empty() ?
                                       permitted_path.c_str() :
                                       nullptr);
 
@@ -128,7 +141,7 @@
 
     // TODO (dimitry): This is a workaround for http://b/26436837
     // will be removed before the release.
-    if (target_sdk_version <= 23) {
+    if (namespace_workaround_enabled(target_sdk_version)) {
       // check if libart.so is loaded.
       void* handle = dlopen("libart.so", RTLD_NOW | RTLD_NOLOAD);
       if (handle != nullptr) {
diff --git a/mkbootimg/mkbootimg b/mkbootimg/mkbootimg
index 7b04bcc..5a13da2 100755
--- a/mkbootimg/mkbootimg
+++ b/mkbootimg/mkbootimg
@@ -102,12 +102,12 @@
 def parse_os_version(x):
     match = re.search(r'^(\d{1,3})(?:\.(\d{1,3})(?:\.(\d{1,3}))?)?', x)
     if match:
-        a = parse_int(match.group(1))
+        a = int(match.group(1))
         b = c = 0
         if match.lastindex >= 2:
-            b = parse_int(match.group(2))
+            b = int(match.group(2))
         if match.lastindex == 3:
-            c = parse_int(match.group(3))
+            c = int(match.group(3))
         # 7 bits allocated for each field
         assert a < 128
         assert b < 128
@@ -118,8 +118,8 @@
 def parse_os_patch_level(x):
     match = re.search(r'^(\d{4})-(\d{2})-(\d{2})', x)
     if match:
-        y = parse_int(match.group(1)) - 2000
-        m = parse_int(match.group(2))
+        y = int(match.group(1)) - 2000
+        m = int(match.group(2))
         # 7 bits allocated for the year, 4 bits for the month
         assert y >= 0 and y < 128
         assert m > 0 and m <= 12