Merge "debuggerd: remove obsolete dumpable check."
diff --git a/adb/Android.mk b/adb/Android.mk
index c51e0b8..b444afa 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -216,9 +216,9 @@
LOCAL_SRC_FILES_darwin := $(LIBADB_TEST_darwin_SRCS)
LOCAL_SRC_FILES_windows := $(LIBADB_TEST_windows_SRCS)
LOCAL_SANITIZE := $(adb_host_sanitize)
+LOCAL_SHARED_LIBRARIES := libbase
LOCAL_STATIC_LIBRARIES := \
libadb \
- libbase \
libcrypto_utils \
libcrypto \
libcutils \
@@ -232,7 +232,7 @@
LOCAL_LDFLAGS_windows := -municode
LOCAL_LDLIBS_linux := -lrt -ldl -lpthread
LOCAL_LDLIBS_darwin := -framework CoreFoundation -framework IOKit -lobjc
-LOCAL_LDLIBS_windows := -lws2_32 -luserenv -static -lwinpthread
+LOCAL_LDLIBS_windows := -lws2_32 -luserenv
LOCAL_STATIC_LIBRARIES_windows := AdbWinApi
LOCAL_MULTILIB := first
@@ -249,7 +249,7 @@
# Use wmain instead of main
LOCAL_LDFLAGS_windows := -municode
-LOCAL_LDLIBS_windows := -lws2_32 -lgdi32 -static -lwinpthread
+LOCAL_LDLIBS_windows := -lws2_32 -lgdi32
LOCAL_STATIC_LIBRARIES_windows := AdbWinApi
LOCAL_REQUIRED_MODULES_windows := AdbWinApi AdbWinUsbApi
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 7afa616..7058acb 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -19,16 +19,15 @@
#include "adb_utils.h"
#include "adb_unique_fd.h"
-#include <libgen.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <algorithm>
-#include <mutex>
#include <vector>
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
@@ -100,52 +99,6 @@
return result;
}
-std::string adb_basename(const std::string& path) {
- static std::mutex& basename_lock = *new std::mutex();
-
- // Copy path because basename may modify the string passed in.
- std::string result(path);
-
- // Use lock because basename() may write to a process global and return a
- // pointer to that. Note that this locking strategy only works if all other
- // callers to basename in the process also grab this same lock.
- std::lock_guard<std::mutex> lock(basename_lock);
-
- // Note that if std::string uses copy-on-write strings, &str[0] will cause
- // the copy to be made, so there is no chance of us accidentally writing to
- // the storage for 'path'.
- char* name = basename(&result[0]);
-
- // In case dirname returned a pointer to a process global, copy that string
- // before leaving the lock.
- result.assign(name);
-
- return result;
-}
-
-std::string adb_dirname(const std::string& path) {
- static std::mutex& dirname_lock = *new std::mutex();
-
- // Copy path because dirname may modify the string passed in.
- std::string result(path);
-
- // Use lock because dirname() may write to a process global and return a
- // pointer to that. Note that this locking strategy only works if all other
- // callers to dirname in the process also grab this same lock.
- std::lock_guard<std::mutex> lock(dirname_lock);
-
- // Note that if std::string uses copy-on-write strings, &str[0] will cause
- // the copy to be made, so there is no chance of us accidentally writing to
- // the storage for 'path'.
- char* parent = dirname(&result[0]);
-
- // In case dirname returned a pointer to a process global, copy that string
- // before leaving the lock.
- result.assign(parent);
-
- return result;
-}
-
// Given a relative or absolute filepath, create the directory hierarchy
// as needed. Returns true if the hierarchy is/was setup.
bool mkdirs(const std::string& path) {
@@ -171,7 +124,7 @@
return true;
}
- const std::string parent(adb_dirname(path));
+ const std::string parent(android::base::Dirname(path));
// If dirname returned the same path as what we passed in, don't go recursive.
// This can happen on Windows when walking up the directory hierarchy and not
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index 2b59034..e0ad103 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -28,11 +28,6 @@
bool getcwd(std::string* cwd);
bool directory_exists(const std::string& path);
-// Like the regular basename and dirname, but thread-safe on all
-// platforms and capable of correctly handling exotic Windows paths.
-std::string adb_basename(const std::string& path);
-std::string adb_dirname(const std::string& path);
-
// Return the user's home directory.
std::string adb_get_homedir_path();
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
index 4cac485..a3bc445 100644
--- a/adb/adb_utils_test.cpp
+++ b/adb/adb_utils_test.cpp
@@ -109,18 +109,6 @@
ASSERT_EQ(R"('abc)')", escape_arg("abc)"));
}
-TEST(adb_utils, adb_basename) {
- EXPECT_EQ("sh", adb_basename("/system/bin/sh"));
- EXPECT_EQ("sh", adb_basename("sh"));
- EXPECT_EQ("sh", adb_basename("/system/bin/sh/"));
-}
-
-TEST(adb_utils, adb_dirname) {
- EXPECT_EQ("/system/bin", adb_dirname("/system/bin/sh"));
- EXPECT_EQ(".", adb_dirname("sh"));
- EXPECT_EQ("/system/bin", adb_dirname("/system/bin/sh/"));
-}
-
void test_mkdirs(const std::string& basepath) {
// Test creating a directory hierarchy.
ASSERT_TRUE(mkdirs(basepath));
diff --git a/adb/bugreport.cpp b/adb/bugreport.cpp
index b7e76a6..a5c312b 100644
--- a/adb/bugreport.cpp
+++ b/adb/bugreport.cpp
@@ -21,6 +21,7 @@
#include <string>
#include <vector>
+#include <android-base/file.h>
#include <android-base/strings.h>
#include "sysdeps.h"
@@ -113,14 +114,14 @@
private:
void SetLineMessage(const std::string& action) {
- line_message_ = action + " " + adb_basename(dest_file_);
+ line_message_ = action + " " + android::base::Basename(dest_file_);
}
void SetSrcFile(const std::string path) {
src_file_ = path;
if (!dest_dir_.empty()) {
// Only uses device-provided name when user passed a directory.
- dest_file_ = adb_basename(path);
+ dest_file_ = android::base::Basename(path);
SetLineMessage("generating");
}
}
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 5a2206f..3de7be6 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -2115,7 +2115,8 @@
std::string cmd = android::base::StringPrintf(
"%s install-write -S %" PRIu64 " %d %d_%s -",
- install_cmd.c_str(), static_cast<uint64_t>(sb.st_size), session_id, i, adb_basename(file).c_str());
+ install_cmd.c_str(), static_cast<uint64_t>(sb.st_size), session_id, i,
+ android::base::Basename(file).c_str());
int localFd = adb_open(file, O_RDONLY);
if (localFd < 0) {
@@ -2233,7 +2234,7 @@
int result = -1;
std::vector<const char*> apk_file = {argv[last_apk]};
std::string apk_dest = android::base::StringPrintf(
- where, adb_basename(argv[last_apk]).c_str());
+ where, android::base::Basename(argv[last_apk]).c_str());
if (!do_sync_push(apk_file, apk_dest.c_str())) goto cleanup_apk;
argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
result = pm_command(transport, serial, argc, argv);
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index 271943d..22bd2f2 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -844,7 +844,8 @@
// TODO(b/25566053): Make pushing empty directories work.
// TODO(b/25457350): We don't preserve permissions on directories.
sc.Warning("skipping empty directory '%s'", lpath.c_str());
- copyinfo ci(adb_dirname(lpath), adb_dirname(rpath), adb_basename(lpath), S_IFDIR);
+ copyinfo ci(android::base::Dirname(lpath), android::base::Dirname(rpath),
+ android::base::Basename(lpath), S_IFDIR);
ci.skip = true;
file_list->push_back(ci);
return true;
@@ -977,7 +978,7 @@
if (dst_dir.back() != '/') {
dst_dir.push_back('/');
}
- dst_dir.append(adb_basename(src_path));
+ dst_dir.append(android::base::Basename(src_path));
}
success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(), false, false);
@@ -995,7 +996,7 @@
if (path_holder.back() != '/') {
path_holder.push_back('/');
}
- path_holder += adb_basename(src_path);
+ path_holder += android::base::Basename(src_path);
dst_path = path_holder.c_str();
}
@@ -1015,7 +1016,8 @@
std::vector<copyinfo> linklist;
// Add an entry for the current directory to ensure it gets created before pulling its contents.
- copyinfo ci(adb_dirname(lpath), adb_dirname(rpath), adb_basename(lpath), S_IFDIR);
+ copyinfo ci(android::base::Dirname(lpath), android::base::Dirname(rpath),
+ android::base::Basename(lpath), S_IFDIR);
file_list->push_back(ci);
// Put the files/dirs in rpath on the lists.
@@ -1149,7 +1151,7 @@
if (srcs.size() == 1 && errno == ENOENT) {
// However, its parent must exist.
struct stat parent_st;
- if (stat(adb_dirname(dst).c_str(), &parent_st) == -1) {
+ if (stat(android::base::Dirname(dst).c_str(), &parent_st) == -1) {
sc.Error("cannot create file/directory '%s': %s", dst, strerror(errno));
return false;
}
@@ -1204,7 +1206,7 @@
if (!adb_is_separator(dst_dir.back())) {
dst_dir.push_back(OS_PATH_SEPARATOR);
}
- dst_dir.append(adb_basename(src_path));
+ dst_dir.append(android::base::Basename(src_path));
}
success &= copy_remote_dir_local(sc, src_path, dst_dir.c_str(), copy_attrs);
@@ -1220,7 +1222,7 @@
// really want to copy to local_dir + OS_PATH_SEPARATOR +
// basename(remote).
path_holder = android::base::StringPrintf("%s%c%s", dst_path, OS_PATH_SEPARATOR,
- adb_basename(src_path).c_str());
+ android::base::Basename(src_path).c_str());
dst_path = path_holder.c_str();
}
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index e667bf8..2acf661 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -31,6 +31,7 @@
#include <unistd.h>
#include <utime.h>
+#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <private/android_filesystem_config.h>
@@ -206,7 +207,7 @@
int fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
if (fd < 0 && errno == ENOENT) {
- if (!secure_mkdirs(adb_dirname(path))) {
+ if (!secure_mkdirs(android::base::Dirname(path))) {
SendSyncFailErrno(s, "secure_mkdirs failed");
goto fail;
}
@@ -333,7 +334,7 @@
ret = symlink(&buffer[0], path.c_str());
if (ret && errno == ENOENT) {
- if (!secure_mkdirs(adb_dirname(path))) {
+ if (!secure_mkdirs(android::base::Dirname(path))) {
SendSyncFailErrno(s, "secure_mkdirs failed");
return false;
}
diff --git a/adb/set_verity_enable_state_service.cpp b/adb/set_verity_enable_state_service.cpp
index f9e028b..76b156d 100644
--- a/adb/set_verity_enable_state_service.cpp
+++ b/adb/set_verity_enable_state_service.cpp
@@ -108,11 +108,10 @@
return;
}
- std::string fstab_filename = "/fstab." + android::base::GetProperty("ro.hardware", "");
-
- fstab = fs_mgr_read_fstab(fstab_filename.c_str());
+ // read all fstab entries at once from all sources
+ fstab = fs_mgr_read_fstab_default();
if (!fstab) {
- WriteFdFmt(fd, "Failed to open %s\nMaybe run adb root?\n", fstab_filename.c_str());
+ WriteFdFmt(fd, "Failed to read fstab\nMaybe run adb root?\n");
return;
}
diff --git a/adf/libadf/Android.bp b/adf/libadf/Android.bp
index 1a81a49..c276c53 100644
--- a/adf/libadf/Android.bp
+++ b/adf/libadf/Android.bp
@@ -14,7 +14,7 @@
cc_library_static {
name: "libadf",
- srcs: ["adf.c"],
+ srcs: ["adf.cpp"],
cflags: ["-Werror"],
local_include_dirs: ["include"],
export_include_dirs: ["include"],
diff --git a/adf/libadf/adf.c b/adf/libadf/adf.cpp
similarity index 73%
rename from adf/libadf/adf.c
rename to adf/libadf/adf.cpp
index 10f88b0..60d8ef0 100644
--- a/adf/libadf/adf.c
+++ b/adf/libadf/adf.cpp
@@ -23,6 +23,10 @@
#include <string.h>
#include <unistd.h>
+#include <algorithm>
+#include <memory>
+#include <vector>
+
#include <linux/limits.h>
#include <sys/ioctl.h>
@@ -31,52 +35,44 @@
#define ADF_BASE_PATH "/dev/"
-static ssize_t adf_find_nodes(const char *pattern, adf_id_t **ids)
+static ssize_t adf_id_vector_to_array(const std::vector<adf_id_t> &in,
+ adf_id_t **out)
{
- DIR *dir;
- struct dirent *dirent;
- size_t n = 0;
- ssize_t ret;
- adf_id_t *ids_ret = NULL;
+ auto size = sizeof(in[0]) * in.size();
+ // We can't use new[] since the existing API says the caller should free()
+ // the returned array
+ auto ret = static_cast<adf_id_t *>(malloc(size));
+ if (!ret)
+ return -ENOMEM;
- dir = opendir(ADF_BASE_PATH);
+ std::copy(in.begin(), in.end(), ret);
+ *out = ret;
+ return in.size();
+}
+
+static ssize_t adf_find_nodes(const char *pattern, adf_id_t **ids_out)
+{
+ struct dirent *dirent;
+ std::unique_ptr<DIR, decltype(&closedir)>
+ dir{opendir(ADF_BASE_PATH), closedir};
if (!dir)
return -errno;
+ std::vector<adf_id_t> ids;
errno = 0;
- while ((dirent = readdir(dir))) {
+ while ((dirent = readdir(dir.get()))) {
adf_id_t id;
int matched = sscanf(dirent->d_name, pattern, &id);
- if (matched < 0) {
- ret = -errno;
- goto done;
- } else if (matched != 1) {
- continue;
- }
-
- adf_id_t *new_ids = realloc(ids_ret, (n + 1) * sizeof(ids_ret[0]));
- if (!new_ids) {
- ret = -ENOMEM;
- goto done;
- }
-
- ids_ret = new_ids;
- ids_ret[n] = id;
- n++;
+ if (matched < 0)
+ return -errno;
+ else if (matched == 1)
+ ids.push_back(id);
}
if (errno)
- ret = -errno;
- else
- ret = n;
+ return -errno;
-done:
- closedir(dir);
- if (ret < 0)
- free(ids_ret);
- else
- *ids = ids_ret;
- return ret;
+ return adf_id_vector_to_array(ids, ids_out);
}
ssize_t adf_devices(adf_id_t **ids)
@@ -115,46 +111,29 @@
if (err < 0)
return -ENOMEM;
- if (data->n_attachments) {
- data->attachments = malloc(sizeof(data->attachments[0]) *
- data->n_attachments);
- if (!data->attachments)
- return -ENOMEM;
- }
+ if (data->n_attachments)
+ data->attachments = new adf_attachment_config[data->n_attachments];
- if (data->n_allowed_attachments) {
+ if (data->n_allowed_attachments)
data->allowed_attachments =
- malloc(sizeof(data->allowed_attachments[0]) *
- data->n_allowed_attachments);
- if (!data->allowed_attachments) {
- ret = -ENOMEM;
- goto done;
- }
- }
+ new adf_attachment_config[data->n_allowed_attachments];
- if (data->custom_data_size) {
- data->custom_data = malloc(data->custom_data_size);
- if (!data->custom_data) {
- ret = -ENOMEM;
- goto done;
- }
- }
+ if (data->custom_data_size)
+ data->custom_data = new char[data->custom_data_size];
err = ioctl(dev->fd, ADF_GET_DEVICE_DATA, data);
- if (err < 0)
+ if (err < 0) {
ret = -errno;
-
-done:
- if (ret < 0)
adf_free_device_data(data);
+ }
return ret;
}
void adf_free_device_data(struct adf_device_data *data)
{
- free(data->attachments);
- free(data->allowed_attachments);
- free(data->custom_data);
+ delete [] data->attachments;
+ delete [] data->allowed_attachments;
+ delete [] static_cast<char *>(data->custom_data);
}
int adf_device_post(struct adf_device *dev,
@@ -252,39 +231,17 @@
adf_id_t overlay_engine, adf_id_t **interfaces)
{
struct adf_device_data data;
- ssize_t n = 0;
- ssize_t ret;
- adf_id_t *ids_ret = NULL;
+ auto err = adf_get_device_data(dev, &data);
+ if (err < 0)
+ return err;
- ret = adf_get_device_data(dev, &data);
- if (ret < 0)
- return ret;
+ std::vector<adf_id_t> ids;
+ for (size_t i = 0; i < data.n_allowed_attachments; i++)
+ if (data.allowed_attachments[i].overlay_engine == overlay_engine)
+ ids.push_back(data.allowed_attachments[i].interface);
- size_t i;
- for (i = 0; i < data.n_allowed_attachments; i++) {
- if (data.allowed_attachments[i].overlay_engine != overlay_engine)
- continue;
-
- adf_id_t *new_ids = realloc(ids_ret, (n + 1) * sizeof(ids_ret[0]));
- if (!new_ids) {
- ret = -ENOMEM;
- goto done;
- }
-
- ids_ret = new_ids;
- ids_ret[n] = data.allowed_attachments[i].interface;
- n++;
- }
-
- ret = n;
-
-done:
adf_free_device_data(&data);
- if (ret < 0)
- free(ids_ret);
- else
- *interfaces = ids_ret;
- return ret;
+ return adf_id_vector_to_array(ids, interfaces);
}
static ssize_t adf_interfaces_filter(struct adf_device *dev,
@@ -292,46 +249,23 @@
bool (*filter)(struct adf_interface_data *data, __u32 match),
__u32 match)
{
- size_t n = 0;
- ssize_t ret;
- adf_id_t *ids_ret = NULL;
-
- size_t i;
- for (i = 0; i < n_in; i++) {
+ std::vector<adf_id_t> ids;
+ for (size_t i = 0; i < n_in; i++) {
int fd = adf_interface_open(dev, in[i], O_RDONLY);
- if (fd < 0) {
- ret = fd;
- goto done;
- }
+ if (fd < 0)
+ return fd;
struct adf_interface_data data;
- ret = adf_get_interface_data(fd, &data);
+ auto ret = adf_get_interface_data(fd, &data);
close(fd);
if (ret < 0)
- goto done;
+ return ret;
- if (!filter(&data, match))
- continue;
-
- adf_id_t *new_ids = realloc(ids_ret, (n + 1) * sizeof(ids_ret[0]));
- if (!new_ids) {
- ret = -ENOMEM;
- goto done;
- }
-
- ids_ret = new_ids;
- ids_ret[n] = in[i];
- n++;
+ if (filter(&data, match))
+ ids.push_back(in[i]);
}
- ret = n;
-
-done:
- if (ret < 0)
- free(ids_ret);
- else
- *out = ids_ret;
- return ret;
+ return adf_id_vector_to_array(ids, out);
}
static bool adf_interface_type_filter(struct adf_interface_data *data,
@@ -385,35 +319,24 @@
if (err < 0)
return -errno;
- if (data->n_available_modes) {
- data->available_modes = malloc(sizeof(data->available_modes[0]) *
- data->n_available_modes);
- if (!data->available_modes)
- return -ENOMEM;
- }
+ if (data->n_available_modes)
+ data->available_modes = new drm_mode_modeinfo[data->n_available_modes];
- if (data->custom_data_size) {
- data->custom_data = malloc(data->custom_data_size);
- if (!data->custom_data) {
- ret = -ENOMEM;
- goto done;
- }
- }
+ if (data->custom_data_size)
+ data->custom_data = new char[data->custom_data_size];
err = ioctl(fd, ADF_GET_INTERFACE_DATA, data);
- if (err < 0)
+ if (err < 0) {
ret = -errno;
-
-done:
- if (ret < 0)
adf_free_interface_data(data);
+ }
return ret;
}
void adf_free_interface_data(struct adf_interface_data *data)
{
- free(data->available_modes);
- free(data->custom_data);
+ delete [] data->available_modes;
+ delete [] static_cast<char *>(data->custom_data);
}
int adf_interface_blank(int fd, __u8 mode)
@@ -522,39 +445,16 @@
adf_id_t interface, adf_id_t **overlay_engines)
{
struct adf_device_data data;
- ssize_t n = 0;
- ssize_t ret;
- adf_id_t *ids_ret = NULL;
+ auto err = adf_get_device_data(dev, &data);
+ if (err < 0)
+ return err;
- ret = adf_get_device_data(dev, &data);
- if (ret < 0)
- return ret;
+ std::vector<adf_id_t> ids;
+ for (size_t i = 0; i < data.n_allowed_attachments; i++)
+ if (data.allowed_attachments[i].interface == interface)
+ ids.push_back(data.allowed_attachments[i].overlay_engine);
- size_t i;
- for (i = 0; i < data.n_allowed_attachments; i++) {
- if (data.allowed_attachments[i].interface != interface)
- continue;
-
- adf_id_t *new_ids = realloc(ids_ret, (n + 1) * sizeof(ids_ret[0]));
- if (!new_ids) {
- ret = -ENOMEM;
- goto done;
- }
-
- ids_ret = new_ids;
- ids_ret[n] = data.allowed_attachments[i].overlay_engine;
- n++;
- }
-
- ret = n;
-
-done:
- adf_free_device_data(&data);
- if (ret < 0)
- free(ids_ret);
- else
- *overlay_engines = ids_ret;
- return ret;
+ return adf_id_vector_to_array(ids, overlay_engines);
}
static ssize_t adf_overlay_engines_filter(struct adf_device *dev,
@@ -562,46 +462,24 @@
bool (*filter)(struct adf_overlay_engine_data *data, void *cookie),
void *cookie)
{
- size_t n = 0;
- ssize_t ret;
- adf_id_t *ids_ret = NULL;
-
+ std::vector<adf_id_t> ids;
size_t i;
for (i = 0; i < n_in; i++) {
int fd = adf_overlay_engine_open(dev, in[i], O_RDONLY);
- if (fd < 0) {
- ret = fd;
- goto done;
- }
+ if (fd < 0)
+ return fd;
struct adf_overlay_engine_data data;
- ret = adf_get_overlay_engine_data(fd, &data);
+ auto ret = adf_get_overlay_engine_data(fd, &data);
close(fd);
if (ret < 0)
- goto done;
+ return ret;
- if (!filter(&data, cookie))
- continue;
-
- adf_id_t *new_ids = realloc(ids_ret, (n + 1) * sizeof(ids_ret[0]));
- if (!new_ids) {
- ret = -ENOMEM;
- goto done;
- }
-
- ids_ret = new_ids;
- ids_ret[n] = in[i];
- n++;
+ if (filter(&data, cookie))
+ ids.push_back(in[i]);
}
- ret = n;
-
-done:
- if (ret < 0)
- free(ids_ret);
- else
- *out = ids_ret;
- return ret;
+ return adf_id_vector_to_array(ids, out);
}
struct format_filter_cookie {
@@ -612,7 +490,7 @@
static bool adf_overlay_engine_format_filter(
struct adf_overlay_engine_data *data, void *cookie)
{
- struct format_filter_cookie *c = cookie;
+ auto c = static_cast<format_filter_cookie *>(cookie);
size_t i;
for (i = 0; i < data->n_supported_formats; i++) {
size_t j;
@@ -656,35 +534,24 @@
if (err < 0)
return -errno;
- if (data->n_supported_formats) {
- data->supported_formats = malloc(sizeof(data->supported_formats[0]) *
- data->n_supported_formats);
- if (!data->supported_formats)
- return -ENOMEM;
- }
+ if (data->n_supported_formats)
+ data->supported_formats = new __u32[data->n_supported_formats];
- if (data->custom_data_size) {
- data->custom_data = malloc(data->custom_data_size);
- if (!data->custom_data) {
- ret = -ENOMEM;
- goto done;
- }
- }
+ if (data->custom_data_size)
+ data->custom_data = new char[data->custom_data_size];
err = ioctl(fd, ADF_GET_OVERLAY_ENGINE_DATA, data);
- if (err < 0)
+ if (err < 0) {
ret = -errno;
-
-done:
- if (ret < 0)
adf_free_overlay_engine_data(data);
+ }
return ret;
}
void adf_free_overlay_engine_data(struct adf_overlay_engine_data *data)
{
- free(data->supported_formats);
- free(data->custom_data);
+ delete [] data->supported_formats;
+ delete [] static_cast<char *>(data->custom_data);
}
bool adf_overlay_engine_supports_format(int fd, __u32 format)
@@ -724,12 +591,12 @@
int adf_read_event(int fd, struct adf_event **event)
{
struct adf_event header;
- struct {
+ struct event_with_data {
struct adf_event base;
uint8_t data[0];
- } *event_ret;
+ };
+ using unique_event = std::unique_ptr<event_with_data, decltype(&free)>;
size_t data_size;
- int ret = 0;
int err = read(fd, &header, sizeof(header));
if (err < 0)
@@ -739,28 +606,23 @@
if (header.length < sizeof(header))
return -EIO;
- event_ret = malloc(header.length);
+ // Again, we can't use new[] since the existing API says the caller should
+ // free() the returned event
+ auto event_ptr = static_cast<event_with_data *>(malloc(header.length));
+ unique_event event_ret{event_ptr, free};
if (!event_ret)
return -ENOMEM;
data_size = header.length - sizeof(header);
- memcpy(event_ret, &header, sizeof(header));
+ memcpy(event_ret.get(), &header, sizeof(header));
ssize_t read_size = read(fd, &event_ret->data, data_size);
- if (read_size < 0) {
- ret = -errno;
- goto done;
- }
- if ((size_t)read_size < data_size) {
- ret = -EIO;
- goto done;
- }
+ if (read_size < 0)
+ return -errno;
+ if ((size_t)read_size < data_size)
+ return -EIO;
- *event = &event_ret->base;
-
-done:
- if (ret < 0)
- free(event_ret);
- return ret;
+ *event = &event_ret.release()->base;
+ return 0;
}
void adf_format_str(__u32 format, char buf[ADF_FORMAT_STR_SIZE])
diff --git a/adf/libadf/tests/adf_test.cpp b/adf/libadf/tests/adf_test.cpp
index 4727c2b..82a91f4 100644
--- a/adf/libadf/tests/adf_test.cpp
+++ b/adf/libadf/tests/adf_test.cpp
@@ -188,7 +188,7 @@
const size_t AdfTest::n_fmt8888 = sizeof(fmt8888) / sizeof(fmt8888[0]);
TEST(adf, devices) {
- adf_id_t *devs;
+ adf_id_t *devs = nullptr;
ssize_t n_devs = adf_devices(&devs);
free(devs);
diff --git a/base/Android.bp b/base/Android.bp
index 694e029..7b1dc8e 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -78,6 +78,7 @@
host_supported: true,
clang: true,
srcs: [
+ "endian_test.cpp",
"errors_test.cpp",
"file_test.cpp",
"logging_test.cpp",
diff --git a/base/endian_test.cpp b/base/endian_test.cpp
new file mode 100644
index 0000000..963ab13
--- /dev/null
+++ b/base/endian_test.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "android-base/endian.h"
+
+#include <gtest/gtest.h>
+
+TEST(endian, constants) {
+ ASSERT_TRUE(__LITTLE_ENDIAN == LITTLE_ENDIAN);
+ ASSERT_TRUE(__BIG_ENDIAN == BIG_ENDIAN);
+ ASSERT_TRUE(__BYTE_ORDER == BYTE_ORDER);
+
+ ASSERT_EQ(__LITTLE_ENDIAN, __BYTE_ORDER);
+}
+
+TEST(endian, smoke) {
+ static constexpr uint16_t le16 = 0x1234;
+ static constexpr uint32_t le32 = 0x12345678;
+ static constexpr uint64_t le64 = 0x123456789abcdef0;
+
+ static constexpr uint16_t be16 = 0x3412;
+ static constexpr uint32_t be32 = 0x78563412;
+ static constexpr uint64_t be64 = 0xf0debc9a78563412;
+
+ ASSERT_EQ(be16, htons(le16));
+ ASSERT_EQ(be32, htonl(le32));
+ ASSERT_EQ(be64, htonq(le64));
+
+ ASSERT_EQ(le16, ntohs(be16));
+ ASSERT_EQ(le32, ntohl(be32));
+ ASSERT_EQ(le64, ntohq(be64));
+
+ ASSERT_EQ(be16, htobe16(le16));
+ ASSERT_EQ(be32, htobe32(le32));
+ ASSERT_EQ(be64, htobe64(le64));
+
+ ASSERT_EQ(le16, betoh16(be16));
+ ASSERT_EQ(le32, betoh32(be32));
+ ASSERT_EQ(le64, betoh64(be64));
+
+ ASSERT_EQ(le16, htole16(le16));
+ ASSERT_EQ(le32, htole32(le32));
+ ASSERT_EQ(le64, htole64(le64));
+
+ ASSERT_EQ(le16, letoh16(le16));
+ ASSERT_EQ(le32, letoh32(le32));
+ ASSERT_EQ(le64, letoh64(le64));
+
+ ASSERT_EQ(le16, be16toh(be16));
+ ASSERT_EQ(le32, be32toh(be32));
+ ASSERT_EQ(le64, be64toh(be64));
+
+ ASSERT_EQ(le16, le16toh(le16));
+ ASSERT_EQ(le32, le32toh(le32));
+ ASSERT_EQ(le64, le64toh(le64));
+}
diff --git a/base/file.cpp b/base/file.cpp
index 6284b04..81b04d7 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -18,11 +18,13 @@
#include <errno.h>
#include <fcntl.h>
+#include <libgen.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <memory>
+#include <mutex>
#include <string>
#include <vector>
@@ -236,5 +238,59 @@
#endif
}
+std::string GetExecutableDirectory() {
+ return Dirname(GetExecutablePath());
+}
+
+std::string Basename(const std::string& path) {
+ // Copy path because basename may modify the string passed in.
+ std::string result(path);
+
+#if !defined(__BIONIC__)
+ // Use lock because basename() may write to a process global and return a
+ // pointer to that. Note that this locking strategy only works if all other
+ // callers to basename in the process also grab this same lock, but its
+ // better than nothing. Bionic's basename returns a thread-local buffer.
+ static std::mutex& basename_lock = *new std::mutex();
+ std::lock_guard<std::mutex> lock(basename_lock);
+#endif
+
+ // Note that if std::string uses copy-on-write strings, &str[0] will cause
+ // the copy to be made, so there is no chance of us accidentally writing to
+ // the storage for 'path'.
+ char* name = basename(&result[0]);
+
+ // In case basename returned a pointer to a process global, copy that string
+ // before leaving the lock.
+ result.assign(name);
+
+ return result;
+}
+
+std::string Dirname(const std::string& path) {
+ // Copy path because dirname may modify the string passed in.
+ std::string result(path);
+
+#if !defined(__BIONIC__)
+ // Use lock because dirname() may write to a process global and return a
+ // pointer to that. Note that this locking strategy only works if all other
+ // callers to dirname in the process also grab this same lock, but its
+ // better than nothing. Bionic's dirname returns a thread-local buffer.
+ static std::mutex& dirname_lock = *new std::mutex();
+ std::lock_guard<std::mutex> lock(dirname_lock);
+#endif
+
+ // Note that if std::string uses copy-on-write strings, &str[0] will cause
+ // the copy to be made, so there is no chance of us accidentally writing to
+ // the storage for 'path'.
+ char* parent = dirname(&result[0]);
+
+ // In case dirname returned a pointer to a process global, copy that string
+ // before leaving the lock.
+ result.assign(parent);
+
+ return result;
+}
+
} // namespace base
} // namespace android
diff --git a/base/file_test.cpp b/base/file_test.cpp
index ed39ce9..1021326 100644
--- a/base/file_test.cpp
+++ b/base/file_test.cpp
@@ -159,6 +159,26 @@
#endif
}
+TEST(file, GetExecutableDirectory) {
+ std::string path = android::base::GetExecutableDirectory();
+ ASSERT_NE("", path);
+ ASSERT_NE(android::base::GetExecutablePath(), path);
+ ASSERT_EQ('/', path[0]);
+ ASSERT_NE('/', path[path.size() - 1]);
+}
+
TEST(file, GetExecutablePath) {
ASSERT_NE("", android::base::GetExecutablePath());
}
+
+TEST(file, Basename) {
+ EXPECT_EQ("sh", android::base::Basename("/system/bin/sh"));
+ EXPECT_EQ("sh", android::base::Basename("sh"));
+ EXPECT_EQ("sh", android::base::Basename("/system/bin/sh/"));
+}
+
+TEST(file, Dirname) {
+ EXPECT_EQ("/system/bin", android::base::Dirname("/system/bin/sh"));
+ EXPECT_EQ(".", android::base::Dirname("sh"));
+ EXPECT_EQ("/system/bin", android::base::Dirname("/system/bin/sh/"));
+}
diff --git a/base/include/android-base/endian.h b/base/include/android-base/endian.h
new file mode 100644
index 0000000..6eb677c
--- /dev/null
+++ b/base/include/android-base/endian.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_BASE_ENDIAN_H
+#define ANDROID_BASE_ENDIAN_H
+
+/* A cross-platform equivalent of bionic's <sys/endian.h>. */
+
+#if defined(__BIONIC__)
+
+#include <sys/endian.h>
+
+#elif defined(__GLIBC__)
+
+/* glibc's <endian.h> is like bionic's <sys/endian.h>. */
+#include <endian.h>
+
+/* glibc keeps htons and htonl in <netinet/in.h>. */
+#include <netinet/in.h>
+
+/* glibc doesn't have the 64-bit variants. */
+#define htonq(x) htobe64(x)
+#define ntohq(x) be64toh(x)
+
+/* glibc has different names to BSD for these. */
+#define betoh16(x) be16toh(x)
+#define betoh32(x) be32toh(x)
+#define betoh64(x) be64toh(x)
+
+#else
+
+/* Mac OS and Windows have nothing. */
+
+#define __LITTLE_ENDIAN 1234
+#define LITTLE_ENDIAN __LITTLE_ENDIAN
+
+#define __BIG_ENDIAN 4321
+#define BIG_ENDIAN __BIG_ENDIAN
+
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#define BYTE_ORDER __BYTE_ORDER
+
+#define htons(x) __builtin_bswap16(x)
+#define htonl(x) __builtin_bswap32(x)
+#define htonq(x) __builtin_bswap64(x)
+
+#define ntohs(x) __builtin_bswap16(x)
+#define ntohl(x) __builtin_bswap32(x)
+#define ntohq(x) __builtin_bswap64(x)
+
+#define htobe16(x) __builtin_bswap16(x)
+#define htobe32(x) __builtin_bswap32(x)
+#define htobe64(x) __builtin_bswap64(x)
+
+#define betoh16(x) __builtin_bswap16(x)
+#define betoh32(x) __builtin_bswap32(x)
+#define betoh64(x) __builtin_bswap64(x)
+
+#define htole16(x) (x)
+#define htole32(x) (x)
+#define htole64(x) (x)
+
+#define letoh16(x) (x)
+#define letoh32(x) (x)
+#define letoh64(x) (x)
+
+#define be16toh(x) __builtin_bswap16(x)
+#define be32toh(x) __builtin_bswap32(x)
+#define be64toh(x) __builtin_bswap64(x)
+
+#define le16toh(x) (x)
+#define le32toh(x) (x)
+#define le64toh(x) (x)
+
+#endif
+
+#endif // ANDROID_BASE_ENDIAN_H
diff --git a/base/include/android-base/file.h b/base/include/android-base/file.h
index cd64262..33d1ab3 100644
--- a/base/include/android-base/file.h
+++ b/base/include/android-base/file.h
@@ -51,6 +51,12 @@
#endif
std::string GetExecutablePath();
+std::string GetExecutableDirectory();
+
+// Like the regular basename and dirname, but thread-safe on all
+// platforms and capable of correctly handling exotic Windows paths.
+std::string Basename(const std::string& path);
+std::string Dirname(const std::string& path);
} // namespace base
} // namespace android
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
index 50677a3..e78edbb 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -17,6 +17,37 @@
#ifndef ANDROID_BASE_LOGGING_H
#define ANDROID_BASE_LOGGING_H
+//
+// Google-style C++ logging.
+//
+
+// This header provides a C++ stream interface to logging.
+//
+// To log:
+//
+// LOG(INFO) << "Some text; " << some_value;
+//
+// Replace `INFO` with any severity from `enum LogSeverity`.
+//
+// To log the result of a failed function and include the string
+// representation of `errno` at the end:
+//
+// PLOG(ERROR) << "Write failed";
+//
+// The output will be something like `Write failed: I/O error`.
+// Remember this as 'P' as in perror(3).
+//
+// To output your own types, simply implement operator<< as normal.
+//
+// By default, output goes to logcat on Android and stderr on the host.
+// A process can use `SetLogger` to decide where all logging goes.
+// Implementations are provided for logcat, stderr, and dmesg.
+
+// This header also provides assertions:
+//
+// CHECK(must_be_true);
+// CHECK_EQ(a, b) << z_is_interesting_too;
+
// NOTE: For Windows, you must include logging.h after windows.h to allow the
// following code to suppress the evil ERROR macro:
#ifdef _WIN32
diff --git a/base/include/android-base/properties.h b/base/include/android-base/properties.h
index e2324b7..4de5e57 100644
--- a/base/include/android-base/properties.h
+++ b/base/include/android-base/properties.h
@@ -66,6 +66,12 @@
const std::string& expected_value,
std::chrono::milliseconds relative_timeout);
+// Waits for the system property `key` to be created.
+// Times out after `relative_timeout`.
+// Returns true on success, false on timeout.
+bool WaitForPropertyCreation(const std::string& key,
+ std::chrono::milliseconds relative_timeout);
+
} // namespace base
} // namespace android
diff --git a/base/properties.cpp b/base/properties.cpp
index acd6c0f..32c0128 100644
--- a/base/properties.cpp
+++ b/base/properties.cpp
@@ -108,8 +108,10 @@
ts.tv_nsec = ns.count();
}
+using AbsTime = std::chrono::time_point<std::chrono::steady_clock>;
+
static void UpdateTimeSpec(timespec& ts,
- const std::chrono::time_point<std::chrono::steady_clock>& timeout) {
+ const AbsTime& timeout) {
auto now = std::chrono::steady_clock::now();
auto remaining_timeout = std::chrono::duration_cast<std::chrono::nanoseconds>(timeout - now);
if (remaining_timeout < 0ns) {
@@ -119,13 +121,16 @@
}
}
-bool WaitForProperty(const std::string& key,
- const std::string& expected_value,
- std::chrono::milliseconds relative_timeout) {
+// Waits for the system property `key` to be created.
+// Times out after `relative_timeout`.
+// Sets absolute_timeout which represents absolute time for the timeout.
+// Returns nullptr on timeout.
+static const prop_info* WaitForPropertyCreation(const std::string& key,
+ const std::chrono::milliseconds& relative_timeout,
+ AbsTime& absolute_timeout) {
// TODO: boot_clock?
auto now = std::chrono::steady_clock::now();
- std::chrono::time_point<std::chrono::steady_clock> absolute_timeout = now + relative_timeout;
- timespec ts;
+ absolute_timeout = now + relative_timeout;
// Find the property's prop_info*.
const prop_info* pi;
@@ -133,14 +138,25 @@
while ((pi = __system_property_find(key.c_str())) == nullptr) {
// The property doesn't even exist yet.
// Wait for a global change and then look again.
+ timespec ts;
UpdateTimeSpec(ts, absolute_timeout);
- if (!__system_property_wait(nullptr, global_serial, &global_serial, &ts)) return false;
+ if (!__system_property_wait(nullptr, global_serial, &global_serial, &ts)) return nullptr;
}
+ return pi;
+}
+
+bool WaitForProperty(const std::string& key,
+ const std::string& expected_value,
+ std::chrono::milliseconds relative_timeout) {
+ AbsTime absolute_timeout;
+ const prop_info* pi = WaitForPropertyCreation(key, relative_timeout, absolute_timeout);
+ if (pi == nullptr) return false;
WaitForPropertyData data;
data.expected_value = &expected_value;
data.done = false;
while (true) {
+ timespec ts;
// Check whether the property has the value we're looking for?
__system_property_read_callback(pi, WaitForPropertyCallback, &data);
if (data.done) return true;
@@ -152,5 +168,11 @@
}
}
+bool WaitForPropertyCreation(const std::string& key,
+ std::chrono::milliseconds relative_timeout) {
+ AbsTime absolute_timeout;
+ return (WaitForPropertyCreation(key, relative_timeout, absolute_timeout) != nullptr);
+}
+
} // namespace base
} // namespace android
diff --git a/base/properties_test.cpp b/base/properties_test.cpp
index c68c2f8..1bbe482 100644
--- a/base/properties_test.cpp
+++ b/base/properties_test.cpp
@@ -150,3 +150,25 @@
// Upper bounds on timing are inherently flaky, but let's try...
ASSERT_LT(std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0), 600ms);
}
+
+TEST(properties, WaitForPropertyCreation) {
+ std::thread thread([&]() {
+ std::this_thread::sleep_for(100ms);
+ android::base::SetProperty("debug.libbase.WaitForPropertyCreation_test", "a");
+ });
+
+ ASSERT_TRUE(android::base::WaitForPropertyCreation(
+ "debug.libbase.WaitForPropertyCreation_test", 1s));
+ thread.join();
+}
+
+TEST(properties, WaitForPropertyCreation_timeout) {
+ auto t0 = std::chrono::steady_clock::now();
+ ASSERT_FALSE(android::base::WaitForPropertyCreation(
+ "debug.libbase.WaitForPropertyCreation_timeout_test", 200ms));
+ auto t1 = std::chrono::steady_clock::now();
+
+ ASSERT_GE(std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0), 200ms);
+ // Upper bounds on timing are inherently flaky, but let's try...
+ ASSERT_LT(std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0), 600ms);
+}
diff --git a/debuggerd/libdebuggerd/test/sys/system_properties.h b/debuggerd/libdebuggerd/test/sys/system_properties.h
index 9d44345..1f4f58a 100644
--- a/debuggerd/libdebuggerd/test/sys/system_properties.h
+++ b/debuggerd/libdebuggerd/test/sys/system_properties.h
@@ -32,7 +32,6 @@
// This is just enough to get the property code to compile on
// the host.
-#define PROP_NAME_MAX 32
#define PROP_VALUE_MAX 92
#endif // _DEBUGGERD_TEST_SYS_SYSTEM_PROPERTIES_H
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index f1a7ad6..2863a26 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -38,6 +38,9 @@
ifneq (,$(filter userdebug,$(TARGET_BUILD_VARIANT)))
LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1
endif
+ifneq (,$(filter eng,$(TARGET_BUILD_VARIANT)))
+LOCAL_CFLAGS += -DALLOW_SKIP_SECURE_CHECK=1
+endif
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 25c41b9..a50817e 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -435,16 +435,6 @@
return ret;
}
-static int device_is_secure() {
- int ret = -1;
- char value[PROP_VALUE_MAX];
- ret = __system_property_get("ro.secure", value);
- /* If error, we want to fail secure */
- if (ret < 0)
- return 1;
- return strcmp(value, "0") ? 1 : 0;
-}
-
static int device_is_force_encrypted() {
int ret = -1;
char value[PROP_VALUE_MAX];
@@ -673,6 +663,23 @@
return -1;
}
+bool is_device_secure() {
+ int ret = -1;
+ char value[PROP_VALUE_MAX];
+ ret = __system_property_get("ro.secure", value);
+ if (ret == 0) {
+#ifdef ALLOW_SKIP_SECURE_CHECK
+ // Allow eng builds to skip this check if the property
+ // is not readable (happens during early mount)
+ return false;
+#else
+ // If error and not an 'eng' build, we want to fail secure.
+ return true;
+#endif
+ }
+ return strcmp(value, "0") ? true : false;
+}
+
/* When multiple fstab records share the same mount_point, it will
* try to mount each one in turn, and ignore any duplicates after a
* first successful mount.
@@ -750,7 +757,7 @@
/* Skips mounting the device. */
continue;
}
- } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
+ } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && is_device_secure()) {
int rc = fs_mgr_setup_verity(&fstab->recs[i], true);
if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
LINFO << "Verity disabled";
@@ -970,7 +977,7 @@
/* Skips mounting the device. */
continue;
}
- } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
+ } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && is_device_secure()) {
int rc = fs_mgr_setup_verity(&fstab->recs[i], true);
if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
LINFO << "Verity disabled";
@@ -1020,7 +1027,7 @@
* mount a tmpfs filesystem at the given point.
* return 0 on success, non-zero on failure.
*/
-int fs_mgr_do_tmpfs_mount(char *n_name)
+int fs_mgr_do_tmpfs_mount(const char *n_name)
{
int ret;
diff --git a/fs_mgr/fs_mgr_boot_config.cpp b/fs_mgr/fs_mgr_boot_config.cpp
index ae442cf..5b2f218 100644
--- a/fs_mgr/fs_mgr_boot_config.cpp
+++ b/fs_mgr/fs_mgr_boot_config.cpp
@@ -49,16 +49,8 @@
}
// lastly, check the device tree
- static const std::string android_dt_dir("/proc/device-tree/firmware/android");
- std::string file_name = android_dt_dir + "/compatible";
- std::string dt_value;
- if (android::base::ReadFileToString(file_name, &dt_value)) {
- if (dt_value != "android,firmware") {
- LERROR << "Error finding compatible android DT node";
- return false;
- }
-
- file_name = android_dt_dir + "/" + key;
+ if (is_dt_compatible()) {
+ std::string file_name = kAndroidDtDir + "/" + key;
// DT entries terminate with '\0' but so do the properties
if (android::base::ReadFileToString(file_name, out_val)) {
return true;
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 10e70d6..5b0243d 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -15,6 +15,7 @@
*/
#include <ctype.h>
+#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
@@ -22,6 +23,10 @@
#include <sys/mount.h>
#include <unistd.h>
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
#include "fs_mgr_priv.h"
struct fs_mgr_flag_values {
@@ -130,6 +135,24 @@
return size;
}
+/* fills 'dt_value' with the underlying device tree value string without
+ * the trailing '\0'. Returns true if 'dt_value' has a valid string, 'false'
+ * otherwise.
+ */
+static bool read_dt_file(const std::string& file_name, std::string* dt_value)
+{
+ if (android::base::ReadFileToString(file_name, dt_value)) {
+ if (!dt_value->empty()) {
+ // trim the trailing '\0' out, otherwise the comparison
+ // will produce false-negatives.
+ dt_value->resize(dt_value->size() - 1);
+ return true;
+ }
+ }
+
+ return false;
+}
+
static int parse_flags(char *flags, struct flag_list *fl,
struct fs_mgr_flag_values *flag_vals,
char *fs_options, int fs_options_len)
@@ -290,6 +313,97 @@
return f;
}
+static bool is_dt_fstab_compatible() {
+ std::string dt_value;
+ std::string file_name = kAndroidDtDir + "/fstab/compatible";
+ if (read_dt_file(file_name, &dt_value)) {
+ if (dt_value == "android,fstab") {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static std::string read_fstab_from_dt() {
+ std::string fstab;
+ if (!is_dt_compatible() || !is_dt_fstab_compatible()) {
+ return fstab;
+ }
+
+ std::string fstabdir_name = kAndroidDtDir + "/fstab";
+ std::unique_ptr<DIR, int (*)(DIR*)> fstabdir(opendir(fstabdir_name.c_str()), closedir);
+ if (!fstabdir) return fstab;
+
+ dirent* dp;
+ while ((dp = readdir(fstabdir.get())) != NULL) {
+ // skip over name and compatible
+ if (dp->d_type != DT_DIR) {
+ continue;
+ }
+
+ // skip if its not 'vendor', 'odm' or 'system'
+ if (strcmp(dp->d_name, "odm") && strcmp(dp->d_name, "system") &&
+ strcmp(dp->d_name, "vendor")) {
+ continue;
+ }
+
+ // create <dev> <mnt_point> <type> <mnt_flags> <fsmgr_flags>\n
+ std::vector<std::string> fstab_entry;
+ std::string file_name;
+ std::string value;
+ file_name = android::base::StringPrintf("%s/%s/dev", fstabdir_name.c_str(), dp->d_name);
+ if (!read_dt_file(file_name, &value)) {
+ LERROR << "dt_fstab: Failed to find device for partition " << dp->d_name;
+ fstab.clear();
+ break;
+ }
+ fstab_entry.push_back(value);
+ fstab_entry.push_back(android::base::StringPrintf("/%s", dp->d_name));
+
+ file_name = android::base::StringPrintf("%s/%s/type", fstabdir_name.c_str(), dp->d_name);
+ if (!read_dt_file(file_name, &value)) {
+ LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
+ fstab.clear();
+ break;
+ }
+ fstab_entry.push_back(value);
+
+ file_name = android::base::StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name);
+ if (!read_dt_file(file_name, &value)) {
+ LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
+ fstab.clear();
+ break;
+ }
+ fstab_entry.push_back(value);
+
+ file_name = android::base::StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name);
+ if (!read_dt_file(file_name, &value)) {
+ LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
+ fstab.clear();
+ break;
+ }
+ fstab_entry.push_back(value);
+
+ fstab += android::base::Join(fstab_entry, " ");
+ fstab += '\n';
+ }
+
+ return fstab;
+}
+
+bool is_dt_compatible() {
+ std::string file_name = kAndroidDtDir + "/compatible";
+ std::string dt_value;
+ if (read_dt_file(file_name, &dt_value)) {
+ if (dt_value == "android,firmware") {
+ return true;
+ }
+ }
+
+ return false;
+}
+
struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file)
{
int cnt, entries;
@@ -444,6 +558,84 @@
return fstab;
}
+/* Returns fstab entries parsed from the device tree if they
+ * exist
+ */
+struct fstab *fs_mgr_read_fstab_dt()
+{
+ std::string fstab_buf = read_fstab_from_dt();
+ if (fstab_buf.empty()) {
+ return NULL;
+ }
+
+ std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
+ fmemopen(static_cast<void*>(const_cast<char*>(fstab_buf.c_str())),
+ fstab_buf.length(), "r"), fclose);
+ if (!fstab_file) {
+ return NULL;
+ }
+
+ struct fstab *fstab = fs_mgr_read_fstab_file(fstab_file.get());
+ if (!fstab) {
+ LERROR << "failed to load fstab from kernel:" << std::endl << fstab_buf;
+ }
+
+ return fstab;
+}
+
+/* combines fstab entries passed in from device tree with
+ * the ones found in /fstab.<hardware>
+ */
+struct fstab *fs_mgr_read_fstab_default()
+{
+ struct fstab *fstab = fs_mgr_read_fstab_dt();
+ std::string hw;
+ if (!fs_mgr_get_boot_config("hardware", &hw)) {
+ // if we fail to find this, return whatever was found in device tree
+ LWARNING << "failed to find device hardware name";
+ return fstab;
+ }
+
+ std::string default_fstab = FSTAB_PREFIX + hw;
+ struct fstab *f = fs_mgr_read_fstab(default_fstab.c_str());
+ if (!f) {
+ // return what we have
+ LWARNING << "failed to read fstab entries from '" << default_fstab << "'";
+ return fstab;
+ }
+
+ // return the fstab read from file if device tree doesn't
+ // have one, other wise merge the two
+ if (!fstab) {
+ fstab = f;
+ } else {
+ int total_entries = fstab->num_entries + f->num_entries;
+ fstab->recs = static_cast<struct fstab_rec *>(realloc(
+ fstab->recs, total_entries * (sizeof(struct fstab_rec))));
+ if (!fstab->recs) {
+ LERROR << "failed to allocate fstab recs";
+ fstab->num_entries = 0;
+ fs_mgr_free_fstab(fstab);
+ return NULL;
+ }
+
+ for (int i = fstab->num_entries, j = 0; i < total_entries; i++, j++) {
+ // copy everything and *not* strdup
+ fstab->recs[i] = f->recs[j];
+ }
+
+ // free up fstab entries read from file, but don't cleanup
+ // the strings within f->recs[X] to make sure they are accessible
+ // through fstab->recs[X].
+ free(f->fstab_filename);
+ free(f);
+
+ fstab->num_entries = total_entries;
+ }
+
+ return fstab;
+}
+
void fs_mgr_free_fstab(struct fstab *fstab)
{
int i;
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 478c145..4e2ac8b 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -41,6 +41,8 @@
#define PWARNING PLOG(WARNING) << FS_MGR_TAG
#define PERROR PLOG(ERROR) << FS_MGR_TAG
+const std::string FSTAB_PREFIX("/fstab.");
+
__BEGIN_DECLS
#define CRYPTO_TMPFS_OPTIONS "size=256m,mode=0771,uid=1000,gid=1000"
@@ -115,6 +117,8 @@
int fs_mgr_set_blk_ro(const char *blockdev);
int fs_mgr_test_access(const char *device);
int fs_mgr_update_for_slotselect(struct fstab *fstab);
+bool is_dt_compatible();
+bool is_device_secure();
__END_DECLS
diff --git a/fs_mgr/fs_mgr_priv_boot_config.h b/fs_mgr/fs_mgr_priv_boot_config.h
index 74bb5eb..8773d33 100644
--- a/fs_mgr/fs_mgr_priv_boot_config.h
+++ b/fs_mgr/fs_mgr_priv_boot_config.h
@@ -20,6 +20,8 @@
#include <sys/cdefs.h>
#include <string>
+const std::string kAndroidDtDir("/proc/device-tree/firmware/android");
+
bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val);
#endif /* __CORE_FS_MGR_PRIV_BOOTCONFIG_H */
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 2c9b0a9..e8ed6a2 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -46,8 +46,6 @@
#include "fs_mgr_priv.h"
#include "fs_mgr_priv_dm_ioctl.h"
-#define FSTAB_PREFIX "/fstab."
-
#define VERITY_TABLE_RSA_KEY "/verity_key"
#define VERITY_TABLE_HASH_IDX 8
#define VERITY_TABLE_SALT_IDX 9
@@ -694,8 +692,6 @@
int fs_mgr_load_verity_state(int *mode)
{
- char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
- char propbuf[PROPERTY_VALUE_MAX];
int rc = -1;
int i;
int current;
@@ -705,13 +701,9 @@
* logging mode, in which case return that */
*mode = VERITY_MODE_DEFAULT;
- property_get("ro.hardware", propbuf, "");
- snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
-
- fstab = fs_mgr_read_fstab(fstab_filename);
-
+ fstab = fs_mgr_read_fstab_default();
if (!fstab) {
- LERROR << "Failed to read " << fstab_filename;
+ LERROR << "Failed to read default fstab";
goto out;
}
@@ -745,7 +737,6 @@
{
alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
bool system_root = false;
- char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
std::string mount_point;
char propbuf[PROPERTY_VALUE_MAX];
const char *status;
@@ -765,22 +756,16 @@
}
fd = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC));
-
if (fd == -1) {
PERROR << "Error opening device mapper";
goto out;
}
- property_get("ro.hardware", propbuf, "");
- snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
-
property_get("ro.build.system_root_image", propbuf, "");
system_root = !strcmp(propbuf, "true");
-
- fstab = fs_mgr_read_fstab(fstab_filename);
-
+ fstab = fs_mgr_read_fstab_default();
if (!fstab) {
- LERROR << "Failed to read " << fstab_filename;
+ LERROR << "Failed to read default fstab";
goto out;
}
@@ -873,6 +858,13 @@
const std::string mount_point(basename(fstab->mount_point));
bool verified_at_boot = false;
+ // This is a public API and so deserves its own check to see if verity
+ // setup is needed at all.
+ if (!is_device_secure()) {
+ LINFO << "Verity setup skipped for " << mount_point;
+ return FS_MGR_SETUP_VERITY_SUCCESS;
+ }
+
if (fec_open(&f, fstab->blk_device, O_RDONLY, FEC_VERITY_DISABLE,
FEC_DEFAULT_ROOTS) < 0) {
PERROR << "Failed to open '" << fstab->blk_device << "'";
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 0402b55..a5e5beb 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -85,6 +85,8 @@
typedef void (*fs_mgr_verity_state_callback)(struct fstab_rec *fstab,
const char *mount_point, int mode, int status);
+struct fstab *fs_mgr_read_fstab_default();
+struct fstab *fs_mgr_read_fstab_dt();
struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file);
struct fstab *fs_mgr_read_fstab(const char *fstab_path);
void fs_mgr_free_fstab(struct fstab *fstab);
@@ -104,7 +106,7 @@
int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
char *tmp_mount_point);
int fs_mgr_do_mount_one(struct fstab_rec *rec);
-int fs_mgr_do_tmpfs_mount(char *n_name);
+int fs_mgr_do_tmpfs_mount(const char *n_name);
int fs_mgr_unmount_all(struct fstab *fstab);
int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc,
char *real_blk_device, int size);
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 2388edc..6dd1cbb 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -476,15 +476,18 @@
static void import_late(const std::vector<std::string>& args, size_t start_index, size_t end_index) {
Parser& parser = Parser::GetInstance();
if (end_index <= start_index) {
- // Use the default set if no path is given
- static const std::vector<std::string> init_directories = {
- "/system/etc/init",
- "/vendor/etc/init",
- "/odm/etc/init"
- };
-
- for (const auto& dir : init_directories) {
- parser.ParseConfig(dir);
+ // 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);
+ }
+ 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);
}
} else {
for (size_t i = start_index; i < end_index; ++i) {
diff --git a/init/devices.cpp b/init/devices.cpp
index 5f54ff8..bd11f5f 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -251,7 +251,10 @@
* some device nodes, so the uid has to be set with chown() and is still
* racy. Fixing the gid race at least fixed the issue with system_server
* opening dynamic input devices under the AID_INPUT gid. */
- setegid(gid);
+ if (setegid(gid)) {
+ PLOG(ERROR) << "setegid(" << gid << ") for " << path << " device failed";
+ goto out;
+ }
/* If the node already exists update its SELinux label to handle cases when
* it was created with the wrong context during coldboot procedure. */
if (mknod(path, mode, dev) && (errno == EEXIST) && secontext) {
@@ -273,7 +276,9 @@
out:
chown(path, uid, -1);
- setegid(AID_ROOT);
+ if (setegid(AID_ROOT)) {
+ PLOG(FATAL) << "setegid(AID_ROOT) failed";
+ }
if (secontext) {
freecon(secontext);
diff --git a/init/init.cpp b/init/init.cpp
index 05f2cfd..ad40426 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -52,6 +52,8 @@
#include <fstream>
#include <memory>
+#include <set>
+#include <vector>
#include "action.h"
#include "bootchart.h"
@@ -502,26 +504,30 @@
std::string dt_value;
std::string file_name = StringPrintf("%s/compatible", android_dt_dir);
- android::base::ReadFileToString(file_name, &dt_value);
- if (!dt_value.compare("android,firmware")) {
- LOG(ERROR) << "firmware/android is not compatible with 'android,firmware'";
- return false;
+ if (android::base::ReadFileToString(file_name, &dt_value)) {
+ // trim the trailing '\0' out, otherwise the comparison
+ // will produce false-negatives.
+ dt_value.resize(dt_value.size() - 1);
+ if (dt_value == "android,firmware") {
+ return true;
+ }
}
- return true;
+ return false;
}
static bool is_dt_fstab_compatible() {
std::string dt_value;
std::string file_name = StringPrintf("%s/%s/compatible", android_dt_dir, "fstab");
- android::base::ReadFileToString(file_name, &dt_value);
- if (!dt_value.compare("android,fstab")) {
- LOG(ERROR) << "firmware/android/fstab is not compatible with 'android,fstab'";
- return false;
+ if (android::base::ReadFileToString(file_name, &dt_value)) {
+ dt_value.resize(dt_value.size() - 1);
+ if (dt_value == "android,fstab") {
+ return true;
+ }
}
- return true;
+ return false;
}
static void process_kernel_dt() {
@@ -664,78 +670,6 @@
}
}
-static std::string import_dt_fstab() {
- std::string fstab;
- if (!is_dt_compatible() || !is_dt_fstab_compatible()) {
- return fstab;
- }
-
- std::string fstabdir_name = StringPrintf("%s/fstab", android_dt_dir);
- std::unique_ptr<DIR, int (*)(DIR*)> fstabdir(opendir(fstabdir_name.c_str()), closedir);
- if (!fstabdir) return fstab;
-
- dirent* dp;
- while ((dp = readdir(fstabdir.get())) != NULL) {
- // skip over name and compatible
- if (dp->d_type != DT_DIR) {
- continue;
- }
-
- // skip if its not 'vendor', 'odm' or 'system'
- if (strcmp(dp->d_name, "odm") && strcmp(dp->d_name, "system") &&
- strcmp(dp->d_name, "vendor")) {
- continue;
- }
-
- // create <dev> <mnt_point> <type> <mnt_flags> <fsmgr_flags>\n
- std::vector<std::string> fstab_entry;
- std::string file_name;
- std::string value;
- file_name = StringPrintf("%s/%s/dev", fstabdir_name.c_str(), dp->d_name);
- if (!android::base::ReadFileToString(file_name, &value)) {
- LOG(ERROR) << "dt_fstab: Failed to find device for partition " << dp->d_name;
- fstab.clear();
- break;
- }
- // trim the terminating '\0' out
- value.resize(value.size() - 1);
- fstab_entry.push_back(value);
- fstab_entry.push_back(StringPrintf("/%s", dp->d_name));
-
- file_name = StringPrintf("%s/%s/type", fstabdir_name.c_str(), dp->d_name);
- if (!android::base::ReadFileToString(file_name, &value)) {
- LOG(ERROR) << "dt_fstab: Failed to find type for partition " << dp->d_name;
- fstab.clear();
- break;
- }
- value.resize(value.size() - 1);
- fstab_entry.push_back(value);
-
- file_name = StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name);
- if (!android::base::ReadFileToString(file_name, &value)) {
- LOG(ERROR) << "dt_fstab: Failed to find type for partition " << dp->d_name;
- fstab.clear();
- break;
- }
- value.resize(value.size() - 1);
- fstab_entry.push_back(value);
-
- file_name = StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name);
- if (!android::base::ReadFileToString(file_name, &value)) {
- LOG(ERROR) << "dt_fstab: Failed to find type for partition " << dp->d_name;
- fstab.clear();
- break;
- }
- value.resize(value.size() - 1);
- fstab_entry.push_back(value);
-
- fstab += android::base::Join(fstab_entry, " ");
- fstab += '\n';
- }
-
- return fstab;
-}
-
static bool early_mount_one(struct fstab_rec* rec) {
if (rec && fs_mgr_is_verified(rec)) {
// setup verity and create the dm-XX block device
@@ -768,78 +702,15 @@
return true;
}
-/* Early mount vendor and ODM partitions. The fstab is read from device-tree. */
-static bool early_mount() {
- std::string fstab = import_dt_fstab();
- if (fstab.empty()) {
- LOG(INFO) << "Early mount skipped (missing fstab in device tree)";
- return true;
+// Creates devices with uevent->partition_name matching one in the in/out
+// partition_names. Note that the partition_names MUST have A/B suffix
+// when A/B is used. Found partitions will then be removed from the
+// partition_names for caller to check which devices are NOT created.
+static void early_device_init(std::set<std::string>* partition_names) {
+ if (partition_names->empty()) {
+ return;
}
-
- std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
- fmemopen(static_cast<void*>(const_cast<char*>(fstab.c_str())), fstab.length(), "r"), fclose);
- if (!fstab_file) {
- PLOG(ERROR) << "Early mount failed to open fstab file in memory";
- return false;
- }
-
- std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> tab(
- fs_mgr_read_fstab_file(fstab_file.get()), fs_mgr_free_fstab);
- if (!tab) {
- LOG(ERROR) << "Early mount fsmgr failed to load fstab from kernel:" << std::endl << fstab;
- return false;
- }
-
- // find out fstab records for odm, system and vendor
- // TODO: add std::map<std::string, fstab_rec*> so all required information about
- // them can be gathered at once in a single loop
- fstab_rec* odm_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/odm");
- fstab_rec* system_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/system");
- fstab_rec* vendor_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/vendor");
- if (!odm_rec && !system_rec && !vendor_rec) {
- // nothing to early mount
- return true;
- }
-
- // don't allow verifyatboot for early mounted partitions
- if ((odm_rec && fs_mgr_is_verifyatboot(odm_rec)) ||
- (system_rec && fs_mgr_is_verifyatboot(system_rec)) ||
- (vendor_rec && fs_mgr_is_verifyatboot(vendor_rec))) {
- LOG(ERROR) << "Early mount partitions can't be verified at boot";
- return false;
- }
-
- // assume A/B device if we find 'slotselect' in any fstab entry
- bool is_ab = ((odm_rec && fs_mgr_is_slotselect(odm_rec)) ||
- (system_rec && fs_mgr_is_slotselect(system_rec)) ||
- (vendor_rec && fs_mgr_is_slotselect(vendor_rec)));
-
- // check for verified partitions
- bool need_verity = ((odm_rec && fs_mgr_is_verified(odm_rec)) ||
- (system_rec && fs_mgr_is_verified(system_rec)) ||
- (vendor_rec && fs_mgr_is_verified(vendor_rec)));
-
- // check if verity metadata is on a separate partition and get partition
- // name from the end of the ->verity_loc path. verity state is not partition
- // specific, so there must be only 1 additional partition that carries
- // verity state.
- std::string meta_partition;
- if (odm_rec && odm_rec->verity_loc) {
- meta_partition = basename(odm_rec->verity_loc);
- } else if (system_rec && system_rec->verity_loc) {
- meta_partition = basename(system_rec->verity_loc);
- } else if (vendor_rec && vendor_rec->verity_loc) {
- meta_partition = basename(vendor_rec->verity_loc);
- }
-
- bool found_odm = !odm_rec;
- bool found_system = !system_rec;
- bool found_vendor = !vendor_rec;
- bool found_meta = meta_partition.empty();
- int count_odm = 0, count_vendor = 0, count_system = 0;
-
- // create the devices we need..
- device_init(nullptr, [&](uevent* uevent) -> coldboot_action_t {
+ device_init(nullptr, [=](uevent* uevent) -> coldboot_action_t {
if (!strncmp(uevent->subsystem, "firmware", 8)) {
return COLDBOOT_CONTINUE;
}
@@ -854,59 +725,121 @@
return COLDBOOT_CONTINUE;
}
- coldboot_action_t ret;
- bool create_this_node = false;
if (uevent->partition_name) {
- // prefix match partition names so we create device nodes for
- // A/B-ed partitions
- if (!found_odm && !strncmp(uevent->partition_name, "odm", 3)) {
- LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
-
- // wait twice for A/B-ed partitions
- count_odm++;
- if (!is_ab || count_odm == 2) {
- found_odm = true;
+ // match partition names to create device nodes for partitions
+ // both partition_names and uevent->partition_name have A/B suffix when A/B is used
+ auto iter = partition_names->find(uevent->partition_name);
+ if (iter != partition_names->end()) {
+ LOG(VERBOSE) << "early_mount: found partition: " << *iter;
+ partition_names->erase(iter);
+ if (partition_names->empty()) {
+ return COLDBOOT_STOP; // found all partitions, stop coldboot
+ } else {
+ return COLDBOOT_CREATE; // create this device and continue to find others
}
-
- create_this_node = true;
- } else if (!found_system && !strncmp(uevent->partition_name, "system", 6)) {
- LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
-
- count_system++;
- if (!is_ab || count_system == 2) {
- found_system = true;
- }
-
- create_this_node = true;
- } else if (!found_vendor && !strncmp(uevent->partition_name, "vendor", 6)) {
- LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
- count_vendor++;
- if (!is_ab || count_vendor == 2) {
- found_vendor = true;
- }
-
- create_this_node = true;
- } else if (!found_meta && (meta_partition == uevent->partition_name)) {
- LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
- found_meta = true;
- create_this_node = true;
}
}
-
- // if we found all other partitions already, create this
- // node and stop coldboot. If this is a prefix matched
- // partition, create device node and continue. For everything
- // else skip the device node
- if (found_meta && found_odm && found_system && found_vendor) {
- ret = COLDBOOT_STOP;
- } else if (create_this_node) {
- ret = COLDBOOT_CREATE;
- } else {
- ret = COLDBOOT_CONTINUE;
- }
-
- return ret;
+ // Not found a partition or find an unneeded partition, continue to find others
+ return COLDBOOT_CONTINUE;
});
+}
+
+static bool get_early_partitions(const std::vector<fstab_rec*>& early_fstab_recs,
+ std::set<std::string>* out_partitions, bool* out_need_verity) {
+ std::string meta_partition;
+ out_partitions->clear();
+ *out_need_verity = false;
+
+ for (auto fstab_rec : early_fstab_recs) {
+ // don't allow verifyatboot for early mounted partitions
+ if (fs_mgr_is_verifyatboot(fstab_rec)) {
+ LOG(ERROR) << "early_mount: partitions can't be verified at boot";
+ return false;
+ }
+ // check for verified partitions
+ if (fs_mgr_is_verified(fstab_rec)) {
+ *out_need_verity = true;
+ }
+ // check if verity metadata is on a separate partition and get partition
+ // name from the end of the ->verity_loc path. verity state is not partition
+ // specific, so there must be only 1 additional partition that carries
+ // verity state.
+ if (fstab_rec->verity_loc) {
+ if (!meta_partition.empty()) {
+ LOG(ERROR) << "early_mount: more than one meta partition found: " << meta_partition
+ << ", " << basename(fstab_rec->verity_loc);
+ return false;
+ } else {
+ meta_partition = basename(fstab_rec->verity_loc);
+ }
+ }
+ }
+
+ // includes those early mount partitions and meta_partition (if any)
+ // note that fstab_rec->blk_device has A/B suffix updated by fs_mgr when A/B is used
+ for (auto fstab_rec : early_fstab_recs) {
+ out_partitions->emplace(basename(fstab_rec->blk_device));
+ }
+
+ if (!meta_partition.empty()) {
+ out_partitions->emplace(std::move(meta_partition));
+ }
+
+ return true;
+}
+
+/* Early mount vendor and ODM partitions. The fstab is read from device-tree. */
+static bool early_mount() {
+ // skip early mount if we're in recovery mode
+ if (access("/sbin/recovery", F_OK) == 0) {
+ LOG(INFO) << "Early mount skipped (recovery mode)";
+ return true;
+ }
+
+ // first check if device tree fstab entries are compatible
+ if (!is_dt_fstab_compatible()) {
+ LOG(INFO) << "Early mount skipped (missing/incompatible fstab in device tree)";
+ return true;
+ }
+
+ std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> tab(
+ fs_mgr_read_fstab_dt(), fs_mgr_free_fstab);
+ if (!tab) {
+ LOG(ERROR) << "Early mount failed to read fstab from device tree";
+ return false;
+ }
+
+ // find out fstab records for odm, system and vendor
+ std::vector<fstab_rec*> early_fstab_recs;
+ for (auto mount_point : {"/odm", "/system", "/vendor"}) {
+ fstab_rec* fstab_rec = fs_mgr_get_entry_for_mount_point(tab.get(), mount_point);
+ if (fstab_rec != nullptr) {
+ early_fstab_recs.push_back(fstab_rec);
+ }
+ }
+
+ // nothing to early mount
+ if (early_fstab_recs.empty()) return true;
+
+ bool need_verity;
+ std::set<std::string> partition_names;
+ // partition_names MUST have A/B suffix when A/B is used
+ if (!get_early_partitions(early_fstab_recs, &partition_names, &need_verity)) {
+ return false;
+ }
+
+ bool success = false;
+ // create the devices we need..
+ early_device_init(&partition_names);
+
+ // early_device_init will remove found partitions from partition_names
+ // So if the partition_names is not empty here, means some partitions
+ // are not found
+ if (!partition_names.empty()) {
+ LOG(ERROR) << "early_mount: partition(s) not found: "
+ << android::base::Join(partition_names, ", ");
+ goto done;
+ }
if (need_verity) {
// create /dev/device mapper
@@ -914,10 +847,10 @@
[&](uevent* uevent) -> coldboot_action_t { return COLDBOOT_STOP; });
}
- bool success = true;
- if (odm_rec && !(success = early_mount_one(odm_rec))) goto done;
- if (system_rec && !(success = early_mount_one(system_rec))) goto done;
- if (vendor_rec && !(success = early_mount_one(vendor_rec))) goto done;
+ for (auto fstab_rec : early_fstab_recs) {
+ if (!early_mount_one(fstab_rec)) goto done;
+ }
+ success = true;
done:
device_close();
@@ -1067,8 +1000,16 @@
std::string bootscript = property_get("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);
}
ActionManager& am = ActionManager::GetInstance();
diff --git a/init/init_parser.h b/init/init_parser.h
index 5ed30ad..f66ba52 100644
--- a/init/init_parser.h
+++ b/init/init_parser.h
@@ -41,6 +41,18 @@
bool ParseConfig(const std::string& path);
void AddSectionParser(const std::string& name,
std::unique_ptr<SectionParser> parser);
+ 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:
Parser();
@@ -50,6 +62,9 @@
bool ParseConfigDir(const std::string& path);
std::map<std::string, std::unique_ptr<SectionParser>> section_parsers_;
+ bool is_system_etc_init_loaded_ = false;
+ bool is_vendor_etc_init_loaded_ = false;
+ bool is_odm_etc_init_loaded_ = false;
};
#endif
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 04bcb18..decd644 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -49,6 +50,7 @@
#include <fs_mgr.h>
#include <android-base/file.h>
+#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include "bootimg.h"
@@ -57,6 +59,8 @@
#include "util.h"
#include "log.h"
+using android::base::StringPrintf;
+
#define PERSISTENT_PROPERTY_DIR "/data/property"
#define FSTAB_PREFIX "/fstab."
#define RECOVERY_MOUNT_POINT "/recovery"
@@ -605,6 +609,8 @@
load_override_properties();
/* Read persistent properties after all default values have been loaded. */
load_persistent_properties();
+ uint64_t start_ns = boot_clock::now().time_since_epoch().count();
+ property_set("ro.boottime.persistent_properties", StringPrintf("%" PRIu64, start_ns).c_str());
}
void load_recovery_id_prop() {
diff --git a/init/service.cpp b/init/service.cpp
index e186f27..ba901fd 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -180,12 +180,6 @@
}
std::string prop_name = StringPrintf("init.svc.%s", name_.c_str());
- if (prop_name.length() >= PROP_NAME_MAX) {
- // If the property name would be too long, we can't set it.
- LOG(ERROR) << "Property name \"init.svc." << name_ << "\" too long; not setting to " << new_state;
- return;
- }
-
property_set(prop_name.c_str(), new_state.c_str());
if (new_state == "running") {
@@ -1040,5 +1034,9 @@
}
bool ServiceParser::IsValidName(const std::string& name) const {
- return is_legal_property_name("init.svc." + name);
+ // Property names can be any length, but may only contain certain characters.
+ // Property values can contain any characters, but may only be a certain length.
+ // (The latter restriction is needed because `start` and `stop` work by writing
+ // the service name to the "ctl.start" and "ctl.stop" properties.)
+ return is_legal_property_name("init.svc." + name) && name.size() <= PROP_VALUE_MAX;
}
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 7e27c3e..1915ced 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -165,7 +165,7 @@
/* Support Bluetooth legacy hal accessing /sys/class/rfkill */
{ 00700, AID_BLUETOOTH, AID_BLUETOOTH, CAP_MASK_LONG(CAP_NET_ADMIN),
- "system/bin/hw/android.hardware.bluetooth@1.0-service" },
+ "vendor/bin/hw/android.hardware.bluetooth@1.0-service" },
/* A non-privileged zygote that spawns isolated processes for web rendering. */
{ 0750, AID_ROOT, AID_ROOT, CAP_MASK_LONG(CAP_SETUID) |
@@ -180,6 +180,7 @@
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump32" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump64" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/debuggerd" },
+ { 00700, AID_ROOT, AID_ROOT, 0, "system/bin/secilc" },
{ 00750, AID_ROOT, AID_ROOT, 0, "system/bin/uncrypt" },
{ 00750, AID_ROOT, AID_ROOT, 0, "system/bin/install-recovery.sh" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/*" },
diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp
index 0b0dc09..718d76b 100644
--- a/libcutils/tests/Android.bp
+++ b/libcutils/tests/Android.bp
@@ -46,6 +46,12 @@
suffix: "64",
},
},
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
}
test_libraries = [
diff --git a/libcutils/tests/multiuser_test.cpp b/libcutils/tests/multiuser_test.cpp
index c5f58b4..ae5c416 100644
--- a/libcutils/tests/multiuser_test.cpp
+++ b/libcutils/tests/multiuser_test.cpp
@@ -17,59 +17,61 @@
#include <cutils/multiuser.h>
#include <gtest/gtest.h>
+static constexpr auto ERR_GID = static_cast<gid_t>(-1);
+
TEST(MultiuserTest, TestMerge) {
- EXPECT_EQ(0, multiuser_get_uid(0, 0));
- EXPECT_EQ(1000, multiuser_get_uid(0, 1000));
- EXPECT_EQ(10000, multiuser_get_uid(0, 10000));
- EXPECT_EQ(50000, multiuser_get_uid(0, 50000));
- EXPECT_EQ(1000000, multiuser_get_uid(10, 0));
- EXPECT_EQ(1001000, multiuser_get_uid(10, 1000));
- EXPECT_EQ(1010000, multiuser_get_uid(10, 10000));
- EXPECT_EQ(1050000, multiuser_get_uid(10, 50000));
+ EXPECT_EQ(0U, multiuser_get_uid(0, 0));
+ EXPECT_EQ(1000U, multiuser_get_uid(0, 1000));
+ EXPECT_EQ(10000U, multiuser_get_uid(0, 10000));
+ EXPECT_EQ(50000U, multiuser_get_uid(0, 50000));
+ EXPECT_EQ(1000000U, multiuser_get_uid(10, 0));
+ EXPECT_EQ(1001000U, multiuser_get_uid(10, 1000));
+ EXPECT_EQ(1010000U, multiuser_get_uid(10, 10000));
+ EXPECT_EQ(1050000U, multiuser_get_uid(10, 50000));
}
TEST(MultiuserTest, TestSplitUser) {
- EXPECT_EQ(0, multiuser_get_user_id(0));
- EXPECT_EQ(0, multiuser_get_user_id(1000));
- EXPECT_EQ(0, multiuser_get_user_id(10000));
- EXPECT_EQ(0, multiuser_get_user_id(50000));
- EXPECT_EQ(10, multiuser_get_user_id(1000000));
- EXPECT_EQ(10, multiuser_get_user_id(1001000));
- EXPECT_EQ(10, multiuser_get_user_id(1010000));
- EXPECT_EQ(10, multiuser_get_user_id(1050000));
+ EXPECT_EQ(0U, multiuser_get_user_id(0));
+ EXPECT_EQ(0U, multiuser_get_user_id(1000));
+ EXPECT_EQ(0U, multiuser_get_user_id(10000));
+ EXPECT_EQ(0U, multiuser_get_user_id(50000));
+ EXPECT_EQ(10U, multiuser_get_user_id(1000000));
+ EXPECT_EQ(10U, multiuser_get_user_id(1001000));
+ EXPECT_EQ(10U, multiuser_get_user_id(1010000));
+ EXPECT_EQ(10U, multiuser_get_user_id(1050000));
}
TEST(MultiuserTest, TestSplitApp) {
- EXPECT_EQ(0, multiuser_get_app_id(0));
- EXPECT_EQ(1000, multiuser_get_app_id(1000));
- EXPECT_EQ(10000, multiuser_get_app_id(10000));
- EXPECT_EQ(50000, multiuser_get_app_id(50000));
- EXPECT_EQ(0, multiuser_get_app_id(1000000));
- EXPECT_EQ(1000, multiuser_get_app_id(1001000));
- EXPECT_EQ(10000, multiuser_get_app_id(1010000));
- EXPECT_EQ(50000, multiuser_get_app_id(1050000));
+ EXPECT_EQ(0U, multiuser_get_app_id(0));
+ EXPECT_EQ(1000U, multiuser_get_app_id(1000));
+ EXPECT_EQ(10000U, multiuser_get_app_id(10000));
+ EXPECT_EQ(50000U, multiuser_get_app_id(50000));
+ EXPECT_EQ(0U, multiuser_get_app_id(1000000));
+ EXPECT_EQ(1000U, multiuser_get_app_id(1001000));
+ EXPECT_EQ(10000U, multiuser_get_app_id(1010000));
+ EXPECT_EQ(50000U, multiuser_get_app_id(1050000));
}
TEST(MultiuserTest, TestCache) {
- EXPECT_EQ(-1, multiuser_get_cache_gid(0, 0));
- EXPECT_EQ(-1, multiuser_get_cache_gid(0, 1000));
- EXPECT_EQ(20000, multiuser_get_cache_gid(0, 10000));
- EXPECT_EQ(-1, multiuser_get_cache_gid(0, 50000));
- EXPECT_EQ(1020000, multiuser_get_cache_gid(10, 10000));
+ EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(0, 0));
+ EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(0, 1000));
+ EXPECT_EQ(20000U, multiuser_get_cache_gid(0, 10000));
+ EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(0, 50000));
+ EXPECT_EQ(1020000U, multiuser_get_cache_gid(10, 10000));
}
TEST(MultiuserTest, TestExt) {
- EXPECT_EQ(-1, multiuser_get_ext_gid(0, 0));
- EXPECT_EQ(-1, multiuser_get_ext_gid(0, 1000));
- EXPECT_EQ(30000, multiuser_get_ext_gid(0, 10000));
- EXPECT_EQ(-1, multiuser_get_ext_gid(0, 50000));
- EXPECT_EQ(1030000, multiuser_get_ext_gid(10, 10000));
+ EXPECT_EQ(ERR_GID, multiuser_get_ext_gid(0, 0));
+ EXPECT_EQ(ERR_GID, multiuser_get_ext_gid(0, 1000));
+ EXPECT_EQ(30000U, multiuser_get_ext_gid(0, 10000));
+ EXPECT_EQ(ERR_GID, multiuser_get_ext_gid(0, 50000));
+ EXPECT_EQ(1030000U, multiuser_get_ext_gid(10, 10000));
}
TEST(MultiuserTest, TestShared) {
- EXPECT_EQ(-1, multiuser_get_shared_gid(0, 0));
- EXPECT_EQ(-1, multiuser_get_shared_gid(0, 1000));
- EXPECT_EQ(50000, multiuser_get_shared_gid(0, 10000));
- EXPECT_EQ(-1, multiuser_get_shared_gid(0, 50000));
- EXPECT_EQ(1050000, multiuser_get_shared_gid(10, 10000));
+ EXPECT_EQ(ERR_GID, multiuser_get_shared_gid(0, 0));
+ EXPECT_EQ(ERR_GID, multiuser_get_shared_gid(0, 1000));
+ EXPECT_EQ(50000U, multiuser_get_shared_gid(0, 10000));
+ EXPECT_EQ(ERR_GID, multiuser_get_shared_gid(0, 50000));
+ EXPECT_EQ(1050000U, multiuser_get_shared_gid(10, 10000));
}
diff --git a/libcutils/tests/sockets_test.cpp b/libcutils/tests/sockets_test.cpp
index 0441fb6..b762ac1 100644
--- a/libcutils/tests/sockets_test.cpp
+++ b/libcutils/tests/sockets_test.cpp
@@ -101,7 +101,7 @@
// should always be able to read its port.
for (int port : {10000, 12345, 15999, 20202, 25000}) {
for (int type : {SOCK_DGRAM, SOCK_STREAM}) {
- server = socket_inaddr_any_server(port, SOCK_DGRAM);
+ server = socket_inaddr_any_server(port, type);
if (server != INVALID_SOCKET) {
EXPECT_EQ(port, socket_get_local_port(server));
}
diff --git a/liblog/event_tag_map.cpp b/liblog/event_tag_map.cpp
index 1f08eb4..42f0f37 100644
--- a/liblog/event_tag_map.cpp
+++ b/liblog/event_tag_map.cpp
@@ -227,19 +227,30 @@
// successful return, it will be pointing to the last character in the
// tag line (i.e. the character before the start of the next line).
//
+// lineNum = 0 removes verbose comments and requires us to cache the
+// content rather than make direct raw references since the content
+// will disappear after the call. A non-zero lineNum means we own the
+// data and it will outlive the call.
+//
// Returns 0 on success, nonzero on failure.
static int scanTagLine(EventTagMap* map, char** pData, int lineNum) {
char* cp;
unsigned long val = strtoul(*pData, &cp, 10);
if (cp == *pData) {
- fprintf(stderr, OUT_TAG ": malformed tag number on line %d\n", lineNum);
+ if (lineNum) {
+ fprintf(stderr, OUT_TAG ": malformed tag number on line %d\n",
+ lineNum);
+ }
errno = EINVAL;
return -1;
}
uint32_t tagIndex = val;
if (tagIndex != val) {
- fprintf(stderr, OUT_TAG ": tag number too large on line %d\n", lineNum);
+ if (lineNum) {
+ fprintf(stderr, OUT_TAG ": tag number too large on line %d\n",
+ lineNum);
+ }
errno = ERANGE;
return -1;
}
@@ -248,7 +259,10 @@
}
if (*cp == '\n') {
- fprintf(stderr, OUT_TAG ": missing tag string on line %d\n", lineNum);
+ if (lineNum) {
+ fprintf(stderr, OUT_TAG ": missing tag string on line %d\n",
+ lineNum);
+ }
errno = EINVAL;
return -1;
}
@@ -259,7 +273,10 @@
size_t tagLen = cp - tag;
if (!isspace(*cp)) {
- fprintf(stderr, OUT_TAG ": invalid tag chars on line %d\n", lineNum);
+ if (lineNum) {
+ fprintf(stderr, OUT_TAG ": invalid tag chars on line %d\n",
+ lineNum);
+ }
errno = EINVAL;
return -1;
}
@@ -293,9 +310,18 @@
#endif
*pData = cp;
- if (map->emplaceUnique(tagIndex, TagFmt(std::make_pair(
- MapString(tag, tagLen), MapString(fmt, fmtLen))), verbose)) {
- return 0;
+ if (lineNum) {
+ if (map->emplaceUnique(tagIndex, TagFmt(std::make_pair(
+ MapString(tag, tagLen), MapString(fmt, fmtLen))), verbose)) {
+ return 0;
+ }
+ } else {
+ // cache
+ if (map->emplaceUnique(tagIndex, TagFmt(std::make_pair(
+ MapString(std::string(tag, tagLen)),
+ MapString(std::string(fmt, fmtLen)))))) {
+ return 0;
+ }
}
errno = EMLINK;
return -1;
@@ -455,12 +481,55 @@
if (map) delete map;
}
+// Cache miss, go to logd to acquire a public reference.
+// Because we lack access to a SHARED PUBLIC /dev/event-log-tags file map?
+static const TagFmt* __getEventTag(EventTagMap* map, unsigned int tag) {
+ // call event tag service to arrange for a new tag
+ char *buf = NULL;
+ // Can not use android::base::StringPrintf, asprintf + free instead.
+ static const char command_template[] = "getEventTag id=%u";
+ int ret = asprintf(&buf, command_template, tag);
+ if (ret > 0) {
+ // Add some buffer margin for an estimate of the full return content.
+ char *cp;
+ size_t size = ret - strlen(command_template) +
+ strlen("65535\n4294967295\t?\t\t\t?\t# uid=32767\n\n\f?success?");
+ if (size > (size_t)ret) {
+ cp = static_cast<char*>(realloc(buf, size));
+ if (cp) {
+ buf = cp;
+ } else {
+ size = ret;
+ }
+ } else {
+ size = ret;
+ }
+ // Ask event log tag service for an existing entry
+ if (__send_log_msg(buf, size) >= 0) {
+ buf[size - 1] = '\0';
+ unsigned long val = strtoul(buf, &cp, 10); // return size
+ if ((buf != cp) && (val > 0) && (*cp == '\n')) { // truncation OK
+ ++cp;
+ if (!scanTagLine(map, &cp, 0)) {
+ free(buf);
+ return map->find(tag);
+ }
+ }
+ }
+ free(buf);
+ }
+ return NULL;
+}
+
// Look up an entry in the map.
LIBLOG_ABI_PUBLIC const char* android_lookupEventTag_len(const EventTagMap* map,
size_t *len,
unsigned int tag) {
if (len) *len = 0;
const TagFmt* str = map->find(tag);
+ if (!str) {
+ str = __getEventTag(const_cast<EventTagMap*>(map), tag);
+ }
if (!str) return NULL;
if (len) *len = str->first.length();
return str->first.data();
@@ -471,6 +540,9 @@
const EventTagMap* map, size_t *len, unsigned int tag) {
if (len) *len = 0;
const TagFmt* str = map->find(tag);
+ if (!str) {
+ str = __getEventTag(const_cast<EventTagMap*>(map), tag);
+ }
if (!str) return NULL;
if (len) *len = str->second.length();
return str->second.data();
diff --git a/libsysutils/Android.mk b/libsysutils/Android.mk
index 330d6cb..584e5a2 100644
--- a/libsysutils/Android.mk
+++ b/libsysutils/Android.mk
@@ -17,6 +17,7 @@
LOCAL_CFLAGS := -Werror
LOCAL_SHARED_LIBRARIES := \
+ libbase \
libcutils \
liblog \
libnl
@@ -24,4 +25,3 @@
LOCAL_EXPORT_C_INCLUDE_DIRS := system/core/libsysutils/include
include $(BUILD_SHARED_LIBRARY)
-
diff --git a/libsysutils/src/ServiceManager.cpp b/libsysutils/src/ServiceManager.cpp
index 13bac09..c7aa1f7 100644
--- a/libsysutils/src/ServiceManager.cpp
+++ b/libsysutils/src/ServiceManager.cpp
@@ -19,34 +19,23 @@
#include <errno.h>
#include <stdio.h>
#include <string.h>
+#include <sys/system_properties.h>
#include <unistd.h>
-#include <cutils/properties.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
#include <log/log.h>
#include <sysutils/ServiceManager.h>
ServiceManager::ServiceManager() {
}
-/* The service name should not exceed SERVICE_NAME_MAX to avoid
- * some weird things. This is due to the fact that:
- *
- * - Starting a service is done by writing its name to the "ctl.start"
- * system property. This triggers the init daemon to actually start
- * the service for us.
- *
- * - Stopping the service is done by writing its name to "ctl.stop"
- * in a similar way.
- *
- * - Reading the status of a service is done by reading the property
- * named "init.svc.<name>"
- *
- * If strlen(<name>) > (PROPERTY_KEY_MAX-1)-9, then you can start/stop
- * the service by writing to ctl.start/stop, but you won't be able to
- * read its state due to the truncation of "init.svc.<name>" into a
- * zero-terminated buffer of PROPERTY_KEY_MAX characters.
- */
-#define SERVICE_NAME_MAX (PROPERTY_KEY_MAX-10)
+// The length of a service name should not exceed SERVICE_NAME_MAX. Starting
+// a service is done by writing its name to the "ctl.start" system property
+// and stopping a service is done by writing its name to "ctl.stop". If a
+// service name is too long to fit in a property, you won't be able to start
+// or stop it.
+static constexpr size_t SERVICE_NAME_MAX = PROP_VALUE_MAX;
/* The maximum amount of time to wait for a service to start or stop,
* in micro-seconds (really an approximation) */
@@ -61,13 +50,14 @@
SLOGE("Service name '%s' is too long", name);
return 0;
}
+
if (isRunning(name)) {
SLOGW("Service '%s' is already running", name);
return 0;
}
SLOGD("Starting service '%s'", name);
- property_set("ctl.start", name);
+ android::base::SetProperty("ctl.start", name);
int count = SLEEP_MAX_USEC;
while(count > 0) {
@@ -90,13 +80,14 @@
SLOGE("Service name '%s' is too long", name);
return 0;
}
+
if (!isRunning(name)) {
SLOGW("Service '%s' is already stopped", name);
return 0;
}
SLOGD("Stopping service '%s'", name);
- property_set("ctl.stop", name);
+ android::base::SetProperty("ctl.stop", name);
int count = SLEEP_MAX_USEC;
while(count > 0) {
@@ -116,19 +107,6 @@
}
bool ServiceManager::isRunning(const char *name) {
- char propVal[PROPERTY_VALUE_MAX];
- char propName[PROPERTY_KEY_MAX];
- int ret;
-
- ret = snprintf(propName, sizeof(propName), "init.svc.%s", name);
- if (ret > (int)sizeof(propName)-1) {
- SLOGD("Service name '%s' is too long", name);
- return false;
- }
-
- if (property_get(propName, propVal, NULL)) {
- if (!strcmp(propVal, "running"))
- return true;
- }
- return false;
+ std::string property_name = android::base::StringPrintf("init.svc.%s", name);
+ return (android::base::GetProperty(property_name, "") == "running");
}
diff --git a/libutils/include/utils/Condition.h b/libutils/include/utils/Condition.h
index 25a53aa..2c80acd 100644
--- a/libutils/include/utils/Condition.h
+++ b/libutils/include/utils/Condition.h
@@ -86,19 +86,22 @@
#if !defined(_WIN32)
-inline Condition::Condition() {
- pthread_cond_init(&mCond, NULL);
+inline Condition::Condition() : Condition(PRIVATE) {
}
inline Condition::Condition(int type) {
+ pthread_condattr_t attr;
+ pthread_condattr_init(&attr);
+#if defined(__linux__)
+ pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
+#endif
+
if (type == SHARED) {
- pthread_condattr_t attr;
- pthread_condattr_init(&attr);
pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
- pthread_cond_init(&mCond, &attr);
- pthread_condattr_destroy(&attr);
- } else {
- pthread_cond_init(&mCond, NULL);
}
+
+ pthread_cond_init(&mCond, &attr);
+ pthread_condattr_destroy(&attr);
+
}
inline Condition::~Condition() {
pthread_cond_destroy(&mCond);
@@ -109,7 +112,7 @@
inline status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) {
struct timespec ts;
#if defined(__linux__)
- clock_gettime(CLOCK_REALTIME, &ts);
+ clock_gettime(CLOCK_MONOTONIC, &ts);
#else // __APPLE__
// Apple doesn't support POSIX clocks.
struct timeval t;
diff --git a/libutils/include/utils/Singleton.h b/libutils/include/utils/Singleton.h
index 7cc4c18..a989a47 100644
--- a/libutils/include/utils/Singleton.h
+++ b/libutils/include/utils/Singleton.h
@@ -26,6 +26,16 @@
namespace android {
// ---------------------------------------------------------------------------
+// Singleton<TYPE> may be used in multiple libraries, only one of which should
+// define the static member variables using ANDROID_SINGLETON_STATIC_INSTANCE.
+// Turn off -Wundefined-var-template so other users don't get:
+// instantiation of variable 'android::Singleton<TYPE>::sLock' required here,
+// but no definition is available
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wundefined-var-template"
+#endif
+
template <typename TYPE>
class ANDROID_API Singleton
{
@@ -56,11 +66,9 @@
static TYPE* sInstance;
};
-template <typename TYPE>
-Mutex Singleton<TYPE>::sLock;
-
-template <typename TYPE>
-TYPE* Singleton<TYPE>::sInstance;
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
/*
* use ANDROID_SINGLETON_STATIC_INSTANCE(TYPE) in your implementation file
diff --git a/libutils/tests/Android.bp b/libutils/tests/Android.bp
index ec6b67f..ea606a1 100644
--- a/libutils/tests/Android.bp
+++ b/libutils/tests/Android.bp
@@ -18,33 +18,74 @@
cc_test {
name: "libutils_tests",
+ host_supported: true,
srcs: [
- "BlobCache_test.cpp",
"BitSet_test.cpp",
- "Looper_test.cpp",
"LruCache_test.cpp",
- "RefBase_test.cpp",
+ "Singleton_test.cpp",
"String8_test.cpp",
"StrongPointer_test.cpp",
- "SystemClock_test.cpp",
"Unicode_test.cpp",
"Vector_test.cpp",
],
- shared_libs: [
- "libz",
- "liblog",
- "libcutils",
- "libutils",
+ target: {
+ android: {
+ srcs: [
+ "BlobCache_test.cpp",
+ "Looper_test.cpp",
+ "RefBase_test.cpp",
+ "SystemClock_test.cpp",
+ ],
+ shared_libs: [
+ "libz",
+ "liblog",
+ "libcutils",
+ "libutils",
+ "libbase",
+ "libdl",
+ ],
+ },
+ linux: {
+ srcs: [
+ "Looper_test.cpp",
+ "RefBase_test.cpp",
+ ],
+ },
+ host: {
+ static_libs: [
+ "libutils",
+ "liblog",
+ "libbase",
+ ],
+ host_ldlibs: ["-ldl"],
+ },
+ },
+
+ required: [
+ "libutils_tests_singleton1",
+ "libutils_tests_singleton2",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
],
}
-cc_test_host {
- name: "libutils_tests_host",
- srcs: ["Vector_test.cpp"],
- static_libs: [
- "libutils",
- "liblog",
- ],
+cc_test_library {
+ name: "libutils_tests_singleton1",
+ host_supported: true,
+ relative_install_path: "libutils_tests",
+ srcs: ["Singleton_test1.cpp"],
+}
+
+cc_test_library {
+ name: "libutils_tests_singleton2",
+ host_supported: true,
+ relative_install_path: "libutils_tests",
+ srcs: ["Singleton_test2.cpp"],
+ shared_libs: ["libutils_tests_singleton1"],
}
diff --git a/libutils/tests/Singleton_test.cpp b/libutils/tests/Singleton_test.cpp
new file mode 100644
index 0000000..9acd3c3
--- /dev/null
+++ b/libutils/tests/Singleton_test.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Singleton_test"
+
+#include <dlfcn.h>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <utils/Singleton.h>
+
+#include <gtest/gtest.h>
+
+#include "Singleton_test.h"
+
+namespace android {
+
+TEST(SingletonTest, bug35674422) {
+ std::string path = android::base::GetExecutableDirectory();
+ // libutils_tests_singleton1.so contains the ANDROID_SINGLETON_STATIC_INSTANCE
+ // definition of SingletonTestData, load it first.
+ std::string lib = android::base::StringPrintf("%s/libutils_tests_singleton1.so", path.c_str());
+ void* handle1 = dlopen(lib.c_str(), RTLD_NOW);
+ ASSERT_TRUE(handle1 != nullptr) << dlerror();
+
+ // libutils_tests_singleton2.so references SingletonTestData but should not
+ // have a definition
+ lib = android::base::StringPrintf("%s/libutils_tests_singleton2.so", path.c_str());
+ void* handle2 = dlopen(lib.c_str(), RTLD_NOW);
+ ASSERT_TRUE(handle2 != nullptr) << dlerror();
+
+ using has_fn_t = decltype(&singletonHasInstance);
+ using get_fn_t = decltype(&singletonGetInstanceContents);
+ using set_fn_t = decltype(&singletonSetInstanceContents);
+
+ has_fn_t has1 = reinterpret_cast<has_fn_t>(dlsym(handle1, "singletonHasInstance"));
+ ASSERT_TRUE(has1 != nullptr) << dlerror();
+ has_fn_t has2 = reinterpret_cast<has_fn_t>(dlsym(handle2, "singletonHasInstance"));
+ ASSERT_TRUE(has2 != nullptr) << dlerror();
+ get_fn_t get1 = reinterpret_cast<get_fn_t>(dlsym(handle1, "singletonGetInstanceContents"));
+ ASSERT_TRUE(get1 != nullptr) << dlerror();
+ get_fn_t get2 = reinterpret_cast<get_fn_t>(dlsym(handle2, "singletonGetInstanceContents"));
+ ASSERT_TRUE(get2 != nullptr) << dlerror();
+ set_fn_t set1 = reinterpret_cast<set_fn_t>(dlsym(handle2, "singletonSetInstanceContents"));
+ ASSERT_TRUE(set1 != nullptr) << dlerror();
+
+ EXPECT_FALSE(has1());
+ EXPECT_FALSE(has2());
+ set1(12345678U);
+ EXPECT_TRUE(has1());
+ EXPECT_TRUE(has2());
+ EXPECT_EQ(12345678U, get1());
+ EXPECT_EQ(12345678U, get2());
+}
+
+}
diff --git a/libutils/tests/Singleton_test.h b/libutils/tests/Singleton_test.h
new file mode 100644
index 0000000..c77d9ff
--- /dev/null
+++ b/libutils/tests/Singleton_test.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_UTILS_SINGLETON_TEST_H
+#define ANDROID_UTILS_SINGLETON_TEST_H
+
+#include <sys/cdefs.h>
+
+#include "Singleton_test.h"
+
+namespace android {
+
+struct SingletonTestData : Singleton<SingletonTestData> {
+ unsigned int contents;
+};
+
+__BEGIN_DECLS
+
+unsigned int singletonGetInstanceContents();
+void singletonSetInstanceContents(unsigned int);
+bool singletonHasInstance();
+
+__END_DECLS
+
+}
+
+#endif // ANDROID_UTILS_SINGLETON_TEST_H
+
diff --git a/libutils/tests/Singleton_test1.cpp b/libutils/tests/Singleton_test1.cpp
new file mode 100644
index 0000000..4a91ec0
--- /dev/null
+++ b/libutils/tests/Singleton_test1.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/Singleton.h>
+
+#include "Singleton_test.h"
+
+namespace android {
+
+// Singleton<SingletonTestStruct> is referenced in Singleton_test1.cpp and
+// Singleton_test2.cpp, but only defined in Singleton_test1.cpp.
+ANDROID_SINGLETON_STATIC_INSTANCE(SingletonTestData);
+
+void singletonSetInstanceContents(unsigned int contents) {
+ SingletonTestData::getInstance().contents = contents;
+}
+
+unsigned int singletonGetInstanceContents() {
+ return SingletonTestData::getInstance().contents;
+}
+
+bool singletonHasInstance() {
+ return SingletonTestData::hasInstance();
+}
+
+}
diff --git a/libutils/tests/Singleton_test2.cpp b/libutils/tests/Singleton_test2.cpp
new file mode 100644
index 0000000..eb2a9df
--- /dev/null
+++ b/libutils/tests/Singleton_test2.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/Singleton.h>
+
+#include "Singleton_test.h"
+
+namespace android {
+
+// Singleton<SingletonTestStruct> is referenced in Singleton_test1.cpp and
+// Singleton_test2.cpp, but only defined in Singleton_test1.cpp.
+
+void singletonSetInstanceContents(unsigned int contents) {
+ SingletonTestData::getInstance().contents = contents;
+}
+
+unsigned int singletonGetInstanceContents() {
+ return SingletonTestData::getInstance().contents;
+}
+
+bool singletonHasInstance() {
+ return SingletonTestData::hasInstance();
+}
+
+}
diff --git a/libutils/tests/StrongPointer_test.cpp b/libutils/tests/StrongPointer_test.cpp
index 323a6f2..153cf96 100644
--- a/libutils/tests/StrongPointer_test.cpp
+++ b/libutils/tests/StrongPointer_test.cpp
@@ -21,13 +21,13 @@
using namespace android;
-class Foo : public LightRefBase<Foo> {
+class SPFoo : public LightRefBase<SPFoo> {
public:
- explicit Foo(bool* deleted_check) : mDeleted(deleted_check) {
+ explicit SPFoo(bool* deleted_check) : mDeleted(deleted_check) {
*mDeleted = false;
}
- ~Foo() {
+ ~SPFoo() {
*mDeleted = true;
}
private:
@@ -36,13 +36,13 @@
TEST(StrongPointer, move) {
bool isDeleted;
- Foo* foo = new Foo(&isDeleted);
+ SPFoo* foo = new SPFoo(&isDeleted);
ASSERT_EQ(0, foo->getStrongCount());
ASSERT_FALSE(isDeleted) << "Already deleted...?";
- sp<Foo> sp1(foo);
+ sp<SPFoo> sp1(foo);
ASSERT_EQ(1, foo->getStrongCount());
{
- sp<Foo> sp2 = std::move(sp1);
+ sp<SPFoo> sp2 = std::move(sp1);
ASSERT_EQ(1, foo->getStrongCount()) << "std::move failed, incremented refcnt";
ASSERT_EQ(nullptr, sp1.get()) << "std::move failed, sp1 is still valid";
// The strong count isn't increasing, let's double check the old object
@@ -52,7 +52,7 @@
ASSERT_FALSE(isDeleted) << "deleted too early! still has a reference!";
{
// Now let's double check it deletes on time
- sp<Foo> sp2 = std::move(sp1);
+ sp<SPFoo> sp2 = std::move(sp1);
}
ASSERT_TRUE(isDeleted) << "foo was leaked!";
}
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 7f852d4..d67dee5 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -67,8 +67,8 @@
std::vector<const char*> argv_hold;
std::vector<std::string> envs;
std::vector<const char*> envp_hold;
- int output_fd;
- int error_fd;
+ int output_fd; // duplication of fileno(output) (below)
+ int error_fd; // duplication of fileno(error) (below)
// library
int fds[2]; // From popen call
@@ -284,6 +284,15 @@
return;
}
context->output = fdopen(context->output_fd, "web");
+ if (context->output == NULL) {
+ logcat_panic(context, HELP_FALSE, "couldn't fdopen output file");
+ return;
+ }
+ if (context->stderr_stdout) {
+ close_error(context);
+ context->error = context->output;
+ context->error_fd = context->output_fd;
+ }
context->outByteCount = 0;
}
@@ -788,6 +797,7 @@
// Simulate shell stderr redirect parsing
if ((argv[i][0] != '2') || (argv[i][1] != '>')) continue;
+ // Append to file not implemented, just open file
size_t skip = (argv[i][2] == '>') + 2;
if (!strcmp(&argv[i][skip], "/dev/null")) {
context->stderr_null = true;
@@ -799,16 +809,29 @@
"stderr redirection to file %s unsupported, skipping\n",
&argv[i][skip]);
}
+ // Only the first one
+ break;
+ }
+
+ const char* filename = NULL;
+ for (int i = 0; i < argc; ++i) {
+ // Simulate shell stdout redirect parsing
+ if (argv[i][0] != '>') continue;
+
+ // Append to file not implemented, just open file
+ filename = &argv[i][(argv[i][1] == '>') + 1];
+ // Only the first one
+ break;
}
// Deal with setting up file descriptors and FILE pointers
- if (context->error_fd >= 0) {
+ if (context->error_fd >= 0) { // Is an error file descriptor supplied?
if (context->error_fd == context->output_fd) {
context->stderr_stdout = true;
- } else if (context->stderr_null) {
+ } else if (context->stderr_null) { // redirection told us to close it
close(context->error_fd);
context->error_fd = -1;
- } else {
+ } else { // All Ok, convert error to a FILE pointer
context->error = fdopen(context->error_fd, "web");
if (!context->error) {
context->retval = -errno;
@@ -819,22 +842,32 @@
}
}
}
- if (context->output_fd >= 0) {
- context->output = fdopen(context->output_fd, "web");
- if (!context->output) {
- context->retval = -errno;
- fprintf(context->stderr_stdout ? stdout : context->error,
- "Failed to fdopen(output_fd=%d) %s\n", context->output_fd,
- strerror(errno));
- goto exit;
+ if (context->output_fd >= 0) { // Is an output file descriptor supplied?
+ if (filename) { // redirect to file, close the supplied file descriptor.
+ close(context->output_fd);
+ context->output_fd = -1;
+ } else { // All Ok, convert output to a FILE pointer
+ context->output = fdopen(context->output_fd, "web");
+ if (!context->output) {
+ context->retval = -errno;
+ fprintf(context->stderr_stdout ? stdout : context->error,
+ "Failed to fdopen(output_fd=%d) %s\n",
+ context->output_fd, strerror(errno));
+ goto exit;
+ }
}
}
+ if (filename) { // We supplied an output file redirected in command line
+ context->output = fopen(filename, "web");
+ }
+ // Deal with 2>&1
if (context->stderr_stdout) context->error = context->output;
+ // Deal with 2>/dev/null
if (context->stderr_null) {
context->error_fd = -1;
context->error = NULL;
}
- // Only happens if output=stdout
+ // Only happens if output=stdout or output=filename
if ((context->output_fd < 0) && context->output) {
context->output_fd = fileno(context->output);
}
@@ -1351,6 +1384,8 @@
for (int i = optind ; i < argc ; i++) {
// skip stderr redirections of _all_ kinds
if ((argv[i][0] == '2') && (argv[i][1] == '>')) continue;
+ // skip stdout redirections of _all_ kinds
+ if (argv[i][0] == '>') continue;
err = android_log_addFilterString(context->logformat, argv[i]);
if (err < 0) {
diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk
index 1c3feba..22aca17 100644
--- a/logcat/tests/Android.mk
+++ b/logcat/tests/Android.mk
@@ -27,11 +27,12 @@
-fno-builtin \
# -----------------------------------------------------------------------------
-# Benchmarks (actually a gTest where the result code does not matter)
+# Benchmarks
# ----------------------------------------------------------------------------
benchmark_src_files := \
- logcat_benchmark.cpp
+ logcat_benchmark.cpp \
+ exec_benchmark.cpp \
# Build benchmarks for the device. Run with:
# adb shell /data/nativetest/logcat-benchmarks/logcat-benchmarks
@@ -40,7 +41,8 @@
LOCAL_MODULE_TAGS := $(test_tags)
LOCAL_CFLAGS += $(test_c_flags)
LOCAL_SRC_FILES := $(benchmark_src_files)
-include $(BUILD_NATIVE_TEST)
+LOCAL_SHARED_LIBRARIES := libbase liblogcat
+include $(BUILD_NATIVE_BENCHMARK)
# -----------------------------------------------------------------------------
# Unit tests.
diff --git a/logcat/tests/exec_benchmark.cpp b/logcat/tests/exec_benchmark.cpp
new file mode 100644
index 0000000..c30a5f5
--- /dev/null
+++ b/logcat/tests/exec_benchmark.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+
+#include <android-base/file.h>
+#include <benchmark/benchmark.h>
+#include <log/logcat.h>
+
+// Dump the statistics and report results
+
+static void logcat_popen_libc(benchmark::State& state, const char* cmd) {
+ while (state.KeepRunning()) {
+ FILE* fp = popen(cmd, "r");
+ std::string ret;
+ android::base::ReadFdToString(fileno(fp), &ret);
+ pclose(fp);
+ }
+}
+
+static void BM_logcat_stat_popen_libc(benchmark::State& state) {
+ logcat_popen_libc(state, "logcat -b all -S");
+}
+BENCHMARK(BM_logcat_stat_popen_libc);
+
+static void logcat_popen_liblogcat(benchmark::State& state, const char* cmd) {
+ while (state.KeepRunning()) {
+ android_logcat_context ctx;
+ FILE* fp = android_logcat_popen(&ctx, cmd);
+ std::string ret;
+ android::base::ReadFdToString(fileno(fp), &ret);
+ android_logcat_pclose(&ctx, fp);
+ }
+}
+
+static void BM_logcat_stat_popen_liblogcat(benchmark::State& state) {
+ logcat_popen_liblogcat(state, "logcat -b all -S");
+}
+BENCHMARK(BM_logcat_stat_popen_liblogcat);
+
+static void logcat_system_libc(benchmark::State& state, const char* cmd) {
+ while (state.KeepRunning()) {
+ system(cmd);
+ }
+}
+
+static void BM_logcat_stat_system_libc(benchmark::State& state) {
+ logcat_system_libc(state, "logcat -b all -S >/dev/null 2>/dev/null");
+}
+BENCHMARK(BM_logcat_stat_system_libc);
+
+static void logcat_system_liblogcat(benchmark::State& state, const char* cmd) {
+ while (state.KeepRunning()) {
+ android_logcat_system(cmd);
+ }
+}
+
+static void BM_logcat_stat_system_liblogcat(benchmark::State& state) {
+ logcat_system_liblogcat(state, "logcat -b all -S >/dev/null 2>/dev/null");
+}
+BENCHMARK(BM_logcat_stat_system_liblogcat);
+
+// Dump the logs and report results
+
+static void BM_logcat_dump_popen_libc(benchmark::State& state) {
+ logcat_popen_libc(state, "logcat -b all -d");
+}
+BENCHMARK(BM_logcat_dump_popen_libc);
+
+static void BM_logcat_dump_popen_liblogcat(benchmark::State& state) {
+ logcat_popen_liblogcat(state, "logcat -b all -d");
+}
+BENCHMARK(BM_logcat_dump_popen_liblogcat);
+
+static void BM_logcat_dump_system_libc(benchmark::State& state) {
+ logcat_system_libc(state, "logcat -b all -d >/dev/null 2>/dev/null");
+}
+BENCHMARK(BM_logcat_dump_system_libc);
+
+static void BM_logcat_dump_system_liblogcat(benchmark::State& state) {
+ logcat_system_liblogcat(state, "logcat -b all -d >/dev/null 2>/dev/null");
+}
+BENCHMARK(BM_logcat_dump_system_liblogcat);
diff --git a/logcat/tests/logcat_benchmark.cpp b/logcat/tests/logcat_benchmark.cpp
index dd85164..8d88628 100644
--- a/logcat/tests/logcat_benchmark.cpp
+++ b/logcat/tests/logcat_benchmark.cpp
@@ -18,19 +18,22 @@
#include <stdlib.h>
#include <string.h>
-#include <gtest/gtest.h>
+#include <benchmark/benchmark.h>
static const char begin[] = "--------- beginning of ";
-TEST(logcat, sorted_order) {
- FILE *fp;
+static void BM_logcat_sorted_order(benchmark::State& state) {
+ FILE* fp;
- ASSERT_TRUE(NULL != (fp = popen(
- "logcat -v time -b radio -b events -b system -b main -d 2>/dev/null",
- "r")));
+ if (!state.KeepRunning()) return;
+
+ fp = popen(
+ "logcat -v time -b radio -b events -b system -b main -d 2>/dev/null",
+ "r");
+ if (!fp) return;
class timestamp {
- private:
+ private:
int month;
int day;
int hour;
@@ -39,44 +42,39 @@
int millisecond;
bool ok;
- public:
- void init(const char *buffer)
- {
+ public:
+ void init(const char* buffer) {
ok = false;
if (buffer != NULL) {
- ok = sscanf(buffer, "%d-%d %d:%d:%d.%d ",
- &month, &day, &hour, &minute, &second, &millisecond) == 6;
+ ok = sscanf(buffer, "%d-%d %d:%d:%d.%d ", &month, &day, &hour,
+ &minute, &second, &millisecond) == 6;
}
}
- explicit timestamp(const char *buffer)
- {
+ explicit timestamp(const char* buffer) {
init(buffer);
}
- bool operator< (timestamp &T)
- {
- return !ok || !T.ok
- || (month < T.month)
- || ((month == T.month)
- && ((day < T.day)
- || ((day == T.day)
- && ((hour < T.hour)
- || ((hour == T.hour)
- && ((minute < T.minute)
- || ((minute == T.minute)
- && ((second < T.second)
- || ((second == T.second)
- && (millisecond < T.millisecond))))))))));
+ bool operator<(timestamp& T) {
+ return !ok || !T.ok || (month < T.month) ||
+ ((month == T.month) &&
+ ((day < T.day) ||
+ ((day == T.day) &&
+ ((hour < T.hour) ||
+ ((hour == T.hour) &&
+ ((minute < T.minute) ||
+ ((minute == T.minute) &&
+ ((second < T.second) ||
+ ((second == T.second) &&
+ (millisecond < T.millisecond))))))))));
}
- bool valid(void)
- {
+ bool valid(void) {
return ok;
}
} last(NULL);
- char *last_buffer = NULL;
+ char* last_buffer = NULL;
char buffer[5120];
int count = 0;
@@ -114,15 +112,22 @@
// Allow few fails, happens with readers active
fprintf(stderr, "%s: %d/%d out of order entries\n",
- (next_lt_last)
- ? ((next_lt_last <= max_ok)
- ? "WARNING"
- : "ERROR")
- : "INFO",
+ (next_lt_last) ? ((next_lt_last <= max_ok) ? "WARNING" : "ERROR")
+ : "INFO",
next_lt_last, count);
- EXPECT_GE(max_ok, next_lt_last);
+ if (next_lt_last > max_ok) {
+ fprintf(stderr, "EXPECT_GE(max_ok=%d, next_lt_last=%d)\n", max_ok,
+ next_lt_last);
+ }
// sample statistically too small
- EXPECT_LT(100, count);
+ if (count < 100) {
+ fprintf(stderr, "EXPECT_LT(100, count=%d)\n", count);
+ }
+
+ state.KeepRunning();
}
+BENCHMARK(BM_logcat_sorted_order);
+
+BENCHMARK_MAIN();
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 7d0c87d..03f878a 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -116,6 +116,12 @@
EXPORT_GLOBAL_ASAN_OPTIONS := export ASAN_OPTIONS include=/system/asan.options
LOCAL_REQUIRED_MODULES := asan.options $(ASAN_OPTIONS_FILES)
endif
+
+EXPORT_GLOBAL_GCOV_OPTIONS :=
+ifeq ($(NATIVE_COVERAGE),true)
+ EXPORT_GLOBAL_GCOV_OPTIONS := export GCOV_PREFIX /data/misc/gcov
+endif
+
# Put it here instead of in init.rc module definition,
# because init.rc is conditionally included.
#
@@ -163,6 +169,7 @@
$(hide) sed -e 's?%BOOTCLASSPATH%?$(PRODUCT_BOOTCLASSPATH)?g' $< >$@
$(hide) sed -i -e 's?%SYSTEMSERVERCLASSPATH%?$(PRODUCT_SYSTEM_SERVER_CLASSPATH)?g' $@
$(hide) sed -i -e 's?%EXPORT_GLOBAL_ASAN_OPTIONS%?$(EXPORT_GLOBAL_ASAN_OPTIONS)?g' $@
+ $(hide) sed -i -e 's?%EXPORT_GLOBAL_GCOV_OPTIONS%?$(EXPORT_GLOBAL_GCOV_OPTIONS)?g' $@
bcp_md5 :=
bcp_dep :=
diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in
index 32817fa..2e2ab74 100644
--- a/rootdir/init.environ.rc.in
+++ b/rootdir/init.environ.rc.in
@@ -10,3 +10,4 @@
export BOOTCLASSPATH %BOOTCLASSPATH%
export SYSTEMSERVERCLASSPATH %SYSTEMSERVERCLASSPATH%
%EXPORT_GLOBAL_ASAN_OPTIONS%
+ %EXPORT_GLOBAL_GCOV_OPTIONS%
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 1e5fa50..757e1ff 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -408,6 +408,7 @@
mkdir /data/misc/profiles/cur 0771 system system
mkdir /data/misc/profiles/ref 0771 system system
mkdir /data/misc/profman 0770 system shell
+ mkdir /data/misc/gcov 0770 root root
# For security reasons, /data/local/tmp should always be empty.
# Do not place files or directories in /data/local/tmp