Merge "sync: store the num_fences from first SYNC_IOC_FILE_INFO" into oc-mr1-dev
am: 3bb2dfd252
Change-Id: I780f2e1b64906c7bc0df3327a51288980938c7f9
diff --git a/adb/Android.mk b/adb/Android.mk
index 5913d94..5d6c418 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -108,7 +108,6 @@
sysdeps_win32_test.cpp \
include $(CLEAR_VARS)
-LOCAL_CLANG := true
LOCAL_MODULE := libadbd_usb
LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=0
LOCAL_SRC_FILES := daemon/usb.cpp
@@ -122,7 +121,6 @@
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
-LOCAL_CLANG := true
LOCAL_MODULE := libadbd
LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=0
LOCAL_SRC_FILES := \
@@ -171,7 +169,6 @@
include $(BUILD_HOST_STATIC_LIBRARY)
include $(CLEAR_VARS)
-LOCAL_CLANG := true
LOCAL_MODULE := adbd_test
LOCAL_CFLAGS := -DADB_HOST=0 $(LIBADB_CFLAGS)
LOCAL_SRC_FILES := \
@@ -330,8 +327,6 @@
include $(CLEAR_VARS)
-LOCAL_CLANG := true
-
LOCAL_SRC_FILES := \
daemon/main.cpp \
daemon/mdns.cpp \
diff --git a/base/Android.bp b/base/Android.bp
index b636dc3..1395756 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -39,7 +39,6 @@
cc_library {
name: "libbase",
vendor_available: true,
- clang: true,
host_supported: true,
srcs: [
"file.cpp",
@@ -109,7 +108,6 @@
cc_test {
name: "libbase_test",
host_supported: true,
- clang: true,
srcs: [
"endian_test.cpp",
"errors_test.cpp",
diff --git a/base/file.cpp b/base/file.cpp
index a2f2887..2f697a1 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -153,6 +153,37 @@
return true;
}
+#if defined(_WIN32)
+// Windows implementation of pread. Note that this DOES move the file descriptors read position,
+// but it does so atomically.
+static ssize_t pread(int fd, void* data, size_t byte_count, off64_t offset) {
+ DWORD bytes_read;
+ OVERLAPPED overlapped;
+ memset(&overlapped, 0, sizeof(OVERLAPPED));
+ overlapped.Offset = static_cast<DWORD>(offset);
+ overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);
+ if (!ReadFile(reinterpret_cast<HANDLE>(_get_osfhandle(fd)), data, static_cast<DWORD>(byte_count),
+ &bytes_read, &overlapped)) {
+ // In case someone tries to read errno (since this is masquerading as a POSIX call)
+ errno = EIO;
+ return -1;
+ }
+ return static_cast<ssize_t>(bytes_read);
+}
+#endif
+
+bool ReadFullyAtOffset(int fd, void* data, size_t byte_count, off64_t offset) {
+ uint8_t* p = reinterpret_cast<uint8_t*>(data);
+ while (byte_count > 0) {
+ ssize_t n = TEMP_FAILURE_RETRY(pread(fd, p, byte_count, offset));
+ if (n <= 0) return false;
+ p += n;
+ byte_count -= n;
+ offset += n;
+ }
+ return true;
+}
+
bool WriteFully(int fd, const void* data, size_t byte_count) {
const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
size_t remaining = byte_count;
diff --git a/base/include/android-base/file.h b/base/include/android-base/file.h
index 651f529..667d6fb 100644
--- a/base/include/android-base/file.h
+++ b/base/include/android-base/file.h
@@ -18,12 +18,18 @@
#define ANDROID_BASE_FILE_H
#include <sys/stat.h>
+#include <sys/types.h>
#include <string>
#if !defined(_WIN32) && !defined(O_BINARY)
#define O_BINARY 0
#endif
+#if defined(__APPLE__)
+/* Mac OS has always had a 64-bit off_t, so it doesn't have off64_t. */
+typedef off_t off64_t;
+#endif
+
namespace android {
namespace base {
@@ -42,6 +48,17 @@
#endif
bool ReadFully(int fd, void* data, size_t byte_count);
+
+// Reads `byte_count` bytes from the file descriptor at the specified offset.
+// Returns false if there was an IO error or EOF was reached before reading `byte_count` bytes.
+//
+// NOTE: On Linux/Mac, this function wraps pread, which provides atomic read support without
+// modifying the read pointer of the file descriptor. On Windows, however, the read pointer does
+// get modified. This means that ReadFullyAtOffset can be used concurrently with other calls to the
+// same function, but concurrently seeking or reading incrementally can lead to unexpected
+// behavior.
+bool ReadFullyAtOffset(int fd, void* data, size_t byte_count, off64_t offset);
+
bool WriteFully(int fd, const void* data, size_t byte_count);
bool RemoveFileIfExists(const std::string& path, std::string* err = nullptr);
diff --git a/bootstat/Android.bp b/bootstat/Android.bp
index bc90a6e..dd357ed 100644
--- a/bootstat/Android.bp
+++ b/bootstat/Android.bp
@@ -32,9 +32,6 @@
"liblog",
"libmetricslogger",
],
- whole_static_libs: ["libgtest_prod"],
- // Clang is required because of C++14
- clang: true,
}
// bootstat static library
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 9249343..007189d 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -15,7 +15,6 @@
libavb
include $(CLEAR_VARS)
-LOCAL_CLANG := true
LOCAL_SANITIZE := integer
LOCAL_SRC_FILES:= fs_mgr_main.cpp
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 91ed496..c9af421 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -249,6 +249,13 @@
le32_to_cpu(es->s_r_blocks_count_lo);
}
+static bool is_ext4_superblock_valid(const struct ext4_super_block* es) {
+ if (es->s_magic != EXT4_SUPER_MAGIC) return false;
+ if (es->s_rev_level != EXT4_DYNAMIC_REV && es->s_rev_level != EXT4_GOOD_OLD_REV) return false;
+ if (EXT4_INODES_PER_GROUP(es) == 0) return false;
+ return true;
+}
+
// Read the primary superblock from an ext4 filesystem. On failure return
// false. If it's not an ext4 filesystem, also set FS_STAT_EXT4_INVALID_MAGIC.
static bool read_ext4_superblock(const char* blk_device, struct ext4_super_block* sb, int* fs_stat) {
@@ -264,9 +271,8 @@
return false;
}
- if (sb->s_magic != EXT4_SUPER_MAGIC) {
- LINFO << "Invalid ext4 magic:0x" << std::hex << sb->s_magic << " "
- << "on '" << blk_device << "'";
+ if (!is_ext4_superblock_valid(sb)) {
+ LINFO << "Invalid ext4 superblock on '" << blk_device << "'";
// not a valid fs, tune2fs, fsck, and mount will all fail.
*fs_stat |= FS_STAT_EXT4_INVALID_MAGIC;
return false;
diff --git a/init/Android.bp b/init/Android.bp
index aaef7e9..0d7240e 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -67,10 +67,10 @@
"devices.cpp",
"firmware_handler.cpp",
"import_parser.cpp",
- "init_parser.cpp",
"log.cpp",
"parser.cpp",
"service.cpp",
+ "tokenizer.cpp",
"uevent_listener.cpp",
"ueventd_parser.cpp",
"util.cpp",
@@ -153,7 +153,6 @@
defaults: ["init_defaults"],
srcs: [
"devices_test.cpp",
- "init_parser_test.cpp",
"init_test.cpp",
"property_service_test.cpp",
"service_test.cpp",
diff --git a/init/Android.mk b/init/Android.mk
index 161256e..293df2f 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -75,6 +75,7 @@
libcutils \
libbase \
libc \
+ libseccomp_policy \
libselinux \
liblog \
libcrypto_utils \
@@ -97,5 +98,4 @@
ln -sf ../init $(TARGET_ROOT_OUT)/sbin/watchdogd
LOCAL_SANITIZE := signed-integer-overflow
-LOCAL_CLANG := true
include $(BUILD_EXECUTABLE)
diff --git a/init/action.h b/init/action.h
index ad15f3f..50cae71 100644
--- a/init/action.h
+++ b/init/action.h
@@ -24,8 +24,8 @@
#include <vector>
#include "builtins.h"
-#include "init_parser.h"
#include "keyword_map.h"
+#include "parser.h"
namespace android {
namespace init {
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 56d0ae2..ae54fa8 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -57,7 +57,7 @@
#include "action.h"
#include "bootchart.h"
#include "init.h"
-#include "init_parser.h"
+#include "parser.h"
#include "property_service.h"
#include "reboot.h"
#include "service.h"
@@ -124,31 +124,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 +163,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 +171,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) {
@@ -388,21 +408,15 @@
* start_index: index of the first path in the args list
*/
static void import_late(const std::vector<std::string>& args, size_t start_index, size_t end_index) {
- Parser& parser = Parser::GetInstance();
+ auto& action_manager = ActionManager::GetInstance();
+ 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.
- if (!parser.is_system_etc_init_loaded()) {
- parser.ParseConfig("/system/etc/init");
- parser.set_is_system_etc_init_loaded(true);
+ for (const auto& path : late_import_paths) {
+ parser.ParseConfig(path);
}
- if (!parser.is_vendor_etc_init_loaded()) {
- parser.ParseConfig("/vendor/etc/init");
- parser.set_is_vendor_etc_init_loaded(true);
- }
- if (!parser.is_odm_etc_init_loaded()) {
- parser.ParseConfig("/odm/etc/init");
- parser.set_is_odm_etc_init_loaded(true);
- }
+ late_import_paths.clear();
} else {
for (size_t i = start_index; i < end_index; ++i) {
parser.ParseConfig(args[i]);
@@ -603,7 +617,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;
@@ -614,7 +628,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;
@@ -624,7 +638,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;
diff --git a/init/import_parser.h b/init/import_parser.h
index b774c57..0d04e0e 100644
--- a/init/import_parser.h
+++ b/init/import_parser.h
@@ -17,11 +17,11 @@
#ifndef _INIT_IMPORT_PARSER_H
#define _INIT_IMPORT_PARSER_H
-#include "init_parser.h"
-
#include <string>
#include <vector>
+#include "parser.h"
+
namespace android {
namespace init {
diff --git a/init/init.cpp b/init/init.cpp
index 715dd72..5693b0f 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -23,6 +23,7 @@
#include <inttypes.h>
#include <libgen.h>
#include <paths.h>
+#include <seccomp_policy.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
@@ -52,18 +53,16 @@
#include <fstream>
#include <memory>
+#include <optional>
#include <vector>
-#include "action.h"
#include "bootchart.h"
#include "import_parser.h"
#include "init_first_stage.h"
-#include "init_parser.h"
#include "keychords.h"
#include "log.h"
#include "property_service.h"
#include "reboot.h"
-#include "service.h"
#include "signal_handler.h"
#include "ueventd.h"
#include "util.h"
@@ -86,7 +85,6 @@
static char qemu[32];
std::string default_console = "/dev/console";
-static time_t process_needs_restart_at;
const char *ENV[32];
@@ -97,11 +95,43 @@
static std::string wait_prop_value;
static bool shutting_down;
+std::vector<std::string> late_import_paths;
+
void DumpState() {
- ServiceManager::GetInstance().DumpState();
+ ServiceList::GetInstance().DumpState();
ActionManager::GetInstance().DumpState();
}
+Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {
+ Parser parser;
+
+ 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, ServiceList& service_list) {
+ Parser parser = CreateParser(action_manager, service_list);
+
+ std::string bootscript = GetProperty("ro.boot.init_rc", "");
+ if (bootscript.empty()) {
+ parser.ParseConfig("/init.rc");
+ if (!parser.ParseConfig("/system/etc/init")) {
+ late_import_paths.emplace_back("/system/etc/init");
+ }
+ if (!parser.ParseConfig("/vendor/etc/init")) {
+ late_import_paths.emplace_back("/vendor/etc/init");
+ }
+ if (!parser.ParseConfig("/odm/etc/init")) {
+ late_import_paths.emplace_back("/odm/etc/init");
+ }
+ } else {
+ parser.ParseConfig(bootscript);
+ }
+}
+
void register_epoll_handler(int fd, void (*fn)()) {
epoll_event ev;
ev.events = EPOLLIN;
@@ -189,16 +219,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;
@@ -554,6 +593,15 @@
return 0;
}
+static void global_seccomp() {
+ import_kernel_cmdline(false, [](const std::string& key, const std::string& value, bool in_qemu) {
+ if (key == "androidboot.seccomp" && value == "global" && !set_global_seccomp_filter()) {
+ LOG(ERROR) << "Failed to globally enable seccomp!";
+ panic();
+ }
+ });
+}
+
static void selinux_init_all_handles(void)
{
sehandle = selinux_android_file_context_handle();
@@ -1025,6 +1073,9 @@
SetInitAvbVersionInRecovery();
+ // Enable seccomp if global boot option was passed (otherwise it is enabled in zygote).
+ global_seccomp();
+
// Set up SELinux, loading the SELinux policy.
selinux_initialize(true);
@@ -1109,26 +1160,9 @@
Action::set_function_map(&function_map);
ActionManager& am = ActionManager::GetInstance();
- ServiceManager& sm = ServiceManager::GetInstance();
- Parser& parser = Parser::GetInstance();
+ ServiceList& sm = ServiceList::GetInstance();
- parser.AddSectionParser("service", std::make_unique<ServiceParser>(&sm));
- parser.AddSectionParser("on", std::make_unique<ActionParser>(&am));
- parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
- std::string bootscript = GetProperty("ro.boot.init_rc", "");
- if (bootscript.empty()) {
- parser.ParseConfig("/init.rc");
- parser.set_is_system_etc_init_loaded(
- parser.ParseConfig("/system/etc/init"));
- parser.set_is_vendor_etc_init_loaded(
- parser.ParseConfig("/vendor/etc/init"));
- parser.set_is_odm_etc_init_loaded(parser.ParseConfig("/odm/etc/init"));
- } else {
- parser.ParseConfig(bootscript);
- parser.set_is_system_etc_init_loaded(true);
- parser.set_is_vendor_etc_init_loaded(true);
- parser.set_is_odm_etc_init_loaded(true);
- }
+ LoadBootScripts(am, sm);
// Turning this on and letting the INFO logging be discarded adds 0.2s to
// Nexus 9 boot time, so it's disabled by default.
@@ -1167,16 +1201,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 aaab523..92b9b70 100644
--- a/init/init.h
+++ b/init/init.h
@@ -21,6 +21,10 @@
#include <selinux/label.h>
+#include "action.h"
+#include "parser.h"
+#include "service.h"
+
namespace android {
namespace init {
@@ -32,6 +36,10 @@
extern struct selabel_handle *sehandle;
extern struct selabel_handle *sehandle_prop;
+extern std::vector<std::string> late_import_paths;
+
+Parser CreateParser(ActionManager& action_manager, ServiceList& service_list);
+
void handle_control_message(const std::string& msg, const std::string& arg);
void property_changed(const std::string& name, const std::string& value);
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
deleted file mode 100644
index 9f7089b..0000000
--- a/init/init_parser.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 2010 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 "init_parser.h"
-
-#include <dirent.h>
-
-#include <android-base/chrono_utils.h>
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-
-#include "parser.h"
-#include "util.h"
-
-namespace android {
-namespace init {
-
-Parser::Parser() {
-}
-
-Parser& Parser::GetInstance() {
- static Parser instance;
- return instance;
-}
-
-void Parser::AddSectionParser(const std::string& name,
- std::unique_ptr<SectionParser> parser) {
- section_parsers_[name] = std::move(parser);
-}
-
-void Parser::AddSingleLineParser(const std::string& prefix, LineCallback callback) {
- line_callbacks_.emplace_back(prefix, callback);
-}
-
-void Parser::ParseData(const std::string& filename, const std::string& data) {
- //TODO: Use a parser with const input and remove this copy
- std::vector<char> data_copy(data.begin(), data.end());
- data_copy.push_back('\0');
-
- parse_state state;
- state.line = 0;
- state.ptr = &data_copy[0];
- state.nexttoken = 0;
-
- SectionParser* section_parser = nullptr;
- std::vector<std::string> args;
-
- for (;;) {
- switch (next_token(&state)) {
- case T_EOF:
- if (section_parser) {
- section_parser->EndSection();
- }
- return;
- case T_NEWLINE:
- state.line++;
- if (args.empty()) {
- break;
- }
- // If we have a line matching a prefix we recognize, call its callback and unset any
- // current section parsers. This is meant for /sys/ and /dev/ line entries for uevent.
- for (const auto& [prefix, callback] : line_callbacks_) {
- if (android::base::StartsWith(args[0], prefix.c_str())) {
- if (section_parser) section_parser->EndSection();
-
- std::string ret_err;
- if (!callback(std::move(args), &ret_err)) {
- LOG(ERROR) << filename << ": " << state.line << ": " << ret_err;
- }
- section_parser = nullptr;
- break;
- }
- }
- if (section_parsers_.count(args[0])) {
- if (section_parser) {
- section_parser->EndSection();
- }
- section_parser = section_parsers_[args[0]].get();
- std::string ret_err;
- if (!section_parser->ParseSection(std::move(args), filename, state.line, &ret_err)) {
- LOG(ERROR) << filename << ": " << state.line << ": " << ret_err;
- section_parser = nullptr;
- }
- } else if (section_parser) {
- std::string ret_err;
- if (!section_parser->ParseLineSection(std::move(args), state.line, &ret_err)) {
- LOG(ERROR) << filename << ": " << state.line << ": " << ret_err;
- }
- }
- args.clear();
- break;
- case T_TEXT:
- args.emplace_back(state.text);
- break;
- }
- }
-}
-
-bool Parser::ParseConfigFile(const std::string& path) {
- LOG(INFO) << "Parsing file " << path << "...";
- android::base::Timer t;
- std::string data;
- std::string err;
- if (!ReadFile(path, &data, &err)) {
- LOG(ERROR) << err;
- return false;
- }
-
- data.push_back('\n'); // TODO: fix parse_config.
- ParseData(path, data);
- for (const auto& [section_name, section_parser] : section_parsers_) {
- section_parser->EndFile();
- }
-
- LOG(VERBOSE) << "(Parsing " << path << " took " << t << ".)";
- return true;
-}
-
-bool Parser::ParseConfigDir(const std::string& path) {
- LOG(INFO) << "Parsing directory " << path << "...";
- std::unique_ptr<DIR, int(*)(DIR*)> config_dir(opendir(path.c_str()), closedir);
- if (!config_dir) {
- PLOG(ERROR) << "Could not import directory '" << path << "'";
- return false;
- }
- dirent* current_file;
- std::vector<std::string> files;
- while ((current_file = readdir(config_dir.get()))) {
- // Ignore directories and only process regular files.
- if (current_file->d_type == DT_REG) {
- std::string current_path =
- android::base::StringPrintf("%s/%s", path.c_str(), current_file->d_name);
- files.emplace_back(current_path);
- }
- }
- // Sort first so we load files in a consistent order (bug 31996208)
- std::sort(files.begin(), files.end());
- for (const auto& file : files) {
- if (!ParseConfigFile(file)) {
- LOG(ERROR) << "could not import file '" << file << "'";
- }
- }
- return true;
-}
-
-bool Parser::ParseConfig(const std::string& path) {
- if (is_dir(path.c_str())) {
- return ParseConfigDir(path);
- }
- return ParseConfigFile(path);
-}
-
-} // namespace init
-} // namespace android
diff --git a/init/init_parser.h b/init/init_parser.h
deleted file mode 100644
index c07a699..0000000
--- a/init/init_parser.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2010 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 _INIT_INIT_PARSER_H_
-#define _INIT_INIT_PARSER_H_
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-// SectionParser is an interface that can parse a given 'section' in init.
-//
-// You can implement up to 4 functions below, with ParseSection() being mandatory.
-// The first two function return bool with false indicating a failure and has a std::string* err
-// parameter into which an error string can be written. It will be reported along with the
-// filename and line number of where the error occurred.
-//
-// 1) bool ParseSection(std::vector<std::string>&& args, const std::string& filename,
-// int line, std::string* err)
-// This function is called when a section is first encountered.
-//
-// 2) bool ParseLineSection(std::vector<std::string>&& args, int line, std::string* err)
-// This function is called on each subsequent line until the next section is encountered.
-//
-// 3) bool EndSection()
-// This function is called either when a new section is found or at the end of the file.
-// It indicates that parsing of the current section is complete and any relevant objects should
-// be committed.
-//
-// 4) bool EndFile()
-// This function is called at the end of the file.
-// It indicates that the parsing has completed and any relevant objects should be committed.
-
-namespace android {
-namespace init {
-
-class SectionParser {
- public:
- virtual ~SectionParser() {}
- virtual bool ParseSection(std::vector<std::string>&& args, const std::string& filename,
- int line, std::string* err) = 0;
- virtual bool ParseLineSection(std::vector<std::string>&&, int, std::string*) { return true; };
- virtual void EndSection(){};
- virtual void EndFile(){};
-};
-
-class Parser {
- public:
- // LineCallback is the type for callbacks that can parse a line starting with a given prefix.
- //
- // They take the form of bool Callback(std::vector<std::string>&& args, std::string* err)
- //
- // Similar to ParseSection() and ParseLineSection(), this function returns bool with false
- // indicating a failure and has an std::string* err parameter into which an error string can
- // be written.
- using LineCallback = std::function<bool(std::vector<std::string>&&, std::string*)>;
-
- // TODO: init is the only user of this as a singleton; remove it.
- static Parser& GetInstance();
-
- Parser();
-
- bool ParseConfig(const std::string& path);
- void AddSectionParser(const std::string& name, std::unique_ptr<SectionParser> parser);
- void AddSingleLineParser(const std::string& prefix, LineCallback callback);
- void set_is_system_etc_init_loaded(bool loaded) { is_system_etc_init_loaded_ = loaded; }
- void set_is_vendor_etc_init_loaded(bool loaded) { is_vendor_etc_init_loaded_ = loaded; }
- void set_is_odm_etc_init_loaded(bool loaded) { is_odm_etc_init_loaded_ = loaded; }
- bool is_system_etc_init_loaded() { return is_system_etc_init_loaded_; }
- bool is_vendor_etc_init_loaded() { return is_vendor_etc_init_loaded_; }
- bool is_odm_etc_init_loaded() { return is_odm_etc_init_loaded_; }
-
- private:
- void ParseData(const std::string& filename, const std::string& data);
- bool ParseConfigFile(const std::string& path);
- bool ParseConfigDir(const std::string& path);
-
- std::map<std::string, std::unique_ptr<SectionParser>> section_parsers_;
- std::vector<std::pair<std::string, LineCallback>> line_callbacks_;
- bool is_system_etc_init_loaded_ = false;
- bool is_vendor_etc_init_loaded_ = false;
- bool is_odm_etc_init_loaded_ = false;
-};
-
-} // namespace init
-} // namespace android
-
-#endif
diff --git a/init/init_parser_test.cpp b/init/init_parser_test.cpp
deleted file mode 100644
index 95f269a..0000000
--- a/init/init_parser_test.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2015 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 "init_parser.h"
-
-#include <string>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include "init.h"
-#include "service.h"
-#include "util.h"
-
-namespace android {
-namespace init {
-
-TEST(init_parser, make_exec_oneshot_service_invalid_syntax) {
- ServiceManager& sm = ServiceManager::GetInstance();
- std::vector<std::string> args;
- // Nothing.
- ASSERT_EQ(nullptr, sm.MakeExecOneshotService(args));
-
- // No arguments to 'exec'.
- args.push_back("exec");
- ASSERT_EQ(nullptr, sm.MakeExecOneshotService(args));
-
- // No command in "exec --".
- args.push_back("--");
- ASSERT_EQ(nullptr, sm.MakeExecOneshotService(args));
-}
-
-TEST(init_parser, make_exec_oneshot_service_too_many_supplementary_gids) {
- ServiceManager& sm = ServiceManager::GetInstance();
- std::vector<std::string> args;
- args.push_back("exec");
- args.push_back("seclabel");
- args.push_back("root"); // uid.
- args.push_back("root"); // gid.
- for (int i = 0; i < NR_SVC_SUPP_GIDS; ++i) {
- args.push_back("root"); // Supplementary gid.
- }
- args.push_back("--");
- args.push_back("/system/bin/id");
- ASSERT_EQ(nullptr, sm.MakeExecOneshotService(args));
-}
-
-static void Test_make_exec_oneshot_service(bool dash_dash, bool seclabel, bool uid,
- bool gid, bool supplementary_gids) {
- ServiceManager& sm = ServiceManager::GetInstance();
- std::vector<std::string> args;
- args.push_back("exec");
- if (seclabel) {
- args.push_back("u:r:su:s0"); // seclabel
- if (uid) {
- args.push_back("log"); // uid
- if (gid) {
- args.push_back("shell"); // gid
- if (supplementary_gids) {
- args.push_back("system"); // supplementary gid 0
- args.push_back("adb"); // supplementary gid 1
- }
- }
- }
- }
- if (dash_dash) {
- args.push_back("--");
- }
- args.push_back("/system/bin/toybox");
- args.push_back("id");
- Service* svc = sm.MakeExecOneshotService(args);
- ASSERT_NE(nullptr, svc);
-
- if (seclabel) {
- ASSERT_EQ("u:r:su:s0", svc->seclabel());
- } else {
- ASSERT_EQ("", svc->seclabel());
- }
- if (uid) {
- uid_t decoded_uid;
- std::string err;
- ASSERT_TRUE(DecodeUid("log", &decoded_uid, &err));
- ASSERT_EQ(decoded_uid, svc->uid());
- } else {
- ASSERT_EQ(0U, svc->uid());
- }
- if (gid) {
- uid_t decoded_uid;
- std::string err;
- ASSERT_TRUE(DecodeUid("shell", &decoded_uid, &err));
- ASSERT_EQ(decoded_uid, svc->gid());
- } else {
- ASSERT_EQ(0U, svc->gid());
- }
- if (supplementary_gids) {
- ASSERT_EQ(2U, svc->supp_gids().size());
- uid_t decoded_uid;
- std::string err;
- ASSERT_TRUE(DecodeUid("system", &decoded_uid, &err));
- ASSERT_EQ(decoded_uid, svc->supp_gids()[0]);
- ASSERT_TRUE(DecodeUid("adb", &decoded_uid, &err));
- ASSERT_EQ(decoded_uid, svc->supp_gids()[1]);
- } else {
- ASSERT_EQ(0U, svc->supp_gids().size());
- }
-
- ASSERT_EQ(static_cast<std::size_t>(2), svc->args().size());
- ASSERT_EQ("/system/bin/toybox", svc->args()[0]);
- ASSERT_EQ("id", svc->args()[1]);
-}
-
-TEST(init_parser, make_exec_oneshot_service_with_everything) {
- Test_make_exec_oneshot_service(true, true, true, true, true);
-}
-
-TEST(init_parser, make_exec_oneshot_service_with_seclabel_uid_gid) {
- Test_make_exec_oneshot_service(true, true, true, true, false);
-}
-
-TEST(init_parser, make_exec_oneshot_service_with_seclabel_uid) {
- Test_make_exec_oneshot_service(true, true, true, false, false);
-}
-
-TEST(init_parser, make_exec_oneshot_service_with_seclabel) {
- Test_make_exec_oneshot_service(true, true, false, false, false);
-}
-
-TEST(init_parser, make_exec_oneshot_service_with_just_command) {
- Test_make_exec_oneshot_service(true, false, false, false, false);
-}
-
-TEST(init_parser, make_exec_oneshot_service_with_just_command_no_dash) {
- Test_make_exec_oneshot_service(false, false, false, false, false);
-}
-
-} // namespace init
-} // namespace android
diff --git a/init/init_test.cpp b/init/init_test.cpp
index 0a4071b..2062290 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -23,8 +23,8 @@
#include "action.h"
#include "builtins.h"
#include "import_parser.h"
-#include "init_parser.h"
#include "keyword_map.h"
+#include "parser.h"
#include "util.h"
namespace android {
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/parser.cpp b/init/parser.cpp
index c0fa6d9..c6f4f45 100644
--- a/init/parser.cpp
+++ b/init/parser.cpp
@@ -1,123 +1,156 @@
+/*
+ * Copyright (C) 2010 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 "parser.h"
+#include <dirent.h>
+
+#include <android-base/chrono_utils.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+#include "tokenizer.h"
+#include "util.h"
+
namespace android {
namespace init {
-int next_token(struct parse_state *state)
-{
- char *x = state->ptr;
- char *s;
+Parser::Parser() {}
- if (state->nexttoken) {
- int t = state->nexttoken;
- state->nexttoken = 0;
- return t;
- }
+void Parser::AddSectionParser(const std::string& name, std::unique_ptr<SectionParser> parser) {
+ section_parsers_[name] = std::move(parser);
+}
+
+void Parser::AddSingleLineParser(const std::string& prefix, LineCallback callback) {
+ line_callbacks_.emplace_back(prefix, callback);
+}
+
+void Parser::ParseData(const std::string& filename, const std::string& data) {
+ // TODO: Use a parser with const input and remove this copy
+ std::vector<char> data_copy(data.begin(), data.end());
+ data_copy.push_back('\0');
+
+ parse_state state;
+ state.line = 0;
+ state.ptr = &data_copy[0];
+ state.nexttoken = 0;
+
+ SectionParser* section_parser = nullptr;
+ std::vector<std::string> args;
for (;;) {
- switch (*x) {
- case 0:
- state->ptr = x;
- return T_EOF;
- case '\n':
- x++;
- state->ptr = x;
- return T_NEWLINE;
- case ' ':
- case '\t':
- case '\r':
- x++;
- continue;
- case '#':
- while (*x && (*x != '\n')) x++;
- if (*x == '\n') {
- state->ptr = x+1;
- return T_NEWLINE;
- } else {
- state->ptr = x;
- return T_EOF;
- }
- default:
- goto text;
+ switch (next_token(&state)) {
+ case T_EOF:
+ if (section_parser) section_parser->EndSection();
+ return;
+ case T_NEWLINE:
+ state.line++;
+ if (args.empty()) break;
+ // If we have a line matching a prefix we recognize, call its callback and unset any
+ // current section parsers. This is meant for /sys/ and /dev/ line entries for
+ // uevent.
+ for (const auto& [prefix, callback] : line_callbacks_) {
+ if (android::base::StartsWith(args[0], prefix.c_str())) {
+ if (section_parser) section_parser->EndSection();
+
+ std::string ret_err;
+ if (!callback(std::move(args), &ret_err)) {
+ LOG(ERROR) << filename << ": " << state.line << ": " << ret_err;
+ }
+ section_parser = nullptr;
+ break;
+ }
+ }
+ if (section_parsers_.count(args[0])) {
+ if (section_parser) section_parser->EndSection();
+ section_parser = section_parsers_[args[0]].get();
+ std::string ret_err;
+ if (!section_parser->ParseSection(std::move(args), filename, state.line,
+ &ret_err)) {
+ LOG(ERROR) << filename << ": " << state.line << ": " << ret_err;
+ section_parser = nullptr;
+ }
+ } else if (section_parser) {
+ std::string ret_err;
+ if (!section_parser->ParseLineSection(std::move(args), state.line, &ret_err)) {
+ LOG(ERROR) << filename << ": " << state.line << ": " << ret_err;
+ }
+ }
+ args.clear();
+ break;
+ case T_TEXT:
+ args.emplace_back(state.text);
+ break;
}
}
+}
+
+bool Parser::ParseConfigFile(const std::string& path) {
+ LOG(INFO) << "Parsing file " << path << "...";
+ android::base::Timer t;
+ std::string data;
+ std::string err;
+ if (!ReadFile(path, &data, &err)) {
+ LOG(ERROR) << err;
+ return false;
+ }
-textdone:
- state->ptr = x;
- *s = 0;
- return T_TEXT;
-text:
- state->text = s = x;
-textresume:
- for (;;) {
- switch (*x) {
- case 0:
- goto textdone;
- case ' ':
- case '\t':
- case '\r':
- x++;
- goto textdone;
- case '\n':
- state->nexttoken = T_NEWLINE;
- x++;
- goto textdone;
- case '"':
- x++;
- for (;;) {
- switch (*x) {
- case 0:
- /* unterminated quoted thing */
- state->ptr = x;
- return T_EOF;
- case '"':
- x++;
- goto textresume;
- default:
- *s++ = *x++;
- }
- }
- break;
- case '\\':
- x++;
- switch (*x) {
- case 0:
- goto textdone;
- case 'n':
- *s++ = '\n';
- break;
- case 'r':
- *s++ = '\r';
- break;
- case 't':
- *s++ = '\t';
- break;
- case '\\':
- *s++ = '\\';
- break;
- case '\r':
- /* \ <cr> <lf> -> line continuation */
- if (x[1] != '\n') {
- x++;
- continue;
- }
- case '\n':
- /* \ <lf> -> line continuation */
- state->line++;
- x++;
- /* eat any extra whitespace */
- while((*x == ' ') || (*x == '\t')) x++;
- continue;
- default:
- /* unknown escape -- just copy */
- *s++ = *x++;
- }
- continue;
- default:
- *s++ = *x++;
+ data.push_back('\n'); // TODO: fix parse_config.
+ ParseData(path, data);
+ for (const auto& [section_name, section_parser] : section_parsers_) {
+ section_parser->EndFile();
+ }
+
+ LOG(VERBOSE) << "(Parsing " << path << " took " << t << ".)";
+ return true;
+}
+
+bool Parser::ParseConfigDir(const std::string& path) {
+ LOG(INFO) << "Parsing directory " << path << "...";
+ std::unique_ptr<DIR, decltype(&closedir)> config_dir(opendir(path.c_str()), closedir);
+ if (!config_dir) {
+ PLOG(ERROR) << "Could not import directory '" << path << "'";
+ return false;
+ }
+ dirent* current_file;
+ std::vector<std::string> files;
+ while ((current_file = readdir(config_dir.get()))) {
+ // Ignore directories and only process regular files.
+ if (current_file->d_type == DT_REG) {
+ std::string current_path =
+ android::base::StringPrintf("%s/%s", path.c_str(), current_file->d_name);
+ files.emplace_back(current_path);
}
}
- return T_EOF;
+ // Sort first so we load files in a consistent order (bug 31996208)
+ std::sort(files.begin(), files.end());
+ for (const auto& file : files) {
+ if (!ParseConfigFile(file)) {
+ LOG(ERROR) << "could not import file '" << file << "'";
+ }
+ }
+ return true;
+}
+
+bool Parser::ParseConfig(const std::string& path) {
+ if (is_dir(path.c_str())) {
+ return ParseConfigDir(path);
+ }
+ return ParseConfigFile(path);
}
} // namespace init
diff --git a/init/parser.h b/init/parser.h
index 86e4c57..fd65ad6 100644
--- a/init/parser.h
+++ b/init/parser.h
@@ -14,27 +14,77 @@
* limitations under the License.
*/
-#ifndef PARSER_H_
-#define PARSER_H_
+#ifndef _INIT_PARSER_H_
+#define _INIT_PARSER_H_
-#define T_EOF 0
-#define T_TEXT 1
-#define T_NEWLINE 2
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+// SectionParser is an interface that can parse a given 'section' in init.
+//
+// You can implement up to 4 functions below, with ParseSection() being mandatory.
+// The first two function return bool with false indicating a failure and has a std::string* err
+// parameter into which an error string can be written. It will be reported along with the
+// filename and line number of where the error occurred.
+//
+// 1) bool ParseSection(std::vector<std::string>&& args, const std::string& filename,
+// int line, std::string* err)
+// This function is called when a section is first encountered.
+//
+// 2) bool ParseLineSection(std::vector<std::string>&& args, int line, std::string* err)
+// This function is called on each subsequent line until the next section is encountered.
+//
+// 3) bool EndSection()
+// This function is called either when a new section is found or at the end of the file.
+// It indicates that parsing of the current section is complete and any relevant objects should
+// be committed.
+//
+// 4) bool EndFile()
+// This function is called at the end of the file.
+// It indicates that the parsing has completed and any relevant objects should be committed.
namespace android {
namespace init {
-struct parse_state
-{
- char *ptr;
- char *text;
- int line;
- int nexttoken;
+class SectionParser {
+ public:
+ virtual ~SectionParser() {}
+ virtual bool ParseSection(std::vector<std::string>&& args, const std::string& filename,
+ int line, std::string* err) = 0;
+ virtual bool ParseLineSection(std::vector<std::string>&&, int, std::string*) { return true; };
+ virtual void EndSection(){};
+ virtual void EndFile(){};
};
-int next_token(struct parse_state *state);
+class Parser {
+ public:
+ // LineCallback is the type for callbacks that can parse a line starting with a given prefix.
+ //
+ // They take the form of bool Callback(std::vector<std::string>&& args, std::string* err)
+ //
+ // Similar to ParseSection() and ParseLineSection(), this function returns bool with false
+ // indicating a failure and has an std::string* err parameter into which an error string can
+ // be written.
+ using LineCallback = std::function<bool(std::vector<std::string>&&, std::string*)>;
+
+ Parser();
+
+ bool ParseConfig(const std::string& path);
+ void AddSectionParser(const std::string& name, std::unique_ptr<SectionParser> parser);
+ void AddSingleLineParser(const std::string& prefix, LineCallback callback);
+
+ private:
+ void ParseData(const std::string& filename, const std::string& data);
+ bool ParseConfigFile(const std::string& path);
+ bool ParseConfigDir(const std::string& path);
+
+ std::map<std::string, std::unique_ptr<SectionParser>> section_parsers_;
+ std::vector<std::pair<std::string, LineCallback>> line_callbacks_;
+};
} // namespace init
} // namespace android
-#endif /* PARSER_H_ */
+#endif
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 17e3576..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().ForEachService([](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().ForEachService([](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().ForEachService([&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 fe38ee2..6f756fa 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -155,28 +155,11 @@
: name(name), value(value) {
}
+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)
- : name_(name),
- classnames_({"default"}),
- flags_(0),
- pid_(0),
- crash_count_(0),
- uid_(0),
- gid_(0),
- namespace_flags_(0),
- seclabel_(""),
- onrestart_(false, "<Service '" + name + "' onrestart>", 0),
- keychord_id_(0),
- ioprio_class_(IoSchedClass_NONE),
- ioprio_pri_(0),
- priority_(0),
- oom_score_adjust_(-1000),
- swappiness_(-1),
- soft_limit_in_bytes_(-1),
- limit_in_bytes_(-1),
- args_(args) {
- onrestart_.InitSingleTrigger("onrestart");
-}
+ : Service(name, 0, 0, 0, {}, 0, 0, "", args) {}
Service::Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid,
const std::vector<gid_t>& supp_gids, const CapSet& capabilities,
@@ -202,6 +185,7 @@
swappiness_(-1),
soft_limit_in_bytes_(-1),
limit_in_bytes_(-1),
+ start_order_(0),
args_(args) {
onrestart_.InitSingleTrigger("onrestart");
}
@@ -297,12 +281,13 @@
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);
+ start_order_ = 0;
// Oneshot processes go into the disabled state on exit,
// except when manually restarted.
@@ -669,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;
}
@@ -825,6 +815,7 @@
time_started_ = boot_clock::now();
pid_ = pid;
flags_ |= SVC_RUNNING;
+ start_order_ = next_start_order_++;
process_cgroup_empty_ = false;
errno = -createProcessGroup(uid_, pid_);
@@ -851,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;
}
@@ -905,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
@@ -966,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;
@@ -1030,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;
@@ -1068,73 +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;
+ return std::make_unique<Service>(name, flags, uid, gid, supp_gids, no_capabilities,
+ namespace_flags, seclabel, str_args);
}
-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();
+// Shutdown services in the opposite order that they were started.
+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());
}
- return nullptr;
+ std::sort(shutdown_services.begin(), shutdown_services.end(),
+ [](const auto& a, const auto& b) { return a->start_order() > b->start_order(); });
+ return shutdown_services;
}
-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());
- }
-}
-
-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();
@@ -1146,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) {
@@ -1238,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;
@@ -1255,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 62a3299..6c143cb 100644
--- a/init/service.h
+++ b/init/service.h
@@ -30,8 +30,8 @@
#include "action.h"
#include "capabilities.h"
#include "descriptors.h"
-#include "init_parser.h"
#include "keyword_map.h"
+#include "parser.h"
#define SVC_DISABLED 0x001 // do not autostart with class
#define SVC_ONESHOT 0x002 // do not restart on exit
@@ -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_; }
@@ -108,6 +115,7 @@
int priority() const { return priority_; }
int oom_score_adjust() const { return oom_score_adjust_; }
bool process_cgroup_empty() const { return process_cgroup_empty_; }
+ unsigned long start_order() const { return start_order_; }
const std::vector<std::string>& args() const { return args_; }
private:
@@ -149,6 +157,9 @@
template <typename T>
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_;
std::string console_;
@@ -190,49 +201,47 @@
bool process_cgroup_empty_ = false;
+ unsigned long start_order_;
+
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 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;
@@ -241,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 44f28a3..62e46f4 100644
--- a/init/service_test.cpp
+++ b/init/service_test.cpp
@@ -23,6 +23,8 @@
#include <gtest/gtest.h>
+#include "util.h"
+
namespace android {
namespace init {
@@ -71,5 +73,120 @@
EXPECT_FALSE(service_in_old_memory->process_cgroup_empty());
}
+TEST(service, make_temporary_oneshot_service_invalid_syntax) {
+ std::vector<std::string> args;
+ // Nothing.
+ ASSERT_EQ(nullptr, Service::MakeTemporaryOneshotService(args));
+
+ // No arguments to 'exec'.
+ args.push_back("exec");
+ ASSERT_EQ(nullptr, Service::MakeTemporaryOneshotService(args));
+
+ // No command in "exec --".
+ args.push_back("--");
+ ASSERT_EQ(nullptr, Service::MakeTemporaryOneshotService(args));
+}
+
+TEST(service, make_temporary_oneshot_service_too_many_supplementary_gids) {
+ std::vector<std::string> args;
+ args.push_back("exec");
+ args.push_back("seclabel");
+ args.push_back("root"); // uid.
+ args.push_back("root"); // gid.
+ for (int i = 0; i < NR_SVC_SUPP_GIDS; ++i) {
+ args.push_back("root"); // Supplementary gid.
+ }
+ args.push_back("--");
+ args.push_back("/system/bin/id");
+ ASSERT_EQ(nullptr, Service::MakeTemporaryOneshotService(args));
+}
+
+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) {
+ args.push_back("u:r:su:s0"); // seclabel
+ if (uid) {
+ args.push_back("log"); // uid
+ if (gid) {
+ args.push_back("shell"); // gid
+ if (supplementary_gids) {
+ args.push_back("system"); // supplementary gid 0
+ args.push_back("adb"); // supplementary gid 1
+ }
+ }
+ }
+ }
+ if (dash_dash) {
+ args.push_back("--");
+ }
+ args.push_back("/system/bin/toybox");
+ args.push_back("id");
+ auto svc = Service::MakeTemporaryOneshotService(args);
+ ASSERT_NE(nullptr, svc);
+
+ if (seclabel) {
+ ASSERT_EQ("u:r:su:s0", svc->seclabel());
+ } else {
+ ASSERT_EQ("", svc->seclabel());
+ }
+ if (uid) {
+ uid_t decoded_uid;
+ std::string err;
+ ASSERT_TRUE(DecodeUid("log", &decoded_uid, &err));
+ ASSERT_EQ(decoded_uid, svc->uid());
+ } else {
+ ASSERT_EQ(0U, svc->uid());
+ }
+ if (gid) {
+ uid_t decoded_uid;
+ std::string err;
+ ASSERT_TRUE(DecodeUid("shell", &decoded_uid, &err));
+ ASSERT_EQ(decoded_uid, svc->gid());
+ } else {
+ ASSERT_EQ(0U, svc->gid());
+ }
+ if (supplementary_gids) {
+ ASSERT_EQ(2U, svc->supp_gids().size());
+ uid_t decoded_uid;
+ std::string err;
+ ASSERT_TRUE(DecodeUid("system", &decoded_uid, &err));
+ ASSERT_EQ(decoded_uid, svc->supp_gids()[0]);
+ ASSERT_TRUE(DecodeUid("adb", &decoded_uid, &err));
+ ASSERT_EQ(decoded_uid, svc->supp_gids()[1]);
+ } else {
+ ASSERT_EQ(0U, svc->supp_gids().size());
+ }
+
+ ASSERT_EQ(static_cast<std::size_t>(2), svc->args().size());
+ ASSERT_EQ("/system/bin/toybox", svc->args()[0]);
+ ASSERT_EQ("id", svc->args()[1]);
+}
+
+TEST(service, make_temporary_oneshot_service_with_everything) {
+ Test_make_temporary_oneshot_service(true, true, true, true, true);
+}
+
+TEST(service, make_temporary_oneshot_service_with_seclabel_uid_gid) {
+ Test_make_temporary_oneshot_service(true, true, true, true, false);
+}
+
+TEST(service, make_temporary_oneshot_service_with_seclabel_uid) {
+ Test_make_temporary_oneshot_service(true, true, true, false, false);
+}
+
+TEST(service, make_temporary_oneshot_service_with_seclabel) {
+ Test_make_temporary_oneshot_service(true, true, 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_temporary_oneshot_service_with_just_command_no_dash) {
+ Test_make_temporary_oneshot_service(false, false, false, false, false);
+}
+
} // namespace init
} // namespace android
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/tokenizer.cpp b/init/tokenizer.cpp
new file mode 100644
index 0000000..f8d9b6b
--- /dev/null
+++ b/init/tokenizer.cpp
@@ -0,0 +1,124 @@
+#include "tokenizer.h"
+
+namespace android {
+namespace init {
+
+int next_token(struct parse_state *state)
+{
+ char *x = state->ptr;
+ char *s;
+
+ if (state->nexttoken) {
+ int t = state->nexttoken;
+ state->nexttoken = 0;
+ return t;
+ }
+
+ for (;;) {
+ switch (*x) {
+ case 0:
+ state->ptr = x;
+ return T_EOF;
+ case '\n':
+ x++;
+ state->ptr = x;
+ return T_NEWLINE;
+ case ' ':
+ case '\t':
+ case '\r':
+ x++;
+ continue;
+ case '#':
+ while (*x && (*x != '\n')) x++;
+ if (*x == '\n') {
+ state->ptr = x+1;
+ return T_NEWLINE;
+ } else {
+ state->ptr = x;
+ return T_EOF;
+ }
+ default:
+ goto text;
+ }
+ }
+
+textdone:
+ state->ptr = x;
+ *s = 0;
+ return T_TEXT;
+text:
+ state->text = s = x;
+textresume:
+ for (;;) {
+ switch (*x) {
+ case 0:
+ goto textdone;
+ case ' ':
+ case '\t':
+ case '\r':
+ x++;
+ goto textdone;
+ case '\n':
+ state->nexttoken = T_NEWLINE;
+ x++;
+ goto textdone;
+ case '"':
+ x++;
+ for (;;) {
+ switch (*x) {
+ case 0:
+ /* unterminated quoted thing */
+ state->ptr = x;
+ return T_EOF;
+ case '"':
+ x++;
+ goto textresume;
+ default:
+ *s++ = *x++;
+ }
+ }
+ break;
+ case '\\':
+ x++;
+ switch (*x) {
+ case 0:
+ goto textdone;
+ case 'n':
+ *s++ = '\n';
+ break;
+ case 'r':
+ *s++ = '\r';
+ break;
+ case 't':
+ *s++ = '\t';
+ break;
+ case '\\':
+ *s++ = '\\';
+ break;
+ case '\r':
+ /* \ <cr> <lf> -> line continuation */
+ if (x[1] != '\n') {
+ x++;
+ continue;
+ }
+ case '\n':
+ /* \ <lf> -> line continuation */
+ state->line++;
+ x++;
+ /* eat any extra whitespace */
+ while((*x == ' ') || (*x == '\t')) x++;
+ continue;
+ default:
+ /* unknown escape -- just copy */
+ *s++ = *x++;
+ }
+ continue;
+ default:
+ *s++ = *x++;
+ }
+ }
+ return T_EOF;
+}
+
+} // namespace init
+} // namespace android
diff --git a/init/tokenizer.h b/init/tokenizer.h
new file mode 100644
index 0000000..72c08ef
--- /dev/null
+++ b/init/tokenizer.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 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 _INIT_TOKENIZER_H_
+#define _INIT_TOKENIZER_H_
+
+#define T_EOF 0
+#define T_TEXT 1
+#define T_NEWLINE 2
+
+namespace android {
+namespace init {
+
+struct parse_state
+{
+ char *ptr;
+ char *text;
+ int line;
+ int nexttoken;
+};
+
+int next_token(struct parse_state *state);
+
+} // namespace init
+} // namespace android
+
+#endif
diff --git a/init/ueventd_parser.h b/init/ueventd_parser.h
index 592df63..51d83ef 100644
--- a/init/ueventd_parser.h
+++ b/init/ueventd_parser.h
@@ -21,7 +21,7 @@
#include <vector>
#include "devices.h"
-#include "init_parser.h"
+#include "parser.h"
namespace android {
namespace init {
diff --git a/libappfuse/Android.bp b/libappfuse/Android.bp
index b0ac5c4..29ffe32 100644
--- a/libappfuse/Android.bp
+++ b/libappfuse/Android.bp
@@ -8,7 +8,6 @@
"-Wall",
"-Werror",
],
- clang: true
}
cc_library_shared {
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 245deb1..85258cd 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -156,8 +156,6 @@
"-Wall",
"-Wextra",
],
-
- clang: true,
}
subdirs = ["tests"]
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 abe6dd6..10f5bc0 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/libion/tests/Android.bp b/libion/tests/Android.bp
index 4428848..b3fcb3b 100644
--- a/libion/tests/Android.bp
+++ b/libion/tests/Android.bp
@@ -16,7 +16,6 @@
cc_test {
name: "ion-unit-tests",
- clang: true,
cflags: [
"-g",
"-Wall",
diff --git a/liblog/include/log/log_main.h b/liblog/include/log/log_main.h
index 68c2e9a..339a06d 100644
--- a/liblog/include/log/log_main.h
+++ b/liblog/include/log/log_main.h
@@ -354,11 +354,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/libmemunreachable/Android.bp b/libmemunreachable/Android.bp
index 826a576..8b76a65 100644
--- a/libmemunreachable/Android.bp
+++ b/libmemunreachable/Android.bp
@@ -6,7 +6,6 @@
"-Wextra",
"-Werror",
],
- clang: true,
shared_libs: [
"libbase",
],
diff --git a/libmetricslogger/Android.bp b/libmetricslogger/Android.bp
index 26a041a..c692d1f 100644
--- a/libmetricslogger/Android.bp
+++ b/libmetricslogger/Android.bp
@@ -7,7 +7,6 @@
cc_defaults {
name: "metricslogger_defaults",
- clang: true,
host_supported: true,
export_include_dirs: ["include"],
diff --git a/libnativebridge/Android.bp b/libnativebridge/Android.bp
index 1cea4cd..8b48a87 100644
--- a/libnativebridge/Android.bp
+++ b/libnativebridge/Android.bp
@@ -12,7 +12,6 @@
host_supported: true,
srcs: ["native_bridge.cc"],
shared_libs: ["liblog"],
- clang: true,
export_include_dirs=["include"],
diff --git a/libnativebridge/tests/Android.mk b/libnativebridge/tests/Android.mk
index 70b3fcc..c1e65ff 100644
--- a/libnativebridge/tests/Android.mk
+++ b/libnativebridge/tests/Android.mk
@@ -34,7 +34,6 @@
$(foreach file,$(test_src_files), \
$(eval include $(CLEAR_VARS)) \
- $(eval LOCAL_CLANG := true) \
$(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
$(eval LOCAL_SRC_FILES := $(file)) \
$(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
@@ -43,7 +42,6 @@
$(foreach file,$(test_src_files), \
$(eval include $(CLEAR_VARS)) \
- $(eval LOCAL_CLANG := true) \
$(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
$(eval LOCAL_SRC_FILES := $(file)) \
$(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp
index c1133fb..13f9744 100644
--- a/libnativeloader/Android.bp
+++ b/libnativeloader/Android.bp
@@ -19,7 +19,6 @@
host_ldlibs: ["-ldl"],
},
},
- clang: true,
cflags: [
"-Werror",
"-Wall",
diff --git a/libpackagelistparser/Android.bp b/libpackagelistparser/Android.bp
index 70ff528..a9fec7d 100644
--- a/libpackagelistparser/Android.bp
+++ b/libpackagelistparser/Android.bp
@@ -6,7 +6,6 @@
local_include_dirs: ["include"],
export_include_dirs: ["include"],
- clang: true,
sanitize: {
misc_undefined: ["integer"],
},
diff --git a/libsync/Android.bp b/libsync/Android.bp
index 257d42d..1646348 100644
--- a/libsync/Android.bp
+++ b/libsync/Android.bp
@@ -52,5 +52,4 @@
"-Wno-missing-field-initializers",
"-Wno-sign-compare",
],
- clang: true,
}
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 9e7cc13..787c10a 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -145,8 +145,6 @@
enabled: true,
},
},
-
- clang: true,
}
// Include subdirectory makefiles
diff --git a/libutils/include/utils/Mutex.h b/libutils/include/utils/Mutex.h
index d106185..af6076c 100644
--- a/libutils/include/utils/Mutex.h
+++ b/libutils/include/utils/Mutex.h
@@ -28,6 +28,53 @@
#include <utils/Errors.h>
#include <utils/Timers.h>
+// Enable thread safety attributes only with clang.
+// The attributes can be safely erased when compiling with other compilers.
+#if defined(__clang__) && (!defined(SWIG))
+#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
+#else
+#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
+#endif
+
+#define CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
+
+#define SCOPED_CAPABILITY THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
+
+#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
+
+#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
+
+#define ACQUIRED_BEFORE(...) THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
+
+#define ACQUIRED_AFTER(...) THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
+
+#define REQUIRES(...) THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
+
+#define REQUIRES_SHARED(...) THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
+
+#define ACQUIRE(...) THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
+
+#define ACQUIRE_SHARED(...) THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
+
+#define RELEASE(...) THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
+
+#define RELEASE_SHARED(...) THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
+
+#define TRY_ACQUIRE(...) THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
+
+#define TRY_ACQUIRE_SHARED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
+
+#define EXCLUDES(...) THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
+
+#define ASSERT_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
+
+#define ASSERT_SHARED_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
+
+#define RETURN_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
+
+#define NO_THREAD_SAFETY_ANALYSIS THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
+
// ---------------------------------------------------------------------------
namespace android {
// ---------------------------------------------------------------------------
@@ -44,24 +91,24 @@
* The mutex must be unlocked by the thread that locked it. They are not
* recursive, i.e. the same thread can't lock it multiple times.
*/
-class Mutex {
-public:
+class CAPABILITY("mutex") Mutex {
+ public:
enum {
PRIVATE = 0,
SHARED = 1
};
- Mutex();
- explicit Mutex(const char* name);
- explicit Mutex(int type, const char* name = NULL);
- ~Mutex();
+ Mutex();
+ explicit Mutex(const char* name);
+ explicit Mutex(int type, const char* name = NULL);
+ ~Mutex();
// lock or unlock the mutex
- status_t lock();
- void unlock();
+ status_t lock() ACQUIRE();
+ void unlock() RELEASE();
// lock if possible; returns 0 on success, error otherwise
- status_t tryLock();
+ status_t tryLock() TRY_ACQUIRE(true);
#if defined(__ANDROID__)
// Lock the mutex, but don't wait longer than timeoutNs (relative time).
@@ -75,32 +122,36 @@
// which is subject to NTP adjustments, and includes time during suspend,
// so a timeout may occur even though no processes could run.
// Not holding a partial wakelock may lead to a system suspend.
- status_t timedLock(nsecs_t timeoutNs);
+ status_t timedLock(nsecs_t timeoutNs) TRY_ACQUIRE(true);
#endif
// Manages the mutex automatically. It'll be locked when Autolock is
// constructed and released when Autolock goes out of scope.
- class Autolock {
- public:
- inline explicit Autolock(Mutex& mutex) : mLock(mutex) { mLock.lock(); }
- inline explicit Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
- inline ~Autolock() { mLock.unlock(); }
- private:
+ class SCOPED_CAPABILITY Autolock {
+ public:
+ inline explicit Autolock(Mutex& mutex) ACQUIRE(mutex) : mLock(mutex) { mLock.lock(); }
+ inline explicit Autolock(Mutex* mutex) ACQUIRE(mutex) : mLock(*mutex) { mLock.lock(); }
+ inline ~Autolock() RELEASE() { mLock.unlock(); }
+
+ private:
Mutex& mLock;
+ // Cannot be copied or moved - declarations only
+ Autolock(const Autolock&);
+ Autolock& operator=(const Autolock&);
};
-private:
+ private:
friend class Condition;
// A mutex cannot be copied
- Mutex(const Mutex&);
- Mutex& operator = (const Mutex&);
+ Mutex(const Mutex&);
+ Mutex& operator=(const Mutex&);
#if !defined(_WIN32)
pthread_mutex_t mMutex;
#else
- void _init();
- void* mState;
+ void _init();
+ void* mState;
#endif
};
diff --git a/libutils/include/utils/Singleton.h b/libutils/include/utils/Singleton.h
index bdb2332..9afedd4 100644
--- a/libutils/include/utils/Singleton.h
+++ b/libutils/include/utils/Singleton.h
@@ -85,7 +85,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/tests/Android.bp b/libutils/tests/Android.bp
index 7b62c24..0869175 100644
--- a/libutils/tests/Android.bp
+++ b/libutils/tests/Android.bp
@@ -23,6 +23,7 @@
srcs: [
"BitSet_test.cpp",
"LruCache_test.cpp",
+ "Mutex_test.cpp",
"Singleton_test.cpp",
"String8_test.cpp",
"StrongPointer_test.cpp",
@@ -71,6 +72,7 @@
"-Wall",
"-Wextra",
"-Werror",
+ "-Wthread-safety",
],
}
diff --git a/libutils/tests/Mutex_test.cpp b/libutils/tests/Mutex_test.cpp
new file mode 100644
index 0000000..8a1805f
--- /dev/null
+++ b/libutils/tests/Mutex_test.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/Mutex.h>
+
+#include <gtest/gtest.h>
+
+static android::Mutex mLock;
+static int i GUARDED_BY(mLock);
+
+void modifyLockedVariable() REQUIRES(mLock) {
+ i = 1;
+}
+
+TEST(Mutex, compile) {
+ android::Mutex::Autolock _l(mLock);
+ i = 0;
+ modifyLockedVariable();
+}
\ No newline at end of file
diff --git a/libziparchive/include/ziparchive/zip_archive_stream_entry.h b/libziparchive/include/ziparchive/zip_archive_stream_entry.h
index a40b799..b4766f8 100644
--- a/libziparchive/include/ziparchive/zip_archive_stream_entry.h
+++ b/libziparchive/include/ziparchive/zip_archive_stream_entry.h
@@ -40,7 +40,8 @@
ZipArchiveHandle handle_;
- uint32_t crc32_;
+ off64_t offset_ = 0;
+ uint32_t crc32_ = 0u;
};
#endif // LIBZIPARCHIVE_ZIPARCHIVESTREAMENTRY_H_
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 17c268b..ad40d42 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -435,13 +435,20 @@
static int32_t ValidateDataDescriptor(MappedZipFile& mapped_zip, ZipEntry* entry) {
uint8_t ddBuf[sizeof(DataDescriptor) + sizeof(DataDescriptor::kOptSignature)];
- if (!mapped_zip.ReadData(ddBuf, sizeof(ddBuf))) {
+ off64_t offset = entry->offset;
+ if (entry->method != kCompressStored) {
+ offset += entry->compressed_length;
+ } else {
+ offset += entry->uncompressed_length;
+ }
+
+ if (!mapped_zip.ReadAtOffset(ddBuf, sizeof(ddBuf), offset)) {
return kIoError;
}
const uint32_t ddSignature = *(reinterpret_cast<const uint32_t*>(ddBuf));
- const uint16_t offset = (ddSignature == DataDescriptor::kOptSignature) ? 4 : 0;
- const DataDescriptor* descriptor = reinterpret_cast<const DataDescriptor*>(ddBuf + offset);
+ const uint16_t ddOffset = (ddSignature == DataDescriptor::kOptSignature) ? 4 : 0;
+ const DataDescriptor* descriptor = reinterpret_cast<const DataDescriptor*>(ddBuf + ddOffset);
// Validate that the values in the data descriptor match those in the central
// directory.
@@ -899,7 +906,9 @@
/* read as much as we can */
if (zstream.avail_in == 0) {
const size_t getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
- if (!mapped_zip.ReadData(read_buf.data(), getSize)) {
+ off64_t offset = entry->offset + (entry->compressed_length - compressed_length);
+ // Make sure to read at offset to ensure concurrent access to the fd.
+ if (!mapped_zip.ReadAtOffset(read_buf.data(), getSize, offset)) {
ALOGW("Zip: inflate read failed, getSize = %zu: %s", getSize, strerror(errno));
return kIoError;
}
@@ -962,12 +971,15 @@
uint64_t crc = 0;
while (count < length) {
uint32_t remaining = length - count;
+ off64_t offset = entry->offset + count;
- // Safe conversion because kBufSize is narrow enough for a 32 bit signed
- // value.
+ // Safe conversion because kBufSize is narrow enough for a 32 bit signed value.
const size_t block_size = (remaining > kBufSize) ? kBufSize : remaining;
- if (!mapped_zip.ReadData(buf.data(), block_size)) {
- ALOGW("CopyFileToFile: copy read failed, block_size = %zu: %s", block_size, strerror(errno));
+
+ // Make sure to read at offset to ensure concurrent access to the fd.
+ if (!mapped_zip.ReadAtOffset(buf.data(), block_size, offset)) {
+ ALOGW("CopyFileToFile: copy read failed, block_size = %zu, offset = %" PRId64 ": %s",
+ block_size, static_cast<int64_t>(offset), strerror(errno));
return kIoError;
}
@@ -986,12 +998,6 @@
int32_t ExtractToWriter(ZipArchiveHandle handle, ZipEntry* entry, Writer* writer) {
ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
const uint16_t method = entry->method;
- off64_t data_offset = entry->offset;
-
- if (!archive->mapped_zip.SeekToOffset(data_offset)) {
- ALOGW("Zip: lseek to data at %" PRId64 " failed", static_cast<int64_t>(data_offset));
- return kIoError;
- }
// this should default to kUnknownCompressionMethod.
int32_t return_value = -1;
@@ -1111,52 +1117,21 @@
}
}
-bool MappedZipFile::SeekToOffset(off64_t offset) {
- if (has_fd_) {
- if (lseek64(fd_, offset, SEEK_SET) != offset) {
- ALOGE("Zip: lseek to %" PRId64 " failed: %s\n", offset, strerror(errno));
- return false;
- }
- return true;
- } else {
- if (offset < 0 || offset > static_cast<off64_t>(data_length_)) {
- ALOGE("Zip: invalid offset: %" PRId64 ", data length: %" PRId64 "\n", offset, data_length_);
- return false;
- }
-
- read_pos_ = offset;
- return true;
- }
-}
-
-bool MappedZipFile::ReadData(uint8_t* buffer, size_t read_amount) {
- if (has_fd_) {
- if (!android::base::ReadFully(fd_, buffer, read_amount)) {
- ALOGE("Zip: read from %d failed\n", fd_);
- return false;
- }
- } else {
- memcpy(buffer, static_cast<uint8_t*>(base_ptr_) + read_pos_, read_amount);
- read_pos_ += read_amount;
- }
- return true;
-}
-
// Attempts to read |len| bytes into |buf| at offset |off|.
bool MappedZipFile::ReadAtOffset(uint8_t* buf, size_t len, off64_t off) {
-#if !defined(_WIN32)
if (has_fd_) {
- if (static_cast<size_t>(TEMP_FAILURE_RETRY(pread64(fd_, buf, len, off))) != len) {
+ if (!android::base::ReadFullyAtOffset(fd_, buf, len, off)) {
ALOGE("Zip: failed to read at offset %" PRId64 "\n", off);
return false;
}
- return true;
+ } else {
+ if (off < 0 || off > static_cast<off64_t>(data_length_)) {
+ ALOGE("Zip: invalid offset: %" PRId64 ", data length: %" PRId64 "\n", off, data_length_);
+ return false;
+ }
+ memcpy(buf, static_cast<uint8_t*>(base_ptr_) + off, len);
}
-#endif
- if (!SeekToOffset(off)) {
- return false;
- }
- return ReadData(buf, len);
+ return true;
}
void CentralDirectory::Initialize(void* map_base_ptr, off64_t cd_start_offset, size_t cd_size) {
diff --git a/libziparchive/zip_archive_private.h b/libziparchive/zip_archive_private.h
index 840f1af..174aa3f 100644
--- a/libziparchive/zip_archive_private.h
+++ b/libziparchive/zip_archive_private.h
@@ -93,14 +93,10 @@
class MappedZipFile {
public:
explicit MappedZipFile(const int fd)
- : has_fd_(true), fd_(fd), base_ptr_(nullptr), data_length_(0), read_pos_(0) {}
+ : has_fd_(true), fd_(fd), base_ptr_(nullptr), data_length_(0) {}
explicit MappedZipFile(void* address, size_t length)
- : has_fd_(false),
- fd_(-1),
- base_ptr_(address),
- data_length_(static_cast<off64_t>(length)),
- read_pos_(0) {}
+ : has_fd_(false), fd_(-1), base_ptr_(address), data_length_(static_cast<off64_t>(length)) {}
bool HasFd() const { return has_fd_; }
@@ -110,10 +106,6 @@
off64_t GetFileLength() const;
- bool SeekToOffset(off64_t offset);
-
- bool ReadData(uint8_t* buffer, size_t read_amount);
-
bool ReadAtOffset(uint8_t* buf, size_t len, off64_t off);
private:
@@ -127,8 +119,6 @@
void* const base_ptr_;
const off64_t data_length_;
- // read_pos_ is the offset to the base_ptr_ where we read data from.
- size_t read_pos_;
};
class CentralDirectory {
diff --git a/libziparchive/zip_archive_stream_entry.cc b/libziparchive/zip_archive_stream_entry.cc
index 50352ef..9ec89b1 100644
--- a/libziparchive/zip_archive_stream_entry.cc
+++ b/libziparchive/zip_archive_stream_entry.cc
@@ -38,13 +38,8 @@
static constexpr size_t kBufSize = 65535;
bool ZipArchiveStreamEntry::Init(const ZipEntry& entry) {
- ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
- off64_t data_offset = entry.offset;
- if (!archive->mapped_zip.SeekToOffset(data_offset)) {
- ALOGW("lseek to data at %" PRId64 " failed: %s", data_offset, strerror(errno));
- return false;
- }
crc32_ = entry.crc32;
+ offset_ = entry.offset;
return true;
}
@@ -61,11 +56,11 @@
protected:
bool Init(const ZipEntry& entry) override;
- uint32_t length_;
+ uint32_t length_ = 0u;
private:
std::vector<uint8_t> data_;
- uint32_t computed_crc32_;
+ uint32_t computed_crc32_ = 0u;
};
bool ZipArchiveStreamEntryUncompressed::Init(const ZipEntry& entry) {
@@ -89,7 +84,7 @@
size_t bytes = (length_ > data_.size()) ? data_.size() : length_;
ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
errno = 0;
- if (!archive->mapped_zip.ReadData(data_.data(), bytes)) {
+ if (!archive->mapped_zip.ReadAtOffset(data_.data(), bytes, offset_)) {
if (errno != 0) {
ALOGE("Error reading from archive fd: %s", strerror(errno));
} else {
@@ -104,6 +99,7 @@
}
computed_crc32_ = crc32(computed_crc32_, data_.data(), data_.size());
length_ -= bytes;
+ offset_ += bytes;
return &data_;
}
@@ -129,9 +125,9 @@
z_stream z_stream_;
std::vector<uint8_t> in_;
std::vector<uint8_t> out_;
- uint32_t uncompressed_length_;
- uint32_t compressed_length_;
- uint32_t computed_crc32_;
+ uint32_t uncompressed_length_ = 0u;
+ uint32_t compressed_length_ = 0u;
+ uint32_t computed_crc32_ = 0u;
};
// This method is using libz macros with old-style-casts
@@ -210,7 +206,7 @@
size_t bytes = (compressed_length_ > in_.size()) ? in_.size() : compressed_length_;
ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
errno = 0;
- if (!archive->mapped_zip.ReadData(in_.data(), bytes)) {
+ if (!archive->mapped_zip.ReadAtOffset(in_.data(), bytes, offset_)) {
if (errno != 0) {
ALOGE("Error reading from archive fd: %s", strerror(errno));
} else {
@@ -220,6 +216,7 @@
}
compressed_length_ -= bytes;
+ offset_ += bytes;
z_stream_.next_in = in_.data();
z_stream_.avail_in = bytes;
}
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/sdcard/Android.mk b/sdcard/Android.mk
index 0c58574..5b4dc58 100644
--- a/sdcard/Android.mk
+++ b/sdcard/Android.mk
@@ -8,6 +8,5 @@
LOCAL_SHARED_LIBRARIES := libbase libcutils libminijail libpackagelistparser
LOCAL_SANITIZE := integer
-LOCAL_CLANG := true
include $(BUILD_EXECUTABLE)