Merge "Enable non-secure side to receive messages > 4K"
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 49c7847..0abb680 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -582,18 +582,12 @@
#ifdef __APPLE__
return pthread_setname_np(name.c_str());
#else
- const char *s = name.c_str();
-
- // pthread_setname_np fails rather than truncating long strings.
- const int max_task_comm_len = 16; // including the null terminator
- if (name.length() > (max_task_comm_len - 1)) {
- char buf[max_task_comm_len];
- strncpy(buf, name.c_str(), sizeof(buf) - 1);
- buf[sizeof(buf) - 1] = '\0';
- s = buf;
- }
-
- return pthread_setname_np(pthread_self(), s) ;
+ // Both bionic and glibc's pthread_setname_np fails rather than truncating long strings.
+ // glibc doesn't have strlcpy, so we have to fake it.
+ char buf[16]; // MAX_TASK_COMM_LEN, but that's not exported by the kernel headers.
+ strncpy(buf, name.c_str(), sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = '\0';
+ return pthread_setname_np(pthread_self(), buf);
#endif
}
diff --git a/bootstat/bootstat.rc b/bootstat/bootstat.rc
index f4756d5..d697efb 100644
--- a/bootstat/bootstat.rc
+++ b/bootstat/bootstat.rc
@@ -1,7 +1,39 @@
# This file is the LOCAL_INIT_RC file for the bootstat command.
on post-fs-data
- mkdir /data/misc/bootstat 0700 root root
+ mkdir /data/misc/bootstat 0700 system log
+ # To deal with ota transition resulting from a change in DAC from
+ # root.root to system.log, may be deleted after ota has settled.
+ chown system log /data/misc/bootstat/absolute_boot_time
+ chown system log /data/misc/bootstat/boot_complete
+ chown system log /data/misc/bootstat/boot_complete_no_encryption
+ chown system log /data/misc/bootstat/boot_reason
+ chown system log /data/misc/bootstat/bootime.bootloader.1BLE
+ chown system log /data/misc/bootstat/bootime.bootloader.1BLL
+ chown system log /data/misc/bootstat/bootime.bootloader.2BLE
+ chown system log /data/misc/bootstat/bootime.bootloader.2BLL
+ chown system log /data/misc/bootstat/bootime.bootloader.AVB
+ chown system log /data/misc/bootstat/bootime.bootloader.KD
+ chown system log /data/misc/bootstat/bootime.bootloader.KL
+ chown system log /data/misc/bootstat/bootime.bootloader.ODT
+ chown system log /data/misc/bootstat/bootime.bootloader.SW
+ chown system log /data/misc/bootstat/bootime.bootloader.total
+ chown system log /data/misc/bootstat/build_date
+ chown system log /data/misc/bootstat/factory_reset
+ chown system log /data/misc/bootstat/factory_reset_boot_complete
+ chown system log /data/misc/bootstat/factory_reset_boot_complete_no_encryption
+ chown system log /data/misc/bootstat/factory_reset_current_time
+ chown system log /data/misc/bootstat/factory_reset_record_value
+ chown system log /data/misc/bootstat/last_boot_time_utc
+ chown system log /data/misc/bootstat/ota_boot_complete
+ chown system log /data/misc/bootstat/ota_boot_complete_no_encryption
+ chown system log /data/misc/bootstat/post_decrypt_time_elapsed
+ chown system log /data/misc/bootstat/ro.boottime.init
+ chown system log /data/misc/bootstat/ro.boottime.init.cold_boot_wait
+ chown system log /data/misc/bootstat/ro.boottime.init.selinux
+ chown system log /data/misc/bootstat/time_since_factory_reset
+ chown system log /data/misc/bootstat/time_since_last_boot
+ # end ota transitional support
# Record the time at which the user has successfully entered the pin to decrypt
# the device, /data is decrypted, and the system is entering the main boot phase.
@@ -10,7 +42,7 @@
# property:init.svc.bootanim=running: The boot animation is running
# property:ro.crypto.type=block: FDE device
on post-fs-data && property:init.svc.bootanim=running && property:ro.crypto.type=block
- exec - root root -- /system/bin/bootstat -r post_decrypt_time_elapsed
+ exec - system log -- /system/bin/bootstat -r post_decrypt_time_elapsed
# sys.logbootcomplete is a signal to enable the bootstat logging mechanism.
# This signaling is necessary to prevent logging boot metrics after a runtime
@@ -33,13 +65,13 @@
# Record boot complete metrics.
on property:sys.boot_completed=1 && property:sys.logbootcomplete=1
# Record boot_complete and related stats (decryption, etc).
- exec - root root -- /system/bin/bootstat --record_boot_complete
+ exec - system log -- /system/bin/bootstat --record_boot_complete
# Record the boot reason.
- exec - root root -- /system/bin/bootstat --record_boot_reason
+ exec - system log -- /system/bin/bootstat --record_boot_reason
# Record time since factory reset.
- exec - root root -- /system/bin/bootstat --record_time_since_factory_reset
+ exec - system log -- /system/bin/bootstat --record_time_since_factory_reset
# Log all boot events.
- exec - root root -- /system/bin/bootstat -l
+ exec - system log -- /system/bin/bootstat -l
diff --git a/debuggerd/crasher/Android.bp b/debuggerd/crasher/Android.bp
index f73f672..b7b1938 100644
--- a/debuggerd/crasher/Android.bp
+++ b/debuggerd/crasher/Android.bp
@@ -2,7 +2,6 @@
name: "crasher-defaults",
cppflags: [
- "-std=gnu++14",
"-W",
"-Wall",
"-Wextra",
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 55cd03e..1275229 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -116,6 +116,26 @@
fatal("%s: %s", buf, strerror(err));
}
+static bool get_main_thread_name(char* buf, size_t len) {
+ int fd = open("/proc/self/comm", O_RDONLY | O_CLOEXEC);
+ if (fd == -1) {
+ return false;
+ }
+
+ ssize_t rc = read(fd, buf, len);
+ close(fd);
+ if (rc == -1) {
+ return false;
+ } else if (rc == 0) {
+ // Should never happen?
+ return false;
+ }
+
+ // There's a trailing newline, replace it with a NUL.
+ buf[rc - 1] = '\0';
+ return true;
+}
+
/*
* Writes a summary of the signal to the log file. We do this so that, if
* for some reason we're not able to contact debuggerd, there is still some
@@ -188,8 +208,14 @@
}
}
- async_safe_format_log(ANDROID_LOG_FATAL, "libc", "Fatal signal %d (%s)%s%s in tid %d (%s)",
- signum, signal_name, code_desc, addr_desc, __gettid(), thread_name);
+ char main_thread_name[MAX_TASK_NAME_LEN + 1];
+ if (!get_main_thread_name(main_thread_name, sizeof(main_thread_name))) {
+ strncpy(main_thread_name, "<unknown>", sizeof(main_thread_name));
+ }
+
+ async_safe_format_log(
+ ANDROID_LOG_FATAL, "libc", "Fatal signal %d (%s)%s%s in tid %d (%s), pid %d (%s)", signum,
+ signal_name, code_desc, addr_desc, __gettid(), thread_name, __getpid(), main_thread_name);
}
/*
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 271ca95..49d9438 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -93,6 +93,9 @@
static unsigned second_offset = 0x00f00000;
static unsigned tags_offset = 0x00000100;
+static bool g_disable_verity = false;
+static bool g_disable_verification = false;
+
static const std::string convert_fbe_marker_filename("convert_fbe");
enum fb_buffer_type {
@@ -419,6 +422,10 @@
" --skip-reboot Will not reboot the device when\n"
" performing commands that normally\n"
" trigger a reboot.\n"
+ " --disable-verity Set the disable-verity flag in the\n"
+ " the vbmeta image being flashed.\n"
+ " --disable-verification Set the disable-verification flag in"
+ " the vbmeta image being flashed.\n"
#if !defined(_WIN32)
" --wipe-and-use-fbe On devices which support it,\n"
" erase userdata and cache, and\n"
@@ -858,10 +865,55 @@
return load_buf_fd(transport, fd.release(), buf);
}
+static void rewrite_vbmeta_buffer(struct fastboot_buffer* buf) {
+ // Buffer needs to be at least the size of the VBMeta struct which
+ // is 256 bytes.
+ if (buf->sz < 256) {
+ return;
+ }
+
+ int fd = make_temporary_fd();
+ if (fd == -1) {
+ die("Failed to create temporary file for vbmeta rewriting");
+ }
+
+ std::string data;
+ if (!android::base::ReadFdToString(buf->fd, &data)) {
+ die("Failed reading from vbmeta");
+ }
+
+ // There's a 32-bit big endian |flags| field at offset 120 where
+ // bit 0 corresponds to disable-verity and bit 1 corresponds to
+ // disable-verification.
+ //
+ // See external/avb/libavb/avb_vbmeta_image.h for the layout of
+ // the VBMeta struct.
+ if (g_disable_verity) {
+ data[123] |= 0x01;
+ }
+ if (g_disable_verification) {
+ data[123] |= 0x02;
+ }
+
+ if (!android::base::WriteStringToFd(data, fd)) {
+ die("Failed writing to modified vbmeta");
+ }
+ close(buf->fd);
+ buf->fd = fd;
+ lseek(fd, 0, SEEK_SET);
+}
+
static void flash_buf(const char *pname, struct fastboot_buffer *buf)
{
sparse_file** s;
+ // Rewrite vbmeta if that's what we're flashing and modification has been requested.
+ if ((g_disable_verity || g_disable_verification) &&
+ (strcmp(pname, "vbmeta") == 0 || strcmp(pname, "vbmeta_a") == 0 ||
+ strcmp(pname, "vbmeta_b") == 0)) {
+ rewrite_vbmeta_buffer(buf);
+ }
+
switch (buf->type) {
case FB_BUFFER_SPARSE: {
std::vector<std::pair<sparse_file*, int64_t>> sparse_files;
@@ -1470,6 +1522,8 @@
{"set-active", optional_argument, 0, 'a'},
{"skip-secondary", no_argument, 0, 0},
{"skip-reboot", no_argument, 0, 0},
+ {"disable-verity", no_argument, 0, 0},
+ {"disable-verification", no_argument, 0, 0},
#if !defined(_WIN32)
{"wipe-and-use-fbe", no_argument, 0, 0},
#endif
@@ -1555,6 +1609,10 @@
skip_secondary = true;
} else if (strcmp("skip-reboot", longopts[longindex].name) == 0 ) {
skip_reboot = true;
+ } else if (strcmp("disable-verity", longopts[longindex].name) == 0 ) {
+ g_disable_verity = true;
+ } else if (strcmp("disable-verification", longopts[longindex].name) == 0 ) {
+ g_disable_verification = true;
#if !defined(_WIN32)
} else if (strcmp("wipe-and-use-fbe", longopts[longindex].name) == 0) {
wants_wipe = true;
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index f3c000e..709f061 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -12,10 +12,14 @@
#include <sys/types.h>
#ifndef WIN32
#include <sys/wait.h>
+#else
+#include <tchar.h>
+#include <windows.h>
#endif
#include <unistd.h>
#include <vector>
+#include <android-base/errors.h>
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
@@ -26,21 +30,49 @@
using android::base::unique_fd;
#ifdef WIN32
-static int generate_ext4_image(const char* fileName, long long partSize, const std::string& initial_dir,
- unsigned eraseBlkSize, unsigned logicalBlkSize)
-{
- unique_fd fd(open(fileName, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR));
- if (fd == -1) {
- fprintf(stderr, "Unable to open output file for EXT4 filesystem: %s\n", strerror(errno));
+static int exec_e2fs_cmd(const char* path, char* const argv[]) {
+ std::string cmd;
+ int i = 0;
+ while (argv[i] != nullptr) {
+ cmd += argv[i++];
+ cmd += " ";
+ }
+ cmd = cmd.substr(0, cmd.size() - 1);
+
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ DWORD exit_code = 0;
+
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ ZeroMemory(&pi, sizeof(pi));
+
+ SetEnvironmentVariableA("MKE2FS_CONFIG", "");
+
+ if (!CreateProcessA(nullptr, // No module name (use command line)
+ const_cast<char*>(cmd.c_str()), // Command line
+ nullptr, // Process handle not inheritable
+ nullptr, // Thread handle not inheritable
+ FALSE, // Set handle inheritance to FALSE
+ 0, // No creation flags
+ nullptr, // Use parent's environment block
+ nullptr, // Use parent's starting directory
+ &si, // Pointer to STARTUPINFO structure
+ &pi) // Pointer to PROCESS_INFORMATION structure
+ ) {
+ fprintf(stderr, "CreateProcess failed: %s\n",
+ android::base::SystemErrorCodeToString(GetLastError()).c_str());
return -1;
}
- if (initial_dir.empty()) {
- make_ext4fs_sparse_fd_align(fd, partSize, NULL, NULL, eraseBlkSize, logicalBlkSize);
- } else {
- make_ext4fs_sparse_fd_directory_align(fd, partSize, NULL, NULL, initial_dir.c_str(),
- eraseBlkSize, logicalBlkSize);
- }
- return 0;
+
+ WaitForSingleObject(pi.hProcess, INFINITE);
+
+ GetExitCodeProcess(pi.hProcess, &exit_code);
+
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+
+ return exit_code != 0;
}
#else
static int exec_e2fs_cmd(const char* path, char* const argv[]) {
@@ -68,6 +100,7 @@
}
return ret;
}
+#endif
static int generate_ext4_image(const char* fileName, long long partSize,
const std::string& initial_dir, unsigned eraseBlkSize,
@@ -91,6 +124,8 @@
}
mke2fs_args.push_back("-E");
mke2fs_args.push_back(ext_attr.c_str());
+ mke2fs_args.push_back("-O");
+ mke2fs_args.push_back("uninit_bg");
mke2fs_args.push_back(fileName);
std::string size_str = std::to_string(partSize / block_size);
@@ -119,7 +154,6 @@
return 0;
}
-#endif
#ifdef USE_F2FS
static int generate_f2fs_image(const char* fileName, long long partSize, const std::string& initial_dir,
diff --git a/gatekeeperd/tests/Android.mk b/gatekeeperd/tests/Android.mk
index a62b1d4..c38c64b 100644
--- a/gatekeeperd/tests/Android.mk
+++ b/gatekeeperd/tests/Android.mk
@@ -19,7 +19,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := gatekeeperd-unit-tests
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers
+LOCAL_CFLAGS += -g -Wall -Werror -Wno-missing-field-initializers
LOCAL_SHARED_LIBRARIES := libgatekeeper libcrypto libbase
LOCAL_STATIC_LIBRARIES := libscrypt_static
LOCAL_C_INCLUDES := external/scrypt/lib/crypto
diff --git a/include/private/fs_config.h b/include/private/fs_config.h
new file mode 100644
index 0000000..e9868a4
--- /dev/null
+++ b/include/private/fs_config.h
@@ -0,0 +1,4 @@
+// TODO(b/63135587) remove this file after the transitive dependency
+// from private/android_filesystem_config.h is resolved. All files that use
+// libcutils/include/private/fs_config.h should include the file directly, not
+// indirectly via private/android_filesystem_config.h.
diff --git a/init/Android.bp b/init/Android.bp
index 0d7240e..432c298 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -69,6 +69,7 @@
"import_parser.cpp",
"log.cpp",
"parser.cpp",
+ "property_service.cpp",
"service.cpp",
"tokenizer.cpp",
"uevent_listener.cpp",
@@ -81,7 +82,12 @@
"libselinux",
"liblog",
"libprocessgroup",
+ "libfs_mgr",
],
+ include_dirs: [
+ "system/core/mkbootimg",
+ ],
+
}
/*
@@ -105,15 +111,11 @@
"init.cpp",
"init_first_stage.cpp",
"keychords.cpp",
- "property_service.cpp",
"reboot.cpp",
"signal_handler.cpp",
"ueventd.cpp",
"watchdogd.cpp",
],
- include_dirs: [
- "system/core/mkbootimg"
- ],
static_libs: [
"libinit",
"libbootloader_message",
@@ -162,9 +164,12 @@
shared_libs: [
"libbase",
"libcutils",
- "libselinux",
],
- static_libs: ["libinit"],
+ static_libs: [
+ "libinit",
+ "libselinux",
+ "libcrypto",
+ ],
}
subdirs = ["*"]
diff --git a/init/Android.mk b/init/Android.mk
index f30c2a4..3886ed5 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -51,15 +51,12 @@
init.cpp \
init_first_stage.cpp \
keychords.cpp \
- property_service.cpp \
reboot.cpp \
signal_handler.cpp \
ueventd.cpp \
watchdogd.cpp \
LOCAL_MODULE:= init
-LOCAL_C_INCLUDES += \
- system/core/mkbootimg
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
diff --git a/init/README.md b/init/README.md
index f3b57bc..0ea00fb 100644
--- a/init/README.md
+++ b/init/README.md
@@ -447,6 +447,9 @@
`rmdir <path>`
> Calls rmdir(2) on the given path.
+`readahead <file|dir>`
+> Calls readahead(2) on the file or files within given directory.
+
`setprop <name> <value>`
> Set system property _name_ to _value_. Properties are expanded
within _value_.
diff --git a/init/builtins.cpp b/init/builtins.cpp
index dec6f40..eea78fd 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -19,6 +19,7 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
+#include <fts.h>
#include <linux/loop.h>
#include <linux/module.h>
#include <mntent.h>
@@ -44,7 +45,9 @@
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
#include <bootloader_message/bootloader_message.h>
#include <cutils/android_reboot.h>
#include <ext4_utils/ext4_crypt.h>
@@ -66,6 +69,8 @@
using namespace std::literals::string_literals;
+using android::base::unique_fd;
+
#define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW
namespace android {
@@ -74,44 +79,36 @@
static constexpr std::chrono::nanoseconds kCommandRetryTimeout = 5s;
static int insmod(const char *filename, const char *options, int flags) {
- int fd = open(filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
+ unique_fd fd(TEMP_FAILURE_RETRY(open(filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
if (fd == -1) {
PLOG(ERROR) << "insmod: open(\"" << filename << "\") failed";
return -1;
}
- int rc = syscall(__NR_finit_module, fd, options, flags);
+ int rc = syscall(__NR_finit_module, fd.get(), options, flags);
if (rc == -1) {
PLOG(ERROR) << "finit_module for \"" << filename << "\" failed";
}
- close(fd);
return rc;
}
static int __ifupdown(const char *interface, int up) {
struct ifreq ifr;
- int s, ret;
strlcpy(ifr.ifr_name, interface, IFNAMSIZ);
- s = socket(AF_INET, SOCK_DGRAM, 0);
- if (s < 0)
- return -1;
+ unique_fd s(TEMP_FAILURE_RETRY(socket(AF_INET, SOCK_DGRAM, 0)));
+ if (s < 0) return -1;
- ret = ioctl(s, SIOCGIFFLAGS, &ifr);
- if (ret < 0) {
- goto done;
+ int ret = ioctl(s, SIOCGIFFLAGS, &ifr);
+ if (ret < 0) return ret;
+
+ if (up) {
+ ifr.ifr_flags |= IFF_UP;
+ } else {
+ ifr.ifr_flags &= ~IFF_UP;
}
- if (up)
- ifr.ifr_flags |= IFF_UP;
- else
- ifr.ifr_flags &= ~IFF_UP;
-
- ret = ioctl(s, SIOCSIFFLAGS, &ifr);
-
-done:
- close(s);
- return ret;
+ return ioctl(s, SIOCSIFFLAGS, &ifr);
}
static int reboot_into_recovery(const std::vector<std::string>& options) {
@@ -124,31 +121,32 @@
return 0;
}
+template <typename F>
+static void ForEachServiceInClass(const std::string& classname, F function) {
+ for (const auto& service : ServiceList::GetInstance()) {
+ if (service->classnames().count(classname)) std::invoke(function, service);
+ }
+}
+
static int do_class_start(const std::vector<std::string>& args) {
- /* Starting a class does not start services
- * which are explicitly disabled. They must
- * be started individually.
- */
- ServiceManager::GetInstance().
- ForEachServiceInClass(args[1], [] (Service* s) { s->StartIfNotDisabled(); });
+ // Starting a class does not start services which are explicitly disabled.
+ // They must be started individually.
+ ForEachServiceInClass(args[1], &Service::StartIfNotDisabled);
return 0;
}
static int do_class_stop(const std::vector<std::string>& args) {
- ServiceManager::GetInstance().
- ForEachServiceInClass(args[1], [] (Service* s) { s->Stop(); });
+ ForEachServiceInClass(args[1], &Service::Stop);
return 0;
}
static int do_class_reset(const std::vector<std::string>& args) {
- ServiceManager::GetInstance().
- ForEachServiceInClass(args[1], [] (Service* s) { s->Reset(); });
+ ForEachServiceInClass(args[1], &Service::Reset);
return 0;
}
static int do_class_restart(const std::vector<std::string>& args) {
- ServiceManager::GetInstance().
- ForEachServiceInClass(args[1], [] (Service* s) { s->Restart(); });
+ ForEachServiceInClass(args[1], &Service::Restart);
return 0;
}
@@ -162,7 +160,7 @@
}
static int do_enable(const std::vector<std::string>& args) {
- Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
+ Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) {
return -1;
}
@@ -170,11 +168,30 @@
}
static int do_exec(const std::vector<std::string>& args) {
- return ServiceManager::GetInstance().Exec(args) ? 0 : -1;
+ auto service = Service::MakeTemporaryOneshotService(args);
+ if (!service) {
+ LOG(ERROR) << "Failed to create exec service: " << android::base::Join(args, " ");
+ return -1;
+ }
+ if (!service->ExecStart()) {
+ LOG(ERROR) << "Failed to Start exec service";
+ return -1;
+ }
+ ServiceList::GetInstance().AddService(std::move(service));
+ return 0;
}
static int do_exec_start(const std::vector<std::string>& args) {
- return ServiceManager::GetInstance().ExecStart(args[1]) ? 0 : -1;
+ Service* service = ServiceList::GetInstance().FindService(args[1]);
+ if (!service) {
+ LOG(ERROR) << "ExecStart(" << args[1] << "): Service not found";
+ return -1;
+ }
+ if (!service->ExecStart()) {
+ LOG(ERROR) << "ExecStart(" << args[1] << "): Could not start Service";
+ return -1;
+ }
+ return 0;
}
static int do_export(const std::vector<std::string>& args) {
@@ -299,15 +316,12 @@
/* mount <type> <device> <path> <flags ...> <options> */
static int do_mount(const std::vector<std::string>& args) {
- char tmp[64];
- const char *source, *target, *system;
- const char *options = NULL;
+ const char* options = nullptr;
unsigned flags = 0;
- std::size_t na = 0;
- int n, i;
- int wait = 0;
+ bool wait = false;
- for (na = 4; na < args.size(); na++) {
+ for (size_t na = 4; na < args.size(); na++) {
+ size_t i;
for (i = 0; mount_flags[i].name; i++) {
if (!args[na].compare(mount_flags[i].name)) {
flags |= mount_flags[i].flag;
@@ -316,57 +330,43 @@
}
if (!mount_flags[i].name) {
- if (!args[na].compare("wait"))
- wait = 1;
- /* if our last argument isn't a flag, wolf it up as an option string */
- else if (na + 1 == args.size())
+ if (!args[na].compare("wait")) {
+ wait = true;
+ // If our last argument isn't a flag, wolf it up as an option string.
+ } else if (na + 1 == args.size()) {
options = args[na].c_str();
+ }
}
}
- system = args[1].c_str();
- source = args[2].c_str();
- target = args[3].c_str();
+ const char* system = args[1].c_str();
+ const char* source = args[2].c_str();
+ const char* target = args[3].c_str();
- if (!strncmp(source, "loop@", 5)) {
- int mode, loop, fd;
- struct loop_info info;
+ if (android::base::StartsWith(source, "loop@")) {
+ int mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR;
+ unique_fd fd(TEMP_FAILURE_RETRY(open(source + 5, mode | O_CLOEXEC)));
+ if (fd < 0) return -1;
- mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR;
- fd = open(source + 5, mode | O_CLOEXEC);
- if (fd < 0) {
- return -1;
- }
+ for (size_t n = 0;; n++) {
+ std::string tmp = android::base::StringPrintf("/dev/block/loop%zu", n);
+ unique_fd loop(TEMP_FAILURE_RETRY(open(tmp.c_str(), mode | O_CLOEXEC)));
+ if (loop < 0) return -1;
- for (n = 0; ; n++) {
- snprintf(tmp, sizeof(tmp), "/dev/block/loop%d", n);
- loop = open(tmp, mode | O_CLOEXEC);
- if (loop < 0) {
- close(fd);
- return -1;
- }
-
+ loop_info info;
/* if it is a blank loop device */
if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) {
/* if it becomes our loop device */
- if (ioctl(loop, LOOP_SET_FD, fd) >= 0) {
- close(fd);
-
- if (mount(tmp, target, system, flags, options) < 0) {
+ if (ioctl(loop, LOOP_SET_FD, fd.get()) >= 0) {
+ if (mount(tmp.c_str(), target, system, flags, options) < 0) {
ioctl(loop, LOOP_CLR_FD, 0);
- close(loop);
return -1;
}
-
- close(loop);
- goto exit_success;
+ return 0;
}
}
-
- close(loop);
}
- close(fd);
LOG(ERROR) << "out of loopback devices";
return -1;
} else {
@@ -378,7 +378,6 @@
}
-exit_success:
return 0;
}
@@ -389,8 +388,8 @@
*/
static void import_late(const std::vector<std::string>& args, size_t start_index, size_t end_index) {
auto& action_manager = ActionManager::GetInstance();
- auto& service_manager = ServiceManager::GetInstance();
- Parser parser = CreateParser(action_manager, service_manager);
+ auto& service_list = ServiceList::GetInstance();
+ Parser parser = CreateParser(action_manager, service_list);
if (end_index <= start_index) {
// Fallbacks for partitions on which early mount isn't enabled.
for (const auto& path : late_import_paths) {
@@ -580,7 +579,7 @@
}
static int do_start(const std::vector<std::string>& args) {
- Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
+ Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) {
LOG(ERROR) << "do_start: Service " << args[1] << " not found";
return -1;
@@ -591,7 +590,7 @@
}
static int do_stop(const std::vector<std::string>& args) {
- Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
+ Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) {
LOG(ERROR) << "do_stop: Service " << args[1] << " not found";
return -1;
@@ -601,7 +600,7 @@
}
static int do_restart(const std::vector<std::string>& args) {
- Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
+ Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) {
LOG(ERROR) << "do_restart: Service " << args[1] << " not found";
return -1;
@@ -629,7 +628,7 @@
static int do_sysclktz(const std::vector<std::string>& args) {
struct timezone tz = {};
- if (android::base::ParseInt(args[1], &tz.tz_minuteswest) && settimeofday(NULL, &tz) != -1) {
+ if (android::base::ParseInt(args[1], &tz.tz_minuteswest) && settimeofday(nullptr, &tz) != -1) {
return 0;
}
return -1;
@@ -662,6 +661,66 @@
return 0;
}
+static int do_readahead(const std::vector<std::string>& args) {
+ struct stat sb;
+
+ if (stat(args[1].c_str(), &sb)) {
+ PLOG(ERROR) << "Error opening " << args[1];
+ return -1;
+ }
+
+ // We will do readahead in a forked process in order not to block init
+ // since it may block while it reads the
+ // filesystem metadata needed to locate the requested blocks. This
+ // occurs frequently with ext[234] on large files using indirect blocks
+ // instead of extents, giving the appearance that the call blocks until
+ // the requested data has been read.
+ pid_t pid = fork();
+ if (pid == 0) {
+ android::base::Timer t;
+ if (S_ISREG(sb.st_mode)) {
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(args[1].c_str(), O_RDONLY)));
+ if (fd == -1) {
+ PLOG(ERROR) << "Error opening file: " << args[1];
+ _exit(EXIT_FAILURE);
+ }
+ if (readahead(fd, 0, std::numeric_limits<size_t>::max())) {
+ PLOG(ERROR) << "Error readahead file: " << args[1];
+ _exit(EXIT_FAILURE);
+ }
+ } else if (S_ISDIR(sb.st_mode)) {
+ char* paths[] = {const_cast<char*>(args[1].data()), nullptr};
+ std::unique_ptr<FTS, decltype(&fts_close)> fts(
+ fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr), fts_close);
+ if (!fts) {
+ PLOG(ERROR) << "Error opening directory: " << args[1];
+ _exit(EXIT_FAILURE);
+ }
+ // Traverse the entire hierarchy and do readahead
+ for (FTSENT* ftsent = fts_read(fts.get()); ftsent != nullptr;
+ ftsent = fts_read(fts.get())) {
+ if (ftsent->fts_info & FTS_F) {
+ android::base::unique_fd fd(
+ TEMP_FAILURE_RETRY(open(ftsent->fts_accpath, O_RDONLY)));
+ if (fd == -1) {
+ PLOG(ERROR) << "Error opening file: " << args[1];
+ continue;
+ }
+ if (readahead(fd, 0, std::numeric_limits<size_t>::max())) {
+ PLOG(ERROR) << "Unable to readahead on file: " << ftsent->fts_accpath;
+ }
+ }
+ }
+ }
+ LOG(INFO) << "Readahead " << args[1] << " took " << t;
+ _exit(0);
+ } else if (pid < 0) {
+ PLOG(ERROR) << "Fork failed";
+ return -1;
+ }
+ return 0;
+}
+
static int do_copy(const std::vector<std::string>& args) {
std::string data;
std::string err;
@@ -900,6 +959,7 @@
{"mount_all", {1, kMax, do_mount_all}},
{"mount", {3, kMax, do_mount}},
{"umount", {1, 1, do_umount}},
+ {"readahead", {1, 1, do_readahead}},
{"restart", {1, 1, do_restart}},
{"restorecon", {1, kMax, do_restorecon}},
{"restorecon_recursive", {1, kMax, do_restorecon_recursive}},
diff --git a/init/init.cpp b/init/init.cpp
index c003c3d..63a993f 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -53,6 +53,7 @@
#include <fstream>
#include <memory>
+#include <optional>
#include <vector>
#include "bootchart.h"
@@ -72,6 +73,7 @@
using android::base::boot_clock;
using android::base::GetProperty;
using android::base::Timer;
+using android::base::unique_fd;
namespace android {
namespace init {
@@ -84,7 +86,6 @@
static char qemu[32];
std::string default_console = "/dev/console";
-static time_t process_needs_restart_at;
const char *ENV[32];
@@ -98,22 +99,22 @@
std::vector<std::string> late_import_paths;
void DumpState() {
- ServiceManager::GetInstance().DumpState();
+ ServiceList::GetInstance().DumpState();
ActionManager::GetInstance().DumpState();
}
-Parser CreateParser(ActionManager& action_manager, ServiceManager& service_manager) {
+Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {
Parser parser;
- parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_manager));
+ parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list));
parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager));
parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
return parser;
}
-static void LoadBootScripts(ActionManager& action_manager, ServiceManager& service_manager) {
- Parser parser = CreateParser(action_manager, service_manager);
+static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
+ Parser parser = CreateParser(action_manager, service_list);
std::string bootscript = GetProperty("ro.boot.init_rc", "");
if (bootscript.empty()) {
@@ -219,16 +220,25 @@
}
}
-static void restart_processes()
-{
- process_needs_restart_at = 0;
- ServiceManager::GetInstance().ForEachServiceWithFlags(SVC_RESTARTING, [](Service* s) {
- s->RestartIfNeeded(&process_needs_restart_at);
- });
+static std::optional<boot_clock::time_point> RestartProcesses() {
+ std::optional<boot_clock::time_point> next_process_restart_time;
+ for (const auto& s : ServiceList::GetInstance()) {
+ if (!(s->flags() & SVC_RESTARTING)) continue;
+
+ auto restart_time = s->time_started() + 5s;
+ if (boot_clock::now() > restart_time) {
+ s->Start();
+ } else {
+ if (!next_process_restart_time || restart_time < *next_process_restart_time) {
+ next_process_restart_time = restart_time;
+ }
+ }
+ }
+ return next_process_restart_time;
}
void handle_control_message(const std::string& msg, const std::string& name) {
- Service* svc = ServiceManager::GetInstance().FindServiceByName(name);
+ Service* svc = ServiceList::GetInstance().FindService(name);
if (svc == nullptr) {
LOG(ERROR) << "no such service '" << name << "'";
return;
@@ -282,65 +292,49 @@
* time. We do not reboot or halt on failures, as this is a best-effort
* attempt.
*/
-static int mix_hwrng_into_linux_rng_action(const std::vector<std::string>& args)
-{
- int result = -1;
- int hwrandom_fd = -1;
- int urandom_fd = -1;
- char buf[512];
- ssize_t chunk_size;
- size_t total_bytes_written = 0;
-
- hwrandom_fd = TEMP_FAILURE_RETRY(
- open("/dev/hw_random", O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
+static int mix_hwrng_into_linux_rng_action(const std::vector<std::string>& args) {
+ unique_fd hwrandom_fd(
+ TEMP_FAILURE_RETRY(open("/dev/hw_random", O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
if (hwrandom_fd == -1) {
if (errno == ENOENT) {
- LOG(ERROR) << "/dev/hw_random not found";
+ LOG(INFO) << "/dev/hw_random not found";
// It's not an error to not have a Hardware RNG.
- result = 0;
- } else {
- PLOG(ERROR) << "Failed to open /dev/hw_random";
+ return 0;
}
- goto ret;
+ PLOG(ERROR) << "Failed to open /dev/hw_random";
+ return -1;
}
- urandom_fd = TEMP_FAILURE_RETRY(
- open("/dev/urandom", O_WRONLY | O_NOFOLLOW | O_CLOEXEC));
+ unique_fd urandom_fd(
+ TEMP_FAILURE_RETRY(open("/dev/urandom", O_WRONLY | O_NOFOLLOW | O_CLOEXEC)));
if (urandom_fd == -1) {
PLOG(ERROR) << "Failed to open /dev/urandom";
- goto ret;
+ return -1;
}
+ char buf[512];
+ size_t total_bytes_written = 0;
while (total_bytes_written < sizeof(buf)) {
- chunk_size = TEMP_FAILURE_RETRY(
- read(hwrandom_fd, buf, sizeof(buf) - total_bytes_written));
+ ssize_t chunk_size =
+ TEMP_FAILURE_RETRY(read(hwrandom_fd, buf, sizeof(buf) - total_bytes_written));
if (chunk_size == -1) {
PLOG(ERROR) << "Failed to read from /dev/hw_random";
- goto ret;
+ return -1;
} else if (chunk_size == 0) {
LOG(ERROR) << "Failed to read from /dev/hw_random: EOF";
- goto ret;
+ return -1;
}
chunk_size = TEMP_FAILURE_RETRY(write(urandom_fd, buf, chunk_size));
if (chunk_size == -1) {
PLOG(ERROR) << "Failed to write to /dev/urandom";
- goto ret;
+ return -1;
}
total_bytes_written += chunk_size;
}
LOG(INFO) << "Mixed " << total_bytes_written << " bytes from /dev/hw_random into /dev/urandom";
- result = 0;
-
-ret:
- if (hwrandom_fd != -1) {
- close(hwrandom_fd);
- }
- if (urandom_fd != -1) {
- close(urandom_fd);
- }
- return result;
+ return 0;
}
static void security_failure() {
@@ -416,45 +410,40 @@
* ec9ee4acd97c drivers: char: random: add get_random_long()
* 5ef11c35ce86 mm: ASLR: use get_random_long()
*/
-static int set_mmap_rnd_bits_action(const std::vector<std::string>& args)
-{
- int ret = -1;
-
- /* values are arch-dependent */
+static int set_mmap_rnd_bits_action(const std::vector<std::string>& args) {
+/* values are arch-dependent */
#if defined(USER_MODE_LINUX)
/* uml does not support mmap_rnd_bits */
- ret = 0;
+ return 0;
#elif defined(__aarch64__)
/* arm64 supports 18 - 33 bits depending on pagesize and VA_SIZE */
if (set_mmap_rnd_bits_min(33, 24, false)
&& set_mmap_rnd_bits_min(16, 16, true)) {
- ret = 0;
+ return 0;
}
#elif defined(__x86_64__)
/* x86_64 supports 28 - 32 bits */
if (set_mmap_rnd_bits_min(32, 32, false)
&& set_mmap_rnd_bits_min(16, 16, true)) {
- ret = 0;
+ return 0;
}
#elif defined(__arm__) || defined(__i386__)
/* check to see if we're running on 64-bit kernel */
bool h64 = !access(MMAP_RND_COMPAT_PATH, F_OK);
/* supported 32-bit architecture must have 16 bits set */
if (set_mmap_rnd_bits_min(16, 16, h64)) {
- ret = 0;
+ return 0;
}
#elif defined(__mips__) || defined(__mips64__)
// TODO: add mips support b/27788820
- ret = 0;
+ return 0;
#else
LOG(ERROR) << "Unknown architecture";
#endif
- if (ret == -1) {
- LOG(ERROR) << "Unable to set adequate mmap entropy value!";
- security_failure();
- }
- return ret;
+ LOG(ERROR) << "Unable to set adequate mmap entropy value!";
+ security_failure();
+ return -1;
}
#define KPTR_RESTRICT_PATH "/proc/sys/kernel/kptr_restrict"
@@ -1024,7 +1013,7 @@
mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
if constexpr (WORLD_WRITABLE_KMSG) {
- mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11));
+ mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11));
}
mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
@@ -1130,7 +1119,7 @@
Action::set_function_map(&function_map);
ActionManager& am = ActionManager::GetInstance();
- ServiceManager& sm = ServiceManager::GetInstance();
+ ServiceList& sm = ServiceList::GetInstance();
LoadBootScripts(am, sm);
@@ -1171,16 +1160,20 @@
// By default, sleep until something happens.
int epoll_timeout_ms = -1;
- if (!(waiting_for_prop || sm.IsWaitingForExec())) {
+ if (!(waiting_for_prop || Service::is_exec_service_running())) {
am.ExecuteOneCommand();
}
- if (!(waiting_for_prop || sm.IsWaitingForExec())) {
- if (!shutting_down) restart_processes();
+ if (!(waiting_for_prop || Service::is_exec_service_running())) {
+ if (!shutting_down) {
+ auto next_process_restart_time = RestartProcesses();
- // If there's a process that needs restarting, wake up in time for that.
- if (process_needs_restart_at != 0) {
- epoll_timeout_ms = (process_needs_restart_at - time(nullptr)) * 1000;
- if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
+ // If there's a process that needs restarting, wake up in time for that.
+ if (next_process_restart_time) {
+ epoll_timeout_ms = std::chrono::ceil<std::chrono::milliseconds>(
+ *next_process_restart_time - boot_clock::now())
+ .count();
+ if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
+ }
}
// If there's more work to do, wake up again immediately.
diff --git a/init/init.h b/init/init.h
index 0a77bd2..92b9b70 100644
--- a/init/init.h
+++ b/init/init.h
@@ -38,7 +38,7 @@
extern std::vector<std::string> late_import_paths;
-Parser CreateParser(ActionManager& action_manager, ServiceManager& service_manager);
+Parser CreateParser(ActionManager& action_manager, ServiceList& service_list);
void handle_control_message(const std::string& msg, const std::string& arg);
diff --git a/init/keychords.cpp b/init/keychords.cpp
index a0d7cc5..2ef0ce7 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -79,7 +79,7 @@
// Only handle keychords if adb is enabled.
std::string adb_enabled = android::base::GetProperty("init.svc.adbd", "");
if (adb_enabled == "running") {
- Service* svc = ServiceManager::GetInstance().FindServiceByKeychord(id);
+ Service* svc = ServiceList::GetInstance().FindService(id, &Service::keychord_id);
if (svc) {
LOG(INFO) << "Starting service " << svc->name() << " from keychord " << id;
svc->Start();
@@ -92,7 +92,9 @@
}
void keychord_init() {
- ServiceManager::GetInstance().ForEachService(add_service_keycodes);
+ for (const auto& service : ServiceList::GetInstance()) {
+ add_service_keycodes(service.get());
+ }
// Nothing to do if no services require keychords.
if (!keychords) {
diff --git a/init/reboot.cpp b/init/reboot.cpp
index ce81483..cfd703e 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -53,6 +53,7 @@
#include "init.h"
#include "property_service.h"
#include "service.h"
+#include "signal_handler.h"
using android::base::StringPrintf;
using android::base::Timer;
@@ -373,7 +374,7 @@
const std::set<std::string> kill_after_apps{"tombstoned", "logd", "adbd"};
// watchdogd is a vendor specific component but should be alive to complete shutdown safely.
const std::set<std::string> to_starts{"watchdogd"};
- ServiceManager::GetInstance().ForEachService([&kill_after_apps, &to_starts](Service* s) {
+ for (const auto& s : ServiceList::GetInstance()) {
if (kill_after_apps.count(s->name())) {
s->SetShutdownCritical();
} else if (to_starts.count(s->name())) {
@@ -382,14 +383,15 @@
} else if (s->IsShutdownCritical()) {
s->Start(); // start shutdown critical service if not started
}
- });
+ }
- Service* bootAnim = ServiceManager::GetInstance().FindServiceByName("bootanim");
- Service* surfaceFlinger = ServiceManager::GetInstance().FindServiceByName("surfaceflinger");
+ Service* bootAnim = ServiceList::GetInstance().FindService("bootanim");
+ Service* surfaceFlinger = ServiceList::GetInstance().FindService("surfaceflinger");
if (bootAnim != nullptr && surfaceFlinger != nullptr && surfaceFlinger->IsRunning()) {
- ServiceManager::GetInstance().ForEachServiceInClass("animation", [](Service* s) {
- s->SetShutdownCritical(); // will not check animation class separately
- });
+ // will not check animation class separately
+ for (const auto& service : ServiceList::GetInstance()) {
+ if (service->classnames().count("animation")) service->SetShutdownCritical();
+ }
}
// optional shutdown step
@@ -398,18 +400,18 @@
LOG(INFO) << "terminating init services";
// Ask all services to terminate except shutdown critical ones.
- ServiceManager::GetInstance().ForEachServiceShutdownOrder([](Service* s) {
+ for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
if (!s->IsShutdownCritical()) s->Terminate();
- });
+ }
int service_count = 0;
// Only wait up to half of timeout here
auto termination_wait_timeout = shutdown_timeout / 2;
while (t.duration() < termination_wait_timeout) {
- ServiceManager::GetInstance().ReapAnyOutstandingChildren();
+ ReapAnyOutstandingChildren();
service_count = 0;
- ServiceManager::GetInstance().ForEachService([&service_count](Service* s) {
+ for (const auto& s : ServiceList::GetInstance()) {
// Count the number of services running except shutdown critical.
// Exclude the console as it will ignore the SIGTERM signal
// and not exit.
@@ -418,7 +420,7 @@
if (!s->IsShutdownCritical() && s->pid() != 0 && (s->flags() & SVC_CONSOLE) == 0) {
service_count++;
}
- });
+ }
if (service_count == 0) {
// All terminable services terminated. We can exit early.
@@ -434,13 +436,13 @@
// minimum safety steps before restarting
// 2. kill all services except ones that are necessary for the shutdown sequence.
- ServiceManager::GetInstance().ForEachServiceShutdownOrder([](Service* s) {
+ for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
if (!s->IsShutdownCritical()) s->Stop();
- });
- ServiceManager::GetInstance().ReapAnyOutstandingChildren();
+ }
+ ReapAnyOutstandingChildren();
// 3. send volume shutdown to vold
- Service* voldService = ServiceManager::GetInstance().FindServiceByName("vold");
+ Service* voldService = ServiceList::GetInstance().FindService("vold");
if (voldService != nullptr && voldService->IsRunning()) {
ShutdownVold();
voldService->Stop();
@@ -448,9 +450,9 @@
LOG(INFO) << "vold not running, skipping vold shutdown";
}
// logcat stopped here
- ServiceManager::GetInstance().ForEachServiceShutdownOrder([&kill_after_apps](Service* s) {
+ for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
if (kill_after_apps.count(s->name())) s->Stop();
- });
+ }
// 4. sync, try umount, and optionally run fsck for user shutdown
sync();
UmountStat stat = TryUmountAndFsck(runFsck, shutdown_timeout - t.duration());
@@ -524,9 +526,9 @@
// Skip wait for prop if it is in progress
ResetWaitForProp();
- // Skip wait for exec if it is in progress
- if (ServiceManager::GetInstance().IsWaitingForExec()) {
- ServiceManager::GetInstance().ClearExecWait();
+ // Clear EXEC flag if there is one pending
+ for (const auto& s : ServiceList::GetInstance()) {
+ s->UnSetExec();
}
return true;
diff --git a/init/service.cpp b/init/service.cpp
index d0a0751..6f756fa 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -156,6 +156,7 @@
}
unsigned long Service::next_start_order_ = 1;
+bool Service::is_exec_service_running_ = false;
Service::Service(const std::string& name, const std::vector<std::string>& args)
: Service(name, 0, 0, 0, {}, 0, 0, "", args) {}
@@ -280,9 +281,9 @@
std::for_each(descriptors_.begin(), descriptors_.end(),
std::bind(&DescriptorInfo::Clean, std::placeholders::_1));
- if (flags_ & SVC_TEMPORARY) {
- return;
- }
+ if (flags_ & SVC_EXEC) UnSetExec();
+
+ if (flags_ & SVC_TEMPORARY) return;
pid_ = 0;
flags_ &= (~SVC_RUNNING);
@@ -653,15 +654,20 @@
return (this->*parser)(args, err);
}
-bool Service::ExecStart(std::unique_ptr<android::base::Timer>* exec_waiter) {
- flags_ |= SVC_EXEC | SVC_ONESHOT;
-
- exec_waiter->reset(new android::base::Timer);
+bool Service::ExecStart() {
+ flags_ |= SVC_ONESHOT;
if (!Start()) {
- exec_waiter->reset();
return false;
}
+
+ flags_ |= SVC_EXEC;
+ is_exec_service_running_ = true;
+
+ LOG(INFO) << "SVC_EXEC pid " << pid_ << " (uid " << uid_ << " gid " << gid_ << "+"
+ << supp_gids_.size() << " context " << (!seclabel_.empty() ? seclabel_ : "default")
+ << ") started; waiting...";
+
return true;
}
@@ -836,12 +842,6 @@
}
}
- if ((flags_ & SVC_EXEC) != 0) {
- LOG(INFO) << "SVC_EXEC pid " << pid_ << " (uid " << uid_ << " gid " << gid_ << "+"
- << supp_gids_.size() << " context "
- << (!seclabel_.empty() ? seclabel_ : "default") << ") started; waiting...";
- }
-
NotifyStateChange("running");
return true;
}
@@ -890,22 +890,6 @@
} /* else: Service is restarting anyways. */
}
-void Service::RestartIfNeeded(time_t* process_needs_restart_at) {
- boot_clock::time_point now = boot_clock::now();
- boot_clock::time_point next_start = time_started_ + 5s;
- if (now > next_start) {
- flags_ &= (~SVC_RESTARTING);
- Start();
- return;
- }
-
- time_t next_start_time_t = time(nullptr) +
- time_t(std::chrono::duration_cast<std::chrono::seconds>(next_start - now).count());
- if (next_start_time_t < *process_needs_restart_at || *process_needs_restart_at == 0) {
- *process_needs_restart_at = next_start_time_t;
- }
-}
-
// The how field should be either SVC_DISABLED, SVC_RESET, or SVC_RESTART.
void Service::StopOrReset(int how) {
// The service is still SVC_RUNNING until its process exits, but if it has
@@ -951,50 +935,18 @@
close(fd);
}
-int ServiceManager::exec_count_ = 0;
+ServiceList::ServiceList() {}
-ServiceManager::ServiceManager() {
-}
-
-ServiceManager& ServiceManager::GetInstance() {
- static ServiceManager instance;
+ServiceList& ServiceList::GetInstance() {
+ static ServiceList instance;
return instance;
}
-void ServiceManager::AddService(std::unique_ptr<Service> service) {
+void ServiceList::AddService(std::unique_ptr<Service> service) {
services_.emplace_back(std::move(service));
}
-bool ServiceManager::Exec(const std::vector<std::string>& args) {
- Service* svc = MakeExecOneshotService(args);
- if (!svc) {
- LOG(ERROR) << "Could not create exec service";
- return false;
- }
- if (!svc->ExecStart(&exec_waiter_)) {
- LOG(ERROR) << "Could not start exec service";
- ServiceManager::GetInstance().RemoveService(*svc);
- return false;
- }
- return true;
-}
-
-bool ServiceManager::ExecStart(const std::string& name) {
- Service* svc = FindServiceByName(name);
- if (!svc) {
- LOG(ERROR) << "ExecStart(" << name << "): Service not found";
- return false;
- }
- if (!svc->ExecStart(&exec_waiter_)) {
- LOG(ERROR) << "ExecStart(" << name << "): Could not start Service";
- return false;
- }
- return true;
-}
-
-bool ServiceManager::IsWaitingForExec() const { return exec_waiter_ != nullptr; }
-
-Service* ServiceManager::MakeExecOneshotService(const std::vector<std::string>& args) {
+std::unique_ptr<Service> Service::MakeTemporaryOneshotService(const std::vector<std::string>& args) {
// Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS...
// SECLABEL can be a - to denote default
std::size_t command_arg = 1;
@@ -1015,10 +967,11 @@
}
std::vector<std::string> str_args(args.begin() + command_arg, args.end());
- exec_count_++;
- std::string name = "exec " + std::to_string(exec_count_) + " (" + Join(str_args, " ") + ")";
+ static size_t exec_count = 0;
+ exec_count++;
+ std::string name = "exec " + std::to_string(exec_count) + " (" + Join(str_args, " ") + ")";
- unsigned flags = SVC_EXEC | SVC_ONESHOT | SVC_TEMPORARY;
+ unsigned flags = SVC_ONESHOT | SVC_TEMPORARY;
CapSet no_capabilities;
unsigned namespace_flags = 0;
@@ -1053,86 +1006,22 @@
}
}
- auto svc_p = std::make_unique<Service>(name, flags, uid, gid, supp_gids, no_capabilities,
- namespace_flags, seclabel, str_args);
- Service* svc = svc_p.get();
- services_.emplace_back(std::move(svc_p));
-
- return svc;
-}
-
-Service* ServiceManager::FindServiceByName(const std::string& name) const {
- auto svc = std::find_if(services_.begin(), services_.end(),
- [&name] (const std::unique_ptr<Service>& s) {
- return name == s->name();
- });
- if (svc != services_.end()) {
- return svc->get();
- }
- return nullptr;
-}
-
-Service* ServiceManager::FindServiceByPid(pid_t pid) const {
- auto svc = std::find_if(services_.begin(), services_.end(),
- [&pid] (const std::unique_ptr<Service>& s) {
- return s->pid() == pid;
- });
- if (svc != services_.end()) {
- return svc->get();
- }
- return nullptr;
-}
-
-Service* ServiceManager::FindServiceByKeychord(int keychord_id) const {
- auto svc = std::find_if(services_.begin(), services_.end(),
- [&keychord_id] (const std::unique_ptr<Service>& s) {
- return s->keychord_id() == keychord_id;
- });
-
- if (svc != services_.end()) {
- return svc->get();
- }
- return nullptr;
-}
-
-void ServiceManager::ForEachService(const std::function<void(Service*)>& callback) const {
- for (const auto& s : services_) {
- callback(s.get());
- }
+ return std::make_unique<Service>(name, flags, uid, gid, supp_gids, no_capabilities,
+ namespace_flags, seclabel, str_args);
}
// Shutdown services in the opposite order that they were started.
-void ServiceManager::ForEachServiceShutdownOrder(const std::function<void(Service*)>& callback) const {
+const std::vector<Service*> ServiceList::services_in_shutdown_order() const {
std::vector<Service*> shutdown_services;
for (const auto& service : services_) {
if (service->start_order() > 0) shutdown_services.emplace_back(service.get());
}
std::sort(shutdown_services.begin(), shutdown_services.end(),
[](const auto& a, const auto& b) { return a->start_order() > b->start_order(); });
- for (const auto& service : shutdown_services) {
- callback(service);
- }
+ return shutdown_services;
}
-void ServiceManager::ForEachServiceInClass(const std::string& classname,
- void (*func)(Service* svc)) const {
- for (const auto& s : services_) {
- if (s->classnames().find(classname) != s->classnames().end()) {
- func(s.get());
- }
- }
-}
-
-void ServiceManager::ForEachServiceWithFlags(unsigned matchflags,
- void (*func)(Service* svc)) const {
- for (const auto& s : services_) {
- if (s->flags() & matchflags) {
- func(s.get());
- }
- }
-}
-
-void ServiceManager::RemoveService(const Service& svc) {
+void ServiceList::RemoveService(const Service& svc) {
auto svc_it = std::find_if(services_.begin(), services_.end(),
[&svc] (const std::unique_ptr<Service>& s) {
return svc.name() == s->name();
@@ -1144,85 +1033,12 @@
services_.erase(svc_it);
}
-void ServiceManager::DumpState() const {
+void ServiceList::DumpState() const {
for (const auto& s : services_) {
s->DumpState();
}
}
-bool ServiceManager::ReapOneProcess() {
- siginfo_t siginfo = {};
- // This returns a zombie pid or informs us that there are no zombies left to be reaped.
- // It does NOT reap the pid; that is done below.
- if (TEMP_FAILURE_RETRY(waitid(P_ALL, 0, &siginfo, WEXITED | WNOHANG | WNOWAIT)) != 0) {
- PLOG(ERROR) << "waitid failed";
- return false;
- }
-
- auto pid = siginfo.si_pid;
- if (pid == 0) return false;
-
- // At this point we know we have a zombie pid, so we use this scopeguard to reap the pid
- // whenever the function returns from this point forward.
- // We do NOT want to reap the zombie earlier as in Service::Reap(), we kill(-pid, ...) and we
- // want the pid to remain valid throughout that (and potentially future) usages.
- auto reaper = make_scope_guard([pid] { TEMP_FAILURE_RETRY(waitpid(pid, nullptr, WNOHANG)); });
-
- if (PropertyChildReap(pid)) {
- return true;
- }
-
- Service* svc = FindServiceByPid(pid);
-
- std::string name;
- std::string wait_string;
- if (svc) {
- name = StringPrintf("Service '%s' (pid %d)", svc->name().c_str(), pid);
- if (svc->flags() & SVC_EXEC) {
- wait_string = StringPrintf(" waiting took %f seconds",
- exec_waiter_->duration().count() / 1000.0f);
- }
- } else {
- name = StringPrintf("Untracked pid %d", pid);
- }
-
- auto status = siginfo.si_status;
- if (WIFEXITED(status)) {
- LOG(INFO) << name << " exited with status " << WEXITSTATUS(status) << wait_string;
- } else if (WIFSIGNALED(status)) {
- LOG(INFO) << name << " killed by signal " << WTERMSIG(status) << wait_string;
- }
-
- if (!svc) {
- return true;
- }
-
- svc->Reap();
-
- if (svc->flags() & SVC_EXEC) {
- exec_waiter_.reset();
- }
- if (svc->flags() & SVC_TEMPORARY) {
- RemoveService(*svc);
- }
-
- return true;
-}
-
-void ServiceManager::ReapAnyOutstandingChildren() {
- while (ReapOneProcess()) {
- }
-}
-
-void ServiceManager::ClearExecWait() {
- // Clear EXEC flag if there is one pending
- // And clear the wait flag
- for (const auto& s : services_) {
- s->UnSetExec();
- }
- exec_waiter_.reset();
-}
-
bool ServiceParser::ParseSection(std::vector<std::string>&& args, const std::string& filename,
int line, std::string* err) {
if (args.size() < 3) {
@@ -1236,7 +1052,7 @@
return false;
}
- Service* old_service = service_manager_->FindServiceByName(name);
+ Service* old_service = service_list_->FindService(name);
if (old_service) {
*err = "ignored duplicate definition of service '" + name + "'";
return false;
@@ -1253,7 +1069,7 @@
void ServiceParser::EndSection() {
if (service_) {
- service_manager_->AddService(std::move(service_));
+ service_list_->AddService(std::move(service_));
}
}
diff --git a/init/service.h b/init/service.h
index 976f431..6c143cb 100644
--- a/init/service.h
+++ b/init/service.h
@@ -73,9 +73,11 @@
unsigned namespace_flags, const std::string& seclabel,
const std::vector<std::string>& args);
+ static std::unique_ptr<Service> MakeTemporaryOneshotService(const std::vector<std::string>& args);
+
bool IsRunning() { return (flags_ & SVC_RUNNING) != 0; }
bool ParseLine(const std::vector<std::string>& args, std::string* err);
- bool ExecStart(std::unique_ptr<android::base::Timer>* exec_waiter);
+ bool ExecStart();
bool Start();
bool StartIfNotDisabled();
bool Enable();
@@ -83,17 +85,22 @@
void Stop();
void Terminate();
void Restart();
- void RestartIfNeeded(time_t* process_needs_restart_at);
void Reap();
void DumpState() const;
void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
bool IsShutdownCritical() const { return (flags_ & SVC_SHUTDOWN_CRITICAL) != 0; }
- void UnSetExec() { flags_ &= ~SVC_EXEC; }
+ void UnSetExec() {
+ is_exec_service_running_ = false;
+ flags_ &= ~SVC_EXEC;
+ }
+
+ static bool is_exec_service_running() { return is_exec_service_running_; }
const std::string& name() const { return name_; }
const std::set<std::string>& classnames() const { return classnames_; }
unsigned flags() const { return flags_; }
pid_t pid() const { return pid_; }
+ android::base::boot_clock::time_point time_started() const { return time_started_; }
int crash_count() const { return crash_count_; }
uid_t uid() const { return uid_; }
gid_t gid() const { return gid_; }
@@ -151,6 +158,7 @@
bool AddDescriptor(const std::vector<std::string>& args, std::string* err);
static unsigned long next_start_order_;
+ static bool is_exec_service_running_;
std::string name_;
std::set<std::string> classnames_;
@@ -198,47 +206,42 @@
std::vector<std::string> args_;
};
-class ServiceManager {
+class ServiceList {
public:
- static ServiceManager& GetInstance();
+ static ServiceList& GetInstance();
// Exposed for testing
- ServiceManager();
+ ServiceList();
void AddService(std::unique_ptr<Service> service);
- Service* MakeExecOneshotService(const std::vector<std::string>& args);
- bool Exec(const std::vector<std::string>& args);
- bool ExecStart(const std::string& name);
- bool IsWaitingForExec() const;
- Service* FindServiceByName(const std::string& name) const;
- Service* FindServiceByPid(pid_t pid) const;
- Service* FindServiceByKeychord(int keychord_id) const;
- void ForEachService(const std::function<void(Service*)>& callback) const;
- void ForEachServiceShutdownOrder(const std::function<void(Service*)>& callback) const;
- void ForEachServiceInClass(const std::string& classname,
- void (*func)(Service* svc)) const;
- void ForEachServiceWithFlags(unsigned matchflags,
- void (*func)(Service* svc)) const;
- void ReapAnyOutstandingChildren();
void RemoveService(const Service& svc);
+
+ template <typename T, typename F = decltype(&Service::name)>
+ Service* FindService(T value, F function = &Service::name) const {
+ auto svc = std::find_if(services_.begin(), services_.end(),
+ [&function, &value](const std::unique_ptr<Service>& s) {
+ return std::invoke(function, s) == value;
+ });
+ if (svc != services_.end()) {
+ return svc->get();
+ }
+ return nullptr;
+ }
+
void DumpState() const;
- void ClearExecWait();
+
+ auto begin() const { return services_.begin(); }
+ auto end() const { return services_.end(); }
+ const std::vector<std::unique_ptr<Service>>& services() const { return services_; }
+ const std::vector<Service*> services_in_shutdown_order() const;
private:
- // Cleans up a child process that exited.
- // Returns true iff a children was cleaned up.
- bool ReapOneProcess();
-
- static int exec_count_; // Every service needs a unique name.
- std::unique_ptr<android::base::Timer> exec_waiter_;
-
std::vector<std::unique_ptr<Service>> services_;
};
class ServiceParser : public SectionParser {
public:
- ServiceParser(ServiceManager* service_manager)
- : service_manager_(service_manager), service_(nullptr) {}
+ ServiceParser(ServiceList* service_list) : service_list_(service_list), service_(nullptr) {}
bool ParseSection(std::vector<std::string>&& args, const std::string& filename, int line,
std::string* err) override;
bool ParseLineSection(std::vector<std::string>&& args, int line, std::string* err) override;
@@ -247,7 +250,7 @@
private:
bool IsValidName(const std::string& name) const;
- ServiceManager* service_manager_;
+ ServiceList* service_list_;
std::unique_ptr<Service> service_;
};
diff --git a/init/service_test.cpp b/init/service_test.cpp
index 123c8a5..62e46f4 100644
--- a/init/service_test.cpp
+++ b/init/service_test.cpp
@@ -73,23 +73,21 @@
EXPECT_FALSE(service_in_old_memory->process_cgroup_empty());
}
-TEST(service, make_exec_oneshot_service_invalid_syntax) {
- ServiceManager& sm = ServiceManager::GetInstance();
+TEST(service, make_temporary_oneshot_service_invalid_syntax) {
std::vector<std::string> args;
// Nothing.
- ASSERT_EQ(nullptr, sm.MakeExecOneshotService(args));
+ ASSERT_EQ(nullptr, Service::MakeTemporaryOneshotService(args));
// No arguments to 'exec'.
args.push_back("exec");
- ASSERT_EQ(nullptr, sm.MakeExecOneshotService(args));
+ ASSERT_EQ(nullptr, Service::MakeTemporaryOneshotService(args));
// No command in "exec --".
args.push_back("--");
- ASSERT_EQ(nullptr, sm.MakeExecOneshotService(args));
+ ASSERT_EQ(nullptr, Service::MakeTemporaryOneshotService(args));
}
-TEST(service, make_exec_oneshot_service_too_many_supplementary_gids) {
- ServiceManager& sm = ServiceManager::GetInstance();
+TEST(service, make_temporary_oneshot_service_too_many_supplementary_gids) {
std::vector<std::string> args;
args.push_back("exec");
args.push_back("seclabel");
@@ -100,12 +98,11 @@
}
args.push_back("--");
args.push_back("/system/bin/id");
- ASSERT_EQ(nullptr, sm.MakeExecOneshotService(args));
+ ASSERT_EQ(nullptr, Service::MakeTemporaryOneshotService(args));
}
-static void Test_make_exec_oneshot_service(bool dash_dash, bool seclabel, bool uid, bool gid,
- bool supplementary_gids) {
- ServiceManager& sm = ServiceManager::GetInstance();
+static void Test_make_temporary_oneshot_service(bool dash_dash, bool seclabel, bool uid, bool gid,
+ bool supplementary_gids) {
std::vector<std::string> args;
args.push_back("exec");
if (seclabel) {
@@ -126,7 +123,7 @@
}
args.push_back("/system/bin/toybox");
args.push_back("id");
- Service* svc = sm.MakeExecOneshotService(args);
+ auto svc = Service::MakeTemporaryOneshotService(args);
ASSERT_NE(nullptr, svc);
if (seclabel) {
@@ -167,28 +164,28 @@
ASSERT_EQ("id", svc->args()[1]);
}
-TEST(service, make_exec_oneshot_service_with_everything) {
- Test_make_exec_oneshot_service(true, true, true, true, true);
+TEST(service, make_temporary_oneshot_service_with_everything) {
+ Test_make_temporary_oneshot_service(true, true, true, true, true);
}
-TEST(service, make_exec_oneshot_service_with_seclabel_uid_gid) {
- Test_make_exec_oneshot_service(true, true, true, true, false);
+TEST(service, make_temporary_oneshot_service_with_seclabel_uid_gid) {
+ Test_make_temporary_oneshot_service(true, true, true, true, false);
}
-TEST(service, make_exec_oneshot_service_with_seclabel_uid) {
- Test_make_exec_oneshot_service(true, true, true, false, false);
+TEST(service, make_temporary_oneshot_service_with_seclabel_uid) {
+ Test_make_temporary_oneshot_service(true, true, true, false, false);
}
-TEST(service, make_exec_oneshot_service_with_seclabel) {
- Test_make_exec_oneshot_service(true, true, false, false, false);
+TEST(service, make_temporary_oneshot_service_with_seclabel) {
+ Test_make_temporary_oneshot_service(true, true, false, false, false);
}
-TEST(service, make_exec_oneshot_service_with_just_command) {
- Test_make_exec_oneshot_service(true, false, false, false, false);
+TEST(service, make_temporary_oneshot_service_with_just_command) {
+ Test_make_temporary_oneshot_service(true, false, false, false, false);
}
-TEST(service, make_exec_oneshot_service_with_just_command_no_dash) {
- Test_make_exec_oneshot_service(false, false, false, false, false);
+TEST(service, make_temporary_oneshot_service_with_just_command_no_dash) {
+ Test_make_temporary_oneshot_service(false, false, false, false, false);
}
} // namespace init
diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp
index db1bfcf..9e49c48 100644
--- a/init/signal_handler.cpp
+++ b/init/signal_handler.cpp
@@ -14,29 +14,94 @@
* limitations under the License.
*/
+#include "signal_handler.h"
+
#include <signal.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
+#include <sys/wait.h>
#include <unistd.h>
+#include <android-base/chrono_utils.h>
#include <android-base/logging.h>
+#include <android-base/scopeguard.h>
+#include <android-base/stringprintf.h>
#include "init.h"
+#include "property_service.h"
#include "service.h"
+using android::base::StringPrintf;
+using android::base::boot_clock;
+using android::base::make_scope_guard;
+
namespace android {
namespace init {
static int signal_write_fd = -1;
static int signal_read_fd = -1;
+static bool ReapOneProcess() {
+ siginfo_t siginfo = {};
+ // This returns a zombie pid or informs us that there are no zombies left to be reaped.
+ // It does NOT reap the pid; that is done below.
+ if (TEMP_FAILURE_RETRY(waitid(P_ALL, 0, &siginfo, WEXITED | WNOHANG | WNOWAIT)) != 0) {
+ PLOG(ERROR) << "waitid failed";
+ return false;
+ }
+
+ auto pid = siginfo.si_pid;
+ if (pid == 0) return false;
+
+ // At this point we know we have a zombie pid, so we use this scopeguard to reap the pid
+ // whenever the function returns from this point forward.
+ // We do NOT want to reap the zombie earlier as in Service::Reap(), we kill(-pid, ...) and we
+ // want the pid to remain valid throughout that (and potentially future) usages.
+ auto reaper = make_scope_guard([pid] { TEMP_FAILURE_RETRY(waitpid(pid, nullptr, WNOHANG)); });
+
+ if (PropertyChildReap(pid)) return true;
+
+ Service* service = ServiceList::GetInstance().FindService(pid, &Service::pid);
+
+ std::string name;
+ std::string wait_string;
+ if (service) {
+ name = StringPrintf("Service '%s' (pid %d)", service->name().c_str(), pid);
+ if (service->flags() & SVC_EXEC) {
+ auto exec_duration = boot_clock::now() - service->time_started();
+ auto exec_duration_ms =
+ std::chrono::duration_cast<std::chrono::milliseconds>(exec_duration).count();
+ wait_string = StringPrintf(" waiting took %f seconds", exec_duration_ms / 1000.0f);
+ }
+ } else {
+ name = StringPrintf("Untracked pid %d", pid);
+ }
+
+ auto status = siginfo.si_status;
+ if (WIFEXITED(status)) {
+ LOG(INFO) << name << " exited with status " << WEXITSTATUS(status) << wait_string;
+ } else if (WIFSIGNALED(status)) {
+ LOG(INFO) << name << " killed by signal " << WTERMSIG(status) << wait_string;
+ }
+
+ if (!service) return true;
+
+ service->Reap();
+
+ if (service->flags() & SVC_TEMPORARY) {
+ ServiceList::GetInstance().RemoveService(*service);
+ }
+
+ return true;
+}
+
static void handle_signal() {
// Clear outstanding requests.
char buf[32];
read(signal_read_fd, buf, sizeof(buf));
- ServiceManager::GetInstance().ReapAnyOutstandingChildren();
+ ReapAnyOutstandingChildren();
}
static void SIGCHLD_handler(int) {
@@ -45,6 +110,11 @@
}
}
+void ReapAnyOutstandingChildren() {
+ while (ReapOneProcess()) {
+ }
+}
+
void signal_handler_init() {
// Create a signalling mechanism for SIGCHLD.
int s[2];
@@ -63,7 +133,7 @@
act.sa_flags = SA_NOCLDSTOP;
sigaction(SIGCHLD, &act, 0);
- ServiceManager::GetInstance().ReapAnyOutstandingChildren();
+ ReapAnyOutstandingChildren();
register_epoll_handler(signal_read_fd, handle_signal);
}
diff --git a/init/signal_handler.h b/init/signal_handler.h
index f7881ab..9362be5 100644
--- a/init/signal_handler.h
+++ b/init/signal_handler.h
@@ -20,6 +20,8 @@
namespace android {
namespace init {
+void ReapAnyOutstandingChildren();
+
void signal_handler_init(void);
} // namespace init
diff --git a/init/ueventd_test.cpp b/init/ueventd_test.cpp
index 4d9a1fa..7290051 100644
--- a/init/ueventd_test.cpp
+++ b/init/ueventd_test.cpp
@@ -19,6 +19,8 @@
#include <sys/stat.h>
#include <unistd.h>
+#include <atomic>
+#include <chrono>
#include <string>
#include <thread>
#include <vector>
@@ -27,8 +29,11 @@
#include <android-base/scopeguard.h>
#include <android-base/test_utils.h>
#include <gtest/gtest.h>
+#include <selinux/android.h>
+#include <selinux/label.h>
#include <selinux/selinux.h>
+using namespace std::chrono_literals;
using namespace std::string_literals;
template <typename T, typename F>
@@ -120,3 +125,80 @@
freecon(file_context);
}
}
+
+TEST(ueventd, selabel_lookup_MultiThreaded) {
+ if (getuid() != 0) {
+ GTEST_LOG_(INFO) << "Skipping test, must be run as root.";
+ return;
+ }
+
+ // Test parameters
+ constexpr auto num_threads = 10;
+ constexpr auto run_time = 200ms;
+
+ std::unique_ptr<selabel_handle, decltype(&selabel_close)> sehandle(
+ selinux_android_file_context_handle(), &selabel_close);
+
+ ASSERT_TRUE(sehandle);
+
+ struct {
+ const char* file;
+ int mode;
+ std::string expected_context;
+ } files_and_modes[] = {
+ {"/dev/zero", 020666, ""},
+ {"/dev/null", 020666, ""},
+ {"/dev/random", 020666, ""},
+ {"/dev/urandom", 020666, ""},
+ };
+
+ // Precondition, ensure that we can lookup all of these from a single thread, and store the
+ // expected context for each.
+ for (size_t i = 0; i < arraysize(files_and_modes); ++i) {
+ char* secontext;
+ ASSERT_EQ(0, selabel_lookup(sehandle.get(), &secontext, files_and_modes[i].file,
+ files_and_modes[i].mode));
+ files_and_modes[i].expected_context = secontext;
+ freecon(secontext);
+ }
+
+ // Now that we know we can access them, and what their context should be, run in parallel.
+ std::atomic_bool stopped = false;
+ std::atomic_uint num_api_failures = 0;
+ std::atomic_uint num_context_check_failures = 0;
+ std::atomic_uint num_successes = 0;
+
+ auto thread_function = [&]() {
+ while (!stopped) {
+ for (size_t i = 0; i < arraysize(files_and_modes); ++i) {
+ char* secontext;
+ int result = selabel_lookup(sehandle.get(), &secontext, files_and_modes[i].file,
+ files_and_modes[i].mode);
+ if (result != 0) {
+ num_api_failures++;
+ } else {
+ if (files_and_modes[i].expected_context != secontext) {
+ num_context_check_failures++;
+ } else {
+ num_successes++;
+ }
+ freecon(secontext);
+ }
+ }
+ }
+ };
+
+ std::vector<std::thread> threads;
+ std::generate_n(back_inserter(threads), num_threads,
+ [&]() { return std::thread(thread_function); });
+
+ std::this_thread::sleep_for(run_time);
+ stopped = true;
+ for (auto& thread : threads) {
+ thread.join();
+ }
+
+ EXPECT_EQ(0U, num_api_failures);
+ EXPECT_EQ(0U, num_context_check_failures);
+ EXPECT_GT(num_successes, 0U);
+}
diff --git a/libappfuse/include/libappfuse/FuseBuffer.h b/libappfuse/include/libappfuse/FuseBuffer.h
index 7abd2fa..959dde7 100644
--- a/libappfuse/include/libappfuse/FuseBuffer.h
+++ b/libappfuse/include/libappfuse/FuseBuffer.h
@@ -54,7 +54,7 @@
// for FUSE_READ
fuse_read_in read_in;
// for FUSE_LOOKUP
- char lookup_name[0];
+ char lookup_name[kFuseMaxWrite];
};
void Reset(uint32_t data_length, uint32_t opcode, uint64_t unique);
};
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index e02aaf2..c58d777 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -53,6 +53,8 @@
"UnwindCurrent.cpp",
"UnwindMap.cpp",
"UnwindPtrace.cpp",
+ "UnwindStack.cpp",
+ "UnwindStackMap.cpp",
]
cc_library_headers {
@@ -84,6 +86,7 @@
"libbase",
"liblog",
"libunwind",
+ "libunwindstack",
],
static_libs: ["libcutils"],
@@ -97,6 +100,7 @@
"libbase",
"liblog",
"libunwind",
+ "libunwindstack",
],
static_libs: ["libcutils"],
@@ -108,6 +112,7 @@
"libbase",
"liblog",
"libunwind",
+ "libunwindstack",
],
static_libs: ["libasync_safe", "libcutils"],
@@ -130,11 +135,13 @@
linux: {
shared_libs: [
"libunwind",
+ "libunwindstack",
],
},
android: {
shared_libs: [
"libunwind",
+ "libunwindstack",
],
},
}
@@ -161,6 +168,7 @@
shared_libs = [
"libbase",
"libunwind",
+ "libunwindstack",
"libziparchive",
],
}
@@ -192,6 +200,7 @@
"libcutils",
"liblog",
"libunwind",
+ "libunwindstack",
],
group_static_libs: true,
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
new file mode 100644
index 0000000..83a5bb6
--- /dev/null
+++ b/libbacktrace/UnwindStack.cpp
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE 1
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ucontext.h>
+
+#include <memory>
+#include <string>
+
+#if !defined(__ANDROID__)
+#include <cutils/threads.h>
+#endif
+
+#include <backtrace/Backtrace.h>
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+#include <unwindstack/RegsGetLocal.h>
+
+#include "BacktraceLog.h"
+#include "UnwindStack.h"
+#include "UnwindStackMap.h"
+
+static std::string GetFunctionName(pid_t pid, BacktraceMap* back_map, uintptr_t pc,
+ uintptr_t* offset) {
+ *offset = 0;
+ unwindstack::Maps* maps = reinterpret_cast<UnwindStackMap*>(back_map)->stack_maps();
+
+ // Get the map for this
+ unwindstack::MapInfo* map_info = maps->Find(pc);
+ if (map_info == nullptr || map_info->flags & PROT_DEVICE_MAP) {
+ return "";
+ }
+
+ unwindstack::Elf* elf = map_info->GetElf(pid, true);
+
+ std::string name;
+ uint64_t func_offset;
+ if (!elf->GetFunctionName(elf->GetRelPc(pc, map_info), &name, &func_offset)) {
+ return "";
+ }
+ *offset = func_offset;
+ return name;
+}
+
+static bool IsUnwindLibrary(const std::string& map_name) {
+ const std::string library(basename(map_name.c_str()));
+ return library == "libunwindstack.so" || library == "libbacktrace.so";
+}
+
+static bool Unwind(pid_t pid, unwindstack::Memory* memory, unwindstack::Regs* regs,
+ BacktraceMap* back_map, std::vector<backtrace_frame_data_t>* frames,
+ size_t num_ignore_frames) {
+ unwindstack::Maps* maps = reinterpret_cast<UnwindStackMap*>(back_map)->stack_maps();
+ bool adjust_rel_pc = false;
+ size_t num_frames = 0;
+ frames->clear();
+ while (num_frames < MAX_BACKTRACE_FRAMES) {
+ if (regs->pc() == 0) {
+ break;
+ }
+ unwindstack::MapInfo* map_info = maps->Find(regs->pc());
+ if (map_info == nullptr) {
+ break;
+ }
+
+ unwindstack::Elf* elf = map_info->GetElf(pid, true);
+ uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info);
+
+ bool skip_frame = num_frames == 0 && IsUnwindLibrary(map_info->name);
+ if (num_ignore_frames == 0 && !skip_frame) {
+ uint64_t adjusted_rel_pc = rel_pc;
+ if (adjust_rel_pc) {
+ adjusted_rel_pc = regs->GetAdjustedPc(rel_pc, elf);
+ }
+ frames->resize(num_frames + 1);
+ backtrace_frame_data_t* frame = &frames->at(num_frames);
+ frame->num = num_frames;
+ // This will point to the adjusted absolute pc. regs->pc() is
+ // unaltered.
+ frame->pc = map_info->start + adjusted_rel_pc;
+ frame->sp = regs->sp();
+ frame->rel_pc = adjusted_rel_pc;
+ frame->stack_size = 0;
+
+ frame->map.start = map_info->start;
+ frame->map.end = map_info->end;
+ frame->map.offset = map_info->offset;
+ frame->map.load_bias = elf->GetLoadBias();
+ frame->map.flags = map_info->flags;
+ frame->map.name = map_info->name;
+
+ uint64_t func_offset = 0;
+ if (!elf->GetFunctionName(adjusted_rel_pc, &frame->func_name, &func_offset)) {
+ frame->func_name = "";
+ }
+ frame->func_offset = func_offset;
+ if (num_frames > 0) {
+ // Set the stack size for the previous frame.
+ backtrace_frame_data_t* prev = &frames->at(num_frames - 1);
+ prev->stack_size = frame->sp - prev->sp;
+ }
+ num_frames++;
+ } else if (!skip_frame && num_ignore_frames > 0) {
+ num_ignore_frames--;
+ }
+ adjust_rel_pc = true;
+
+ // Do not unwind through a device map.
+ if (map_info->flags & PROT_DEVICE_MAP) {
+ break;
+ }
+ unwindstack::MapInfo* sp_info = maps->Find(regs->sp());
+ if (sp_info->flags & PROT_DEVICE_MAP) {
+ break;
+ }
+
+ if (!elf->Step(rel_pc + map_info->elf_offset, regs, memory)) {
+ break;
+ }
+ }
+
+ return true;
+}
+
+UnwindStackCurrent::UnwindStackCurrent(pid_t pid, pid_t tid, BacktraceMap* map)
+ : BacktraceCurrent(pid, tid, map), memory_(new unwindstack::MemoryLocal) {}
+
+std::string UnwindStackCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
+ return ::GetFunctionName(Pid(), GetMap(), pc, offset);
+}
+
+bool UnwindStackCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) {
+ std::unique_ptr<unwindstack::Regs> regs;
+ if (ucontext == nullptr) {
+ regs.reset(unwindstack::Regs::CreateFromLocal());
+ // Fill in the registers from this function. Do it here to avoid
+ // one extra function call appearing in the unwind.
+ unwindstack::RegsGetLocal(regs.get());
+ } else {
+ regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::GetMachineType(), ucontext));
+ }
+
+ error_ = BACKTRACE_UNWIND_NO_ERROR;
+ return ::Unwind(getpid(), memory_.get(), regs.get(), GetMap(), &frames_, num_ignore_frames);
+}
+
+UnwindStackPtrace::UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
+ : BacktracePtrace(pid, tid, map), memory_(new unwindstack::MemoryRemote(pid)) {}
+
+std::string UnwindStackPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
+ return ::GetFunctionName(Pid(), GetMap(), pc, offset);
+}
+
+bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, ucontext_t* context) {
+ std::unique_ptr<unwindstack::Regs> regs;
+ if (context == nullptr) {
+ uint32_t machine_type;
+ regs.reset(unwindstack::Regs::RemoteGet(Tid(), &machine_type));
+ } else {
+ regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::GetMachineType(), context));
+ }
+
+ error_ = BACKTRACE_UNWIND_NO_ERROR;
+ return ::Unwind(Pid(), memory_.get(), regs.get(), GetMap(), &frames_, num_ignore_frames);
+}
+
+Backtrace* Backtrace::CreateNew(pid_t pid, pid_t tid, BacktraceMap* map) {
+ if (pid == BACKTRACE_CURRENT_PROCESS) {
+ pid = getpid();
+ if (tid == BACKTRACE_CURRENT_THREAD) {
+ tid = gettid();
+ }
+ } else if (tid == BACKTRACE_CURRENT_THREAD) {
+ tid = pid;
+ }
+
+ if (map == nullptr) {
+// This would cause the wrong type of map object to be created, so disallow.
+#if defined(__ANDROID__)
+ __assert2(__FILE__, __LINE__, __PRETTY_FUNCTION__,
+ "Backtrace::CreateNew() must be called with a real map pointer.");
+#else
+ BACK_LOGE("Backtrace::CreateNew() must be called with a real map pointer.");
+ abort();
+#endif
+ }
+
+ if (pid == getpid()) {
+ return new UnwindStackCurrent(pid, tid, map);
+ } else {
+ return new UnwindStackPtrace(pid, tid, map);
+ }
+}
diff --git a/libbacktrace/UnwindStack.h b/libbacktrace/UnwindStack.h
new file mode 100644
index 0000000..32d1f51
--- /dev/null
+++ b/libbacktrace/UnwindStack.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef _LIBBACKTRACE_UNWIND_STACK_H
+#define _LIBBACKTRACE_UNWIND_STACK_H
+
+#include <stdint.h>
+
+#include <string>
+
+#include <backtrace/BacktraceMap.h>
+#include <unwindstack/Memory.h>
+
+#include "BacktraceCurrent.h"
+#include "BacktracePtrace.h"
+
+class UnwindStackCurrent : public BacktraceCurrent {
+ public:
+ UnwindStackCurrent(pid_t pid, pid_t tid, BacktraceMap* map);
+ virtual ~UnwindStackCurrent() = default;
+
+ std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override;
+
+ bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) override;
+
+ private:
+ std::unique_ptr<unwindstack::Memory> memory_;
+};
+
+class UnwindStackPtrace : public BacktracePtrace {
+ public:
+ UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map);
+ virtual ~UnwindStackPtrace() = default;
+
+ bool Unwind(size_t num_ignore_frames, ucontext_t* context) override;
+
+ std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
+
+ private:
+ std::unique_ptr<unwindstack::Memory> memory_;
+};
+
+#endif // _LIBBACKTRACE_UNWIND_STACK_H
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
new file mode 100644
index 0000000..ba9fd87
--- /dev/null
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2017 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 <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <backtrace/BacktraceMap.h>
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+
+#include "UnwindStackMap.h"
+
+//-------------------------------------------------------------------------
+UnwindStackMap::UnwindStackMap(pid_t pid) : BacktraceMap(pid) {}
+
+bool UnwindStackMap::Build() {
+ if (pid_ == 0) {
+ pid_ = getpid();
+ stack_maps_.reset(new unwindstack::LocalMaps);
+ } else {
+ stack_maps_.reset(new unwindstack::RemoteMaps(pid_));
+ }
+
+ if (!stack_maps_->Parse()) {
+ return false;
+ }
+
+ // Iterate through the maps and fill in the backtrace_map_t structure.
+ for (auto& map_info : *stack_maps_) {
+ backtrace_map_t map;
+ map.start = map_info.start;
+ map.end = map_info.end;
+ map.offset = map_info.offset;
+ // Set to -1 so that it is demand loaded.
+ map.load_bias = static_cast<uintptr_t>(-1);
+ map.flags = map_info.flags;
+ map.name = map_info.name;
+
+ maps_.push_back(map);
+ }
+
+ return true;
+}
+
+void UnwindStackMap::FillIn(uintptr_t addr, backtrace_map_t* map) {
+ BacktraceMap::FillIn(addr, map);
+ if (map->load_bias != static_cast<uintptr_t>(-1)) {
+ return;
+ }
+
+ // Fill in the load_bias.
+ unwindstack::MapInfo* map_info = stack_maps_->Find(addr);
+ if (map_info == nullptr) {
+ return;
+ }
+ unwindstack::Elf* elf = map_info->GetElf(pid_, true);
+ map->load_bias = elf->GetLoadBias();
+}
+
+//-------------------------------------------------------------------------
+// BacktraceMap create function.
+//-------------------------------------------------------------------------
+BacktraceMap* BacktraceMap::CreateNew(pid_t pid, bool uncached) {
+ BacktraceMap* map;
+
+ if (uncached) {
+ // Force use of the base class to parse the maps when this call is made.
+ map = new BacktraceMap(pid);
+ } else if (pid == getpid()) {
+ map = new UnwindStackMap(0);
+ } else {
+ map = new UnwindStackMap(pid);
+ }
+ if (!map->Build()) {
+ delete map;
+ return nullptr;
+ }
+ return map;
+}
diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h
new file mode 100644
index 0000000..7885b74
--- /dev/null
+++ b/libbacktrace/UnwindStackMap.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef _LIBBACKTRACE_UNWINDSTACK_MAP_H
+#define _LIBBACKTRACE_UNWINDSTACK_MAP_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <backtrace/BacktraceMap.h>
+#include <unwindstack/Maps.h>
+
+class UnwindStackMap : public BacktraceMap {
+ public:
+ explicit UnwindStackMap(pid_t pid);
+ ~UnwindStackMap() = default;
+
+ bool Build() override;
+
+ void FillIn(uintptr_t addr, backtrace_map_t* map) override;
+
+ unwindstack::Maps* stack_maps() { return stack_maps_.get(); }
+
+ protected:
+ std::unique_ptr<unwindstack::Maps> stack_maps_;
+};
+
+#endif // _LIBBACKTRACE_UNWINDSTACK_MAP_H
diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h
index b919e81..d67ea50 100644
--- a/libbacktrace/include/backtrace/Backtrace.h
+++ b/libbacktrace/include/backtrace/Backtrace.h
@@ -90,6 +90,8 @@
// If map is NULL, then create the map and manage it internally.
// If map is not NULL, the map is still owned by the caller.
static Backtrace* Create(pid_t pid, pid_t tid, BacktraceMap* map = NULL);
+ // Same as above, but uses a different underlying unwinder.
+ static Backtrace* CreateNew(pid_t pid, pid_t tid, BacktraceMap* map = NULL);
// Create an offline Backtrace object that can be used to do an unwind without a process
// that is still running. If cache_file is set to true, then elf information will be cached
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index 02a50f7..963c34b 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -52,6 +52,8 @@
// Passing a map created with uncached set to true to Backtrace::Create()
// is unsupported.
static BacktraceMap* Create(pid_t pid, bool uncached = false);
+ // Same as above, but is compatible with the new unwinder.
+ static BacktraceMap* CreateNew(pid_t pid, bool uncached = false);
static BacktraceMap* Create(pid_t pid, const std::vector<backtrace_map_t>& maps);
diff --git a/libbacktrace/include/backtrace/backtrace_constants.h b/libbacktrace/include/backtrace/backtrace_constants.h
index f8c1575..373a1e5 100644
--- a/libbacktrace/include/backtrace/backtrace_constants.h
+++ b/libbacktrace/include/backtrace/backtrace_constants.h
@@ -20,10 +20,10 @@
// When the pid to be traced is set to this value, then trace the current
// process. If the tid value is not BACKTRACE_NO_TID, then the specified
// thread from the current process will be traced.
-#define BACKTRACE_CURRENT_PROCESS -1
+#define BACKTRACE_CURRENT_PROCESS (-1)
// When the tid to be traced is set to this value, then trace the specified
// current thread of the specified pid.
-#define BACKTRACE_CURRENT_THREAD -1
+#define BACKTRACE_CURRENT_THREAD (-1)
#define MAX_BACKTRACE_FRAMES 64
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 85258cd..8528a4b 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -150,6 +150,7 @@
"libutils_headers",
],
export_header_lib_headers: ["libcutils_headers"],
+ local_include_dirs: ["include"],
cflags: [
"-Werror",
diff --git a/libcutils/canned_fs_config.c b/libcutils/canned_fs_config.c
index 96ca566..819a846 100644
--- a/libcutils/canned_fs_config.c
+++ b/libcutils/canned_fs_config.c
@@ -23,6 +23,7 @@
#include <string.h>
#include <private/android_filesystem_config.h>
+#include <private/fs_config.h>
#include <private/canned_fs_config.h>
typedef struct {
diff --git a/libcutils/include/cutils/android_filesystem_config.h b/libcutils/include/cutils/android_filesystem_config.h
new file mode 120000
index 0000000..d2a92fe
--- /dev/null
+++ b/libcutils/include/cutils/android_filesystem_config.h
@@ -0,0 +1 @@
+../private/android_filesystem_config.h
\ No newline at end of file
diff --git a/libcutils/include/cutils/list.h b/libcutils/include/cutils/list.h
index 4ba2cfd..dfdc53b 100644
--- a/libcutils/include/cutils/list.h
+++ b/libcutils/include/cutils/list.h
@@ -34,20 +34,20 @@
#define list_declare(name) \
struct listnode name = { \
- .next = &name, \
- .prev = &name, \
+ .next = &(name), \
+ .prev = &(name), \
}
#define list_for_each(node, list) \
- for (node = (list)->next; node != (list); node = node->next)
+ for ((node) = (list)->next; (node) != (list); (node) = (node)->next)
#define list_for_each_reverse(node, list) \
- for (node = (list)->prev; node != (list); node = node->prev)
+ for ((node) = (list)->prev; (node) != (list); (node) = (node)->prev)
#define list_for_each_safe(node, n, list) \
- for (node = (list)->next, n = node->next; \
- node != (list); \
- node = n, n = node->next)
+ for ((node) = (list)->next, (n) = (node)->next; \
+ (node) != (list); \
+ (node) = (n), (n) = (node)->next)
static inline void list_init(struct listnode *node)
{
diff --git a/libcutils/include/cutils/native_handle.h b/libcutils/include/cutils/native_handle.h
index 7d6a988..55754b5 100644
--- a/libcutils/include/cutils/native_handle.h
+++ b/libcutils/include/cutils/native_handle.h
@@ -25,8 +25,8 @@
/* Declare a char array for use with native_handle_init */
#define NATIVE_HANDLE_DECLARE_STORAGE(name, maxFds, maxInts) \
- alignas(native_handle_t) char name[ \
- sizeof(native_handle_t) + sizeof(int) * (maxFds + maxInts)]
+ alignas(native_handle_t) char (name)[ \
+ sizeof(native_handle_t) + sizeof(int) * ((maxFds) + (maxInts))]
typedef struct native_handle
{
diff --git a/libcutils/include/cutils/properties.h b/libcutils/include/cutils/properties.h
index b45f58f..d2e0871 100644
--- a/libcutils/include/cutils/properties.h
+++ b/libcutils/include/cutils/properties.h
@@ -43,12 +43,7 @@
** If the property read fails or returns an empty value, the default
** value is used (if nonnull).
*/
-int property_get(const char *key, char *value, const char *default_value)
-/* Sometimes we use not-Bionic with this, so we need this check. */
-#if defined(__BIONIC_FORTIFY)
- __overloadable __RENAME_CLANG(property_get)
-#endif
- ;
+int property_get(const char* key, char* value, const char* default_value);
/* property_get_bool: returns the value of key coerced into a
** boolean. If the property is not set, then the default value is returned.
@@ -119,27 +114,15 @@
#if defined(__clang__)
-/* Some projects use -Weverything; enable_if is clang-specific.
-** FIXME: This is marked used because we'll otherwise get complaints about an
-** unused static function. This is more robust than marking it unused, since
-** -Wused-but-marked-unused is a thing that will complain if this function is
-** actually used, thus making FORTIFY noisier when an error happens. It's going
-** to go away anyway during our FORTIFY cleanup.
-**/
+/* Some projects use -Weverything; diagnose_if is clang-specific. */
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgcc-compat"
-__BIONIC_ERROR_FUNCTION_VISIBILITY
-int property_get(const char *key, char *value, const char *default_value)
- __overloadable
- __enable_if(__bos(value) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
- __bos(value) < PROPERTY_VALUE_MAX, __property_get_err_str)
- __errorattr(__property_get_err_str)
- __attribute__((used));
+int property_get(const char* key, char* value, const char* default_value)
+ __clang_error_if(__bos(value) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
+ __bos(value) < PROPERTY_VALUE_MAX,
+ __property_get_err_str);
#pragma clang diagnostic pop
-/* No object size? No FORTIFY.
-*/
-
#else /* defined(__clang__) */
extern int __property_get_real(const char *, char *, const char *)
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 02141d6..55ece54 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -14,11 +14,6 @@
* limitations under the License.
*/
-/* This file is used to define the properties of the filesystem
-** images generated by build tools (mkbootfs and mkyaffs2image) and
-** by the device side of adb.
-*/
-
/*
* This file is consumed by build/tools/fs_config and is used
* for generating various files. Anything #define AID_<name>
@@ -49,18 +44,12 @@
#ifndef _ANDROID_FILESYSTEM_CONFIG_H_
#define _ANDROID_FILESYSTEM_CONFIG_H_
-#include <stdint.h>
-#include <sys/cdefs.h>
#include <sys/types.h>
-#if defined(__BIONIC__)
-#include <linux/capability.h>
-#else
-#include "android_filesystem_capability.h"
+#if !defined(__ANDROID_VNDK__) && !defined(EXCLUDE_FS_CONFIG_STRUCTURES)
+#include <private/fs_config.h>
#endif
-#define CAP_MASK_LONG(cap_name) (1ULL << (cap_name))
-
/* This is the master Users and Groups config for the platform.
* DO NOT EVER RENUMBER
*/
@@ -131,6 +120,8 @@
#define AID_ESE 1060 /* embedded secure element (eSE) subsystem */
#define AID_OTA_UPDATE 1061 /* resource tracking UID for OTA updates */
#define AID_AUTOMOTIVE_EVS 1062 /* Automotive rear and surround view system */
+#define AID_LOWPAN 1063 /* LoWPAN subsystem */
+#define AID_HSM 1064 /* hardware security module subsystem */
/* Changes to this file must be made in AOSP, *not* in internal branches. */
#define AID_SHELL 2000 /* adb and debug shell user */
@@ -193,36 +184,4 @@
* Also see build/tools/fs_config for more details.
*/
-#if !defined(EXCLUDE_FS_CONFIG_STRUCTURES)
-
-struct fs_path_config {
- unsigned mode;
- unsigned uid;
- unsigned gid;
- uint64_t capabilities;
- const char* prefix;
-};
-
-/* Rules for directories and files has moved to system/code/libcutils/fs_config.c */
-
-__BEGIN_DECLS
-
-/*
- * Used in:
- * build/tools/fs_config/fs_config.c
- * build/tools/fs_get_stats/fs_get_stats.c
- * system/extras/ext4_utils/make_ext4fs_main.c
- * external/squashfs-tools/squashfs-tools/android.c
- * system/core/cpio/mkbootfs.c
- * system/core/adb/file_sync_service.cpp
- * system/extras/ext4_utils/canned_fs_config.c
- */
-void fs_config(const char* path, int dir, const char* target_out_path, unsigned* uid, unsigned* gid,
- unsigned* mode, uint64_t* capabilities);
-
-ssize_t fs_config_generate(char* buffer, size_t length, const struct fs_path_config* pc);
-
-__END_DECLS
-
-#endif
#endif
diff --git a/libcutils/include/private/fs_config.h b/libcutils/include/private/fs_config.h
index 7dad668..aab5042 100644
--- a/libcutils/include/private/fs_config.h
+++ b/libcutils/include/private/fs_config.h
@@ -14,10 +14,24 @@
* limitations under the License.
*/
+/* This file is used to define the properties of the filesystem
+** images generated by build tools (mkbootfs and mkyaffs2image) and
+** by the device side of adb.
+*/
+
#ifndef _LIBS_CUTILS_PRIVATE_FS_CONFIG_H
#define _LIBS_CUTILS_PRIVATE_FS_CONFIG_H
#include <stdint.h>
+#include <sys/cdefs.h>
+
+#if defined(__BIONIC__)
+#include <linux/capability.h>
+#else // defined(__BIONIC__)
+#include "android_filesystem_capability.h"
+#endif // defined(__BIONIC__)
+
+#define CAP_MASK_LONG(cap_name) (1ULL << (cap_name))
/*
* binary format for the runtime <partition>/etc/fs_config_(dirs|files)
@@ -34,4 +48,33 @@
char prefix[];
} __attribute__((__aligned__(sizeof(uint64_t))));
+struct fs_path_config {
+ unsigned mode;
+ unsigned uid;
+ unsigned gid;
+ uint64_t capabilities;
+ const char* prefix;
+};
+
+/* Rules for directories and files has moved to system/code/libcutils/fs_config.c */
+
+__BEGIN_DECLS
+
+/*
+ * Used in:
+ * build/tools/fs_config/fs_config.c
+ * build/tools/fs_get_stats/fs_get_stats.c
+ * system/extras/ext4_utils/make_ext4fs_main.c
+ * external/squashfs-tools/squashfs-tools/android.c
+ * system/core/cpio/mkbootfs.c
+ * system/core/adb/file_sync_service.cpp
+ * system/extras/ext4_utils/canned_fs_config.c
+ */
+void fs_config(const char* path, int dir, const char* target_out_path, unsigned* uid, unsigned* gid,
+ unsigned* mode, uint64_t* capabilities);
+
+ssize_t fs_config_generate(char* buffer, size_t length, const struct fs_path_config* pc);
+
+__END_DECLS
+
#endif /* _LIBS_CUTILS_PRIVATE_FS_CONFIG_H */
diff --git a/libcutils/include_vndk/cutils/android_filesystem_config.h b/libcutils/include_vndk/cutils/android_filesystem_config.h
new file mode 120000
index 0000000..13a5a08
--- /dev/null
+++ b/libcutils/include_vndk/cutils/android_filesystem_config.h
@@ -0,0 +1 @@
+../../include/private/android_filesystem_config.h
\ No newline at end of file
diff --git a/libcutils/include_vndk/private b/libcutils/include_vndk/private
deleted file mode 120000
index 2245a85..0000000
--- a/libcutils/include_vndk/private
+++ /dev/null
@@ -1 +0,0 @@
-../include/private
\ No newline at end of file
diff --git a/libcutils/socket_network_client_unix.c b/libcutils/socket_network_client_unix.c
index 37851b1..1b87c49 100644
--- a/libcutils/socket_network_client_unix.c
+++ b/libcutils/socket_network_client_unix.c
@@ -63,7 +63,7 @@
for (struct addrinfo* addr = addrs; addr != NULL; addr = addr->ai_next) {
// The Mac doesn't have SOCK_NONBLOCK.
int s = socket(addr->ai_family, type, addr->ai_protocol);
- if (s == -1 || toggle_O_NONBLOCK(s) == -1) return -1;
+ if (s == -1 || toggle_O_NONBLOCK(s) == -1) break;
int rc = connect(s, addr->ai_addr, addr->ai_addrlen);
if (rc == 0) {
diff --git a/libcutils/trace-container.c b/libcutils/trace-container.c
new file mode 100644
index 0000000..03e91b1
--- /dev/null
+++ b/libcutils/trace-container.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2017 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 "trace-dev.inc"
+
+#include <cutils/sockets.h>
+#include <sys/stat.h>
+#include <time.h>
+
+/**
+ * For tracing in container, tags are written into a socket
+ * instead of ftrace. Additional data is appended so we need extra space.
+ */
+#define CONTAINER_ATRACE_MESSAGE_LENGTH (ATRACE_MESSAGE_LENGTH + 512)
+
+static pthread_once_t atrace_once_control = PTHREAD_ONCE_INIT;
+
+// Variables used for tracing in container with socket.
+// Note that we need to manually close and reopen socket when Zygote is forking. This requires
+// writing and closing sockets on multiple threads. A rwlock is used for avoiding concurrent
+// operation on the file descriptor.
+static bool atrace_use_container_sock = false;
+static int atrace_container_sock_fd = -1;
+static pthread_mutex_t atrace_enabling_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_rwlock_t atrace_container_sock_rwlock = PTHREAD_RWLOCK_INITIALIZER;
+
+static bool atrace_init_container_sock()
+{
+ pthread_rwlock_wrlock(&atrace_container_sock_rwlock);
+ atrace_container_sock_fd =
+ socket_local_client("trace", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET);
+ if (atrace_container_sock_fd < 0) {
+ ALOGE("Error opening container trace socket: %s (%d)", strerror(errno), errno);
+ }
+ pthread_rwlock_unlock(&atrace_container_sock_rwlock);
+ return atrace_container_sock_fd != -1;
+}
+
+static void atrace_close_container_sock()
+{
+ pthread_rwlock_wrlock(&atrace_container_sock_rwlock);
+ if (atrace_container_sock_fd != -1) close(atrace_container_sock_fd);
+ atrace_container_sock_fd = -1;
+ pthread_rwlock_unlock(&atrace_container_sock_rwlock);
+}
+
+// Set whether tracing is enabled in this process. This is used to prevent
+// the Zygote process from tracing. We need to close the socket in the container when tracing is
+// disabled, and reopen it again after Zygote forking.
+void atrace_set_tracing_enabled(bool enabled)
+{
+ pthread_mutex_lock(&atrace_enabling_mutex);
+ if (atrace_use_container_sock) {
+ bool already_enabled = atomic_load_explicit(&atrace_is_enabled, memory_order_acquire);
+ if (enabled && !already_enabled) {
+ // Trace was disabled previously. Re-initialize container socket.
+ atrace_init_container_sock();
+ } else if (!enabled && already_enabled) {
+ // Trace was enabled previously. Close container socket.
+ atrace_close_container_sock();
+ }
+ }
+ atomic_store_explicit(&atrace_is_enabled, enabled, memory_order_release);
+ pthread_mutex_unlock(&atrace_enabling_mutex);
+ atrace_update_tags();
+}
+
+static void atrace_init_once()
+{
+ atrace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY | O_CLOEXEC);
+ if (atrace_marker_fd < 0) {
+ // We're in container, ftrace may be disabled. In such case, we use the
+ // socket to write trace event.
+
+ // Protect the initialization of container socket from
+ // atrace_set_tracing_enabled.
+ pthread_mutex_lock(&atrace_enabling_mutex);
+ atrace_use_container_sock = true;
+ bool success = false;
+ if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
+ success = atrace_init_container_sock();
+ }
+ pthread_mutex_unlock(&atrace_enabling_mutex);
+
+ if (!success) {
+ atrace_enabled_tags = 0;
+ goto done;
+ }
+ }
+ atrace_enabled_tags = atrace_get_property();
+
+done:
+ atomic_store_explicit(&atrace_is_ready, true, memory_order_release);
+}
+
+void atrace_setup()
+{
+ pthread_once(&atrace_once_control, atrace_init_once);
+}
+
+static inline uint64_t gettime(clockid_t clk_id)
+{
+ struct timespec ts;
+ clock_gettime(clk_id, &ts);
+ return ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
+}
+
+// Write trace events to container trace file. Note that we need to amend tid and time information
+// here comparing to normal ftrace, where those informations are added by kernel.
+#define WRITE_MSG_IN_CONTAINER_LOCKED(ph, sep_before_name, value_format, name, value) { \
+ char buf[CONTAINER_ATRACE_MESSAGE_LENGTH]; \
+ int pid = getpid(); \
+ int tid = gettid(); \
+ uint64_t ts = gettime(CLOCK_MONOTONIC); \
+ uint64_t tts = gettime(CLOCK_THREAD_CPUTIME_ID); \
+ int len = snprintf( \
+ buf, sizeof(buf), \
+ ph "|%d|%d|%" PRIu64 "|%" PRIu64 sep_before_name "%s" value_format, \
+ pid, tid, ts, tts, name, value); \
+ if (len >= (int) sizeof(buf)) { \
+ int name_len = strlen(name) - (len - sizeof(buf)) - 1; \
+ /* Truncate the name to make the message fit. */ \
+ if (name_len > 0) { \
+ ALOGW("Truncated name in %s: %s\n", __FUNCTION__, name); \
+ len = snprintf( \
+ buf, sizeof(buf), \
+ ph "|%d|%d|%" PRIu64 "|%" PRIu64 sep_before_name "%.*s" value_format, \
+ pid, tid, ts, tts, name_len, name, value); \
+ } else { \
+ /* Data is still too long. Drop it. */ \
+ ALOGW("Data is too long in %s: %s\n", __FUNCTION__, name); \
+ len = 0; \
+ } \
+ } \
+ if (len > 0) { \
+ write(atrace_container_sock_fd, buf, len); \
+ } \
+}
+
+#define WRITE_MSG_IN_CONTAINER(ph, sep_before_name, value_format, name, value) { \
+ pthread_rwlock_rdlock(&atrace_container_sock_rwlock); \
+ if (atrace_container_sock_fd != -1) { \
+ WRITE_MSG_IN_CONTAINER_LOCKED(ph, sep_before_name, value_format, name, value); \
+ } \
+ pthread_rwlock_unlock(&atrace_container_sock_rwlock); \
+}
+
+void atrace_begin_body(const char* name)
+{
+ if (CC_LIKELY(atrace_use_container_sock)) {
+ WRITE_MSG_IN_CONTAINER("B", "|", "%s", name, "");
+ return;
+ }
+
+ if (atrace_marker_fd < 0) return;
+
+ WRITE_MSG("B|%d|", "%s", name, "");
+}
+
+void atrace_end_body()
+{
+ if (CC_LIKELY(atrace_use_container_sock)) {
+ WRITE_MSG_IN_CONTAINER("E", "", "%s", "", "");
+ return;
+ }
+
+ if (atrace_marker_fd < 0) return;
+
+ WRITE_MSG("E|%d", "%s", "", "");
+}
+
+void atrace_async_begin_body(const char* name, int32_t cookie)
+{
+ if (CC_LIKELY(atrace_use_container_sock)) {
+ WRITE_MSG_IN_CONTAINER("S", "|", "|%d", name, cookie);
+ return;
+ }
+
+ if (atrace_marker_fd < 0) return;
+
+ WRITE_MSG("S|%d|", "|%" PRId32, name, cookie);
+}
+
+void atrace_async_end_body(const char* name, int32_t cookie)
+{
+ if (CC_LIKELY(atrace_use_container_sock)) {
+ WRITE_MSG_IN_CONTAINER("F", "|", "|%d", name, cookie);
+ return;
+ }
+
+ if (atrace_marker_fd < 0) return;
+
+ WRITE_MSG("F|%d|", "|%" PRId32, name, cookie);
+}
+
+void atrace_int_body(const char* name, int32_t value)
+{
+ if (CC_LIKELY(atrace_use_container_sock)) {
+ WRITE_MSG_IN_CONTAINER("C", "|", "|%" PRId32, name, value);
+ return;
+ }
+
+ if (atrace_marker_fd < 0) return;
+
+ WRITE_MSG("C|%d|", "|%" PRId32, name, value);
+}
+
+void atrace_int64_body(const char* name, int64_t value)
+{
+ if (CC_LIKELY(atrace_use_container_sock)) {
+ WRITE_MSG_IN_CONTAINER("C", "|", "|%" PRId64, name, value);
+ return;
+ }
+
+ if (atrace_marker_fd < 0) return;
+
+ WRITE_MSG("C|%d|", "|%" PRId64, name, value);
+}
diff --git a/libcutils/trace-dev.c b/libcutils/trace-dev.c
index d45e5a9..4468e83 100644
--- a/libcutils/trace-dev.c
+++ b/libcutils/trace-dev.c
@@ -14,47 +14,9 @@
* limitations under the License.
*/
-#define LOG_TAG "cutils-trace"
+#include "trace-dev.inc"
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <pthread.h>
-#include <stdatomic.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include <cutils/compiler.h>
-#include <cutils/properties.h>
-#include <cutils/trace.h>
-#include <log/log.h>
-#include <log/log_properties.h>
-
-/**
- * Maximum size of a message that can be logged to the trace buffer.
- * Note this message includes a tag, the pid, and the string given as the name.
- * Names should be kept short to get the most use of the trace buffer.
- */
-#define ATRACE_MESSAGE_LENGTH 1024
-
-atomic_bool atrace_is_ready = ATOMIC_VAR_INIT(false);
-int atrace_marker_fd = -1;
-uint64_t atrace_enabled_tags = ATRACE_TAG_NOT_READY;
-static bool atrace_is_debuggable = false;
-static atomic_bool atrace_is_enabled = ATOMIC_VAR_INIT(true);
-static pthread_once_t atrace_once_control = PTHREAD_ONCE_INIT;
-static pthread_mutex_t atrace_tags_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-// Set whether this process is debuggable, which determines whether
-// application-level tracing is allowed when the ro.debuggable system property
-// is not set to '1'.
-void atrace_set_debuggable(bool debuggable)
-{
- atrace_is_debuggable = debuggable;
- atrace_update_tags();
-}
+static pthread_once_t atrace_once_control = PTHREAD_ONCE_INIT;
// Set whether tracing is enabled in this process. This is used to prevent
// the Zygote process from tracing.
@@ -64,101 +26,6 @@
atrace_update_tags();
}
-// Check whether the given command line matches one of the comma-separated
-// values listed in the app_cmdlines property.
-static bool atrace_is_cmdline_match(const char* cmdline)
-{
- int count = property_get_int32("debug.atrace.app_number", 0);
-
- char buf[PROPERTY_KEY_MAX];
- char value[PROPERTY_VALUE_MAX];
-
- for (int i = 0; i < count; i++) {
- snprintf(buf, sizeof(buf), "debug.atrace.app_%d", i);
- property_get(buf, value, "");
- if (strcmp(value, cmdline) == 0) {
- return true;
- }
- }
-
- return false;
-}
-
-// Determine whether application-level tracing is enabled for this process.
-static bool atrace_is_app_tracing_enabled()
-{
- bool sys_debuggable = __android_log_is_debuggable();
- bool result = false;
-
- if (sys_debuggable || atrace_is_debuggable) {
- // Check whether tracing is enabled for this process.
- FILE * file = fopen("/proc/self/cmdline", "re");
- if (file) {
- char cmdline[4096];
- if (fgets(cmdline, sizeof(cmdline), file)) {
- result = atrace_is_cmdline_match(cmdline);
- } else {
- ALOGE("Error reading cmdline: %s (%d)", strerror(errno), errno);
- }
- fclose(file);
- } else {
- ALOGE("Error opening /proc/self/cmdline: %s (%d)", strerror(errno),
- errno);
- }
- }
-
- return result;
-}
-
-// Read the sysprop and return the value tags should be set to
-static uint64_t atrace_get_property()
-{
- char value[PROPERTY_VALUE_MAX];
- char *endptr;
- uint64_t tags;
-
- property_get("debug.atrace.tags.enableflags", value, "0");
- errno = 0;
- tags = strtoull(value, &endptr, 0);
- if (value[0] == '\0' || *endptr != '\0') {
- ALOGE("Error parsing trace property: Not a number: %s", value);
- return 0;
- } else if (errno == ERANGE || tags == ULLONG_MAX) {
- ALOGE("Error parsing trace property: Number too large: %s", value);
- return 0;
- }
-
- // Only set the "app" tag if this process was selected for app-level debug
- // tracing.
- if (atrace_is_app_tracing_enabled()) {
- tags |= ATRACE_TAG_APP;
- } else {
- tags &= ~ATRACE_TAG_APP;
- }
-
- return (tags | ATRACE_TAG_ALWAYS) & ATRACE_TAG_VALID_MASK;
-}
-
-// Update tags if tracing is ready. Useful as a sysprop change callback.
-void atrace_update_tags()
-{
- uint64_t tags;
- if (CC_UNLIKELY(atomic_load_explicit(&atrace_is_ready, memory_order_acquire))) {
- if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
- tags = atrace_get_property();
- pthread_mutex_lock(&atrace_tags_mutex);
- atrace_enabled_tags = tags;
- pthread_mutex_unlock(&atrace_tags_mutex);
- } else {
- // Tracing is disabled for this process, so we simply don't
- // initialize the tags.
- pthread_mutex_lock(&atrace_tags_mutex);
- atrace_enabled_tags = ATRACE_TAG_NOT_READY;
- pthread_mutex_unlock(&atrace_tags_mutex);
- }
- }
-}
-
static void atrace_init_once()
{
atrace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY | O_CLOEXEC);
@@ -181,54 +48,30 @@
void atrace_begin_body(const char* name)
{
- char buf[ATRACE_MESSAGE_LENGTH];
-
- int len = snprintf(buf, sizeof(buf), "B|%d|%s", getpid(), name);
- if (len >= (int) sizeof(buf)) {
- ALOGW("Truncated name in %s: %s\n", __FUNCTION__, name);
- len = sizeof(buf) - 1;
- }
- write(atrace_marker_fd, buf, len);
+ WRITE_MSG("B|%d|", "%s", name, "");
}
void atrace_end_body()
{
- char c = 'E';
- write(atrace_marker_fd, &c, 1);
-}
-
-#define WRITE_MSG(format_begin, format_end, pid, name, value) { \
- char buf[ATRACE_MESSAGE_LENGTH]; \
- int len = snprintf(buf, sizeof(buf), format_begin "%s" format_end, pid, \
- name, value); \
- if (len >= (int) sizeof(buf)) { \
- /* Given the sizeof(buf), and all of the current format buffers, \
- * it is impossible for name_len to be < 0 if len >= sizeof(buf). */ \
- int name_len = strlen(name) - (len - sizeof(buf)) - 1; \
- /* Truncate the name to make the message fit. */ \
- ALOGW("Truncated name in %s: %s\n", __FUNCTION__, name); \
- len = snprintf(buf, sizeof(buf), format_begin "%.*s" format_end, pid, \
- name_len, name, value); \
- } \
- write(atrace_marker_fd, buf, len); \
+ WRITE_MSG("E|%d", "%s", "", "");
}
void atrace_async_begin_body(const char* name, int32_t cookie)
{
- WRITE_MSG("S|%d|", "|%" PRId32, getpid(), name, cookie);
+ WRITE_MSG("S|%d|", "|%" PRId32, name, cookie);
}
void atrace_async_end_body(const char* name, int32_t cookie)
{
- WRITE_MSG("F|%d|", "|%" PRId32, getpid(), name, cookie);
+ WRITE_MSG("F|%d|", "|%" PRId32, name, cookie);
}
void atrace_int_body(const char* name, int32_t value)
{
- WRITE_MSG("C|%d|", "|%" PRId32, getpid(), name, value);
+ WRITE_MSG("C|%d|", "|%" PRId32, name, value);
}
void atrace_int64_body(const char* name, int64_t value)
{
- WRITE_MSG("C|%d|", "|%" PRId64, getpid(), name, value);
+ WRITE_MSG("C|%d|", "|%" PRId64, name, value);
}
diff --git a/libcutils/trace-dev.inc b/libcutils/trace-dev.inc
new file mode 100644
index 0000000..f32330a
--- /dev/null
+++ b/libcutils/trace-dev.inc
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef __TRACE_DEV_INC
+#define __TRACE_DEV_INC
+
+#define LOG_TAG "cutils-trace"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <pthread.h>
+#include <stdatomic.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <cutils/compiler.h>
+#include <cutils/properties.h>
+#include <cutils/trace.h>
+#include <log/log.h>
+#include <log/log_properties.h>
+
+/**
+ * Maximum size of a message that can be logged to the trace buffer.
+ * Note this message includes a tag, the pid, and the string given as the name.
+ * Names should be kept short to get the most use of the trace buffer.
+ */
+#define ATRACE_MESSAGE_LENGTH 1024
+
+atomic_bool atrace_is_ready = ATOMIC_VAR_INIT(false);
+int atrace_marker_fd = -1;
+uint64_t atrace_enabled_tags = ATRACE_TAG_NOT_READY;
+static bool atrace_is_debuggable = false;
+static atomic_bool atrace_is_enabled = ATOMIC_VAR_INIT(true);
+static pthread_mutex_t atrace_tags_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+// Set whether this process is debuggable, which determines whether
+// application-level tracing is allowed when the ro.debuggable system property
+// is not set to '1'.
+void atrace_set_debuggable(bool debuggable)
+{
+ atrace_is_debuggable = debuggable;
+ atrace_update_tags();
+}
+
+// Check whether the given command line matches one of the comma-separated
+// values listed in the app_cmdlines property.
+static bool atrace_is_cmdline_match(const char* cmdline)
+{
+ int count = property_get_int32("debug.atrace.app_number", 0);
+
+ char buf[PROPERTY_KEY_MAX];
+ char value[PROPERTY_VALUE_MAX];
+
+ for (int i = 0; i < count; i++) {
+ snprintf(buf, sizeof(buf), "debug.atrace.app_%d", i);
+ property_get(buf, value, "");
+ if (strcmp(value, cmdline) == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Determine whether application-level tracing is enabled for this process.
+static bool atrace_is_app_tracing_enabled()
+{
+ bool sys_debuggable = __android_log_is_debuggable();
+ bool result = false;
+
+ if (sys_debuggable || atrace_is_debuggable) {
+ // Check whether tracing is enabled for this process.
+ FILE * file = fopen("/proc/self/cmdline", "re");
+ if (file) {
+ char cmdline[4096];
+ if (fgets(cmdline, sizeof(cmdline), file)) {
+ result = atrace_is_cmdline_match(cmdline);
+ } else {
+ ALOGE("Error reading cmdline: %s (%d)", strerror(errno), errno);
+ }
+ fclose(file);
+ } else {
+ ALOGE("Error opening /proc/self/cmdline: %s (%d)", strerror(errno),
+ errno);
+ }
+ }
+
+ return result;
+}
+
+// Read the sysprop and return the value tags should be set to
+static uint64_t atrace_get_property()
+{
+ char value[PROPERTY_VALUE_MAX];
+ char *endptr;
+ uint64_t tags;
+
+ property_get("debug.atrace.tags.enableflags", value, "0");
+ errno = 0;
+ tags = strtoull(value, &endptr, 0);
+ if (value[0] == '\0' || *endptr != '\0') {
+ ALOGE("Error parsing trace property: Not a number: %s", value);
+ return 0;
+ } else if (errno == ERANGE || tags == ULLONG_MAX) {
+ ALOGE("Error parsing trace property: Number too large: %s", value);
+ return 0;
+ }
+
+ // Only set the "app" tag if this process was selected for app-level debug
+ // tracing.
+ if (atrace_is_app_tracing_enabled()) {
+ tags |= ATRACE_TAG_APP;
+ } else {
+ tags &= ~ATRACE_TAG_APP;
+ }
+
+ return (tags | ATRACE_TAG_ALWAYS) & ATRACE_TAG_VALID_MASK;
+}
+
+// Update tags if tracing is ready. Useful as a sysprop change callback.
+void atrace_update_tags()
+{
+ uint64_t tags;
+ if (CC_UNLIKELY(atomic_load_explicit(&atrace_is_ready, memory_order_acquire))) {
+ if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
+ tags = atrace_get_property();
+ pthread_mutex_lock(&atrace_tags_mutex);
+ atrace_enabled_tags = tags;
+ pthread_mutex_unlock(&atrace_tags_mutex);
+ } else {
+ // Tracing is disabled for this process, so we simply don't
+ // initialize the tags.
+ pthread_mutex_lock(&atrace_tags_mutex);
+ atrace_enabled_tags = ATRACE_TAG_NOT_READY;
+ pthread_mutex_unlock(&atrace_tags_mutex);
+ }
+ }
+}
+
+#define WRITE_MSG(format_begin, format_end, name, value) { \
+ char buf[ATRACE_MESSAGE_LENGTH]; \
+ int pid = getpid(); \
+ int len = snprintf(buf, sizeof(buf), format_begin "%s" format_end, pid, \
+ name, value); \
+ if (len >= (int) sizeof(buf)) { \
+ /* Given the sizeof(buf), and all of the current format buffers, \
+ * it is impossible for name_len to be < 0 if len >= sizeof(buf). */ \
+ int name_len = strlen(name) - (len - sizeof(buf)) - 1; \
+ /* Truncate the name to make the message fit. */ \
+ ALOGW("Truncated name in %s: %s\n", __FUNCTION__, name); \
+ len = snprintf(buf, sizeof(buf), format_begin "%.*s" format_end, pid, \
+ name_len, name, value); \
+ } \
+ write(atrace_marker_fd, buf, len); \
+}
+
+#endif // __TRACE_DEV_INC
diff --git a/liblog/include/log/log_main.h b/liblog/include/log/log_main.h
index da16158..5a3f04c 100644
--- a/liblog/include/log/log_main.h
+++ b/liblog/include/log/log_main.h
@@ -355,11 +355,11 @@
#if LOG_NDEBUG /* Production */
#define android_testLog(prio, tag) \
- (__android_log_is_loggable_len(prio, tag, (tag && *tag) ? strlen(tag) : 0, \
+ (__android_log_is_loggable_len(prio, tag, ((tag) && *(tag)) ? strlen(tag) : 0, \
ANDROID_LOG_DEBUG) != 0)
#else
#define android_testLog(prio, tag) \
- (__android_log_is_loggable_len(prio, tag, (tag && *tag) ? strlen(tag) : 0, \
+ (__android_log_is_loggable_len(prio, tag, ((tag) && *(tag)) ? strlen(tag) : 0, \
ANDROID_LOG_VERBOSE) != 0)
#endif
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 46ec5ef..e2d5aeb 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -105,7 +105,7 @@
}
#if (defined(__ANDROID__) && defined(USING_LOGGER_DEFAULT))
-static std::string popenToString(std::string command) {
+static std::string popenToString(const std::string& command) {
std::string ret;
FILE* fp = popen(command.c_str(), "r");
@@ -129,17 +129,17 @@
static bool isLogdwActive() {
std::string logdwSignature =
popenToString("grep /dev/socket/logdw /proc/net/unix");
- size_t beginning = logdwSignature.find(" ");
+ size_t beginning = logdwSignature.find(' ');
if (beginning == std::string::npos) return true;
- beginning = logdwSignature.find(" ", beginning + 1);
+ beginning = logdwSignature.find(' ', beginning + 1);
if (beginning == std::string::npos) return true;
- size_t end = logdwSignature.find(" ", beginning + 1);
+ size_t end = logdwSignature.find(' ', beginning + 1);
if (end == std::string::npos) return true;
- end = logdwSignature.find(" ", end + 1);
+ end = logdwSignature.find(' ', end + 1);
if (end == std::string::npos) return true;
- end = logdwSignature.find(" ", end + 1);
+ end = logdwSignature.find(' ', end + 1);
if (end == std::string::npos) return true;
- end = logdwSignature.find(" ", end + 1);
+ end = logdwSignature.find(' ', end + 1);
if (end == std::string::npos) return true;
std::string allLogdwEndpoints = popenToString(
"grep ' 00000002" + logdwSignature.substr(beginning, end - beginning) +
@@ -159,7 +159,7 @@
// NB: fgrep with multiple strings is broken in Android
for (beginning = 0;
- (end = allLogdwEndpoints.find("\n", beginning)) != std::string::npos;
+ (end = allLogdwEndpoints.find('\n', beginning)) != std::string::npos;
beginning = end + 1) {
if (myPidFds.find(allLogdwEndpoints.substr(beginning, end - beginning)) !=
std::string::npos)
@@ -3170,7 +3170,7 @@
return (offset != std::string::npos) &&
((offset = content.find_first_not_of(" \t", offset + strlen(needle))) !=
std::string::npos) &&
- (content.find_first_not_of("0", offset) != offset);
+ (content.find_first_not_of('0', offset) != offset);
}
// must not be: '<needle:> 0 kB'
@@ -3239,7 +3239,7 @@
filename = android::base::StringPrintf("/proc/%d/comm", pid);
android::base::ReadFileToString(filename, &content);
content = android::base::StringPrintf(
- "%d:%s", pid, content.substr(0, content.find("\n")).c_str());
+ "%d:%s", pid, content.substr(0, content.find('\n')).c_str());
EXPECT_TRUE(IsOk(shared_ok, content));
EXPECT_TRUE(IsOk(private_ok, content));
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 04c4cfa..b971a9e 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -30,19 +30,11 @@
enabled: false,
},
},
-
- arch: {
- mips: {
- enabled: false,
- },
- mips64: {
- enabled: false,
- },
- },
}
cc_library {
name: "libunwindstack",
+ vendor_available: true,
defaults: ["libunwindstack_flags"],
export_include_dirs: ["include"],
diff --git a/libunwindstack/DwarfEhFrame.cpp b/libunwindstack/DwarfEhFrame.cpp
index d0b35c3..db8f558 100644
--- a/libunwindstack/DwarfEhFrame.cpp
+++ b/libunwindstack/DwarfEhFrame.cpp
@@ -100,7 +100,7 @@
fde_info_.erase(index);
return nullptr;
}
- info->pc = value;
+ info->pc = value + 4;
return info;
}
@@ -175,7 +175,7 @@
last_error_ = DWARF_ERROR_MEMORY_INVALID;
return false;
}
- info->pc = value;
+ info->pc = value + 4;
if (pc < info->pc) {
if (prev_info == nullptr) {
diff --git a/libunwindstack/DwarfMemory.cpp b/libunwindstack/DwarfMemory.cpp
index b6e0412..901f492 100644
--- a/libunwindstack/DwarfMemory.cpp
+++ b/libunwindstack/DwarfMemory.cpp
@@ -235,7 +235,7 @@
return false;
}
- return AdjustEncodedValue(encoding & 0xf0, value);
+ return AdjustEncodedValue(encoding & 0x70, value);
}
// Instantiate all of the needed template functions.
diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h
index a97ca2b..26485ae 100644
--- a/libunwindstack/include/unwindstack/DwarfSection.h
+++ b/libunwindstack/include/unwindstack/DwarfSection.h
@@ -106,7 +106,7 @@
DwarfMemory memory_;
DwarfError last_error_;
- uint64_t fde_count_;
+ uint64_t fde_count_ = 0;
std::unordered_map<uint64_t, DwarfFde> fde_entries_;
std::unordered_map<uint64_t, DwarfCie> cie_entries_;
std::unordered_map<uint64_t, dwarf_loc_regs_t> cie_loc_regs_;
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index 2a97dde..1854767 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -41,6 +41,7 @@
uint64_t elf_offset;
Memory* CreateMemory(pid_t pid);
+ // This function guarantees it will never return nullptr.
Elf* GetElf(pid_t pid, bool init_gnu_debugdata = false);
};
diff --git a/libunwindstack/include/unwindstack/RegsGetLocal.h b/libunwindstack/include/unwindstack/RegsGetLocal.h
index ffec213..d1461d8 100644
--- a/libunwindstack/include/unwindstack/RegsGetLocal.h
+++ b/libunwindstack/include/unwindstack/RegsGetLocal.h
@@ -97,6 +97,11 @@
regs->SetFromRaw();
}
+#elif defined(__mips__)
+
+// Stub to allow mips to build.
+void RegsGetLocal(Regs*) {}
+
#endif
} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfEhFrameTest.cpp b/libunwindstack/tests/DwarfEhFrameTest.cpp
index e9501e3..07159b0 100644
--- a/libunwindstack/tests/DwarfEhFrameTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameTest.cpp
@@ -124,7 +124,7 @@
auto info = this->eh_frame_->GetFdeInfoFromIndex(2);
ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(0x1380U, info->pc);
+ EXPECT_EQ(0x1384U, info->pc);
EXPECT_EQ(0x1540U, info->offset);
}
@@ -139,7 +139,7 @@
auto info = this->eh_frame_->GetFdeInfoFromIndex(2);
ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(0x3340U, info->pc);
+ EXPECT_EQ(0x3344U, info->pc);
EXPECT_EQ(0x3500U, info->offset);
}
@@ -153,7 +153,7 @@
auto info = this->eh_frame_->GetFdeInfoFromIndex(2);
ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(0x340U, info->pc);
+ EXPECT_EQ(0x344U, info->pc);
EXPECT_EQ(0x500U, info->offset);
// Clear the memory so that this will fail if it doesn't read cached data.
@@ -161,7 +161,7 @@
info = this->eh_frame_->GetFdeInfoFromIndex(2);
ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(0x340U, info->pc);
+ EXPECT_EQ(0x344U, info->pc);
EXPECT_EQ(0x500U, info->offset);
}
@@ -220,18 +220,18 @@
// Verify that if entries is zero, that it fails.
uint64_t fde_offset;
- ASSERT_FALSE(this->eh_frame_->GetFdeOffsetSequential(0x340, &fde_offset));
+ ASSERT_FALSE(this->eh_frame_->GetFdeOffsetSequential(0x344, &fde_offset));
this->eh_frame_->TestSetCurEntriesOffset(0x1040);
- ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x340, &fde_offset));
+ ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x344, &fde_offset));
EXPECT_EQ(0x500U, fde_offset);
- ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x440, &fde_offset));
+ ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x444, &fde_offset));
EXPECT_EQ(0x600U, fde_offset);
// Expect that the data is cached so no more memory reads will occur.
this->memory_.Clear();
- ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x440, &fde_offset));
+ ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x444, &fde_offset));
EXPECT_EQ(0x600U, fde_offset);
}
diff --git a/libunwindstack/tests/DwarfMemoryTest.cpp b/libunwindstack/tests/DwarfMemoryTest.cpp
index 08fe7cf..f12d2fe 100644
--- a/libunwindstack/tests/DwarfMemoryTest.cpp
+++ b/libunwindstack/tests/DwarfMemoryTest.cpp
@@ -52,6 +52,8 @@
void ReadEncodedValue_non_zero_adjust();
template <typename AddressType>
void ReadEncodedValue_overflow();
+ template <typename AddressType>
+ void ReadEncodedValue_high_bit_set();
MemoryFake memory_;
std::unique_ptr<DwarfMemory> dwarf_mem_;
@@ -435,6 +437,26 @@
ReadEncodedValue_overflow<uint64_t>();
}
+template <typename AddressType>
+void DwarfMemoryTest::ReadEncodedValue_high_bit_set() {
+ uint64_t value;
+ memory_.SetData32(0, 0x15234);
+ ASSERT_FALSE(dwarf_mem_->ReadEncodedValue<AddressType>(0xc3, &value));
+
+ dwarf_mem_->set_func_offset(0x60000);
+ dwarf_mem_->set_cur_offset(0);
+ ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0xc3, &value));
+ ASSERT_EQ(0x75234U, value);
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_high_bit_set_uint32_t) {
+ ReadEncodedValue_high_bit_set<uint32_t>();
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_high_bit_set_uint64_t) {
+ ReadEncodedValue_high_bit_set<uint64_t>();
+}
+
TEST_F(DwarfMemoryTest, AdjustEncodedValue_absptr) {
uint64_t value = 0x1234;
ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x00, &value));
diff --git a/libutils/include/utils/Singleton.h b/libutils/include/utils/Singleton.h
index a989a47..abb72f5 100644
--- a/libutils/include/utils/Singleton.h
+++ b/libutils/include/utils/Singleton.h
@@ -82,7 +82,7 @@
#define ANDROID_SINGLETON_STATIC_INSTANCE(TYPE) \
template<> ::android::Mutex \
(::android::Singleton< TYPE >::sLock)(::android::Mutex::PRIVATE); \
- template<> TYPE* ::android::Singleton< TYPE >::sInstance(0); \
+ template<> TYPE* ::android::Singleton< TYPE >::sInstance(0); /* NOLINT */ \
template class ::android::Singleton< TYPE >;
diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h
index f6433a8..cb3d338 100644
--- a/libutils/include/utils/String16.h
+++ b/libutils/include/utils/String16.h
@@ -67,7 +67,6 @@
inline const char16_t* string() const;
-//TODO(b/35363681): remove
private:
static inline std::string std_string(const String16& str);
public:
diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h
index f5f9219..1f3e5d8 100644
--- a/libutils/include/utils/String8.h
+++ b/libutils/include/utils/String8.h
@@ -67,7 +67,6 @@
inline const char* c_str() const;
inline const char* string() const;
-// TODO(b/35363681): remove
private:
static inline std::string std_string(const String8& str);
public:
diff --git a/logcat/Android.bp b/logcat/Android.bp
new file mode 100644
index 0000000..729c8ff
--- /dev/null
+++ b/logcat/Android.bp
@@ -0,0 +1,74 @@
+//
+// Copyright (C) 2006-2017 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.
+//
+
+cc_defaults {
+ name: "logcat_defaults",
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "liblog",
+ "libpcrecpp",
+ ],
+ logtags: ["event.logtags"],
+}
+
+cc_library {
+ name: "liblogcat",
+
+ defaults: ["logcat_defaults"],
+ srcs: [
+ "logcat.cpp",
+ "getopt_long.cpp",
+ "logcat_system.cpp",
+ ],
+ export_include_dirs: ["include"],
+}
+
+cc_binary {
+ name: "logcat",
+
+ defaults: ["logcat_defaults"],
+ shared_libs: ["liblogcat"],
+ srcs: [
+ "logcat_main.cpp",
+ ],
+}
+
+cc_binary {
+ name: "logcatd",
+
+ defaults: ["logcat_defaults"],
+ shared_libs: ["liblogcat"],
+ srcs: [
+ "logcatd_main.cpp",
+ ],
+}
+
+cc_prebuilt_binary {
+ name: "logpersist.start",
+ srcs: ["logpersist"],
+ init_rc: ["logcatd.rc"],
+ symlinks: ["logpersist.stop", "logpersist.cat"],
+ strip: {
+ none: true,
+ }
+}
diff --git a/logcat/Android.mk b/logcat/Android.mk
index 4e11ca9..a716993 100644
--- a/logcat/Android.mk
+++ b/logcat/Android.mk
@@ -2,48 +2,4 @@
LOCAL_PATH := $(call my-dir)
-logcatLibs := liblog libbase libcutils libpcrecpp
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := logcat
-LOCAL_SRC_FILES := logcat_main.cpp event.logtags
-LOCAL_SHARED_LIBRARIES := liblogcat $(logcatLibs)
-LOCAL_CFLAGS := -Werror
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := logcatd
-LOCAL_MODULE_TAGS := debug
-LOCAL_SRC_FILES := logcatd_main.cpp event.logtags
-LOCAL_SHARED_LIBRARIES := liblogcat $(logcatLibs)
-LOCAL_CFLAGS := -Werror
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := liblogcat
-LOCAL_SRC_FILES := logcat.cpp getopt_long.cpp logcat_system.cpp
-LOCAL_SHARED_LIBRARIES := $(logcatLibs)
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -Werror
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := logpersist.start
-LOCAL_MODULE_TAGS := debug
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_INIT_RC := logcatd.rc
-LOCAL_MODULE_PATH := $(bin_dir)
-LOCAL_SRC_FILES := logpersist
-ALL_TOOLS := logpersist.start logpersist.stop logpersist.cat
-LOCAL_POST_INSTALL_CMD := $(hide) $(foreach t,$(filter-out $(LOCAL_MODULE),$(ALL_TOOLS)),ln -sf $(LOCAL_MODULE) $(TARGET_OUT)/bin/$(t);)
-include $(BUILD_PREBUILT)
-
include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index f64196f..3d56472 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -1019,7 +1019,6 @@
break;
case 'm': {
- char* end = nullptr;
if (!getSizeTArg(optctx.optarg, &context->maxCount)) {
logcat_panic(context, HELP_FALSE,
"-%c \"%s\" isn't an "
@@ -1182,7 +1181,6 @@
std::unique_ptr<char, void (*)(void*)> formats(
strdup(optctx.optarg), free);
char* arg = formats.get();
- unsigned idMask = 0;
char* sv = nullptr; // protect against -ENOMEM above
while (!!(arg = strtok_r(arg, delimiters, &sv))) {
err = setLogFormat(context, arg);
@@ -1256,7 +1254,7 @@
// example: "qemu_pipe,pipe:logcat"
// upon opening of /dev/qemu_pipe, the "pipe:logcat"
// string with trailing '\0' should be written to the fd
- size_t pos = devname.find(",");
+ size_t pos = devname.find(',');
if (pos != std::string::npos) {
pipePurpose = devname.substr(pos + 1);
devname = devname.substr(0, pos);
@@ -1733,7 +1731,7 @@
pthread_attr_setschedparam(&attr, ¶m);
pthread_attr_setschedpolicy(&attr, SCHED_BATCH);
if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
- int save_errno = errno;
+ save_errno = errno;
goto pthread_attr_exit;
}
@@ -1773,7 +1771,7 @@
context->retval = EXIT_SUCCESS;
if (pthread_create(&context->thr, &attr,
(void*(*)(void*))__logcat, context)) {
- int save_errno = errno;
+ save_errno = errno;
goto argv_exit;
}
pthread_attr_destroy(&attr);
diff --git a/logcat/tests/liblogcat_test.cpp b/logcat/tests/liblogcat_test.cpp
index 9e9a2c2..c8a00da 100644
--- a/logcat/tests/liblogcat_test.cpp
+++ b/logcat/tests/liblogcat_test.cpp
@@ -17,8 +17,8 @@
#include <log/logcat.h>
#define logcat_define(context) android_logcat_context context
-#define logcat_popen(context, command) android_logcat_popen(&context, command)
-#define logcat_pclose(context, fp) android_logcat_pclose(&context, fp)
+#define logcat_popen(context, command) android_logcat_popen(&(context), command)
+#define logcat_pclose(context, fp) android_logcat_pclose(&(context), fp)
#define logcat_system(command) android_logcat_system(command)
#define logcat liblogcat
diff --git a/rootdir/asan.options b/rootdir/asan.options
index d728f12..a264d2d 100644
--- a/rootdir/asan.options
+++ b/rootdir/asan.options
@@ -5,3 +5,4 @@
detect_container_overflow=0
abort_on_error=1
include_if_exists=/system/asan.options.%b
+include_if_exists=/data/asan/system/asan.options.%b
diff --git a/rootdir/etc/public.libraries.android.txt b/rootdir/etc/public.libraries.android.txt
index e6c94ff..e70ed51 100644
--- a/rootdir/etc/public.libraries.android.txt
+++ b/rootdir/etc/public.libraries.android.txt
@@ -1,3 +1,4 @@
+# See https://android.googlesource.com/platform/ndk/+/master/docs/PlatformApis.md
libandroid.so
libc.so
libcamera2ndk.so
diff --git a/rootdir/etc/public.libraries.wear.txt b/rootdir/etc/public.libraries.wear.txt
index 292730a..e494ee0 100644
--- a/rootdir/etc/public.libraries.wear.txt
+++ b/rootdir/etc/public.libraries.wear.txt
@@ -1,3 +1,4 @@
+# See https://android.googlesource.com/platform/ndk/+/master/docs/PlatformApis.md
libandroid.so
libc.so
libcamera2ndk.so
diff --git a/trusty/keymaster/trusty_keymaster_device.cpp b/trusty/keymaster/trusty_keymaster_device.cpp
index e2342f3..ff74146 100644
--- a/trusty/keymaster/trusty_keymaster_device.cpp
+++ b/trusty/keymaster/trusty_keymaster_device.cpp
@@ -577,7 +577,9 @@
return error_;
}
if (input && input->data_length > kMaximumFinishInputLength) {
- return KM_ERROR_INVALID_ARGUMENT;
+ ALOGE("%zu-byte input to finish; only %zu bytes allowed",
+ input->data_length, kMaximumFinishInputLength);
+ return KM_ERROR_INVALID_INPUT_LENGTH;
}
if (out_params) {
diff --git a/trusty/storage/tests/Android.bp b/trusty/storage/tests/Android.bp
index 3eff3f2..1e4fced 100644
--- a/trusty/storage/tests/Android.bp
+++ b/trusty/storage/tests/Android.bp
@@ -21,7 +21,6 @@
"-g",
"-Wall",
"-Werror",
- "-std=gnu++11",
"-Wno-missing-field-initializers",
],