Merge "libunwindstack: make machine type a property of Regs."
diff --git a/adb/bugreport.cpp b/adb/bugreport.cpp
index f63ac08..abef86a 100644
--- a/adb/bugreport.cpp
+++ b/adb/bugreport.cpp
@@ -102,7 +102,7 @@
std::vector<const char*> srcs{src_file_.c_str()};
SetLineMessage("pulling");
status_ =
- br_->DoSyncPull(srcs, destination.c_str(), true, line_message_.c_str()) ? 0 : 1;
+ br_->DoSyncPull(srcs, destination.c_str(), false, line_message_.c_str()) ? 0 : 1;
if (status_ != 0) {
fprintf(stderr,
"Bug report finished but could not be copied to '%s'.\n"
diff --git a/adb/bugreport_test.cpp b/adb/bugreport_test.cpp
index 758f24a..72ca59a 100644
--- a/adb/bugreport_test.cpp
+++ b/adb/bugreport_test.cpp
@@ -185,7 +185,7 @@
.WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device/da_bugreport.zip")),
WithArg<2>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
- true, StrEq("pulling da_bugreport.zip")))
+ false, StrEq("pulling da_bugreport.zip")))
.WillOnce(Return(true));
const char* args[] = {"bugreport"};
@@ -205,7 +205,7 @@
WithArg<2>(WriteOnStdout("OK:/device/da_bugreport.zip\n")),
WithArg<2>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
- true, StrEq("pulling da_bugreport.zip")))
+ false, StrEq("pulling da_bugreport.zip")))
.WillOnce(Return(true));
const char* args[] = {"bugreport"};
@@ -219,7 +219,7 @@
.WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip")),
WithArg<2>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
- true, StrEq("pulling file.zip")))
+ false, StrEq("pulling file.zip")))
.WillOnce(Return(true));
const char* args[] = {"bugreport", "file.zip"};
@@ -235,7 +235,7 @@
WithArg<2>(WriteOnStdout("/bugreport.zip")),
WithArg<2>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
- true, StrEq("pulling file.zip")))
+ false, StrEq("pulling file.zip")))
.WillOnce(Return(true));
const char* args[] = {"bugreport", "file.zip"};
@@ -271,7 +271,7 @@
WithArg<2>(ReturnCallbackDone())));
// clang-format on
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
- true, StrEq("pulling file.zip")))
+ false, StrEq("pulling file.zip")))
.WillOnce(Return(true));
const char* args[] = {"bugreport", "file.zip"};
@@ -302,7 +302,7 @@
WithArg<2>(ReturnCallbackDone())));
// clang-format on
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
- true, StrEq("pulling file.zip")))
+ false, StrEq("pulling file.zip")))
.WillOnce(Return(true));
const char* args[] = {"bugreport", "file.zip"};
@@ -325,7 +325,7 @@
WithArg<2>(ReturnCallbackDone())));
// clang-format on
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
- true, StrEq("pulling file.zip")))
+ false, StrEq("pulling file.zip")))
.WillOnce(Return(true));
const char* args[] = {"bugreport", "file.zip"};
@@ -344,7 +344,7 @@
WithArg<2>(WriteOnStdout("OK:/device/da_bugreport.zip")),
WithArg<2>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
- true, StrEq("pulling da_bugreport.zip")))
+ false, StrEq("pulling da_bugreport.zip")))
.WillOnce(Return(true));
const char* args[] = {"bugreport", td.path};
@@ -358,7 +358,7 @@
.WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip\n")),
WithArg<2>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
- true, StrEq("pulling file.zip")))
+ false, StrEq("pulling file.zip")))
.WillOnce(Return(true));
const char* args[] = {"bugreport", "file"};
@@ -377,7 +377,7 @@
WithArg<2>(WriteOnStdout("OK:/device/da_bugreport.zip")),
WithArg<2>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
- true, StrEq("pulling da_bugreport.zip")))
+ false, StrEq("pulling da_bugreport.zip")))
.WillOnce(Return(true));
const char* args[] = {"bugreport", td.path};
@@ -458,7 +458,7 @@
.WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip")),
WithArg<2>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
- true, HasSubstr("file.zip")))
+ false, HasSubstr("file.zip")))
.WillOnce(Return(false));
const char* args[] = {"bugreport", "file.zip"};
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 9f23473..d126f52 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -1588,9 +1588,13 @@
} else {
return 0;
}
- }
- else if (!strcmp(argv[0], "tcpip") && argc > 1) {
- return adb_connect_command(android::base::StringPrintf("tcpip:%s", argv[1]));
+ } else if (!strcmp(argv[0], "tcpip")) {
+ if (argc != 2) return syntax_error("tcpip requires an argument");
+ int port;
+ if (!android::base::ParseInt(argv[1], &port, 1, 65535)) {
+ return syntax_error("tcpip: invalid port: %s", argv[1]);
+ }
+ return adb_connect_command(android::base::StringPrintf("tcpip:%d", port));
}
else if (!strcmp(argv[0], "remount") ||
!strcmp(argv[0], "reboot") ||
diff --git a/adb/test_adb.py b/adb/test_adb.py
index cb3e0d8..98c8a59 100644
--- a/adb/test_adb.py
+++ b/adb/test_adb.py
@@ -60,13 +60,13 @@
stderr=subprocess.STDOUT)
out, _ = p.communicate()
self.assertEqual(1, p.returncode)
- self.assertIn('help message', out)
+ self.assertIn('requires an argument', out)
p = subprocess.Popen(['adb', 'tcpip', 'foo'], stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
out, _ = p.communicate()
self.assertEqual(1, p.returncode)
- self.assertIn('error', out)
+ self.assertIn('invalid port', out)
# Helper method that reads a pipe until it is closed, then sets the event.
def _read_pipe_and_set_event(self, pipe, event):
diff --git a/base/Android.bp b/base/Android.bp
index 1395756..82aee2a 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -40,6 +40,10 @@
name: "libbase",
vendor_available: true,
host_supported: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
srcs: [
"file.cpp",
"logging.cpp",
diff --git a/base/include/android-base/macros.h b/base/include/android-base/macros.h
index 88bbe8a..25f2ff4 100644
--- a/base/include/android-base/macros.h
+++ b/base/include/android-base/macros.h
@@ -179,4 +179,19 @@
} while (0)
#endif
+// Current ABI string
+#if defined(__arm__)
+#define ABI_STRING "arm"
+#elif defined(__aarch64__)
+#define ABI_STRING "arm64"
+#elif defined(__i386__)
+#define ABI_STRING "x86"
+#elif defined(__x86_64__)
+#define ABI_STRING "x86_64"
+#elif defined(__mips__) && !defined(__LP64__)
+#define ABI_STRING "mips"
+#elif defined(__mips__) && defined(__LP64__)
+#define ABI_STRING "mips64"
+#endif
+
#endif // ANDROID_BASE_MACROS_H
diff --git a/debuggerd/libdebuggerd/include/utility.h b/debuggerd/libdebuggerd/include/utility.h
index e5e5106..f481b78 100644
--- a/debuggerd/libdebuggerd/include/utility.h
+++ b/debuggerd/libdebuggerd/include/utility.h
@@ -24,26 +24,9 @@
#include <string>
+#include <android-base/macros.h>
#include <backtrace/Backtrace.h>
-// Figure out the abi based on defined macros.
-#if defined(__arm__)
-#define ABI_STRING "arm"
-#elif defined(__aarch64__)
-#define ABI_STRING "arm64"
-#elif defined(__mips__) && !defined(__LP64__)
-#define ABI_STRING "mips"
-#elif defined(__mips__) && defined(__LP64__)
-#define ABI_STRING "mips64"
-#elif defined(__i386__)
-#define ABI_STRING "x86"
-#elif defined(__x86_64__)
-#define ABI_STRING "x86_64"
-#else
-#error "Unsupported ABI"
-#endif
-
-
struct log_t{
// Tombstone file descriptor.
int tfd;
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 49d9438..5f2267c 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -1463,7 +1463,7 @@
if (fs_generator_generate(gen, output.path, size, initial_dir,
eraseBlkSize, logicalBlkSize)) {
- fprintf(stderr, "Cannot generate image: %s\n", strerror(errno));
+ die("Cannot generate image for %s\n", partition);
return;
}
diff --git a/init/Android.bp b/init/Android.bp
index b1f0279..efa5a02 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -54,6 +54,9 @@
"-DSHUTDOWN_ZERO_TIMEOUT=1",
],
},
+ uml: {
+ cppflags: ["-DUSER_MODE_LINUX"],
+ }
},
}
diff --git a/init/Android.mk b/init/Android.mk
index 3886ed5..23ada73 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -30,10 +30,6 @@
init_options += -DLOG_UEVENTS=0
-ifeq ($(TARGET_USER_MODE_LINUX), true)
- init_cflags += -DUSER_MODE_LINUX
-endif
-
init_cflags += \
$(init_options) \
-Wall -Wextra \
diff --git a/init/action.cpp b/init/action.cpp
index f687074..60204a8 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -91,14 +91,25 @@
auto result = command.InvokeFunc();
auto duration = t.duration();
+ // There are many legacy paths in rootdir/init.rc that will virtually never exist on a new
+ // device, such as '/sys/class/leds/jogball-backlight/brightness'. As of this writing, there
+ // are 198 such failures on bullhead. Instead of spamming the log reporting them, we do not
+ // report such failures unless we're running at the DEBUG log level.
+ bool report_failure = !result.has_value();
+ if (report_failure && android::base::GetMinimumLogSeverity() > android::base::DEBUG &&
+ result.error_errno() == ENOENT) {
+ report_failure = false;
+ }
+
// Any action longer than 50ms will be warned to user as slow operation
- if (duration > 50ms || android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
+ if (report_failure || duration > 50ms ||
+ android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
std::string trigger_name = BuildTriggersString();
std::string cmd_str = command.BuildCommandString();
LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << " (" << filename_
<< ":" << command.line() << ") took " << duration.count() << "ms and "
- << (result ? "succeeded" : "failed: " + result.error());
+ << (result ? "succeeded" : "failed: " + result.error_string());
}
}
diff --git a/init/builtins.cpp b/init/builtins.cpp
index f807343..54ccf09 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -127,7 +127,9 @@
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) return Error() << "Could not find service";
- if (!svc->Enable()) return Error() << "Could not enable service";
+ if (auto result = svc->Enable(); !result) {
+ return Error() << "Could not enable service: " << result.error();
+ }
return Success();
}
@@ -137,8 +139,8 @@
if (!service) {
return Error() << "Could not create exec service";
}
- if (!service->ExecStart()) {
- return Error() << "Could not start exec service";
+ if (auto result = service->ExecStart(); !result) {
+ return Error() << "Could not start exec service: " << result.error();
}
ServiceList::GetInstance().AddService(std::move(service));
@@ -151,16 +153,16 @@
return Error() << "Service not found";
}
- if (!service->ExecStart()) {
- return Error() << "Could not start Service";
+ if (auto result = service->ExecStart(); !result) {
+ return Error() << "Could not start exec service: " << result.error();
}
return Success();
}
static Result<Success> do_export(const std::vector<std::string>& args) {
- if (!add_environment(args[1].c_str(), args[2].c_str())) {
- return Error();
+ if (setenv(args[1].c_str(), args[2].c_str(), 1) == -1) {
+ return ErrnoError() << "setenv() failed";
}
return Success();
}
@@ -583,7 +585,9 @@
static Result<Success> do_start(const std::vector<std::string>& args) {
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) return Error() << "service " << args[1] << " not found";
- if (!svc->Start()) return Error() << "failed to start service";
+ if (auto result = svc->Start(); !result) {
+ return Error() << "Could not start service: " << result.error();
+ }
return Success();
}
@@ -608,6 +612,11 @@
static Result<Success> do_symlink(const std::vector<std::string>& args) {
if (symlink(args[1].c_str(), args[2].c_str()) < 0) {
+ // The symlink builtin is often used to create symlinks for older devices to be backwards
+ // compatible with new paths, therefore we skip reporting this error.
+ if (errno == EEXIST && android::base::GetMinimumLogSeverity() > android::base::DEBUG) {
+ return Success();
+ }
return ErrnoError() << "symlink() failed";
}
return Success();
diff --git a/init/descriptors.cpp b/init/descriptors.cpp
index cc5b948..6265687 100644
--- a/init/descriptors.cpp
+++ b/init/descriptors.cpp
@@ -28,7 +28,6 @@
#include <cutils/android_get_control_file.h>
#include <cutils/sockets.h>
-#include "init.h"
#include "util.h"
namespace android {
@@ -62,7 +61,7 @@
[] (char& c) { c = isalnum(c) ? c : '_'; });
std::string val = std::to_string(fd);
- add_environment(publishedName.c_str(), val.c_str());
+ setenv(publishedName.c_str(), val.c_str(), 1);
// make sure we don't close on exec
fcntl(fd, F_SETFD, 0);
diff --git a/init/init.cpp b/init/init.cpp
index d0afac1..e1bd3a2 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -71,8 +71,6 @@
std::string default_console = "/dev/console";
-const char *ENV[32];
-
static int epoll_fd = -1;
static std::unique_ptr<Timer> waiting_for_prop(nullptr);
@@ -126,38 +124,6 @@
}
}
-/* add_environment - add "key=value" to the current environment */
-int add_environment(const char *key, const char *val)
-{
- size_t n;
- size_t key_len = strlen(key);
-
- /* The last environment entry is reserved to terminate the list */
- for (n = 0; n < (arraysize(ENV) - 1); n++) {
-
- /* Delete any existing entry for this key */
- if (ENV[n] != NULL) {
- size_t entry_key_len = strcspn(ENV[n], "=");
- if ((entry_key_len == key_len) && (strncmp(ENV[n], key, entry_key_len) == 0)) {
- free((char*)ENV[n]);
- ENV[n] = NULL;
- }
- }
-
- /* Add entry if a free slot is available */
- if (ENV[n] == NULL) {
- char* entry;
- asprintf(&entry, "%s=%s", key, val);
- ENV[n] = entry;
- return 0;
- }
- }
-
- LOG(ERROR) << "No env. room to store: '" << key << "':'" << val << "'";
-
- return -1;
-}
-
bool start_waiting_for_property(const char *name, const char *value)
{
if (waiting_for_prop) {
@@ -429,8 +395,6 @@
install_reboot_signal_handlers();
}
- add_environment("PATH", _PATH_DEFPATH);
-
bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
if (is_first_stage) {
@@ -439,6 +403,8 @@
// Clear the umask.
umask(0);
+ clearenv();
+ setenv("PATH", _PATH_DEFPATH, 1);
// Get the basic filesystem setup we need put together in the initramdisk
// on / and then we'll let the rc file figure out the rest.
mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
diff --git a/init/init.h b/init/init.h
index 50a7c83..b757c1d 100644
--- a/init/init.h
+++ b/init/init.h
@@ -30,9 +30,7 @@
// Note: These globals are *only* valid in init, so they should not be used in ueventd,
// watchdogd, or any files that may be included in those, such as devices.cpp and util.cpp.
// TODO: Have an Init class and remove all globals.
-extern const char *ENV[32];
extern std::string default_console;
-
extern std::vector<std::string> late_import_paths;
Parser CreateParser(ActionManager& action_manager, ServiceList& service_list);
@@ -43,8 +41,6 @@
void register_epoll_handler(int fd, void (*fn)());
-int add_environment(const char* key, const char* val);
-
bool start_waiting_for_property(const char *name, const char *value);
void DumpState();
diff --git a/init/property_service.cpp b/init/property_service.cpp
index e07550a..f0e4d2e 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -690,6 +690,17 @@
* has mounted /data.
*/
void load_persist_props(void) {
+ // Devices with FDE have load_persist_props called twice; the first time when the temporary
+ // /data partition is mounted and then again once /data is truly mounted. We do not want to
+ // read persistent properties from the temporary /data partition or mark persistent properties
+ // as having been loaded during the first call, so we return in that case.
+ std::string crypto_state = android::base::GetProperty("ro.crypto.state", "");
+ std::string crypto_type = android::base::GetProperty("ro.crypto.type", "");
+ if (crypto_state == "encrypted" && crypto_type == "block") {
+ static size_t num_calls = 0;
+ if (++num_calls == 1) return;
+ }
+
load_override_properties();
/* Read persistent properties after all default values have been loaded. */
load_persistent_properties();
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 5bae4bc..97a8ddd 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -347,14 +347,10 @@
Timer t;
LOG(INFO) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget;
- android::base::WriteStringToFile(StringPrintf("%s\n", reason.c_str()), LAST_REBOOT_REASON_FILE,
- S_IRUSR | S_IWUSR, AID_SYSTEM, AID_SYSTEM);
+ property_set(LAST_REBOOT_REASON_PROPERTY, reason.c_str());
+ sync();
- bool is_thermal_shutdown = false;
- if (cmd == ANDROID_RB_THERMOFF) {
- is_thermal_shutdown = true;
- runFsck = false;
- }
+ bool is_thermal_shutdown = cmd == ANDROID_RB_THERMOFF;
auto shutdown_timeout = 0ms;
if (!SHUTDOWN_ZERO_TIMEOUT) {
@@ -476,10 +472,15 @@
command_invalid = true;
} else if (cmd_params[0] == "shutdown") {
cmd = ANDROID_RB_POWEROFF;
- if (cmd_params.size() == 2 && cmd_params[1] == "userrequested") {
- // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED.
- // Run fsck once the file system is remounted in read-only mode.
- run_fsck = true;
+ if (cmd_params.size() == 2) {
+ if (cmd_params[1] == "userrequested") {
+ // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED.
+ // Run fsck once the file system is remounted in read-only mode.
+ run_fsck = true;
+ } else if (cmd_params[1] == "thermal") {
+ // run_fsck is false to avoid delay
+ cmd = ANDROID_RB_THERMOFF;
+ }
}
} else if (cmd_params[0] == "reboot") {
cmd = ANDROID_RB_RESTART2;
@@ -495,14 +496,11 @@
<< err;
}
}
- // If there is an additional bootloader parameter, pass it along
- if (cmd_params.size() == 3) {
+ // If there is an additional parameter, pass it along
+ if ((cmd_params.size() == 3) && cmd_params[2].size()) {
reboot_target += "," + cmd_params[2];
}
}
- } else if (command == "thermal-shutdown") { // no additional parameter allowed
- // run_fsck is false to avoid delay
- cmd = ANDROID_RB_THERMOFF;
} else {
command_invalid = true;
}
diff --git a/init/reboot.h b/init/reboot.h
index 8586556..ece407f 100644
--- a/init/reboot.h
+++ b/init/reboot.h
@@ -27,7 +27,7 @@
/* Reboot / shutdown the system.
* cmd ANDROID_RB_* as defined in android_reboot.h
- * reason Reason string like "reboot", "userrequested"
+ * reason Reason string like "reboot", "shutdown,userrequested"
* rebootTarget Reboot target string like "bootloader". Otherwise, it should be an
* empty string.
* runFsck Whether to run fsck after umount is done.
diff --git a/init/result.h b/init/result.h
index 64fa69f..36c3b83 100644
--- a/init/result.h
+++ b/init/result.h
@@ -21,9 +21,13 @@
// There are 3 classes that implement this functionality and one additional helper type.
//
// Result<T> either contains a member of type T that can be accessed using similar semantics as
-// std::optional<T> or it contains a std::string describing an error, which can be accessed via
+// std::optional<T> or it contains a ResultError describing an error, which can be accessed via
// Result<T>::error().
//
+// ResultError is a type that contains both a std::string describing the error and a copy of errno
+// from when the error occurred. ResultError can be used in an ostream directly to print its
+// string value.
+//
// Success is a typedef that aids in creating Result<T> that do not contain a return value.
// Result<Success> is the correct return type for a function that either returns successfully or
// returns an error value. Returning Success() from a function that returns Result<Success> is the
@@ -33,10 +37,20 @@
// to T or from the constructor arguments for T. This allows you to return a type T directly from
// a function that returns Result<T>.
//
-// Error and ErrnoError are used to construct a Result<T> that has failed. Each of these classes
-// take an ostream as an input and are implicitly cast to a Result<T> containing that failure.
-// ErrnoError() additionally appends ": " + strerror(errno) to the end of the failure string to aid
-// in interacting with C APIs.
+// Error and ErrnoError are used to construct a Result<T> that has failed. The Error class takes
+// an ostream as an input and are implicitly cast to a Result<T> containing that failure.
+// ErrnoError() is a helper function to create an Error class that appends ": " + strerror(errno)
+// to the end of the failure string to aid in interacting with C APIs. Alternatively, an errno
+// value can be directly specified via the Error() constructor.
+//
+// ResultError can be used in the ostream when using Error to construct a Result<T>. In this case,
+// the string that the ResultError takes is passed through the stream normally, but the errno is
+// passed to the Result<T>. This can be used to pass errno from a failing C function up multiple
+// callers.
+//
+// ResultError can also directly construct a Result<T>. This is particularly useful if you have a
+// function that return Result<T> but you have a Result<U> and want to return its error. In this
+// case, you can return the .error() from the Result<U> to construct the Result<T>.
// An example of how to use these is below:
// Result<U> CalculateResult(const T& input) {
@@ -66,9 +80,29 @@
namespace android {
namespace init {
+struct ResultError {
+ template <typename T>
+ ResultError(T&& error_string, int error_errno)
+ : error_string(std::forward<T>(error_string)), error_errno(error_errno) {}
+
+ std::string error_string;
+ int error_errno;
+};
+
+inline std::ostream& operator<<(std::ostream& os, const ResultError& t) {
+ os << t.error_string;
+ return os;
+}
+
+inline std::ostream& operator<<(std::ostream& os, ResultError&& t) {
+ os << std::move(t.error_string);
+ return os;
+}
+
class Error {
public:
- Error() : append_errno_(0) {}
+ Error() : errno_(0), append_errno_(false) {}
+ Error(int errno_to_append) : errno_(errno_to_append), append_errno_(true) {}
template <typename T>
Error&& operator<<(T&& t) {
@@ -76,30 +110,45 @@
return std::move(*this);
}
- const std::string str() const {
- if (append_errno_) {
- return ss_.str() + ": " + strerror(append_errno_);
- }
- return ss_.str();
+ Error&& operator<<(const ResultError& result_error) {
+ ss_ << result_error.error_string;
+ errno_ = result_error.error_errno;
+ return std::move(*this);
}
+ Error&& operator<<(ResultError&& result_error) {
+ ss_ << std::move(result_error.error_string);
+ errno_ = result_error.error_errno;
+ return std::move(*this);
+ }
+
+ const std::string str() const {
+ std::string str = ss_.str();
+ if (append_errno_) {
+ if (str.empty()) {
+ return strerror(errno_);
+ }
+ return str + ": " + strerror(errno_);
+ }
+ return str;
+ }
+
+ int get_errno() const { return errno_; }
+
Error(const Error&) = delete;
Error(Error&&) = delete;
Error& operator=(const Error&) = delete;
Error& operator=(Error&&) = delete;
- protected:
- Error(int append_errno) : append_errno_(append_errno) {}
-
private:
std::stringstream ss_;
- int append_errno_;
+ int errno_;
+ bool append_errno_;
};
-class ErrnoError : public Error {
- public:
- ErrnoError() : Error(errno) {}
-};
+inline Error ErrnoError() {
+ return Error(errno);
+}
template <typename T>
class Result {
@@ -107,7 +156,13 @@
template <typename... U>
Result(U&&... result) : contents_(std::in_place_index_t<0>(), std::forward<U>(result)...) {}
- Result(Error&& fb) : contents_(std::in_place_index_t<1>(), fb.str()) {}
+ Result(Error&& error) : contents_(std::in_place_index_t<1>(), error.str(), error.get_errno()) {}
+ Result(const ResultError& result_error)
+ : contents_(std::in_place_index_t<1>(), result_error.error_string,
+ result_error.error_errno) {}
+ Result(ResultError&& result_error)
+ : contents_(std::in_place_index_t<1>(), std::move(result_error.error_string),
+ result_error.error_errno) {}
bool has_value() const { return contents_.index() == 0; }
@@ -116,9 +171,17 @@
T&& value() && { return std::get<0>(std::move(contents_)); }
const T&& value() const && { return std::get<0>(std::move(contents_)); }
- const std::string& error() const & { return std::get<1>(contents_); }
- std::string&& error() && { return std::get<1>(std::move(contents_)); }
- const std::string&& error() const && { return std::get<1>(std::move(contents_)); }
+ const ResultError& error() const & { return std::get<1>(contents_); }
+ ResultError&& error() && { return std::get<1>(std::move(contents_)); }
+ const ResultError&& error() const && { return std::get<1>(std::move(contents_)); }
+
+ const std::string& error_string() const & { return std::get<1>(contents_).error_string; }
+ std::string&& error_string() && { return std::get<1>(std::move(contents_)).error_string; }
+ const std::string&& error_string() const && {
+ return std::get<1>(std::move(contents_)).error_string;
+ }
+
+ int error_errno() const { return std::get<1>(contents_).error_errno; }
explicit operator bool() const { return has_value(); }
@@ -131,7 +194,7 @@
const T* operator->() const { return &value(); }
private:
- std::variant<T, std::string> contents_;
+ std::variant<T, ResultError> contents_;
};
using Success = std::monostate;
diff --git a/init/result_test.cpp b/init/result_test.cpp
index ca65013..19caaf5 100644
--- a/init/result_test.cpp
+++ b/init/result_test.cpp
@@ -74,7 +74,8 @@
ASSERT_FALSE(result);
ASSERT_FALSE(result.has_value());
- EXPECT_EQ("failure1", result.error());
+ EXPECT_EQ(0, result.error_errno());
+ EXPECT_EQ("failure1", result.error_string());
}
TEST(result, result_error_empty) {
@@ -82,7 +83,8 @@
ASSERT_FALSE(result);
ASSERT_FALSE(result.has_value());
- EXPECT_EQ("", result.error());
+ EXPECT_EQ(0, result.error_errno());
+ EXPECT_EQ("", result.error_string());
}
TEST(result, result_error_rvalue) {
@@ -96,7 +98,8 @@
ASSERT_FALSE(MakeRvalueErrorResult());
ASSERT_FALSE(MakeRvalueErrorResult().has_value());
- EXPECT_EQ("failure1", MakeRvalueErrorResult().error());
+ EXPECT_EQ(0, MakeRvalueErrorResult().error_errno());
+ EXPECT_EQ("failure1", MakeRvalueErrorResult().error_string());
}
TEST(result, result_errno_error) {
@@ -107,7 +110,72 @@
ASSERT_FALSE(result);
ASSERT_FALSE(result.has_value());
- EXPECT_EQ("failure1: "s + strerror(test_errno), result.error());
+ EXPECT_EQ(test_errno, result.error_errno());
+ EXPECT_EQ("failure1: "s + strerror(test_errno), result.error_string());
+}
+
+TEST(result, result_errno_error_no_text) {
+ constexpr int test_errno = 6;
+ errno = test_errno;
+ Result<Success> result = ErrnoError();
+
+ ASSERT_FALSE(result);
+ ASSERT_FALSE(result.has_value());
+
+ EXPECT_EQ(test_errno, result.error_errno());
+ EXPECT_EQ(strerror(test_errno), result.error_string());
+}
+
+TEST(result, result_error_from_other_result) {
+ auto error_text = "test error"s;
+ Result<Success> result = Error() << error_text;
+
+ ASSERT_FALSE(result);
+ ASSERT_FALSE(result.has_value());
+
+ Result<std::string> result2 = result.error();
+
+ ASSERT_FALSE(result2);
+ ASSERT_FALSE(result2.has_value());
+
+ EXPECT_EQ(0, result.error_errno());
+ EXPECT_EQ(error_text, result.error_string());
+}
+
+TEST(result, result_error_through_ostream) {
+ auto error_text = "test error"s;
+ Result<Success> result = Error() << error_text;
+
+ ASSERT_FALSE(result);
+ ASSERT_FALSE(result.has_value());
+
+ Result<std::string> result2 = Error() << result.error();
+
+ ASSERT_FALSE(result2);
+ ASSERT_FALSE(result2.has_value());
+
+ EXPECT_EQ(0, result.error_errno());
+ EXPECT_EQ(error_text, result.error_string());
+}
+
+TEST(result, result_errno_error_through_ostream) {
+ auto error_text = "test error"s;
+ constexpr int test_errno = 6;
+ errno = 6;
+ Result<Success> result = ErrnoError() << error_text;
+
+ errno = 0;
+
+ ASSERT_FALSE(result);
+ ASSERT_FALSE(result.has_value());
+
+ Result<std::string> result2 = Error() << result.error();
+
+ ASSERT_FALSE(result2);
+ ASSERT_FALSE(result2.has_value());
+
+ EXPECT_EQ(test_errno, result.error_errno());
+ EXPECT_EQ(error_text + ": " + strerror(test_errno), result.error_string());
}
TEST(result, constructor_forwarding) {
@@ -215,7 +283,7 @@
TEST(result, die_on_get_error_succesful_result) {
Result<std::string> result = "success";
- ASSERT_DEATH(result.error(), "");
+ ASSERT_DEATH(result.error_string(), "");
}
} // namespace init
diff --git a/init/selinux.cpp b/init/selinux.cpp
index c824028..ef59164 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -48,7 +48,6 @@
#include "selinux.h"
#include <fcntl.h>
-#include <paths.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
@@ -126,8 +125,7 @@
}
TEMP_FAILURE_RETRY(close(pipe_fds[1]));
- const char* envp[] = {_PATH_DEFPATH, nullptr};
- if (execve(filename, argv, (char**)envp) == -1) {
+ if (execv(filename, argv) == -1) {
PLOG(ERROR) << "Failed to execve " << filename;
return false;
}
diff --git a/init/service.cpp b/init/service.cpp
index 6ab60e3..dee0c3d 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -57,22 +57,20 @@
namespace android {
namespace init {
-static std::string ComputeContextFromExecutable(std::string& service_name,
- const std::string& service_path) {
+static Result<std::string> ComputeContextFromExecutable(std::string& service_name,
+ const std::string& service_path) {
std::string computed_context;
char* raw_con = nullptr;
char* raw_filecon = nullptr;
if (getcon(&raw_con) == -1) {
- LOG(ERROR) << "could not get context while starting '" << service_name << "'";
- return "";
+ return Error() << "Could not get security context";
}
std::unique_ptr<char> mycon(raw_con);
if (getfilecon(service_path.c_str(), &raw_filecon) == -1) {
- LOG(ERROR) << "could not get file context while starting '" << service_name << "'";
- return "";
+ return Error() << "Could not get file context";
}
std::unique_ptr<char> filecon(raw_filecon);
@@ -84,12 +82,14 @@
free(new_con);
}
if (rc == 0 && computed_context == mycon.get()) {
- LOG(ERROR) << "service " << service_name << " does not have a SELinux domain defined";
- return "";
+ return Error() << "File " << service_path << "(labeled \"" << filecon.get()
+ << "\") has incorrect label or no domain transition from " << mycon.get()
+ << " to another SELinux domain defined. Have you configured your "
+ "service correctly? https://source.android.com/security/selinux/"
+ "device-policy#label_new_services_and_address_denials";
}
if (rc < 0) {
- LOG(ERROR) << "could not get context while starting '" << service_name << "'";
- return "";
+ return Error() << "Could not get process context";
}
return computed_context;
}
@@ -147,14 +147,6 @@
strs->push_back(nullptr);
}
-ServiceEnvironmentInfo::ServiceEnvironmentInfo() {
-}
-
-ServiceEnvironmentInfo::ServiceEnvironmentInfo(const std::string& name,
- const std::string& value)
- : name(name), value(value) {
-}
-
unsigned long Service::next_start_order_ = 1;
bool Service::is_exec_service_running_ = false;
@@ -507,7 +499,7 @@
}
Result<Success> Service::ParseSetenv(const std::vector<std::string>& args) {
- envvars_.emplace_back(args[1], args[2]);
+ environment_vars_.emplace_back(args[1], args[2]);
return Success();
}
@@ -637,16 +629,16 @@
static const OptionParserMap parser_map;
auto parser = parser_map.FindFunction(args);
- if (!parser) return Error() << parser.error();
+ if (!parser) return parser.error();
return std::invoke(*parser, this, args);
}
-bool Service::ExecStart() {
+Result<Success> Service::ExecStart() {
flags_ |= SVC_ONESHOT;
- if (!Start()) {
- return false;
+ if (auto result = Start(); !result) {
+ return result;
}
flags_ |= SVC_EXEC;
@@ -656,10 +648,10 @@
<< supp_gids_.size() << " context " << (!seclabel_.empty() ? seclabel_ : "default")
<< ") started; waiting...";
- return true;
+ return Success();
}
-bool Service::Start() {
+Result<Success> Service::Start() {
// Starting a service removes it from the disabled or reset state and
// immediately takes it out of the restarting state if it was in there.
flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
@@ -668,7 +660,8 @@
// process of exiting, we've ensured that they will immediately restart
// on exit, unless they are ONESHOT.
if (flags_ & SVC_RUNNING) {
- return false;
+ // It is not an error to try to start a service that is already running.
+ return Success();
}
bool needs_console = (flags_ & SVC_CONSOLE);
@@ -681,28 +674,27 @@
// properly registered for the device node
int console_fd = open(console_.c_str(), O_RDWR | O_CLOEXEC);
if (console_fd < 0) {
- PLOG(ERROR) << "service '" << name_ << "' couldn't open console '" << console_ << "'";
flags_ |= SVC_DISABLED;
- return false;
+ return ErrnoError() << "Couldn't open console '" << console_ << "'";
}
close(console_fd);
}
struct stat sb;
if (stat(args_[0].c_str(), &sb) == -1) {
- PLOG(ERROR) << "cannot find '" << args_[0] << "', disabling '" << name_ << "'";
flags_ |= SVC_DISABLED;
- return false;
+ return ErrnoError() << "Cannot find '" << args_[0] << "'";
}
std::string scon;
if (!seclabel_.empty()) {
scon = seclabel_;
} else {
- scon = ComputeContextFromExecutable(name_, args_[0]);
- if (scon == "") {
- return false;
+ auto result = ComputeContextFromExecutable(name_, args_[0]);
+ if (!result) {
+ return result.error();
}
+ scon = *result;
}
LOG(INFO) << "starting service '" << name_ << "'...";
@@ -723,8 +715,8 @@
SetUpPidNamespace(name_);
}
- for (const auto& ei : envvars_) {
- add_environment(ei.name.c_str(), ei.value.c_str());
+ for (const auto& [key, value] : environment_vars_) {
+ setenv(key.c_str(), value.c_str(), 1);
}
std::for_each(descriptors_.begin(), descriptors_.end(),
@@ -779,7 +771,7 @@
std::vector<char*> strs;
ExpandArgs(args_, &strs);
- if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) {
+ if (execv(strs[0], (char**)&strs[0]) < 0) {
PLOG(ERROR) << "cannot execve('" << strs[0] << "')";
}
@@ -787,9 +779,8 @@
}
if (pid < 0) {
- PLOG(ERROR) << "failed to fork for '" << name_ << "'";
pid_ = 0;
- return false;
+ return ErrnoError() << "Failed to fork";
}
if (oom_score_adjust_ != -1000) {
@@ -831,24 +822,24 @@
}
NotifyStateChange("running");
- return true;
+ return Success();
}
-bool Service::StartIfNotDisabled() {
+Result<Success> Service::StartIfNotDisabled() {
if (!(flags_ & SVC_DISABLED)) {
return Start();
} else {
flags_ |= SVC_DISABLED_START;
}
- return true;
+ return Success();
}
-bool Service::Enable() {
+Result<Success> Service::Enable() {
flags_ &= ~(SVC_DISABLED | SVC_RC_DISABLED);
if (flags_ & SVC_DISABLED_START) {
return Start();
}
- return true;
+ return Success();
}
void Service::Reset() {
@@ -874,7 +865,9 @@
StopOrReset(SVC_RESTART);
} else if (!(flags_ & SVC_RESTARTING)) {
/* Just start the service since it's not running. */
- Start();
+ if (auto result = Start(); !result) {
+ LOG(ERROR) << "Could not restart '" << name_ << "': " << result.error();
+ }
} /* else: Service is restarting anyways. */
}
diff --git a/init/service.h b/init/service.h
index fe85129..1f2c44f 100644
--- a/init/service.h
+++ b/init/service.h
@@ -57,13 +57,6 @@
namespace android {
namespace init {
-struct ServiceEnvironmentInfo {
- ServiceEnvironmentInfo();
- ServiceEnvironmentInfo(const std::string& name, const std::string& value);
- std::string name;
- std::string value;
-};
-
class Service {
public:
Service(const std::string& name, const std::vector<std::string>& args);
@@ -77,10 +70,10 @@
bool IsRunning() { return (flags_ & SVC_RUNNING) != 0; }
Result<Success> ParseLine(const std::vector<std::string>& args);
- bool ExecStart();
- bool Start();
- bool StartIfNotDisabled();
- bool Enable();
+ Result<Success> ExecStart();
+ Result<Success> Start();
+ Result<Success> StartIfNotDisabled();
+ Result<Success> Enable();
void Reset();
void Stop();
void Terminate();
@@ -178,7 +171,7 @@
std::string seclabel_;
std::vector<std::unique_ptr<DescriptorInfo>> descriptors_;
- std::vector<ServiceEnvironmentInfo> envvars_;
+ std::vector<std::pair<std::string, std::string>> environment_vars_;
Action onrestart_; // Commands to execute on restart.
diff --git a/init/util.cpp b/init/util.cpp
index 9112c3f..a19a6f3 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -206,13 +206,16 @@
}
int wait_for_file(const char* filename, std::chrono::nanoseconds timeout) {
- boot_clock::time_point timeout_time = boot_clock::now() + timeout;
- while (boot_clock::now() < timeout_time) {
+ android::base::Timer t;
+ while (t.duration() < timeout) {
struct stat sb;
- if (stat(filename, &sb) != -1) return 0;
-
+ if (stat(filename, &sb) != -1) {
+ LOG(INFO) << "wait for '" << filename << "' took " << t;
+ return 0;
+ }
std::this_thread::sleep_for(10ms);
}
+ LOG(WARNING) << "wait for '" << filename << "' timed out and took " << t;
return -1;
}
diff --git a/init/util_test.cpp b/init/util_test.cpp
index 007d10e..3ae53a4 100644
--- a/init/util_test.cpp
+++ b/init/util_test.cpp
@@ -34,7 +34,7 @@
auto file_contents = ReadFile("/proc/does-not-exist");
EXPECT_EQ(ENOENT, errno);
ASSERT_FALSE(file_contents);
- EXPECT_EQ("open() failed: No such file or directory", file_contents.error());
+ EXPECT_EQ("open() failed: No such file or directory", file_contents.error_string());
}
TEST(util, ReadFileGroupWriteable) {
@@ -45,7 +45,7 @@
EXPECT_NE(-1, fchmodat(AT_FDCWD, tf.path, 0620, AT_SYMLINK_NOFOLLOW)) << strerror(errno);
auto file_contents = ReadFile(tf.path);
ASSERT_FALSE(file_contents) << strerror(errno);
- EXPECT_EQ("Skipping insecure file", file_contents.error());
+ EXPECT_EQ("Skipping insecure file", file_contents.error_string());
}
TEST(util, ReadFileWorldWiteable) {
@@ -56,7 +56,7 @@
EXPECT_NE(-1, fchmodat(AT_FDCWD, tf.path, 0602, AT_SYMLINK_NOFOLLOW)) << strerror(errno);
auto file_contents = ReadFile(tf.path);
ASSERT_FALSE(file_contents) << strerror(errno);
- EXPECT_EQ("Skipping insecure file", file_contents.error());
+ EXPECT_EQ("Skipping insecure file", file_contents.error_string());
}
TEST(util, ReadFileSymbolicLink) {
@@ -65,7 +65,7 @@
auto file_contents = ReadFile("/charger");
EXPECT_EQ(ELOOP, errno);
ASSERT_FALSE(file_contents);
- EXPECT_EQ("open() failed: Too many symbolic links encountered", file_contents.error());
+ EXPECT_EQ("open() failed: Too many symbolic links encountered", file_contents.error_string());
}
TEST(util, ReadFileSuccess) {
@@ -130,7 +130,7 @@
decoded_uid = DecodeUid("toot");
EXPECT_FALSE(decoded_uid);
- EXPECT_EQ("getpwnam failed: No such file or directory", decoded_uid.error());
+ EXPECT_EQ("getpwnam failed: No such file or directory", decoded_uid.error_string());
decoded_uid = DecodeUid("123");
EXPECT_TRUE(decoded_uid);
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index c58d777..4190403 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -66,6 +66,10 @@
cc_library {
name: "libbacktrace",
vendor_available: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
defaults: ["libbacktrace_common"],
host_supported: true,
@@ -240,3 +244,17 @@
},
},
}
+
+cc_benchmark {
+ name: "backtrace_benchmarks",
+ defaults: ["libbacktrace_common"],
+
+ srcs: [
+ "backtrace_benchmarks.cpp",
+ ],
+
+ shared_libs: [
+ "libbacktrace",
+ "libbase",
+ ],
+}
diff --git a/libbacktrace/backtrace_benchmarks.cpp b/libbacktrace/backtrace_benchmarks.cpp
new file mode 100644
index 0000000..30c2a55
--- /dev/null
+++ b/libbacktrace/backtrace_benchmarks.cpp
@@ -0,0 +1,162 @@
+/*
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <android-base/file.h>
+
+#include <benchmark/benchmark.h>
+
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
+
+// Definitions of prctl arguments to set a vma name in Android kernels.
+#define ANDROID_PR_SET_VMA 0x53564d41
+#define ANDROID_PR_SET_VMA_ANON_NAME 0
+
+constexpr size_t kNumMaps = 2000;
+constexpr size_t kNumIterations = 1000;
+
+static bool CountMaps(pid_t pid, size_t* num_maps) {
+ // Minimize the calls that might allocate memory. If too much memory
+ // gets allocated, then this routine will add extra maps and the next
+ // call will fail to get the same number of maps as before.
+ int fd =
+ open((std::string("/proc/") + std::to_string(pid) + "/maps").c_str(), O_RDONLY | O_CLOEXEC);
+ if (fd == -1) {
+ fprintf(stderr, "Cannot open map file for pid %d: %s\n", pid, strerror(errno));
+ return false;
+ }
+ *num_maps = 0;
+ while (true) {
+ char buffer[2048];
+ ssize_t bytes = read(fd, buffer, sizeof(buffer));
+ if (bytes <= 0) {
+ break;
+ }
+ // Count the '\n'.
+ for (size_t i = 0; i < static_cast<size_t>(bytes); i++) {
+ if (buffer[i] == '\n') {
+ ++*num_maps;
+ }
+ }
+ }
+
+ close(fd);
+ return true;
+}
+
+static void CreateMap(benchmark::State& state, BacktraceMap* (*map_func)(pid_t, bool)) {
+ state.PauseTiming();
+ // Create a remote process so that the map data is exactly the same.
+ // Also, so that we can create a set number of maps.
+ pid_t pid;
+ if ((pid = fork()) == 0) {
+ size_t num_maps;
+ if (!CountMaps(getpid(), &num_maps)) {
+ exit(1);
+ }
+ // Create uniquely named maps.
+ std::vector<void*> maps;
+ for (size_t i = num_maps; i < kNumMaps; i++) {
+ int flags = PROT_READ | PROT_WRITE;
+ // Alternate page type to make sure a map entry is added for each call.
+ if ((i % 2) == 0) {
+ flags |= PROT_EXEC;
+ }
+ void* memory = mmap(nullptr, PAGE_SIZE, flags, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (memory == MAP_FAILED) {
+ fprintf(stderr, "Failed to create map: %s\n", strerror(errno));
+ exit(1);
+ }
+ memset(memory, 0x1, PAGE_SIZE);
+ if (prctl(ANDROID_PR_SET_VMA, ANDROID_PR_SET_VMA_ANON_NAME, memory, PAGE_SIZE, "test_map") ==
+ -1) {
+ fprintf(stderr, "Failed: %s\n", strerror(errno));
+ }
+ maps.push_back(memory);
+ }
+
+ if (!CountMaps(getpid(), &num_maps)) {
+ exit(1);
+ }
+
+ if (num_maps != kNumMaps) {
+ fprintf(stderr, "Maps set incorrectly: %zu found, %zu expected.\n", num_maps, kNumMaps);
+ std::string str;
+ android::base::ReadFileToString("/proc/self/maps", &str);
+ fprintf(stderr, "%s\n", str.c_str());
+ exit(1);
+ }
+
+ // Wait for an hour at most.
+ sleep(3600);
+ exit(1);
+ } else if (pid < 0) {
+ fprintf(stderr, "Fork failed: %s\n", strerror(errno));
+ return;
+ }
+
+ size_t num_maps = 0;
+ for (size_t i = 0; i < 2000; i++) {
+ if (CountMaps(pid, &num_maps) && num_maps == kNumMaps) {
+ break;
+ }
+ usleep(1000);
+ }
+ if (num_maps != kNumMaps) {
+ fprintf(stderr, "Timed out waiting for the number of maps available: %zu\n", num_maps);
+ return;
+ }
+
+ state.ResumeTiming();
+ while (state.KeepRunning()) {
+ for (size_t i = 0; i < static_cast<size_t>(state.range(0)); i++) {
+ BacktraceMap* map = map_func(pid, false);
+ if (map == nullptr) {
+ fprintf(stderr, "Failed to create map\n");
+ return;
+ }
+ delete map;
+ }
+ }
+ state.PauseTiming();
+
+ kill(pid, SIGKILL);
+ waitpid(pid, nullptr, 0);
+}
+
+static void BM_create_map(benchmark::State& state) {
+ CreateMap(state, BacktraceMap::Create);
+}
+BENCHMARK(BM_create_map)->Arg(kNumIterations);
+
+static void BM_create_map_new(benchmark::State& state) {
+ CreateMap(state, BacktraceMap::CreateNew);
+}
+BENCHMARK(BM_create_map_new)->Arg(kNumIterations);
+
+BENCHMARK_MAIN();
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 8528a4b..cfe8d29 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -50,6 +50,10 @@
cc_library {
name: "libcutils",
vendor_available: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
host_supported: true,
srcs: [
"config_utils.c",
diff --git a/libcutils/android_reboot.c b/libcutils/android_reboot.c
index a33e45f..996d89d 100644
--- a/libcutils/android_reboot.c
+++ b/libcutils/android_reboot.c
@@ -35,11 +35,11 @@
restart_cmd = "shutdown";
break;
case ANDROID_RB_THERMOFF:
- restart_cmd = "thermal-shutdown";
+ restart_cmd = "shutdown,thermal";
break;
}
if (!restart_cmd) return -1;
- if (arg) {
+ if (arg && arg[0]) {
ret = asprintf(&prop_value, "%s,%s", restart_cmd, arg);
} else {
ret = asprintf(&prop_value, "%s", restart_cmd);
diff --git a/libcutils/include/cutils/android_reboot.h b/libcutils/include/cutils/android_reboot.h
index 716567a..a903adb 100644
--- a/libcutils/include/cutils/android_reboot.h
+++ b/libcutils/include/cutils/android_reboot.h
@@ -29,8 +29,8 @@
/* Properties */
#define ANDROID_RB_PROPERTY "sys.powerctl"
-/* Android reboot reason stored in this file */
-#define LAST_REBOOT_REASON_FILE "/data/misc/reboot/last_reboot_reason"
+/* Android reboot reason stored in this property */
+#define LAST_REBOOT_REASON_PROPERTY "persist.sys.boot.reason"
/* Reboot or shutdown the system.
* This call uses ANDROID_RB_PROPERTY to request reboot to init process.
diff --git a/libion/Android.bp b/libion/Android.bp
index 6f267e4..6d9fae0 100644
--- a/libion/Android.bp
+++ b/libion/Android.bp
@@ -1,7 +1,11 @@
cc_library {
name: "libion",
- vendor_available: true,
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
srcs: ["ion.c"],
shared_libs: ["liblog"],
local_include_dirs: [
diff --git a/liblog/logd_reader.c b/liblog/logd_reader.c
index 600f4bb..603ba24 100644
--- a/liblog/logd_reader.c
+++ b/liblog/logd_reader.c
@@ -590,20 +590,30 @@
memset(log_msg, 0, sizeof(*log_msg));
+ unsigned int new_alarm = 0;
if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
+ if ((logger_list->mode & ANDROID_LOG_WRAP) &&
+ (logger_list->start.tv_sec || logger_list->start.tv_nsec)) {
+ /* b/64143705 */
+ new_alarm = (ANDROID_LOG_WRAP_DEFAULT_TIMEOUT * 11) / 10 + 10;
+ logger_list->mode &= ~ANDROID_LOG_WRAP;
+ } else {
+ new_alarm = 30;
+ }
+
memset(&ignore, 0, sizeof(ignore));
ignore.sa_handler = caught_signal;
sigemptyset(&ignore.sa_mask);
/* particularily useful if tombstone is reporting for logd */
sigaction(SIGALRM, &ignore, &old_sigaction);
- old_alarm = alarm(30);
+ old_alarm = alarm(new_alarm);
}
/* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */
ret = recv(ret, log_msg, LOGGER_ENTRY_MAX_LEN, 0);
e = errno;
- if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
+ if (new_alarm) {
if ((ret == 0) || (e == EINTR)) {
e = EAGAIN;
ret = -1;
diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk
index ab96429..275a2d6 100644
--- a/liblog/tests/Android.mk
+++ b/liblog/tests/Android.mk
@@ -64,7 +64,8 @@
log_radio_test.cpp \
log_read_test.cpp \
log_system_test.cpp \
- log_time_test.cpp
+ log_time_test.cpp \
+ log_wrap_test.cpp
# Build tests for the device (with .so). Run with:
# adb shell /data/nativetest/liblog-unit-tests/liblog-unit-tests
diff --git a/liblog/tests/log_id_test.cpp b/liblog/tests/log_id_test.cpp
index c56fa8b..9fb5a2c 100644
--- a/liblog/tests/log_id_test.cpp
+++ b/liblog/tests/log_id_test.cpp
@@ -89,12 +89,12 @@
ASSERT_EQ(0, pthread_create(&t[i], NULL, ConcurrentPrintFn,
reinterpret_cast<void*>(i)));
}
- int ret = 0;
+ int ret = 1;
for (i = 0; i < NUM_CONCURRENT; i++) {
void* result;
ASSERT_EQ(0, pthread_join(t[i], &result));
int this_result = reinterpret_cast<uintptr_t>(result);
- if ((0 == ret) && (0 != this_result)) {
+ if ((0 < ret) && (ret != this_result)) {
ret = this_result;
}
}
diff --git a/liblog/tests/log_wrap_test.cpp b/liblog/tests/log_wrap_test.cpp
new file mode 100644
index 0000000..ebf0b15
--- /dev/null
+++ b/liblog/tests/log_wrap_test.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2013-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 <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <android-base/chrono_utils.h>
+#include <android-base/stringprintf.h>
+#include <android/log.h> // minimal logging API
+#include <gtest/gtest.h>
+#include <log/log_properties.h>
+#include <log/log_read.h>
+#include <log/log_time.h>
+#include <log/log_transport.h>
+
+#ifdef __ANDROID__
+static void read_with_wrap() {
+ android_set_log_transport(LOGGER_LOGD);
+
+ // Read the last line in the log to get a starting timestamp. We're assuming
+ // the log is not empty.
+ const int mode = ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK;
+ struct logger_list* logger_list =
+ android_logger_list_open(LOG_ID_MAIN, mode, 1000, 0);
+
+ ASSERT_NE(logger_list, nullptr);
+
+ log_msg log_msg;
+ int ret = android_logger_list_read(logger_list, &log_msg);
+ android_logger_list_close(logger_list);
+ ASSERT_GT(ret, 0);
+
+ log_time start(log_msg.entry.sec, log_msg.entry.nsec);
+ ASSERT_NE(start, log_time());
+
+ logger_list =
+ android_logger_list_alloc_time(mode | ANDROID_LOG_WRAP, start, 0);
+ ASSERT_NE(logger_list, nullptr);
+
+ struct logger* logger = android_logger_open(logger_list, LOG_ID_MAIN);
+ EXPECT_NE(logger, nullptr);
+ if (logger) {
+ android_logger_list_read(logger_list, &log_msg);
+ }
+
+ android_logger_list_close(logger_list);
+}
+
+static void caught_signal(int /* signum */) {
+}
+#endif
+
+// b/64143705 confirm fixed
+TEST(liblog, wrap_mode_blocks) {
+#ifdef __ANDROID__
+
+ android::base::Timer timer;
+
+ // The read call is expected to take up to 2 hours in the happy case.
+ // We only want to make sure it waits for longer than 30s, but we can't
+ // use an alarm as the implementation uses it. So we run the test in
+ // a separate process.
+ pid_t pid = fork();
+
+ if (pid == 0) {
+ // child
+ read_with_wrap();
+ _exit(0);
+ }
+
+ struct sigaction ignore, old_sigaction;
+ memset(&ignore, 0, sizeof(ignore));
+ ignore.sa_handler = caught_signal;
+ sigemptyset(&ignore.sa_mask);
+ sigaction(SIGALRM, &ignore, &old_sigaction);
+ alarm(45);
+
+ bool killed = false;
+ for (;;) {
+ siginfo_t info = {};
+ // This wait will succeed if the child exits, or fail with EINTR if the
+ // alarm goes off first - a loose approximation to a timed wait.
+ int ret = waitid(P_PID, pid, &info, WEXITED);
+ if (ret >= 0 || errno != EINTR) {
+ EXPECT_EQ(ret, 0);
+ if (!killed) {
+ EXPECT_EQ(info.si_status, 0);
+ }
+ break;
+ }
+ unsigned int alarm_left = alarm(0);
+ if (alarm_left > 0) {
+ alarm(alarm_left);
+ } else {
+ kill(pid, SIGTERM);
+ killed = true;
+ }
+ }
+
+ alarm(0);
+ EXPECT_GT(timer.duration(), std::chrono::seconds(40));
+#else
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}
diff --git a/libmemunreachable/MemUnreachable.cpp b/libmemunreachable/MemUnreachable.cpp
index 5e062fd..24fdc7f 100644
--- a/libmemunreachable/MemUnreachable.cpp
+++ b/libmemunreachable/MemUnreachable.cpp
@@ -479,23 +479,6 @@
return oss.str();
}
-// Figure out the abi based on defined macros.
-#if defined(__arm__)
-#define ABI_STRING "arm"
-#elif defined(__aarch64__)
-#define ABI_STRING "arm64"
-#elif defined(__mips__) && !defined(__LP64__)
-#define ABI_STRING "mips"
-#elif defined(__mips__) && defined(__LP64__)
-#define ABI_STRING "mips64"
-#elif defined(__i386__)
-#define ABI_STRING "x86"
-#elif defined(__x86_64__)
-#define ABI_STRING "x86_64"
-#else
-#error "Unsupported ABI"
-#endif
-
std::string UnreachableMemoryInfo::ToString(bool log_contents) const {
std::ostringstream oss;
oss << " " << leak_bytes << " bytes in ";
diff --git a/libnativebridge/Android.bp b/libnativebridge/Android.bp
index 8b48a87..b3c42f0 100644
--- a/libnativebridge/Android.bp
+++ b/libnativebridge/Android.bp
@@ -11,7 +11,7 @@
host_supported: true,
srcs: ["native_bridge.cc"],
- shared_libs: ["liblog"],
+ shared_libs: ["liblog", "libbase"],
export_include_dirs=["include"],
diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc
index 02b4fe7..e24307a 100644
--- a/libnativebridge/native_bridge.cc
+++ b/libnativebridge/native_bridge.cc
@@ -28,6 +28,7 @@
#include <cstring>
+#include <android-base/macros.h>
#include <log/log.h>
namespace android {
@@ -243,29 +244,12 @@
}
}
-#if defined(__arm__)
-static const char* kRuntimeISA = "arm";
-#elif defined(__aarch64__)
-static const char* kRuntimeISA = "arm64";
-#elif defined(__mips__) && !defined(__LP64__)
-static const char* kRuntimeISA = "mips";
-#elif defined(__mips__) && defined(__LP64__)
-static const char* kRuntimeISA = "mips64";
-#elif defined(__i386__)
-static const char* kRuntimeISA = "x86";
-#elif defined(__x86_64__)
-static const char* kRuntimeISA = "x86_64";
-#else
-static const char* kRuntimeISA = "unknown";
-#endif
-
-
bool NeedsNativeBridge(const char* instruction_set) {
if (instruction_set == nullptr) {
ALOGE("Null instruction set in NeedsNativeBridge.");
return false;
}
- return strncmp(instruction_set, kRuntimeISA, strlen(kRuntimeISA) + 1) != 0;
+ return strncmp(instruction_set, ABI_STRING, strlen(ABI_STRING) + 1) != 0;
}
#ifdef __APPLE__
diff --git a/libnativebridge/tests/Android.mk b/libnativebridge/tests/Android.mk
index c1e65ff..b3861e0 100644
--- a/libnativebridge/tests/Android.mk
+++ b/libnativebridge/tests/Android.mk
@@ -29,6 +29,7 @@
shared_libraries := \
liblog \
+ libbase \
libnativebridge \
libnativebridge-dummy
diff --git a/libnativebridge/tests/NeedsNativeBridge_test.cpp b/libnativebridge/tests/NeedsNativeBridge_test.cpp
index 2067ed2..c8ff743 100644
--- a/libnativebridge/tests/NeedsNativeBridge_test.cpp
+++ b/libnativebridge/tests/NeedsNativeBridge_test.cpp
@@ -16,34 +16,20 @@
#include "NativeBridgeTest.h"
+#include <android-base/macros.h>
+
namespace android {
static const char* kISAs[] = { "arm", "arm64", "mips", "mips64", "x86", "x86_64", "random", "64arm",
"64_x86", "64_x86_64", "", "reallylongstringabcd", nullptr };
-#if defined(__arm__)
-static const char* kRuntimeISA = "arm";
-#elif defined(__aarch64__)
-static const char* kRuntimeISA = "arm64";
-#elif defined(__mips__) && !defined(__LP64__)
-static const char* kRuntimeISA = "mips";
-#elif defined(__mips__) && defined(__LP64__)
-static const char* kRuntimeISA = "mips64";
-#elif defined(__i386__)
-static const char* kRuntimeISA = "x86";
-#elif defined(__x86_64__)
-static const char* kRuntimeISA = "x86_64";
-#else
-static const char* kRuntimeISA = "unknown";
-#endif
-
TEST_F(NativeBridgeTest, NeedsNativeBridge) {
- EXPECT_EQ(false, NeedsNativeBridge(kRuntimeISA));
+ EXPECT_EQ(false, NeedsNativeBridge(ABI_STRING));
- const size_t kISACount = sizeof(kISAs)/sizeof(kISAs[0]);
- for (size_t i = 0; i < kISACount; i++) {
- EXPECT_EQ(kISAs[i] == nullptr ? false : strcmp(kISAs[i], kRuntimeISA) != 0,
- NeedsNativeBridge(kISAs[i]));
+ const size_t kISACount = sizeof(kISAs) / sizeof(kISAs[0]);
+ for (size_t i = 0; i < kISACount; i++) {
+ EXPECT_EQ(kISAs[i] == nullptr ? false : strcmp(kISAs[i], ABI_STRING) != 0,
+ NeedsNativeBridge(kISAs[i]));
}
}
diff --git a/libunwindstack/Maps.cpp b/libunwindstack/Maps.cpp
index 8a90423..5e1c0a2 100644
--- a/libunwindstack/Maps.cpp
+++ b/libunwindstack/Maps.cpp
@@ -25,6 +25,7 @@
#include <android-base/unique_fd.h>
+#include <cctype>
#include <memory>
#include <string>
#include <vector>
@@ -55,63 +56,151 @@
return nullptr;
}
-bool Maps::ParseLine(const char* line, MapInfo* map_info) {
- char permissions[5];
- int name_pos;
- // Linux /proc/<pid>/maps lines:
+// Assumes that line does not end in '\n'.
+static bool InternalParseLine(const char* line, MapInfo* map_info) {
+ // Do not use a sscanf implementation since it is not performant.
+
+ // Example linux /proc/<pid>/maps lines:
// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so
- if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %4s %" SCNx64 " %*x:%*x %*d %n", &map_info->start,
- &map_info->end, permissions, &map_info->offset, &name_pos) != 4) {
+ char* str;
+ const char* old_str = line;
+ map_info->start = strtoul(old_str, &str, 16);
+ if (old_str == str || *str++ != '-') {
return false;
}
- map_info->flags = PROT_NONE;
- if (permissions[0] == 'r') {
+
+ old_str = str;
+ map_info->end = strtoul(old_str, &str, 16);
+ if (old_str == str || !std::isspace(*str++)) {
+ return false;
+ }
+
+ while (std::isspace(*str)) {
+ str++;
+ }
+
+ // Parse permissions data.
+ if (*str == '\0') {
+ return false;
+ }
+ map_info->flags = 0;
+ if (*str == 'r') {
map_info->flags |= PROT_READ;
+ } else if (*str != '-') {
+ return false;
}
- if (permissions[1] == 'w') {
+ str++;
+ if (*str == 'w') {
map_info->flags |= PROT_WRITE;
+ } else if (*str != '-') {
+ return false;
}
- if (permissions[2] == 'x') {
+ str++;
+ if (*str == 'x') {
map_info->flags |= PROT_EXEC;
+ } else if (*str != '-') {
+ return false;
+ }
+ str++;
+ if (*str != 'p' && *str != 's') {
+ return false;
+ }
+ str++;
+
+ if (!std::isspace(*str++)) {
+ return false;
}
- if (line[name_pos] != '\0') {
- map_info->name = &line[name_pos];
- size_t length = map_info->name.length() - 1;
- if (map_info->name[length] == '\n') {
- map_info->name.erase(length);
- }
-
- // Mark a device map in /dev/and not in /dev/ashmem/ specially.
- if (map_info->name.substr(0, 5) == "/dev/" && map_info->name.substr(5, 7) != "ashmem/") {
- map_info->flags |= MAPS_FLAGS_DEVICE_MAP;
- }
+ old_str = str;
+ map_info->offset = strtoul(old_str, &str, 16);
+ if (old_str == str || !std::isspace(*str)) {
+ return false;
}
+ // Ignore the 00:00 values.
+ old_str = str;
+ (void)strtoul(old_str, &str, 16);
+ if (old_str == str || *str++ != ':') {
+ return false;
+ }
+ if (std::isspace(*str)) {
+ return false;
+ }
+
+ // Skip the inode.
+ old_str = str;
+ (void)strtoul(str, &str, 16);
+ if (old_str == str || !std::isspace(*str++)) {
+ return false;
+ }
+
+ // Skip decimal digit.
+ old_str = str;
+ (void)strtoul(old_str, &str, 10);
+ if (old_str == str || (!std::isspace(*str) && *str != '\0')) {
+ return false;
+ }
+
+ while (std::isspace(*str)) {
+ str++;
+ }
+ if (*str == '\0') {
+ map_info->name = str;
+ return true;
+ }
+
+ // Save the name data.
+ map_info->name = str;
+
+ // Mark a device map in /dev/ and not in /dev/ashmem/ specially.
+ if (map_info->name.substr(0, 5) == "/dev/" && map_info->name.substr(5, 7) != "ashmem/") {
+ map_info->flags |= MAPS_FLAGS_DEVICE_MAP;
+ }
return true;
}
bool Maps::Parse() {
- std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(GetMapsFile().c_str(), "re"), fclose);
- if (!fp) {
+ int fd = open(GetMapsFile().c_str(), O_RDONLY | O_CLOEXEC);
+ if (fd == -1) {
return false;
}
- bool valid = true;
- char* line = nullptr;
- size_t line_len;
- while (getline(&line, &line_len, fp.get()) > 0) {
- MapInfo map_info;
- if (!ParseLine(line, &map_info)) {
- valid = false;
+ bool return_value = true;
+ char buffer[2048];
+ size_t leftover = 0;
+ while (true) {
+ ssize_t bytes = read(fd, &buffer[leftover], 2048 - leftover);
+ if (bytes == -1) {
+ return_value = false;
break;
}
+ if (bytes == 0) {
+ break;
+ }
+ bytes += leftover;
+ char* line = buffer;
+ while (bytes > 0) {
+ char* newline = static_cast<char*>(memchr(line, '\n', bytes));
+ if (newline == nullptr) {
+ memmove(buffer, line, bytes);
+ break;
+ }
+ *newline = '\0';
- maps_.push_back(map_info);
+ MapInfo map_info;
+ if (!InternalParseLine(line, &map_info)) {
+ return_value = false;
+ break;
+ }
+ maps_.push_back(map_info);
+
+ bytes -= newline - line + 1;
+ line = newline + 1;
+ }
+ leftover = bytes;
}
- free(line);
-
- return valid;
+ close(fd);
+ return return_value;
}
Maps::~Maps() {
@@ -129,12 +218,12 @@
if (end_of_line == nullptr) {
line = start_of_line;
} else {
- end_of_line++;
line = std::string(start_of_line, end_of_line - start_of_line);
+ end_of_line++;
}
MapInfo map_info;
- if (!ParseLine(line.c_str(), &map_info)) {
+ if (!InternalParseLine(line.c_str(), &map_info)) {
return false;
}
maps_.push_back(map_info);
diff --git a/libunwindstack/include/unwindstack/Maps.h b/libunwindstack/include/unwindstack/Maps.h
index 0b02739..22122a9 100644
--- a/libunwindstack/include/unwindstack/Maps.h
+++ b/libunwindstack/include/unwindstack/Maps.h
@@ -38,8 +38,6 @@
MapInfo* Find(uint64_t pc);
- bool ParseLine(const char* line, MapInfo* map_info);
-
virtual bool Parse();
virtual const std::string GetMapsFile() const { return ""; }
@@ -54,6 +52,11 @@
size_t Total() { return maps_.size(); }
+ MapInfo* Get(size_t index) {
+ if (index >= maps_.size()) return nullptr;
+ return &maps_[index];
+ }
+
protected:
std::vector<MapInfo> maps_;
};
diff --git a/libunwindstack/tests/MapsTest.cpp b/libunwindstack/tests/MapsTest.cpp
index 9430cf3..2d15a4e 100644
--- a/libunwindstack/tests/MapsTest.cpp
+++ b/libunwindstack/tests/MapsTest.cpp
@@ -14,9 +14,11 @@
* limitations under the License.
*/
+#include <inttypes.h>
#include <sys/mman.h>
#include <android-base/file.h>
+#include <android-base/stringprintf.h>
#include <android-base/test_utils.h>
#include <gtest/gtest.h>
@@ -24,13 +26,116 @@
namespace unwindstack {
+static void VerifyLine(std::string line, MapInfo* info) {
+ BufferMaps maps(line.c_str());
+
+ if (info == nullptr) {
+ ASSERT_FALSE(maps.Parse()) << "Failed on: " + line;
+ } else {
+ ASSERT_TRUE(maps.Parse()) << "Failed on: " + line;
+ MapInfo* element = maps.Get(0);
+ ASSERT_TRUE(element != nullptr) << "Failed on: " + line;
+ *info = *element;
+ }
+}
+
+TEST(MapsTest, verify_parse_line) {
+ MapInfo info;
+
+ VerifyLine("01-02 rwxp 03 04:05 06\n", &info);
+ EXPECT_EQ(1U, info.start);
+ EXPECT_EQ(2U, info.end);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info.flags);
+ EXPECT_EQ(3U, info.offset);
+ EXPECT_EQ("", info.name);
+
+ VerifyLine("0a-0b ---s 0c 0d:0e 06 /fake/name\n", &info);
+ EXPECT_EQ(0xaU, info.start);
+ EXPECT_EQ(0xbU, info.end);
+ EXPECT_EQ(0U, info.flags);
+ EXPECT_EQ(0xcU, info.offset);
+ EXPECT_EQ("/fake/name", info.name);
+
+ VerifyLine("01-02 rwxp 03 04:05 06 /fake/name/again\n", &info);
+ EXPECT_EQ(1U, info.start);
+ EXPECT_EQ(2U, info.end);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info.flags);
+ EXPECT_EQ(3U, info.offset);
+ EXPECT_EQ("/fake/name/again", info.name);
+
+ VerifyLine("-00 rwxp 00 00:00 0\n", nullptr);
+ VerifyLine("00- rwxp 00 00:00 0\n", nullptr);
+ VerifyLine("00-00 rwxp 00 :00 0\n", nullptr);
+ VerifyLine("00-00 rwxp 00 00:00 \n", nullptr);
+ VerifyLine("x-00 rwxp 00 00:00 0\n", nullptr);
+ VerifyLine("00 -00 rwxp 00 00:00 0\n", nullptr);
+ VerifyLine("00-x rwxp 00 00:00 0\n", nullptr);
+ VerifyLine("00-x rwxp 00 00:00 0\n", nullptr);
+ VerifyLine("00-00x rwxp 00 00:00 0\n", nullptr);
+ VerifyLine("00-00 rwxp0 00 00:00 0\n", nullptr);
+ VerifyLine("00-00 rwxp0 00 00:00 0\n", nullptr);
+ VerifyLine("00-00 rwp 00 00:00 0\n", nullptr);
+ VerifyLine("00-00 rwxp 0000:00 0\n", nullptr);
+ VerifyLine("00-00 rwxp 00 00 :00 0\n", nullptr);
+ VerifyLine("00-00 rwxp 00 00: 00 0\n", nullptr);
+ VerifyLine("00-00 rwxp 00 00:000\n", nullptr);
+ VerifyLine("00-00 rwxp 00 00:00 0/fake\n", nullptr);
+ VerifyLine("00-00 xxxx 00 00:00 0 /fake\n", nullptr);
+ VerifyLine("00-00 ywxp 00 00:00 0 /fake\n", nullptr);
+ VerifyLine("00-00 ryxp 00 00:00 0 /fake\n", nullptr);
+ VerifyLine("00-00 rwyp 00 00:00 0 /fake\n", nullptr);
+ VerifyLine("00-00 rwx- 00 00:00 0 /fake\n", nullptr);
+ VerifyLine("0\n", nullptr);
+ VerifyLine("00\n", nullptr);
+ VerifyLine("00-\n", nullptr);
+ VerifyLine("00-0\n", nullptr);
+ VerifyLine("00-00\n", nullptr);
+ VerifyLine("00-00 \n", nullptr);
+ VerifyLine("00-00 -\n", nullptr);
+ VerifyLine("00-00 r\n", nullptr);
+ VerifyLine("00-00 --\n", nullptr);
+ VerifyLine("00-00 rw\n", nullptr);
+ VerifyLine("00-00 ---\n", nullptr);
+ VerifyLine("00-00 rwx\n", nullptr);
+ VerifyLine("00-00 ---s\n", nullptr);
+ VerifyLine("00-00 ---p\n", nullptr);
+ VerifyLine("00-00 ---s 0\n", nullptr);
+ VerifyLine("00-00 ---p 0 \n", nullptr);
+ VerifyLine("00-00 ---p 0 0\n", nullptr);
+ VerifyLine("00-00 ---p 0 0:\n", nullptr);
+ VerifyLine("00-00 ---p 0 0:0\n", nullptr);
+ VerifyLine("00-00 ---p 0 0:0 \n", nullptr);
+
+ // Line to verify that the parser will detect a completely malformed line
+ // properly.
+ VerifyLine("7ffff7dda000-7ffff7dfd7ffff7ff3000-7ffff7ff4000 ---p 0000f000 fc:02 44171565\n",
+ nullptr);
+}
+
+TEST(MapsTest, verify_large_values) {
+ MapInfo info;
+#if defined(__LP64__)
+ VerifyLine("fabcdef012345678-f12345678abcdef8 rwxp f0b0d0f010305070 00:00 0\n", &info);
+ EXPECT_EQ(0xfabcdef012345678UL, info.start);
+ EXPECT_EQ(0xf12345678abcdef8UL, info.end);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info.flags);
+ EXPECT_EQ(0xf0b0d0f010305070UL, info.offset);
+#else
+ VerifyLine("f2345678-fabcdef8 rwxp f0305070 00:00 0\n", &info);
+ EXPECT_EQ(0xf2345678UL, info.start);
+ EXPECT_EQ(0xfabcdef8UL, info.end);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info.flags);
+ EXPECT_EQ(0xf0305070UL, info.offset);
+#endif
+}
+
TEST(MapsTest, parse_permissions) {
BufferMaps maps(
- "1000-2000 ---- 00000000 00:00 0\n"
- "2000-3000 r--- 00000000 00:00 0\n"
- "3000-4000 -w-- 00000000 00:00 0\n"
- "4000-5000 --x- 00000000 00:00 0\n"
- "5000-6000 rwx- 00000000 00:00 0\n");
+ "1000-2000 ---s 00000000 00:00 0\n"
+ "2000-3000 r--s 00000000 00:00 0\n"
+ "3000-4000 -w-s 00000000 00:00 0\n"
+ "4000-5000 --xp 00000000 00:00 0\n"
+ "5000-6000 rwxp 00000000 00:00 0\n");
ASSERT_TRUE(maps.Parse());
ASSERT_EQ(5U, maps.Total());
@@ -70,28 +175,28 @@
TEST(MapsTest, parse_name) {
BufferMaps maps(
- "720b29b000-720b29e000 rw-p 00000000 00:00 0\n"
- "720b29e000-720b29f000 rw-p 00000000 00:00 0 /system/lib/fake.so\n"
- "720b29f000-720b2a0000 rw-p 00000000 00:00 0");
+ "7b29b000-7b29e000 rw-p 00000000 00:00 0\n"
+ "7b29e000-7b29f000 rw-p 00000000 00:00 0 /system/lib/fake.so\n"
+ "7b29f000-7b2a0000 rw-p 00000000 00:00 0");
ASSERT_TRUE(maps.Parse());
ASSERT_EQ(3U, maps.Total());
auto it = maps.begin();
ASSERT_EQ("", it->name);
- ASSERT_EQ(0x720b29b000U, it->start);
- ASSERT_EQ(0x720b29e000U, it->end);
+ ASSERT_EQ(0x7b29b000U, it->start);
+ ASSERT_EQ(0x7b29e000U, it->end);
ASSERT_EQ(0U, it->offset);
ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
++it;
ASSERT_EQ("/system/lib/fake.so", it->name);
- ASSERT_EQ(0x720b29e000U, it->start);
- ASSERT_EQ(0x720b29f000U, it->end);
+ ASSERT_EQ(0x7b29e000U, it->start);
+ ASSERT_EQ(0x7b29f000U, it->end);
ASSERT_EQ(0U, it->offset);
ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
++it;
ASSERT_EQ("", it->name);
- ASSERT_EQ(0x720b29f000U, it->start);
- ASSERT_EQ(0x720b2a0000U, it->end);
+ ASSERT_EQ(0x7b29f000U, it->start);
+ ASSERT_EQ(0x7b2a0000U, it->end);
ASSERT_EQ(0U, it->offset);
ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
++it;
@@ -149,9 +254,9 @@
ASSERT_TRUE(tf.fd != -1);
ASSERT_TRUE(
- android::base::WriteStringToFile("720b29b000-720b29e000 r-xp a0000000 00:00 0 /fake.so\n"
- "720b2b0000-720b2e0000 r-xp b0000000 00:00 0 /fake2.so\n"
- "720b2e0000-720b2f0000 r-xp c0000000 00:00 0 /fake3.so\n",
+ android::base::WriteStringToFile("7b29b000-7b29e000 r-xp a0000000 00:00 0 /fake.so\n"
+ "7b2b0000-7b2e0000 r-xp b0000000 00:00 0 /fake2.so\n"
+ "7b2e0000-7b2f0000 r-xp c0000000 00:00 0 /fake3.so\n",
tf.path, 0660, getuid(), getgid()));
FileMaps maps(tf.path);
@@ -159,20 +264,20 @@
ASSERT_TRUE(maps.Parse());
ASSERT_EQ(3U, maps.Total());
auto it = maps.begin();
- ASSERT_EQ(0x720b29b000U, it->start);
- ASSERT_EQ(0x720b29e000U, it->end);
+ ASSERT_EQ(0x7b29b000U, it->start);
+ ASSERT_EQ(0x7b29e000U, it->end);
ASSERT_EQ(0xa0000000U, it->offset);
ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
ASSERT_EQ("/fake.so", it->name);
++it;
- ASSERT_EQ(0x720b2b0000U, it->start);
- ASSERT_EQ(0x720b2e0000U, it->end);
+ ASSERT_EQ(0x7b2b0000U, it->start);
+ ASSERT_EQ(0x7b2e0000U, it->end);
ASSERT_EQ(0xb0000000U, it->offset);
ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
ASSERT_EQ("/fake2.so", it->name);
++it;
- ASSERT_EQ(0x720b2e0000U, it->start);
- ASSERT_EQ(0x720b2f0000U, it->end);
+ ASSERT_EQ(0x7b2e0000U, it->start);
+ ASSERT_EQ(0x7b2f0000U, it->end);
ASSERT_EQ(0xc0000000U, it->offset);
ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
ASSERT_EQ("/fake3.so", it->name);
@@ -180,6 +285,163 @@
ASSERT_EQ(it, maps.end());
}
+TEST(MapsTest, file_no_map_name) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ ASSERT_TRUE(
+ android::base::WriteStringToFile("7b29b000-7b29e000 r-xp a0000000 00:00 0\n"
+ "7b2b0000-7b2e0000 r-xp b0000000 00:00 0 /fake2.so\n"
+ "7b2e0000-7b2f0000 r-xp c0000000 00:00 0 \n",
+ tf.path, 0660, getuid(), getgid()));
+
+ FileMaps maps(tf.path);
+
+ ASSERT_TRUE(maps.Parse());
+ ASSERT_EQ(3U, maps.Total());
+ auto it = maps.begin();
+ ASSERT_EQ(0x7b29b000U, it->start);
+ ASSERT_EQ(0x7b29e000U, it->end);
+ ASSERT_EQ(0xa0000000U, it->offset);
+ ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
+ ASSERT_EQ("", it->name);
+ ++it;
+ ASSERT_EQ(0x7b2b0000U, it->start);
+ ASSERT_EQ(0x7b2e0000U, it->end);
+ ASSERT_EQ(0xb0000000U, it->offset);
+ ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
+ ASSERT_EQ("/fake2.so", it->name);
+ ++it;
+ ASSERT_EQ(0x7b2e0000U, it->start);
+ ASSERT_EQ(0x7b2f0000U, it->end);
+ ASSERT_EQ(0xc0000000U, it->offset);
+ ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
+ ASSERT_EQ("", it->name);
+ ++it;
+ ASSERT_EQ(it, maps.end());
+}
+
+// Verify that a file that crosses a buffer is parsed correctly.
+static std::string CreateEntry(size_t index) {
+ return android::base::StringPrintf("%08zx-%08zx rwxp 0000 00:00 0\n", index * 4096,
+ (index + 1) * 4096);
+}
+
+TEST(MapsTest, file_buffer_cross) {
+ constexpr size_t kBufferSize = 2048;
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ // Compute how many to add in the first buffer.
+ size_t entry_len = CreateEntry(0).size();
+ size_t index;
+ std::string file_data;
+ for (index = 0; index < kBufferSize / entry_len; index++) {
+ file_data += CreateEntry(index);
+ }
+ // Add a long name to make sure that the first buffer does not contain a
+ // complete line.
+ // Remove the last newline.
+ size_t extra = 0;
+ size_t leftover = kBufferSize % entry_len;
+ size_t overlap1_index = 0;
+ std::string overlap1_name;
+ if (leftover == 0) {
+ // Exact match, add a long name to cross over the value.
+ overlap1_name = "/fake/name/is/long/on/purpose";
+ file_data.erase(file_data.size() - 1);
+ file_data += ' ' + overlap1_name + '\n';
+ extra = entry_len + overlap1_name.size() + 1;
+ overlap1_index = index;
+ }
+
+ // Compute how many need to go in to hit the buffer boundary exactly.
+ size_t bytes_left_in_buffer = kBufferSize - extra;
+ size_t entries_to_add = bytes_left_in_buffer / entry_len + index;
+ for (; index < entries_to_add; index++) {
+ file_data += CreateEntry(index);
+ }
+
+ // Now figure out how many bytes to add to get exactly to the buffer boundary.
+ leftover = bytes_left_in_buffer % entry_len;
+ std::string overlap2_name;
+ size_t overlap2_index = 0;
+ if (leftover != 0) {
+ file_data.erase(file_data.size() - 1);
+ file_data += ' ';
+ overlap2_name = std::string(leftover - 1, 'x');
+ file_data += overlap2_name + '\n';
+ overlap2_index = index - 1;
+ }
+
+ // Now add a few entries on the next page.
+ for (size_t start = index; index < start + 10; index++) {
+ file_data += CreateEntry(index);
+ }
+
+ ASSERT_TRUE(android::base::WriteStringToFile(file_data, tf.path, 0660, getuid(), getgid()));
+
+ FileMaps maps(tf.path);
+ ASSERT_TRUE(maps.Parse());
+ EXPECT_EQ(index, maps.Total());
+ // Verify all of the maps.
+ for (size_t i = 0; i < index; i++) {
+ MapInfo* info = maps.Get(i);
+ ASSERT_TRUE(info != nullptr) << "Failed verifying index " + std::to_string(i);
+ EXPECT_EQ(i * 4096, info->start) << "Failed verifying index " + std::to_string(i);
+ EXPECT_EQ((i + 1) * 4096, info->end) << "Failed verifying index " + std::to_string(i);
+ EXPECT_EQ(0U, info->offset) << "Failed verifying index " + std::to_string(i);
+ if (overlap1_index != 0 && i == overlap1_index) {
+ EXPECT_EQ(overlap1_name, info->name) << "Failed verifying overlap1 name " + std::to_string(i);
+ } else if (overlap2_index != 0 && i == overlap2_index) {
+ EXPECT_EQ(overlap2_name, info->name) << "Failed verifying overlap2 name " + std::to_string(i);
+ } else {
+ EXPECT_EQ("", info->name) << "Failed verifying index " + std::to_string(i);
+ }
+ }
+}
+
+TEST(MapsTest, file_should_fail) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "7ffff7dda000-7ffff7dfd7ffff7ff3000-7ffff7ff4000 ---p 0000f000 fc:02 44171565\n", tf.path,
+ 0660, getuid(), getgid()));
+
+ FileMaps maps(tf.path);
+
+ ASSERT_FALSE(maps.Parse());
+}
+
+// Create a maps file that is extremely large.
+TEST(MapsTest, large_file) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ std::string file_data;
+ uint64_t start = 0x700000;
+ for (size_t i = 0; i < 5000; i++) {
+ file_data +=
+ android::base::StringPrintf("%" PRIx64 "-%" PRIx64 " r-xp 1000 00:0 0 /fake%zu.so\n",
+ start + i * 4096, start + (i + 1) * 4096, i);
+ }
+
+ ASSERT_TRUE(android::base::WriteStringToFile(file_data, tf.path, 0660, getuid(), getgid()));
+
+ FileMaps maps(tf.path);
+
+ ASSERT_TRUE(maps.Parse());
+ ASSERT_EQ(5000U, maps.Total());
+ for (size_t i = 0; i < 5000; i++) {
+ MapInfo* info = maps.Get(i);
+ ASSERT_EQ(start + i * 4096, info->start) << "Failed at map " + std::to_string(i);
+ ASSERT_EQ(start + (i + 1) * 4096, info->end) << "Failed at map " + std::to_string(i);
+ std::string name = "/fake" + std::to_string(i) + ".so";
+ ASSERT_EQ(name, info->name) << "Failed at map " + std::to_string(i);
+ }
+}
+
TEST(MapsTest, find) {
BufferMaps maps(
"1000-2000 r--p 00000010 00:00 0 /system/lib/fake1.so\n"
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 7d293ef..adcde81 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -44,6 +44,10 @@
cc_library {
name: "libutils",
vendor_available: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
host_supported: true,
srcs: [
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index ee38d1c..cfcbaa5 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -25,7 +25,11 @@
#include <sys/uio.h>
#include <syslog.h>
+#include <fstream>
+#include <sstream>
+
#include <android-base/macros.h>
+#include <log/log_properties.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
@@ -138,6 +142,71 @@
return true;
}
+static inline bool hasMetadata(char* str, int str_len) {
+ // need to check and see if str already contains bug metadata from
+ // possibility of stuttering if log audit crashes and then reloads kernel
+ // messages. Kernel denials that contain metadata will either end in
+ // "b/[0-9]+$" or "b/[0-9]+ duplicate messages suppressed$" which will put
+ // a '/' character at either 9 or 39 indices away from the end of the str.
+ return str_len >= 39 &&
+ (str[str_len - 9] == '/' || str[str_len - 39] == '/');
+}
+
+std::map<std::string, std::string> LogAudit::populateDenialMap() {
+ std::ifstream bug_file("/system/etc/selinux/selinux_denial_metadata");
+ std::string line;
+ // allocate a map for the static map pointer in logParse to keep track of,
+ // this function only runs once
+ std::map<std::string, std::string> denial_to_bug;
+ if (bug_file.good()) {
+ std::string scontext;
+ std::string tcontext;
+ std::string tclass;
+ std::string bug_num;
+ while (std::getline(bug_file, line)) {
+ std::stringstream split_line(line);
+ split_line >> scontext >> tcontext >> tclass >> bug_num;
+ denial_to_bug.emplace(scontext + tcontext + tclass, bug_num);
+ }
+ }
+ return denial_to_bug;
+}
+
+std::string LogAudit::denialParse(const std::string& denial, char terminator,
+ const std::string& search_term) {
+ size_t start_index = denial.find(search_term);
+ if (start_index != std::string::npos) {
+ start_index += search_term.length();
+ return denial.substr(
+ start_index, denial.find(terminator, start_index) - start_index);
+ }
+ return "";
+}
+
+void LogAudit::logParse(const std::string& string, std::string* bug_num) {
+ if (!__android_log_is_debuggable()) {
+ bug_num->assign("");
+ return;
+ }
+ static std::map<std::string, std::string> denial_to_bug =
+ populateDenialMap();
+ std::string scontext = denialParse(string, ':', "scontext=u:object_r:");
+ std::string tcontext = denialParse(string, ':', "tcontext=u:object_r:");
+ std::string tclass = denialParse(string, ' ', "tclass=");
+ if (scontext.empty()) {
+ scontext = denialParse(string, ':', "scontext=u:r:");
+ }
+ if (tcontext.empty()) {
+ tcontext = denialParse(string, ':', "tcontext=u:r:");
+ }
+ auto search = denial_to_bug.find(scontext + tcontext + tclass);
+ if (search != denial_to_bug.end()) {
+ bug_num->assign(" b/" + search->second);
+ } else {
+ bug_num->assign("");
+ }
+}
+
int LogAudit::logPrint(const char* fmt, ...) {
if (fmt == NULL) {
return -EINVAL;
@@ -153,7 +222,6 @@
if (rc < 0) {
return rc;
}
-
char* cp;
// Work around kernels missing
// https://github.com/torvalds/linux/commit/b8f89caafeb55fba75b74bea25adc4e4cd91be67
@@ -165,10 +233,10 @@
while ((cp = strstr(str, " "))) {
memmove(cp, cp + 1, strlen(cp + 1) + 1);
}
-
bool info = strstr(str, " permissive=1") || strstr(str, " policy loaded ");
+ static std::string bug_metadata;
if ((fdDmesg >= 0) && initialized) {
- struct iovec iov[3];
+ struct iovec iov[4];
static const char log_info[] = { KMSG_PRIORITY(LOG_INFO) };
static const char log_warning[] = { KMSG_PRIORITY(LOG_WARNING) };
static const char newline[] = "\n";
@@ -197,19 +265,20 @@
}
if (!skip) {
static const char resume[] = " duplicate messages suppressed\n";
-
iov[0].iov_base = last_info ? const_cast<char*>(log_info)
: const_cast<char*>(log_warning);
iov[0].iov_len =
last_info ? sizeof(log_info) : sizeof(log_warning);
iov[1].iov_base = last_str;
iov[1].iov_len = strlen(last_str);
+ iov[2].iov_base = const_cast<char*>(bug_metadata.c_str());
+ iov[2].iov_len = bug_metadata.length();
if (count > 1) {
- iov[2].iov_base = const_cast<char*>(resume);
- iov[2].iov_len = strlen(resume);
+ iov[3].iov_base = const_cast<char*>(resume);
+ iov[3].iov_len = strlen(resume);
} else {
- iov[2].iov_base = const_cast<char*>(newline);
- iov[2].iov_len = strlen(newline);
+ iov[3].iov_base = const_cast<char*>(newline);
+ iov[3].iov_len = strlen(newline);
}
writev(fdDmesg, iov, arraysize(iov));
@@ -223,13 +292,16 @@
last_info = info;
}
if (count == 0) {
+ logParse(str, &bug_metadata);
iov[0].iov_base = info ? const_cast<char*>(log_info)
: const_cast<char*>(log_warning);
iov[0].iov_len = info ? sizeof(log_info) : sizeof(log_warning);
iov[1].iov_base = str;
iov[1].iov_len = strlen(str);
- iov[2].iov_base = const_cast<char*>(newline);
- iov[2].iov_len = strlen(newline);
+ iov[2].iov_base = const_cast<char*>(bug_metadata.c_str());
+ iov[2].iov_len = bug_metadata.length();
+ iov[3].iov_base = const_cast<char*>(newline);
+ iov[3].iov_len = strlen(newline);
writev(fdDmesg, iov, arraysize(iov));
}
@@ -285,24 +357,32 @@
// log to events
- size_t l = strnlen(str, LOGGER_ENTRY_MAX_PAYLOAD);
- size_t n = l + sizeof(android_log_event_string_t);
+ size_t str_len = strnlen(str, LOGGER_ENTRY_MAX_PAYLOAD);
+ if (((fdDmesg < 0) || !initialized) && !hasMetadata(str, str_len))
+ logParse(str, &bug_metadata);
+ str_len = (str_len + bug_metadata.length() <= LOGGER_ENTRY_MAX_PAYLOAD)
+ ? str_len + bug_metadata.length()
+ : LOGGER_ENTRY_MAX_PAYLOAD;
+ size_t message_len = str_len + sizeof(android_log_event_string_t);
bool notify = false;
if (events) { // begin scope for event buffer
- uint32_t buffer[(n + sizeof(uint32_t) - 1) / sizeof(uint32_t)];
+ uint32_t buffer[(message_len + sizeof(uint32_t) - 1) / sizeof(uint32_t)];
android_log_event_string_t* event =
reinterpret_cast<android_log_event_string_t*>(buffer);
event->header.tag = htole32(AUDITD_LOG_TAG);
event->type = EVENT_TYPE_STRING;
- event->length = htole32(l);
- memcpy(event->data, str, l);
+ event->length = htole32(message_len);
+ memcpy(event->data, str, str_len - bug_metadata.length());
+ memcpy(event->data + str_len - bug_metadata.length(),
+ bug_metadata.c_str(), bug_metadata.length());
- rc = logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid,
- reinterpret_cast<char*>(event),
- (n <= USHRT_MAX) ? (unsigned short)n : USHRT_MAX);
+ rc = logbuf->log(
+ LOG_ID_EVENTS, now, uid, pid, tid, reinterpret_cast<char*>(event),
+ (message_len <= USHRT_MAX) ? (unsigned short)message_len
+ : USHRT_MAX);
if (rc >= 0) {
notify = true;
}
@@ -333,28 +413,31 @@
const char* ecomm = strchr(comm, '"');
if (ecomm) {
++ecomm;
- l = ecomm - comm;
+ str_len = ecomm - comm;
} else {
- l = strlen(comm) + 1;
+ str_len = strlen(comm) + 1;
ecomm = "";
}
- size_t b = estr - str;
- if (b > LOGGER_ENTRY_MAX_PAYLOAD) {
- b = LOGGER_ENTRY_MAX_PAYLOAD;
+ size_t prefix_len = estr - str;
+ if (prefix_len > LOGGER_ENTRY_MAX_PAYLOAD) {
+ prefix_len = LOGGER_ENTRY_MAX_PAYLOAD;
}
- size_t e = strnlen(ecomm, LOGGER_ENTRY_MAX_PAYLOAD - b);
- n = b + e + l + 2;
+ size_t suffix_len = strnlen(ecomm, LOGGER_ENTRY_MAX_PAYLOAD - prefix_len);
+ message_len = str_len + prefix_len + suffix_len + bug_metadata.length() + 2;
if (main) { // begin scope for main buffer
- char newstr[n];
+ char newstr[message_len];
*newstr = info ? ANDROID_LOG_INFO : ANDROID_LOG_WARN;
- strlcpy(newstr + 1, comm, l);
- strncpy(newstr + 1 + l, str, b);
- strncpy(newstr + 1 + l + b, ecomm, e);
+ strlcpy(newstr + 1, comm, str_len);
+ strncpy(newstr + 1 + str_len, str, prefix_len);
+ strncpy(newstr + 1 + str_len + prefix_len, ecomm, suffix_len);
+ strncpy(newstr + 1 + str_len + prefix_len + suffix_len,
+ bug_metadata.c_str(), bug_metadata.length());
rc = logbuf->log(LOG_ID_MAIN, now, uid, pid, tid, newstr,
- (n <= USHRT_MAX) ? (unsigned short)n : USHRT_MAX);
+ (message_len <= USHRT_MAX) ? (unsigned short)message_len
+ : USHRT_MAX);
if (rc >= 0) {
notify = true;
@@ -368,7 +451,7 @@
if (notify) {
reader->notifyNewLog();
if (rc < 0) {
- rc = n;
+ rc = message_len;
}
}
diff --git a/logd/LogAudit.h b/logd/LogAudit.h
index 5947819..2bd02d4 100644
--- a/logd/LogAudit.h
+++ b/logd/LogAudit.h
@@ -17,6 +17,7 @@
#ifndef _LOGD_LOG_AUDIT_H__
#define _LOGD_LOG_AUDIT_H__
+#include <map>
#include <queue>
#include <sysutils/SocketListener.h>
@@ -50,6 +51,10 @@
private:
static int getLogSocket();
+ std::map<std::string, std::string> populateDenialMap();
+ std::string denialParse(const std::string& denial, char terminator,
+ const std::string& search_term);
+ void logParse(const std::string& string, std::string* bug_num);
int logPrint(const char* fmt, ...)
__attribute__((__format__(__printf__, 2, 3)));
};
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 4397b14..8ee5ea1 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -646,16 +646,20 @@
recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
}
- alarm_timeout =
- alarm((old_alarm <= 0) ? old_alarm
- : (old_alarm > (1 + 3 - alarm_wrap))
- ? old_alarm - 3 + alarm_wrap
- : 2);
+ if (old_alarm > 0) {
+ unsigned int time_spent = 3 - alarm_wrap;
+ if (old_alarm > time_spent + 1) {
+ old_alarm -= time_spent;
+ } else {
+ old_alarm = 2;
+ }
+ }
+ alarm_timeout = alarm(old_alarm);
sigaction(SIGALRM, &old_sigaction, nullptr);
close(fd);
- if (!content_wrap && !alarm_wrap && content_timeout && alarm_timeout) {
+ if (content_wrap && alarm_wrap && content_timeout && alarm_timeout) {
break;
}
}
@@ -710,8 +714,8 @@
// A few tries to get it right just in case wrap kicks in due to
// content providers being active during the test.
int i = 5;
- log_time now(android_log_clockid());
- now.tv_sec -= 30; // reach back a moderate period of time
+ log_time start(android_log_clockid());
+ start.tv_sec -= 30; // reach back a moderate period of time
while (--i) {
int fd = socket_local_client("logdr", ANDROID_SOCKET_NAMESPACE_RESERVED,
@@ -726,7 +730,7 @@
std::string ask = android::base::StringPrintf(
"dumpAndClose lids=0,1,2,3,4,5 timeout=6 start=%" PRIu32
".%09" PRIu32,
- now.tv_sec, now.tv_nsec);
+ start.tv_sec, start.tv_nsec);
struct sigaction ignore, old_sigaction;
memset(&ignore, 0, sizeof(ignore));
@@ -756,11 +760,15 @@
recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
}
- alarm_timeout =
- alarm((old_alarm <= 0) ? old_alarm
- : (old_alarm > (1 + 3 - alarm_wrap))
- ? old_alarm - 3 + alarm_wrap
- : 2);
+ if (old_alarm > 0) {
+ unsigned int time_spent = 3 - alarm_wrap;
+ if (old_alarm > time_spent + 1) {
+ old_alarm -= time_spent;
+ } else {
+ old_alarm = 2;
+ }
+ }
+ alarm_timeout = alarm(old_alarm);
sigaction(SIGALRM, &old_sigaction, nullptr);
close(fd);
@@ -773,23 +781,23 @@
// active _or_ inactive during the test.
if (content_timeout) {
log_time msg(msg_timeout.entry.sec, msg_timeout.entry.nsec);
- if (msg < now) {
+ if (msg < start) {
fprintf(stderr, "%u.%09u < %u.%09u\n", msg_timeout.entry.sec,
- msg_timeout.entry.nsec, (unsigned)now.tv_sec,
- (unsigned)now.tv_nsec);
+ msg_timeout.entry.nsec, (unsigned)start.tv_sec,
+ (unsigned)start.tv_nsec);
_exit(-1);
}
- if (msg > now) {
- now = msg;
- now.tv_sec += 30;
- msg = log_time(android_log_clockid());
- if (now > msg) {
- now = msg;
- --now.tv_sec;
+ if (msg > start) {
+ start = msg;
+ start.tv_sec += 30;
+ log_time now = log_time(android_log_clockid());
+ if (start > now) {
+ start = now;
+ --start.tv_sec;
}
}
} else {
- now.tv_sec -= 120; // inactive, reach further back!
+ start.tv_sec -= 120; // inactive, reach further back!
}
}
@@ -802,8 +810,8 @@
}
if (content_wrap || !content_timeout) {
- fprintf(stderr, "now=%" PRIu32 ".%09" PRIu32 "\n", now.tv_sec,
- now.tv_nsec);
+ fprintf(stderr, "start=%" PRIu32 ".%09" PRIu32 "\n", start.tv_sec,
+ start.tv_nsec);
}
EXPECT_TRUE(written);
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 4c2eb52..1199543 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -430,7 +430,6 @@
mkdir /data/misc/boottrace 0771 system shell
mkdir /data/misc/update_engine 0700 root root
mkdir /data/misc/trace 0700 root root
- mkdir /data/misc/reboot 0700 system system
# profile file layout
mkdir /data/misc/profiles 0771 system system
mkdir /data/misc/profiles/cur 0771 system system