Merge "Revert "Use process_vm_readv to read memory.""
diff --git a/adb/Android.mk b/adb/Android.mk
index e17240b..be04cfa 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -18,11 +18,9 @@
-DADB_REVISION='"$(adb_version)"' \
ADB_COMMON_linux_CFLAGS := \
- -std=c++14 \
-Wexit-time-destructors \
ADB_COMMON_darwin_CFLAGS := \
- -std=c++14 \
-Wexit-time-destructors \
# Define windows.h and tchar.h Unicode preprocessor symbols so that
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 29d6e65..8b6b2b5 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -1089,6 +1089,31 @@
return 1;
}
+ if (!strcmp(service, "reconnect-offline")) {
+ std::string response;
+ close_usb_devices([&response](const atransport* transport) {
+ switch (transport->connection_state) {
+ case kCsOffline:
+ case kCsUnauthorized:
+ response += "reconnecting ";
+ if (transport->serial) {
+ response += transport->serial;
+ } else {
+ response += "<unknown>";
+ }
+ response += "\n";
+ return true;
+ default:
+ return false;
+ }
+ });
+ if (!response.empty()) {
+ response.resize(response.size() - 1);
+ }
+ SendOkay(reply_fd, response);
+ return 0;
+ }
+
if (!strcmp(service, "features")) {
std::string error;
atransport* t = acquire_one_transport(type, serial, nullptr, &error);
diff --git a/adb/adb.h b/adb/adb.h
index 2797f6b..df59aaa 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -139,8 +139,10 @@
int init_socket_transport(atransport *t, int s, int port, int local);
void init_usb_transport(atransport *t, usb_handle *usb, ConnectionState state);
+std::string getEmulatorSerialString(int console_port);
#if ADB_HOST
atransport* find_emulator_transport_by_adb_port(int adb_port);
+atransport* find_emulator_transport_by_console_port(int console_port);
#endif
int service_to_fd(const char* name, const atransport* transport);
diff --git a/adb/adb_trace.cpp b/adb/adb_trace.cpp
index 369dec9..002d061 100644
--- a/adb/adb_trace.cpp
+++ b/adb/adb_trace.cpp
@@ -155,7 +155,24 @@
}
#endif
+#if !defined(_WIN32)
+ // adb historically ignored $ANDROID_LOG_TAGS but passed it through to logcat.
+ // If set, move it out of the way so that libbase logging doesn't try to parse it.
+ std::string log_tags;
+ char* ANDROID_LOG_TAGS = getenv("ANDROID_LOG_TAGS");
+ if (ANDROID_LOG_TAGS) {
+ log_tags = ANDROID_LOG_TAGS;
+ unsetenv("ANDROID_LOG_TAGS");
+ }
+#endif
+
android::base::InitLogging(argv, &AdbLogger);
+
+#if !defined(_WIN32)
+ // Put $ANDROID_LOG_TAGS back so we can pass it to logcat.
+ if (!log_tags.empty()) setenv("ANDROID_LOG_TAGS", log_tags.c_str(), 1);
+#endif
+
setup_trace_mask();
VLOG(ADB) << adb_version();
diff --git a/adb/bugreport.cpp b/adb/bugreport.cpp
index c348dd5..143c62a 100644
--- a/adb/bugreport.cpp
+++ b/adb/bugreport.cpp
@@ -21,6 +21,7 @@
#include <string>
#include <vector>
+#include <android-base/parseint.h>
#include <android-base/strings.h>
#include "sysdeps.h"
@@ -143,9 +144,11 @@
//
size_t idx1 = line.rfind(BUGZ_PROGRESS_PREFIX) + strlen(BUGZ_PROGRESS_PREFIX);
size_t idx2 = line.rfind(BUGZ_PROGRESS_SEPARATOR);
- int progress = std::stoi(line.substr(idx1, (idx2 - idx1)));
- int total = std::stoi(line.substr(idx2 + 1));
- br_->UpdateProgress(line_message_, progress, total);
+ int progress, total;
+ if (android::base::ParseInt(line.substr(idx1, (idx2 - idx1)), &progress) &&
+ android::base::ParseInt(line.substr(idx2 + 1), &total)) {
+ br_->UpdateProgress(line_message_, progress, total);
+ }
} else {
invalid_lines_.push_back(line);
}
@@ -237,8 +240,7 @@
// Uses a default value until device provides the proper name
dest_file = "bugreport.zip";
} else {
- if (!android::base::EndsWith(dest_file, ".zip")) {
- // TODO: use a case-insensitive comparison (like EndsWithIgnoreCase
+ if (!android::base::EndsWithIgnoreCase(dest_file, ".zip")) {
dest_file += ".zip";
}
}
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 54e254a..e15bcad 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -686,100 +686,100 @@
static int adb_shell(int argc, const char** argv) {
FeatureSet features;
std::string error;
-
if (!adb_get_feature_set(&features, &error)) {
fprintf(stderr, "error: %s\n", error.c_str());
return 1;
}
- bool use_shell_protocol = CanUseFeature(features, kFeatureShell2);
- if (!use_shell_protocol) {
- D("shell protocol not supported, using raw data transfer");
- } else {
- D("using shell protocol");
- }
+ enum PtyAllocationMode { kPtyAuto, kPtyNo, kPtyYes, kPtyDefinitely };
+
+ // Defaults.
+ char escape_char = '~'; // -e
+ bool use_shell_protocol = CanUseFeature(features, kFeatureShell2); // -x
+ PtyAllocationMode tty = use_shell_protocol ? kPtyAuto : kPtyDefinitely; // -t/-T
// Parse shell-specific command-line options.
- // argv[0] is always "shell".
- --argc;
- ++argv;
- int t_arg_count = 0;
- char escape_char = '~';
- while (argc) {
- if (!strcmp(argv[0], "-e")) {
- if (argc < 2 || !(strlen(argv[1]) == 1 || strcmp(argv[1], "none") == 0)) {
- fprintf(stderr, "error: -e requires a single-character argument or 'none'\n");
+ argv[0] = "adb shell"; // So getopt(3) error messages start "adb shell".
+ optind = 1; // argv[0] is always "shell", so set `optind` appropriately.
+ int opt;
+ while ((opt = getopt(argc, const_cast<char**>(argv), "+e:ntTx")) != -1) {
+ switch (opt) {
+ case 'e':
+ if (!(strlen(optarg) == 1 || strcmp(optarg, "none") == 0)) {
+ fprintf(stderr, "error: -e requires a single-character argument or 'none'\n");
+ return 1;
+ }
+ escape_char = (strcmp(optarg, "none") == 0) ? 0 : optarg[0];
+ break;
+ case 'n':
+ close_stdin();
+ break;
+ case 'x':
+ // This option basically asks for historical behavior, so set options that
+ // correspond to the historical defaults. This is slightly weird in that -Tx
+ // is fine (because we'll undo the -T) but -xT isn't, but that does seem to
+ // be our least worst choice...
+ use_shell_protocol = false;
+ tty = kPtyDefinitely;
+ escape_char = '~';
+ break;
+ case 't':
+ // Like ssh, -t arguments are cumulative so that multiple -t's
+ // are needed to force a PTY.
+ tty = (tty >= kPtyYes) ? kPtyDefinitely : kPtyYes;
+ break;
+ case 'T':
+ tty = kPtyNo;
+ break;
+ default:
+ // getopt(3) already printed an error message for us.
return 1;
- }
- escape_char = (strcmp(argv[1], "none") == 0) ? 0 : argv[1][0];
- argc -= 2;
- argv += 2;
- } else if (!strcmp(argv[0], "-T") || !strcmp(argv[0], "-t")) {
- // Like ssh, -t arguments are cumulative so that multiple -t's
- // are needed to force a PTY.
- if (argv[0][1] == 't') {
- ++t_arg_count;
- } else {
- t_arg_count = -1;
- }
- --argc;
- ++argv;
- } else if (!strcmp(argv[0], "-x")) {
- use_shell_protocol = false;
- --argc;
- ++argv;
- } else if (!strcmp(argv[0], "-n")) {
- close_stdin();
-
- --argc;
- ++argv;
- } else {
- break;
}
}
- // Legacy shell protocol requires a remote PTY to close the subprocess properly which creates
- // some weird interactions with -tT.
- if (!use_shell_protocol && t_arg_count != 0) {
- if (!CanUseFeature(features, kFeatureShell2)) {
- fprintf(stderr, "error: target doesn't support PTY args -Tt\n");
- } else {
- fprintf(stderr, "error: PTY args -Tt cannot be used with -x\n");
- }
- return 1;
- }
+ bool is_interactive = (optind == argc);
- std::string shell_type_arg;
- if (CanUseFeature(features, kFeatureShell2)) {
- if (t_arg_count < 0) {
+ std::string shell_type_arg = kShellServiceArgPty;
+ if (tty == kPtyNo) {
+ shell_type_arg = kShellServiceArgRaw;
+ } else if (tty == kPtyAuto) {
+ // If stdin isn't a TTY, default to a raw shell; this lets
+ // things like `adb shell < my_script.sh` work as expected.
+ // Non-interactive shells should also not have a pty.
+ if (!unix_isatty(STDIN_FILENO) || !is_interactive) {
shell_type_arg = kShellServiceArgRaw;
- } else if (t_arg_count == 0) {
- // If stdin isn't a TTY, default to a raw shell; this lets
- // things like `adb shell < my_script.sh` work as expected.
- // Otherwise leave |shell_type_arg| blank which uses PTY for
- // interactive shells and raw for non-interactive.
- if (!unix_isatty(STDIN_FILENO)) {
- shell_type_arg = kShellServiceArgRaw;
- }
- } else if (t_arg_count == 1) {
- // A single -t arg isn't enough to override implicit -T.
- if (!unix_isatty(STDIN_FILENO)) {
- fprintf(stderr,
- "Remote PTY will not be allocated because stdin is not a terminal.\n"
- "Use multiple -t options to force remote PTY allocation.\n");
- shell_type_arg = kShellServiceArgRaw;
- } else {
- shell_type_arg = kShellServiceArgPty;
- }
+ }
+ } else if (tty == kPtyYes) {
+ // A single -t arg isn't enough to override implicit -T.
+ if (!unix_isatty(STDIN_FILENO)) {
+ fprintf(stderr,
+ "Remote PTY will not be allocated because stdin is not a terminal.\n"
+ "Use multiple -t options to force remote PTY allocation.\n");
+ shell_type_arg = kShellServiceArgRaw;
+ }
+ }
+
+ D("shell -e 0x%x t=%d use_shell_protocol=%s shell_type_arg=%s\n",
+ escape_char, tty,
+ use_shell_protocol ? "true" : "false",
+ (shell_type_arg == kShellServiceArgPty) ? "pty" : "raw");
+
+ // Raw mode is only supported when talking to a new device *and* using the shell protocol.
+ if (!use_shell_protocol) {
+ if (shell_type_arg != kShellServiceArgPty) {
+ fprintf(stderr, "error: %s only supports allocating a pty\n",
+ !CanUseFeature(features, kFeatureShell2) ? "device" : "-x");
+ return 1;
} else {
- shell_type_arg = kShellServiceArgPty;
+ // If we're not using the shell protocol, the type argument must be empty.
+ shell_type_arg = "";
}
}
std::string command;
- if (argc) {
+ if (optind < argc) {
// We don't escape here, just like ssh(1). http://b/20564385.
- command = android::base::Join(std::vector<const char*>(argv, argv + argc), ' ');
+ command = android::base::Join(std::vector<const char*>(argv + optind, argv + argc), ' ');
}
return RemoteShell(use_shell_protocol, shell_type_arg, escape_char, command);
@@ -1401,7 +1401,7 @@
return !CanUseFeature(features, kFeatureCmd);
}
-int adb_commandline(int argc, const char **argv) {
+int adb_commandline(int argc, const char** argv) {
int no_daemon = 0;
int is_daemon = 0;
int is_server = 0;
@@ -1950,10 +1950,17 @@
} else if (!strcmp(argv[0], "reconnect")) {
if (argc == 1) {
return adb_query_command("host:reconnect");
- } else if (argc == 2 && !strcmp(argv[1], "device")) {
- std::string err;
- adb_connect("reconnect", &err);
- return 0;
+ } else if (argc == 2) {
+ if (!strcmp(argv[1], "device")) {
+ std::string err;
+ adb_connect("reconnect", &err);
+ return 0;
+ } else if (!strcmp(argv[1], "offline")) {
+ std::string err;
+ return adb_query_command("host:reconnect-offline");
+ } else {
+ return usage();
+ }
}
}
@@ -1983,20 +1990,15 @@
static int install_app(TransportType transport, const char* serial, int argc, const char** argv) {
// The last argument must be the APK file
const char* file = argv[argc - 1];
- const char* dot = strrchr(file, '.');
- bool found_apk = false;
- struct stat sb;
- if (dot && !strcasecmp(dot, ".apk")) {
- if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
- fprintf(stderr, "Invalid APK file: %s\n", file);
- return EXIT_FAILURE;
- }
- found_apk = true;
+ if (!android::base::EndsWithIgnoreCase(file, ".apk")) {
+ fprintf(stderr, "Filename doesn't end .apk: %s\n", file);
+ return EXIT_FAILURE;
}
- if (!found_apk) {
- fprintf(stderr, "Missing APK file\n");
- return EXIT_FAILURE;
+ struct stat sb;
+ if (stat(file, &sb) == -1) {
+ fprintf(stderr, "Failed to stat %s: %s\n", file, strerror(errno));
+ return 1;
}
int localFd = adb_open(file, O_RDONLY);
@@ -2042,22 +2044,16 @@
static int install_multiple_app(TransportType transport, const char* serial, int argc,
const char** argv)
{
- int i;
- struct stat sb;
- uint64_t total_size = 0;
// Find all APK arguments starting at end.
// All other arguments passed through verbatim.
int first_apk = -1;
- for (i = argc - 1; i >= 0; i--) {
+ uint64_t total_size = 0;
+ for (int i = argc - 1; i >= 0; i--) {
const char* file = argv[i];
- const char* dot = strrchr(file, '.');
- if (dot && !strcasecmp(dot, ".apk")) {
- if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
- fprintf(stderr, "Invalid APK file: %s\n", file);
- return EXIT_FAILURE;
- }
- total_size += sb.st_size;
+ if (android::base::EndsWithIgnoreCase(file, ".apk")) {
+ struct stat sb;
+ if (stat(file, &sb) != -1) total_size += sb.st_size;
first_apk = i;
} else {
break;
@@ -2065,7 +2061,7 @@
}
if (first_apk == -1) {
- fprintf(stderr, "Missing APK file\n");
+ fprintf(stderr, "No APK file on command line\n");
return 1;
}
@@ -2077,7 +2073,7 @@
}
std::string cmd = android::base::StringPrintf("%s install-create -S %" PRIu64, install_cmd.c_str(), total_size);
- for (i = 1; i < first_apk; i++) {
+ for (int i = 1; i < first_apk; i++) {
cmd += " " + escape_arg(argv[i]);
}
@@ -2109,10 +2105,11 @@
// Valid session, now stream the APKs
int success = 1;
- for (i = first_apk; i < argc; i++) {
+ for (int i = first_apk; i < argc; i++) {
const char* file = argv[i];
+ struct stat sb;
if (stat(file, &sb) == -1) {
- fprintf(stderr, "Failed to stat %s\n", file);
+ fprintf(stderr, "Failed to stat %s: %s\n", file, strerror(errno));
success = 0;
goto finalize_session;
}
@@ -2212,10 +2209,8 @@
static const char *const DATA_DEST = "/data/local/tmp/%s";
static const char *const SD_DEST = "/sdcard/tmp/%s";
const char* where = DATA_DEST;
- int i;
- struct stat sb;
- for (i = 1; i < argc; i++) {
+ for (int i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-s")) {
where = SD_DEST;
}
@@ -2224,22 +2219,15 @@
// Find last APK argument.
// All other arguments passed through verbatim.
int last_apk = -1;
- for (i = argc - 1; i >= 0; i--) {
- const char* file = argv[i];
- const char* dot = strrchr(file, '.');
- if (dot && !strcasecmp(dot, ".apk")) {
- if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
- fprintf(stderr, "Invalid APK file: %s\n", file);
- return EXIT_FAILURE;
- }
-
+ for (int i = argc - 1; i >= 0; i--) {
+ if (android::base::EndsWithIgnoreCase(argv[i], ".apk")) {
last_apk = i;
break;
}
}
if (last_apk == -1) {
- fprintf(stderr, "Missing APK file\n");
+ fprintf(stderr, "No APK file on command line\n");
return EXIT_FAILURE;
}
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 094988a..78434a0 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -35,7 +35,8 @@
#include <scoped_minijail.h>
#include "debuggerd/client.h"
-#include "private/android_filesystem_config.h"
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
#include "selinux/android.h"
#include "adb.h"
@@ -48,7 +49,7 @@
static void drop_capabilities_bounding_set_if_needed(struct minijail *j) {
#if defined(ALLOW_ADBD_ROOT)
- if (android::base::GetBoolProperty("ro.debuggable", false)) {
+ if (__android_log_is_debuggable()) {
return;
}
#endif
@@ -68,7 +69,7 @@
// ro.secure:
// Drop privileges by default. Set to 1 on userdebug and user builds.
bool ro_secure = android::base::GetBoolProperty("ro.secure", true);
- bool ro_debuggable = android::base::GetBoolProperty("ro.debuggable", false);
+ bool ro_debuggable = __android_log_is_debuggable();
// Drop privileges if ro.secure is set...
bool drop = ro_secure;
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index 837902a..7a92d2e 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -198,11 +198,6 @@
// Ignore the result of calling fchmod. It's not supported
// by all filesystems, so we don't check for success. b/12441485
fchmod(fd, mode);
-
- if (!update_capabilities(path, capabilities)) {
- SendSyncFailErrno(s, "update_capabilities failed");
- goto fail;
- }
}
while (true) {
@@ -232,6 +227,11 @@
adb_close(fd);
+ if (!update_capabilities(path, capabilities)) {
+ SendSyncFailErrno(s, "update_capabilities failed");
+ goto fail;
+ }
+
utimbuf u;
u.actime = timestamp;
u.modtime = timestamp;
diff --git a/adb/services.cpp b/adb/services.cpp
index 0c3dd00..2fbc15a 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -38,8 +38,9 @@
#include <cutils/sockets.h>
#if !ADB_HOST
-#include "cutils/android_reboot.h"
#include <android-base/properties.h>
+#include <cutils/android_reboot.h>
+#include <private/android_logger.h>
#endif
#include "adb.h"
@@ -73,7 +74,7 @@
WriteFdExactly(fd, "adbd is already running as root\n");
adb_close(fd);
} else {
- if (!android::base::GetBoolProperty("ro.debuggable", false)) {
+ if (!__android_log_is_debuggable()) {
WriteFdExactly(fd, "adbd cannot run as root in production builds\n");
adb_close(fd);
return;
diff --git a/adb/set_verity_enable_state_service.cpp b/adb/set_verity_enable_state_service.cpp
index ae628e4..f9e028b 100644
--- a/adb/set_verity_enable_state_service.cpp
+++ b/adb/set_verity_enable_state_service.cpp
@@ -26,6 +26,7 @@
#include "android-base/properties.h"
#include "android-base/stringprintf.h"
+#include <private/android_logger.h>
#include "adb.h"
#include "adb_io.h"
@@ -102,8 +103,7 @@
WriteFdFmt(fd, "verity not enabled - ENG build\n");
return;
}
-
- if (!android::base::GetBoolProperty("ro.debuggable", false)) {
+ if (!__android_log_is_debuggable()) {
WriteFdFmt(fd, "verity cannot be disabled/enabled - USER build\n");
return;
}
diff --git a/adb/shell_service_protocol_test.cpp b/adb/shell_service_protocol_test.cpp
index a826035..b0fa3ed 100644
--- a/adb/shell_service_protocol_test.cpp
+++ b/adb/shell_service_protocol_test.cpp
@@ -86,9 +86,10 @@
namespace {
-// Returns true if the packet contains the given values.
+// Returns true if the packet contains the given values. `data` can't be null.
bool PacketEquals(const ShellProtocol* protocol, ShellProtocol::Id id,
const void* data, size_t data_length) {
+ // Note that passing memcmp null is bad, even if data_length is 0.
return (protocol->id() == id &&
protocol->data_length() == data_length &&
!memcmp(data, protocol->data(), data_length));
@@ -130,7 +131,8 @@
ASSERT_TRUE(write_protocol_->Write(id, 0));
ASSERT_TRUE(read_protocol_->Read());
- ASSERT_TRUE(PacketEquals(read_protocol_, id, nullptr, 0));
+ char buf[1];
+ ASSERT_TRUE(PacketEquals(read_protocol_, id, buf, 0));
}
// Tests exit code packets.
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index fff6049..c05903f 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -32,6 +32,7 @@
#if !ADB_HOST
#include <android-base/properties.h>
+#include <private/android_logger.h>
#endif
#include "adb.h"
@@ -416,12 +417,7 @@
D("LS(%d): bound to '%s' via %d", s->id, name, fd);
#if !ADB_HOST
- bool debuggable = false;
- if (!strncmp(name, "root:", 5)) {
- debuggable = android::base::GetBoolProperty("ro.debuggable", false);
- }
-
- if ((!strncmp(name, "root:", 5) && getuid() != 0 && debuggable) ||
+ if ((!strncmp(name, "root:", 5) && getuid() != 0 && __android_log_is_debuggable()) ||
(!strncmp(name, "unroot:", 7) && getuid() == 0) ||
!strncmp(name, "usb:", 4) ||
!strncmp(name, "tcpip:", 6)) {
@@ -795,11 +791,14 @@
}
#endif
- if (!(s->transport) || (s->transport->connection_state == kCsOffline)) {
+ if (!s->transport) {
+ SendFail(s->peer->fd, "device offline (no transport)");
+ goto fail;
+ } else if (s->transport->connection_state == kCsOffline) {
/* if there's no remote we fail the connection
** right here and terminate it
*/
- SendFail(s->peer->fd, "device offline (x)");
+ SendFail(s->peer->fd, "device offline (transport offline)");
goto fail;
}
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 3ed589c..ad9b9fd 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -594,11 +594,14 @@
}
inline int network_loopback_client(int port, int type, std::string* error) {
- return _fd_set_error_str(socket_loopback_client(port, type), error);
+ return _fd_set_error_str(socket_network_client("localhost", port, type), error);
}
inline int network_loopback_server(int port, int type, std::string* error) {
- return _fd_set_error_str(socket_loopback_server(port, type), error);
+ int fd = socket_loopback_server(port, type);
+ if (fd < 0 && errno == EAFNOSUPPORT)
+ return _fd_set_error_str(socket_loopback_server6(port, type), error);
+ return _fd_set_error_str(fd, error);
}
inline int network_inaddr_any_server(int port, int type, std::string* error) {
diff --git a/adb/test_device.py b/adb/test_device.py
index b12bf88..02a16e4 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -371,15 +371,8 @@
def test_pty_logic(self):
"""Tests that a PTY is allocated when it should be.
- PTY allocation behavior should match ssh; some behavior requires
- a terminal stdin to test so this test will be skipped if stdin
- is not a terminal.
+ PTY allocation behavior should match ssh.
"""
- if not self.device.has_shell_protocol():
- raise unittest.SkipTest('PTY arguments unsupported on this device')
- if not os.isatty(sys.stdin.fileno()):
- raise unittest.SkipTest('PTY tests require stdin terminal')
-
def check_pty(args):
"""Checks adb shell PTY allocation.
@@ -409,16 +402,34 @@
# -T: never allocate PTY.
self.assertEqual((False, False), check_pty(['-T']))
- # No args: PTY only if stdin is a terminal and shell is interactive,
- # which is difficult to reliably test from a script.
- self.assertEqual((False, False), check_pty([]))
+ # These tests require a new device.
+ if self.device.has_shell_protocol() and os.isatty(sys.stdin.fileno()):
+ # No args: PTY only if stdin is a terminal and shell is interactive,
+ # which is difficult to reliably test from a script.
+ self.assertEqual((False, False), check_pty([]))
- # -t: PTY if stdin is a terminal.
- self.assertEqual((True, False), check_pty(['-t']))
+ # -t: PTY if stdin is a terminal.
+ self.assertEqual((True, False), check_pty(['-t']))
# -t -t: always allocate PTY.
self.assertEqual((True, True), check_pty(['-t', '-t']))
+ # -tt: always allocate PTY, POSIX style (http://b/32216152).
+ self.assertEqual((True, True), check_pty(['-tt']))
+
+ # -ttt: ssh has weird even/odd behavior with multiple -t flags, but
+ # we follow the man page instead.
+ self.assertEqual((True, True), check_pty(['-ttt']))
+
+ # -ttx: -x and -tt aren't incompatible (though -Tx would be an error).
+ self.assertEqual((True, True), check_pty(['-ttx']))
+
+ # -Ttt: -tt cancels out -T.
+ self.assertEqual((True, True), check_pty(['-Ttt']))
+
+ # -ttT: -T cancels out -tt.
+ self.assertEqual((False, False), check_pty(['-ttT']))
+
def test_shell_protocol(self):
"""Tests the shell protocol on the device.
@@ -473,8 +484,12 @@
self.device.shell(proc_query)
os.kill(sleep_proc.pid, signal.SIGINT)
sleep_proc.communicate()
- self.assertEqual(1, self.device.shell_nocheck(proc_query)[0],
- 'subprocess failed to terminate')
+
+ # It can take some time for the process to receive the signal and die.
+ end_time = time.time() + 3
+ while self.device.shell_nocheck(proc_query)[0] != 1:
+ self.assertFalse(time.time() > end_time,
+ 'subprocess failed to terminate in time')
def test_non_interactive_stdin(self):
"""Tests that non-interactive shells send stdin."""
@@ -507,13 +522,14 @@
trap "echo SIGINT > {path}; exit 0" SIGINT
trap "echo SIGHUP > {path}; exit 0" SIGHUP
echo Waiting
- while true; do sleep 100; done
+ read
""".format(path=log_path)
script = ";".join([x.strip() for x in script.strip().splitlines()])
- process = self.device.shell_popen(
- ["sh", "-c", "'{}'".format(script)], kill_atexit=False, stdout=subprocess.PIPE)
+ process = self.device.shell_popen([script], kill_atexit=False,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE)
self.assertEqual("Waiting\n", process.stdout.readline())
process.send_signal(signal.SIGINT)
@@ -521,7 +537,7 @@
# Waiting for the local adb to finish is insufficient, since it hangs
# up immediately.
- time.sleep(0.25)
+ time.sleep(1)
stdout, _ = self.device.shell(["cat", log_path])
self.assertEqual(stdout.strip(), "SIGHUP")
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 7b4bb1c..132702d 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -908,12 +908,18 @@
return result;
}
+void close_usb_devices(std::function<bool(const atransport*)> predicate) {
+ std::lock_guard<std::mutex> lock(transport_lock);
+ for (auto& t : transport_list) {
+ if (predicate(t)) {
+ t->Kick();
+ }
+ }
+}
+
/* hack for osx */
void close_usb_devices() {
- std::lock_guard<std::mutex> lock(transport_lock);
- for (const auto& t : transport_list) {
- t->Kick();
- }
+ close_usb_devices([](const atransport*) { return true; });
}
#endif // ADB_HOST
diff --git a/adb/transport.h b/adb/transport.h
index 621516c..b2df838 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -20,6 +20,7 @@
#include <sys/types.h>
#include <deque>
+#include <functional>
#include <list>
#include <memory>
#include <string>
@@ -199,8 +200,8 @@
int check_header(apacket* p, atransport* t);
int check_data(apacket* p);
-/* for MacOS X cleanup */
void close_usb_devices();
+void close_usb_devices(std::function<bool(const atransport*)> predicate);
void send_packet(apacket* p, atransport* t);
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index a94b41e..ba2b28d 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -103,7 +103,8 @@
int fd = -1;
#if ADB_HOST
- if (find_emulator_transport_by_adb_port(adb_port) != nullptr) {
+ if (find_emulator_transport_by_adb_port(adb_port) != nullptr ||
+ find_emulator_transport_by_console_port(console_port) != nullptr) {
return -1;
}
@@ -120,7 +121,7 @@
D("client: connected on remote on fd %d", fd);
close_on_exec(fd);
disable_tcp_nagle(fd);
- std::string serial = android::base::StringPrintf("emulator-%d", console_port);
+ std::string serial = getEmulatorSerialString(console_port);
if (register_socket_transport(fd, serial.c_str(), adb_port, 1) == 0) {
return 0;
}
@@ -225,7 +226,8 @@
D("server: new connection on fd %d", fd);
close_on_exec(fd);
disable_tcp_nagle(fd);
- if (register_socket_transport(fd, "host", port, 1) != 0) {
+ std::string serial = android::base::StringPrintf("host-%d", fd);
+ if (register_socket_transport(fd, serial.c_str(), port, 1) != 0) {
adb_close(fd);
}
}
@@ -431,6 +433,11 @@
return NULL;
}
+std::string getEmulatorSerialString(int console_port)
+{
+ return android::base::StringPrintf("emulator-%d", console_port);
+}
+
atransport* find_emulator_transport_by_adb_port(int adb_port)
{
std::lock_guard<std::mutex> lock(local_transports_lock);
@@ -438,6 +445,12 @@
return result;
}
+atransport* find_emulator_transport_by_console_port(int console_port)
+{
+ return find_transport(getEmulatorSerialString(console_port).c_str());
+}
+
+
/* Only call this function if you already hold local_transports_lock. */
int get_available_local_transport_index_locked()
{
diff --git a/base/Android.bp b/base/Android.bp
index 88d8ad1..e6ad15b 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -73,6 +73,7 @@
"errors_test.cpp",
"file_test.cpp",
"logging_test.cpp",
+ "parsedouble_test.cpp",
"parseint_test.cpp",
"parsenetaddress_test.cpp",
"quick_exit_test.cpp",
diff --git a/base/include/android-base/parsedouble.h b/base/include/android-base/parsedouble.h
new file mode 100644
index 0000000..daa6902
--- /dev/null
+++ b/base/include/android-base/parsedouble.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_BASE_PARSEDOUBLE_H
+#define ANDROID_BASE_PARSEDOUBLE_H
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include <limits>
+
+namespace android {
+namespace base {
+
+// Parse double value in the string 's' and sets 'out' to that value.
+// Optionally allows the caller to define a 'min' and 'max' beyond which
+// otherwise valid values will be rejected. Returns boolean success.
+static inline bool ParseDouble(const char* s, double* out,
+ double min = std::numeric_limits<double>::lowest(),
+ double max = std::numeric_limits<double>::max()) {
+ errno = 0;
+ char* end;
+ double result = strtod(s, &end);
+ if (errno != 0 || s == end || *end != '\0') {
+ return false;
+ }
+ if (result < min || max < result) {
+ return false;
+ }
+ *out = result;
+ return true;
+}
+
+} // namespace base
+} // namespace android
+
+#endif // ANDROID_BASE_PARSEDOUBLE_H
diff --git a/base/include/android-base/parseint.h b/base/include/android-base/parseint.h
index 7415409..2c8570e 100644
--- a/base/include/android-base/parseint.h
+++ b/base/include/android-base/parseint.h
@@ -21,13 +21,15 @@
#include <stdlib.h>
#include <limits>
+#include <string>
namespace android {
namespace base {
// Parses the unsigned decimal integer in the string 's' and sets 'out' to
// that value. Optionally allows the caller to define a 'max' beyond which
-// otherwise valid values will be rejected. Returns boolean success.
+// otherwise valid values will be rejected. Returns boolean success; 'out'
+// is untouched if parsing fails.
template <typename T>
bool ParseUint(const char* s, T* out,
T max = std::numeric_limits<T>::max()) {
@@ -45,10 +47,17 @@
return true;
}
+// TODO: string_view
+template <typename T>
+bool ParseUint(const std::string& s, T* out,
+ T max = std::numeric_limits<T>::max()) {
+ return ParseUint(s.c_str(), out, max);
+}
+
// Parses the signed decimal integer in the string 's' and sets 'out' to
// that value. Optionally allows the caller to define a 'min' and 'max
// beyond which otherwise valid values will be rejected. Returns boolean
-// success.
+// success; 'out' is untouched if parsing fails.
template <typename T>
bool ParseInt(const char* s, T* out,
T min = std::numeric_limits<T>::min(),
@@ -67,6 +76,14 @@
return true;
}
+// TODO: string_view
+template <typename T>
+bool ParseInt(const std::string& s, T* out,
+ T min = std::numeric_limits<T>::min(),
+ T max = std::numeric_limits<T>::max()) {
+ return ParseInt(s.c_str(), out, min, max);
+}
+
} // namespace base
} // namespace android
diff --git a/base/include/android-base/strings.h b/base/include/android-base/strings.h
index 69781cd..b8a9289 100644
--- a/base/include/android-base/strings.h
+++ b/base/include/android-base/strings.h
@@ -58,9 +58,11 @@
// Tests whether 's' starts with 'prefix'.
bool StartsWith(const std::string& s, const char* prefix);
+bool StartsWithIgnoreCase(const std::string& s, const char* prefix);
// Tests whether 's' ends with 'suffix'.
bool EndsWith(const std::string& s, const char* suffix);
+bool EndsWithIgnoreCase(const std::string& s, const char* suffix);
} // namespace base
} // namespace android
diff --git a/base/include/android-base/test_utils.h b/base/include/android-base/test_utils.h
index 4ea3c8e..c0bf0c1 100644
--- a/base/include/android-base/test_utils.h
+++ b/base/include/android-base/test_utils.h
@@ -48,4 +48,21 @@
DISALLOW_COPY_AND_ASSIGN(TemporaryDir);
};
+class CapturedStderr {
+ public:
+ CapturedStderr();
+ ~CapturedStderr();
+
+ int fd() const;
+
+ private:
+ void init();
+ void reset();
+
+ TemporaryFile temp_file_;
+ int old_stderr_;
+
+ DISALLOW_COPY_AND_ASSIGN(CapturedStderr);
+};
+
#endif // ANDROID_BASE_TEST_UTILS_H
diff --git a/base/logging.cpp b/base/logging.cpp
index dab86fe..cbc3c8a 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -45,7 +45,7 @@
// Headers for LogMessage::LogLine.
#ifdef __ANDROID__
-#include <android/log.h>
+#include <log/log.h>
#include <android/set_abort_message.h>
#else
#include <sys/types.h>
diff --git a/base/logging_test.cpp b/base/logging_test.cpp
index 1ee181a..2d9c2ba 100644
--- a/base/logging_test.cpp
+++ b/base/logging_test.cpp
@@ -37,42 +37,6 @@
#define HOST_TEST(suite, name) TEST(suite, name)
#endif
-class CapturedStderr {
- public:
- CapturedStderr() : old_stderr_(-1) {
- init();
- }
-
- ~CapturedStderr() {
- reset();
- }
-
- int fd() const {
- return temp_file_.fd;
- }
-
- private:
- void init() {
-#if defined(_WIN32)
- // On Windows, stderr is often buffered, so make sure it is unbuffered so
- // that we can immediately read back what was written to stderr.
- ASSERT_EQ(0, setvbuf(stderr, NULL, _IONBF, 0));
-#endif
- old_stderr_ = dup(STDERR_FILENO);
- ASSERT_NE(-1, old_stderr_);
- ASSERT_NE(-1, dup2(fd(), STDERR_FILENO));
- }
-
- void reset() {
- ASSERT_NE(-1, dup2(old_stderr_, STDERR_FILENO));
- ASSERT_EQ(0, close(old_stderr_));
- // Note: cannot restore prior setvbuf() setting.
- }
-
- TemporaryFile temp_file_;
- int old_stderr_;
-};
-
#if defined(_WIN32)
static void ExitSignalAbortHandler(int) {
_exit(3);
diff --git a/base/parsedouble_test.cpp b/base/parsedouble_test.cpp
new file mode 100644
index 0000000..8734c42
--- /dev/null
+++ b/base/parsedouble_test.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "android-base/parsedouble.h"
+
+#include <gtest/gtest.h>
+
+TEST(parsedouble, smoke) {
+ double d;
+ ASSERT_FALSE(android::base::ParseDouble("", &d));
+ ASSERT_FALSE(android::base::ParseDouble("x", &d));
+ ASSERT_FALSE(android::base::ParseDouble("123.4x", &d));
+
+ ASSERT_TRUE(android::base::ParseDouble("123.4", &d));
+ ASSERT_DOUBLE_EQ(123.4, d);
+ ASSERT_TRUE(android::base::ParseDouble("-123.4", &d));
+ ASSERT_DOUBLE_EQ(-123.4, d);
+
+ ASSERT_TRUE(android::base::ParseDouble("0", &d, 0.0));
+ ASSERT_DOUBLE_EQ(0.0, d);
+ ASSERT_FALSE(android::base::ParseDouble("0", &d, 1e-9));
+ ASSERT_FALSE(android::base::ParseDouble("3.0", &d, -1.0, 2.0));
+ ASSERT_TRUE(android::base::ParseDouble("1.0", &d, 0.0, 2.0));
+ ASSERT_DOUBLE_EQ(1.0, d);
+}
diff --git a/base/parseint_test.cpp b/base/parseint_test.cpp
index 6a3ba31..483b1d3 100644
--- a/base/parseint_test.cpp
+++ b/base/parseint_test.cpp
@@ -19,7 +19,7 @@
#include <gtest/gtest.h>
TEST(parseint, signed_smoke) {
- int i;
+ int i = 0;
ASSERT_FALSE(android::base::ParseInt("x", &i));
ASSERT_FALSE(android::base::ParseInt("123x", &i));
@@ -28,7 +28,7 @@
ASSERT_TRUE(android::base::ParseInt("-123", &i));
ASSERT_EQ(-123, i);
- short s;
+ short s = 0;
ASSERT_TRUE(android::base::ParseInt("1234", &s));
ASSERT_EQ(1234, s);
@@ -39,7 +39,7 @@
}
TEST(parseint, unsigned_smoke) {
- unsigned int i;
+ unsigned int i = 0u;
ASSERT_FALSE(android::base::ParseUint("x", &i));
ASSERT_FALSE(android::base::ParseUint("123x", &i));
@@ -47,7 +47,7 @@
ASSERT_EQ(123u, i);
ASSERT_FALSE(android::base::ParseUint("-123", &i));
- unsigned short s;
+ unsigned short s = 0u;
ASSERT_TRUE(android::base::ParseUint("1234", &s));
ASSERT_EQ(1234u, s);
@@ -58,21 +58,41 @@
}
TEST(parseint, no_implicit_octal) {
- int i;
+ int i = 0;
ASSERT_TRUE(android::base::ParseInt("0123", &i));
ASSERT_EQ(123, i);
- unsigned int u;
+ unsigned int u = 0u;
ASSERT_TRUE(android::base::ParseUint("0123", &u));
ASSERT_EQ(123u, u);
}
TEST(parseint, explicit_hex) {
- int i;
+ int i = 0;
ASSERT_TRUE(android::base::ParseInt("0x123", &i));
ASSERT_EQ(0x123, i);
- unsigned int u;
+ unsigned int u = 0u;
ASSERT_TRUE(android::base::ParseUint("0x123", &u));
ASSERT_EQ(0x123u, u);
}
+
+TEST(parseint, string) {
+ int i = 0;
+ ASSERT_TRUE(android::base::ParseInt(std::string("123"), &i));
+ ASSERT_EQ(123, i);
+
+ unsigned int u = 0u;
+ ASSERT_TRUE(android::base::ParseUint(std::string("123"), &u));
+ ASSERT_EQ(123u, u);
+}
+
+TEST(parseint, untouched_on_failure) {
+ int i = 123;
+ ASSERT_FALSE(android::base::ParseInt("456x", &i));
+ ASSERT_EQ(123, i);
+
+ unsigned int u = 123u;
+ ASSERT_FALSE(android::base::ParseInt("456x", &u));
+ ASSERT_EQ(123u, u);
+}
diff --git a/base/properties.cpp b/base/properties.cpp
index fab3005..37daf9a 100644
--- a/base/properties.cpp
+++ b/base/properties.cpp
@@ -52,7 +52,7 @@
T GetIntProperty(const std::string& key, T default_value, T min, T max) {
T result;
std::string value = GetProperty(key, "");
- if (!value.empty() && android::base::ParseInt(value.c_str(), &result, min, max)) return result;
+ if (!value.empty() && android::base::ParseInt(value, &result, min, max)) return result;
return default_value;
}
@@ -60,7 +60,7 @@
T GetUintProperty(const std::string& key, T default_value, T max) {
T result;
std::string value = GetProperty(key, "");
- if (!value.empty() && android::base::ParseUint(value.c_str(), &result, max)) return result;
+ if (!value.empty() && android::base::ParseUint(value, &result, max)) return result;
return default_value;
}
diff --git a/base/strings.cpp b/base/strings.cpp
index b8775df..7a94ad7 100644
--- a/base/strings.cpp
+++ b/base/strings.cpp
@@ -87,17 +87,29 @@
template std::string Join(const std::vector<const char*>&, const std::string&);
bool StartsWith(const std::string& s, const char* prefix) {
- return s.compare(0, strlen(prefix), prefix) == 0;
+ return strncmp(s.c_str(), prefix, strlen(prefix)) == 0;
}
-bool EndsWith(const std::string& s, const char* suffix) {
+bool StartsWithIgnoreCase(const std::string& s, const char* prefix) {
+ return strncasecmp(s.c_str(), prefix, strlen(prefix)) == 0;
+}
+
+static bool EndsWith(const std::string& s, const char* suffix, bool case_sensitive) {
size_t suffix_length = strlen(suffix);
size_t string_length = s.size();
if (suffix_length > string_length) {
return false;
}
size_t offset = string_length - suffix_length;
- return s.compare(offset, suffix_length, suffix) == 0;
+ return (case_sensitive ? strncmp : strncasecmp)(s.c_str() + offset, suffix, suffix_length) == 0;
+}
+
+bool EndsWith(const std::string& s, const char* suffix) {
+ return EndsWith(s, suffix, true);
+}
+
+bool EndsWithIgnoreCase(const std::string& s, const char* suffix) {
+ return EndsWith(s, suffix, false);
}
} // namespace base
diff --git a/base/strings_test.cpp b/base/strings_test.cpp
index 30ae29e..5fb21dd 100644
--- a/base/strings_test.cpp
+++ b/base/strings_test.cpp
@@ -134,44 +134,113 @@
"2,1" == android::base::Join(list, ','));
}
-TEST(strings, startswith_empty) {
+TEST(strings, StartsWith_empty) {
ASSERT_FALSE(android::base::StartsWith("", "foo"));
ASSERT_TRUE(android::base::StartsWith("", ""));
}
-TEST(strings, startswith_simple) {
+TEST(strings, StartsWithIgnoreCase_empty) {
+ ASSERT_FALSE(android::base::StartsWithIgnoreCase("", "foo"));
+ ASSERT_TRUE(android::base::StartsWithIgnoreCase("", ""));
+}
+
+TEST(strings, StartsWith_simple) {
ASSERT_TRUE(android::base::StartsWith("foo", ""));
ASSERT_TRUE(android::base::StartsWith("foo", "f"));
ASSERT_TRUE(android::base::StartsWith("foo", "fo"));
ASSERT_TRUE(android::base::StartsWith("foo", "foo"));
}
-TEST(strings, startswith_prefix_too_long) {
+TEST(strings, StartsWithIgnoreCase_simple) {
+ ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", ""));
+ ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "f"));
+ ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "F"));
+ ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fo"));
+ ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fO"));
+ ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "Fo"));
+ ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FO"));
+ ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "foo"));
+ ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "foO"));
+ ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fOo"));
+ ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fOO"));
+ ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "Foo"));
+ ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FoO"));
+ ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FOo"));
+ ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FOO"));
+}
+
+TEST(strings, StartsWith_prefix_too_long) {
ASSERT_FALSE(android::base::StartsWith("foo", "foobar"));
}
-TEST(strings, startswith_contains_prefix) {
+TEST(strings, StartsWithIgnoreCase_prefix_too_long) {
+ ASSERT_FALSE(android::base::StartsWithIgnoreCase("foo", "foobar"));
+ ASSERT_FALSE(android::base::StartsWithIgnoreCase("foo", "FOOBAR"));
+}
+
+TEST(strings, StartsWith_contains_prefix) {
ASSERT_FALSE(android::base::StartsWith("foobar", "oba"));
ASSERT_FALSE(android::base::StartsWith("foobar", "bar"));
}
-TEST(strings, endswith_empty) {
+TEST(strings, StartsWithIgnoreCase_contains_prefix) {
+ ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "oba"));
+ ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "OBA"));
+ ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "bar"));
+ ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "BAR"));
+}
+
+TEST(strings, EndsWith_empty) {
ASSERT_FALSE(android::base::EndsWith("", "foo"));
ASSERT_TRUE(android::base::EndsWith("", ""));
}
-TEST(strings, endswith_simple) {
+TEST(strings, EndsWithIgnoreCase_empty) {
+ ASSERT_FALSE(android::base::EndsWithIgnoreCase("", "foo"));
+ ASSERT_FALSE(android::base::EndsWithIgnoreCase("", "FOO"));
+ ASSERT_TRUE(android::base::EndsWithIgnoreCase("", ""));
+}
+
+TEST(strings, EndsWith_simple) {
ASSERT_TRUE(android::base::EndsWith("foo", ""));
ASSERT_TRUE(android::base::EndsWith("foo", "o"));
ASSERT_TRUE(android::base::EndsWith("foo", "oo"));
ASSERT_TRUE(android::base::EndsWith("foo", "foo"));
}
-TEST(strings, endswith_prefix_too_long) {
+TEST(strings, EndsWithIgnoreCase_simple) {
+ ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", ""));
+ ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "o"));
+ ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "O"));
+ ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "oo"));
+ ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "oO"));
+ ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "Oo"));
+ ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "OO"));
+ ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "foo"));
+ ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "foO"));
+ ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "fOo"));
+ ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "fOO"));
+ ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "Foo"));
+ ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "FoO"));
+ ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "FOo"));
+ ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "FOO"));
+}
+
+TEST(strings, EndsWith_prefix_too_long) {
ASSERT_FALSE(android::base::EndsWith("foo", "foobar"));
}
-TEST(strings, endswith_contains_prefix) {
+TEST(strings, EndsWithIgnoreCase_prefix_too_long) {
+ ASSERT_FALSE(android::base::EndsWithIgnoreCase("foo", "foobar"));
+ ASSERT_FALSE(android::base::EndsWithIgnoreCase("foo", "FOOBAR"));
+}
+
+TEST(strings, EndsWith_contains_prefix) {
ASSERT_FALSE(android::base::EndsWith("foobar", "oba"));
ASSERT_FALSE(android::base::EndsWith("foobar", "foo"));
}
+
+TEST(strings, EndsWithIgnoreCase_contains_prefix) {
+ ASSERT_FALSE(android::base::EndsWithIgnoreCase("foobar", "OBA"));
+ ASSERT_FALSE(android::base::EndsWithIgnoreCase("foobar", "FOO"));
+}
diff --git a/base/test_utils.cpp b/base/test_utils.cpp
index 635af6c..3b3d698 100644
--- a/base/test_utils.cpp
+++ b/base/test_utils.cpp
@@ -102,3 +102,32 @@
OS_PATH_SEPARATOR);
return (mkdtemp(path) != nullptr);
}
+
+CapturedStderr::CapturedStderr() : old_stderr_(-1) {
+ init();
+}
+
+CapturedStderr::~CapturedStderr() {
+ reset();
+}
+
+int CapturedStderr::fd() const {
+ return temp_file_.fd;
+}
+
+void CapturedStderr::init() {
+#if defined(_WIN32)
+ // On Windows, stderr is often buffered, so make sure it is unbuffered so
+ // that we can immediately read back what was written to stderr.
+ CHECK_EQ(0, setvbuf(stderr, NULL, _IONBF, 0));
+#endif
+ old_stderr_ = dup(STDERR_FILENO);
+ CHECK_NE(-1, old_stderr_);
+ CHECK_NE(-1, dup2(fd(), STDERR_FILENO));
+}
+
+void CapturedStderr::reset() {
+ CHECK_NE(-1, dup2(old_stderr_, STDERR_FILENO));
+ CHECK_EQ(0, close(old_stderr_));
+ // Note: cannot restore prior setvbuf() setting.
+}
diff --git a/bootstat/Android.bp b/bootstat/Android.bp
index 89b4598..d98a9d7 100644
--- a/bootstat/Android.bp
+++ b/bootstat/Android.bp
@@ -16,7 +16,6 @@
bootstat_lib_src_files = [
"boot_event_record_store.cpp",
- "event_log_list_builder.cpp",
"histogram_logger.cpp",
"uptime_parser.cpp",
]
@@ -88,7 +87,6 @@
],
srcs: [
"boot_event_record_store_test.cpp",
- "event_log_list_builder_test.cpp",
"testrunner.cpp",
],
}
diff --git a/bootstat/boot_event_record_store.cpp b/bootstat/boot_event_record_store.cpp
index 346eada..78be944 100644
--- a/bootstat/boot_event_record_store.cpp
+++ b/bootstat/boot_event_record_store.cpp
@@ -59,7 +59,7 @@
// Ignore existing bootstat records (which do not contain file content).
if (!content.empty()) {
int32_t value;
- if (android::base::ParseInt(content.c_str(), &value)) {
+ if (android::base::ParseInt(content, &value)) {
bootstat::LogHistogram("bootstat_mtime_matches_content", value == *uptime);
}
}
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 0ab4c98..7c0e85d 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -35,7 +35,6 @@
#include <cutils/properties.h>
#include "boot_event_record_store.h"
-#include "event_log_list_builder.h" /* ToDo: switch to liblog implementation */
#include "histogram_logger.h"
#include "uptime_parser.h"
@@ -60,7 +59,7 @@
BootEventRecordStore boot_event_store;
if (!value_str.empty()) {
int32_t value = 0;
- if (android::base::ParseInt(value_str.c_str(), &value)) {
+ if (android::base::ParseInt(value_str, &value)) {
boot_event_store.AddBootEventWithValue(event, value);
}
} else {
@@ -193,7 +192,7 @@
std::string build_date_str = GetProperty("ro.build.date.utc");
int32_t build_date;
- if (!android::base::ParseInt(build_date_str.c_str(), &build_date)) {
+ if (!android::base::ParseInt(build_date_str, &build_date)) {
return std::string();
}
diff --git a/bootstat/event_log_list_builder.cpp b/bootstat/event_log_list_builder.cpp
deleted file mode 100644
index a6af13e..0000000
--- a/bootstat/event_log_list_builder.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "event_log_list_builder.h"
-
-#include <cinttypes>
-#include <memory>
-#include <string>
-
-#include <android/log.h>
-#include <android-base/logging.h>
-
-namespace {
-
-const size_t MAX_EVENT_PAYLOAD_SIZE = 512 - 1; // Leave room for final '\n'.
-const size_t EVENT_TYPE_SIZE = 1; // Size in bytes of the event type marker.
-
-} // namespace
-
-EventLogListBuilder::EventLogListBuilder()
- : payload_count_(0),
- payload_size_(0),
- payload_(std::make_unique<uint8_t[]>(MAX_EVENT_PAYLOAD_SIZE)) {
- memset(payload_.get(), 0, MAX_EVENT_PAYLOAD_SIZE);
-
- // Set up the top-level EventLog data type.
- AppendByte(EVENT_TYPE_LIST);
-
- // Skip over the byte prepresenting the number of items in the list. This
- // value is set in Release().
- payload_size_++;
-}
-
-bool EventLogListBuilder::Append(int value) {
- DCHECK_NE(static_cast<uint8_t*>(nullptr), payload_.get());
-
- if (!IsSpaceAvailable(sizeof(value) + EVENT_TYPE_SIZE)) {
- return false;
- }
-
- AppendByte(EVENT_TYPE_INT);
- AppendData(&value, sizeof(value));
-
- payload_count_++;
- return true;
-}
-
-bool EventLogListBuilder::Append(const std::string& value) {
- DCHECK_NE(static_cast<uint8_t*>(nullptr), payload_.get());
-
- int len = value.length();
- if (!IsSpaceAvailable(sizeof(len) + len)) {
- return false;
- }
-
- AppendByte(EVENT_TYPE_STRING);
- AppendData(&len, sizeof(len));
- AppendData(value.c_str(), len);
-
- payload_count_++;
- return true;
-}
-
-void EventLogListBuilder::Release(std::unique_ptr<uint8_t[]>* log,
- size_t* size) {
- // Finalize the log payload.
- payload_[1] = payload_count_;
-
- // Return the log payload.
- *size = payload_size_;
- *log = std::move(payload_);
-}
-
-void EventLogListBuilder::AppendData(const void* data, size_t size) {
- DCHECK_LT(payload_size_ + size, MAX_EVENT_PAYLOAD_SIZE);
- memcpy(&payload_[payload_size_], data, size);
- payload_size_ += size;
-}
-
-void EventLogListBuilder::AppendByte(uint8_t byte) {
- DCHECK_LT(payload_size_ + sizeof(byte), MAX_EVENT_PAYLOAD_SIZE);
- payload_[payload_size_++] = byte;
-}
-
-bool EventLogListBuilder::IsSpaceAvailable(size_t value_size) {
- size_t space_needed = value_size + EVENT_TYPE_SIZE;
- if (payload_size_ + space_needed > MAX_EVENT_PAYLOAD_SIZE) {
- size_t remaining = MAX_EVENT_PAYLOAD_SIZE - payload_size_;
- LOG(WARNING) << "Not enough space for value. remain=" <<
- remaining << "; needed=" << space_needed;
- return false;
- }
-
- return true;
-}
diff --git a/bootstat/event_log_list_builder.h b/bootstat/event_log_list_builder.h
deleted file mode 100644
index 4e29b01..0000000
--- a/bootstat/event_log_list_builder.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef EVENT_LOG_LIST_BUILDER_H_
-#define EVENT_LOG_LIST_BUILDER_H_
-
-#include <cstdint>
-#include <memory>
-
-#include <android-base/macros.h>
-
-// EventLogListBuilder provides a mechanism to build an EventLog list
-// consisting of int and string EventLog values.
-//
-// NOTE: This class does not provide the ability to append an embedded list,
-// i.e., a list containing a list.
-class EventLogListBuilder {
- public:
- EventLogListBuilder();
-
- // Append a single value of a specified type.
- bool Append(int value);
- bool Append(const std::string& value);
-
- // Finalizes construction of the EventLog list and releases the data
- // to the caller. Caller takes ownership of the payload. No further calls
- // to append* may be made once the payload is acquired by the caller.
- void Release(std::unique_ptr<uint8_t[]>* log, size_t* size);
-
- private:
- // Appends |data| of the given |size| to the payload.
- void AppendData(const void* data, size_t size);
-
- // Appends a single byte to the payload.
- void AppendByte(uint8_t byte);
-
- // Returns true iff the remaining capacity in |payload_| is large enough to
- // accommodate |value_size| bytes. The space required to log the event type
- // is included in the internal calculation so must not be passed in to
- // |value_size|.
- bool IsSpaceAvailable(size_t value_size);
-
- // The number of items in the EventLog list.
- size_t payload_count_;
-
- // The size of the data stored in |payload_|. Used to track where to insert
- // new data.
- size_t payload_size_;
-
- // The payload constructed by calls to log*. The payload may only contain
- // MAX_EVENT_PAYLOAD (512) bytes.
- std::unique_ptr<uint8_t[]> payload_;
-
- DISALLOW_COPY_AND_ASSIGN(EventLogListBuilder);
-};
-
- #endif // EVENT_LOG_LIST_BUILDER_H_
diff --git a/bootstat/event_log_list_builder_test.cpp b/bootstat/event_log_list_builder_test.cpp
deleted file mode 100644
index 8f7f323..0000000
--- a/bootstat/event_log_list_builder_test.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "event_log_list_builder.h"
-
-#include <inttypes.h>
-
-#include <android/log.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-using testing::ElementsAreArray;
-
-TEST(EventLogListBuilder, Empty) {
- EventLogListBuilder builder;
-
- const uint8_t EXPECTED_LOG[] = {
- EVENT_TYPE_LIST,
- 0, // Number of items in the list.
- };
-
- std::unique_ptr<uint8_t[]> log;
- size_t size;
- builder.Release(&log, &size);
- EXPECT_EQ(2U, size);
-
- uint8_t* log_data = log.get();
- EXPECT_THAT(std::vector<uint8_t>(log_data, log_data + size),
- ElementsAreArray(EXPECTED_LOG));
-}
-
-TEST(EventLogListBuilder, SingleInt) {
- EventLogListBuilder builder;
-
- const uint8_t EXPECTED_LOG[] = {
- EVENT_TYPE_LIST,
- 1, // Number of items in the list.
- EVENT_TYPE_INT,
- 42, 0, 0, 0, // 4 byte integer value.
- };
-
- builder.Append(42);
-
- std::unique_ptr<uint8_t[]> log;
- size_t size;
- builder.Release(&log, &size);
- EXPECT_EQ(7U, size);
-
- uint8_t* log_data = log.get();
- EXPECT_THAT(std::vector<uint8_t>(log_data, log_data + size),
- ElementsAreArray(EXPECTED_LOG));
-}
-
-TEST(EventLogListBuilder, SingleString) {
- EventLogListBuilder builder;
-
- const uint8_t EXPECTED_LOG[] = {
- EVENT_TYPE_LIST,
- 1, // Number of items in the list.
- EVENT_TYPE_STRING,
- 5, 0, 0, 0, // 4 byte length of the string.
- 'D', 'r', 'o', 'i', 'd',
- };
-
- builder.Append("Droid");
-
- std::unique_ptr<uint8_t[]> log;
- size_t size;
- builder.Release(&log, &size);
- EXPECT_EQ(12U, size);
-
- uint8_t* log_data = log.get();
- EXPECT_THAT(std::vector<uint8_t>(log_data, log_data + size),
- ElementsAreArray(EXPECTED_LOG));
-}
-
-TEST(EventLogListBuilder, IntThenString) {
- EventLogListBuilder builder;
-
- const uint8_t EXPECTED_LOG[] = {
- EVENT_TYPE_LIST,
- 2, // Number of items in the list.
- EVENT_TYPE_INT,
- 42, 0, 0, 0, // 4 byte integer value.
- EVENT_TYPE_STRING,
- 5, 0, 0, 0, // 4 byte length of the string.
- 'D', 'r', 'o', 'i', 'd',
- };
-
- builder.Append(42);
- builder.Append("Droid");
-
- std::unique_ptr<uint8_t[]> log;
- size_t size;
- builder.Release(&log, &size);
- EXPECT_EQ(17U, size);
-
- uint8_t* log_data = log.get();
- EXPECT_THAT(std::vector<uint8_t>(log_data, log_data + size),
- ElementsAreArray(EXPECTED_LOG));
-}
diff --git a/bootstat/histogram_logger.cpp b/bootstat/histogram_logger.cpp
index 3144d8b..6a9ef2b 100644
--- a/bootstat/histogram_logger.cpp
+++ b/bootstat/histogram_logger.cpp
@@ -17,27 +17,16 @@
#include "histogram_logger.h"
#include <cstdlib>
-#include <memory>
-#include <android/log.h>
#include <android-base/logging.h>
-
-#include "event_log_list_builder.h"
+#include <log/log.h>
namespace bootstat {
void LogHistogram(const std::string& event, int32_t data) {
LOG(INFO) << "Logging histogram: " << event << " " << data;
-
- EventLogListBuilder log_builder;
- log_builder.Append(event);
- log_builder.Append(data);
-
- std::unique_ptr<uint8_t[]> log;
- size_t size;
- log_builder.Release(&log, &size);
-
- android_bWriteLog(HISTOGRAM_LOG_TAG, log.get(), size);
+ android_log_event_context log(HISTOGRAM_LOG_TAG);
+ log << event << data << LOG_ID_EVENTS;
}
} // namespace bootstat
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index fdedb76..155b309 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -1,7 +1,6 @@
LOCAL_PATH := $(call my-dir)
common_cppflags := \
- -std=gnu++11 \
-W \
-Wall \
-Wextra \
@@ -121,6 +120,7 @@
libbacktrace \
libbase \
libcutils \
+ liblog
debuggerd_c_includes := \
$(LOCAL_PATH)/test \
diff --git a/debuggerd/crasher.cpp b/debuggerd/crasher.cpp
index cfcc26e..b0e8b17 100644
--- a/debuggerd/crasher.cpp
+++ b/debuggerd/crasher.cpp
@@ -1,3 +1,21 @@
+/*
+ * Copyright 2006, 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 "crasher"
+
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
@@ -142,7 +160,11 @@
{
fprintf(stderr, "%s: init pid=%d tid=%d\n", __progname, getpid(), gettid());
- if (!strncmp(arg, "exhaustfd-", strlen("exhaustfd-"))) {
+ if (!strncmp(arg, "wait-", strlen("wait-"))) {
+ char buf[1];
+ TEMP_FAILURE_RETRY(read(STDIN_FILENO, buf, sizeof(buf)));
+ return do_action(arg + strlen("wait-"));
+ } else if (!strncmp(arg, "exhaustfd-", strlen("exhaustfd-"))) {
errno = 0;
while (errno != EMFILE) {
open("/dev/null", O_RDONLY);
@@ -217,6 +239,8 @@
fprintf(stderr, "on the process' main thread.\n");
fprintf(stderr, "prefix any of the above with 'exhaustfd-' to exhaust\n");
fprintf(stderr, "all available file descriptors before crashing.\n");
+ fprintf(stderr, "prefix any of the above with 'wait-' to wait until input is received on stdin\n");
+
return EXIT_SUCCESS;
}
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index b8a62a5..5ae66db 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "debuggerd"
+
#include <arpa/inet.h>
#include <dirent.h>
#include <elf.h>
diff --git a/debuggerd/getevent.cpp b/debuggerd/getevent.cpp
index dfa7bec..dbb878a 100644
--- a/debuggerd/getevent.cpp
+++ b/debuggerd/getevent.cpp
@@ -26,6 +26,7 @@
#include <sys/ioctl.h>
#include <sys/limits.h>
#include <sys/poll.h>
+#include <unistd.h>
#include <memory>
diff --git a/debuggerd/signal_sender.cpp b/debuggerd/signal_sender.cpp
index 3adbef2..7fe4dee 100644
--- a/debuggerd/signal_sender.cpp
+++ b/debuggerd/signal_sender.cpp
@@ -14,7 +14,10 @@
* limitations under the License.
*/
+#define LOG_TAG "debuggerd-signal"
+
#include <errno.h>
+#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
diff --git a/debuggerd/test/log_fake.cpp b/debuggerd/test/log_fake.cpp
index 59910ad..3336bcb 100644
--- a/debuggerd/test/log_fake.cpp
+++ b/debuggerd/test/log_fake.cpp
@@ -19,8 +19,8 @@
#include <string>
-#include <android/log.h>
#include <android-base/stringprintf.h>
+#include <log/log.h>
// Forward declarations.
class Backtrace;
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index c87182e..1e47483 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -32,13 +32,14 @@
#include <memory>
#include <string>
-#include <android/log.h>
#include <android-base/stringprintf.h>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
#include <cutils/properties.h>
+#include <log/log.h>
#include <log/logprint.h>
#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
#include <selinux/android.h>
@@ -575,9 +576,9 @@
AndroidLogEntry e;
char buf[512];
android_log_processBinaryLogBuffer(entry, &e, g_eventTagMap, buf, sizeof(buf));
- _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8s: %s\n",
+ _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8.*s: %s\n",
timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
- 'I', e.tag, e.message);
+ 'I', (int)e.tagLen, e.tag, e.message);
continue;
}
@@ -622,9 +623,7 @@
static void dump_crash(log_t* log, BacktraceMap* map, pid_t pid, pid_t tid,
const std::set<pid_t>& siblings, uintptr_t abort_msg_address) {
// don't copy log messages to tombstone unless this is a dev device
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.debuggable", value, "0");
- bool want_logs = (value[0] == '1');
+ bool want_logs = __android_log_is_debuggable();
_LOG(log, logtype::HEADER,
"*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index e334e71..419d36c 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -27,9 +27,9 @@
#include <string>
-#include <android/log.h>
#include <android-base/stringprintf.h>
#include <backtrace/Backtrace.h>
+#include <log/log.h>
// Whitelist output desired in the logcat output.
bool is_allowed_in_logcat(enum logtype ltype) {
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index d69a81f..286de5b 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -37,7 +37,6 @@
LOCAL_MODULE := fastboot
LOCAL_MODULE_TAGS := debug
LOCAL_MODULE_HOST_OS := darwin linux windows
-LOCAL_CONLYFLAGS += -std=gnu99
LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
LOCAL_CFLAGS += -DFASTBOOT_REVISION='"$(fastboot_version)"'
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index d6b631f..4cd423a 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -755,7 +755,7 @@
max_download_size = android::base::Trim(max_download_size);
uint64_t limit;
- if (!android::base::ParseUint(max_download_size.c_str(), &limit)) {
+ if (!android::base::ParseUint(max_download_size, &limit)) {
fprintf(stderr, "couldn't parse max-download-size '%s'\n", max_download_size.c_str());
return 0;
}
@@ -903,7 +903,7 @@
if (!fb_getvar(transport, "slot-count", &var)) {
if (supports_AB_obsolete(transport)) return 2; // Legacy support
}
- if (!android::base::ParseInt(var.c_str(), &count)) return 0;
+ if (!android::base::ParseInt(var, &count)) return 0;
return count;
}
@@ -1362,7 +1362,7 @@
}
int64_t size;
- if (!android::base::ParseInt(partition_size.c_str(), &size)) {
+ if (!android::base::ParseInt(partition_size, &size)) {
fprintf(stderr, "Couldn't parse partition size '%s'.\n", partition_size.c_str());
return;
}
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 2ed6b91..b1511fe 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -41,6 +41,7 @@
#include <linux/loop.h>
#include <logwrap/logwrap.h>
#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
#include "fs_mgr_priv.h"
#include "fs_mgr_priv_verity.h"
@@ -240,7 +241,7 @@
return ret;
}
-static int fs_match(char *in1, char *in2)
+static int fs_match(const char *in1, const char *in2)
{
char *n1;
char *n2;
@@ -260,15 +261,6 @@
return ret;
}
-static int device_is_debuggable() {
- int ret = -1;
- char value[PROP_VALUE_MAX];
- ret = __system_property_get("ro.debuggable", value);
- if (ret < 0)
- return ret;
- return strcmp(value, "1") ? 0 : 1;
-}
-
static int device_is_secure() {
int ret = -1;
char value[PROP_VALUE_MAX];
@@ -537,7 +529,7 @@
if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
int rc = fs_mgr_setup_verity(&fstab->recs[i]);
- if (device_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
+ if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
INFO("Verity disabled");
} else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) {
ERROR("Could not set up verified partition, skipping!\n");
@@ -659,7 +651,7 @@
* If multiple fstab entries are to be mounted on "n_name", it will try to mount each one
* in turn, and stop on 1st success, or no more match.
*/
-int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
+int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
char *tmp_mount_point)
{
int i = 0;
@@ -699,7 +691,7 @@
if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
int rc = fs_mgr_setup_verity(&fstab->recs[i]);
- if (device_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
+ if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
INFO("Verity disabled");
} else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) {
ERROR("Could not set up verified partition, skipping!\n");
@@ -903,7 +895,7 @@
{
if ((fstab_rec->fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
int rc = fs_mgr_setup_verity(fstab_rec);
- if (device_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
+ if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
INFO("Verity disabled");
return FS_MGR_EARLY_SETUP_VERITY_NO_VERITY;
} else if (rc == FS_MGR_SETUP_VERITY_SUCCESS) {
diff --git a/fs_mgr/fs_mgr_main.c b/fs_mgr/fs_mgr_main.c
index 33a7496..4bfe202 100644
--- a/fs_mgr/fs_mgr_main.c
+++ b/fs_mgr/fs_mgr_main.c
@@ -14,12 +14,17 @@
* limitations under the License.
*/
+#define _GNU_SOURCE
+
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
-#include <libgen.h>
#include "fs_mgr_priv.h"
+#ifdef _LIBGEN_H
+#warning "libgen.h must not be included"
+#endif
+
char *me = "";
static void usage(void)
@@ -32,10 +37,10 @@
* and exit the program, do not return to the caller.
* Return the number of argv[] entries consumed.
*/
-static void parse_options(int argc, char *argv[], int *a_flag, int *u_flag, int *n_flag,
- char **n_name, char **n_blk_dev)
+static void parse_options(int argc, char * const argv[], int *a_flag, int *u_flag, int *n_flag,
+ const char **n_name, const char **n_blk_dev)
{
- me = basename(strdup(argv[0]));
+ me = basename(argv[0]);
if (argc <= 1) {
usage();
@@ -75,14 +80,14 @@
return;
}
-int main(int argc, char *argv[])
+int main(int argc, char * const argv[])
{
int a_flag=0;
int u_flag=0;
int n_flag=0;
- char *n_name=NULL;
- char *n_blk_dev=NULL;
- char *fstab_file=NULL;
+ const char *n_name=NULL;
+ const char *n_blk_dev=NULL;
+ const char *fstab_file=NULL;
struct fstab *fstab=NULL;
klog_set_level(6);
@@ -97,7 +102,7 @@
if (a_flag) {
return fs_mgr_mount_all(fstab, MOUNT_MODE_DEFAULT);
} else if (n_flag) {
- return fs_mgr_do_mount(fstab, n_name, n_blk_dev, 0);
+ return fs_mgr_do_mount(fstab, n_name, (char *)n_blk_dev, 0);
} else if (u_flag) {
return fs_mgr_unmount_all(fstab);
} else {
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 767b3b3..67104cc 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -341,6 +341,17 @@
return 0;
}
+static int test_access(char *device) {
+ int tries = 25;
+ while (tries--) {
+ if (!access(device, F_OK) || errno != ENOENT) {
+ return 0;
+ }
+ usleep(40 * 1000);
+ }
+ return -1;
+}
+
static int check_verity_restart(const char *fname)
{
char buffer[VERITY_KMSG_BUFSIZE + 1];
@@ -1020,6 +1031,11 @@
fstab->blk_device = verity_blk_name;
verity_blk_name = 0;
+ // make sure we've set everything up properly
+ if (test_access(fstab->blk_device) < 0) {
+ goto out;
+ }
+
retval = FS_MGR_SETUP_VERITY_SUCCESS;
out:
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index c0116ef..b120f7c 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -95,7 +95,7 @@
#define FS_MGR_DOMNT_FAILED (-1)
#define FS_MGR_DOMNT_BUSY (-2)
-int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
+int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
char *tmp_mount_point);
int fs_mgr_do_tmpfs_mount(char *n_name);
int fs_mgr_unmount_all(struct fstab *fstab);
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index f81e7d9..0c90a54 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -29,6 +29,7 @@
#include <memory>
#include <android-base/file.h>
+#include <android-base/parseint.h>
#include <android-base/strings.h>
#include <batteryservice/BatteryService.h>
#include <cutils/klog.h>
@@ -182,7 +183,7 @@
int value = 0;
if (readFromFile(path, &buf) > 0)
- value = std::stoi(buf.c_str(), NULL, 0);
+ android::base::ParseInt(buf, &value);
return value;
}
diff --git a/include/android/log.h b/include/android/log.h
index 9b26839..5673357 100644
--- a/include/android/log.h
+++ b/include/android/log.h
@@ -67,25 +67,55 @@
* NOTE: These functions MUST be implemented by /system/lib/liblog.so
*/
-#if !defined(_WIN32)
-#include <pthread.h>
-#endif
#include <stdarg.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <log/uio.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
+ * This file uses ", ## __VA_ARGS__" zero-argument token pasting to
+ * work around issues with debug-only syntax errors in assertions
+ * that are missing format strings. See commit
+ * 19299904343daf191267564fe32e6cd5c165cd42
+ */
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
+#endif
+
+#ifndef __predict_false
+#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
+#endif
+
+/*
+ * LOG_TAG is the local tag used for the following simplified
+ * logging macros. You must set this preprocessor definition,
+ * or more tenuously supply a variable definition, before using
+ * the macros.
+ */
+
+/*
+ * Normally we strip the effects of ALOGV (VERBOSE messages),
+ * LOG_FATAL and LOG_FATAL_IF (FATAL assert messages) from the
+ * release builds be defining NDEBUG. You can modify this (for
+ * example with "#define LOG_NDEBUG 0" at the top of your source
+ * file) to change that behavior.
+ */
+
+#ifndef LOG_NDEBUG
+#ifdef NDEBUG
+#define LOG_NDEBUG 1
+#else
+#define LOG_NDEBUG 0
+#endif
+#endif
+
+/*
* Android log priority values, in ascending priority order.
*/
+#ifndef __android_LogPriority_defined
+#define __android_LogPriority_defined
typedef enum android_LogPriority {
ANDROID_LOG_UNKNOWN = 0,
ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */
@@ -97,21 +127,20 @@
ANDROID_LOG_FATAL,
ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
} android_LogPriority;
-
-/*
- * Release any logger resources (a new log write will immediately re-acquire)
- */
-void __android_log_close();
+#endif
/*
* Send a simple string to the log.
*/
-int __android_log_write(int prio, const char *tag, const char *text);
+int __android_log_write(int prio, const char* tag, const char* text);
+
+#define android_writeLog(prio, tag, text) \
+ __android_log_write(prio, tag, text)
/*
* Send a formatted string to the log, used like printf(fmt,...)
*/
-int __android_log_print(int prio, const char *tag, const char *fmt, ...)
+int __android_log_print(int prio, const char* tag, const char* fmt, ...)
#if defined(__GNUC__)
#ifdef __USE_MINGW_ANSI_STDIO
#if __USE_MINGW_ANSI_STDIO
@@ -125,19 +154,53 @@
#endif
;
+#define android_printLog(prio, tag, ...) \
+ __android_log_print(prio, tag, __VA_ARGS__)
+
+/*
+ * Log macro that allows you to specify a number for the priority.
+ */
+#ifndef LOG_PRI
+#define LOG_PRI(priority, tag, ...) \
+ android_printLog(priority, tag, __VA_ARGS__)
+#endif
+
/*
* A variant of __android_log_print() that takes a va_list to list
* additional parameters.
*/
-int __android_log_vprint(int prio, const char *tag,
- const char *fmt, va_list ap);
+int __android_log_vprint(int prio, const char* tag,
+ const char* fmt, va_list ap)
+#if defined(__GNUC__)
+#ifdef __USE_MINGW_ANSI_STDIO
+#if __USE_MINGW_ANSI_STDIO
+ __attribute__ ((format(gnu_printf, 3, 0)))
+#else
+ __attribute__ ((format(printf, 3, 0)))
+#endif
+#else
+ __attribute__ ((format(printf, 3, 0)))
+#endif
+#endif
+ ;
+
+#define android_vprintLog(prio, cond, tag, ...) \
+ __android_log_vprint(prio, tag, __VA_ARGS__)
+
+/*
+ * Log macro that allows you to pass in a varargs ("args" is a va_list).
+ */
+#ifndef LOG_PRI_VA
+#define LOG_PRI_VA(priority, tag, fmt, args) \
+ android_vprintLog(priority, NULL, tag, fmt, args)
+#endif
/*
* Log an assertion failure and abort the process to have a chance
* to inspect it if a debugger is attached. This uses the FATAL priority.
*/
-void __android_log_assert(const char *cond, const char *tag,
- const char *fmt, ...)
+void __android_log_assert(const char* cond, const char* tag,
+ const char* fmt, ...)
#if defined(__GNUC__)
__attribute__ ((__noreturn__))
#ifdef __USE_MINGW_ANSI_STDIO
@@ -152,74 +215,91 @@
#endif
;
-//
-// C/C++ logging functions. See the logging documentation for API details.
-//
-// We'd like these to be available from C code (in case we import some from
-// somewhere), so this has a C interface.
-//
-// The output will be correct when the log file is shared between multiple
-// threads and/or multiple processes so long as the operating system
-// supports O_APPEND. These calls have mutex-protected data structures
-// and so are NOT reentrant. Do not use LOG in a signal handler.
-//
+/* XXX Macros to work around syntax errors in places where format string
+ * arg is not passed to ALOG_ASSERT, LOG_ALWAYS_FATAL or LOG_ALWAYS_FATAL_IF
+ * (happens only in debug builds).
+ */
-// This file uses ", ## __VA_ARGS__" zero-argument token pasting to
-// work around issues with debug-only syntax errors in assertions
-// that are missing format strings. See commit
-// 19299904343daf191267564fe32e6cd5c165cd42
-#if defined(__clang__)
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
-#endif
+/* Returns 2nd arg. Used to substitute default value if caller's vararg list
+ * is empty.
+ */
+#define __android_second(dummy, second, ...) second
-int __android_log_bwrite(int32_t tag, const void *payload, size_t len);
-int __android_log_btwrite(int32_t tag, char type, const void *payload,
- size_t len);
-int __android_log_bswrite(int32_t tag, const char *payload);
+/* If passed multiple args, returns ',' followed by all but 1st arg, otherwise
+ * returns nothing.
+ */
+#define __android_rest(first, ...) , ## __VA_ARGS__
-// ---------------------------------------------------------------------
+#define android_printAssert(cond, tag, ...) \
+ __android_log_assert(cond, tag, \
+ __android_second(0, ## __VA_ARGS__, NULL) __android_rest(__VA_ARGS__))
/*
- * Normally we strip ALOGV (VERBOSE messages) from release builds.
- * You can modify this (for example with "#define LOG_NDEBUG 0"
- * at the top of your source file) to change that behavior.
+ * Log a fatal error. If the given condition fails, this stops program
+ * execution like a normal assertion, but also generating the given message.
+ * It is NOT stripped from release builds. Note that the condition test
+ * is -inverted- from the normal assert() semantics.
*/
-#ifndef LOG_NDEBUG
-#ifdef NDEBUG
-#define LOG_NDEBUG 1
+#ifndef LOG_ALWAYS_FATAL_IF
+#define LOG_ALWAYS_FATAL_IF(cond, ...) \
+ ( (__predict_false(cond)) \
+ ? ((void)android_printAssert(#cond, LOG_TAG, ## __VA_ARGS__)) \
+ : (void)0 )
+#endif
+
+#ifndef LOG_ALWAYS_FATAL
+#define LOG_ALWAYS_FATAL(...) \
+ ( ((void)android_printAssert(NULL, LOG_TAG, ## __VA_ARGS__)) )
+#endif
+
+/*
+ * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that
+ * are stripped out of release builds.
+ */
+
+#if LOG_NDEBUG
+
+#ifndef LOG_FATAL_IF
+#define LOG_FATAL_IF(cond, ...) ((void)0)
+#endif
+#ifndef LOG_FATAL
+#define LOG_FATAL(...) ((void)0)
+#endif
+
#else
-#define LOG_NDEBUG 0
+
+#ifndef LOG_FATAL_IF
+#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ## __VA_ARGS__)
#endif
+#ifndef LOG_FATAL
+#define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__)
+#endif
+
#endif
/*
- * This is the local tag used for the following simplified
- * logging macros. You can change this preprocessor definition
- * before using the other macros to change the tag.
+ * Assertion that generates a log message when the assertion fails.
+ * Stripped out of release builds. Uses the current LOG_TAG.
*/
-#ifndef LOG_TAG
-#define LOG_TAG NULL
+#ifndef ALOG_ASSERT
+#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__)
#endif
-// ---------------------------------------------------------------------
-
-#ifndef __predict_false
-#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
-#endif
+/* --------------------------------------------------------------------- */
/*
- * -DLINT_RLOG in sources that you want to enforce that all logging
- * goes to the radio log buffer. If any logging goes to any of the other
- * log buffers, there will be a compile or link error to highlight the
- * problem. This is not a replacement for a full audit of the code since
- * this only catches compiled code, not ifdef'd debug code. Options to
- * defining this, either temporarily to do a spot check, or permanently
- * to enforce, in all the communications trees; We have hopes to ensure
- * that by supplying just the radio log buffer that the communications
- * teams will have their one-stop shop for triaging issues.
+ * C/C++ logging functions. See the logging documentation for API details.
+ *
+ * We'd like these to be available from C code (in case we import some from
+ * somewhere), so this has a C interface.
+ *
+ * The output will be correct when the log file is shared between multiple
+ * threads and/or multiple processes so long as the operating system
+ * supports O_APPEND. These calls have mutex-protected data structures
+ * and so are NOT reentrant. Do not use LOG in a signal handler.
*/
-#ifndef LINT_RLOG
+
+/* --------------------------------------------------------------------- */
/*
* Simplified macro to send a verbose log message using the current LOG_TAG.
@@ -300,7 +380,7 @@
: (void)0 )
#endif
-// ---------------------------------------------------------------------
+/* --------------------------------------------------------------------- */
/*
* Conditional based on whether the current LOG_TAG is enabled at
@@ -346,236 +426,7 @@
#define IF_ALOGE() IF_ALOG(LOG_ERROR, LOG_TAG)
#endif
-
-// ---------------------------------------------------------------------
-
-/*
- * Simplified macro to send a verbose system log message using the current LOG_TAG.
- */
-#ifndef SLOGV
-#define __SLOGV(...) \
- ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
-#if LOG_NDEBUG
-#define SLOGV(...) do { if (0) { __SLOGV(__VA_ARGS__); } } while (0)
-#else
-#define SLOGV(...) __SLOGV(__VA_ARGS__)
-#endif
-#endif
-
-#ifndef SLOGV_IF
-#if LOG_NDEBUG
-#define SLOGV_IF(cond, ...) ((void)0)
-#else
-#define SLOGV_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
-#endif
-#endif
-
-/*
- * Simplified macro to send a debug system log message using the current LOG_TAG.
- */
-#ifndef SLOGD
-#define SLOGD(...) \
- ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef SLOGD_IF
-#define SLOGD_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
-#endif
-
-/*
- * Simplified macro to send an info system log message using the current LOG_TAG.
- */
-#ifndef SLOGI
-#define SLOGI(...) \
- ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef SLOGI_IF
-#define SLOGI_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
-#endif
-
-/*
- * Simplified macro to send a warning system log message using the current LOG_TAG.
- */
-#ifndef SLOGW
-#define SLOGW(...) \
- ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef SLOGW_IF
-#define SLOGW_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
-#endif
-
-/*
- * Simplified macro to send an error system log message using the current LOG_TAG.
- */
-#ifndef SLOGE
-#define SLOGE(...) \
- ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef SLOGE_IF
-#define SLOGE_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
-#endif
-
-#endif /* !LINT_RLOG */
-
-// ---------------------------------------------------------------------
-
-/*
- * Simplified macro to send a verbose radio log message using the current LOG_TAG.
- */
-#ifndef RLOGV
-#define __RLOGV(...) \
- ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
-#if LOG_NDEBUG
-#define RLOGV(...) do { if (0) { __RLOGV(__VA_ARGS__); } } while (0)
-#else
-#define RLOGV(...) __RLOGV(__VA_ARGS__)
-#endif
-#endif
-
-#ifndef RLOGV_IF
-#if LOG_NDEBUG
-#define RLOGV_IF(cond, ...) ((void)0)
-#else
-#define RLOGV_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
-#endif
-#endif
-
-/*
- * Simplified macro to send a debug radio log message using the current LOG_TAG.
- */
-#ifndef RLOGD
-#define RLOGD(...) \
- ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef RLOGD_IF
-#define RLOGD_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
-#endif
-
-/*
- * Simplified macro to send an info radio log message using the current LOG_TAG.
- */
-#ifndef RLOGI
-#define RLOGI(...) \
- ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef RLOGI_IF
-#define RLOGI_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
-#endif
-
-/*
- * Simplified macro to send a warning radio log message using the current LOG_TAG.
- */
-#ifndef RLOGW
-#define RLOGW(...) \
- ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef RLOGW_IF
-#define RLOGW_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
-#endif
-
-/*
- * Simplified macro to send an error radio log message using the current LOG_TAG.
- */
-#ifndef RLOGE
-#define RLOGE(...) \
- ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef RLOGE_IF
-#define RLOGE_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
-#endif
-
-
-// ---------------------------------------------------------------------
-
-/*
- * Log a fatal error. If the given condition fails, this stops program
- * execution like a normal assertion, but also generating the given message.
- * It is NOT stripped from release builds. Note that the condition test
- * is -inverted- from the normal assert() semantics.
- */
-#ifndef LOG_ALWAYS_FATAL_IF
-#define LOG_ALWAYS_FATAL_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)android_printAssert(#cond, LOG_TAG, ## __VA_ARGS__)) \
- : (void)0 )
-#endif
-
-#ifndef LOG_ALWAYS_FATAL
-#define LOG_ALWAYS_FATAL(...) \
- ( ((void)android_printAssert(NULL, LOG_TAG, ## __VA_ARGS__)) )
-#endif
-
-/*
- * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that
- * are stripped out of release builds.
- */
-#if LOG_NDEBUG
-
-#ifndef LOG_FATAL_IF
-#define LOG_FATAL_IF(cond, ...) ((void)0)
-#endif
-#ifndef LOG_FATAL
-#define LOG_FATAL(...) ((void)0)
-#endif
-
-#else
-
-#ifndef LOG_FATAL_IF
-#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ## __VA_ARGS__)
-#endif
-#ifndef LOG_FATAL
-#define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__)
-#endif
-
-#endif
-
-/*
- * Assertion that generates a log message when the assertion fails.
- * Stripped out of release builds. Uses the current LOG_TAG.
- */
-#ifndef ALOG_ASSERT
-#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__)
-//#define ALOG_ASSERT(cond) LOG_FATAL_IF(!(cond), "Assertion failed: " #cond)
-#endif
-
-// ---------------------------------------------------------------------
+/* --------------------------------------------------------------------- */
/*
* Basic log message macro.
@@ -591,22 +442,6 @@
#endif
/*
- * Log macro that allows you to specify a number for the priority.
- */
-#ifndef LOG_PRI
-#define LOG_PRI(priority, tag, ...) \
- android_printLog(priority, tag, __VA_ARGS__)
-#endif
-
-/*
- * Log macro that allows you to pass in a varargs ("args" is a va_list).
- */
-#ifndef LOG_PRI_VA
-#define LOG_PRI_VA(priority, tag, fmt, args) \
- android_vprintLog(priority, NULL, tag, fmt, args)
-#endif
-
-/*
* Conditional given a desired logging priority and tag.
*/
#ifndef IF_ALOG
@@ -614,181 +449,7 @@
if (android_testLog(ANDROID_##priority, tag))
#endif
-// ---------------------------------------------------------------------
-
-/*
- * Event logging.
- */
-
-/*
- * Event log entry types.
- */
-typedef enum {
- /* Special markers for android_log_list_element type */
- EVENT_TYPE_LIST_STOP = '\n', /* declare end of list */
- EVENT_TYPE_UNKNOWN = '?', /* protocol error */
-
- /* must match with declaration in java/android/android/util/EventLog.java */
- EVENT_TYPE_INT = 0, /* uint32_t */
- EVENT_TYPE_LONG = 1, /* uint64_t */
- EVENT_TYPE_STRING = 2,
- EVENT_TYPE_LIST = 3,
- EVENT_TYPE_FLOAT = 4,
-} AndroidEventLogType;
-#define sizeof_AndroidEventLogType sizeof(typeof_AndroidEventLogType)
-#define typeof_AndroidEventLogType unsigned char
-
-#ifndef LOG_EVENT_INT
-#define LOG_EVENT_INT(_tag, _value) { \
- int intBuf = _value; \
- (void) android_btWriteLog(_tag, EVENT_TYPE_INT, &intBuf, \
- sizeof(intBuf)); \
- }
-#endif
-#ifndef LOG_EVENT_LONG
-#define LOG_EVENT_LONG(_tag, _value) { \
- long long longBuf = _value; \
- (void) android_btWriteLog(_tag, EVENT_TYPE_LONG, &longBuf, \
- sizeof(longBuf)); \
- }
-#endif
-#ifndef LOG_EVENT_FLOAT
-#define LOG_EVENT_FLOAT(_tag, _value) { \
- float floatBuf = _value; \
- (void) android_btWriteLog(_tag, EVENT_TYPE_FLOAT, &floatBuf, \
- sizeof(floatBuf)); \
- }
-#endif
-#ifndef LOG_EVENT_STRING
-#define LOG_EVENT_STRING(_tag, _value) \
- (void) __android_log_bswrite(_tag, _value);
-#endif
-
-typedef enum log_id {
- LOG_ID_MIN = 0,
-
-#ifndef LINT_RLOG
- LOG_ID_MAIN = 0,
-#endif
- LOG_ID_RADIO = 1,
-#ifndef LINT_RLOG
- LOG_ID_EVENTS = 2,
- LOG_ID_SYSTEM = 3,
- LOG_ID_CRASH = 4,
- LOG_ID_SECURITY = 5,
- LOG_ID_KERNEL = 6, /* place last, third-parties can not use it */
-#endif
-
- LOG_ID_MAX
-} log_id_t;
-#define sizeof_log_id_t sizeof(typeof_log_id_t)
-#define typeof_log_id_t unsigned char
-
-/* For manipulating lists of events. */
-
-#define ANDROID_MAX_LIST_NEST_DEPTH 8
-
-/*
- * The opaque context used to manipulate lists of events.
- */
-typedef struct android_log_context_internal *android_log_context;
-
-/*
- * Elements returned when reading a list of events.
- */
-typedef struct {
- AndroidEventLogType type;
- uint16_t complete;
- uint16_t len;
- union {
- int32_t int32;
- int64_t int64;
- char *string;
- float float32;
- } data;
-} android_log_list_element;
-
-/*
- * Creates a context associated with an event tag to write elements to
- * the list of events.
- */
-android_log_context create_android_logger(uint32_t tag);
-
-/* All lists must be braced by a begin and end call */
-/*
- * NB: If the first level braces are missing when specifying multiple
- * elements, we will manufacturer a list to embrace it for your API
- * convenience. For a single element, it will remain solitary.
- */
-int android_log_write_list_begin(android_log_context ctx);
-int android_log_write_list_end(android_log_context ctx);
-
-int android_log_write_int32(android_log_context ctx, int32_t value);
-int android_log_write_int64(android_log_context ctx, int64_t value);
-int android_log_write_string8(android_log_context ctx, const char *value);
-int android_log_write_string8_len(android_log_context ctx,
- const char *value, size_t maxlen);
-int android_log_write_float32(android_log_context ctx, float value);
-
-/* Submit the composed list context to the specified logger id */
-/* NB: LOG_ID_EVENTS and LOG_ID_SECURITY only valid binary buffers */
-int android_log_write_list(android_log_context ctx, log_id_t id);
-
-/*
- * Creates a context from a raw buffer representing a list of events to be read.
- */
-android_log_context create_android_log_parser(const char *msg, size_t len);
-
-android_log_list_element android_log_read_next(android_log_context ctx);
-android_log_list_element android_log_peek_next(android_log_context ctx);
-
-/* Finished with reader or writer context */
-int android_log_destroy(android_log_context *ctx);
-
-/*
- * ===========================================================================
- *
- * The stuff in the rest of this file should not be used directly.
- */
-
-#define android_printLog(prio, tag, ...) \
- __android_log_print(prio, tag, __VA_ARGS__)
-
-#define android_vprintLog(prio, cond, tag, ...) \
- __android_log_vprint(prio, tag, __VA_ARGS__)
-
-/* XXX Macros to work around syntax errors in places where format string
- * arg is not passed to ALOG_ASSERT, LOG_ALWAYS_FATAL or LOG_ALWAYS_FATAL_IF
- * (happens only in debug builds).
- */
-
-/* Returns 2nd arg. Used to substitute default value if caller's vararg list
- * is empty.
- */
-#define __android_second(dummy, second, ...) second
-
-/* If passed multiple args, returns ',' followed by all but 1st arg, otherwise
- * returns nothing.
- */
-#define __android_rest(first, ...) , ## __VA_ARGS__
-
-#define android_printAssert(cond, tag, ...) \
- __android_log_assert(cond, tag, \
- __android_second(0, ## __VA_ARGS__, NULL) __android_rest(__VA_ARGS__))
-
-#define android_writeLog(prio, tag, text) \
- __android_log_write(prio, tag, text)
-
-#define android_bWriteLog(tag, payload, len) \
- __android_log_bwrite(tag, payload, len)
-#define android_btWriteLog(tag, type, payload, len) \
- __android_log_btwrite(tag, type, payload, len)
-
-#define android_errorWriteLog(tag, subTag) \
- __android_log_error_write(tag, subTag, -1, NULL, 0)
-
-#define android_errorWriteWithInfoLog(tag, subTag, uid, data, dataLen) \
- __android_log_error_write(tag, subTag, uid, data, dataLen)
+/* --------------------------------------------------------------------- */
/*
* IF_ALOG uses android_testLog, but IF_ALOG can be overridden.
@@ -798,6 +459,35 @@
* IF_ALOG as a convenient means to reimplement their policy
* over Android.
*/
+
+#ifndef __ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE
+#ifndef __ANDROID_API__
+#define __ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE 2
+#elif __ANDROID_API__ > 24 /* > Nougat */
+#define __ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE 2
+#elif __ANDROID_API__ > 22 /* > Lollipop */
+#define __ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE 1
+#else
+#define __ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE 0
+#endif
+#endif
+
+#if __ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE
+
+/*
+ * Use the per-tag properties "log.tag.<tagname>" to generate a runtime
+ * result of non-zero to expose a log. prio is ANDROID_LOG_VERBOSE to
+ * ANDROID_LOG_FATAL. default_prio if no property. Undefined behavior if
+ * any other value.
+ */
+int __android_log_is_loggable(int prio, const char* tag, int default_prio);
+
+#if __ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE > 1
+#include <sys/types.h>
+
+int __android_log_is_loggable_len(int prio, const char* tag, size_t len,
+ int default_prio);
+
#if LOG_NDEBUG /* Production */
#define android_testLog(prio, tag) \
(__android_log_is_loggable_len(prio, tag, (tag && *tag) ? strlen(tag) : 0, \
@@ -808,27 +498,23 @@
ANDROID_LOG_VERBOSE) != 0)
#endif
-/*
- * Use the per-tag properties "log.tag.<tagname>" to generate a runtime
- * result of non-zero to expose a log. prio is ANDROID_LOG_VERBOSE to
- * ANDROID_LOG_FATAL. default_prio if no property. Undefined behavior if
- * any other value.
- */
-int __android_log_is_loggable(int prio, const char *tag, int default_prio);
-int __android_log_is_loggable_len(int prio, const char *tag, size_t len, int default_prio);
+#else
-int __android_log_error_write(int tag, const char *subTag, int32_t uid, const char *data,
- uint32_t dataLen);
-
-/*
- * Send a simple string to the log.
- */
-int __android_log_buf_write(int bufID, int prio, const char *tag, const char *text);
-int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...)
-#if defined(__GNUC__)
- __attribute__((__format__(printf, 4, 5)))
+#if LOG_NDEBUG /* Production */
+#define android_testLog(prio, tag) \
+ (__android_log_is_loggable(prio, tag, ANDROID_LOG_DEBUG) != 0)
+#else
+#define android_testLog(prio, tag) \
+ (__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE) != 0)
#endif
- ;
+
+#endif
+
+#else /* __ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE */
+
+#define android_testLog(prio, tag) (1)
+
+#endif /* !__ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE */
#if defined(__clang__)
#pragma clang diagnostic pop
diff --git a/include/cutils/files.h b/include/cutils/files.h
new file mode 100644
index 0000000..0210e30
--- /dev/null
+++ b/include/cutils/files.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_FILES_H
+#define __CUTILS_FILES_H
+
+#define ANDROID_FILE_ENV_PREFIX "ANDROID_FILE_"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * android_get_control_file - simple helper function to get the file
+ * descriptor of our init-managed file. `path' is the filename path as
+ * given in init.rc. Returns -1 on error.
+ */
+int android_get_control_file(const char* path);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_FILES_H */
diff --git a/include/cutils/log.h b/include/cutils/log.h
index ffb8268..0e0248e 100644
--- a/include/cutils/log.h
+++ b/include/cutils/log.h
@@ -1 +1 @@
-#include <android/log.h>
+#include <log/log.h>
diff --git a/include/cutils/native_handle.h b/include/cutils/native_handle.h
index 813dadc..7d6a988 100644
--- a/include/cutils/native_handle.h
+++ b/include/cutils/native_handle.h
@@ -17,10 +17,17 @@
#ifndef NATIVE_HANDLE_H_
#define NATIVE_HANDLE_H_
+#include <stdalign.h>
+
#ifdef __cplusplus
extern "C" {
#endif
+/* Declare a char array for use with native_handle_init */
+#define NATIVE_HANDLE_DECLARE_STORAGE(name, maxFds, maxInts) \
+ alignas(native_handle_t) char name[ \
+ sizeof(native_handle_t) + sizeof(int) * (maxFds + maxInts)]
+
typedef struct native_handle
{
int version; /* sizeof(native_handle_t) */
@@ -46,6 +53,14 @@
*/
int native_handle_close(const native_handle_t* h);
+/*
+ * native_handle_init
+ *
+ * Initializes a native_handle_t from storage. storage must be declared with
+ * NATIVE_HANDLE_DECLARE_STORAGE. numFds and numInts must not respectively
+ * exceed maxFds and maxInts used to declare the storage.
+ */
+native_handle_t* native_handle_init(char* storage, int numFds, int numInts);
/*
* native_handle_create
diff --git a/include/cutils/sockets.h b/include/cutils/sockets.h
index a93c8ea..4626e7a 100644
--- a/include/cutils/sockets.h
+++ b/include/cutils/sockets.h
@@ -84,11 +84,11 @@
*
* These functions return INVALID_SOCKET (-1) on failure for all platforms.
*/
-int socket_loopback_client(int port, int type);
cutils_socket_t socket_network_client(const char* host, int port, int type);
int socket_network_client_timeout(const char* host, int port, int type,
int timeout, int* getaddrinfo_error);
int socket_loopback_server(int port, int type);
+int socket_loopback_server6(int port, int type);
int socket_local_server(const char* name, int namespaceId, int type);
int socket_local_server_bind(int s, const char* name, int namespaceId);
int socket_local_client_connect(int fd, const char *name, int namespaceId,
diff --git a/include/log/event_tag_map.h b/include/log/event_tag_map.h
index 69774ba..22e62ec 100644
--- a/include/log/event_tag_map.h
+++ b/include/log/event_tag_map.h
@@ -48,7 +48,15 @@
* Look up a tag by index. Returns the tag string & string length, or NULL if
* not found. Returned string is not guaranteed to be nul terminated.
*/
-const char* android_lookupEventTag_len(const EventTagMap* map, size_t* len, unsigned int tag);
+const char* android_lookupEventTag_len(const EventTagMap* map,
+ size_t* len, unsigned int tag);
+
+/*
+ * Look up a format by index. Returns the format string & string length,
+ * or NULL if not found. Returned string is not guaranteed to be nul terminated.
+ */
+const char* android_lookupEventFormat_len(const EventTagMap* map,
+ size_t* len, unsigned int tag);
#ifdef __cplusplus
}
diff --git a/include/log/log.h b/include/log/log.h
index ffb8268..a44aba8 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -1 +1,1031 @@
+/*
+ * Copyright (C) 2005-2014 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 _LIBS_LOG_LOG_H
+#define _LIBS_LOG_LOG_H
+
+/* Too many in the ecosystem assume these are included */
+#if !defined(_WIN32)
+#include <pthread.h>
+#endif
+#include <stdint.h> /* uint16_t, int32_t */
+#include <stdio.h>
+#include <sys/types.h>
+#include <time.h> /* clock_gettime */
+#include <unistd.h>
+
+#include <log/uio.h> /* helper to define iovec for portability */
+
+#if (defined(__cplusplus) && defined(_USING_LIBCXX))
+extern "C++" {
+#include <string>
+}
+#endif
+
#include <android/log.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * LOG_TAG is the local tag used for the following simplified
+ * logging macros. You can change this preprocessor definition
+ * before using the other macros to change the tag.
+ */
+
+#ifndef LOG_TAG
+#define LOG_TAG NULL
+#endif
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * This file uses ", ## __VA_ARGS__" zero-argument token pasting to
+ * work around issues with debug-only syntax errors in assertions
+ * that are missing format strings. See commit
+ * 19299904343daf191267564fe32e6cd5c165cd42
+ */
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
+#endif
+
+/*
+ * Send a simple string to the log.
+ */
+int __android_log_buf_write(int bufID, int prio, const char* tag, const char* text);
+int __android_log_buf_print(int bufID, int prio, const char* tag, const char* fmt, ...)
+#if defined(__GNUC__)
+ __attribute__((__format__(printf, 4, 5)))
+#endif
+ ;
+
+/*
+ * Simplified macro to send a verbose system log message using current LOG_TAG.
+ */
+#ifndef SLOGV
+#define __SLOGV(...) \
+ ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#if LOG_NDEBUG
+#define SLOGV(...) do { if (0) { __SLOGV(__VA_ARGS__); } } while (0)
+#else
+#define SLOGV(...) __SLOGV(__VA_ARGS__)
+#endif
+#endif
+
+#ifndef SLOGV_IF
+#if LOG_NDEBUG
+#define SLOGV_IF(cond, ...) ((void)0)
+#else
+#define SLOGV_IF(cond, ...) \
+ ( (__predict_false(cond)) \
+ ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
+ : (void)0 )
+#endif
+#endif
+
+/*
+ * Simplified macro to send a debug system log message using current LOG_TAG.
+ */
+#ifndef SLOGD
+#define SLOGD(...) \
+ ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGD_IF
+#define SLOGD_IF(cond, ...) \
+ ( (__predict_false(cond)) \
+ ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
+ : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an info system log message using current LOG_TAG.
+ */
+#ifndef SLOGI
+#define SLOGI(...) \
+ ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGI_IF
+#define SLOGI_IF(cond, ...) \
+ ( (__predict_false(cond)) \
+ ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
+ : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send a warning system log message using current LOG_TAG.
+ */
+#ifndef SLOGW
+#define SLOGW(...) \
+ ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGW_IF
+#define SLOGW_IF(cond, ...) \
+ ( (__predict_false(cond)) \
+ ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
+ : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an error system log message using current LOG_TAG.
+ */
+#ifndef SLOGE
+#define SLOGE(...) \
+ ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGE_IF
+#define SLOGE_IF(cond, ...) \
+ ( (__predict_false(cond)) \
+ ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
+ : (void)0 )
+#endif
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Simplified macro to send a verbose radio log message using current LOG_TAG.
+ */
+#ifndef RLOGV
+#define __RLOGV(...) \
+ ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#if LOG_NDEBUG
+#define RLOGV(...) do { if (0) { __RLOGV(__VA_ARGS__); } } while (0)
+#else
+#define RLOGV(...) __RLOGV(__VA_ARGS__)
+#endif
+#endif
+
+#ifndef RLOGV_IF
+#if LOG_NDEBUG
+#define RLOGV_IF(cond, ...) ((void)0)
+#else
+#define RLOGV_IF(cond, ...) \
+ ( (__predict_false(cond)) \
+ ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
+ : (void)0 )
+#endif
+#endif
+
+/*
+ * Simplified macro to send a debug radio log message using current LOG_TAG.
+ */
+#ifndef RLOGD
+#define RLOGD(...) \
+ ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef RLOGD_IF
+#define RLOGD_IF(cond, ...) \
+ ( (__predict_false(cond)) \
+ ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
+ : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an info radio log message using current LOG_TAG.
+ */
+#ifndef RLOGI
+#define RLOGI(...) \
+ ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef RLOGI_IF
+#define RLOGI_IF(cond, ...) \
+ ( (__predict_false(cond)) \
+ ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
+ : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send a warning radio log message using current LOG_TAG.
+ */
+#ifndef RLOGW
+#define RLOGW(...) \
+ ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef RLOGW_IF
+#define RLOGW_IF(cond, ...) \
+ ( (__predict_false(cond)) \
+ ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
+ : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an error radio log message using current LOG_TAG.
+ */
+#ifndef RLOGE
+#define RLOGE(...) \
+ ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef RLOGE_IF
+#define RLOGE_IF(cond, ...) \
+ ( (__predict_false(cond)) \
+ ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
+ : (void)0 )
+#endif
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Event logging.
+ */
+
+/*
+ * The following should not be used directly.
+ */
+
+int __android_log_bwrite(int32_t tag, const void* payload, size_t len);
+int __android_log_btwrite(int32_t tag, char type, const void* payload,
+ size_t len);
+int __android_log_bswrite(int32_t tag, const char* payload);
+
+#define android_bWriteLog(tag, payload, len) \
+ __android_log_bwrite(tag, payload, len)
+#define android_btWriteLog(tag, type, payload, len) \
+ __android_log_btwrite(tag, type, payload, len)
+
+/*
+ * Event log entry types.
+ */
+#ifndef __AndroidEventLogType_defined
+#define __AndroidEventLogType_defined
+typedef enum {
+ /* Special markers for android_log_list_element type */
+ EVENT_TYPE_LIST_STOP = '\n', /* declare end of list */
+ EVENT_TYPE_UNKNOWN = '?', /* protocol error */
+
+ /* must match with declaration in java/android/android/util/EventLog.java */
+ EVENT_TYPE_INT = 0, /* int32_t */
+ EVENT_TYPE_LONG = 1, /* int64_t */
+ EVENT_TYPE_STRING = 2,
+ EVENT_TYPE_LIST = 3,
+ EVENT_TYPE_FLOAT = 4,
+} AndroidEventLogType;
+#endif
+#define sizeof_AndroidEventLogType sizeof(typeof_AndroidEventLogType)
+#define typeof_AndroidEventLogType unsigned char
+
+#ifndef LOG_EVENT_INT
+#define LOG_EVENT_INT(_tag, _value) { \
+ int intBuf = _value; \
+ (void) android_btWriteLog(_tag, EVENT_TYPE_INT, &intBuf, \
+ sizeof(intBuf)); \
+ }
+#endif
+#ifndef LOG_EVENT_LONG
+#define LOG_EVENT_LONG(_tag, _value) { \
+ long long longBuf = _value; \
+ (void) android_btWriteLog(_tag, EVENT_TYPE_LONG, &longBuf, \
+ sizeof(longBuf)); \
+ }
+#endif
+#ifndef LOG_EVENT_FLOAT
+#define LOG_EVENT_FLOAT(_tag, _value) { \
+ float floatBuf = _value; \
+ (void) android_btWriteLog(_tag, EVENT_TYPE_FLOAT, &floatBuf, \
+ sizeof(floatBuf)); \
+ }
+#endif
+#ifndef LOG_EVENT_STRING
+#define LOG_EVENT_STRING(_tag, _value) \
+ (void) __android_log_bswrite(_tag, _value);
+#endif
+
+#ifndef log_id_t_defined
+#define log_id_t_defined
+typedef enum log_id {
+ LOG_ID_MIN = 0,
+
+ LOG_ID_MAIN = 0,
+ LOG_ID_RADIO = 1,
+ LOG_ID_EVENTS = 2,
+ LOG_ID_SYSTEM = 3,
+ LOG_ID_CRASH = 4,
+ LOG_ID_SECURITY = 5,
+ LOG_ID_KERNEL = 6, /* place last, third-parties can not use it */
+
+ LOG_ID_MAX
+} log_id_t;
+#endif
+#define sizeof_log_id_t sizeof(typeof_log_id_t)
+#define typeof_log_id_t unsigned char
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Native log reading interface section. See logcat for sample code.
+ *
+ * The preferred API is an exec of logcat. Likely uses of this interface
+ * are if native code suffers from exec or filtration being too costly,
+ * access to raw information, or parsing is an issue.
+ */
+
+/*
+ * The userspace structure for version 1 of the logger_entry ABI.
+ */
+#ifndef __struct_logger_entry_defined
+#define __struct_logger_entry_defined
+struct logger_entry {
+ uint16_t len; /* length of the payload */
+ uint16_t __pad; /* no matter what, we get 2 bytes of padding */
+ int32_t pid; /* generating process's pid */
+ int32_t tid; /* generating process's tid */
+ int32_t sec; /* seconds since Epoch */
+ int32_t nsec; /* nanoseconds */
+#ifndef __cplusplus
+ char msg[0]; /* the entry's payload */
+#endif
+};
+#endif
+
+/*
+ * The userspace structure for version 2 of the logger_entry ABI.
+ */
+#ifndef __struct_logger_entry_v2_defined
+#define __struct_logger_entry_v2_defined
+struct logger_entry_v2 {
+ uint16_t len; /* length of the payload */
+ uint16_t hdr_size; /* sizeof(struct logger_entry_v2) */
+ int32_t pid; /* generating process's pid */
+ int32_t tid; /* generating process's tid */
+ int32_t sec; /* seconds since Epoch */
+ int32_t nsec; /* nanoseconds */
+ uint32_t euid; /* effective UID of logger */
+#ifndef __cplusplus
+ char msg[0]; /* the entry's payload */
+#endif
+} __attribute__((__packed__));
+#endif
+
+/*
+ * The userspace structure for version 3 of the logger_entry ABI.
+ */
+#ifndef __struct_logger_entry_v3_defined
+#define __struct_logger_entry_v3_defined
+struct logger_entry_v3 {
+ uint16_t len; /* length of the payload */
+ uint16_t hdr_size; /* sizeof(struct logger_entry_v3) */
+ int32_t pid; /* generating process's pid */
+ int32_t tid; /* generating process's tid */
+ int32_t sec; /* seconds since Epoch */
+ int32_t nsec; /* nanoseconds */
+ uint32_t lid; /* log id of the payload */
+#ifndef __cplusplus
+ char msg[0]; /* the entry's payload */
+#endif
+} __attribute__((__packed__));
+#endif
+
+/*
+ * The userspace structure for version 4 of the logger_entry ABI.
+ */
+#ifndef __struct_logger_entry_v4_defined
+#define __struct_logger_entry_v4_defined
+struct logger_entry_v4 {
+ uint16_t len; /* length of the payload */
+ uint16_t hdr_size; /* sizeof(struct logger_entry_v4) */
+ int32_t pid; /* generating process's pid */
+ uint32_t tid; /* generating process's tid */
+ uint32_t sec; /* seconds since Epoch */
+ uint32_t nsec; /* nanoseconds */
+ uint32_t lid; /* log id of the payload, bottom 4 bits currently */
+ uint32_t uid; /* generating process's uid */
+#ifndef __cplusplus
+ char msg[0]; /* the entry's payload */
+#endif
+};
+#endif
+
+/* struct log_time is a wire-format variant of struct timespec */
+#define NS_PER_SEC 1000000000ULL
+
+#ifndef __struct_log_time_defined
+#define __struct_log_time_defined
+#ifdef __cplusplus
+
+/*
+ * NB: we did NOT define a copy constructor. This will result in structure
+ * no longer being compatible with pass-by-value which is desired
+ * efficient behavior. Also, pass-by-reference breaks C/C++ ABI.
+ */
+struct log_time {
+public:
+ uint32_t tv_sec; /* good to Feb 5 2106 */
+ uint32_t tv_nsec;
+
+ static const uint32_t tv_sec_max = 0xFFFFFFFFUL;
+ static const uint32_t tv_nsec_max = 999999999UL;
+
+ log_time(const timespec& T)
+ {
+ tv_sec = static_cast<uint32_t>(T.tv_sec);
+ tv_nsec = static_cast<uint32_t>(T.tv_nsec);
+ }
+ log_time(uint32_t sec, uint32_t nsec)
+ {
+ tv_sec = sec;
+ tv_nsec = nsec;
+ }
+#ifdef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
+#define __struct_log_time_private_defined
+ static const timespec EPOCH;
+#endif
+ log_time()
+ {
+ }
+#ifdef __linux__
+ log_time(clockid_t id)
+ {
+ timespec T;
+ clock_gettime(id, &T);
+ tv_sec = static_cast<uint32_t>(T.tv_sec);
+ tv_nsec = static_cast<uint32_t>(T.tv_nsec);
+ }
+#endif
+ log_time(const char* T)
+ {
+ const uint8_t* c = reinterpret_cast<const uint8_t*>(T);
+ tv_sec = c[0] |
+ (static_cast<uint32_t>(c[1]) << 8) |
+ (static_cast<uint32_t>(c[2]) << 16) |
+ (static_cast<uint32_t>(c[3]) << 24);
+ tv_nsec = c[4] |
+ (static_cast<uint32_t>(c[5]) << 8) |
+ (static_cast<uint32_t>(c[6]) << 16) |
+ (static_cast<uint32_t>(c[7]) << 24);
+ }
+
+ /* timespec */
+ bool operator== (const timespec& T) const
+ {
+ return (tv_sec == static_cast<uint32_t>(T.tv_sec))
+ && (tv_nsec == static_cast<uint32_t>(T.tv_nsec));
+ }
+ bool operator!= (const timespec& T) const
+ {
+ return !(*this == T);
+ }
+ bool operator< (const timespec& T) const
+ {
+ return (tv_sec < static_cast<uint32_t>(T.tv_sec))
+ || ((tv_sec == static_cast<uint32_t>(T.tv_sec))
+ && (tv_nsec < static_cast<uint32_t>(T.tv_nsec)));
+ }
+ bool operator>= (const timespec& T) const
+ {
+ return !(*this < T);
+ }
+ bool operator> (const timespec& T) const
+ {
+ return (tv_sec > static_cast<uint32_t>(T.tv_sec))
+ || ((tv_sec == static_cast<uint32_t>(T.tv_sec))
+ && (tv_nsec > static_cast<uint32_t>(T.tv_nsec)));
+ }
+ bool operator<= (const timespec& T) const
+ {
+ return !(*this > T);
+ }
+
+#ifdef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
+ log_time operator-= (const timespec& T);
+ log_time operator- (const timespec& T) const
+ {
+ log_time local(*this);
+ return local -= T;
+ }
+ log_time operator+= (const timespec& T);
+ log_time operator+ (const timespec& T) const
+ {
+ log_time local(*this);
+ return local += T;
+ }
+#endif
+
+ /* log_time */
+ bool operator== (const log_time& T) const
+ {
+ return (tv_sec == T.tv_sec) && (tv_nsec == T.tv_nsec);
+ }
+ bool operator!= (const log_time& T) const
+ {
+ return !(*this == T);
+ }
+ bool operator< (const log_time& T) const
+ {
+ return (tv_sec < T.tv_sec)
+ || ((tv_sec == T.tv_sec) && (tv_nsec < T.tv_nsec));
+ }
+ bool operator>= (const log_time& T) const
+ {
+ return !(*this < T);
+ }
+ bool operator> (const log_time& T) const
+ {
+ return (tv_sec > T.tv_sec)
+ || ((tv_sec == T.tv_sec) && (tv_nsec > T.tv_nsec));
+ }
+ bool operator<= (const log_time& T) const
+ {
+ return !(*this > T);
+ }
+
+#ifdef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
+ log_time operator-= (const log_time& T);
+ log_time operator- (const log_time& T) const
+ {
+ log_time local(*this);
+ return local -= T;
+ }
+ log_time operator+= (const log_time& T);
+ log_time operator+ (const log_time& T) const
+ {
+ log_time local(*this);
+ return local += T;
+ }
+#endif
+
+ uint64_t nsec() const
+ {
+ return static_cast<uint64_t>(tv_sec) * NS_PER_SEC + tv_nsec;
+ }
+
+#ifdef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
+ static const char default_format[];
+
+ /* Add %#q for the fraction of a second to the standard library functions */
+ char* strptime(const char* s, const char* format = default_format);
+#endif
+} __attribute__((__packed__));
+
+#else
+
+typedef struct log_time {
+ uint32_t tv_sec;
+ uint32_t tv_nsec;
+} __attribute__((__packed__)) log_time;
+
+#endif
+#endif
+
+/*
+ * The maximum size of the log entry payload that can be
+ * written to the logger. An attempt to write more than
+ * this amount will result in a truncated log entry.
+ */
+#define LOGGER_ENTRY_MAX_PAYLOAD 4068
+
+/*
+ * The maximum size of a log entry which can be read from the
+ * kernel logger driver. An attempt to read less than this amount
+ * may result in read() returning EINVAL.
+ */
+#define LOGGER_ENTRY_MAX_LEN (5*1024)
+
+#ifndef __struct_log_msg_defined
+#define __struct_log_msg_defined
+struct log_msg {
+ union {
+ unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
+ struct logger_entry_v4 entry;
+ struct logger_entry_v4 entry_v4;
+ struct logger_entry_v3 entry_v3;
+ struct logger_entry_v2 entry_v2;
+ struct logger_entry entry_v1;
+ } __attribute__((aligned(4)));
+#ifdef __cplusplus
+ /* Matching log_time operators */
+ bool operator== (const log_msg& T) const
+ {
+ return (entry.sec == T.entry.sec) && (entry.nsec == T.entry.nsec);
+ }
+ bool operator!= (const log_msg& T) const
+ {
+ return !(*this == T);
+ }
+ bool operator< (const log_msg& T) const
+ {
+ return (entry.sec < T.entry.sec)
+ || ((entry.sec == T.entry.sec)
+ && (entry.nsec < T.entry.nsec));
+ }
+ bool operator>= (const log_msg& T) const
+ {
+ return !(*this < T);
+ }
+ bool operator> (const log_msg& T) const
+ {
+ return (entry.sec > T.entry.sec)
+ || ((entry.sec == T.entry.sec)
+ && (entry.nsec > T.entry.nsec));
+ }
+ bool operator<= (const log_msg& T) const
+ {
+ return !(*this > T);
+ }
+ uint64_t nsec() const
+ {
+ return static_cast<uint64_t>(entry.sec) * NS_PER_SEC + entry.nsec;
+ }
+
+ /* packet methods */
+ log_id_t id()
+ {
+ return static_cast<log_id_t>(entry.lid);
+ }
+ char* msg()
+ {
+ unsigned short hdr_size = entry.hdr_size;
+ if (!hdr_size) {
+ hdr_size = sizeof(entry_v1);
+ }
+ if ((hdr_size < sizeof(entry_v1)) || (hdr_size > sizeof(entry))) {
+ return NULL;
+ }
+ return reinterpret_cast<char*>(buf) + hdr_size;
+ }
+ unsigned int len()
+ {
+ return (entry.hdr_size ?
+ entry.hdr_size :
+ static_cast<uint16_t>(sizeof(entry_v1))) +
+ entry.len;
+ }
+#endif
+};
+#endif
+
+#ifndef __ANDROID_USE_LIBLOG_READER_INTERFACE
+#ifndef __ANDROID_API__
+#define __ANDROID_USE_LIBLOG_READER_INTERFACE 3
+#elif __ANDROID_API__ > 23 /* > Marshmallow */
+#define __ANDROID_USE_LIBLOG_READER_INTERFACE 3
+#elif __ANDROID_API__ > 22 /* > Lollipop */
+#define __ANDROID_USE_LIBLOG_READER_INTERFACE 2
+#elif __ANDROID_API__ > 19 /* > KitKat */
+#define __ANDROID_USE_LIBLOG_READER_INTERFACE 1
+#else
+#define __ANDROID_USE_LIBLOG_READER_INTERFACE 0
+#endif
+#endif
+
+#if __ANDROID_USE_LIBLOG_READER_INTERFACE
+
+struct logger;
+
+log_id_t android_logger_get_id(struct logger* logger);
+
+int android_logger_clear(struct logger* logger);
+long android_logger_get_log_size(struct logger* logger);
+int android_logger_set_log_size(struct logger* logger, unsigned long size);
+long android_logger_get_log_readable_size(struct logger* logger);
+int android_logger_get_log_version(struct logger* logger);
+
+struct logger_list;
+
+#if __ANDROID_USE_LIBLOG_READER_INTERFACE > 1
+ssize_t android_logger_get_statistics(struct logger_list* logger_list,
+ char* buf, size_t len);
+ssize_t android_logger_get_prune_list(struct logger_list* logger_list,
+ char* buf, size_t len);
+int android_logger_set_prune_list(struct logger_list* logger_list,
+ char* buf, size_t len);
+#endif
+
+#define ANDROID_LOG_RDONLY O_RDONLY
+#define ANDROID_LOG_WRONLY O_WRONLY
+#define ANDROID_LOG_RDWR O_RDWR
+#define ANDROID_LOG_ACCMODE O_ACCMODE
+#define ANDROID_LOG_NONBLOCK O_NONBLOCK
+#if __ANDROID_USE_LIBLOG_READER_INTERFACE > 2
+#define ANDROID_LOG_WRAP 0x40000000 /* Block until buffer about to wrap */
+#define ANDROID_LOG_WRAP_DEFAULT_TIMEOUT 7200 /* 2 hour default */
+#endif
+#if __ANDROID_USE_LIBLOG_READER_INTERFACE > 1
+#define ANDROID_LOG_PSTORE 0x80000000
+#endif
+
+struct logger_list* android_logger_list_alloc(int mode,
+ unsigned int tail,
+ pid_t pid);
+struct logger_list* android_logger_list_alloc_time(int mode,
+ log_time start,
+ pid_t pid);
+void android_logger_list_free(struct logger_list* logger_list);
+/* In the purest sense, the following two are orthogonal interfaces */
+int android_logger_list_read(struct logger_list* logger_list,
+ struct log_msg* log_msg);
+
+/* Multiple log_id_t opens */
+struct logger* android_logger_open(struct logger_list* logger_list,
+ log_id_t id);
+#define android_logger_close android_logger_free
+/* Single log_id_t open */
+struct logger_list* android_logger_list_open(log_id_t id,
+ int mode,
+ unsigned int tail,
+ pid_t pid);
+#define android_logger_list_close android_logger_list_free
+
+#endif /* __ANDROID_USE_LIBLOG_READER_INTERFACE */
+
+#ifdef __linux__
+
+#ifndef __ANDROID_USE_LIBLOG_CLOCK_INTERFACE
+#ifndef __ANDROID_API__
+#define __ANDROID_USE_LIBLOG_CLOCK_INTERFACE 1
+#elif __ANDROID_API__ > 22 /* > Lollipop */
+#define __ANDROID_USE_LIBLOG_CLOCK_INTERFACE 1
+#else
+#define __ANDROID_USE_LIBLOG_CLOCK_INTERFACE 0
+#endif
+#endif
+
+#if __ANDROID_USE_LIBLOG_CLOCK_INTERFACE
+clockid_t android_log_clockid();
+#endif
+
+#endif /* __linux__ */
+
+/*
+ * log_id_t helpers
+ */
+log_id_t android_name_to_log_id(const char* logName);
+const char* android_log_id_to_name(log_id_t log_id);
+
+/* --------------------------------------------------------------------- */
+
+#ifndef __ANDROID_USE_LIBLOG_EVENT_INTERFACE
+#ifndef __ANDROID_API__
+#define __ANDROID_USE_LIBLOG_EVENT_INTERFACE 1
+#elif __ANDROID_API__ > 23 /* > Marshmallow */
+#define __ANDROID_USE_LIBLOG_EVENT_INTERFACE 1
+#else
+#define __ANDROID_USE_LIBLOG_EVENT_INTERFACE 0
+#endif
+#endif
+
+#if __ANDROID_USE_LIBLOG_EVENT_INTERFACE
+
+/* For manipulating lists of events. */
+
+#define ANDROID_MAX_LIST_NEST_DEPTH 8
+
+/*
+ * The opaque context used to manipulate lists of events.
+ */
+#ifndef __android_log_context_defined
+#define __android_log_context_defined
+typedef struct android_log_context_internal* android_log_context;
+#endif
+
+/*
+ * Elements returned when reading a list of events.
+ */
+#ifndef __android_log_list_element_defined
+#define __android_log_list_element_defined
+typedef struct {
+ AndroidEventLogType type;
+ uint16_t complete;
+ uint16_t len;
+ union {
+ int32_t int32;
+ int64_t int64;
+ char* string;
+ float float32;
+ } data;
+} android_log_list_element;
+#endif
+
+/*
+ * Creates a context associated with an event tag to write elements to
+ * the list of events.
+ */
+android_log_context create_android_logger(uint32_t tag);
+
+/* All lists must be braced by a begin and end call */
+/*
+ * NB: If the first level braces are missing when specifying multiple
+ * elements, we will manufacturer a list to embrace it for your API
+ * convenience. For a single element, it will remain solitary.
+ */
+int android_log_write_list_begin(android_log_context ctx);
+int android_log_write_list_end(android_log_context ctx);
+
+int android_log_write_int32(android_log_context ctx, int32_t value);
+int android_log_write_int64(android_log_context ctx, int64_t value);
+int android_log_write_string8(android_log_context ctx, const char* value);
+int android_log_write_string8_len(android_log_context ctx,
+ const char* value, size_t maxlen);
+int android_log_write_float32(android_log_context ctx, float value);
+
+/* Submit the composed list context to the specified logger id */
+/* NB: LOG_ID_EVENTS and LOG_ID_SECURITY only valid binary buffers */
+int android_log_write_list(android_log_context ctx, log_id_t id);
+
+/*
+ * Creates a context from a raw buffer representing a list of events to be read.
+ */
+android_log_context create_android_log_parser(const char* msg, size_t len);
+
+android_log_list_element android_log_read_next(android_log_context ctx);
+android_log_list_element android_log_peek_next(android_log_context ctx);
+
+/* Finished with reader or writer context */
+int android_log_destroy(android_log_context* ctx);
+
+#ifdef __cplusplus
+#ifndef __class_android_log_event_context
+#define __class_android_log_event_context
+/* android_log_context C++ helpers */
+extern "C++" {
+class android_log_event_context {
+ android_log_context ctx;
+ int ret;
+
+ android_log_event_context(const android_log_event_context&) = delete;
+ void operator =(const android_log_event_context&) = delete;
+
+public:
+ explicit android_log_event_context(int tag) : ret(0) {
+ ctx = create_android_logger(static_cast<uint32_t>(tag));
+ }
+ explicit android_log_event_context(log_msg& log_msg) : ret(0) {
+ ctx = create_android_log_parser(log_msg.msg() + sizeof(uint32_t),
+ log_msg.entry.len - sizeof(uint32_t));
+ }
+ ~android_log_event_context() { android_log_destroy(&ctx); }
+
+ int close() {
+ int retval = android_log_destroy(&ctx);
+ if (retval < 0) ret = retval;
+ return retval;
+ }
+
+ /* To allow above C calls to use this class as parameter */
+ operator android_log_context() const { return ctx; }
+
+ int status() const { return ret; }
+
+ int begin() {
+ int retval = android_log_write_list_begin(ctx);
+ if (retval < 0) ret = retval;
+ return ret;
+ }
+ int end() {
+ int retval = android_log_write_list_end(ctx);
+ if (retval < 0) ret = retval;
+ return ret;
+ }
+
+ android_log_event_context& operator <<(int32_t value) {
+ int retval = android_log_write_int32(ctx, value);
+ if (retval < 0) ret = retval;
+ return *this;
+ }
+ android_log_event_context& operator <<(uint32_t value) {
+ int retval = android_log_write_int32(ctx, static_cast<int32_t>(value));
+ if (retval < 0) ret = retval;
+ return *this;
+ }
+ android_log_event_context& operator <<(int64_t value) {
+ int retval = android_log_write_int64(ctx, value);
+ if (retval < 0) ret = retval;
+ return *this;
+ }
+ android_log_event_context& operator <<(uint64_t value) {
+ int retval = android_log_write_int64(ctx, static_cast<int64_t>(value));
+ if (retval < 0) ret = retval;
+ return *this;
+ }
+ android_log_event_context& operator <<(const char* value) {
+ int retval = android_log_write_string8(ctx, value);
+ if (retval < 0) ret = retval;
+ return *this;
+ }
+#if defined(_USING_LIBCXX)
+ android_log_event_context& operator <<(const std::string& value) {
+ int retval = android_log_write_string8_len(ctx,
+ value.data(),
+ value.length());
+ if (retval < 0) ret = retval;
+ return *this;
+ }
+#endif
+ android_log_event_context& operator <<(float value) {
+ int retval = android_log_write_float32(ctx, value);
+ if (retval < 0) ret = retval;
+ return *this;
+ }
+
+ int write(log_id_t id = LOG_ID_EVENTS) {
+ int retval = android_log_write_list(ctx, id);
+ if (retval < 0) ret = retval;
+ return ret;
+ }
+
+ int operator <<(log_id_t id) {
+ int retval = android_log_write_list(ctx, id);
+ if (retval < 0) ret = retval;
+ android_log_destroy(&ctx);
+ return ret;
+ }
+
+ /*
+ * Append should be a lesser-used interface, but adds
+ * access to string with length. So we offer all types.
+ */
+ template <typename Tvalue>
+ bool Append(Tvalue value) { *this << value; return ret >= 0; }
+
+ bool Append(const char* value, size_t len) {
+ int retval = android_log_write_string8_len(ctx, value, len);
+ if (retval < 0) ret = retval;
+ return ret >= 0;
+ }
+
+ android_log_list_element read() { return android_log_read_next(ctx); }
+ android_log_list_element peek() { return android_log_peek_next(ctx); }
+
+};
+}
+#endif
+#endif
+
+#endif /* __ANDROID_USE_LIBLOG_EVENT_INTERFACE */
+
+/* --------------------------------------------------------------------- */
+
+#ifndef _ANDROID_USE_LIBLOG_SAFETYNET_INTERFACE
+#ifndef __ANDROID_API__
+#define __ANDROID_USE_LIBLOG_SAFETYNET_INTERFACE 1
+#elif __ANDROID_API__ > 22 /* > Lollipop */
+#define __ANDROID_USE_LIBLOG_SAFETYNET_INTERFACE 1
+#else
+#define __ANDROID_USE_LIBLOG_SAFETYNET_INTERFACE 0
+#endif
+#endif
+
+#if __ANDROID_USE_LIBLOG_SAFETYNET_INTERFACE
+
+#define android_errorWriteLog(tag, subTag) \
+ __android_log_error_write(tag, subTag, -1, NULL, 0)
+
+#define android_errorWriteWithInfoLog(tag, subTag, uid, data, dataLen) \
+ __android_log_error_write(tag, subTag, uid, data, dataLen)
+
+int __android_log_error_write(int tag, const char* subTag, int32_t uid,
+ const char* data, uint32_t dataLen);
+
+#endif /* __ANDROID_USE_LIBLOG_SAFETYNET_INTERFACE */
+
+/* --------------------------------------------------------------------- */
+
+#ifndef __ANDROID_USE_LIBLOG_CLOSE_INTERFACE
+#ifndef __ANDROID_API__
+#define __ANDROID_USE_LIBLOG_CLOSE_INTERFACE 1
+#elif __ANDROID_API__ > 18 /* > JellyBean */
+#define __ANDROID_USE_LIBLOG_CLOSE_INTERFACE 1
+#else
+#define __ANDROID_USE_LIBLOG_CLOSE_INTERFACE 0
+#endif
+#endif
+
+#if __ANDROID_USE_LIBLOG_CLOSE_INTERFACE
+/*
+ * Release any logger resources (a new log write will immediately re-acquire)
+ *
+ * May be used to clean up File descriptors after a Fork, the resources are
+ * all O_CLOEXEC so wil self clean on exec().
+ */
+void __android_log_close();
+#endif
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBS_LOG_LOG_H */
diff --git a/include/log/logd.h b/include/log/logd.h
index ffb8268..0e0248e 100644
--- a/include/log/logd.h
+++ b/include/log/logd.h
@@ -1 +1 @@
-#include <android/log.h>
+#include <log/log.h>
diff --git a/include/log/logger.h b/include/log/logger.h
index 46587fb..0e0248e 100644
--- a/include/log/logger.h
+++ b/include/log/logger.h
@@ -1,462 +1 @@
-/*
-**
-** Copyright 2007-2014, The Android Open Source Project
-**
-** This file is dual licensed. It may be redistributed and/or modified
-** under the terms of the Apache 2.0 License OR version 2 of the GNU
-** General Public License.
-*/
-
-#ifndef _LIBS_LOG_LOGGER_H
-#define _LIBS_LOG_LOGGER_H
-
-#include <stdint.h>
-#include <time.h>
-
-#ifdef __cplusplus
-#include <string>
-#endif
-
-#include <android/log.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * The userspace structure for version 1 of the logger_entry ABI.
- * This structure is returned to userspace by the kernel logger
- * driver unless an upgrade to a newer ABI version is requested.
- */
-struct logger_entry {
- uint16_t len; /* length of the payload */
- uint16_t __pad; /* no matter what, we get 2 bytes of padding */
- int32_t pid; /* generating process's pid */
- int32_t tid; /* generating process's tid */
- int32_t sec; /* seconds since Epoch */
- int32_t nsec; /* nanoseconds */
- char msg[0]; /* the entry's payload */
-} __attribute__((__packed__));
-
-/*
- * The userspace structure for version 2 of the logger_entry ABI.
- * This structure is returned to userspace if ioctl(LOGGER_SET_VERSION)
- * is called with version==2; or used with the user space log daemon.
- */
-struct logger_entry_v2 {
- uint16_t len; /* length of the payload */
- uint16_t hdr_size; /* sizeof(struct logger_entry_v2) */
- int32_t pid; /* generating process's pid */
- int32_t tid; /* generating process's tid */
- int32_t sec; /* seconds since Epoch */
- int32_t nsec; /* nanoseconds */
- uint32_t euid; /* effective UID of logger */
- char msg[0]; /* the entry's payload */
-} __attribute__((__packed__));
-
-struct logger_entry_v3 {
- uint16_t len; /* length of the payload */
- uint16_t hdr_size; /* sizeof(struct logger_entry_v3) */
- int32_t pid; /* generating process's pid */
- int32_t tid; /* generating process's tid */
- int32_t sec; /* seconds since Epoch */
- int32_t nsec; /* nanoseconds */
- uint32_t lid; /* log id of the payload */
- char msg[0]; /* the entry's payload */
-} __attribute__((__packed__));
-
-struct logger_entry_v4 {
- uint16_t len; /* length of the payload */
- uint16_t hdr_size; /* sizeof(struct logger_entry_v4) */
- int32_t pid; /* generating process's pid */
- uint32_t tid; /* generating process's tid */
- uint32_t sec; /* seconds since Epoch */
- uint32_t nsec; /* nanoseconds */
- uint32_t lid; /* log id of the payload, bottom 4 bits currently */
- uint32_t uid; /* generating process's uid */
- char msg[0]; /* the entry's payload */
-} __attribute__((__packed__));
-
-/* struct log_time is a wire-format variant of struct timespec */
-#define NS_PER_SEC 1000000000ULL
-
-#ifdef __cplusplus
-
-// NB: do NOT define a copy constructor. This will result in structure
-// no longer being compatible with pass-by-value which is desired
-// efficient behavior. Also, pass-by-reference breaks C/C++ ABI.
-struct log_time {
-public:
- uint32_t tv_sec; // good to Feb 5 2106
- uint32_t tv_nsec;
-
- static const uint32_t tv_sec_max = 0xFFFFFFFFUL;
- static const uint32_t tv_nsec_max = 999999999UL;
-
- log_time(const timespec &T)
- {
- tv_sec = T.tv_sec;
- tv_nsec = T.tv_nsec;
- }
- log_time(uint32_t sec, uint32_t nsec)
- {
- tv_sec = sec;
- tv_nsec = nsec;
- }
- static const timespec EPOCH;
- log_time()
- {
- }
-#ifdef __linux__
- log_time(clockid_t id)
- {
- timespec T;
- clock_gettime(id, &T);
- tv_sec = T.tv_sec;
- tv_nsec = T.tv_nsec;
- }
-#endif
- log_time(const char *T)
- {
- const uint8_t *c = (const uint8_t *) T;
- tv_sec = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24);
- tv_nsec = c[4] | (c[5] << 8) | (c[6] << 16) | (c[7] << 24);
- }
-
- // timespec
- bool operator== (const timespec &T) const
- {
- return (tv_sec == static_cast<uint32_t>(T.tv_sec))
- && (tv_nsec == static_cast<uint32_t>(T.tv_nsec));
- }
- bool operator!= (const timespec &T) const
- {
- return !(*this == T);
- }
- bool operator< (const timespec &T) const
- {
- return (tv_sec < static_cast<uint32_t>(T.tv_sec))
- || ((tv_sec == static_cast<uint32_t>(T.tv_sec))
- && (tv_nsec < static_cast<uint32_t>(T.tv_nsec)));
- }
- bool operator>= (const timespec &T) const
- {
- return !(*this < T);
- }
- bool operator> (const timespec &T) const
- {
- return (tv_sec > static_cast<uint32_t>(T.tv_sec))
- || ((tv_sec == static_cast<uint32_t>(T.tv_sec))
- && (tv_nsec > static_cast<uint32_t>(T.tv_nsec)));
- }
- bool operator<= (const timespec &T) const
- {
- return !(*this > T);
- }
- log_time operator-= (const timespec &T);
- log_time operator- (const timespec &T) const
- {
- log_time local(*this);
- return local -= T;
- }
- log_time operator+= (const timespec &T);
- log_time operator+ (const timespec &T) const
- {
- log_time local(*this);
- return local += T;
- }
-
- // log_time
- bool operator== (const log_time &T) const
- {
- return (tv_sec == T.tv_sec) && (tv_nsec == T.tv_nsec);
- }
- bool operator!= (const log_time &T) const
- {
- return !(*this == T);
- }
- bool operator< (const log_time &T) const
- {
- return (tv_sec < T.tv_sec)
- || ((tv_sec == T.tv_sec) && (tv_nsec < T.tv_nsec));
- }
- bool operator>= (const log_time &T) const
- {
- return !(*this < T);
- }
- bool operator> (const log_time &T) const
- {
- return (tv_sec > T.tv_sec)
- || ((tv_sec == T.tv_sec) && (tv_nsec > T.tv_nsec));
- }
- bool operator<= (const log_time &T) const
- {
- return !(*this > T);
- }
- log_time operator-= (const log_time &T);
- log_time operator- (const log_time &T) const
- {
- log_time local(*this);
- return local -= T;
- }
- log_time operator+= (const log_time &T);
- log_time operator+ (const log_time &T) const
- {
- log_time local(*this);
- return local += T;
- }
-
- uint64_t nsec() const
- {
- return static_cast<uint64_t>(tv_sec) * NS_PER_SEC + tv_nsec;
- }
-
- static const char default_format[];
-
- // Add %#q for the fraction of a second to the standard library functions
- char *strptime(const char *s, const char *format = default_format);
-} __attribute__((__packed__));
-
-#else
-
-typedef struct log_time {
- uint32_t tv_sec;
- uint32_t tv_nsec;
-} __attribute__((__packed__)) log_time;
-
-#endif
-
-/*
- * The maximum size of the log entry payload that can be
- * written to the logger. An attempt to write more than
- * this amount will result in a truncated log entry.
- */
-#define LOGGER_ENTRY_MAX_PAYLOAD 4068
-
-/*
- * The maximum size of a log entry which can be read from the
- * kernel logger driver. An attempt to read less than this amount
- * may result in read() returning EINVAL.
- */
-#define LOGGER_ENTRY_MAX_LEN (5*1024)
-
-struct log_msg {
- union {
- unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
- struct logger_entry_v4 entry;
- struct logger_entry_v4 entry_v4;
- struct logger_entry_v3 entry_v3;
- struct logger_entry_v2 entry_v2;
- struct logger_entry entry_v1;
- } __attribute__((aligned(4)));
-#ifdef __cplusplus
- /* Matching log_time operators */
- bool operator== (const log_msg &T) const
- {
- return (entry.sec == T.entry.sec) && (entry.nsec == T.entry.nsec);
- }
- bool operator!= (const log_msg &T) const
- {
- return !(*this == T);
- }
- bool operator< (const log_msg &T) const
- {
- return (entry.sec < T.entry.sec)
- || ((entry.sec == T.entry.sec)
- && (entry.nsec < T.entry.nsec));
- }
- bool operator>= (const log_msg &T) const
- {
- return !(*this < T);
- }
- bool operator> (const log_msg &T) const
- {
- return (entry.sec > T.entry.sec)
- || ((entry.sec == T.entry.sec)
- && (entry.nsec > T.entry.nsec));
- }
- bool operator<= (const log_msg &T) const
- {
- return !(*this > T);
- }
- uint64_t nsec() const
- {
- return static_cast<uint64_t>(entry.sec) * NS_PER_SEC + entry.nsec;
- }
-
- /* packet methods */
- log_id_t id()
- {
- return (log_id_t) entry.lid;
- }
- char *msg()
- {
- unsigned short hdr_size = entry.hdr_size;
- if (!hdr_size) {
- hdr_size = sizeof(entry_v1);
- }
- if ((hdr_size < sizeof(entry_v1)) || (hdr_size > sizeof(entry))) {
- return NULL;
- }
- return (char *) buf + hdr_size;
- }
- unsigned int len()
- {
- return (entry.hdr_size ? entry.hdr_size : sizeof(entry_v1)) + entry.len;
- }
-#endif
-};
-
-struct logger;
-
-log_id_t android_logger_get_id(struct logger *logger);
-
-int android_logger_clear(struct logger *logger);
-long android_logger_get_log_size(struct logger *logger);
-int android_logger_set_log_size(struct logger *logger, unsigned long size);
-long android_logger_get_log_readable_size(struct logger *logger);
-int android_logger_get_log_version(struct logger *logger);
-
-struct logger_list;
-
-ssize_t android_logger_get_statistics(struct logger_list *logger_list,
- char *buf, size_t len);
-ssize_t android_logger_get_prune_list(struct logger_list *logger_list,
- char *buf, size_t len);
-int android_logger_set_prune_list(struct logger_list *logger_list,
- char *buf, size_t len);
-
-#define ANDROID_LOG_RDONLY O_RDONLY
-#define ANDROID_LOG_WRONLY O_WRONLY
-#define ANDROID_LOG_RDWR O_RDWR
-#define ANDROID_LOG_ACCMODE O_ACCMODE
-#define ANDROID_LOG_NONBLOCK O_NONBLOCK
-#define ANDROID_LOG_WRAP 0x40000000 /* Block until buffer about to wrap */
-#define ANDROID_LOG_WRAP_DEFAULT_TIMEOUT 7200 /* 2 hour default */
-#define ANDROID_LOG_PSTORE 0x80000000
-
-struct logger_list *android_logger_list_alloc(int mode,
- unsigned int tail,
- pid_t pid);
-struct logger_list *android_logger_list_alloc_time(int mode,
- log_time start,
- pid_t pid);
-void android_logger_list_free(struct logger_list *logger_list);
-/* In the purest sense, the following two are orthogonal interfaces */
-int android_logger_list_read(struct logger_list *logger_list,
- struct log_msg *log_msg);
-
-/* Multiple log_id_t opens */
-struct logger *android_logger_open(struct logger_list *logger_list,
- log_id_t id);
-#define android_logger_close android_logger_free
-/* Single log_id_t open */
-struct logger_list *android_logger_list_open(log_id_t id,
- int mode,
- unsigned int tail,
- pid_t pid);
-#define android_logger_list_close android_logger_list_free
-
-#ifdef __linux__
-clockid_t android_log_clockid();
-#endif
-
-/*
- * log_id_t helpers
- */
-log_id_t android_name_to_log_id(const char *logName);
-const char *android_log_id_to_name(log_id_t log_id);
-
-#ifdef __cplusplus
-// android_log_context C++ helpers
-class android_log_event_context {
- android_log_context ctx;
- int ret;
-
-public:
- explicit android_log_event_context(int tag) : ret(0) {
- ctx = create_android_logger(tag);
- }
- explicit android_log_event_context(log_msg& log_msg) : ret(0) {
- ctx = create_android_log_parser(log_msg.msg() + sizeof(uint32_t),
- log_msg.entry.len - sizeof(uint32_t));
- }
- ~android_log_event_context() { android_log_destroy(&ctx); }
-
- int close() {
- int retval = android_log_destroy(&ctx);
- if (retval < 0) ret = retval;
- return retval;
- }
-
- // To allow above C calls to use this class as parameter
- operator android_log_context() const { return ctx; };
-
- int error() const { return ret; }
-
- int begin() {
- int retval = android_log_write_list_begin(ctx);
- if (retval < 0) ret = retval;
- return ret;
- }
- int end() {
- int retval = android_log_write_list_end(ctx);
- if (retval < 0) ret = retval;
- return ret;
- }
-
- android_log_event_context& operator <<(int32_t value) {
- int retval = android_log_write_int32(ctx, value);
- if (retval < 0) ret = retval;
- return *this;
- }
- android_log_event_context& operator <<(uint32_t value) {
- int retval = android_log_write_int32(ctx, value);
- if (retval < 0) ret = retval;
- return *this;
- }
- android_log_event_context& operator <<(int64_t value) {
- int retval = android_log_write_int64(ctx, value);
- if (retval < 0) ret = retval;
- return *this;
- }
- android_log_event_context& operator <<(uint64_t value) {
- int retval = android_log_write_int64(ctx, value);
- if (retval < 0) ret = retval;
- return *this;
- }
- android_log_event_context& operator <<(const char* value) {
- int retval = android_log_write_string8(ctx, value);
- if (retval < 0) ret = retval;
- return *this;
- }
- android_log_event_context& operator <<(std::string& value) {
- int retval = android_log_write_string8_len(ctx,
- value.data(),
- value.length());
- if (retval < 0) ret = retval;
- return *this;
- }
- android_log_event_context& operator <<(float value) {
- int retval = android_log_write_float32(ctx, value);
- if (retval < 0) ret = retval;
- return *this;
- }
-
- int write(log_id_t id) {
- int retval = android_log_write_list(ctx, id);
- if (retval < 0) ret = retval;
- return ret;
- }
-
- android_log_list_element read() { return android_log_read_next(ctx); }
- android_log_list_element peak() { return android_log_peek_next(ctx); }
-
-};
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _LIBS_LOG_LOGGER_H */
+#include <log/log.h>
diff --git a/include/log/logprint.h b/include/log/logprint.h
index e5cd1de..3509e7f 100644
--- a/include/log/logprint.h
+++ b/include/log/logprint.h
@@ -21,7 +21,6 @@
#include <android/log.h>
#include <log/event_tag_map.h>
-#include <log/logger.h> /* struct logger_entry */
#ifdef __cplusplus
extern "C" {
@@ -47,6 +46,7 @@
FORMAT_MODIFIER_EPOCH, /* Print time as seconds since Jan 1 1970 */
FORMAT_MODIFIER_MONOTONIC, /* Print cpu time as seconds since start */
FORMAT_MODIFIER_UID, /* Adds uid */
+ FORMAT_MODIFIER_DESCRIPT, /* Adds descriptive */
} AndroidLogPrintFormat;
typedef struct AndroidLogFormat_t AndroidLogFormat;
@@ -58,24 +58,24 @@
int32_t uid;
int32_t pid;
int32_t tid;
- const char * tag;
+ const char* tag;
size_t tagLen;
size_t messageLen;
- const char * message;
+ const char* message;
} AndroidLogEntry;
-AndroidLogFormat *android_log_format_new();
+AndroidLogFormat* android_log_format_new();
-void android_log_format_free(AndroidLogFormat *p_format);
+void android_log_format_free(AndroidLogFormat* p_format);
/* currently returns 0 if format is a modifier, 1 if not */
-int android_log_setPrintFormat(AndroidLogFormat *p_format,
+int android_log_setPrintFormat(AndroidLogFormat* p_format,
AndroidLogPrintFormat format);
/**
* Returns FORMAT_OFF on invalid string
*/
-AndroidLogPrintFormat android_log_formatFromString(const char *s);
+AndroidLogPrintFormat android_log_formatFromString(const char* s);
/**
* filterExpression: a single filter expression
@@ -87,9 +87,8 @@
*
*/
-int android_log_addFilterRule(AndroidLogFormat *p_format,
- const char *filterExpression);
-
+int android_log_addFilterRule(AndroidLogFormat* p_format,
+ const char* filterExpression);
/**
* filterString: a whitespace-separated set of filter expressions
@@ -101,17 +100,15 @@
*
*/
-int android_log_addFilterString(AndroidLogFormat *p_format,
- const char *filterString);
-
+int android_log_addFilterString(AndroidLogFormat* p_format,
+ const char* filterString);
/**
* returns 1 if this log line should be printed based on its priority
* and tag, and 0 if it should not
*/
int android_log_shouldPrintLine (
- AndroidLogFormat *p_format, const char *tag, android_LogPriority pri);
-
+ AndroidLogFormat* p_format, const char* tag, android_LogPriority pri);
/**
* Splits a wire-format buffer into an AndroidLogEntry
@@ -120,8 +117,8 @@
* Returns 0 on success and -1 on invalid wire format (entry will be
* in unspecified state)
*/
-int android_log_processLogBuffer(struct logger_entry *buf,
- AndroidLogEntry *entry);
+int android_log_processLogBuffer(struct logger_entry* buf,
+ AndroidLogEntry* entry);
/**
* Like android_log_processLogBuffer, but for binary logs.
@@ -129,11 +126,10 @@
* If "map" is non-NULL, it will be used to convert the log tag number
* into a string.
*/
-int android_log_processBinaryLogBuffer(struct logger_entry *buf,
- AndroidLogEntry *entry, const EventTagMap* map, char* messageBuf,
+int android_log_processBinaryLogBuffer(struct logger_entry* buf,
+ AndroidLogEntry* entry, const EventTagMap* map, char* messageBuf,
int messageBufLen);
-
/**
* Formats a log message into a buffer
*
@@ -142,13 +138,12 @@
* Returns NULL on malloc error
*/
-char *android_log_formatLogLine (
- AndroidLogFormat *p_format,
- char *defaultBuffer,
+char* android_log_formatLogLine (
+ AndroidLogFormat* p_format,
+ char* defaultBuffer,
size_t defaultBufferSize,
- const AndroidLogEntry *p_line,
- size_t *p_outLength);
-
+ const AndroidLogEntry* p_line,
+ size_t* p_outLength);
/**
* Either print or do not print log line, based on filter
@@ -157,14 +152,12 @@
*
*/
int android_log_printLogLine(
- AndroidLogFormat *p_format,
+ AndroidLogFormat* p_format,
int fd,
- const AndroidLogEntry *entry);
-
+ const AndroidLogEntry* entry);
#ifdef __cplusplus
}
#endif
-
#endif /*_LOGPRINT_H*/
diff --git a/include/nativebridge/native_bridge.h b/include/nativebridge/native_bridge.h
index 18300bc..45266de 100644
--- a/include/nativebridge/native_bridge.h
+++ b/include/nativebridge/native_bridge.h
@@ -62,12 +62,19 @@
bool NativeBridgeInitialized();
// Load a shared library that is supported by the native bridge.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Use NativeBridgeLoadLibraryExt() instead in namespace scenario.
void* NativeBridgeLoadLibrary(const char* libpath, int flag);
// Get a native bridge trampoline for specified native method.
void* NativeBridgeGetTrampoline(void* handle, const char* name, const char* shorty, uint32_t len);
-// True if native library is valid and is for an ABI that is supported by native bridge.
+// True if native library paths are valid and is for an ABI that is supported by native bridge.
+// The *libpath* must point to a library.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Use NativeBridgeIsPathSupported() instead in namespace scenario.
bool NativeBridgeIsSupported(const char* libpath);
// Returns the version number of the native bridge. This information is available after a
@@ -91,6 +98,48 @@
// This functionality is exposed mainly for testing.
bool NativeBridgeNameAcceptable(const char* native_bridge_library_filename);
+// Decrements the reference count on the dynamic library handler. If the reference count drops
+// to zero then the dynamic library is unloaded.
+int NativeBridgeUnloadLibrary(void* handle);
+
+// Get last error message of native bridge when fail to load library or search symbol.
+// This is reflection of dlerror() for native bridge.
+const char* NativeBridgeGetError();
+
+struct native_bridge_namespace_t;
+
+// True if native library paths are valid and is for an ABI that is supported by native bridge.
+// Different from NativeBridgeIsSupported(), the *path* here must be a directory containing
+// libraries of an ABI.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Use NativeBridgeIsSupported() instead in non-namespace scenario.
+bool NativeBridgeIsPathSupported(const char* path);
+
+// Initializes public and anonymous namespace at native bridge side.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Should not use in non-namespace scenario.
+bool NativeBridgeInitNamespace(const char* public_ns_sonames,
+ const char* anon_ns_library_path);
+
+// Create a namespace and pass the key of related namespaces to native bridge.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Should not use in non-namespace scenario.
+native_bridge_namespace_t* NativeBridgeCreateNamespace(const char* name,
+ const char* ld_library_path,
+ const char* default_library_path,
+ uint64_t type,
+ const char* permitted_when_isolated_path,
+ native_bridge_namespace_t* parent_ns);
+
+// Load a shared library with namespace key that is supported by the native bridge.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Use NativeBridgeLoadLibrary() instead in non-namespace scenario.
+void* NativeBridgeLoadLibraryExt(const char* libpath, int flag, native_bridge_namespace_t* ns);
+
// Native bridge interfaces to runtime.
struct NativeBridgeCallbacks {
// Version number of the interface.
@@ -114,6 +163,9 @@
// flag [IN] the stardard RTLD_XXX defined in bionic dlfcn.h
// Returns:
// The opaque handle of the shared library if sucessful, otherwise NULL
+ //
+ // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+ // Use loadLibraryExt instead in namespace scenario.
void* (*loadLibrary)(const char* libpath, int flag);
// Get a native bridge trampoline for specified native method. The trampoline has same
@@ -133,6 +185,9 @@
// libpath [IN] path to the shared library
// Returns:
// TRUE if library is supported by native bridge, FALSE otherwise
+ //
+ // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+ // Use isPathSupported instead in namespace scenario.
bool (*isSupported)(const char* libpath);
// Provide environment values required by the app running with native bridge according to the
@@ -169,6 +224,88 @@
// runtime.
// Otherwise, a pointer to the signal handler.
NativeBridgeSignalHandlerFn (*getSignalHandler)(int signal);
+
+ // Added callbacks in version 3.
+
+ // Decrements the reference count on the dynamic library handler. If the reference count drops
+ // to zero then the dynamic library is unloaded.
+ //
+ // Parameters:
+ // handle [IN] the handler of a dynamic library.
+ //
+ // Returns:
+ // 0 on success, and nonzero on error.
+ int (*unloadLibrary)(void* handle);
+
+ // Dump the last failure message of native bridge when fail to load library or search symbol.
+ //
+ // Parameters:
+ //
+ // Returns:
+ // A string describing the most recent error that occurred when load library
+ // or lookup symbol via native bridge.
+ const char* (*getError)();
+
+ // Check whether library paths are supported by native bridge.
+ //
+ // Parameters:
+ // library_path [IN] search paths for native libraries (directories separated by ':')
+ // Returns:
+ // TRUE if libraries within search paths are supported by native bridge, FALSE otherwise
+ //
+ // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+ // Use isSupported instead in non-namespace scenario.
+ bool (*isPathSupported)(const char* library_path);
+
+ // Initializes anonymous namespace at native bridge side and pass the key of
+ // two namespaces(default and anonymous) owned by dynamic linker to native bridge.
+ //
+ // Parameters:
+ // public_ns_sonames [IN] the name of "public" libraries.
+ // anon_ns_library_path [IN] the library search path of (anonymous) namespace.
+ // Returns:
+ // true if the pass is ok.
+ // Otherwise, false.
+ //
+ // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+ // Should not use in non-namespace scenario.
+ bool (*initNamespace)(const char* public_ns_sonames,
+ const char* anon_ns_library_path);
+
+
+ // Create a namespace and pass the key of releated namespaces to native bridge.
+ //
+ // Parameters:
+ // name [IN] the name of the namespace.
+ // ld_library_path [IN] the first set of library search paths of the namespace.
+ // default_library_path [IN] the second set of library search path of the namespace.
+ // type [IN] the attribute of the namespace.
+ // permitted_when_isolated_path [IN] the permitted path for isolated namespace(if it is).
+ // parent_ns [IN] the pointer of the parent namespace to be inherited from.
+ // Returns:
+ // native_bridge_namespace_t* for created namespace or nullptr in the case of error.
+ //
+ // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+ // Should not use in non-namespace scenario.
+ native_bridge_namespace_t* (*createNamespace)(const char* name,
+ const char* ld_library_path,
+ const char* default_library_path,
+ uint64_t type,
+ const char* permitted_when_isolated_path,
+ native_bridge_namespace_t* parent_ns);
+
+ // Load a shared library within a namespace.
+ //
+ // Parameters:
+ // libpath [IN] path to the shared library
+ // flag [IN] the stardard RTLD_XXX defined in bionic dlfcn.h
+ // ns [IN] the pointer of the namespace in which the library should be loaded.
+ // Returns:
+ // The opaque handle of the shared library if sucessful, otherwise NULL
+ //
+ // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+ // Use loadLibrary instead in non-namespace scenario.
+ void* (*loadLibraryExt)(const char* libpath, int flag, native_bridge_namespace_t* ns);
};
// Runtime interfaces to native bridge.
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 167a6d9..c364317 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -95,6 +95,7 @@
#define AID_DNS 1051 /* DNS resolution daemon (system: netd) */
#define AID_DNS_TETHER 1052 /* DNS resolution daemon (tether: dnsmasq) */
#define AID_WEBVIEW_ZYGOTE 1053 /* WebView zygote process */
+#define AID_VEHICLE_NETWORK 1054 /* Vehicle network service */
/* Changes to this file must be made in AOSP, *not* in internal branches. */
#define AID_SHELL 2000 /* adb and debug shell user */
@@ -208,6 +209,7 @@
{ "dns", AID_DNS, },
{ "dns_tether", AID_DNS_TETHER, },
{ "webview_zygote", AID_WEBVIEW_ZYGOTE, },
+ { "vehicle_network", AID_VEHICLE_NETWORK, },
{ "shell", AID_SHELL, },
{ "cache", AID_CACHE, },
diff --git a/include/private/android_logger.h b/include/private/android_logger.h
index 141001c..f3c6cf7 100644
--- a/include/private/android_logger.h
+++ b/include/private/android_logger.h
@@ -21,11 +21,11 @@
/* Android private interfaces */
+#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
-#include <android/log.h>
-#include <log/logger.h> /* log_time */
+#include <log/log.h>
#define LOGGER_MAGIC 'l'
@@ -109,8 +109,8 @@
ssize_t __android_log_pmsg_file_write(
log_id_t logId,
char prio,
- const char *filename,
- const char *buf, size_t len);
+ const char* filename,
+ const char* buf, size_t len);
#define LOG_ID_ANY ((log_id_t)-1)
#define ANDROID_LOG_ANY ANDROID_LOG_UNKNOWN
@@ -119,17 +119,33 @@
typedef ssize_t (*__android_log_pmsg_file_read_fn)(
log_id_t logId,
char prio,
- const char *filename,
- const char *buf, size_t len, void *arg);
+ const char* filename,
+ const char* buf, size_t len, void* arg);
ssize_t __android_log_pmsg_file_read(
- log_id_t logId, char prio, const char *prefix,
- __android_log_pmsg_file_read_fn fn, void *arg);
+ log_id_t logId, char prio, const char* prefix,
+ __android_log_pmsg_file_read_fn fn, void* arg);
-int __android_log_security_bwrite(int32_t tag, const void *payload, size_t len);
-int __android_log_security_bswrite(int32_t tag, const char *payload);
+int __android_log_security_bwrite(int32_t tag, const void* payload, size_t len);
+int __android_log_security_bswrite(int32_t tag, const char* payload);
int __android_log_security(); /* Device Owner is present */
+int __android_log_is_debuggable();
+
+#define BOOL_DEFAULT_FLAG_TRUE_FALSE 0x1
+#define BOOL_DEFAULT_FALSE 0x0 /* false if property not present */
+#define BOOL_DEFAULT_TRUE 0x1 /* true if property not present */
+#define BOOL_DEFAULT_FLAG_PERSIST 0x2 /* <key>, persist.<key>, ro.<key> */
+#define BOOL_DEFAULT_FLAG_ENG 0x4 /* off for user */
+#define BOOL_DEFAULT_FLAG_SVELTE 0x8 /* off for low_ram */
+bool __android_logger_property_get_bool(const char* key, int flag);
+
+#define LOG_BUFFER_SIZE (256 * 1024) /* Tuned with ro.logd.size per-platform */
+#define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
+#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
+unsigned long __android_logger_get_buffer_size(log_id_t logId);
+bool __android_logger_valid_buffer_size(unsigned long value);
+
#if defined(__cplusplus)
}
#endif
diff --git a/include/utils/Log.h b/include/utils/Log.h
index 6ef3fa3..5276a49 100644
--- a/include/utils/Log.h
+++ b/include/utils/Log.h
@@ -30,7 +30,7 @@
#include <sys/types.h>
-#include <android/log.h>
+#include <log/log.h>
#ifdef __cplusplus
diff --git a/include/utils/SortedVector.h b/include/utils/SortedVector.h
index 9f2ec02..86f3496 100644
--- a/include/utils/SortedVector.h
+++ b/include/utils/SortedVector.h
@@ -21,7 +21,7 @@
#include <stdint.h>
#include <sys/types.h>
-#include <android/log.h>
+#include <log/log.h>
#include <utils/TypeHelpers.h>
#include <utils/Vector.h>
#include <utils/VectorImpl.h>
diff --git a/include/utils/Vector.h b/include/utils/Vector.h
index 6c1931e..28a77b8 100644
--- a/include/utils/Vector.h
+++ b/include/utils/Vector.h
@@ -22,7 +22,7 @@
#include <new>
-#include <android/log.h>
+#include <log/log.h>
#include <utils/TypeHelpers.h>
#include <utils/VectorImpl.h>
diff --git a/include/ziparchive/zip_archive.h b/include/ziparchive/zip_archive.h
index 4f68c3b..fc845a4 100644
--- a/include/ziparchive/zip_archive.h
+++ b/include/ziparchive/zip_archive.h
@@ -130,6 +130,8 @@
int32_t OpenArchiveFd(const int fd, const char* debugFileName,
ZipArchiveHandle *handle, bool assume_ownership = true);
+int32_t OpenArchiveFromMemory(void* address, size_t length, const char* debugFileName,
+ ZipArchiveHandle *handle);
/*
* Close archive, releasing resources associated with it. This will
* unmap the central directory of the zipfile and free all internal
@@ -214,6 +216,17 @@
const char* ErrorCodeString(int32_t error_code);
+#if !defined(_WIN32)
+typedef bool (*ProcessZipEntryFunction)(const uint8_t* buf, size_t buf_size, void* cookie);
+
+/*
+ * Stream the uncompressed data through the supplied function,
+ * passing cookie to it each time it gets called.
+*/
+int32_t ProcessZipEntryContents(ZipArchiveHandle handle, ZipEntry* entry,
+ ProcessZipEntryFunction func, void* cookie);
+#endif
+
__END_DECLS
#endif // LIBZIPARCHIVE_ZIPARCHIVE_H_
diff --git a/init/Android.mk b/init/Android.mk
index 704304e..442a5f3 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -45,6 +45,8 @@
LOCAL_CPPFLAGS := $(init_cflags)
LOCAL_SRC_FILES:= \
action.cpp \
+ capabilities.cpp \
+ descriptors.cpp \
import_parser.cpp \
init_parser.cpp \
log.cpp \
@@ -53,6 +55,7 @@
util.cpp \
LOCAL_STATIC_LIBRARIES := libbase libselinux liblog libprocessgroup
+LOCAL_WHOLE_STATIC_LIBRARIES := libcap
LOCAL_MODULE := libinit
LOCAL_SANITIZE := integer
LOCAL_CLANG := true
@@ -82,7 +85,7 @@
LOCAL_STATIC_LIBRARIES := \
libinit \
- libbootloader_message_writer \
+ libbootloader_message \
libfs_mgr \
libfec \
libfec_rs \
@@ -102,7 +105,7 @@
libz \
libprocessgroup
-# Create symlinks
+# Create symlinks.
LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
ln -sf ../init $(TARGET_ROOT_OUT)/sbin/ueventd; \
ln -sf ../init $(TARGET_ROOT_OUT)/sbin/watchdogd
@@ -112,8 +115,8 @@
include $(BUILD_EXECUTABLE)
-
-
+# Unit tests.
+# =========================================================
include $(CLEAR_VARS)
LOCAL_MODULE := init_tests
LOCAL_SRC_FILES := \
@@ -123,8 +126,10 @@
LOCAL_SHARED_LIBRARIES += \
libcutils \
libbase \
+ libselinux \
LOCAL_STATIC_LIBRARIES := libinit
LOCAL_SANITIZE := integer
LOCAL_CLANG := true
+LOCAL_CPPFLAGS := -Wall -Wextra -Werror
include $(BUILD_NATIVE_TEST)
diff --git a/init/action.cpp b/init/action.cpp
index ed88f6d..a12f225 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -118,14 +118,16 @@
Timer t;
int result = command.InvokeFunc();
- // TODO: this should probably be changed to "if (failed || took a long time)"...
- if (android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
+ double duration_ms = t.duration() * 1000;
+ // Any action longer than 50ms will be warned to user as slow operation
+ if (duration_ms > 50.0 ||
+ android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
std::string trigger_name = BuildTriggersString();
std::string cmd_str = command.BuildCommandString();
std::string source = command.BuildSourceString();
LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << source
- << " returned " << result << " took " << t.duration() << "s";
+ << " returned " << result << " took " << duration_ms << "ms.";
}
}
diff --git a/init/bootchart.cpp b/init/bootchart.cpp
index 467a838..8fb55f0 100644
--- a/init/bootchart.cpp
+++ b/init/bootchart.cpp
@@ -241,6 +241,7 @@
fclose(log_disks);
fclose(log_procs);
acct(NULL);
+ LOG(INFO) << "Bootcharting finished";
}
void bootchart_sample(int* timeout) {
@@ -253,12 +254,12 @@
int elapsed_time = current_time - g_last_bootchart_time;
if (elapsed_time >= BOOTCHART_POLLING_MS) {
- /* count missed samples */
+ // Count missed samples.
while (elapsed_time >= BOOTCHART_POLLING_MS) {
elapsed_time -= BOOTCHART_POLLING_MS;
g_remaining_samples--;
}
- /* count may be negative, take a sample anyway */
+ // Count may be negative, take a sample anyway.
g_last_bootchart_time = current_time;
if (bootchart_step() < 0 || g_remaining_samples <= 0) {
bootchart_finish();
diff --git a/init/builtins.cpp b/init/builtins.cpp
index f4ba018..3e50f4d 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -46,7 +46,7 @@
#include <android-base/parseint.h>
#include <android-base/strings.h>
#include <android-base/stringprintf.h>
-#include <bootloader_message_writer.h>
+#include <bootloader_message/bootloader_message.h>
#include <cutils/partition_utils.h>
#include <cutils/android_reboot.h>
#include <ext4_utils/ext4_crypt.h>
@@ -304,7 +304,7 @@
/* mkdir <path> [mode] [owner] [group] */
if (args.size() >= 3) {
- mode = std::stoul(args[2], 0, 8);
+ mode = std::strtoul(args[2].c_str(), 0, 8);
}
ret = make_dir(args[1].c_str(), mode);
@@ -637,10 +637,13 @@
static int do_setrlimit(const std::vector<std::string>& args) {
struct rlimit limit;
int resource;
- resource = std::stoi(args[1]);
- limit.rlim_cur = std::stoi(args[2]);
- limit.rlim_max = std::stoi(args[3]);
- return setrlimit(resource, &limit);
+ if (android::base::ParseInt(args[1], &resource) &&
+ android::base::ParseUint(args[2], &limit.rlim_cur) &&
+ android::base::ParseUint(args[3], &limit.rlim_max)) {
+ return setrlimit(resource, &limit);
+ }
+ LOG(WARNING) << "ignoring setrlimit " << args[1] << " " << args[2] << " " << args[3];
+ return -1;
}
static int do_start(const std::vector<std::string>& args) {
@@ -700,6 +703,15 @@
callback_on_ro_remount = unmount_and_fsck;
} else if (cmd == ANDROID_RB_RESTART2) {
reboot_target = &command[len + 1];
+ // When rebooting to the bootloader notify the bootloader writing
+ // also the BCB.
+ if (strcmp(reboot_target, "bootloader") == 0) {
+ std::string err;
+ if (!write_reboot_bootloader(&err)) {
+ LOG(ERROR) << "reboot-bootloader: Error writing "
+ "bootloader_message: " << err;
+ }
+ }
}
} else if (command[len] != '\0') {
LOG(ERROR) << "powerctl: unrecognized reboot target '" << &command[len] << "'";
@@ -709,7 +721,7 @@
std::string timeout = property_get("ro.build.shutdown_timeout");
unsigned int delay = 0;
- if (android::base::ParseUint(timeout.c_str(), &delay) && delay > 0) {
+ if (android::base::ParseUint(timeout, &delay) && delay > 0) {
Timer t;
// Ask all services to terminate.
ServiceManager::GetInstance().ForEachService(
@@ -764,13 +776,11 @@
}
static int do_sysclktz(const std::vector<std::string>& args) {
- struct timezone tz;
-
- memset(&tz, 0, sizeof(tz));
- tz.tz_minuteswest = std::stoi(args[1]);
- if (settimeofday(NULL, &tz))
- return -1;
- return 0;
+ struct timezone tz = {};
+ if (android::base::ParseInt(args[1], &tz.tz_minuteswest) && settimeofday(NULL, &tz) != -1) {
+ return 0;
+ }
+ return -1;
}
static int do_verity_load_state(const std::vector<std::string>& args) {
@@ -914,7 +924,8 @@
static int do_loglevel(const std::vector<std::string>& args) {
// TODO: support names instead/as well?
- int log_level = std::stoi(args[1]);
+ int log_level = -1;
+ android::base::ParseInt(args[1], &log_level);
android::base::LogSeverity severity;
switch (log_level) {
case 7: severity = android::base::DEBUG; break;
@@ -947,9 +958,12 @@
if (args.size() == 2) {
return wait_for_file(args[1].c_str(), COMMAND_RETRY_TIMEOUT);
} else if (args.size() == 3) {
- return wait_for_file(args[1].c_str(), std::stoi(args[2]));
- } else
- return -1;
+ int timeout;
+ if (android::base::ParseInt(args[2], &timeout)) {
+ return wait_for_file(args[1].c_str(), timeout);
+ }
+ }
+ return -1;
}
/*
diff --git a/init/capabilities.cpp b/init/capabilities.cpp
new file mode 100644
index 0000000..4592adc
--- /dev/null
+++ b/init/capabilities.cpp
@@ -0,0 +1,166 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "capabilities.h"
+
+#include <sys/capability.h>
+#include <sys/prctl.h>
+
+#include <map>
+#include <memory>
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+
+#define CAP_MAP_ENTRY(cap) { #cap, CAP_##cap }
+
+namespace {
+const std::map<std::string, int> cap_map = {
+ CAP_MAP_ENTRY(CHOWN),
+ CAP_MAP_ENTRY(DAC_OVERRIDE),
+ CAP_MAP_ENTRY(DAC_READ_SEARCH),
+ CAP_MAP_ENTRY(FOWNER),
+ CAP_MAP_ENTRY(FSETID),
+ CAP_MAP_ENTRY(KILL),
+ CAP_MAP_ENTRY(SETGID),
+ CAP_MAP_ENTRY(SETUID),
+ CAP_MAP_ENTRY(SETPCAP),
+ CAP_MAP_ENTRY(LINUX_IMMUTABLE),
+ CAP_MAP_ENTRY(NET_BIND_SERVICE),
+ CAP_MAP_ENTRY(NET_BROADCAST),
+ CAP_MAP_ENTRY(NET_ADMIN),
+ CAP_MAP_ENTRY(NET_RAW),
+ CAP_MAP_ENTRY(IPC_LOCK),
+ CAP_MAP_ENTRY(IPC_OWNER),
+ CAP_MAP_ENTRY(SYS_MODULE),
+ CAP_MAP_ENTRY(SYS_RAWIO),
+ CAP_MAP_ENTRY(SYS_CHROOT),
+ CAP_MAP_ENTRY(SYS_PTRACE),
+ CAP_MAP_ENTRY(SYS_PACCT),
+ CAP_MAP_ENTRY(SYS_ADMIN),
+ CAP_MAP_ENTRY(SYS_BOOT),
+ CAP_MAP_ENTRY(SYS_NICE),
+ CAP_MAP_ENTRY(SYS_RESOURCE),
+ CAP_MAP_ENTRY(SYS_TIME),
+ CAP_MAP_ENTRY(SYS_TTY_CONFIG),
+ CAP_MAP_ENTRY(MKNOD),
+ CAP_MAP_ENTRY(LEASE),
+ CAP_MAP_ENTRY(AUDIT_WRITE),
+ CAP_MAP_ENTRY(AUDIT_CONTROL),
+ CAP_MAP_ENTRY(SETFCAP),
+ CAP_MAP_ENTRY(MAC_OVERRIDE),
+ CAP_MAP_ENTRY(MAC_ADMIN),
+ CAP_MAP_ENTRY(SYSLOG),
+ CAP_MAP_ENTRY(WAKE_ALARM),
+ CAP_MAP_ENTRY(BLOCK_SUSPEND),
+ CAP_MAP_ENTRY(AUDIT_READ),
+};
+
+static_assert(CAP_LAST_CAP == CAP_AUDIT_READ, "CAP_LAST_CAP is not CAP_AUDIT_READ");
+
+bool DropBoundingSet(const CapSet& to_keep) {
+ for (size_t cap = 0; cap < to_keep.size(); ++cap) {
+ if (to_keep.test(cap)) {
+ // No need to drop this capability.
+ continue;
+ }
+ if (cap_drop_bound(cap) == -1) {
+ PLOG(ERROR) << "cap_drop_bound(" << cap << ") failed";
+ return false;
+ }
+ }
+ return true;
+}
+
+bool SetProcCaps(const CapSet& to_keep, bool add_setpcap) {
+ cap_t caps = cap_init();
+ auto deleter = [](cap_t* p) { cap_free(*p); };
+ std::unique_ptr<cap_t, decltype(deleter)> ptr_caps(&caps, deleter);
+
+ cap_clear(caps);
+ cap_value_t value[1];
+ for (size_t cap = 0; cap <= to_keep.size(); ++cap) {
+ if (to_keep.test(cap)) {
+ value[0] = cap;
+ if (cap_set_flag(caps, CAP_INHERITABLE, arraysize(value), value, CAP_SET) != 0 ||
+ cap_set_flag(caps, CAP_PERMITTED, arraysize(value), value, CAP_SET) != 0) {
+ PLOG(ERROR) << "cap_set_flag(INHERITABLE|PERMITTED, " << cap << ") failed";
+ return false;
+ }
+ }
+ }
+
+ if (add_setpcap) {
+ value[0] = CAP_SETPCAP;
+ if (cap_set_flag(caps, CAP_PERMITTED, arraysize(value), value, CAP_SET) != 0 ||
+ cap_set_flag(caps, CAP_EFFECTIVE, arraysize(value), value, CAP_SET) != 0) {
+ PLOG(ERROR) << "cap_set_flag(PERMITTED|EFFECTIVE, " << CAP_SETPCAP << ") failed";
+ return false;
+ }
+ }
+
+ if (cap_set_proc(caps) != 0) {
+ PLOG(ERROR) << "cap_set_proc(" << to_keep.to_ulong() << ") failed";
+ return false;
+ }
+ return true;
+}
+
+bool SetAmbientCaps(const CapSet& to_raise) {
+ for (size_t cap = 0; cap < to_raise.size(); ++cap) {
+ if (to_raise.test(cap)) {
+ if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0) != 0) {
+ PLOG(ERROR) << "prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, " << cap << ") failed";
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+} // namespace anonymous
+
+int LookupCap(const std::string& cap_name) {
+ auto e = cap_map.find(cap_name);
+ if (e != cap_map.end()) {
+ return e->second;
+ } else {
+ return -1;
+ }
+}
+
+bool SetCapsForExec(const CapSet& to_keep) {
+ // Need to keep SETPCAP to drop bounding set below.
+ bool add_setpcap = true;
+ if (!SetProcCaps(to_keep, add_setpcap)) {
+ LOG(ERROR) << "failed to apply initial capset";
+ return false;
+ }
+
+ if (!DropBoundingSet(to_keep)) {
+ return false;
+ }
+
+ // If SETPCAP wasn't specifically requested, drop it now.
+ add_setpcap = false;
+ if (!SetProcCaps(to_keep, add_setpcap)) {
+ LOG(ERROR) << "failed to apply final capset";
+ return false;
+ }
+
+ // Add the capabilities to the ambient set so that they are preserved across
+ // execve(2).
+ // See http://man7.org/linux/man-pages/man7/capabilities.7.html.
+ return SetAmbientCaps(to_keep);
+}
diff --git a/Android.bp b/init/capabilities.h
similarity index 74%
rename from Android.bp
rename to init/capabilities.h
index 949a7fe..368178d 100644
--- a/Android.bp
+++ b/init/capabilities.h
@@ -12,11 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-ndk_headers {
- name: "liblog_headers",
- from: "include/android",
- to: "android",
- srcs: ["include/android/log.h"],
-}
+#include <linux/capability.h>
-optional_subdirs = ["*"]
+#include <bitset>
+#include <string>
+
+using CapSet = std::bitset<CAP_LAST_CAP + 1>;
+
+int LookupCap(const std::string& cap_name);
+bool SetCapsForExec(const CapSet& to_keep);
diff --git a/init/descriptors.cpp b/init/descriptors.cpp
new file mode 100644
index 0000000..10aae88
--- /dev/null
+++ b/init/descriptors.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "descriptors.h"
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <android-base/stringprintf.h>
+#include <cutils/files.h>
+#include <cutils/sockets.h>
+
+#include "init.h"
+#include "log.h"
+#include "util.h"
+
+DescriptorInfo::DescriptorInfo(const std::string& name, const std::string& type, uid_t uid,
+ gid_t gid, int perm, const std::string& context)
+ : name_(name), type_(type), uid_(uid), gid_(gid), perm_(perm), context_(context) {
+}
+
+DescriptorInfo::~DescriptorInfo() {
+}
+
+std::ostream& operator<<(std::ostream& os, const DescriptorInfo& info) {
+ return os << " descriptors " << info.name_ << " " << info.type_ << " " << std::oct << info.perm_;
+}
+
+bool DescriptorInfo::operator==(const DescriptorInfo& other) const {
+ return name_ == other.name_ && type_ == other.type_ && key() == other.key();
+}
+
+void DescriptorInfo::CreateAndPublish(const std::string& globalContext) const {
+ // Create
+ const std::string& contextStr = context_.empty() ? globalContext : context_;
+ int fd = Create(contextStr);
+ if (fd < 0) return;
+
+ // Publish
+ std::string publishedName = key() + name_;
+ std::for_each(publishedName.begin(), publishedName.end(),
+ [] (char& c) { c = isalnum(c) ? c : '_'; });
+
+ std::string val = android::base::StringPrintf("%d", fd);
+ add_environment(publishedName.c_str(), val.c_str());
+
+ // make sure we don't close on exec
+ fcntl(fd, F_SETFD, 0);
+}
+
+void DescriptorInfo::Clean() const {
+}
+
+SocketInfo::SocketInfo(const std::string& name, const std::string& type, uid_t uid,
+ gid_t gid, int perm, const std::string& context)
+ : DescriptorInfo(name, type, uid, gid, perm, context) {
+}
+
+void SocketInfo::Clean() const {
+ unlink(android::base::StringPrintf(ANDROID_SOCKET_DIR "/%s", name().c_str()).c_str());
+}
+
+int SocketInfo::Create(const std::string& context) const {
+ int flags = ((type() == "stream" ? SOCK_STREAM :
+ (type() == "dgram" ? SOCK_DGRAM :
+ SOCK_SEQPACKET)));
+ return create_socket(name().c_str(), flags, perm(), uid(), gid(), context.c_str());
+}
+
+const std::string SocketInfo::key() const {
+ return ANDROID_SOCKET_ENV_PREFIX;
+}
+
+FileInfo::FileInfo(const std::string& name, const std::string& type, uid_t uid,
+ gid_t gid, int perm, const std::string& context)
+ : DescriptorInfo(name, type, uid, gid, perm, context) {
+}
+
+int FileInfo::Create(const std::string& context) const {
+ int flags = ((type() == "r" ? O_RDONLY :
+ (type() == "w" ? (O_WRONLY | O_CREAT) :
+ (O_RDWR | O_CREAT))));
+ return create_file(name().c_str(), flags, perm(), uid(), gid(), context.c_str());
+}
+
+const std::string FileInfo::key() const {
+ return ANDROID_FILE_ENV_PREFIX;
+}
diff --git a/init/descriptors.h b/init/descriptors.h
new file mode 100644
index 0000000..ff276fb
--- /dev/null
+++ b/init/descriptors.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef _INIT_DESCRIPTORS_H
+#define _INIT_DESCRIPTORS_H
+
+#include <sys/types.h>
+
+#include <string>
+
+class DescriptorInfo {
+ public:
+ DescriptorInfo(const std::string& name, const std::string& type, uid_t uid,
+ gid_t gid, int perm, const std::string& context);
+ virtual ~DescriptorInfo();
+
+ friend std::ostream& operator<<(std::ostream& os, const class DescriptorInfo& info);
+ bool operator==(const DescriptorInfo& other) const;
+
+ void CreateAndPublish(const std::string& globalContext) const;
+ virtual void Clean() const;
+
+ protected:
+ const std::string& name() const { return name_; }
+ const std::string& type() const { return type_; }
+ uid_t uid() const { return uid_; }
+ gid_t gid() const { return gid_; }
+ int perm() const { return perm_; }
+ const std::string& context() const { return context_; }
+
+ private:
+ std::string name_;
+ std::string type_;
+ uid_t uid_;
+ gid_t gid_;
+ int perm_;
+ std::string context_;
+
+ virtual int Create(const std::string& globalContext) const = 0;
+ virtual const std::string key() const = 0;
+};
+
+std::ostream& operator<<(std::ostream& os, const DescriptorInfo& info);
+
+class SocketInfo : public DescriptorInfo {
+ public:
+ SocketInfo(const std::string& name, const std::string& type, uid_t uid,
+ gid_t gid, int perm, const std::string& context);
+ void Clean() const override;
+ private:
+ virtual int Create(const std::string& context) const override;
+ virtual const std::string key() const override;
+};
+
+class FileInfo : public DescriptorInfo {
+ public:
+ FileInfo(const std::string& name, const std::string& type, uid_t uid,
+ gid_t gid, int perm, const std::string& context);
+ private:
+ virtual int Create(const std::string& context) const override;
+ virtual const std::string key() const override;
+};
+
+#endif
diff --git a/init/init.cpp b/init/init.cpp
index 957527b..7c37d28 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -585,19 +585,43 @@
mount("devpts", "/dev/pts", "devpts", 0, NULL);
#define MAKE_STR(x) __STRING(x)
mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));
+ gid_t groups[] = { AID_READPROC };
+ setgroups(arraysize(groups), groups);
mount("sysfs", "/sys", "sysfs", 0, NULL);
mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
- early_mount();
}
// Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
// talk to the outside world...
InitKernelLogging(argv);
- LOG(INFO) << "init " << (is_first_stage ? "first stage" : "second stage") << " started!";
+ if (is_first_stage) {
+ LOG(INFO) << "init first stage started!";
- if (!is_first_stage) {
+ // Mount devices defined in android.early.* kernel commandline
+ early_mount();
+
+ // Set up SELinux, including loading the SELinux policy if we're in the kernel domain.
+ selinux_initialize(true);
+
+ // If we're in the kernel domain, re-exec init to transition to the init domain now
+ // that the SELinux policy has been loaded.
+
+ if (restorecon("/init") == -1) {
+ PLOG(ERROR) << "restorecon failed";
+ security_failure();
+ }
+ char* path = argv[0];
+ char* args[] = { path, const_cast<char*>("--second-stage"), nullptr };
+ if (execv(path, args) == -1) {
+ PLOG(ERROR) << "execv(\"" << path << "\") failed";
+ security_failure();
+ }
+
+ } else {
+ LOG(INFO) << "init second stage started!";
+
// Indicate that booting is in progress to background fw loaders, etc.
close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
@@ -611,24 +635,9 @@
// Propagate the kernel variables to internal variables
// used by init as well as the current required properties.
export_kernel_boot_props();
- }
- // Set up SELinux, including loading the SELinux policy if we're in the kernel domain.
- selinux_initialize(is_first_stage);
-
- // If we're in the kernel domain, re-exec init to transition to the init domain now
- // that the SELinux policy has been loaded.
- if (is_first_stage) {
- if (restorecon("/init") == -1) {
- PLOG(ERROR) << "restorecon failed";
- security_failure();
- }
- char* path = argv[0];
- char* args[] = { path, const_cast<char*>("--second-stage"), nullptr };
- if (execv(path, args) == -1) {
- PLOG(ERROR) << "execv(\"" << path << "\") failed";
- security_failure();
- }
+ // Now set up SELinux for second stage
+ selinux_initialize(false);
}
// These directories were necessarily created before initial policy load
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 1e569af..e7176c6 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -141,23 +141,24 @@
}
}
-static bool is_legal_property_name(const char* name, size_t namelen)
+bool is_legal_property_name(const std::string &name)
{
- size_t i;
+ size_t namelen = name.size();
+
if (namelen >= PROP_NAME_MAX) return false;
if (namelen < 1) return false;
if (name[0] == '.') return false;
if (name[namelen - 1] == '.') return false;
- /* Only allow alphanumeric, plus '.', '-', or '_' */
+ /* Only allow alphanumeric, plus '.', '-', '@', or '_' */
/* Don't allow ".." to appear in a property name */
- for (i = 0; i < namelen; i++) {
+ for (size_t i = 0; i < namelen; i++) {
if (name[i] == '.') {
// i=0 is guaranteed to never have a dot. See above.
if (name[i-1] == '.') return false;
continue;
}
- if (name[i] == '_' || name[i] == '-') continue;
+ if (name[i] == '_' || name[i] == '-' || name[i] == '@') continue;
if (name[i] >= 'a' && name[i] <= 'z') continue;
if (name[i] >= 'A' && name[i] <= 'Z') continue;
if (name[i] >= '0' && name[i] <= '9') continue;
@@ -168,10 +169,9 @@
}
static int property_set_impl(const char* name, const char* value) {
- size_t namelen = strlen(name);
size_t valuelen = strlen(value);
- if (!is_legal_property_name(name, namelen)) return -1;
+ if (!is_legal_property_name(name)) return -1;
if (valuelen >= PROP_VALUE_MAX) return -1;
if (strcmp("selinux.restorecon_recursive", name) == 0 && valuelen > 0) {
@@ -188,7 +188,7 @@
__system_property_update(pi, value, valuelen);
} else {
- int rc = __system_property_add(name, namelen, value, valuelen);
+ int rc = __system_property_add(name, strlen(name), value, valuelen);
if (rc < 0) {
return rc;
}
@@ -272,7 +272,7 @@
msg.name[PROP_NAME_MAX-1] = 0;
msg.value[PROP_VALUE_MAX-1] = 0;
- if (!is_legal_property_name(msg.name, strlen(msg.name))) {
+ if (!is_legal_property_name(msg.name)) {
LOG(ERROR) << "sys_prop: illegal property name \"" << msg.name << "\"";
close(s);
return;
diff --git a/init/property_service.h b/init/property_service.h
index dbaed34..e3a2acb 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -34,6 +34,7 @@
extern void start_property_service(void);
std::string property_get(const char* name);
extern int property_set(const char *name, const char *value);
+extern bool is_legal_property_name(const std::string &name);
#endif /* _INIT_PROPERTY_H */
diff --git a/init/readme.txt b/init/readme.txt
index 26225b2..500b1d8 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -141,33 +141,49 @@
Set the environment variable <name> to <value> in the launched process.
socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]
- Create a unix domain socket named /dev/socket/<name> and pass
- its fd to the launched process. <type> must be "dgram", "stream" or "seqpacket".
- User and group default to 0.
- 'seclabel' is the SELinux security context for the socket.
- It defaults to the service security context, as specified by seclabel or
- computed based on the service executable file security context.
+ Create a unix domain socket named /dev/socket/<name> and pass its fd to the
+ launched process. <type> must be "dgram", "stream" or "seqpacket". User and
+ group default to 0. 'seclabel' is the SELinux security context for the
+ socket. It defaults to the service security context, as specified by
+ seclabel or computed based on the service executable file security context.
+ For native executables see libcutils android_get_control_socket().
+
+file <path> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]
+ Open/Create a file path and pass its fd to the launched process. <type> must
+ be "r", "w" or "rw". User and group default to 0. 'seclabel' is the SELinux
+ security context for the file if it must be created. It defaults to the
+ service security context, as specified by seclabel or computed based on the
+ service executable file security context. For native executables see
+ libcutils android_get_control_file().
user <username>
- Change to username before exec'ing this service.
+ Change to 'username' before exec'ing this service.
Currently defaults to root. (??? probably should default to nobody)
As of Android M, processes should use this option even if they
- require linux capabilities. Previously, to acquire linux
+ require Linux capabilities. Previously, to acquire Linux
capabilities, a process would need to run as root, request the
capabilities, then drop to its desired uid. There is a new
mechanism through fs_config that allows device manufacturers to add
- linux capabilities to specific binaries on a file system that should
+ Linux capabilities to specific binaries on a file system that should
be used instead. This mechanism is described on
http://source.android.com/devices/tech/config/filesystem.html. When
using this new mechanism, processes can use the user option to
select their desired uid without ever running as root.
+ As of Android O, processes can also request capabilities directly in their .rc
+ files. See the "capabilities" option below.
group <groupname> [ <groupname> ]*
- Change to groupname before exec'ing this service. Additional
+ Change to 'groupname' before exec'ing this service. Additional
groupnames beyond the (required) first one are used to set the
supplemental groups of the process (via setgroups()).
Currently defaults to root. (??? probably should default to nobody)
+capabilities <capability> [ <capability> ]*
+ Set capabilities when exec'ing this service. 'capability' should be a Linux
+ capability without the "CAP_" prefix, like "NET_ADMIN" or "SETPCAP". See
+ http://man7.org/linux/man-pages/man7/capabilities.7.html for a list of Linux
+ capabilities.
+
seclabel <seclabel>
Change to 'seclabel' before exec'ing this service.
Primarily for use by services run from the rootfs, e.g. ueventd, adbd.
diff --git a/init/service.cpp b/init/service.cpp
index 503d84f..f093dd9 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -17,6 +17,7 @@
#include "service.h"
#include <fcntl.h>
+#include <linux/securebits.h>
#include <sched.h>
#include <sys/mount.h>
#include <sys/prctl.h>
@@ -31,10 +32,10 @@
#include <selinux/selinux.h>
#include <android-base/file.h>
+#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <cutils/android_reboot.h>
-#include <cutils/sockets.h>
#include <system/thread_defs.h>
#include <processgroup/processgroup.h>
@@ -46,6 +47,7 @@
#include "property_service.h"
#include "util.h"
+using android::base::ParseInt;
using android::base::StringPrintf;
using android::base::WriteStringToFile;
@@ -142,14 +144,6 @@
strs->push_back(nullptr);
}
-SocketInfo::SocketInfo() : uid(0), gid(0), perm(0) {
-}
-
-SocketInfo::SocketInfo(const std::string& name, const std::string& type, uid_t uid,
- gid_t gid, int perm, const std::string& socketcon)
- : name(name), type(type), uid(uid), gid(gid), perm(perm), socketcon(socketcon) {
-}
-
ServiceEnvironmentInfo::ServiceEnvironmentInfo() {
}
@@ -169,14 +163,16 @@
Service::Service(const std::string& name, const std::string& classname,
unsigned flags, uid_t uid, gid_t gid,
- const std::vector<gid_t>& supp_gids, unsigned namespace_flags,
+ const std::vector<gid_t>& supp_gids,
+ const CapSet& capabilities, unsigned namespace_flags,
const std::string& seclabel,
const std::vector<std::string>& args)
: name_(name), classname_(classname), flags_(flags), pid_(0),
time_started_(0), time_crashed_(0), nr_crashed_(0), uid_(uid), gid_(gid),
- supp_gids_(supp_gids), namespace_flags_(namespace_flags),
- seclabel_(seclabel), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0),
- priority_(0), oom_score_adjust_(-1000), args_(args) {
+ supp_gids_(supp_gids), capabilities_(capabilities),
+ namespace_flags_(namespace_flags), seclabel_(seclabel),
+ ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0), priority_(0),
+ oom_score_adjust_(-1000), args_(args) {
onrestart_.InitSingleTrigger("onrestart");
}
@@ -208,21 +204,14 @@
}
}
-void Service::CreateSockets(const std::string& context) {
- for (const auto& si : sockets_) {
- int socket_type = ((si.type == "stream" ? SOCK_STREAM :
- (si.type == "dgram" ? SOCK_DGRAM :
- SOCK_SEQPACKET)));
- const char* socketcon = !si.socketcon.empty() ? si.socketcon.c_str() : context.c_str();
-
- int s = create_socket(si.name.c_str(), socket_type, si.perm, si.uid, si.gid, socketcon);
- if (s >= 0) {
- PublishSocket(si.name, s);
+void Service::SetProcessAttributes() {
+ // Keep capabilites on uid change.
+ if (capabilities_.any() && uid_) {
+ if (prctl(PR_SET_SECUREBITS, SECBIT_KEEP_CAPS | SECBIT_KEEP_CAPS_LOCKED) != 0) {
+ PLOG(FATAL) << "prtcl(PR_SET_KEEPCAPS) failed for " << name_;
}
}
-}
-void Service::SetProcessAttributes() {
// TODO: work out why this fails for `console` then upgrade to FATAL.
if (setpgid(0, getpid()) == -1) PLOG(ERROR) << "setpgid failed for " << name_;
@@ -231,10 +220,8 @@
PLOG(FATAL) << "setgid failed for " << name_;
}
}
- if (!supp_gids_.empty()) {
- if (setgroups(supp_gids_.size(), &supp_gids_[0]) != 0) {
- PLOG(FATAL) << "setgroups failed for " << name_;
- }
+ if (setgroups(supp_gids_.size(), &supp_gids_[0]) != 0) {
+ PLOG(FATAL) << "setgroups failed for " << name_;
}
if (uid_) {
if (setuid(uid_) != 0) {
@@ -251,6 +238,11 @@
PLOG(FATAL) << "setpriority failed for " << name_;
}
}
+ if (capabilities_.any()) {
+ if (!SetCapsForExec(capabilities_)) {
+ LOG(FATAL) << "cannot set capabilities for " << name_;
+ }
+ }
}
bool Service::Reap() {
@@ -258,11 +250,9 @@
KillProcessGroup(SIGKILL);
}
- // Remove any sockets we may have created.
- for (const auto& si : sockets_) {
- std::string tmp = StringPrintf(ANDROID_SOCKET_DIR "/%s", si.name.c_str());
- unlink(tmp.c_str());
- }
+ // Remove any descriptor resources we may have created.
+ std::for_each(descriptors_.begin(), descriptors_.end(),
+ std::bind(&DescriptorInfo::Clean, std::placeholders::_1));
if (flags_ & SVC_EXEC) {
LOG(INFO) << "SVC_EXEC pid " << pid_ << " finished...";
@@ -315,9 +305,23 @@
LOG(INFO) << "service " << name_;
LOG(INFO) << " class '" << classname_ << "'";
LOG(INFO) << " exec "<< android::base::Join(args_, " ");
- for (const auto& si : sockets_) {
- LOG(INFO) << " socket " << si.name << " " << si.type << " " << std::oct << si.perm;
+ std::for_each(descriptors_.begin(), descriptors_.end(),
+ [] (const auto& info) { LOG(INFO) << *info; });
+}
+
+bool Service::ParseCapabilities(const std::vector<std::string>& args, std::string* err) {
+ capabilities_ = 0;
+
+ for (size_t i = 1; i < args.size(); i++) {
+ const std::string& arg = args[i];
+ int cap = LookupCap(arg);
+ if (cap == -1) {
+ *err = StringPrintf("invalid capability '%s'", arg.c_str());
+ return false;
+ }
+ capabilities_[cap] = true;
}
+ return true;
}
bool Service::ParseClass(const std::vector<std::string>& args, std::string* err) {
@@ -351,22 +355,19 @@
}
bool Service::ParsePriority(const std::vector<std::string>& args, std::string* err) {
- priority_ = std::stoi(args[1]);
-
- if (priority_ < ANDROID_PRIORITY_HIGHEST || priority_ > ANDROID_PRIORITY_LOWEST) {
- priority_ = 0;
+ priority_ = 0;
+ if (!ParseInt(args[1], &priority_,
+ static_cast<int>(ANDROID_PRIORITY_HIGHEST), // highest is negative
+ static_cast<int>(ANDROID_PRIORITY_LOWEST))) {
*err = StringPrintf("process priority value must be range %d - %d",
ANDROID_PRIORITY_HIGHEST, ANDROID_PRIORITY_LOWEST);
return false;
}
-
return true;
}
bool Service::ParseIoprio(const std::vector<std::string>& args, std::string* err) {
- ioprio_pri_ = std::stoul(args[2], 0, 8);
-
- if (ioprio_pri_ < 0 || ioprio_pri_ > 7) {
+ if (!ParseInt(args[2], &ioprio_pri_, 0, 7)) {
*err = "priority value must be range 0 - 7";
return false;
}
@@ -387,7 +388,12 @@
bool Service::ParseKeycodes(const std::vector<std::string>& args, std::string* err) {
for (std::size_t i = 1; i < args.size(); i++) {
- keycodes_.emplace_back(std::stoi(args[i]));
+ int code;
+ if (ParseInt(args[i], &code)) {
+ keycodes_.emplace_back(code);
+ } else {
+ LOG(WARNING) << "ignoring invalid keycode: " << args[i];
+ }
}
return true;
}
@@ -420,17 +426,13 @@
}
bool Service::ParseOomScoreAdjust(const std::vector<std::string>& args, std::string* err) {
- oom_score_adjust_ = std::stol(args[1], 0, 10);
-
- if (oom_score_adjust_ < -1000 || oom_score_adjust_ > 1000) {
+ if (!ParseInt(args[1], &oom_score_adjust_, -1000, 1000)) {
*err = "oom_score_adjust value must be in range -1000 - +1000";
return false;
}
-
return true;
}
-
bool Service::ParseSeclabel(const std::vector<std::string>& args, std::string* err) {
seclabel_ = args[1];
return true;
@@ -441,20 +443,48 @@
return true;
}
-/* name type perm [ uid gid context ] */
+template <typename T>
+bool Service::AddDescriptor(const std::vector<std::string>& args, std::string* err) {
+ int perm = args.size() > 3 ? std::strtoul(args[3].c_str(), 0, 8) : -1;
+ uid_t uid = args.size() > 4 ? decode_uid(args[4].c_str()) : 0;
+ gid_t gid = args.size() > 5 ? decode_uid(args[5].c_str()) : 0;
+ std::string context = args.size() > 6 ? args[6] : "";
+
+ auto descriptor = std::make_unique<T>(args[1], args[2], uid, gid, perm, context);
+
+ auto old =
+ std::find_if(descriptors_.begin(), descriptors_.end(),
+ [&descriptor] (const auto& other) { return descriptor.get() == other.get(); });
+
+ if (old != descriptors_.end()) {
+ *err = "duplicate descriptor " + args[1] + " " + args[2];
+ return false;
+ }
+
+ descriptors_.emplace_back(std::move(descriptor));
+ return true;
+}
+
+// name type perm [ uid gid context ]
bool Service::ParseSocket(const std::vector<std::string>& args, std::string* err) {
if (args[2] != "dgram" && args[2] != "stream" && args[2] != "seqpacket") {
*err = "socket type must be 'dgram', 'stream' or 'seqpacket'";
return false;
}
+ return AddDescriptor<SocketInfo>(args, err);
+}
- int perm = std::stoul(args[3], 0, 8);
- uid_t uid = args.size() > 4 ? decode_uid(args[4].c_str()) : 0;
- gid_t gid = args.size() > 5 ? decode_uid(args[5].c_str()) : 0;
- std::string socketcon = args.size() > 6 ? args[6] : "";
-
- sockets_.emplace_back(args[1], args[2], uid, gid, perm, socketcon);
- return true;
+// name type perm [ uid gid context ]
+bool Service::ParseFile(const std::vector<std::string>& args, std::string* err) {
+ if (args[2] != "r" && args[2] != "w" && args[2] != "rw") {
+ *err = "file type must be 'r', 'w' or 'rw'";
+ return false;
+ }
+ if ((args[1][0] != '/') || (args[1].find("../") != std::string::npos)) {
+ *err = "file name must not be relative";
+ return false;
+ }
+ return AddDescriptor<FileInfo>(args, err);
}
bool Service::ParseUser(const std::vector<std::string>& args, std::string* err) {
@@ -478,6 +508,8 @@
Service::OptionParserMap::Map& Service::OptionParserMap::map() const {
constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
static const Map option_parsers = {
+ {"capabilities",
+ {1, kMax, &Service::ParseCapabilities}},
{"class", {1, 1, &Service::ParseClass}},
{"console", {0, 1, &Service::ParseConsole}},
{"critical", {0, 0, &Service::ParseCritical}},
@@ -494,6 +526,7 @@
{"seclabel", {1, 1, &Service::ParseSeclabel}},
{"setenv", {2, 2, &Service::ParseSetenv}},
{"socket", {3, 6, &Service::ParseSocket}},
+ {"file", {2, 6, &Service::ParseFile}},
{"user", {1, 1, &Service::ParseUser}},
{"writepid", {1, kMax, &Service::ParseWritepid}},
};
@@ -583,7 +616,8 @@
add_environment(ei.name.c_str(), ei.value.c_str());
}
- CreateSockets(scon);
+ std::for_each(descriptors_.begin(), descriptors_.end(),
+ std::bind(&DescriptorInfo::CreateAndPublish, std::placeholders::_1, scon));
std::string pid_str = StringPrintf("%d", getpid());
for (const auto& file : writepid_files_) {
@@ -757,15 +791,6 @@
close(fd);
}
-void Service::PublishSocket(const std::string& name, int fd) const {
- std::string key = StringPrintf(ANDROID_SOCKET_ENV_PREFIX "%s", name.c_str());
- std::string val = StringPrintf("%d", fd);
- add_environment(key.c_str(), val.c_str());
-
- /* make sure we don't close-on-exec */
- fcntl(fd, F_SETFD, 0);
-}
-
int ServiceManager::exec_count_ = 0;
ServiceManager::ServiceManager() {
@@ -809,6 +834,7 @@
exec_count_++;
std::string name = StringPrintf("exec %d (%s)", exec_count_, str_args[0].c_str());
unsigned flags = SVC_EXEC | SVC_ONESHOT;
+ CapSet no_capabilities;
unsigned namespace_flags = 0;
std::string seclabel = "";
@@ -829,9 +855,9 @@
}
}
- std::unique_ptr<Service> svc_p(new Service(name, "default", flags, uid, gid,
- supp_gids, namespace_flags,
- seclabel, str_args));
+ std::unique_ptr<Service> svc_p(new Service(name, "default", flags, uid, gid, supp_gids,
+ no_capabilities, namespace_flags, seclabel,
+ str_args));
if (!svc_p) {
LOG(ERROR) << "Couldn't allocate service for exec of '" << str_args[0] << "'";
return nullptr;
@@ -996,13 +1022,5 @@
}
bool ServiceParser::IsValidName(const std::string& name) const {
- if (name.size() > 16) {
- return false;
- }
- for (const auto& c : name) {
- if (!isalnum(c) && (c != '_') && (c != '-')) {
- return false;
- }
- }
- return true;
+ return is_legal_property_name("init.svc." + name);
}
diff --git a/init/service.h b/init/service.h
index 4a3412c..d9e8f57 100644
--- a/init/service.h
+++ b/init/service.h
@@ -26,6 +26,8 @@
#include <vector>
#include "action.h"
+#include "capabilities.h"
+#include "descriptors.h"
#include "init_parser.h"
#include "keyword_map.h"
@@ -47,18 +49,6 @@
class Action;
class ServiceManager;
-struct SocketInfo {
- SocketInfo();
- SocketInfo(const std::string& name, const std::string& type, uid_t uid,
- gid_t gid, int perm, const std::string& socketcon);
- std::string name;
- std::string type;
- uid_t uid;
- gid_t gid;
- int perm;
- std::string socketcon;
-};
-
struct ServiceEnvironmentInfo {
ServiceEnvironmentInfo();
ServiceEnvironmentInfo(const std::string& name, const std::string& value);
@@ -73,8 +63,9 @@
Service(const std::string& name, const std::string& classname,
unsigned flags, uid_t uid, gid_t gid,
- const std::vector<gid_t>& supp_gids, unsigned namespace_flags,
- const std::string& seclabel, const std::vector<std::string>& args);
+ const std::vector<gid_t>& supp_gids, const CapSet& capabilities,
+ unsigned namespace_flags, const std::string& seclabel,
+ const std::vector<std::string>& args);
bool ParseLine(const std::vector<std::string>& args, std::string* err);
bool Start();
@@ -111,11 +102,10 @@
void StopOrReset(int how);
void ZapStdio() const;
void OpenConsole() const;
- void PublishSocket(const std::string& name, int fd) const;
void KillProcessGroup(int signal);
- void CreateSockets(const std::string& scon);
void SetProcessAttributes();
+ bool ParseCapabilities(const std::vector<std::string>& args, std::string *err);
bool ParseClass(const std::vector<std::string>& args, std::string* err);
bool ParseConsole(const std::vector<std::string>& args, std::string* err);
bool ParseCritical(const std::vector<std::string>& args, std::string* err);
@@ -131,9 +121,13 @@
bool ParseSeclabel(const std::vector<std::string>& args, std::string* err);
bool ParseSetenv(const std::vector<std::string>& args, std::string* err);
bool ParseSocket(const std::vector<std::string>& args, std::string* err);
+ bool ParseFile(const std::vector<std::string>& args, std::string* err);
bool ParseUser(const std::vector<std::string>& args, std::string* err);
bool ParseWritepid(const std::vector<std::string>& args, std::string* err);
+ template <typename T>
+ bool AddDescriptor(const std::vector<std::string>& args, std::string* err);
+
std::string name_;
std::string classname_;
std::string console_;
@@ -147,11 +141,12 @@
uid_t uid_;
gid_t gid_;
std::vector<gid_t> supp_gids_;
+ CapSet capabilities_;
unsigned namespace_flags_;
std::string seclabel_;
- std::vector<SocketInfo> sockets_;
+ std::vector<std::unique_ptr<DescriptorInfo>> descriptors_;
std::vector<ServiceEnvironmentInfo> envvars_;
Action onrestart_; // Commands to execute on restart.
diff --git a/init/util.cpp b/init/util.cpp
index e451edd..ff46e4f 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -14,32 +14,33 @@
* limitations under the License.
*/
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <ftw.h>
+#include <pwd.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <errno.h>
#include <time.h>
-#include <ftw.h>
-#include <pwd.h>
+#include <unistd.h>
-#include <selinux/label.h>
#include <selinux/android.h>
+#include <selinux/label.h>
+#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <sys/socket.h>
#include <sys/un.h>
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include <android-base/strings.h>
-
+#include <android-base/unique_fd.h>
/* for ANDROID_SOCKET_* */
#include <cutils/sockets.h>
-#include <android-base/stringprintf.h>
#include "init.h"
#include "log.h"
@@ -89,10 +90,6 @@
int create_socket(const char *name, int type, mode_t perm, uid_t uid,
gid_t gid, const char *socketcon)
{
- struct sockaddr_un addr;
- int fd, ret, savederrno;
- char *filecon;
-
if (socketcon) {
if (setsockcreatecon(socketcon) == -1) {
PLOG(ERROR) << "setsockcreatecon(\"" << socketcon << "\") failed";
@@ -100,52 +97,49 @@
}
}
- fd = socket(PF_UNIX, type, 0);
+ android::base::unique_fd fd(socket(PF_UNIX, type, 0));
if (fd < 0) {
PLOG(ERROR) << "Failed to open socket '" << name << "'";
return -1;
}
- if (socketcon)
- setsockcreatecon(NULL);
+ if (socketcon) setsockcreatecon(NULL);
+ struct sockaddr_un addr;
memset(&addr, 0 , sizeof(addr));
addr.sun_family = AF_UNIX;
snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",
name);
- ret = unlink(addr.sun_path);
- if (ret != 0 && errno != ENOENT) {
+ if ((unlink(addr.sun_path) != 0) && (errno != ENOENT)) {
PLOG(ERROR) << "Failed to unlink old socket '" << name << "'";
- goto out_close;
+ return -1;
}
- filecon = NULL;
+ char *filecon = NULL;
if (sehandle) {
- ret = selabel_lookup(sehandle, &filecon, addr.sun_path, S_IFSOCK);
- if (ret == 0)
+ if (selabel_lookup(sehandle, &filecon, addr.sun_path, S_IFSOCK) == 0) {
setfscreatecon(filecon);
+ }
}
- ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
- savederrno = errno;
+ int ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
+ int savederrno = errno;
setfscreatecon(NULL);
freecon(filecon);
if (ret) {
- errno = savederrno;
+ errno = savederrno;
PLOG(ERROR) << "Failed to bind socket '" << name << "'";
goto out_unlink;
}
- ret = lchown(addr.sun_path, uid, gid);
- if (ret) {
+ if (lchown(addr.sun_path, uid, gid)) {
PLOG(ERROR) << "Failed to lchown socket '" << addr.sun_path << "'";
goto out_unlink;
}
- ret = fchmodat(AT_FDCWD, addr.sun_path, perm, AT_SYMLINK_NOFOLLOW);
- if (ret) {
+ if (fchmodat(AT_FDCWD, addr.sun_path, perm, AT_SYMLINK_NOFOLLOW)) {
PLOG(ERROR) << "Failed to fchmodat socket '" << addr.sun_path << "'";
goto out_unlink;
}
@@ -155,15 +149,76 @@
<< ", user " << uid
<< ", group " << gid;
- return fd;
+ return fd.release();
out_unlink:
unlink(addr.sun_path);
-out_close:
- close(fd);
return -1;
}
+/*
+ * create_file - opens and creates a file as dictated in init.rc.
+ * This file is inherited by the daemon. We communicate the file
+ * descriptor's value via the environment variable ANDROID_FILE_<basename>
+ */
+int create_file(const char *path, int flags, mode_t perm, uid_t uid,
+ gid_t gid, const char *filecon)
+{
+ char *secontext = NULL;
+
+ if (filecon) {
+ if (setsockcreatecon(filecon) == -1) {
+ PLOG(ERROR) << "setsockcreatecon(\"" << filecon << "\") failed";
+ return -1;
+ }
+ } else if (sehandle) {
+ if (selabel_lookup(sehandle, &secontext, path, perm) != -1) {
+ if (setfscreatecon(secontext) == -1) {
+ freecon(secontext); // does not upset errno value
+ PLOG(ERROR) << "setfscreatecon(\"" << secontext << "\") failed";
+ return -1;
+ }
+ }
+ }
+
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path, flags | O_NDELAY, perm)));
+ int savederrno = errno;
+
+ if (filecon) {
+ setsockcreatecon(NULL);
+ lsetfilecon(path, filecon);
+ } else {
+ setfscreatecon(NULL);
+ freecon(secontext);
+ }
+
+ if (fd < 0) {
+ errno = savederrno;
+ PLOG(ERROR) << "Failed to open/create file '" << path << "'";
+ return -1;
+ }
+
+ if (!(flags & O_NDELAY)) fcntl(fd, F_SETFD, flags);
+
+ if (lchown(path, uid, gid)) {
+ PLOG(ERROR) << "Failed to lchown file '" << path << "'";
+ return -1;
+ }
+ if (perm != static_cast<mode_t>(-1)) {
+ if (fchmodat(AT_FDCWD, path, perm, AT_SYMLINK_NOFOLLOW)) {
+ PLOG(ERROR) << "Failed to fchmodat file '" << path << "'";
+ return -1;
+ }
+ }
+
+ LOG(INFO) << "Created file '" << path << "'"
+ << ", mode " << std::oct << perm << std::dec
+ << ", user " << uid
+ << ", group " << gid;
+
+ return fd.release();
+}
+
bool read_file(const char* path, std::string* content) {
content->clear();
diff --git a/init/util.h b/init/util.h
index 5fcbdf0..12ab173 100644
--- a/init/util.h
+++ b/init/util.h
@@ -27,6 +27,8 @@
int create_socket(const char *name, int type, mode_t perm,
uid_t uid, gid_t gid, const char *socketcon);
+int create_file(const char *path, int mode, mode_t perm,
+ uid_t uid, gid_t gid, const char *filecon);
bool read_file(const char* path, std::string* content);
int write_file(const char* path, const char* content);
diff --git a/init/util_test.cpp b/init/util_test.cpp
index 228954b..6ecbf90 100644
--- a/init/util_test.cpp
+++ b/init/util_test.cpp
@@ -17,7 +17,15 @@
#include "util.h"
#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cutils/files.h>
#include <gtest/gtest.h>
+#include <selinux/android.h>
TEST(util, read_file_ENOENT) {
std::string s("hello");
@@ -41,3 +49,51 @@
EXPECT_EQ(UINT_MAX, decode_uid("toot"));
EXPECT_EQ(123U, decode_uid("123"));
}
+
+struct selabel_handle *sehandle;
+
+TEST(util, create_file) {
+ if (!sehandle) sehandle = selinux_android_file_context_handle();
+
+ static const char path[] = "/data/local/tmp/util.create_file.test";
+ static const char key[] = ANDROID_FILE_ENV_PREFIX "_data_local_tmp_util_create_file_test";
+ EXPECT_EQ(unsetenv(key), 0);
+ unlink(path);
+
+ int fd;
+ uid_t uid = decode_uid("logd");
+ gid_t gid = decode_uid("system");
+ mode_t perms = S_IRWXU | S_IWGRP | S_IRGRP | S_IROTH;
+ static const char context[] = "u:object_r:misc_logd_file:s0";
+ EXPECT_GE(fd = create_file(path, O_RDWR | O_CREAT, perms, uid, gid, context), 0);
+ if (fd < 0) return;
+ static const char hello[] = "hello world\n";
+ static const ssize_t len = strlen(hello);
+ EXPECT_EQ(write(fd, hello, len), len);
+ char buffer[sizeof(hello)];
+ memset(buffer, 0, sizeof(buffer));
+ EXPECT_GE(lseek(fd, 0, SEEK_SET), 0);
+ EXPECT_EQ(read(fd, buffer, sizeof(buffer)), len);
+ EXPECT_EQ(strcmp(hello, buffer), 0);
+ char val[32];
+ snprintf(val, sizeof(val), "%d", fd);
+ EXPECT_EQ(android_get_control_file(path), -1);
+ setenv(key, val, true);
+ EXPECT_EQ(android_get_control_file(path), fd);
+ close(fd);
+ EXPECT_EQ(android_get_control_file(path), -1);
+ EXPECT_EQ(unsetenv(key), 0);
+ struct stat st;
+ EXPECT_EQ(stat(path, &st), 0);
+ EXPECT_EQ(st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO), perms);
+ EXPECT_EQ(st.st_uid, uid);
+ EXPECT_EQ(st.st_gid, gid);
+ security_context_t con;
+ EXPECT_GE(getfilecon(path, &con), 0);
+ EXPECT_NE(con, static_cast<security_context_t>(NULL));
+ if (con) {
+ EXPECT_EQ(context, std::string(con));
+ }
+ freecon(con);
+ EXPECT_EQ(unlink(path), 0);
+}
diff --git a/libappfuse/Android.bp b/libappfuse/Android.bp
new file mode 100644
index 0000000..8b46154
--- /dev/null
+++ b/libappfuse/Android.bp
@@ -0,0 +1,26 @@
+// Copyright 2016 The Android Open Source Project
+
+cc_defaults {
+ name: "libappfuse_defaults",
+ local_include_dirs: ["include"],
+ shared_libs: ["libbase"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ clang: true
+}
+
+cc_library_shared {
+ name: "libappfuse",
+ defaults: ["libappfuse_defaults"],
+ export_include_dirs: ["include"],
+ srcs: ["FuseBuffer.cc", "FuseBridgeLoop.cc"]
+}
+
+cc_test {
+ name: "libappfuse_test",
+ defaults: ["libappfuse_defaults"],
+ shared_libs: ["libappfuse"],
+ srcs: ["tests/FuseBridgeLoopTest.cc", "tests/FuseBufferTest.cc"]
+}
diff --git a/libappfuse/FuseBridgeLoop.cc b/libappfuse/FuseBridgeLoop.cc
new file mode 100644
index 0000000..332556d
--- /dev/null
+++ b/libappfuse/FuseBridgeLoop.cc
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specic language governing permissions and
+ * limitations under the License.
+ */
+
+#include "libappfuse/FuseBridgeLoop.h"
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+
+namespace android {
+
+bool FuseBridgeLoop::Start(
+ int raw_dev_fd, int raw_proxy_fd, FuseBridgeLoop::Callback* callback) {
+ base::unique_fd dev_fd(raw_dev_fd);
+ base::unique_fd proxy_fd(raw_proxy_fd);
+
+ LOG(DEBUG) << "Start fuse loop.";
+ while (true) {
+ if (!buffer_.request.Read(dev_fd)) {
+ return false;
+ }
+
+ const uint32_t opcode = buffer_.request.header.opcode;
+ LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode;
+ switch (opcode) {
+ case FUSE_FORGET:
+ // Do not reply to FUSE_FORGET.
+ continue;
+
+ case FUSE_LOOKUP:
+ case FUSE_GETATTR:
+ case FUSE_OPEN:
+ case FUSE_READ:
+ case FUSE_WRITE:
+ case FUSE_RELEASE:
+ case FUSE_FLUSH:
+ if (!buffer_.request.Write(proxy_fd)) {
+ LOG(ERROR) << "Failed to write a request to the proxy.";
+ return false;
+ }
+ if (!buffer_.response.Read(proxy_fd)) {
+ LOG(ERROR) << "Failed to read a response from the proxy.";
+ return false;
+ }
+ break;
+
+ case FUSE_INIT:
+ buffer_.HandleInit();
+ break;
+
+ default:
+ buffer_.HandleNotImpl();
+ break;
+ }
+
+ if (!buffer_.response.Write(dev_fd)) {
+ LOG(ERROR) << "Failed to write a response to the device.";
+ return false;
+ }
+
+ if (opcode == FUSE_INIT) {
+ callback->OnMount();
+ }
+ }
+}
+
+} // namespace android
diff --git a/libappfuse/FuseBuffer.cc b/libappfuse/FuseBuffer.cc
new file mode 100644
index 0000000..45280a5
--- /dev/null
+++ b/libappfuse/FuseBuffer.cc
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specic language governing permissions and
+ * limitations under the License.
+ */
+
+#include "libappfuse/FuseBuffer.h"
+
+#include <inttypes.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <algorithm>
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+
+namespace android {
+
+template <typename T, typename Header>
+bool FuseMessage<T, Header>::CheckHeaderLength() const {
+ if (sizeof(Header) <= header.len && header.len <= sizeof(T)) {
+ return true;
+ } else {
+ LOG(ERROR) << "Packet size is invalid=" << header.len;
+ return false;
+ }
+}
+
+template <typename T, typename Header>
+bool FuseMessage<T, Header>::CheckResult(
+ int result, const char* operation_name) const {
+ if (result >= 0 && static_cast<uint32_t>(result) == header.len) {
+ return true;
+ } else {
+ PLOG(ERROR) << "Failed to " << operation_name
+ << " a packet from FD. result=" << result << " header.len="
+ << header.len;
+ return false;
+ }
+}
+
+template <typename T, typename Header>
+bool FuseMessage<T, Header>::Read(int fd) {
+ const ssize_t result = TEMP_FAILURE_RETRY(::read(fd, this, sizeof(T)));
+ return CheckHeaderLength() && CheckResult(result, "read");
+}
+
+template <typename T, typename Header>
+bool FuseMessage<T, Header>::Write(int fd) const {
+ if (!CheckHeaderLength()) {
+ return false;
+ }
+ const ssize_t result = TEMP_FAILURE_RETRY(::write(fd, this, header.len));
+ return CheckResult(result, "write");
+}
+
+template struct FuseMessage<FuseRequest, fuse_in_header>;
+template struct FuseMessage<FuseResponse, fuse_out_header>;
+
+void FuseResponse::ResetHeader(
+ uint32_t data_length, int32_t error, uint64_t unique) {
+ CHECK_LE(error, 0) << "error should be zero or negative.";
+ header.len = sizeof(fuse_out_header) + data_length;
+ header.error = error;
+ header.unique = unique;
+}
+
+void FuseResponse::Reset(uint32_t data_length, int32_t error, uint64_t unique) {
+ memset(this, 0, sizeof(fuse_out_header) + data_length);
+ ResetHeader(data_length, error, unique);
+}
+
+void FuseBuffer::HandleInit() {
+ const fuse_init_in* const in = &request.init_in;
+
+ // Before writing |out|, we need to copy data from |in|.
+ const uint64_t unique = request.header.unique;
+ const uint32_t minor = in->minor;
+ const uint32_t max_readahead = in->max_readahead;
+
+ // Kernel 2.6.16 is the first stable kernel with struct fuse_init_out
+ // defined (fuse version 7.6). The structure is the same from 7.6 through
+ // 7.22. Beginning with 7.23, the structure increased in size and added
+ // new parameters.
+ if (in->major != FUSE_KERNEL_VERSION || in->minor < 6) {
+ LOG(ERROR) << "Fuse kernel version mismatch: Kernel version " << in->major
+ << "." << in->minor << " Expected at least " << FUSE_KERNEL_VERSION
+ << ".6";
+ response.Reset(0, -EPERM, unique);
+ return;
+ }
+
+ // We limit ourselves to 15 because we don't handle BATCH_FORGET yet
+ size_t response_size = sizeof(fuse_init_out);
+#if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
+ // FUSE_KERNEL_VERSION >= 23.
+
+ // If the kernel only works on minor revs older than or equal to 22,
+ // then use the older structure size since this code only uses the 7.22
+ // version of the structure.
+ if (minor <= 22) {
+ response_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
+ }
+#endif
+
+ response.Reset(response_size, kFuseSuccess, unique);
+ fuse_init_out* const out = &response.init_out;
+ out->major = FUSE_KERNEL_VERSION;
+ // We limit ourselves to 15 because we don't handle BATCH_FORGET yet.
+ out->minor = std::min(minor, 15u);
+ out->max_readahead = max_readahead;
+ out->flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
+ out->max_background = 32;
+ out->congestion_threshold = 32;
+ out->max_write = kFuseMaxWrite;
+}
+
+void FuseBuffer::HandleNotImpl() {
+ LOG(VERBOSE) << "NOTIMPL op=" << request.header.opcode << " uniq="
+ << request.header.unique << " nid=" << request.header.nodeid;
+ const uint64_t unique = request.header.unique;
+ response.Reset(0, -ENOSYS, unique);
+}
+
+} // namespace android
diff --git a/libappfuse/include/libappfuse/FuseBridgeLoop.h b/libappfuse/include/libappfuse/FuseBridgeLoop.h
new file mode 100644
index 0000000..2006532
--- /dev/null
+++ b/libappfuse/include/libappfuse/FuseBridgeLoop.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specic language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_LIBAPPFUSE_FUSEBRIDGELOOP_H_
+#define ANDROID_LIBAPPFUSE_FUSEBRIDGELOOP_H_
+
+#include "libappfuse/FuseBuffer.h"
+
+namespace android {
+
+class FuseBridgeLoop {
+ public:
+ class Callback {
+ public:
+ virtual void OnMount() = 0;
+ virtual ~Callback() = default;
+ };
+
+ bool Start(int dev_fd, int proxy_fd, Callback* callback);
+
+ private:
+ FuseBuffer buffer_;
+};
+
+} // namespace android
+
+#endif // ANDROID_LIBAPPFUSE_FUSEBRIDGELOOP_H_
diff --git a/libappfuse/include/libappfuse/FuseBuffer.h b/libappfuse/include/libappfuse/FuseBuffer.h
new file mode 100644
index 0000000..071b777
--- /dev/null
+++ b/libappfuse/include/libappfuse/FuseBuffer.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specic language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_LIBAPPFUSE_FUSEBUFFER_H_
+#define ANDROID_LIBAPPFUSE_FUSEBUFFER_H_
+
+#include <linux/fuse.h>
+
+namespace android {
+
+// The numbers came from sdcard.c.
+// Maximum number of bytes to write/read in one request/one reply.
+constexpr size_t kFuseMaxWrite = 256 * 1024;
+constexpr size_t kFuseMaxRead = 128 * 1024;
+constexpr int32_t kFuseSuccess = 0;
+
+template<typename T, typename Header>
+struct FuseMessage {
+ Header header;
+ bool Read(int fd);
+ bool Write(int fd) const;
+ private:
+ bool CheckHeaderLength() const;
+ bool CheckResult(int result, const char* operation_name) const;
+};
+
+struct FuseRequest : public FuseMessage<FuseRequest, fuse_in_header> {
+ union {
+ struct {
+ fuse_write_in write_in;
+ char write_data[kFuseMaxWrite];
+ };
+ fuse_open_in open_in;
+ fuse_init_in init_in;
+ fuse_read_in read_in;
+ char lookup_name[0];
+ };
+};
+
+struct FuseResponse : public FuseMessage<FuseResponse, fuse_out_header> {
+ union {
+ fuse_init_out init_out;
+ fuse_entry_out entry_out;
+ fuse_attr_out attr_out;
+ fuse_open_out open_out;
+ char read_data[kFuseMaxRead];
+ fuse_write_out write_out;
+ };
+ void Reset(uint32_t data_length, int32_t error, uint64_t unique);
+ void ResetHeader(uint32_t data_length, int32_t error, uint64_t unique);
+};
+
+union FuseBuffer {
+ FuseRequest request;
+ FuseResponse response;
+
+ void HandleInit();
+ void HandleNotImpl();
+};
+
+class FuseProxyLoop {
+ class IFuseProxyLoopCallback {
+ public:
+ virtual void OnMount() = 0;
+ virtual ~IFuseProxyLoopCallback() = default;
+ };
+
+ bool Start(int dev_fd, int proxy_fd, IFuseProxyLoopCallback* callback);
+
+ private:
+ FuseBuffer buffer_;
+};
+
+} // namespace android
+
+#endif // ANDROID_LIBAPPFUSE_FUSEBUFFER_H_
diff --git a/libappfuse/tests/FuseBridgeLoopTest.cc b/libappfuse/tests/FuseBridgeLoopTest.cc
new file mode 100644
index 0000000..31e3690
--- /dev/null
+++ b/libappfuse/tests/FuseBridgeLoopTest.cc
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specic language governing permissions and
+ * limitations under the License.
+ */
+
+#include "libappfuse/FuseBridgeLoop.h"
+
+#include <sys/socket.h>
+
+#include <sstream>
+#include <thread>
+
+#include <gtest/gtest.h>
+
+namespace android {
+
+class Callback : public FuseBridgeLoop::Callback {
+ public:
+ bool mounted;
+ Callback() : mounted(false) {}
+ void OnMount() override {
+ mounted = true;
+ }
+};
+
+class FuseBridgeLoopTest : public ::testing::Test {
+ protected:
+ int dev_sockets_[2];
+ int proxy_sockets_[2];
+ Callback callback_;
+ std::thread thread_;
+
+ FuseRequest request_;
+ FuseResponse response_;
+
+ void SetUp() {
+ ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, dev_sockets_));
+ ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, proxy_sockets_));
+ thread_ = std::thread([this] {
+ FuseBridgeLoop loop;
+ loop.Start(dev_sockets_[1], proxy_sockets_[0], &callback_);
+ });
+ }
+
+ void CheckNotImpl(uint32_t opcode) {
+ SCOPED_TRACE((std::ostringstream() << "opcode: " << opcode).str());
+
+ memset(&request_, 0, sizeof(FuseRequest));
+ request_.header.opcode = opcode;
+ request_.header.len = sizeof(fuse_in_header);
+ ASSERT_TRUE(request_.Write(dev_sockets_[0]));
+
+ memset(&response_, 0, sizeof(FuseResponse));
+ ASSERT_TRUE(response_.Read(dev_sockets_[0]));
+ EXPECT_EQ(-ENOSYS, response_.header.error);
+ }
+
+ void CheckProxy(uint32_t opcode) {
+ SCOPED_TRACE((std::ostringstream() << "opcode: " << opcode).str());
+
+ memset(&request_, 0, sizeof(FuseRequest));
+ request_.header.opcode = opcode;
+ request_.header.unique = opcode; // Use opcode as unique.
+ request_.header.len = sizeof(fuse_in_header);
+ ASSERT_TRUE(request_.Write(dev_sockets_[0]));
+
+ memset(&request_, 0, sizeof(FuseRequest));
+ ASSERT_TRUE(request_.Read(proxy_sockets_[1]));
+ EXPECT_EQ(opcode, request_.header.opcode);
+ EXPECT_EQ(opcode, request_.header.unique);
+
+ memset(&response_, 0, sizeof(FuseResponse));
+ response_.header.len = sizeof(fuse_out_header);
+ response_.header.unique = opcode; // Use opcode as unique.
+ response_.header.error = kFuseSuccess;
+ ASSERT_TRUE(response_.Write(proxy_sockets_[1]));
+
+ memset(&response_, 0, sizeof(FuseResponse));
+ ASSERT_TRUE(response_.Read(dev_sockets_[0]));
+ EXPECT_EQ(opcode, response_.header.unique);
+ EXPECT_EQ(kFuseSuccess, response_.header.error);
+ }
+
+ void SendInitRequest(uint64_t unique) {
+ memset(&request_, 0, sizeof(FuseRequest));
+ request_.header.opcode = FUSE_INIT;
+ request_.header.unique = unique;
+ request_.header.len = sizeof(fuse_in_header) + sizeof(fuse_init_in);
+ request_.init_in.major = FUSE_KERNEL_VERSION;
+ request_.init_in.minor = FUSE_KERNEL_MINOR_VERSION;
+ ASSERT_TRUE(request_.Write(dev_sockets_[0]));
+ }
+
+ void Close() {
+ close(dev_sockets_[0]);
+ close(dev_sockets_[1]);
+ close(proxy_sockets_[0]);
+ close(proxy_sockets_[1]);
+ if (thread_.joinable()) {
+ thread_.join();
+ }
+ }
+
+ void TearDown() {
+ Close();
+ }
+};
+
+TEST_F(FuseBridgeLoopTest, FuseInit) {
+ SendInitRequest(1u);
+
+ memset(&response_, 0, sizeof(FuseResponse));
+ ASSERT_TRUE(response_.Read(dev_sockets_[0]));
+ EXPECT_EQ(kFuseSuccess, response_.header.error);
+ EXPECT_EQ(1u, response_.header.unique);
+
+ // Unmount.
+ Close();
+ EXPECT_TRUE(callback_.mounted);
+}
+
+TEST_F(FuseBridgeLoopTest, FuseForget) {
+ memset(&request_, 0, sizeof(FuseRequest));
+ request_.header.opcode = FUSE_FORGET;
+ request_.header.unique = 1u;
+ request_.header.len = sizeof(fuse_in_header) + sizeof(fuse_forget_in);
+ ASSERT_TRUE(request_.Write(dev_sockets_[0]));
+
+ SendInitRequest(2u);
+
+ memset(&response_, 0, sizeof(FuseResponse));
+ ASSERT_TRUE(response_.Read(dev_sockets_[0]));
+ EXPECT_EQ(2u, response_.header.unique) <<
+ "The loop must not respond to FUSE_FORGET";
+}
+
+TEST_F(FuseBridgeLoopTest, FuseNotImpl) {
+ CheckNotImpl(FUSE_SETATTR);
+ CheckNotImpl(FUSE_READLINK);
+ CheckNotImpl(FUSE_SYMLINK);
+ CheckNotImpl(FUSE_MKNOD);
+ CheckNotImpl(FUSE_MKDIR);
+ CheckNotImpl(FUSE_UNLINK);
+ CheckNotImpl(FUSE_RMDIR);
+ CheckNotImpl(FUSE_RENAME);
+ CheckNotImpl(FUSE_LINK);
+ CheckNotImpl(FUSE_STATFS);
+ CheckNotImpl(FUSE_FSYNC);
+ CheckNotImpl(FUSE_SETXATTR);
+ CheckNotImpl(FUSE_GETXATTR);
+ CheckNotImpl(FUSE_LISTXATTR);
+ CheckNotImpl(FUSE_REMOVEXATTR);
+ CheckNotImpl(FUSE_OPENDIR);
+ CheckNotImpl(FUSE_READDIR);
+ CheckNotImpl(FUSE_RELEASEDIR);
+ CheckNotImpl(FUSE_FSYNCDIR);
+ CheckNotImpl(FUSE_GETLK);
+ CheckNotImpl(FUSE_SETLK);
+ CheckNotImpl(FUSE_SETLKW);
+ CheckNotImpl(FUSE_ACCESS);
+ CheckNotImpl(FUSE_CREATE);
+ CheckNotImpl(FUSE_INTERRUPT);
+ CheckNotImpl(FUSE_BMAP);
+ CheckNotImpl(FUSE_DESTROY);
+ CheckNotImpl(FUSE_IOCTL);
+ CheckNotImpl(FUSE_POLL);
+ CheckNotImpl(FUSE_NOTIFY_REPLY);
+ CheckNotImpl(FUSE_BATCH_FORGET);
+ CheckNotImpl(FUSE_FALLOCATE);
+ CheckNotImpl(FUSE_READDIRPLUS);
+ CheckNotImpl(FUSE_RENAME2);
+ CheckNotImpl(FUSE_LSEEK);
+}
+
+TEST_F(FuseBridgeLoopTest, Proxy) {
+ CheckProxy(FUSE_LOOKUP);
+ CheckProxy(FUSE_GETATTR);
+ CheckProxy(FUSE_OPEN);
+ CheckProxy(FUSE_READ);
+ CheckProxy(FUSE_WRITE);
+ CheckProxy(FUSE_RELEASE);
+ CheckProxy(FUSE_FLUSH);
+}
+
+} // android
diff --git a/libappfuse/tests/FuseBufferTest.cc b/libappfuse/tests/FuseBufferTest.cc
new file mode 100644
index 0000000..1aacfe3
--- /dev/null
+++ b/libappfuse/tests/FuseBufferTest.cc
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specic language governing permissions and
+ * limitations under the License.
+ */
+
+#include "libappfuse/FuseBuffer.h"
+
+#include <fcntl.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include <android-base/unique_fd.h>
+#include <gtest/gtest.h>
+
+namespace android {
+
+constexpr char kTempFile[] = "/data/local/tmp/appfuse_test_dump";
+
+void OpenTempFile(android::base::unique_fd* fd) {
+ fd->reset(open(kTempFile, O_CREAT | O_RDWR));
+ ASSERT_NE(-1, *fd) << strerror(errno);
+ unlink(kTempFile);
+ ASSERT_NE(-1, *fd) << strerror(errno);
+}
+
+void TestReadInvalidLength(size_t headerSize, size_t write_size) {
+ android::base::unique_fd fd;
+ OpenTempFile(&fd);
+
+ char buffer[std::max(headerSize, sizeof(FuseRequest))];
+ FuseRequest* const packet = reinterpret_cast<FuseRequest*>(buffer);
+ packet->header.len = headerSize;
+ ASSERT_NE(-1, write(fd, packet, write_size)) << strerror(errno);
+
+ lseek(fd, 0, SEEK_SET);
+ EXPECT_FALSE(packet->Read(fd));
+}
+
+void TestWriteInvalidLength(size_t size) {
+ android::base::unique_fd fd;
+ OpenTempFile(&fd);
+
+ char buffer[std::max(size, sizeof(FuseRequest))];
+ FuseRequest* const packet = reinterpret_cast<FuseRequest*>(buffer);
+ packet->header.len = size;
+ EXPECT_FALSE(packet->Write(fd));
+}
+
+// Use FuseRequest as a template instance of FuseMessage.
+
+TEST(FuseMessageTest, ReadAndWrite) {
+ android::base::unique_fd fd;
+ OpenTempFile(&fd);
+
+ FuseRequest request;
+ request.header.len = sizeof(FuseRequest);
+ request.header.opcode = 1;
+ request.header.unique = 2;
+ request.header.nodeid = 3;
+ request.header.uid = 4;
+ request.header.gid = 5;
+ request.header.pid = 6;
+ strcpy(request.lookup_name, "test");
+
+ ASSERT_TRUE(request.Write(fd));
+
+ memset(&request, 0, sizeof(FuseRequest));
+ lseek(fd, 0, SEEK_SET);
+
+ ASSERT_TRUE(request.Read(fd));
+ EXPECT_EQ(sizeof(FuseRequest), request.header.len);
+ EXPECT_EQ(1u, request.header.opcode);
+ EXPECT_EQ(2u, request.header.unique);
+ EXPECT_EQ(3u, request.header.nodeid);
+ EXPECT_EQ(4u, request.header.uid);
+ EXPECT_EQ(5u, request.header.gid);
+ EXPECT_EQ(6u, request.header.pid);
+ EXPECT_STREQ("test", request.lookup_name);
+}
+
+TEST(FuseMessageTest, Read_InconsistentLength) {
+ TestReadInvalidLength(sizeof(fuse_in_header), sizeof(fuse_in_header) + 1);
+}
+
+TEST(FuseMessageTest, Read_TooLong) {
+ TestReadInvalidLength(sizeof(FuseRequest) + 1, sizeof(FuseRequest) + 1);
+}
+
+TEST(FuseMessageTest, Read_TooShort) {
+ TestReadInvalidLength(sizeof(fuse_in_header) - 1, sizeof(fuse_in_header) - 1);
+}
+
+TEST(FuseMessageTest, Write_TooLong) {
+ TestWriteInvalidLength(sizeof(FuseRequest) + 1);
+}
+
+TEST(FuseMessageTest, Write_TooShort) {
+ TestWriteInvalidLength(sizeof(fuse_in_header) - 1);
+}
+
+TEST(FuseResponseTest, Reset) {
+ FuseResponse response;
+ // Write 1 to the first ten bytes.
+ memset(response.read_data, 'a', 10);
+
+ response.Reset(0, -1, 2);
+ EXPECT_EQ(sizeof(fuse_out_header), response.header.len);
+ EXPECT_EQ(-1, response.header.error);
+ EXPECT_EQ(2u, response.header.unique);
+ EXPECT_EQ('a', response.read_data[0]);
+ EXPECT_EQ('a', response.read_data[9]);
+
+ response.Reset(5, -4, 3);
+ EXPECT_EQ(sizeof(fuse_out_header) + 5, response.header.len);
+ EXPECT_EQ(-4, response.header.error);
+ EXPECT_EQ(3u, response.header.unique);
+ EXPECT_EQ(0, response.read_data[0]);
+ EXPECT_EQ(0, response.read_data[1]);
+ EXPECT_EQ(0, response.read_data[2]);
+ EXPECT_EQ(0, response.read_data[3]);
+ EXPECT_EQ(0, response.read_data[4]);
+ EXPECT_EQ('a', response.read_data[5]);
+}
+
+TEST(FuseResponseTest, ResetHeader) {
+ FuseResponse response;
+ // Write 1 to the first ten bytes.
+ memset(response.read_data, 'a', 10);
+
+ response.ResetHeader(0, -1, 2);
+ EXPECT_EQ(sizeof(fuse_out_header), response.header.len);
+ EXPECT_EQ(-1, response.header.error);
+ EXPECT_EQ(2u, response.header.unique);
+ EXPECT_EQ('a', response.read_data[0]);
+ EXPECT_EQ('a', response.read_data[9]);
+
+ response.ResetHeader(5, -4, 3);
+ EXPECT_EQ(sizeof(fuse_out_header) + 5, response.header.len);
+ EXPECT_EQ(-4, response.header.error);
+ EXPECT_EQ(3u, response.header.unique);
+ EXPECT_EQ('a', response.read_data[0]);
+ EXPECT_EQ('a', response.read_data[9]);
+}
+
+TEST(FuseBufferTest, HandleInit) {
+ FuseBuffer buffer;
+ memset(&buffer, 0, sizeof(FuseBuffer));
+
+ buffer.request.header.opcode = FUSE_INIT;
+ buffer.request.init_in.major = FUSE_KERNEL_VERSION;
+ buffer.request.init_in.minor = FUSE_KERNEL_MINOR_VERSION;
+
+ buffer.HandleInit();
+
+ ASSERT_EQ(sizeof(fuse_out_header) + sizeof(fuse_init_out),
+ buffer.response.header.len);
+ EXPECT_EQ(kFuseSuccess, buffer.response.header.error);
+ EXPECT_EQ(static_cast<unsigned int>(FUSE_KERNEL_VERSION),
+ buffer.response.init_out.major);
+ EXPECT_EQ(15u, buffer.response.init_out.minor);
+ EXPECT_EQ(static_cast<unsigned int>(FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES),
+ buffer.response.init_out.flags);
+ EXPECT_EQ(kFuseMaxWrite, buffer.response.init_out.max_write);
+}
+
+TEST(FuseBufferTest, HandleNotImpl) {
+ FuseBuffer buffer;
+ memset(&buffer, 0, sizeof(FuseBuffer));
+
+ buffer.HandleNotImpl();
+
+ ASSERT_EQ(sizeof(fuse_out_header), buffer.response.header.len);
+ EXPECT_EQ(-ENOSYS, buffer.response.header.error);
+}
+}
+ // namespace android
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 93d997b..5c72234 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -21,8 +21,6 @@
"-Wall",
"-Werror",
],
- conlyflags: ["-std=gnu99"],
- cppflags: ["-std=gnu++11"],
clang_cflags: ["-Wno-inline-asm"],
@@ -94,6 +92,7 @@
],
static_libs: ["libcutils"],
+ host_ldlibs: ["-lrt"],
},
android: {
srcs: libbacktrace_sources,
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index 56a3970..bb17325 100644
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -20,12 +20,6 @@
-Wall \
-Werror \
-libbacktrace_common_conlyflags := \
- -std=gnu99 \
-
-libbacktrace_common_cppflags := \
- -std=gnu++11 \
-
libbacktrace_common_c_includes := \
external/libunwind/include/tdep \
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index 19ea1e3..4496375 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "backtrace-map"
+
#include <ctype.h>
#include <inttypes.h>
#include <stdint.h>
diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp
index c2b68bc..a05a6d8 100644
--- a/libbacktrace/BacktraceOffline.cpp
+++ b/libbacktrace/BacktraceOffline.cpp
@@ -719,7 +719,7 @@
auto binary_or_err = llvm::object::createBinary(buffer_or_err.get()->getMemBufferRef());
if (!binary_or_err) {
BACK_LOGW("failed to create binary for %s in %s: %s", elf_file.c_str(), apk_file.c_str(),
- binary_or_err.getError().message().c_str());
+ llvm::toString(binary_or_err.takeError()).c_str());
return nothing;
}
return llvm::object::OwningBinary<llvm::object::Binary>(std::move(binary_or_err.get()),
diff --git a/libcrypto_utils/Android.bp b/libcrypto_utils/Android.bp
index ca7bd31..f2560e6 100644
--- a/libcrypto_utils/Android.bp
+++ b/libcrypto_utils/Android.bp
@@ -24,7 +24,6 @@
"-Wall",
"-Wextra",
"-Werror",
- "-std=c99",
],
local_include_dirs: ["include"],
export_include_dirs: ["include"],
diff --git a/libcrypto_utils/tests/Android.mk b/libcrypto_utils/tests/Android.mk
index bdaef71..ef3d0cf 100644
--- a/libcrypto_utils/tests/Android.mk
+++ b/libcrypto_utils/tests/Android.mk
@@ -19,6 +19,6 @@
include $(CLEAR_VARS)
LOCAL_MODULE := libcrypto_utils_test
LOCAL_SRC_FILES := android_pubkey_test.cpp
-LOCAL_CFLAGS := -Wall -Werror -Wextra -std=c++11
+LOCAL_CFLAGS := -Wall -Werror -Wextra
LOCAL_SHARED_LIBRARIES := libcrypto_utils libcrypto
include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 955c0ec..f7b497d 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -23,7 +23,6 @@
"socket_inaddr_any_server_unix.c",
"socket_local_client_unix.c",
"socket_local_server_unix.c",
- "socket_loopback_client_unix.c",
"socket_loopback_server_unix.c",
"socket_network_client_unix.c",
"sockets_unix.cpp",
@@ -35,6 +34,7 @@
host_supported: true,
srcs: [
"config_utils.c",
+ "files.cpp",
"fs_config.c",
"canned_fs_config.c",
"hashmap.c",
@@ -89,10 +89,6 @@
static_libs: ["libdebuggerd_client"],
export_static_lib_headers: ["libdebuggerd_client"],
-
- cflags: [
- "-std=gnu90",
- ],
},
android_arm: {
diff --git a/libcutils/dlmalloc_stubs.c b/libcutils/dlmalloc_stubs.c
index 86fc880..6c07bed 100644
--- a/libcutils/dlmalloc_stubs.c
+++ b/libcutils/dlmalloc_stubs.c
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "dlmalloc-stubs"
+
#include "android/log.h"
#define UNUSED __attribute__((__unused__))
diff --git a/libcutils/files.cpp b/libcutils/files.cpp
new file mode 100644
index 0000000..bf15b42
--- /dev/null
+++ b/libcutils/files.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+// This file contains files implementation that can be shared between
+// platforms as long as the correct headers are included.
+#define _GNU_SOURCE 1 // for asprintf
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cutils/files.h>
+
+#ifndef TEMP_FAILURE_RETRY // _WIN32 does not define
+#define TEMP_FAILURE_RETRY(exp) (exp)
+#endif
+
+int android_get_control_file(const char* path) {
+ if (!path) return -1;
+
+ char *key = NULL;
+ if (asprintf(&key, ANDROID_FILE_ENV_PREFIX "%s", path) < 0) return -1;
+ if (!key) return -1;
+
+ char *cp = key;
+ while (*cp) {
+ if (!isalnum(*cp)) *cp = '_';
+ ++cp;
+ }
+
+ const char* val = getenv(key);
+ free(key);
+ if (!val) return -1;
+
+ errno = 0;
+ long fd = strtol(val, NULL, 10);
+ if (errno) return -1;
+
+ // validity checking
+ if ((fd < 0) || (fd > INT_MAX)) return -1;
+#if defined(_SC_OPEN_MAX)
+ if (fd >= sysconf(_SC_OPEN_MAX)) return -1;
+#elif defined(OPEN_MAX)
+ if (fd >= OPEN_MAX) return -1;
+#elif defined(_POSIX_OPEN_MAX)
+ if (fd >= _POSIX_OPEN_MAX) return -1;
+#endif
+
+#if defined(F_GETFD)
+ if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD)) < 0) return -1;
+#elif defined(F_GETFL)
+ if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL)) < 0) return -1;
+#else
+ struct stat s;
+ if (TEMP_FAILURE_RETRY(fstat(fd, &s)) < 0) return -1;
+#endif
+
+#if defined(__linux__)
+ char *proc = NULL;
+ if (asprintf(&proc, "/proc/self/fd/%ld", fd) < 0) return -1;
+ if (!proc) return -1;
+
+ size_t len = strlen(path);
+ char *buf = static_cast<char *>(calloc(1, len + 2));
+ if (!buf) {
+ free(proc);
+ return -1;
+ }
+ ssize_t ret = TEMP_FAILURE_RETRY(readlink(proc, buf, len + 1));
+ free(proc);
+ int cmp = (len != static_cast<size_t>(ret)) || strcmp(buf, path);
+ free(buf);
+ if (ret < 0) return -1;
+ if (cmp != 0) return -1;
+#endif
+
+ // It is what we think it is
+ return static_cast<int>(fd);
+}
diff --git a/libcutils/fs.c b/libcutils/fs.c
index 1622ed9..c49233e 100644
--- a/libcutils/fs.c
+++ b/libcutils/fs.c
@@ -25,6 +25,7 @@
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 3116236..60a389b 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -139,15 +139,35 @@
{ 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procmem" },
/* the following files have enhanced capabilities and ARE included in user builds. */
- { 00750, AID_ROOT, AID_SHELL, CAP_MASK_LONG(CAP_SETUID) | CAP_MASK_LONG(CAP_SETGID), "system/bin/run-as" },
- { 00700, AID_SYSTEM, AID_SHELL, CAP_MASK_LONG(CAP_BLOCK_SUSPEND), "system/bin/inputflinger" },
+ { 00550, AID_LOGD, AID_LOGD, CAP_MASK_LONG(CAP_SYSLOG) |
+ CAP_MASK_LONG(CAP_AUDIT_CONTROL) |
+ CAP_MASK_LONG(CAP_SETGID),
+ "system/bin/logd" },
+ { 00750, AID_ROOT, AID_SHELL, CAP_MASK_LONG(CAP_SETUID) |
+ CAP_MASK_LONG(CAP_SETGID),
+ "system/bin/run-as" },
+ { 00700, AID_SYSTEM, AID_SHELL, CAP_MASK_LONG(CAP_BLOCK_SUSPEND),
+ "system/bin/inputflinger" },
/* Support hostapd administering a network interface. */
- { 00755, AID_WIFI, AID_WIFI, CAP_MASK_LONG(CAP_NET_ADMIN) |
- CAP_MASK_LONG(CAP_NET_RAW), "system/bin/hostapd" },
+ { 00755, AID_WIFI, AID_WIFI, CAP_MASK_LONG(CAP_NET_ADMIN) |
+ CAP_MASK_LONG(CAP_NET_RAW),
+ "system/bin/hostapd" },
/* Support wifi_hal_legacy administering a network interface. */
- { 00755, AID_WIFI, AID_WIFI, CAP_MASK_LONG(CAP_NET_ADMIN) | CAP_MASK_LONG(CAP_NET_RAW), "system/bin/hw/wifi_hal_legacy" },
+ { 00755, AID_WIFI, AID_WIFI, CAP_MASK_LONG(CAP_NET_ADMIN) |
+ CAP_MASK_LONG(CAP_NET_RAW),
+ "system/bin/hw/android.hardware.wifi@1.0-service" },
+
+ /* A non-privileged zygote that spawns isolated processes for web rendering. */
+ { 0750, AID_ROOT, AID_ROOT, CAP_MASK_LONG(CAP_SETUID) |
+ CAP_MASK_LONG(CAP_SETGID) |
+ CAP_MASK_LONG(CAP_SETPCAP),
+ "system/bin/webview_zygote32" },
+ { 0750, AID_ROOT, AID_ROOT, CAP_MASK_LONG(CAP_SETUID) |
+ CAP_MASK_LONG(CAP_SETGID) |
+ CAP_MASK_LONG(CAP_SETPCAP),
+ "system/bin/webview_zygote64" },
{ 00750, AID_ROOT, AID_ROOT, 0, "system/bin/uncrypt" },
{ 00750, AID_ROOT, AID_ROOT, 0, "system/bin/install-recovery.sh" },
diff --git a/libcutils/klog.cpp b/libcutils/klog.cpp
index 061af1b..9d823cf 100644
--- a/libcutils/klog.cpp
+++ b/libcutils/klog.cpp
@@ -24,6 +24,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include <cutils/files.h>
#include <cutils/klog.h>
static int klog_level = KLOG_DEFAULT_LEVEL;
@@ -37,7 +38,11 @@
}
static int __open_klog(void) {
- return TEMP_FAILURE_RETRY(open("/dev/kmsg", O_WRONLY | O_CLOEXEC));
+ static const char kmsg_device[] = "/dev/kmsg";
+
+ int ret = android_get_control_file(kmsg_device);
+ if (ret >= 0) return ret;
+ return TEMP_FAILURE_RETRY(open(kmsg_device, O_WRONLY | O_CLOEXEC));
}
#define LOG_BUF_MAX 512
diff --git a/libcutils/native_handle.c b/libcutils/native_handle.c
index cae146d..9f4840a 100644
--- a/libcutils/native_handle.c
+++ b/libcutils/native_handle.c
@@ -28,6 +28,20 @@
static const int kMaxNativeFds = 1024;
static const int kMaxNativeInts = 1024;
+native_handle_t* native_handle_init(char* storage, int numFds, int numInts)
+{
+ if ((uintptr_t) storage % alignof(native_handle_t)) {
+ return NULL;
+ }
+
+ native_handle_t* handle = (native_handle_t*) storage;
+ handle->version = sizeof(native_handle_t);
+ handle->numFds = numFds;
+ handle->numInts = numInts;
+
+ return handle;
+}
+
native_handle_t* native_handle_create(int numFds, int numInts)
{
if (numFds < 0 || numInts < 0 || numFds > kMaxNativeFds || numInts > kMaxNativeInts) {
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index 2cc72a6..cab9263 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -23,7 +23,7 @@
#include <string.h>
#include <unistd.h>
-#include <android/log.h>
+#include <log/log.h>
#include <cutils/sched_policy.h>
#define UNUSED __attribute__((__unused__))
diff --git a/libcutils/socket_loopback_client_unix.c b/libcutils/socket_loopback_client_unix.c
deleted file mode 100644
index e14cffb..0000000
--- a/libcutils/socket_loopback_client_unix.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-** Copyright 2006, 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 <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#if !defined(_WIN32)
-#include <sys/socket.h>
-#include <sys/select.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#endif
-
-#include <cutils/sockets.h>
-
-/* Connect to port on the loopback IP interface. type is
- * SOCK_STREAM or SOCK_DGRAM.
- * return is a file descriptor or -1 on error
- */
-int socket_loopback_client(int port, int type)
-{
- struct sockaddr_in addr;
- int s;
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
- s = socket(AF_INET, type, 0);
- if(s < 0) return -1;
-
- if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- close(s);
- return -1;
- }
-
- return s;
-
-}
-
diff --git a/libcutils/socket_loopback_server_unix.c b/libcutils/socket_loopback_server_unix.c
index b600e34..7b92fd6 100644
--- a/libcutils/socket_loopback_server_unix.c
+++ b/libcutils/socket_loopback_server_unix.c
@@ -31,24 +31,18 @@
#include <cutils/sockets.h>
-/* open listen() port on loopback interface */
-int socket_loopback_server(int port, int type)
+static int _socket_loopback_server(int family, int type, struct sockaddr * addr, size_t size)
{
- struct sockaddr_in addr;
int s, n;
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
- s = socket(AF_INET, type, 0);
- if(s < 0) return -1;
+ s = socket(family, type, 0);
+ if(s < 0)
+ return -1;
n = 1;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *) &n, sizeof(n));
- if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ if(bind(s, addr, size) < 0) {
close(s);
return -1;
}
@@ -60,10 +54,35 @@
if (ret < 0) {
close(s);
- return -1;
+ return -1;
}
}
return s;
}
+/* open listen() port on loopback IPv6 interface */
+int socket_loopback_server6(int port, int type)
+{
+ struct sockaddr_in6 addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = htons(port);
+ addr.sin6_addr = in6addr_loopback;
+
+ return _socket_loopback_server(AF_INET6, type, (struct sockaddr *) &addr, sizeof(addr));
+}
+
+/* open listen() port on loopback interface */
+int socket_loopback_server(int port, int type)
+{
+ struct sockaddr_in addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ return _socket_loopback_server(AF_INET, type, (struct sockaddr *) &addr, sizeof(addr));
+}
diff --git a/libcutils/sockets.cpp b/libcutils/sockets.cpp
index bba63ac..63761a2 100644
--- a/libcutils/sockets.cpp
+++ b/libcutils/sockets.cpp
@@ -28,11 +28,31 @@
// This file contains socket implementation that can be shared between
// platforms as long as the correct headers are included.
+#define _GNU_SOURCE 1 // For asprintf
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#if !defined(_WIN32)
+#include <netinet/in.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#if !defined(_WIN32)
+#include <sys/un.h>
+#endif
+#include <unistd.h>
+
+#include <string>
#include <cutils/sockets.h>
-#if !defined(_WIN32)
-#include <netinet/in.h>
+#ifndef TEMP_FAILURE_RETRY // _WIN32 does not define
+#define TEMP_FAILURE_RETRY(exp) (exp)
#endif
int socket_get_local_port(cutils_socket_t sock) {
@@ -47,22 +67,56 @@
}
int android_get_control_socket(const char* name) {
- char key[64];
- snprintf(key, sizeof(key), ANDROID_SOCKET_ENV_PREFIX "%s", name);
+ char *key = NULL;
+ if (asprintf(&key, ANDROID_SOCKET_ENV_PREFIX "%s", name) < 0) return -1;
+ if (!key) return -1;
+
+ char *cp = key;
+ while (*cp) {
+ if (!isalnum(*cp)) *cp = '_';
+ ++cp;
+ }
const char* val = getenv(key);
- if (!val) {
- return -1;
- }
+ free(key);
+ if (!val) return -1;
errno = 0;
- long ret = strtol(val, NULL, 10);
- if (errno) {
- return -1;
- }
- if (ret < 0 || ret > INT_MAX) {
- return -1;
- }
+ long fd = strtol(val, NULL, 10);
+ if (errno) return -1;
- return static_cast<int>(ret);
+ // validity checking
+ if ((fd < 0) || (fd > INT_MAX)) return -1;
+#if defined(_SC_OPEN_MAX)
+ if (fd >= sysconf(_SC_OPEN_MAX)) return -1;
+#elif defined(OPEN_MAX)
+ if (fd >= OPEN_MAX) return -1;
+#elif defined(_POSIX_OPEN_MAX)
+ if (fd >= _POSIX_OPEN_MAX) return -1;
+#endif
+
+#if defined(F_GETFD)
+ if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD)) < 0) return -1;
+#elif defined(F_GETFL)
+ if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL)) < 0) return -1;
+#else
+ struct stat s;
+ if (TEMP_FAILURE_RETRY(fstat(fd, &s)) < 0) return -1;
+#endif
+
+#if !defined(_WIN32)
+ struct sockaddr_un addr;
+ socklen_t addrlen = sizeof(addr);
+ int ret = TEMP_FAILURE_RETRY(getsockname(fd, (struct sockaddr *)&addr, &addrlen));
+ if (ret < 0) return -1;
+ char *path = NULL;
+ if (asprintf(&path, ANDROID_SOCKET_DIR"/%s", name) < 0) return -1;
+ if (!path) return -1;
+ int cmp = strcmp(addr.sun_path, path);
+ free(path);
+ if (cmp != 0) return -1;
+#endif
+
+ // It is what we think it is
+ return static_cast<int>(fd);
}
diff --git a/libcutils/sockets_unix.cpp b/libcutils/sockets_unix.cpp
index e51a1c7..3545403 100644
--- a/libcutils/sockets_unix.cpp
+++ b/libcutils/sockets_unix.cpp
@@ -14,7 +14,11 @@
* limitations under the License.
*/
+#define LOG_TAG "socket-unix"
+
#include <sys/uio.h>
+#include <time.h>
+#include <unistd.h>
#include <android/log.h>
#include <cutils/sockets.h>
diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp
index 06d0e28..bd35412 100644
--- a/libcutils/tests/Android.bp
+++ b/libcutils/tests/Android.bp
@@ -14,7 +14,7 @@
cc_defaults {
name: "libcutils_test_default",
- srcs: ["sockets_test.cpp"],
+ srcs: ["sockets_test.cpp", "files_test.cpp"],
target: {
android: {
diff --git a/libcutils/tests/files_test.cpp b/libcutils/tests/files_test.cpp
new file mode 100644
index 0000000..1a7d673
--- /dev/null
+++ b/libcutils/tests/files_test.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include <cutils/files.h>
+#include <gtest/gtest.h>
+
+TEST(FilesTest, android_get_control_file) {
+ static const char key[] = ANDROID_FILE_ENV_PREFIX "_dev_kmsg";
+ static const char name[] = "/dev/kmsg";
+
+ EXPECT_EQ(unsetenv(key), 0);
+ EXPECT_EQ(android_get_control_file(name), -1);
+
+ int fd;
+ ASSERT_GE(fd = open(name, O_RDONLY | O_CLOEXEC), 0);
+ EXPECT_EQ(android_get_control_file(name), -1);
+
+ char val[32];
+ snprintf(val, sizeof(val), "%d", fd);
+ EXPECT_EQ(setenv(key, val, true), 0);
+
+ EXPECT_EQ(android_get_control_file(name), fd);
+ close(fd);
+ EXPECT_EQ(android_get_control_file(name), -1);
+ EXPECT_EQ(unsetenv(key), 0);
+ EXPECT_EQ(android_get_control_file(name), -1);
+}
diff --git a/libcutils/tests/sockets_test.cpp b/libcutils/tests/sockets_test.cpp
index 0f682a2..adfbf4a 100644
--- a/libcutils/tests/sockets_test.cpp
+++ b/libcutils/tests/sockets_test.cpp
@@ -18,10 +18,14 @@
// IPv6 capabilities. These tests assume that no UDP packets are lost, which
// should be the case for loopback communication, but is not guaranteed.
-#include <cutils/sockets.h>
-
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
#include <time.h>
+#include <cutils/sockets.h>
#include <gtest/gtest.h>
// Makes sure the passed sockets are valid, sends data between them, and closes
@@ -185,3 +189,49 @@
TEST(SocketsTest, TestSocketSendBuffersFailure) {
EXPECT_EQ(-1, socket_send_buffers(INVALID_SOCKET, nullptr, 0));
}
+
+#ifndef SOCK_NONBLOCK
+#define SOCK_NONBLOCK 0
+#endif
+
+#ifndef SOCK_CLOEXEC
+#define SOCK_CLOEXEC 0
+#endif
+
+TEST(SocketsTest, android_get_control_socket) {
+ static const char key[] = ANDROID_SOCKET_ENV_PREFIX "SocketsTest_android_get_control_socket";
+ static const char* name = key + strlen(ANDROID_SOCKET_ENV_PREFIX);
+
+ EXPECT_EQ(unsetenv(key), 0);
+ EXPECT_EQ(android_get_control_socket(name), -1);
+
+ int fd;
+ ASSERT_GE(fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0), 0);
+#ifdef F_GETFL
+ int flags;
+ ASSERT_GE(flags = fcntl(fd, F_GETFL), 0);
+ ASSERT_GE(fcntl(fd, F_SETFL, flags | O_NONBLOCK), 0);
+#endif
+ EXPECT_EQ(android_get_control_socket(name), -1);
+
+ struct sockaddr_un addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s", name);
+ unlink(addr.sun_path);
+
+ EXPECT_EQ(bind(fd, (struct sockaddr*)&addr, sizeof(addr)), 0);
+ EXPECT_EQ(android_get_control_socket(name), -1);
+
+ char val[32];
+ snprintf(val, sizeof(val), "%d", fd);
+ EXPECT_EQ(setenv(key, val, true), 0);
+
+ EXPECT_EQ(android_get_control_socket(name), fd);
+ socket_close(fd);
+ EXPECT_EQ(android_get_control_socket(name), -1);
+ EXPECT_EQ(unlink(addr.sun_path), 0);
+ EXPECT_EQ(android_get_control_socket(name), -1);
+ EXPECT_EQ(unsetenv(key), 0);
+ EXPECT_EQ(android_get_control_socket(name), -1);
+}
diff --git a/libcutils/trace-dev.c b/libcutils/trace-dev.c
index dcd9582..113f423 100644
--- a/libcutils/trace-dev.c
+++ b/libcutils/trace-dev.c
@@ -26,10 +26,10 @@
#include <string.h>
#include <sys/types.h>
-#include <android/log.h>
#include <cutils/compiler.h>
#include <cutils/properties.h>
#include <cutils/trace.h>
+#include <private/android_logger.h>
/**
* Maximum size of a message that can be logged to the trace buffer.
@@ -86,16 +86,9 @@
// Determine whether application-level tracing is enabled for this process.
static bool atrace_is_app_tracing_enabled()
{
- bool sys_debuggable = false;
- char value[PROPERTY_VALUE_MAX];
+ bool sys_debuggable = __android_log_is_debuggable();
bool result = false;
- // Check whether the system is debuggable.
- property_get("ro.debuggable", value, "0");
- if (value[0] == '1') {
- sys_debuggable = true;
- }
-
if (sys_debuggable || atrace_is_debuggable) {
// Check whether tracing is enabled for this process.
FILE * file = fopen("/proc/self/cmdline", "re");
diff --git a/libion/ion.c b/libion/ion.c
index 424776a..2db8845 100644
--- a/libion/ion.c
+++ b/libion/ion.c
@@ -27,13 +27,14 @@
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
+#include <unistd.h>
#include <android/log.h>
#include <ion/ion.h>
int ion_open()
{
- int fd = open("/dev/ion", O_RDWR);
+ int fd = open("/dev/ion", O_RDONLY);
if (fd < 0)
ALOGE("open /dev/ion failed!\n");
return fd;
diff --git a/libion/tests/device_test.cpp b/libion/tests/device_test.cpp
index 0be52bf..eb3f7b6 100644
--- a/libion/tests/device_test.cpp
+++ b/libion/tests/device_test.cpp
@@ -46,7 +46,7 @@
void Device::SetUp()
{
IonAllHeapsTest::SetUp();
- m_deviceFd = open("/dev/ion-test", O_RDWR);
+ m_deviceFd = open("/dev/ion-test", O_RDONLY);
ASSERT_GE(m_deviceFd, 0);
}
diff --git a/liblog/Android.bp b/liblog/Android.bp
index c59dde9..16aa4fa 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -91,6 +91,22 @@
compile_multilib: "both",
}
+// system/core/android/log.h needs some work before it can be included in the
+// NDK. It defines a *lot* of macros that previously were usable names in NDK
+// sources that used android/log.h. As an example, the following file defines
+// LOG_TAG as a variable, but the variable name gets macro replaced if we use
+// the current android/log.h.
+// https://android.googlesource.com/platform/external/deqp/+/4adc1515f867b26c19c2f7498e9de93a230a234d/framework/platform/android/tcuTestLogParserJNI.cpp#41
+//
+// For now, we keep a copy of the old NDK android/log.h in legacy-ndk-includes.
+ndk_headers {
+ name: "liblog_headers",
+ from: "legacy-ndk-includes",
+ to: "android",
+ srcs: ["legacy-ndk-includes/log.h"],
+ license: "NOTICE",
+}
+
ndk_library {
name: "liblog.ndk",
symbol_file: "liblog.map.txt",
diff --git a/liblog/README b/liblog/README
index eefa80f..610338c 100644
--- a/liblog/README
+++ b/liblog/README
@@ -1,12 +1,18 @@
-LIBLOG(3) Android NDK Programming Manual LIBLOG(3)
+LIBLOG(3) Android Internal NDK Programming Manual LIBLOG(3)
NAME
- liblog - Android NDK logger interfaces
+ liblog - Android Internal NDK logger interfaces
SYNOPSIS
- #include <android/log.h>
+ /*
+ * Please limit to 24 characters for runtime is loggable,
+ * 16 characters for persist is loggable, and logcat pretty
+ * alignment with limit of 7 characters.
+ */
+ #define LOG_TAG "yourtag"
+ #include <log/log.h>
ALOG(android_priority, tag, format, ...)
IF_ALOG(android_priority, tag)
@@ -56,9 +62,7 @@
LOG_EVENT_INT(tag, value)
LOG_EVENT_LONG(tag, value)
- Link with -llog
-
- #include <log/logger.h>
+ clockid_t android_log_clockid()
log_id_t android_logger_get_id(struct logger *logger)
int android_logger_clear(struct logger *logger)
@@ -66,21 +70,44 @@
int android_logger_get_log_readable_size(struct logger *logger)
int android_logger_get_log_version(struct logger *logger)
- struct logger_list *android_logger_list_alloc(int mode, unsigned int
- tail, pid_t pid)
- struct logger *android_logger_open(struct logger_list *logger_list,
- log_id_t id)
- struct logger_list *android_logger_list_open(log_id_t id, int mode,
- unsigned int tail, pid_t pid)
-
- int android_logger_list_read(struct logger_list *logger_list, struct
- log_msg *log_msg
-
+ struct logger_list *android_logger_list_alloc(int mode,
+ unsigned int tail,
+ pid_t pid)
+ struct logger *android_logger_open(struct logger_list *logger_list,
+ log_id_t id)
+ struct logger_list *android_logger_list_open(log_id_t id, int mode,
+ unsigned int tail,
+ pid_t pid)
+ int android_logger_list_read(struct logger_list *logger_list,
+ struct log_msg *log_msg)
void android_logger_list_free(struct logger_list *logger_list)
log_id_t android_name_to_log_id(const char *logName)
const char *android_log_id_to_name(log_id_t log_id)
+ android_log_context create_android_logger(uint32_t tag)
+
+ int android_log_write_list_begin(android_log_context ctx)
+ int android_log_write_list_end(android_log_context ctx)
+
+ int android_log_write_int32(android_log_context ctx, int32_t value)
+ int android_log_write_int64(android_log_context ctx, int64_t value)
+ int android_log_write_string8(android_log_context ctx,
+ const char *value)
+ int android_log_write_string8_len(android_log_context ctx,
+ const char *value, size_t maxlen)
+ int android_log_write_float32(android_log_context ctx, float value)
+
+ int android_log_write_list(android_log_context ctx,
+ log_id_t id = LOG_ID_EVENTS)
+
+ android_log_context create_android_log_parser(const char *msg,
+ size_t len)
+ android_log_list_element android_log_read_next(android_log_context ctx)
+ android_log_list_element android_log_peek_next(android_log_context ctx)
+
+ int android_log_destroy(android_log_context *ctx)
+
Link with -llog
DESCRIPTION
@@ -163,8 +190,8 @@
library retries on EINTR, -EINTR should never be returned.
SEE ALSO
- syslogd(8)
+ syslogd(8), klogd, auditd(8)
- 24 Jan 2014 LIBLOG(3)
+ 17 Oct 2016 LIBLOG(3)
diff --git a/liblog/event_tag_map.c b/liblog/event_tag_map.c
index 6705fb2..f9cad99 100644
--- a/liblog/event_tag_map.c
+++ b/liblog/event_tag_map.c
@@ -19,6 +19,7 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
@@ -37,6 +38,8 @@
uint32_t tagIndex;
char* tagStr;
size_t tagLen;
+ char* fmtStr;
+ size_t fmtLen;
} EventTag;
/*
@@ -175,6 +178,39 @@
return NULL;
}
+/*
+ * Look up an entry in the map.
+ *
+ * The entries are sorted by tag number, so we can do a binary search.
+ */
+LIBLOG_ABI_PUBLIC const char* android_lookupEventFormat_len(
+ const EventTagMap* map, size_t *len, unsigned int tag)
+{
+ int lo = 0;
+ int hi = map->numTags - 1;
+
+ while (lo <= hi) {
+ int mid = (lo + hi) / 2;
+ int cmp = map->tagArray[mid].tagIndex - tag;
+
+ if (cmp < 0) {
+ /* tag is bigger */
+ lo = mid + 1;
+ } else if (cmp > 0) {
+ /* tag is smaller */
+ hi = mid - 1;
+ } else {
+ /* found */
+ if (len) *len = map->tagArray[mid].fmtLen;
+ return map->tagArray[mid].fmtStr;
+ }
+ }
+
+ errno = ENOENT;
+ if (len) *len = 0;
+ return NULL;
+}
+
LIBLOG_ABI_PUBLIC const char* android_lookupEventTag(const EventTagMap* map,
unsigned int tag)
{
@@ -363,17 +399,21 @@
}
tag->tagLen = cp - tag->tagStr;
- if (isspace(*cp)) {
- /* just ignore the rest of the line till \n
- TODO: read the tag description that follows the tag name
- */
- while (*cp != '\n') ++cp;
- } else {
+ if (!isspace(*cp)) {
fprintf(stderr, "%s: invalid tag chars on line %d\n", OUT_TAG, lineNum);
errno = EINVAL;
return -1;
}
+ while (isspace(*cp) && (*cp != '\n')) ++cp;
+ if (*cp != '#') {
+ tag->fmtStr = cp;
+ while ((*cp != '\n') && (*cp != '#')) ++cp;
+ while ((cp > tag->fmtStr) && isspace(*(cp - 1))) --cp;
+ tag->fmtLen = cp - tag->fmtStr;
+ }
+
+ while (*cp != '\n') ++cp;
*pData = cp;
return 0;
@@ -405,12 +445,14 @@
for (i = 1; i < map->numTags; i++) {
if (map->tagArray[i].tagIndex == map->tagArray[i - 1].tagIndex) {
fprintf(stderr,
- "%s: duplicate tag entries (%" PRIu32 ":%.*s and %" PRIu32 ":%.*s)\n",
+ "%s: duplicate tag entries (%" PRIu32 ":%.*s:%.*s and %" PRIu32 ":%.*s:%.*s)\n",
OUT_TAG,
- map->tagArray[i].tagIndex, (int)map->tagArray[i].tagLen,
- map->tagArray[i].tagStr,
- map->tagArray[i - 1].tagIndex, (int)map->tagArray[i - 1].tagLen,
- map->tagArray[i - 1].tagStr);
+ map->tagArray[i].tagIndex,
+ (int)map->tagArray[i].tagLen, map->tagArray[i].tagStr,
+ (int)map->tagArray[i].fmtLen, map->tagArray[i].fmtStr,
+ map->tagArray[i - 1].tagIndex,
+ (int)map->tagArray[i - 1].tagLen, map->tagArray[i - 1].fmtStr,
+ (int)map->tagArray[i - 1].fmtLen, map->tagArray[i - 1].fmtStr);
errno = EMLINK;
return -1;
}
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c
index 7bd1f83..4939221 100644
--- a/liblog/fake_log_device.c
+++ b/liblog/fake_log_device.c
@@ -25,10 +25,14 @@
#if !defined(_WIN32)
#include <pthread.h>
#endif
+#include <stdint.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
#include <android/log.h>
+#include <log/uio.h>
#include "fake_log_device.h"
#include "log_portability.h"
@@ -727,3 +731,8 @@
int logLevel = def;
return logLevel >= 0 && prio >= logLevel;
}
+
+LIBLOG_ABI_PRIVATE int __android_log_is_debuggable()
+{
+ return 1;
+}
diff --git a/liblog/fake_writer.c b/liblog/fake_writer.c
index 47935e3..dab8bc5 100644
--- a/liblog/fake_writer.c
+++ b/liblog/fake_writer.c
@@ -18,7 +18,7 @@
#include <fcntl.h>
#include <unistd.h>
-#include <android/log.h>
+#include <log/log.h>
#include "config_write.h"
#include "fake_log_device.h"
diff --git a/liblog/legacy-ndk-includes/log.h b/liblog/legacy-ndk-includes/log.h
new file mode 100644
index 0000000..0ea4c29
--- /dev/null
+++ b/liblog/legacy-ndk-includes/log.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2009 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_LOG_H
+#define _ANDROID_LOG_H
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ * This file is part of Android's set of stable system headers
+ * exposed by the Android NDK (Native Development Kit) since
+ * platform release 1.5
+ *
+ * Third-party source AND binary code relies on the definitions
+ * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+/*
+ * Support routines to send messages to the Android in-kernel log buffer,
+ * which can later be accessed through the 'logcat' utility.
+ *
+ * Each log message must have
+ * - a priority
+ * - a log tag
+ * - some text
+ *
+ * The tag normally corresponds to the component that emits the log message,
+ * and should be reasonably small.
+ *
+ * Log message text may be truncated to less than an implementation-specific
+ * limit (e.g. 1023 characters max).
+ *
+ * Note that a newline character ("\n") will be appended automatically to your
+ * log message, if not already there. It is not possible to send several messages
+ * and have them appear on a single line in logcat.
+ *
+ * PLEASE USE LOGS WITH MODERATION:
+ *
+ * - Sending log messages eats CPU and slow down your application and the
+ * system.
+ *
+ * - The circular log buffer is pretty small (<64KB), sending many messages
+ * might push off other important log messages from the rest of the system.
+ *
+ * - In release builds, only send log messages to account for exceptional
+ * conditions.
+ *
+ * NOTE: These functions MUST be implemented by /system/lib/liblog.so
+ */
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Android log priority values, in ascending priority order.
+ */
+typedef enum android_LogPriority {
+ ANDROID_LOG_UNKNOWN = 0,
+ ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */
+ ANDROID_LOG_VERBOSE,
+ ANDROID_LOG_DEBUG,
+ ANDROID_LOG_INFO,
+ ANDROID_LOG_WARN,
+ ANDROID_LOG_ERROR,
+ ANDROID_LOG_FATAL,
+ ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
+} android_LogPriority;
+
+/*
+ * Send a simple string to the log.
+ */
+int __android_log_write(int prio, const char *tag, const char *text);
+
+/*
+ * Send a formatted string to the log, used like printf(fmt,...)
+ */
+int __android_log_print(int prio, const char *tag, const char *fmt, ...)
+#if defined(__GNUC__)
+ __attribute__ ((format(printf, 3, 4)))
+#endif
+ ;
+
+/*
+ * A variant of __android_log_print() that takes a va_list to list
+ * additional parameters.
+ */
+int __android_log_vprint(int prio, const char *tag,
+ const char *fmt, va_list ap);
+
+/*
+ * Log an assertion failure and SIGTRAP the process to have a chance
+ * to inspect it, if a debugger is attached. This uses the FATAL priority.
+ */
+void __android_log_assert(const char *cond, const char *tag,
+ const char *fmt, ...)
+#if defined(__GNUC__)
+ __attribute__ ((noreturn))
+ __attribute__ ((format(printf, 3, 4)))
+#endif
+ ;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ANDROID_LOG_H */
diff --git a/liblog/liblog.map.txt b/liblog/liblog.map.txt
index 5f19cc1..599dc90 100644
--- a/liblog/liblog.map.txt
+++ b/liblog/liblog.map.txt
@@ -1,14 +1,19 @@
LIBLOG {
global:
__android_log_assert;
- __android_log_btwrite;
- __android_log_buf_print; # introduced-arm=21 introduced-arm64=21 introduced-mips=9 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
- __android_log_buf_write; # introduced-arm=21 introduced-arm64=21 introduced-mips=9 introduced-mips64=21 introduced-x86=9 introduced-x86_64=21
- __android_log_bwrite;
- __android_log_dev_available;
__android_log_print;
__android_log_vprint;
__android_log_write;
local:
*;
};
+
+LIBLOG_M {
+ global:
+ __android_log_is_loggable;
+};
+
+LIBLOG_O {
+ global:
+ __android_log_is_loggable_len;
+};
diff --git a/liblog/log_event_write.c b/liblog/log_event_write.c
index 8c8a9a1..7262fc5 100644
--- a/liblog/log_event_write.c
+++ b/liblog/log_event_write.c
@@ -15,8 +15,9 @@
*/
#include <errno.h>
+#include <stdint.h>
-#include <android/log.h>
+#include <log/log.h>
#include "log_portability.h"
diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c
index 4af8507..dda09e0 100644
--- a/liblog/log_is_loggable.c
+++ b/liblog/log_is_loggable.c
@@ -16,12 +16,14 @@
#include <ctype.h>
#include <pthread.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
+#include <unistd.h>
-#include <android/log.h>
+#include <private/android_logger.h>
#include "log_portability.h"
@@ -47,12 +49,16 @@
}
struct cache {
- const prop_info *pinfo;
+ const prop_info* pinfo;
uint32_t serial;
+};
+
+struct cache_char {
+ struct cache cache;
unsigned char c;
};
-static int check_cache(struct cache *cache)
+static int check_cache(struct cache* cache)
{
return cache->pinfo
&& __system_property_serial(cache->pinfo) != cache->serial;
@@ -61,18 +67,18 @@
#define BOOLEAN_TRUE 0xFF
#define BOOLEAN_FALSE 0xFE
-static void refresh_cache(struct cache *cache, const char *key)
+static void refresh_cache(struct cache_char* cache, const char* key)
{
char buf[PROP_VALUE_MAX];
- if (!cache->pinfo) {
- cache->pinfo = __system_property_find(key);
- if (!cache->pinfo) {
+ if (!cache->cache.pinfo) {
+ cache->cache.pinfo = __system_property_find(key);
+ if (!cache->cache.pinfo) {
return;
}
}
- cache->serial = __system_property_serial(cache->pinfo);
- __system_property_read(cache->pinfo, 0, buf);
+ cache->cache.serial = __system_property_serial(cache->cache.pinfo);
+ __system_property_read(cache->cache.pinfo, 0, buf);
switch(buf[0]) {
case 't': case 'T':
cache->c = strcasecmp(buf + 1, "rue") ? buf[0] : BOOLEAN_TRUE;
@@ -85,7 +91,7 @@
}
}
-static int __android_log_level(const char *tag, size_t len, int default_prio)
+static int __android_log_level(const char* tag, size_t len, int default_prio)
{
/* sizeof() is used on this array below */
static const char log_namespace[] = "persist.log.tag.";
@@ -93,8 +99,8 @@
/* calculate the size of our key temporary buffer */
const size_t taglen = tag ? len : 0;
/* sizeof(log_namespace) = strlen(log_namespace) + 1 */
- char key[sizeof(log_namespace) + taglen]; /* may be > PROPERTY_KEY_MAX */
- char *kp;
+ char key[sizeof(log_namespace) + taglen]; /* may be > PROP_NAME_MAX */
+ char* kp;
size_t i;
char c = 0;
/*
@@ -110,8 +116,8 @@
static uint32_t global_serial;
/* some compilers erroneously see uninitialized use. !not_locked */
uint32_t current_global_serial = 0;
- static struct cache tag_cache[2];
- static struct cache global_cache[2];
+ static struct cache_char tag_cache[2];
+ static struct cache_char global_cache[2];
int change_detected;
int global_change_detected;
int not_locked;
@@ -125,12 +131,12 @@
* check all known serial numbers to changes.
*/
for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
- if (check_cache(&tag_cache[i])) {
+ if (check_cache(&tag_cache[i].cache)) {
change_detected = 1;
}
}
for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) {
- if (check_cache(&global_cache[i])) {
+ if (check_cache(&global_cache[i].cache)) {
global_change_detected = 1;
}
}
@@ -154,7 +160,7 @@
|| ((len < sizeof(last_tag)) && last_tag[len])) {
/* invalidate log.tag.<tag> cache */
for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
- tag_cache[i].pinfo = NULL;
+ tag_cache[i].cache.pinfo = NULL;
tag_cache[i].c = '\0';
}
last_tag[0] = '\0';
@@ -174,11 +180,11 @@
kp = key;
for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
- struct cache *cache = &tag_cache[i];
- struct cache temp_cache;
+ struct cache_char* cache = &tag_cache[i];
+ struct cache_char temp_cache;
if (not_locked) {
- temp_cache.pinfo = NULL;
+ temp_cache.cache.pinfo = NULL;
temp_cache.c = '\0';
cache = &temp_cache;
}
@@ -212,13 +218,13 @@
kp = key;
for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) {
- struct cache *cache = &global_cache[i];
- struct cache temp_cache;
+ struct cache_char* cache = &global_cache[i];
+ struct cache_char temp_cache;
if (not_locked) {
temp_cache = *cache;
- if (temp_cache.pinfo != cache->pinfo) { /* check atomic */
- temp_cache.pinfo = NULL;
+ if (temp_cache.cache.pinfo != cache->cache.pinfo) { /* check atomic */
+ temp_cache.cache.pinfo = NULL;
temp_cache.c = '\0';
}
cache = &temp_cache;
@@ -257,7 +263,7 @@
}
LIBLOG_ABI_PUBLIC int __android_log_is_loggable_len(int prio,
- const char *tag, size_t len,
+ const char* tag, size_t len,
int default_prio)
{
int logLevel = __android_log_level(tag, len, default_prio);
@@ -265,7 +271,7 @@
}
LIBLOG_ABI_PUBLIC int __android_log_is_loggable(int prio,
- const char *tag,
+ const char* tag,
int default_prio)
{
int logLevel = __android_log_level(tag,
@@ -274,21 +280,21 @@
return logLevel >= 0 && prio >= logLevel;
}
-LIBLOG_HIDDEN int __android_log_is_debuggable()
+LIBLOG_ABI_PRIVATE int __android_log_is_debuggable()
{
static uint32_t serial;
- static struct cache tag_cache;
+ static struct cache_char tag_cache;
static const char key[] = "ro.debuggable";
int ret;
if (tag_cache.c) { /* ro property does not change after set */
ret = tag_cache.c == '1';
} else if (lock()) {
- struct cache temp_cache = { NULL, -1, '\0' };
+ struct cache_char temp_cache = { { NULL, -1 }, '\0' };
refresh_cache(&temp_cache, key);
ret = temp_cache.c == '1';
} else {
- int change_detected = check_cache(&tag_cache);
+ int change_detected = check_cache(&tag_cache.cache);
uint32_t current_serial = __system_property_area_serial();
if (current_serial != serial) {
change_detected = 1;
@@ -310,17 +316,17 @@
* Since a change is rare, we will accept a trylock failure gracefully.
* Use a separate lock from is_loggable to keep contention down b/25563384.
*/
-struct cache2 {
+struct cache2_char {
pthread_mutex_t lock;
uint32_t serial;
- const char *key_persist;
- struct cache cache_persist;
- const char *key_ro;
- struct cache cache_ro;
- unsigned char (*const evaluate)(const struct cache2 *self);
+ const char* key_persist;
+ struct cache_char cache_persist;
+ const char* key_ro;
+ struct cache_char cache_ro;
+ unsigned char (*const evaluate)(const struct cache2_char *self);
};
-static inline unsigned char do_cache2(struct cache2 *self)
+static inline unsigned char do_cache2_char(struct cache2_char *self)
{
uint32_t current_serial;
int change_detected;
@@ -331,8 +337,8 @@
return self->evaluate(self);
}
- change_detected = check_cache(&self->cache_persist)
- || check_cache(&self->cache_ro);
+ change_detected = check_cache(&self->cache_persist.cache)
+ || check_cache(&self->cache_ro.cache);
current_serial = __system_property_area_serial();
if (current_serial != self->serial) {
change_detected = 1;
@@ -349,7 +355,7 @@
return c;
}
-static unsigned char evaluate_persist_ro(const struct cache2 *self)
+static unsigned char evaluate_persist_ro(const struct cache2_char *self)
{
unsigned char c = self->cache_persist.c;
@@ -366,17 +372,17 @@
*/
LIBLOG_ABI_PUBLIC clockid_t android_log_clockid()
{
- static struct cache2 clockid = {
+ static struct cache2_char clockid = {
PTHREAD_MUTEX_INITIALIZER,
0,
"persist.logd.timestamp",
- { NULL, -1, '\0' },
+ { { NULL, -1 }, '\0' },
"ro.logd.timestamp",
- { NULL, -1, '\0' },
+ { { NULL, -1 }, '\0' },
evaluate_persist_ro
};
- return (tolower(do_cache2(&clockid)) == 'm')
+ return (tolower(do_cache2_char(&clockid)) == 'm')
? CLOCK_MONOTONIC
: CLOCK_REALTIME;
}
@@ -385,7 +391,7 @@
* Security state generally remains constant, but the DO must be able
* to turn off logging should it become spammy after an attack is detected.
*/
-static unsigned char evaluate_security(const struct cache2 *self)
+static unsigned char evaluate_security(const struct cache2_char *self)
{
unsigned char c = self->cache_ro.c;
@@ -394,15 +400,265 @@
LIBLOG_ABI_PUBLIC int __android_log_security()
{
- static struct cache2 security = {
+ static struct cache2_char security = {
PTHREAD_MUTEX_INITIALIZER,
0,
"persist.logd.security",
- { NULL, -1, BOOLEAN_FALSE },
+ { { NULL, -1 }, BOOLEAN_FALSE },
"ro.device_owner",
- { NULL, -1, BOOLEAN_FALSE },
+ { { NULL, -1 }, BOOLEAN_FALSE },
evaluate_security
};
- return do_cache2(&security);
+ return do_cache2_char(&security);
+}
+
+/*
+ * Interface that represents the logd buffer size determination so that others
+ * need not guess our intentions.
+ */
+
+/* Property helper */
+static bool check_flag(const char* prop, const char* flag) {
+ const char* cp = strcasestr(prop, flag);
+ if (!cp) {
+ return false;
+ }
+ /* We only will document comma (,) */
+ static const char sep[] = ",:;|+ \t\f";
+ if ((cp != prop) && !strchr(sep, cp[-1])) {
+ return false;
+ }
+ cp += strlen(flag);
+ return !*cp || !!strchr(sep, *cp);
+}
+
+/* cache structure */
+struct cache_property {
+ struct cache cache;
+ char property[PROP_VALUE_MAX];
+};
+
+static void refresh_cache_property(struct cache_property* cache, const char* key)
+{
+ if (!cache->cache.pinfo) {
+ cache->cache.pinfo = __system_property_find(key);
+ if (!cache->cache.pinfo) {
+ return;
+ }
+ }
+ cache->cache.serial = __system_property_serial(cache->cache.pinfo);
+ __system_property_read(cache->cache.pinfo, 0, cache->property);
+}
+
+/* get boolean with the logger twist that supports eng adjustments */
+LIBLOG_ABI_PRIVATE bool __android_logger_property_get_bool(const char* key,
+ int flag)
+{
+ struct cache_property property = { { NULL, -1 }, { 0 } };
+ if (flag & BOOL_DEFAULT_FLAG_PERSIST) {
+ char newkey[PROP_NAME_MAX];
+ snprintf(newkey, sizeof(newkey), "ro.%s", key);
+ refresh_cache_property(&property, newkey);
+ property.cache.pinfo = NULL;
+ property.cache.serial = -1;
+ snprintf(newkey, sizeof(newkey), "persist.%s", key);
+ refresh_cache_property(&property, newkey);
+ property.cache.pinfo = NULL;
+ property.cache.serial = -1;
+ }
+
+ refresh_cache_property(&property, key);
+
+ if (check_flag(property.property, "true")) {
+ return true;
+ }
+ if (check_flag(property.property, "false")) {
+ return false;
+ }
+ if (check_flag(property.property, "eng")) {
+ flag |= BOOL_DEFAULT_FLAG_ENG;
+ }
+ /* this is really a "not" flag */
+ if (check_flag(property.property, "svelte")) {
+ flag |= BOOL_DEFAULT_FLAG_SVELTE;
+ }
+
+ /* Sanity Check */
+ if (flag & (BOOL_DEFAULT_FLAG_SVELTE | BOOL_DEFAULT_FLAG_ENG)) {
+ flag &= ~BOOL_DEFAULT_FLAG_TRUE_FALSE;
+ flag |= BOOL_DEFAULT_TRUE;
+ }
+
+ if ((flag & BOOL_DEFAULT_FLAG_SVELTE)
+ && __android_logger_property_get_bool("ro.config.low_ram",
+ BOOL_DEFAULT_FALSE)) {
+ return false;
+ }
+ if ((flag & BOOL_DEFAULT_FLAG_ENG) && !__android_log_is_debuggable()) {
+ return false;
+ }
+
+ return (flag & BOOL_DEFAULT_FLAG_TRUE_FALSE) != BOOL_DEFAULT_FALSE;
+}
+
+LIBLOG_ABI_PRIVATE bool __android_logger_valid_buffer_size(unsigned long value)
+{
+ static long pages, pagesize;
+ unsigned long maximum;
+
+ if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
+ return false;
+ }
+
+ if (!pages) {
+ pages = sysconf(_SC_PHYS_PAGES);
+ }
+ if (pages < 1) {
+ return true;
+ }
+
+ if (!pagesize) {
+ pagesize = sysconf(_SC_PAGESIZE);
+ if (pagesize <= 1) {
+ pagesize = PAGE_SIZE;
+ }
+ }
+
+ /* maximum memory impact a somewhat arbitrary ~3% */
+ pages = (pages + 31) / 32;
+ maximum = pages * pagesize;
+
+ if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
+ return true;
+ }
+
+ return value <= maximum;
+}
+
+struct cache2_property_size {
+ pthread_mutex_t lock;
+ uint32_t serial;
+ const char* key_persist;
+ struct cache_property cache_persist;
+ const char* key_ro;
+ struct cache_property cache_ro;
+ unsigned long (*const evaluate)(const struct cache2_property_size* self);
+};
+
+static inline unsigned long do_cache2_property_size(struct cache2_property_size* self)
+{
+ uint32_t current_serial;
+ int change_detected;
+ unsigned long v;
+
+ if (pthread_mutex_trylock(&self->lock)) {
+ /* We are willing to accept some race in this context */
+ return self->evaluate(self);
+ }
+
+ change_detected = check_cache(&self->cache_persist.cache)
+ || check_cache(&self->cache_ro.cache);
+ current_serial = __system_property_area_serial();
+ if (current_serial != self->serial) {
+ change_detected = 1;
+ }
+ if (change_detected) {
+ refresh_cache_property(&self->cache_persist, self->key_persist);
+ refresh_cache_property(&self->cache_ro, self->key_ro);
+ self->serial = current_serial;
+ }
+ v = self->evaluate(self);
+
+ pthread_mutex_unlock(&self->lock);
+
+ return v;
+}
+
+static unsigned long property_get_size_from_cache(const struct cache_property* cache)
+{
+ char* cp;
+ unsigned long value = strtoul(cache->property, &cp, 10);
+
+ switch(*cp) {
+ case 'm':
+ case 'M':
+ value *= 1024;
+ /* FALLTHRU */
+ case 'k':
+ case 'K':
+ value *= 1024;
+ /* FALLTHRU */
+ case '\0':
+ break;
+
+ default:
+ value = 0;
+ }
+
+ if (!__android_logger_valid_buffer_size(value)) {
+ value = 0;
+ }
+
+ return value;
+}
+
+static unsigned long evaluate_property_get_size(const struct cache2_property_size* self)
+{
+ unsigned long size = property_get_size_from_cache(&self->cache_persist);
+ if (size) {
+ return size;
+ }
+ return property_get_size_from_cache(&self->cache_ro);
+}
+
+LIBLOG_ABI_PRIVATE unsigned long __android_logger_get_buffer_size(log_id_t logId)
+{
+ static const char global_tunable[] = "persist.logd.size"; /* Settings App */
+ static const char global_default[] = "ro.logd.size"; /* BoardConfig.mk */
+ static struct cache2_property_size global = {
+ PTHREAD_MUTEX_INITIALIZER,
+ 0,
+ global_tunable,
+ { { NULL, -1 }, {} },
+ global_default,
+ { { NULL, -1 }, {} },
+ evaluate_property_get_size
+ };
+ char key_persist[PROP_NAME_MAX];
+ char key_ro[PROP_NAME_MAX];
+ struct cache2_property_size local = {
+ PTHREAD_MUTEX_INITIALIZER,
+ 0,
+ key_persist,
+ { { NULL, -1 }, {} },
+ key_ro,
+ { { NULL, -1 }, {} },
+ evaluate_property_get_size
+ };
+ unsigned long property_size, default_size;
+
+ default_size = do_cache2_property_size(&global);
+ if (!default_size) {
+ default_size = __android_logger_property_get_bool("ro.config.low_ram",
+ BOOL_DEFAULT_FALSE)
+ ? LOG_BUFFER_MIN_SIZE /* 64K */
+ : LOG_BUFFER_SIZE; /* 256K */
+ }
+
+ snprintf(key_persist, sizeof(key_persist), "%s.%s",
+ global_tunable, android_log_id_to_name(logId));
+ snprintf(key_ro, sizeof(key_ro), "%s.%s",
+ global_default, android_log_id_to_name(logId));
+ property_size = do_cache2_property_size(&local);
+
+ if (!property_size) {
+ property_size = default_size;
+ }
+
+ if (!property_size) {
+ property_size = LOG_BUFFER_SIZE;
+ }
+
+ return property_size;
}
diff --git a/liblog/log_time.cpp b/liblog/log_time.cpp
index c8bd27d..dfd2d44 100644
--- a/liblog/log_time.cpp
+++ b/liblog/log_time.cpp
@@ -19,7 +19,7 @@
#include <stdio.h>
#include <string.h>
-#include <log/logger.h>
+#include <private/android_logger.h>
#include "log_portability.h"
diff --git a/liblog/logd_reader.c b/liblog/logd_reader.c
index 563b5c7..99d7fea 100644
--- a/liblog/logd_reader.c
+++ b/liblog/logd_reader.c
@@ -31,9 +31,7 @@
#include <time.h>
#include <unistd.h>
-#include <android/log.h>
#include <cutils/sockets.h>
-#include <log/logger.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
@@ -482,17 +480,17 @@
struct sigaction old_sigaction;
unsigned int old_alarm = 0;
char buffer[256], *cp, c;
- int e, ret, remaining;
-
- int sock = transp->context.sock;
- if (sock > 0) {
- return sock;
- }
+ int e, ret, remaining, sock;
if (!logger_list) {
return -EINVAL;
}
+ sock = atomic_load(&transp->context.sock);
+ if (sock > 0) {
+ return sock;
+ }
+
sock = socket_local_client("logdr",
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_SEQPACKET);
@@ -587,7 +585,11 @@
return ret;
}
- return transp->context.sock = sock;
+ ret = atomic_exchange(&transp->context.sock, sock);
+ if ((ret > 0) && (ret != sock)) {
+ close(ret);
+ }
+ return sock;
}
/* Read from the selected logs */
@@ -662,8 +664,8 @@
static void logdClose(struct android_log_logger_list *logger_list __unused,
struct android_log_transport_context *transp)
{
- if (transp->context.sock > 0) {
- close (transp->context.sock);
- transp->context.sock = -1;
+ int sock = atomic_exchange(&transp->context.sock, -1);
+ if (sock > 0) {
+ close (sock);
}
}
diff --git a/liblog/logd_writer.c b/liblog/logd_writer.c
index e8e392d..8fdfb92 100644
--- a/liblog/logd_writer.c
+++ b/liblog/logd_writer.c
@@ -31,9 +31,7 @@
#include <time.h>
#include <unistd.h>
-#include <android/log.h>
#include <cutils/sockets.h>
-#include <log/logger.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
@@ -65,7 +63,8 @@
{
int i, ret = 0;
- if (logdLoggerWrite.context.sock < 0) {
+ i = atomic_load(&logdLoggerWrite.context.sock);
+ if (i < 0) {
i = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
if (i < 0) {
ret = -errno;
@@ -80,7 +79,11 @@
ret = -errno;
close(i);
} else {
- logdLoggerWrite.context.sock = i;
+ ret = atomic_exchange(&logdLoggerWrite.context.sock, i);
+ if ((ret >= 0) && (ret != i)) {
+ close(ret);
+ }
+ ret = 0;
}
}
}
@@ -90,9 +93,9 @@
static void logdClose()
{
- if (logdLoggerWrite.context.sock >= 0) {
- close(logdLoggerWrite.context.sock);
- logdLoggerWrite.context.sock = -1;
+ int sock = atomic_exchange(&logdLoggerWrite.context.sock, -1);
+ if (sock >= 0) {
+ close(sock);
}
}
@@ -101,7 +104,7 @@
if (logId > LOG_ID_SECURITY) {
return -EINVAL;
}
- if (logdLoggerWrite.context.sock < 0) {
+ if (atomic_load(&logdLoggerWrite.context.sock) < 0) {
if (access("/dev/socket/logdw", W_OK) == 0) {
return 0;
}
@@ -121,7 +124,7 @@
static atomic_int_fast32_t dropped;
static atomic_int_fast32_t droppedSecurity;
- if (logdLoggerWrite.context.sock < 0) {
+ if (atomic_load(&logdLoggerWrite.context.sock) < 0) {
return -EBADF;
}
@@ -160,7 +163,7 @@
newVec[0].iov_base = (unsigned char *)&header;
newVec[0].iov_len = sizeof(header);
- if (logdLoggerWrite.context.sock > 0) {
+ if (atomic_load(&logdLoggerWrite.context.sock) > 0) {
int32_t snapshot = atomic_exchange_explicit(&droppedSecurity, 0,
memory_order_relaxed);
if (snapshot) {
@@ -174,7 +177,8 @@
newVec[headerLength].iov_base = &buffer;
newVec[headerLength].iov_len = sizeof(buffer);
- ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, 2));
+ ret = TEMP_FAILURE_RETRY(writev(
+ atomic_load(&logdLoggerWrite.context.sock), newVec, 2));
if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
atomic_fetch_add_explicit(&droppedSecurity, snapshot,
memory_order_relaxed);
@@ -194,7 +198,8 @@
newVec[headerLength].iov_base = &buffer;
newVec[headerLength].iov_len = sizeof(buffer);
- ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, 2));
+ ret = TEMP_FAILURE_RETRY(writev(
+ atomic_load(&logdLoggerWrite.context.sock), newVec, 2));
if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
atomic_fetch_add_explicit(&dropped, snapshot,
memory_order_relaxed);
@@ -223,7 +228,8 @@
* ENOTCONN occurs if logd dies.
* EAGAIN occurs if logd is overloaded.
*/
- ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, i));
+ ret = TEMP_FAILURE_RETRY(writev(
+ atomic_load(&logdLoggerWrite.context.sock), newVec, i));
if (ret < 0) {
ret = -errno;
if (ret == -ENOTCONN) {
@@ -236,7 +242,8 @@
return ret;
}
- ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, i));
+ ret = TEMP_FAILURE_RETRY(writev(
+ atomic_load(&logdLoggerWrite.context.sock), newVec, i));
if (ret < 0) {
ret = -errno;
}
diff --git a/liblog/logger.h b/liblog/logger.h
index 8fb2b4d..50d1cb4 100644
--- a/liblog/logger.h
+++ b/liblog/logger.h
@@ -17,12 +17,12 @@
#ifndef _LIBLOG_LOGGER_H__
#define _LIBLOG_LOGGER_H__
+#include <stdatomic.h>
#include <stdbool.h>
-#include <log/uio.h>
-#include <android/log.h>
#include <cutils/list.h>
-#include <log/logger.h>
+#include <log/log.h>
+#include <log/uio.h>
#include "log_portability.h"
@@ -31,9 +31,10 @@
/* Union, sock or fd of zero is not allowed unless static initialized */
union android_log_context {
void *private;
- int sock;
- int fd;
+ atomic_int sock;
+ atomic_int fd;
struct listnode *node;
+ atomic_uintptr_t atomic_pointer;
};
struct android_log_transport_write {
@@ -155,7 +156,6 @@
LIBLOG_HIDDEN void __android_log_lock();
LIBLOG_HIDDEN int __android_log_trylock();
LIBLOG_HIDDEN void __android_log_unlock();
-LIBLOG_HIDDEN int __android_log_is_debuggable();
__END_DECLS
diff --git a/liblog/logger_name.c b/liblog/logger_name.c
index 12e263a..5c4feaf 100644
--- a/liblog/logger_name.c
+++ b/liblog/logger_name.c
@@ -16,8 +16,7 @@
#include <string.h>
-#include <android/log.h>
-#include <log/logger.h>
+#include <log/log.h>
#include "log_portability.h"
diff --git a/liblog/logger_read.c b/liblog/logger_read.c
index d979e22..c3cb7ad 100644
--- a/liblog/logger_read.c
+++ b/liblog/logger_read.c
@@ -25,7 +25,6 @@
#include <android/log.h>
#include <cutils/list.h>
-#include <log/logger.h>
#include <private/android_filesystem_config.h>
#include "config_read.h"
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index 1e56b27..157bd88 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -24,9 +24,7 @@
#include <android/set_abort_message.h>
#endif
-#include <android/log.h>
#include <log/event_tag_map.h>
-#include <log/logger.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
@@ -191,7 +189,7 @@
__android_log_unlock();
#if defined(__BIONIC__)
- android_closeEventTagMap(m);
+ if (m != (EventTagMap *)(uintptr_t)-1LL) android_closeEventTagMap(m);
#endif
}
diff --git a/liblog/logprint.c b/liblog/logprint.c
index f9b14bd..fb942a1 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -21,19 +21,18 @@
#include <assert.h>
#include <ctype.h>
#include <errno.h>
+#include <inttypes.h>
#include <pwd.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <inttypes.h>
#include <sys/param.h>
#include <sys/types.h>
-#include <android/log.h>
#include <cutils/list.h>
-#include <log/logger.h>
+#include <log/log.h>
#include <log/logprint.h>
#include "log_portability.h"
@@ -59,9 +58,16 @@
bool epoch_output;
bool monotonic_output;
bool uid_output;
+ bool descriptive_output;
};
/*
+ * API issues prevent us from exposing "descriptive" in AndroidLogFormat_t
+ * during android_log_processBinaryLogBuffer(), so we break layering.
+ */
+static bool descriptive_output = false;
+
+/*
* gnome-terminal color tags
* See http://misc.flogisoft.com/bash/tip_colors_and_formatting
* for ideas on how to set the forground color of the text for xterm.
@@ -210,6 +216,8 @@
p_ret->epoch_output = false;
p_ret->monotonic_output = android_log_clockid() == CLOCK_MONOTONIC;
p_ret->uid_output = false;
+ p_ret->descriptive_output = false;
+ descriptive_output = false;
return p_ret;
}
@@ -268,6 +276,10 @@
case FORMAT_MODIFIER_UID:
p_format->uid_output = true;
return 0;
+ case FORMAT_MODIFIER_DESCRIPT:
+ p_format->descriptive_output = true;
+ descriptive_output = true;
+ return 0;
default:
break;
}
@@ -295,6 +307,7 @@
else if (strcmp(formatString, "threadtime") == 0) format = FORMAT_THREADTIME;
else if (strcmp(formatString, "long") == 0) format = FORMAT_LONG;
else if (strcmp(formatString, "color") == 0) format = FORMAT_MODIFIER_COLOR;
+ else if (strcmp(formatString, "colour") == 0) format = FORMAT_MODIFIER_COLOR;
else if (strcmp(formatString, "usec") == 0) format = FORMAT_MODIFIER_TIME_USEC;
else if (strcmp(formatString, "printable") == 0) format = FORMAT_MODIFIER_PRINTABLE;
else if (strcmp(formatString, "year") == 0) format = FORMAT_MODIFIER_YEAR;
@@ -302,6 +315,7 @@
else if (strcmp(formatString, "epoch") == 0) format = FORMAT_MODIFIER_EPOCH;
else if (strcmp(formatString, "monotonic") == 0) format = FORMAT_MODIFIER_MONOTONIC;
else if (strcmp(formatString, "uid") == 0) format = FORMAT_MODIFIER_UID;
+ else if (strcmp(formatString, "descriptive") == 0) format = FORMAT_MODIFIER_DESCRIPT;
else {
extern char *tzname[2];
static const char gmt[] = "GMT";
@@ -567,6 +581,19 @@
return ((uint64_t) high << 32) | (uint64_t) low;
}
+static bool findChar(const char** cp, size_t* len, int c) {
+ while (*len && isspace(**cp)) {
+ ++*cp;
+ --*len;
+ }
+ if (c == INT_MAX) return *len;
+ if (*len && (**cp == c)) {
+ ++*cp;
+ --*len;
+ return true;
+ }
+ return false;
+}
/*
* Recursively convert binary log data to printable form.
@@ -579,27 +606,128 @@
*
* Returns 0 on success, 1 on buffer full, -1 on failure.
*/
+enum objectType {
+ TYPE_OBJECTS = '1',
+ TYPE_BYTES = '2',
+ TYPE_MILLISECONDS = '3',
+ TYPE_ALLOCATIONS = '4',
+ TYPE_ID = '5',
+ TYPE_PERCENT = '6'
+};
+
static int android_log_printBinaryEvent(const unsigned char** pEventData,
- size_t* pEventDataLen, char** pOutBuf, size_t* pOutBufLen)
+ size_t* pEventDataLen, char** pOutBuf, size_t* pOutBufLen,
+ const char** fmtStr, size_t* fmtLen)
{
const unsigned char* eventData = *pEventData;
size_t eventDataLen = *pEventDataLen;
char* outBuf = *pOutBuf;
+ char* outBufSave = outBuf;
size_t outBufLen = *pOutBufLen;
+ size_t outBufLenSave = outBufLen;
unsigned char type;
size_t outCount;
int result = 0;
+ const char* cp;
+ size_t len;
+ int64_t lval;
if (eventDataLen < 1)
return -1;
type = *eventData++;
eventDataLen--;
+ cp = NULL;
+ len = 0;
+ if (fmtStr && *fmtStr && fmtLen && *fmtLen && **fmtStr) {
+ cp = *fmtStr;
+ len = *fmtLen;
+ }
+ /*
+ * event.logtag format specification:
+ *
+ * Optionally, after the tag names can be put a description for the value(s)
+ * of the tag. Description are in the format
+ * (<name>|data type[|data unit])
+ * Multiple values are separated by commas.
+ *
+ * The data type is a number from the following values:
+ * 1: int
+ * 2: long
+ * 3: string
+ * 4: list
+ * 5: float
+ *
+ * The data unit is a number taken from the following list:
+ * 1: Number of objects
+ * 2: Number of bytes
+ * 3: Number of milliseconds
+ * 4: Number of allocations
+ * 5: Id
+ * 6: Percent
+ * Default value for data of type int/long is 2 (bytes).
+ */
+ if (!cp || !findChar(&cp, &len, '(')) {
+ len = 0;
+ } else {
+ char* outBufLastSpace = NULL;
+
+ findChar(&cp, &len, INT_MAX);
+ while (len && *cp && (*cp != '|') && (*cp != ')')) {
+ if (outBufLen <= 0) {
+ /* halt output */
+ goto no_room;
+ }
+ outBufLastSpace = isspace(*cp) ? outBuf : NULL;
+ *outBuf = *cp;
+ ++outBuf;
+ ++cp;
+ --outBufLen;
+ --len;
+ }
+ if (outBufLastSpace) {
+ outBufLen += outBuf - outBufLastSpace;
+ outBuf = outBufLastSpace;
+ }
+ if (outBufLen <= 0) {
+ /* halt output */
+ goto no_room;
+ }
+ if (outBufSave != outBuf) {
+ *outBuf = '=';
+ ++outBuf;
+ --outBufLen;
+ }
+
+ if (findChar(&cp, &len, '|') && findChar(&cp, &len, INT_MAX)) {
+ static const unsigned char typeTable[] = {
+ EVENT_TYPE_INT,
+ EVENT_TYPE_LONG,
+ EVENT_TYPE_STRING,
+ EVENT_TYPE_LIST,
+ EVENT_TYPE_FLOAT
+ };
+
+ if ((*cp >= '1') &&
+ (*cp < (char)('1' + (sizeof(typeTable) / sizeof(typeTable[0])))) &&
+ (type != typeTable[(size_t)(*cp - '1')])) len = 0;
+
+ if (len) {
+ ++cp;
+ --len;
+ } else {
+ /* reset the format */
+ outBuf = outBufSave;
+ outBufLen = outBufLenSave;
+ }
+ }
+ }
+ lval = 0;
switch (type) {
case EVENT_TYPE_INT:
/* 32-bit signed int */
{
- int ival;
+ int32_t ival;
if (eventDataLen < 4)
return -1;
@@ -607,35 +735,24 @@
eventData += 4;
eventDataLen -= 4;
- outCount = snprintf(outBuf, outBufLen, "%d", ival);
- if (outCount < outBufLen) {
- outBuf += outCount;
- outBufLen -= outCount;
- } else {
- /* halt output */
- goto no_room;
- }
+ lval = ival;
}
- break;
+ goto pr_lval;
case EVENT_TYPE_LONG:
/* 64-bit signed long */
- {
- uint64_t lval;
-
- if (eventDataLen < 8)
- return -1;
- lval = get8LE(eventData);
- eventData += 8;
- eventDataLen -= 8;
-
- outCount = snprintf(outBuf, outBufLen, "%" PRId64, lval);
- if (outCount < outBufLen) {
- outBuf += outCount;
- outBufLen -= outCount;
- } else {
- /* halt output */
- goto no_room;
- }
+ if (eventDataLen < 8)
+ return -1;
+ lval = get8LE(eventData);
+ eventData += 8;
+ eventDataLen -= 8;
+ pr_lval:
+ outCount = snprintf(outBuf, outBufLen, "%" PRId64, lval);
+ if (outCount < outBufLen) {
+ outBuf += outCount;
+ outBufLen -= outCount;
+ } else {
+ /* halt output */
+ goto no_room;
}
break;
case EVENT_TYPE_FLOAT:
@@ -675,6 +792,11 @@
if (eventDataLen < strLen)
return -1;
+ if (cp && (strLen == 0)) {
+ /* reset the format if no content */
+ outBuf = outBufSave;
+ outBufLen = outBufLenSave;
+ }
if (strLen < outBufLen) {
memcpy(outBuf, eventData, strLen);
outBuf += strLen;
@@ -711,7 +833,7 @@
for (i = 0; i < count; i++) {
result = android_log_printBinaryEvent(&eventData, &eventDataLen,
- &outBuf, &outBufLen);
+ &outBuf, &outBufLen, fmtStr, fmtLen);
if (result != 0)
goto bail;
@@ -737,12 +859,90 @@
fprintf(stderr, "Unknown binary event type %d\n", type);
return -1;
}
+ if (cp && len) {
+ if (findChar(&cp, &len, '|') && findChar(&cp, &len, INT_MAX)) {
+ switch (*cp) {
+ case TYPE_OBJECTS:
+ outCount = 0;
+ /* outCount = snprintf(outBuf, outBufLen, " objects"); */
+ break;
+ case TYPE_BYTES:
+ if ((lval != 0) && ((lval % 1024) == 0)) {
+ /* repaint with multiplier */
+ static const char suffixTable[] = { 'K', 'M', 'G', 'T' };
+ size_t idx = 0;
+ outBuf -= outCount;
+ outBufLen += outCount;
+ do {
+ lval /= 1024;
+ if ((lval % 1024) != 0) break;
+ } while (++idx < ((sizeof(suffixTable) /
+ sizeof(suffixTable[0])) - 1));
+ outCount = snprintf(outBuf, outBufLen,
+ "%" PRId64 "%cB",
+ lval, suffixTable[idx]);
+ } else {
+ outCount = snprintf(outBuf, outBufLen, "B");
+ }
+ break;
+ case TYPE_MILLISECONDS:
+ if (((lval <= -1000) || (1000 <= lval)) &&
+ (outBufLen || (outBuf[-1] == '0'))) {
+ /* repaint as (fractional) seconds, possibly saving space */
+ if (outBufLen) outBuf[0] = outBuf[-1];
+ outBuf[-1] = outBuf[-2];
+ outBuf[-2] = outBuf[-3];
+ outBuf[-3] = '.';
+ while ((outBufLen == 0) || (*outBuf == '0')) {
+ --outBuf;
+ ++outBufLen;
+ }
+ if (*outBuf != '.') {
+ ++outBuf;
+ --outBufLen;
+ }
+ outCount = snprintf(outBuf, outBufLen, "s");
+ } else {
+ outCount = snprintf(outBuf, outBufLen, "ms");
+ }
+ break;
+ case TYPE_ALLOCATIONS:
+ outCount = 0;
+ /* outCount = snprintf(outBuf, outBufLen, " allocations"); */
+ break;
+ case TYPE_ID:
+ outCount = 0;
+ break;
+ case TYPE_PERCENT:
+ outCount = snprintf(outBuf, outBufLen, "%%");
+ break;
+ default: /* ? */
+ outCount = 0;
+ break;
+ }
+ ++cp;
+ --len;
+ if (outCount < outBufLen) {
+ outBuf += outCount;
+ outBufLen -= outCount;
+ } else if (outCount) {
+ /* halt output */
+ goto no_room;
+ }
+ }
+ if (!findChar(&cp, &len, ')')) len = 0;
+ if (!findChar(&cp, &len, ',')) len = 0;
+ }
bail:
*pEventData = eventData;
*pEventDataLen = eventDataLen;
*pOutBuf = outBuf;
*pOutBufLen = outBufLen;
+ if (cp) {
+ *fmtStr = cp;
+ *fmtLen = len;
+ }
return result;
no_room:
@@ -765,7 +965,7 @@
char *messageBuf, int messageBufLen)
{
size_t inCount;
- unsigned int tagIndex;
+ uint32_t tagIndex;
const unsigned char* eventData;
entry->tv_sec = buf->sec;
@@ -818,7 +1018,7 @@
if (entry->tag == NULL) {
size_t tagLen;
- tagLen = snprintf(messageBuf, messageBufLen, "[%d]", tagIndex);
+ tagLen = snprintf(messageBuf, messageBufLen, "[%" PRIu32 "]", tagIndex);
if (tagLen >= (size_t)messageBufLen) {
tagLen = messageBufLen - 1;
}
@@ -832,10 +1032,27 @@
* Format the event log data into the buffer.
*/
char* outBuf = messageBuf;
- size_t outRemaining = messageBufLen-1; /* leave one for nul byte */
+ size_t outRemaining = messageBufLen - 1; /* leave one for nul byte */
int result;
+ const char* fmtStr = NULL;
+ size_t fmtLen = 0;
+ if (descriptive_output && map) {
+ fmtStr = android_lookupEventFormat_len(map, &fmtLen, tagIndex);
+ }
result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
- &outRemaining);
+ &outRemaining, &fmtStr, &fmtLen);
+ if ((result == 1) && fmtStr) {
+ /* We overflowed :-(, let's repaint the line w/o format dressings */
+ eventData = (const unsigned char*)buf->msg;
+ if (buf2->hdr_size) {
+ eventData = ((unsigned char *)buf2) + buf2->hdr_size;
+ }
+ eventData += 4;
+ outBuf = messageBuf;
+ outRemaining = messageBufLen - 1;
+ result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
+ &outRemaining, NULL, NULL);
+ }
if (result < 0) {
fprintf(stderr, "Binary log entry conversion failed\n");
return -1;
diff --git a/liblog/pmsg_reader.c b/liblog/pmsg_reader.c
index 679c159..a0a69c1 100644
--- a/liblog/pmsg_reader.c
+++ b/liblog/pmsg_reader.c
@@ -151,8 +151,8 @@
memset(log_msg, 0, sizeof(*log_msg));
- if (transp->context.fd <= 0) {
- int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
+ if (atomic_load(&transp->context.fd) <= 0) {
+ int i, fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
if (fd < 0) {
return -errno;
@@ -164,13 +164,22 @@
return -errno;
}
}
- transp->context.fd = fd;
+ i = atomic_exchange(&transp->context.fd, fd);
+ if ((i > 0) && (i != fd)) {
+ close(i);
+ }
preread_count = 0;
}
while(1) {
+ int fd;
+
if (preread_count < sizeof(buf)) {
- ret = TEMP_FAILURE_RETRY(read(transp->context.fd,
+ fd = atomic_load(&transp->context.fd);
+ if (fd <= 0) {
+ return -EBADF;
+ }
+ ret = TEMP_FAILURE_RETRY(read(fd,
&buf.p.magic + preread_count,
sizeof(buf) - preread_count));
if (ret < 0) {
@@ -212,9 +221,13 @@
log_msg->entry_v4.msg :
log_msg->entry_v3.msg;
*msg = buf.prio;
- ret = TEMP_FAILURE_RETRY(read(transp->context.fd,
- msg + sizeof(buf.prio),
- buf.p.len - sizeof(buf)));
+ fd = atomic_load(&transp->context.fd);
+ if (fd <= 0) {
+ return -EBADF;
+ }
+ ret = TEMP_FAILURE_RETRY(read(fd,
+ msg + sizeof(buf.prio),
+ buf.p.len - sizeof(buf)));
if (ret < 0) {
return -errno;
}
@@ -239,12 +252,19 @@
}
}
- current = TEMP_FAILURE_RETRY(lseek(transp->context.fd,
- (off_t)0, SEEK_CUR));
+ fd = atomic_load(&transp->context.fd);
+ if (fd <= 0) {
+ return -EBADF;
+ }
+ current = TEMP_FAILURE_RETRY(lseek(fd, (off_t)0, SEEK_CUR));
if (current < 0) {
return -errno;
}
- next = TEMP_FAILURE_RETRY(lseek(transp->context.fd,
+ fd = atomic_load(&transp->context.fd);
+ if (fd <= 0) {
+ return -EBADF;
+ }
+ next = TEMP_FAILURE_RETRY(lseek(fd,
(off_t)(buf.p.len - sizeof(buf)),
SEEK_CUR));
if (next < 0) {
@@ -258,10 +278,10 @@
static void pmsgClose(struct android_log_logger_list *logger_list __unused,
struct android_log_transport_context *transp) {
- if (transp->context.fd > 0) {
- close (transp->context.fd);
+ int fd = atomic_exchange(&transp->context.fd, 0);
+ if (fd > 0) {
+ close (fd);
}
- transp->context.fd = 0;
}
LIBLOG_ABI_PRIVATE ssize_t __android_log_pmsg_file_read(
diff --git a/liblog/pmsg_writer.c b/liblog/pmsg_writer.c
index 06652f3..c1c068e 100644
--- a/liblog/pmsg_writer.c
+++ b/liblog/pmsg_writer.c
@@ -20,14 +20,12 @@
#include <errno.h>
#include <fcntl.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
-#include <android/log.h>
-#include <log/logger.h>
-
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
@@ -53,18 +51,25 @@
static int pmsgOpen()
{
- if (pmsgLoggerWrite.context.fd < 0) {
- pmsgLoggerWrite.context.fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
+ int fd = atomic_load(&pmsgLoggerWrite.context.fd);
+ if (fd < 0) {
+ int i;
+
+ fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
+ i = atomic_exchange(&pmsgLoggerWrite.context.fd, fd);
+ if ((i >= 0) && (i != fd)) {
+ close(i);
+ }
}
- return pmsgLoggerWrite.context.fd;
+ return fd;
}
static void pmsgClose()
{
- if (pmsgLoggerWrite.context.fd >= 0) {
- close(pmsgLoggerWrite.context.fd);
- pmsgLoggerWrite.context.fd = -1;
+ int fd = atomic_exchange(&pmsgLoggerWrite.context.fd, -1);
+ if (fd >= 0) {
+ close(fd);
}
}
@@ -78,7 +83,7 @@
!__android_log_is_debuggable()) {
return -EINVAL;
}
- if (pmsgLoggerWrite.context.fd < 0) {
+ if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) {
if (access("/dev/pmsg0", W_OK) == 0) {
return 0;
}
@@ -115,7 +120,7 @@
}
}
- if (pmsgLoggerWrite.context.fd < 0) {
+ if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) {
return -EBADF;
}
@@ -169,7 +174,8 @@
}
pmsgHeader.len += payloadSize;
- ret = TEMP_FAILURE_RETRY(writev(pmsgLoggerWrite.context.fd, newVec, i));
+ ret = TEMP_FAILURE_RETRY(writev(atomic_load(&pmsgLoggerWrite.context.fd),
+ newVec, i));
if (ret < 0) {
ret = errno ? -errno : -ENOTCONN;
}
@@ -206,7 +212,7 @@
char prio,
const char *filename,
const char *buf, size_t len) {
- int fd;
+ bool weOpened;
size_t length, packet_len;
const char *tag;
char *cp, *slash;
@@ -228,16 +234,6 @@
return -ENOMEM;
}
- fd = pmsgLoggerWrite.context.fd;
- if (fd < 0) {
- __android_log_lock();
- fd = pmsgOpen();
- __android_log_unlock();
- if (fd < 0) {
- return -EBADF;
- }
- }
-
tag = cp;
slash = strrchr(cp, '/');
if (slash) {
@@ -256,6 +252,7 @@
vec[1].iov_base = (unsigned char *)tag;
vec[1].iov_len = length;
+ weOpened = false;
for (ts.tv_nsec = 0, length = len;
length;
ts.tv_nsec += ANDROID_LOG_PMSG_FILE_SEQUENCE) {
@@ -279,15 +276,36 @@
vec[2].iov_base = (unsigned char *)buf;
vec[2].iov_len = transfer;
+ if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) {
+ if (!weOpened) { /* Impossible for weOpened = true here */
+ __android_log_lock();
+ }
+ weOpened = atomic_load(&pmsgLoggerWrite.context.fd) < 0;
+ if (!weOpened) {
+ __android_log_unlock();
+ } else if (pmsgOpen() < 0) {
+ __android_log_unlock();
+ return -EBADF;
+ }
+ }
+
ret = pmsgWrite(logId, &ts, vec, sizeof(vec) / sizeof(vec[0]));
if (ret <= 0) {
+ if (weOpened) {
+ pmsgClose();
+ __android_log_unlock();
+ }
free(cp);
- return ret;
+ return ret ? ret : (len - length);
}
length -= transfer;
buf += transfer;
}
+ if (weOpened) {
+ pmsgClose();
+ __android_log_unlock();
+ }
free(cp);
return len;
}
diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk
index a755b98..158987a 100644
--- a/liblog/tests/Android.mk
+++ b/liblog/tests/Android.mk
@@ -28,7 +28,6 @@
-Wall -Wextra \
-Werror \
-fno-builtin \
- -std=gnu++11
benchmark_src_files := \
benchmark_main.cpp \
@@ -54,7 +53,6 @@
-Wall -Wextra \
-Werror \
-fno-builtin \
- -std=gnu++11
test_src_files := \
liblog_test.cpp
diff --git a/liblog/tests/libc_test.cpp b/liblog/tests/libc_test.cpp
index 3d58147..f05a955 100644
--- a/liblog/tests/libc_test.cpp
+++ b/liblog/tests/libc_test.cpp
@@ -16,6 +16,7 @@
#include <gtest/gtest.h>
+#include <errno.h>
#include <stdio.h>
TEST(libc, __pstore_append) {
@@ -23,6 +24,22 @@
ASSERT_TRUE(NULL != (fp = fopen("/dev/pmsg0", "a")));
static const char message[] = "libc.__pstore_append\n";
ASSERT_EQ((size_t)1, fwrite(message, sizeof(message), 1, fp));
- ASSERT_EQ(0, fclose(fp));
- fprintf(stderr, "Reboot, ensure string libc.__pstore_append is in /sys/fs/pstore/pmsg-ramoops-0\n");
+ int fflushReturn = fflush(fp);
+ int fflushErrno = fflushReturn ? errno : 0;
+ ASSERT_EQ(0, fflushReturn);
+ ASSERT_EQ(0, fflushErrno);
+ int fcloseReturn = fclose(fp);
+ int fcloseErrno = fcloseReturn ? errno : 0;
+ ASSERT_EQ(0, fcloseReturn);
+ ASSERT_EQ(0, fcloseErrno);
+ if ((fcloseErrno == ENOMEM) || (fflushErrno == ENOMEM)) {
+ fprintf(stderr,
+ "Kernel does not have space allocated to pmsg pstore driver configured\n"
+ );
+ }
+ if (!fcloseReturn && !fcloseErrno && !fflushReturn && !fflushReturn) {
+ fprintf(stderr,
+ "Reboot, ensure string libc.__pstore_append is in /sys/fs/pstore/pmsg-ramoops-0\n"
+ );
+ }
}
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index cd012ce..44045c3 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -20,9 +20,7 @@
#include <sys/types.h>
#include <unistd.h>
-#include <android/log.h>
#include <cutils/sockets.h>
-#include <log/logger.h>
#include <private/android_logger.h>
#include "benchmark.h"
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index b1dae9e..9c09523 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -16,22 +16,22 @@
#include <ctype.h>
#include <dirent.h>
+#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <semaphore.h>
#include <signal.h>
+#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <string>
-#include <android/log.h>
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <cutils/properties.h>
#include <gtest/gtest.h>
-#include <log/logger.h>
#include <log/logprint.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
@@ -129,6 +129,70 @@
ASSERT_LT(0, ret);
}
+std::string popenToString(std::string command) {
+ std::string ret;
+
+ FILE* fp = popen(command.c_str(), "r");
+ if (fp) {
+ if (!android::base::ReadFdToString(fileno(fp), &ret)) ret = "";
+ pclose(fp);
+ }
+ return ret;
+}
+
+static bool isPmsgActive() {
+ pid_t pid = getpid();
+
+ std::string myPidFds = popenToString(android::base::StringPrintf(
+ "ls -l /proc/%d/fd", pid));
+ if (myPidFds.length() == 0) return true; // guess it is?
+
+ return std::string::npos != myPidFds.find(" -> /dev/pmsg0");
+}
+
+static bool isLogdwActive() {
+ std::string logdwSignature = popenToString(
+ "grep /dev/socket/logdw /proc/net/unix");
+ size_t beginning = logdwSignature.find(" ");
+ if (beginning == std::string::npos) return true;
+ beginning = logdwSignature.find(" ", beginning + 1);
+ if (beginning == std::string::npos) return true;
+ size_t end = logdwSignature.find(" ", beginning + 1);
+ if (end == std::string::npos) return true;
+ end = logdwSignature.find(" ", end + 1);
+ if (end == std::string::npos) return true;
+ end = logdwSignature.find(" ", end + 1);
+ if (end == std::string::npos) return true;
+ end = logdwSignature.find(" ", end + 1);
+ if (end == std::string::npos) return true;
+ std::string allLogdwEndpoints = popenToString(
+ "grep ' 00000002" +
+ logdwSignature.substr(beginning, end - beginning) +
+ " ' /proc/net/unix | " +
+ "sed -n 's/.* \\([0-9][0-9]*\\)$/ -> socket:[\\1]/p'");
+ if (allLogdwEndpoints.length() == 0) return true;
+
+ // NB: allLogdwEndpoints has some false positives in it, but those
+ // strangers do not overlap with the simplistic activities inside this
+ // test suite.
+
+ pid_t pid = getpid();
+
+ std::string myPidFds = popenToString(android::base::StringPrintf(
+ "ls -l /proc/%d/fd", pid));
+ if (myPidFds.length() == 0) return true;
+
+ // NB: fgrep with multiple strings is broken in Android
+ for (beginning = 0;
+ (end = allLogdwEndpoints.find("\n", beginning)) != std::string::npos;
+ beginning = end + 1) {
+ if (myPidFds.find(allLogdwEndpoints.substr(beginning,
+ end - beginning)) !=
+ std::string::npos) return true;
+ }
+ return false;
+}
+
TEST(liblog, __android_log_btwrite__android_logger_list_read) {
struct logger_list *logger_list;
@@ -140,10 +204,22 @@
// Check that we can close and reopen the logger
log_time ts(CLOCK_MONOTONIC);
ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
+ bool pmsgActiveAfter__android_log_btwrite = isPmsgActive();
+ bool logdwActiveAfter__android_log_btwrite = isLogdwActive();
+ EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
+ EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
__android_log_close();
+ bool pmsgActiveAfter__android_log_close = isPmsgActive();
+ bool logdwActiveAfter__android_log_close = isLogdwActive();
+ EXPECT_FALSE(pmsgActiveAfter__android_log_close);
+ EXPECT_FALSE(logdwActiveAfter__android_log_close);
log_time ts1(CLOCK_MONOTONIC);
ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1)));
+ pmsgActiveAfter__android_log_btwrite = isPmsgActive();
+ logdwActiveAfter__android_log_btwrite = isLogdwActive();
+ EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
+ EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
usleep(1000000);
int count = 0;
@@ -2575,12 +2651,42 @@
"/data/william-shakespeare/MuchAdoAboutNothing.txt";
TEST(liblog, __android_log_pmsg_file_write) {
+ __android_log_close();
+ bool pmsgActiveAfter__android_log_close = isPmsgActive();
+ bool logdwActiveAfter__android_log_close = isLogdwActive();
+ EXPECT_FALSE(pmsgActiveAfter__android_log_close);
+ EXPECT_FALSE(logdwActiveAfter__android_log_close);
+ int return__android_log_pmsg_file_write = __android_log_pmsg_file_write(
+ LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
+ __pmsg_file, max_payload_buf, sizeof(max_payload_buf));
+ EXPECT_LT(0, return__android_log_pmsg_file_write);
+ if (return__android_log_pmsg_file_write == -ENOMEM) {
+ fprintf(stderr,
+ "Kernel does not have space allocated to pmsg pstore driver configured\n"
+ );
+ } else if (!return__android_log_pmsg_file_write) {
+ fprintf(stderr, "Reboot, ensure file %s matches\n"
+ "with liblog.__android_log_msg_file_read test\n",
+ __pmsg_file);
+ }
+ bool pmsgActiveAfter__android_pmsg_file_write = isPmsgActive();
+ bool logdwActiveAfter__android_pmsg_file_write = isLogdwActive();
+ EXPECT_FALSE(pmsgActiveAfter__android_pmsg_file_write);
+ EXPECT_FALSE(logdwActiveAfter__android_pmsg_file_write);
+ EXPECT_LT(0, __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
+ "TEST__android_log_pmsg_file_write",
+ "main"));
+ bool pmsgActiveAfter__android_log_buf_print = isPmsgActive();
+ bool logdwActiveAfter__android_log_buf_print = isLogdwActive();
+ EXPECT_TRUE(pmsgActiveAfter__android_log_buf_print);
+ EXPECT_TRUE(logdwActiveAfter__android_log_buf_print);
EXPECT_LT(0, __android_log_pmsg_file_write(
LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
__pmsg_file, max_payload_buf, sizeof(max_payload_buf)));
- fprintf(stderr, "Reboot, ensure file %s matches\n"
- "with liblog.__android_log_msg_file_read test\n",
- __pmsg_file);
+ pmsgActiveAfter__android_pmsg_file_write = isPmsgActive();
+ logdwActiveAfter__android_pmsg_file_write = isLogdwActive();
+ EXPECT_TRUE(pmsgActiveAfter__android_pmsg_file_write);
+ EXPECT_TRUE(logdwActiveAfter__android_pmsg_file_write);
}
ssize_t __pmsg_fn(log_id_t logId, char prio, const char *filename,
@@ -2597,7 +2703,7 @@
strcmp(max_payload_buf, buf)) {
fprintf(stderr, "comparison fails on content \"%s\"\n", buf);
}
- return !arg ||
+ return arg ||
(LOG_ID_CRASH != logId) ||
(ANDROID_LOG_VERBOSE != prio) ||
!strstr(__pmsg_file, filename) ||
@@ -2608,10 +2714,21 @@
TEST(liblog, __android_log_pmsg_file_read) {
signaled = 0;
+ __android_log_close();
+ bool pmsgActiveAfter__android_log_close = isPmsgActive();
+ bool logdwActiveAfter__android_log_close = isLogdwActive();
+ EXPECT_FALSE(pmsgActiveAfter__android_log_close);
+ EXPECT_FALSE(logdwActiveAfter__android_log_close);
+
ssize_t ret = __android_log_pmsg_file_read(
LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
__pmsg_file, __pmsg_fn, NULL);
+ bool pmsgActiveAfter__android_log_pmsg_file_read = isPmsgActive();
+ bool logdwActiveAfter__android_log_pmsg_file_read = isLogdwActive();
+ EXPECT_FALSE(pmsgActiveAfter__android_log_pmsg_file_read);
+ EXPECT_FALSE(logdwActiveAfter__android_log_pmsg_file_read);
+
if (ret == -ENOENT) {
fprintf(stderr,
"No pre-boot results of liblog.__android_log_mesg_file_write to "
diff --git a/libmemunreachable/Android.bp b/libmemunreachable/Android.bp
index 85bc421..4662368 100644
--- a/libmemunreachable/Android.bp
+++ b/libmemunreachable/Android.bp
@@ -2,7 +2,6 @@
name: "libmemunreachable_defaults",
cflags: [
- "-std=c++14",
"-Wall",
"-Wextra",
"-Werror",
diff --git a/libnativebridge/Android.bp b/libnativebridge/Android.bp
index 598dfcd..5fb56f2 100644
--- a/libnativebridge/Android.bp
+++ b/libnativebridge/Android.bp
@@ -12,7 +12,6 @@
"-Wall",
],
cppflags: [
- "-std=gnu++11",
"-fvisibility=protected",
],
diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc
index 9f9c83f..eafc53d 100644
--- a/libnativebridge/native_bridge.cc
+++ b/libnativebridge/native_bridge.cc
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "nativebridge"
+
#include "nativebridge/native_bridge.h"
#include <dlfcn.h>
@@ -22,6 +24,7 @@
#include <stdio.h>
#include <sys/mount.h>
#include <sys/stat.h>
+#include <unistd.h>
#include <cstring>
@@ -77,6 +80,19 @@
// Current state of the native bridge.
static NativeBridgeState state = NativeBridgeState::kNotSetup;
+// The version of NativeBridge implementation.
+// Different Nativebridge interface needs the service of different version of
+// Nativebridge implementation.
+// Used by isCompatibleWith() which is introduced in v2.
+enum NativeBridgeImplementationVersion {
+ // first version, not used.
+ DEFAULT_VERSION = 1,
+ // The version which signal semantic is introduced.
+ SIGNAL_VERSION = 2,
+ // The version which namespace semantic is introduced.
+ NAMESPACE_VERSION = 3,
+};
+
// Whether we had an error at some point.
static bool had_error = false;
@@ -97,8 +113,6 @@
// and hard code the directory name again here.
static constexpr const char* kCodeCacheDir = "code_cache";
-static constexpr uint32_t kLibNativeBridgeVersion = 2;
-
// Characters allowed in a native bridge filename. The first character must
// be in [a-zA-Z] (expected 'l' for "libx"). The rest must be in [a-zA-Z0-9._-].
static bool CharacterAllowed(char c, bool first) {
@@ -149,19 +163,18 @@
}
}
-static bool VersionCheck(const NativeBridgeCallbacks* cb) {
+// The policy of invoking Nativebridge changed in v3 with/without namespace.
+// Suggest Nativebridge implementation not maintain backward-compatible.
+static bool isCompatibleWith(const uint32_t version) {
// Libnativebridge is now designed to be forward-compatible. So only "0" is an unsupported
// version.
- if (cb == nullptr || cb->version == 0) {
+ if (callbacks == nullptr || callbacks->version == 0 || version == 0) {
return false;
}
// If this is a v2+ bridge, it may not be forwards- or backwards-compatible. Check.
- if (cb->version >= 2) {
- if (!callbacks->isCompatibleWith(kLibNativeBridgeVersion)) {
- // TODO: Scan which version is supported, and fall back to handle it.
- return false;
- }
+ if (callbacks->version >= SIGNAL_VERSION) {
+ return callbacks->isCompatibleWith(version);
}
return true;
@@ -202,7 +215,7 @@
callbacks = reinterpret_cast<NativeBridgeCallbacks*>(dlsym(handle,
kNativeBridgeInterfaceSymbol));
if (callbacks != nullptr) {
- if (VersionCheck(callbacks)) {
+ if (isCompatibleWith(NAMESPACE_VERSION)) {
// Store the handle for later.
native_bridge_handle = handle;
} else {
@@ -517,8 +530,91 @@
}
NativeBridgeSignalHandlerFn NativeBridgeGetSignalHandler(int signal) {
- if (NativeBridgeInitialized() && callbacks->version >= 2) {
- return callbacks->getSignalHandler(signal);
+ if (NativeBridgeInitialized()) {
+ if (isCompatibleWith(SIGNAL_VERSION)) {
+ return callbacks->getSignalHandler(signal);
+ } else {
+ ALOGE("not compatible with version %d, cannot get signal handler", SIGNAL_VERSION);
+ }
+ }
+ return nullptr;
+}
+
+int NativeBridgeUnloadLibrary(void* handle) {
+ if (NativeBridgeInitialized()) {
+ if (isCompatibleWith(NAMESPACE_VERSION)) {
+ return callbacks->unloadLibrary(handle);
+ } else {
+ ALOGE("not compatible with version %d, cannot unload library", NAMESPACE_VERSION);
+ }
+ }
+ return -1;
+}
+
+const char* NativeBridgeGetError() {
+ if (NativeBridgeInitialized()) {
+ if (isCompatibleWith(NAMESPACE_VERSION)) {
+ return callbacks->getError();
+ } else {
+ return "native bridge implementation is not compatible with version 3, cannot get message";
+ }
+ }
+ return "native bridge is not initialized";
+}
+
+bool NativeBridgeIsPathSupported(const char* path) {
+ if (NativeBridgeInitialized()) {
+ if (isCompatibleWith(NAMESPACE_VERSION)) {
+ return callbacks->isPathSupported(path);
+ } else {
+ ALOGE("not compatible with version %d, cannot check via library path", NAMESPACE_VERSION);
+ }
+ }
+ return false;
+}
+
+bool NativeBridgeInitNamespace(const char* public_ns_sonames,
+ const char* anon_ns_library_path) {
+ if (NativeBridgeInitialized()) {
+ if (isCompatibleWith(NAMESPACE_VERSION)) {
+ return callbacks->initNamespace(public_ns_sonames, anon_ns_library_path);
+ } else {
+ ALOGE("not compatible with version %d, cannot init namespace", NAMESPACE_VERSION);
+ }
+ }
+
+ return false;
+}
+
+native_bridge_namespace_t* NativeBridgeCreateNamespace(const char* name,
+ const char* ld_library_path,
+ const char* default_library_path,
+ uint64_t type,
+ const char* permitted_when_isolated_path,
+ native_bridge_namespace_t* parent_ns) {
+ if (NativeBridgeInitialized()) {
+ if (isCompatibleWith(NAMESPACE_VERSION)) {
+ return callbacks->createNamespace(name,
+ ld_library_path,
+ default_library_path,
+ type,
+ permitted_when_isolated_path,
+ parent_ns);
+ } else {
+ ALOGE("not compatible with version %d, cannot create namespace %s", NAMESPACE_VERSION, name);
+ }
+ }
+
+ return nullptr;
+}
+
+void* NativeBridgeLoadLibraryExt(const char* libpath, int flag, native_bridge_namespace_t* ns) {
+ if (NativeBridgeInitialized()) {
+ if (isCompatibleWith(NAMESPACE_VERSION)) {
+ return callbacks->loadLibraryExt(libpath, flag, ns);
+ } else {
+ ALOGE("not compatible with version %d, cannot load library in namespace", NAMESPACE_VERSION);
+ }
}
return nullptr;
}
diff --git a/libnativebridge/tests/Android.mk b/libnativebridge/tests/Android.mk
index 7265939..4c3e862 100644
--- a/libnativebridge/tests/Android.mk
+++ b/libnativebridge/tests/Android.mk
@@ -20,7 +20,13 @@
PreInitializeNativeBridgeFail2_test.cpp \
ReSetupNativeBridge_test.cpp \
UnavailableNativeBridge_test.cpp \
- ValidNameNativeBridge_test.cpp
+ ValidNameNativeBridge_test.cpp \
+ NativeBridge3UnloadLibrary_test.cpp \
+ NativeBridge3GetError_test.cpp \
+ NativeBridge3IsPathSupported_test.cpp \
+ NativeBridge3InitNamespace_test.cpp \
+ NativeBridge3CreateNamespace_test.cpp \
+ NativeBridge3LoadLibraryExt_test.cpp
shared_libraries := \
@@ -31,7 +37,6 @@
$(foreach file,$(test_src_files), \
$(eval include $(CLEAR_VARS)) \
$(eval LOCAL_CLANG := true) \
- $(eval LOCAL_CPPFLAGS := -std=gnu++11) \
$(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
$(eval LOCAL_SRC_FILES := $(file)) \
$(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
@@ -41,7 +46,6 @@
$(foreach file,$(test_src_files), \
$(eval include $(CLEAR_VARS)) \
$(eval LOCAL_CLANG := true) \
- $(eval LOCAL_CPPFLAGS := -std=gnu++11) \
$(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
$(eval LOCAL_SRC_FILES := $(file)) \
$(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
diff --git a/libnativebridge/tests/Android.nativebridge-dummy.mk b/libnativebridge/tests/Android.nativebridge-dummy.mk
index 551765a..2d78be0 100644
--- a/libnativebridge/tests/Android.nativebridge-dummy.mk
+++ b/libnativebridge/tests/Android.nativebridge-dummy.mk
@@ -12,7 +12,7 @@
LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
LOCAL_CLANG := true
LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
+LOCAL_CPPFLAGS := -fvisibility=protected
LOCAL_SHARED_LIBRARIES := libdl
LOCAL_MULTILIB := both
@@ -27,7 +27,7 @@
LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
LOCAL_CLANG := true
LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
+LOCAL_CPPFLAGS := -fvisibility=protected
LOCAL_LDFLAGS := -ldl
LOCAL_MULTILIB := both
@@ -48,7 +48,7 @@
LOCAL_SRC_FILES:= $(NATIVE_BRIDGE2_COMMON_SRC_FILES)
LOCAL_CLANG := true
LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
+LOCAL_CPPFLAGS := -fvisibility=protected
LOCAL_SHARED_LIBRARIES := libdl
LOCAL_MULTILIB := both
@@ -63,8 +63,46 @@
LOCAL_SRC_FILES:= $(NATIVE_BRIDGE2_COMMON_SRC_FILES)
LOCAL_CLANG := true
LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CPPFLAGS := -fvisibility=protected
+LOCAL_LDFLAGS := -ldl
+LOCAL_MULTILIB := both
+
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+
+# v3.
+
+NATIVE_BRIDGE3_COMMON_SRC_FILES := \
+ DummyNativeBridge3.cpp
+
+# Shared library for target
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libnativebridge3-dummy
+
+LOCAL_SRC_FILES:= $(NATIVE_BRIDGE3_COMMON_SRC_FILES)
+LOCAL_CLANG := true
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
+LOCAL_LDFLAGS := -ldl
+LOCAL_MULTILIB := both
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Shared library for host
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libnativebridge3-dummy
+
+LOCAL_SRC_FILES:= $(NATIVE_BRIDGE3_COMMON_SRC_FILES)
+LOCAL_CLANG := true
+LOCAL_CFLAGS += -Werror -Wall
LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
LOCAL_LDFLAGS := -ldl
LOCAL_MULTILIB := both
include $(BUILD_HOST_SHARED_LIBRARY)
+
+
diff --git a/libnativebridge/tests/DummyNativeBridge3.cpp b/libnativebridge/tests/DummyNativeBridge3.cpp
new file mode 100644
index 0000000..13fce85
--- /dev/null
+++ b/libnativebridge/tests/DummyNativeBridge3.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// A dummy implementation of the native-bridge interface.
+
+#include "nativebridge/native_bridge.h"
+
+#include <signal.h>
+
+// NativeBridgeCallbacks implementations
+extern "C" bool native_bridge3_initialize(
+ const android::NativeBridgeRuntimeCallbacks* /* art_cbs */,
+ const char* /* app_code_cache_dir */,
+ const char* /* isa */) {
+ return true;
+}
+
+extern "C" void* native_bridge3_loadLibrary(const char* /* libpath */, int /* flag */) {
+ return nullptr;
+}
+
+extern "C" void* native_bridge3_getTrampoline(void* /* handle */, const char* /* name */,
+ const char* /* shorty */, uint32_t /* len */) {
+ return nullptr;
+}
+
+extern "C" bool native_bridge3_isSupported(const char* /* libpath */) {
+ return false;
+}
+
+extern "C" const struct android::NativeBridgeRuntimeValues* native_bridge3_getAppEnv(
+ const char* /* abi */) {
+ return nullptr;
+}
+
+extern "C" bool native_bridge3_isCompatibleWith(uint32_t version) {
+ // For testing, allow 1-3, but disallow 4+.
+ return version <= 3;
+}
+
+static bool native_bridge3_dummy_signal_handler(int, siginfo_t*, void*) {
+ // TODO: Implement something here. We'd either have to have a death test with a log here, or
+ // we'd have to be able to resume after the faulting instruction...
+ return true;
+}
+
+extern "C" android::NativeBridgeSignalHandlerFn native_bridge3_getSignalHandler(int signal) {
+ if (signal == SIGSEGV) {
+ return &native_bridge3_dummy_signal_handler;
+ }
+ return nullptr;
+}
+
+extern "C" int native_bridge3_unloadLibrary(void* /* handle */) {
+ return 0;
+}
+
+extern "C" const char* native_bridge3_getError() {
+ return nullptr;
+}
+
+extern "C" bool native_bridge3_isPathSupported(const char* /* path */) {
+ return true;
+}
+
+extern "C" bool native_bridge3_initNamespace(const char* /* public_ns_sonames */,
+ const char* /* anon_ns_library_path */) {
+ return true;
+}
+
+extern "C" android::native_bridge_namespace_t*
+native_bridge3_createNamespace(const char* /* name */,
+ const char* /* ld_library_path */,
+ const char* /* default_library_path */,
+ uint64_t /* type */,
+ const char* /* permitted_when_isolated_path */,
+ android::native_bridge_namespace_t* /* parent_ns */) {
+ return nullptr;
+}
+
+extern "C" void* native_bridge3_loadLibraryExt(const char* /* libpath */,
+ int /* flag */,
+ android::native_bridge_namespace_t* /* ns */) {
+ return nullptr;
+}
+
+
+android::NativeBridgeCallbacks NativeBridgeItf {
+ // v1
+ .version = 3,
+ .initialize = &native_bridge3_initialize,
+ .loadLibrary = &native_bridge3_loadLibrary,
+ .getTrampoline = &native_bridge3_getTrampoline,
+ .isSupported = &native_bridge3_isSupported,
+ .getAppEnv = &native_bridge3_getAppEnv,
+ // v2
+ .isCompatibleWith = &native_bridge3_isCompatibleWith,
+ .getSignalHandler = &native_bridge3_getSignalHandler,
+ // v3
+ .unloadLibrary = &native_bridge3_unloadLibrary,
+ .getError = &native_bridge3_getError,
+ .isPathSupported = &native_bridge3_isPathSupported,
+ .initNamespace = &native_bridge3_initNamespace,
+ .createNamespace = &native_bridge3_createNamespace,
+ .loadLibraryExt = &native_bridge3_loadLibraryExt
+};
+
diff --git a/libnativebridge/tests/NativeBridge3CreateNamespace_test.cpp b/libnativebridge/tests/NativeBridge3CreateNamespace_test.cpp
new file mode 100644
index 0000000..668d942
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3CreateNamespace_test.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_CreateNamespace) {
+ // Init
+ ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+
+ ASSERT_EQ(3U, NativeBridgeGetVersion());
+ ASSERT_EQ(nullptr, NativeBridgeCreateNamespace(nullptr, nullptr, nullptr,
+ 0, nullptr, nullptr));
+
+ // Clean-up code_cache
+ ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/NativeBridge3GetError_test.cpp b/libnativebridge/tests/NativeBridge3GetError_test.cpp
new file mode 100644
index 0000000..0b9f582
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3GetError_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_GetError) {
+ // Init
+ ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+
+ ASSERT_EQ(3U, NativeBridgeGetVersion());
+ ASSERT_EQ(nullptr, NativeBridgeGetError());
+
+ // Clean-up code_cache
+ ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/NativeBridge3InitNamespace_test.cpp b/libnativebridge/tests/NativeBridge3InitNamespace_test.cpp
new file mode 100644
index 0000000..ae0fd2b
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3InitNamespace_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_InitNamespace) {
+ // Init
+ ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+
+ ASSERT_EQ(3U, NativeBridgeGetVersion());
+ ASSERT_EQ(true, NativeBridgeInitNamespace(nullptr, nullptr));
+
+ // Clean-up code_cache
+ ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/NativeBridge3IsPathSupported_test.cpp b/libnativebridge/tests/NativeBridge3IsPathSupported_test.cpp
new file mode 100644
index 0000000..325e40b
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3IsPathSupported_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_IsPathSupported) {
+ // Init
+ ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+
+ ASSERT_EQ(3U, NativeBridgeGetVersion());
+ ASSERT_EQ(true, NativeBridgeIsPathSupported(nullptr));
+
+ // Clean-up code_cache
+ ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/NativeBridge3LoadLibraryExt_test.cpp b/libnativebridge/tests/NativeBridge3LoadLibraryExt_test.cpp
new file mode 100644
index 0000000..4caeb44
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3LoadLibraryExt_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_LoadLibraryExt) {
+ // Init
+ ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+
+ ASSERT_EQ(3U, NativeBridgeGetVersion());
+ ASSERT_EQ(nullptr, NativeBridgeLoadLibraryExt(nullptr, 0, nullptr));
+
+ // Clean-up code_cache
+ ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/NativeBridge3UnloadLibrary_test.cpp b/libnativebridge/tests/NativeBridge3UnloadLibrary_test.cpp
new file mode 100644
index 0000000..93a979c
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3UnloadLibrary_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_UnloadLibrary) {
+ // Init
+ ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+
+ ASSERT_EQ(3U, NativeBridgeGetVersion());
+ ASSERT_EQ(0, NativeBridgeUnloadLibrary(nullptr));
+
+ // Clean-up code_cache
+ ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/NativeBridgeTest.h b/libnativebridge/tests/NativeBridgeTest.h
index d489420..0f99816 100644
--- a/libnativebridge/tests/NativeBridgeTest.h
+++ b/libnativebridge/tests/NativeBridgeTest.h
@@ -25,6 +25,8 @@
constexpr const char* kNativeBridgeLibrary = "libnativebridge-dummy.so";
constexpr const char* kCodeCache = "./code_cache";
constexpr const char* kCodeCacheStatFail = "./code_cache/temp";
+constexpr const char* kNativeBridgeLibrary2 = "libnativebridge2-dummy.so";
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
namespace android {
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp
index b4a69bc..9d33899 100644
--- a/libnativeloader/Android.bp
+++ b/libnativeloader/Android.bp
@@ -8,6 +8,7 @@
"libnativehelper",
"liblog",
"libcutils",
+ "libnativebridge",
],
static_libs: ["libbase"],
target: {
@@ -24,7 +25,6 @@
"-Wall",
],
cppflags: [
- "-std=gnu++14",
"-fvisibility=hidden",
],
export_include_dirs: ["include"],
diff --git a/libnativeloader/include/nativeloader/native_loader.h b/libnativeloader/include/nativeloader/native_loader.h
index 2a6aaec..99ae3a7 100644
--- a/libnativeloader/include/nativeloader/native_loader.h
+++ b/libnativeloader/include/nativeloader/native_loader.h
@@ -19,6 +19,7 @@
#include "jni.h"
#include <stdint.h>
+#include <string>
#if defined(__ANDROID__)
#include <android/dlext.h>
#endif
@@ -41,10 +42,12 @@
int32_t target_sdk_version,
const char* path,
jobject class_loader,
- jstring library_path);
+ jstring library_path,
+ bool* needs_native_bridge,
+ std::string* error_msg);
__attribute__((visibility("default")))
-bool CloseNativeLibrary(void* handle);
+bool CloseNativeLibrary(void* handle, const bool needs_native_bridge);
#if defined(__ANDROID__)
// Look up linker namespace by class_loader. Returns nullptr if
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 3a6e54d..15fe054 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -24,6 +24,7 @@
#include "android/log.h"
#include "cutils/properties.h"
#endif
+#include "nativebridge/native_bridge.h"
#include <algorithm>
#include <vector>
@@ -34,11 +35,53 @@
#include <android-base/macros.h>
#include <android-base/strings.h>
+#define CHECK(predicate) LOG_ALWAYS_FATAL_IF(!(predicate),\
+ "%s:%d: %s CHECK '" #predicate "' failed.",\
+ __FILE__, __LINE__, __FUNCTION__)
+
namespace android {
#if defined(__ANDROID__)
-static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot = "/etc/public.libraries.txt";
-static constexpr const char* kPublicNativeLibrariesVendorConfig = "/vendor/etc/public.libraries.txt";
+class NativeLoaderNamespace {
+ public:
+ NativeLoaderNamespace()
+ : android_ns_(nullptr), native_bridge_ns_(nullptr) { }
+
+ explicit NativeLoaderNamespace(android_namespace_t* ns)
+ : android_ns_(ns), native_bridge_ns_(nullptr) { }
+
+ explicit NativeLoaderNamespace(native_bridge_namespace_t* ns)
+ : android_ns_(nullptr), native_bridge_ns_(ns) { }
+
+ NativeLoaderNamespace(NativeLoaderNamespace&& that) = default;
+ NativeLoaderNamespace(const NativeLoaderNamespace& that) = default;
+
+ NativeLoaderNamespace& operator=(const NativeLoaderNamespace& that) = default;
+
+ android_namespace_t* get_android_ns() const {
+ CHECK(native_bridge_ns_ == nullptr);
+ return android_ns_;
+ }
+
+ native_bridge_namespace_t* get_native_bridge_ns() const {
+ CHECK(android_ns_ == nullptr);
+ return native_bridge_ns_;
+ }
+
+ bool is_android_namespace() const {
+ return native_bridge_ns_ == nullptr;
+ }
+
+ private:
+ // Only one of them can be not null
+ android_namespace_t* android_ns_;
+ native_bridge_namespace_t* native_bridge_ns_;
+};
+
+static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot =
+ "/etc/public.libraries.txt";
+static constexpr const char* kPublicNativeLibrariesVendorConfig =
+ "/vendor/etc/public.libraries.txt";
// (http://b/27588281) This is a workaround for apps using custom classloaders and calling
// System.load() with an absolute path which is outside of the classloader library search path.
@@ -55,11 +98,13 @@
public:
LibraryNamespaces() : initialized_(false) { }
- android_namespace_t* Create(JNIEnv* env,
- jobject class_loader,
- bool is_shared,
- jstring java_library_path,
- jstring java_permitted_path) {
+ bool Create(JNIEnv* env,
+ jobject class_loader,
+ bool is_shared,
+ jstring java_library_path,
+ jstring java_permitted_path,
+ NativeLoaderNamespace* ns,
+ std::string* error_msg) {
std::string library_path; // empty string by default.
if (java_library_path != nullptr) {
@@ -82,13 +127,13 @@
}
}
- if (!initialized_ && !InitPublicNamespace(library_path.c_str())) {
- return nullptr;
+ if (!initialized_ && !InitPublicNamespace(library_path.c_str(), error_msg)) {
+ return false;
}
- android_namespace_t* ns = FindNamespaceByClassLoader(env, class_loader);
+ bool found = FindNamespaceByClassLoader(env, class_loader, nullptr);
- LOG_ALWAYS_FATAL_IF(ns != nullptr,
+ LOG_ALWAYS_FATAL_IF(found,
"There is already a namespace associated with this classloader");
uint64_t namespace_type = ANDROID_NAMESPACE_TYPE_ISOLATED;
@@ -96,28 +141,66 @@
namespace_type |= ANDROID_NAMESPACE_TYPE_SHARED;
}
- android_namespace_t* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
+ NativeLoaderNamespace parent_ns;
+ bool found_parent_namespace = FindParentNamespaceByClassLoader(env, class_loader, &parent_ns);
- ns = android_create_namespace("classloader-namespace",
- nullptr,
- library_path.c_str(),
- namespace_type,
- permitted_path.c_str(),
- parent_ns);
+ bool is_native_bridge = false;
- if (ns != nullptr) {
- namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), ns));
+ if (found_parent_namespace) {
+ is_native_bridge = !parent_ns.is_android_namespace();
+ } else if (!library_path.empty()) {
+ is_native_bridge = NativeBridgeIsPathSupported(library_path.c_str());
}
- return ns;
+ NativeLoaderNamespace native_loader_ns;
+ if (!is_native_bridge) {
+ android_namespace_t* ns = android_create_namespace("classloader-namespace",
+ nullptr,
+ library_path.c_str(),
+ namespace_type,
+ permitted_path.c_str(),
+ parent_ns.get_android_ns());
+ if (ns == nullptr) {
+ *error_msg = dlerror();
+ return false;
+ }
+
+ native_loader_ns = NativeLoaderNamespace(ns);
+ } else {
+ native_bridge_namespace_t* ns = NativeBridgeCreateNamespace("classloader-namespace",
+ nullptr,
+ library_path.c_str(),
+ namespace_type,
+ permitted_path.c_str(),
+ parent_ns.get_native_bridge_ns());
+ if (ns == nullptr) {
+ *error_msg = NativeBridgeGetError();
+ return false;
+ }
+
+ native_loader_ns = NativeLoaderNamespace(ns);
+ }
+
+ namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), native_loader_ns));
+
+ *ns = native_loader_ns;
+ return true;
}
- android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
+ bool FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader, NativeLoaderNamespace* ns) {
auto it = std::find_if(namespaces_.begin(), namespaces_.end(),
- [&](const std::pair<jweak, android_namespace_t*>& value) {
+ [&](const std::pair<jweak, NativeLoaderNamespace>& value) {
return env->IsSameObject(value.first, class_loader);
});
- return it != namespaces_.end() ? it->second : nullptr;
+ if (it != namespaces_.end()) {
+ if (ns != nullptr) {
+ *ns = it->second;
+ }
+
+ return true;
+ }
+
+ return false;
}
void Initialize() {
@@ -217,12 +300,29 @@
return true;
}
- bool InitPublicNamespace(const char* library_path) {
+ bool InitPublicNamespace(const char* library_path, std::string* error_msg) {
+ // Ask native bride if this apps library path should be handled by it
+ bool is_native_bridge = NativeBridgeIsPathSupported(library_path);
+
// (http://b/25844435) - Some apps call dlopen from generated code (mono jited
// code is one example) unknown to linker in which case linker uses anonymous
// namespace. The second argument specifies the search path for the anonymous
// namespace which is the library_path of the classloader.
- initialized_ = android_init_namespaces(public_libraries_.c_str(), library_path);
+ initialized_ = android_init_namespaces(public_libraries_.c_str(),
+ is_native_bridge ? nullptr : library_path);
+ if (!initialized_) {
+ *error_msg = dlerror();
+ return false;
+ }
+
+ // and now initialize native bridge namespaces if necessary.
+ if (NativeBridgeInitialized()) {
+ initialized_ = NativeBridgeInitNamespace(public_libraries_.c_str(),
+ is_native_bridge ? library_path : nullptr);
+ if (!initialized_) {
+ *error_msg = NativeBridgeGetError();
+ }
+ }
return initialized_;
}
@@ -236,22 +336,24 @@
return env->CallObjectMethod(class_loader, get_parent);
}
- android_namespace_t* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
+ bool FindParentNamespaceByClassLoader(JNIEnv* env,
+ jobject class_loader,
+ NativeLoaderNamespace* ns) {
jobject parent_class_loader = GetParentClassLoader(env, class_loader);
while (parent_class_loader != nullptr) {
- android_namespace_t* ns = FindNamespaceByClassLoader(env, parent_class_loader);
- if (ns != nullptr) {
- return ns;
+ if (FindNamespaceByClassLoader(env, parent_class_loader, ns)) {
+ return true;
}
parent_class_loader = GetParentClassLoader(env, parent_class_loader);
}
- return nullptr;
+
+ return false;
}
bool initialized_;
- std::vector<std::pair<jweak, android_namespace_t*>> namespaces_;
+ std::vector<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
std::string public_libraries_;
@@ -285,13 +387,18 @@
#if defined(__ANDROID__)
UNUSED(target_sdk_version);
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
- android_namespace_t* ns = g_namespaces->Create(env,
- class_loader,
- is_shared,
- library_path,
- permitted_path);
- if (ns == nullptr) {
- return env->NewStringUTF(dlerror());
+
+ std::string error_msg;
+ NativeLoaderNamespace ns;
+ bool success = g_namespaces->Create(env,
+ class_loader,
+ is_shared,
+ library_path,
+ permitted_path,
+ &ns,
+ &error_msg);
+ if (!success) {
+ return env->NewStringUTF(error_msg.c_str());
}
#else
UNUSED(env, target_sdk_version, class_loader, is_shared,
@@ -304,44 +411,83 @@
int32_t target_sdk_version,
const char* path,
jobject class_loader,
- jstring library_path) {
+ jstring library_path,
+ bool* needs_native_bridge,
+ std::string* error_msg) {
#if defined(__ANDROID__)
UNUSED(target_sdk_version);
if (class_loader == nullptr) {
+ *needs_native_bridge = false;
return dlopen(path, RTLD_NOW);
}
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
- android_namespace_t* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader);
+ NativeLoaderNamespace ns;
- if (ns == nullptr) {
+ if (!g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
// This is the case where the classloader was not created by ApplicationLoaders
// In this case we create an isolated not-shared namespace for it.
- ns = g_namespaces->Create(env, class_loader, false, library_path, nullptr);
- if (ns == nullptr) {
+ if (!g_namespaces->Create(env, class_loader, false, library_path, nullptr, &ns, error_msg)) {
return nullptr;
}
}
- android_dlextinfo extinfo;
- extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
- extinfo.library_namespace = ns;
+ if (ns.is_android_namespace()) {
+ android_dlextinfo extinfo;
+ extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+ extinfo.library_namespace = ns.get_android_ns();
- return android_dlopen_ext(path, RTLD_NOW, &extinfo);
+ void* handle = android_dlopen_ext(path, RTLD_NOW, &extinfo);
+ if (handle == nullptr) {
+ *error_msg = dlerror();
+ }
+ *needs_native_bridge = false;
+ return handle;
+ } else {
+ void* handle = NativeBridgeLoadLibraryExt(path, RTLD_NOW, ns.get_native_bridge_ns());
+ if (handle == nullptr) {
+ *error_msg = NativeBridgeGetError();
+ }
+ *needs_native_bridge = true;
+ return handle;
+ }
#else
UNUSED(env, target_sdk_version, class_loader, library_path);
- return dlopen(path, RTLD_NOW);
+ *needs_native_bridge = false;
+ void* handle = dlopen(path, RTLD_NOW);
+ if (handle == nullptr) {
+ if (NativeBridgeIsSupported(path)) {
+ *needs_native_bridge = true;
+ handle = NativeBridgeLoadLibrary(path, RTLD_NOW);
+ if (handle == nullptr) {
+ *error_msg = NativeBridgeGetError();
+ }
+ } else {
+ *needs_native_bridge = false;
+ *error_msg = dlerror();
+ }
+ }
+ return handle;
#endif
}
-bool CloseNativeLibrary(void* handle) {
- return dlclose(handle) == 0;
+bool CloseNativeLibrary(void* handle, const bool needs_native_bridge) {
+ return needs_native_bridge ? NativeBridgeUnloadLibrary(handle) :
+ dlclose(handle);
}
#if defined(__ANDROID__)
+// native_bridge_namespaces are not supported for callers of this function.
+// This function will return nullptr in the case when application is running
+// on native bridge.
android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
- return g_namespaces->FindNamespaceByClassLoader(env, class_loader);
+ NativeLoaderNamespace ns;
+ if (g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
+ return ns.is_android_namespace() ? ns.get_android_ns() : nullptr;
+ }
+
+ return nullptr;
}
#endif
diff --git a/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp b/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp
index 67eba80..e212f1b 100644
--- a/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp
+++ b/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp
@@ -14,6 +14,7 @@
** See the License for the specific language governing permissions and
** limitations under the License.
*/
+#define LOG_TAG "pixelflinger-code"
#include <errno.h>
#include <stdint.h>
diff --git a/libpixelflinger/codeflinger/blending.cpp b/libpixelflinger/codeflinger/blending.cpp
index d4aa475..092f140 100644
--- a/libpixelflinger/codeflinger/blending.cpp
+++ b/libpixelflinger/codeflinger/blending.cpp
@@ -15,6 +15,8 @@
** limitations under the License.
*/
+#define LOG_TAG "pixelflinger-code"
+
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
diff --git a/libpixelflinger/codeflinger/load_store.cpp b/libpixelflinger/codeflinger/load_store.cpp
index d68f6dc..b8a0e55 100644
--- a/libpixelflinger/codeflinger/load_store.cpp
+++ b/libpixelflinger/codeflinger/load_store.cpp
@@ -15,6 +15,8 @@
** limitations under the License.
*/
+#define LOG_TAG "pixelflinger-code"
+
#include <assert.h>
#include <stdio.h>
diff --git a/libpixelflinger/codeflinger/texturing.cpp b/libpixelflinger/codeflinger/texturing.cpp
index d66981d..f4f4657 100644
--- a/libpixelflinger/codeflinger/texturing.cpp
+++ b/libpixelflinger/codeflinger/texturing.cpp
@@ -15,6 +15,8 @@
** limitations under the License.
*/
+#define LOG_TAG "pixelflinger-code"
+
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
diff --git a/libpixelflinger/trap.cpp b/libpixelflinger/trap.cpp
index f00e50a..fa6338a 100644
--- a/libpixelflinger/trap.cpp
+++ b/libpixelflinger/trap.cpp
@@ -15,6 +15,8 @@
** limitations under the License.
*/
+#define LOG_TAG "pixelflinger-trap"
+
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/libsync/Android.bp b/libsync/Android.bp
index 4948aa5..a4e5599 100644
--- a/libsync/Android.bp
+++ b/libsync/Android.bp
@@ -34,7 +34,6 @@
"-g",
"-Wall",
"-Werror",
- "-std=gnu++11",
"-Wno-missing-field-initializers",
"-Wno-sign-compare",
],
diff --git a/libsysutils/src/FrameworkCommand.cpp b/libsysutils/src/FrameworkCommand.cpp
index dccacda..a6c4abc 100644
--- a/libsysutils/src/FrameworkCommand.cpp
+++ b/libsysutils/src/FrameworkCommand.cpp
@@ -18,7 +18,7 @@
#include <errno.h>
-#include <android/log.h>
+#include <log/log.h>
#include <sysutils/FrameworkCommand.h>
#define UNUSED __attribute__((unused))
diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp
index b96174a..52f28af 100644
--- a/libsysutils/src/FrameworkListener.cpp
+++ b/libsysutils/src/FrameworkListener.cpp
@@ -19,8 +19,9 @@
#include <errno.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
-#include <android/log.h>
+#include <log/log.h>
#include <sysutils/FrameworkCommand.h>
#include <sysutils/FrameworkListener.h>
#include <sysutils/SocketClient.h>
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index b787692..fef801a 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -41,7 +41,7 @@
const int LOCAL_QLOG_NL_EVENT = 112;
const int LOCAL_NFLOG_PACKET = NFNL_SUBSYS_ULOG << 8 | NFULNL_MSG_PACKET;
-#include <android/log.h>
+#include <log/log.h>
#include <sysutils/NetlinkEvent.h>
NetlinkEvent::NetlinkEvent() {
diff --git a/libsysutils/src/NetlinkListener.cpp b/libsysutils/src/NetlinkListener.cpp
index 1c4c7df..896dad3 100644
--- a/libsysutils/src/NetlinkListener.cpp
+++ b/libsysutils/src/NetlinkListener.cpp
@@ -20,11 +20,12 @@
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
+#include <unistd.h>
#include <linux/netlink.h> /* out of order because must follow sys/socket.h */
-#include <android/log.h>
#include <cutils/uevent.h>
+#include <log/log.h>
#include <sysutils/NetlinkEvent.h>
#if 1
diff --git a/libsysutils/src/ServiceManager.cpp b/libsysutils/src/ServiceManager.cpp
index 1abe988..13bac09 100644
--- a/libsysutils/src/ServiceManager.cpp
+++ b/libsysutils/src/ServiceManager.cpp
@@ -17,10 +17,12 @@
#define LOG_TAG "Service"
#include <errno.h>
+#include <stdio.h>
#include <string.h>
+#include <unistd.h>
-#include <android/log.h>
#include <cutils/properties.h>
+#include <log/log.h>
#include <sysutils/ServiceManager.h>
ServiceManager::ServiceManager() {
diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp
index 02505d3..971f908 100644
--- a/libsysutils/src/SocketClient.cpp
+++ b/libsysutils/src/SocketClient.cpp
@@ -25,8 +25,9 @@
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
+#include <unistd.h>
-#include <android/log.h>
+#include <log/log.h>
#include <sysutils/SocketClient.h>
SocketClient::SocketClient(int socket, bool owned) {
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index 6a676a9..3f8f3db 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -24,9 +24,10 @@
#include <sys/time.h>
#include <sys/types.h>
#include <sys/un.h>
+#include <unistd.h>
-#include <android/log.h>
#include <cutils/sockets.h>
+#include <log/log.h>
#include <sysutils/SocketListener.h>
#include <sysutils/SocketClient.h>
diff --git a/libutils/SharedBuffer.cpp b/libutils/SharedBuffer.cpp
index 2b3690c..269326a 100644
--- a/libutils/SharedBuffer.cpp
+++ b/libutils/SharedBuffer.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "sharedbuffer"
+
#include <stdlib.h>
#include <string.h>
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index 0652101..c32f462 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "unicode"
+
#include <limits.h>
#include <stddef.h>
diff --git a/libziparchive/testdata/dummy-update.zip b/libziparchive/testdata/dummy-update.zip
new file mode 100644
index 0000000..6976bf1
--- /dev/null
+++ b/libziparchive/testdata/dummy-update.zip
Binary files differ
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index cc3f0e4..d36cc3f 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -18,6 +18,8 @@
* Read-only access to Zip archives, with minimal heap allocation.
*/
+#define LOG_TAG "ziparchive"
+
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
@@ -30,11 +32,11 @@
#include <memory>
#include <vector>
-#include <android/log.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/macros.h> // TEMP_FAILURE_RETRY may or may not be in unistd
#include <android-base/memory.h>
+#include <log/log.h>
#include <utils/Compat.h>
#include <utils/FileMap.h>
#include "ziparchive/zip_archive.h"
@@ -215,19 +217,14 @@
return 0;
}
-static int32_t MapCentralDirectory0(int fd, const char* debug_file_name,
- ZipArchive* archive, off64_t file_length,
- off64_t read_amount, uint8_t* scan_buffer) {
+static int32_t MapCentralDirectory0(const char* debug_file_name, ZipArchive* archive,
+ off64_t file_length, off64_t read_amount,
+ uint8_t* scan_buffer) {
const off64_t search_start = file_length - read_amount;
- if (lseek64(fd, search_start, SEEK_SET) != search_start) {
- ALOGW("Zip: seek %" PRId64 " failed: %s", static_cast<int64_t>(search_start),
- strerror(errno));
- return kIoError;
- }
- if (!android::base::ReadFully(fd, scan_buffer, static_cast<size_t>(read_amount))) {
- ALOGW("Zip: read %" PRId64 " failed: %s", static_cast<int64_t>(read_amount),
- strerror(errno));
+ if(!archive->mapped_zip.ReadAtOffset(scan_buffer, read_amount, search_start)) {
+ ALOGE("Zip: read %" PRId64 " from offset %" PRId64 " failed",
+ static_cast<int64_t>(read_amount), static_cast<int64_t>(search_start));
return kIoError;
}
@@ -287,9 +284,11 @@
* It all looks good. Create a mapping for the CD, and set the fields
* in archive.
*/
- if (!archive->directory_map.create(debug_file_name, fd,
- static_cast<off64_t>(eocd->cd_start_offset),
- static_cast<size_t>(eocd->cd_size), true /* read only */) ) {
+
+ if (!archive->InitializeCentralDirectory(debug_file_name,
+ static_cast<off64_t>(eocd->cd_start_offset),
+ static_cast<size_t>(eocd->cd_size))) {
+ ALOGE("Zip: failed to intialize central directory.\n");
return kMmapFailed;
}
@@ -304,18 +303,16 @@
*
* On success, returns 0 after populating fields from the EOCD area:
* directory_offset
- * directory_map
+ * directory_ptr
* num_entries
*/
-static int32_t MapCentralDirectory(int fd, const char* debug_file_name,
- ZipArchive* archive) {
+static int32_t MapCentralDirectory(const char* debug_file_name, ZipArchive* archive) {
// Test file length. We use lseek64 to make sure the file
// is small enough to be a zip file (Its size must be less than
// 0xffffffff bytes).
- off64_t file_length = lseek64(fd, 0, SEEK_END);
+ off64_t file_length = archive->mapped_zip.GetFileLength();
if (file_length == -1) {
- ALOGV("Zip: lseek on fd %d failed", fd);
return kInvalidFile;
}
@@ -346,11 +343,9 @@
read_amount = file_length;
}
- uint8_t* scan_buffer = reinterpret_cast<uint8_t*>(malloc(read_amount));
- int32_t result = MapCentralDirectory0(fd, debug_file_name, archive,
- file_length, read_amount, scan_buffer);
-
- free(scan_buffer);
+ std::vector<uint8_t> scan_buffer(read_amount);
+ int32_t result = MapCentralDirectory0(debug_file_name, archive, file_length, read_amount,
+ scan_buffer.data());
return result;
}
@@ -361,9 +356,8 @@
* Returns 0 on success.
*/
static int32_t ParseZipArchive(ZipArchive* archive) {
- const uint8_t* const cd_ptr =
- reinterpret_cast<const uint8_t*>(archive->directory_map.getDataPtr());
- const size_t cd_length = archive->directory_map.getDataLength();
+ const uint8_t* const cd_ptr = archive->central_directory.GetBasePtr();
+ const size_t cd_length = archive->central_directory.GetMapLength();
const uint16_t num_entries = archive->num_entries;
/*
@@ -437,7 +431,7 @@
static int32_t OpenArchiveInternal(ZipArchive* archive,
const char* debug_file_name) {
int32_t result = -1;
- if ((result = MapCentralDirectory(archive->fd, debug_file_name, archive))) {
+ if ((result = MapCentralDirectory(debug_file_name, archive)) != 0) {
return result;
}
@@ -468,6 +462,13 @@
return OpenArchiveInternal(archive, fileName);
}
+int32_t OpenArchiveFromMemory(void* address, size_t length, const char* debug_file_name,
+ ZipArchiveHandle *handle) {
+ ZipArchive* archive = new ZipArchive(address, length);
+ *handle = archive;
+ return OpenArchiveInternal(archive, debug_file_name);
+}
+
/*
* Close a ZipArchive, closing the file and freeing the contents.
*/
@@ -477,10 +478,10 @@
delete archive;
}
-static int32_t UpdateEntryFromDataDescriptor(int fd,
+static int32_t UpdateEntryFromDataDescriptor(MappedZipFile& mapped_zip,
ZipEntry *entry) {
uint8_t ddBuf[sizeof(DataDescriptor) + sizeof(DataDescriptor::kOptSignature)];
- if (!android::base::ReadFully(fd, ddBuf, sizeof(ddBuf))) {
+ if (!mapped_zip.ReadData(ddBuf, sizeof(ddBuf))) {
return kIoError;
}
@@ -495,23 +496,6 @@
return 0;
}
-// Attempts to read |len| bytes into |buf| at offset |off|.
-// On non-Windows platforms, callers are guaranteed that the |fd|
-// offset is unchanged and there is no side effect to this call.
-//
-// On Windows platforms this is not thread-safe.
-static inline bool ReadAtOffset(int fd, uint8_t* buf, size_t len, off64_t off) {
-#if !defined(_WIN32)
- return TEMP_FAILURE_RETRY(pread64(fd, buf, len, off));
-#else
- if (lseek64(fd, off, SEEK_SET) != off) {
- ALOGW("Zip: failed seek to offset %" PRId64, off);
- return false;
- }
- return android::base::ReadFully(fd, buf, len);
-#endif
-}
-
static int32_t FindEntry(const ZipArchive* archive, const int ent,
ZipEntry* data) {
const uint16_t nameLen = archive->hash_table[ent].name_length;
@@ -525,9 +509,8 @@
// This is the base of our mmapped region, we have to sanity check that
// the name that's in the hash table is a pointer to a location within
// this mapped region.
- const uint8_t* base_ptr = reinterpret_cast<const uint8_t*>(
- archive->directory_map.getDataPtr());
- if (ptr < base_ptr || ptr > base_ptr + archive->directory_map.getDataLength()) {
+ const uint8_t* base_ptr = archive->central_directory.GetBasePtr();
+ if (ptr < base_ptr || ptr > base_ptr + archive->central_directory.GetMapLength()) {
ALOGW("Zip: Invalid entry pointer");
return kInvalidOffset;
}
@@ -559,7 +542,7 @@
}
uint8_t lfh_buf[sizeof(LocalFileHeader)];
- if (!ReadAtOffset(archive->fd, lfh_buf, sizeof(lfh_buf), local_header_offset)) {
+ if (!archive->mapped_zip.ReadAtOffset(lfh_buf, sizeof(lfh_buf), local_header_offset)) {
ALOGW("Zip: failed reading lfh name from offset %" PRId64,
static_cast<int64_t>(local_header_offset));
return kIoError;
@@ -599,19 +582,16 @@
return kInvalidOffset;
}
- uint8_t* name_buf = reinterpret_cast<uint8_t*>(malloc(nameLen));
- if (!ReadAtOffset(archive->fd, name_buf, nameLen, name_offset)) {
+ std::vector<uint8_t> name_buf(nameLen);
+ if (!archive->mapped_zip.ReadAtOffset(name_buf.data(), nameLen, name_offset)) {
ALOGW("Zip: failed reading lfh name from offset %" PRId64, static_cast<int64_t>(name_offset));
- free(name_buf);
return kIoError;
}
- if (memcmp(archive->hash_table[ent].name, name_buf, nameLen)) {
- free(name_buf);
+ if (memcmp(archive->hash_table[ent].name, name_buf.data(), nameLen)) {
return kInconsistentInformation;
}
- free(name_buf);
} else {
ALOGW("Zip: lfh name did not match central directory.");
return kInconsistentInformation;
@@ -881,7 +861,7 @@
}
#pragma GCC diagnostic pop
-static int32_t InflateEntryToWriter(int fd, const ZipEntry* entry,
+static int32_t InflateEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry,
Writer* writer, uint64_t* crc_out) {
const size_t kBufSize = 32768;
std::vector<uint8_t> read_buf(kBufSize);
@@ -931,7 +911,7 @@
/* read as much as we can */
if (zstream.avail_in == 0) {
const size_t getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
- if (!android::base::ReadFully(fd, read_buf.data(), getSize)) {
+ if (!mapped_zip.ReadData(read_buf.data(), getSize)) {
ALOGW("Zip: inflate read failed, getSize = %zu: %s", getSize, strerror(errno));
return kIoError;
}
@@ -979,7 +959,7 @@
return 0;
}
-static int32_t CopyEntryToWriter(int fd, const ZipEntry* entry, Writer* writer,
+static int32_t CopyEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry, Writer* writer,
uint64_t *crc_out) {
static const uint32_t kBufSize = 32768;
std::vector<uint8_t> buf(kBufSize);
@@ -993,7 +973,7 @@
// Safe conversion because kBufSize is narrow enough for a 32 bit signed
// value.
const size_t block_size = (remaining > kBufSize) ? kBufSize : remaining;
- if (!android::base::ReadFully(fd, buf.data(), block_size)) {
+ if (!mapped_zip.ReadData(buf.data(), block_size)) {
ALOGW("CopyFileToFile: copy read failed, block_size = %zu: %s", block_size, strerror(errno));
return kIoError;
}
@@ -1016,7 +996,7 @@
const uint16_t method = entry->method;
off64_t data_offset = entry->offset;
- if (lseek64(archive->fd, data_offset, SEEK_SET) != data_offset) {
+ if (!archive->mapped_zip.SeekToOffset(data_offset)) {
ALOGW("Zip: lseek to data at %" PRId64 " failed", static_cast<int64_t>(data_offset));
return kIoError;
}
@@ -1025,13 +1005,13 @@
int32_t return_value = -1;
uint64_t crc = 0;
if (method == kCompressStored) {
- return_value = CopyEntryToWriter(archive->fd, entry, writer, &crc);
+ return_value = CopyEntryToWriter(archive->mapped_zip, entry, writer, &crc);
} else if (method == kCompressDeflated) {
- return_value = InflateEntryToWriter(archive->fd, entry, writer, &crc);
+ return_value = InflateEntryToWriter(archive->mapped_zip, entry, writer, &crc);
}
if (!return_value && entry->has_data_descriptor) {
- return_value = UpdateEntryFromDataDescriptor(archive->fd, entry);
+ return_value = UpdateEntryFromDataDescriptor(archive->mapped_zip, entry);
if (return_value) {
return return_value;
}
@@ -1072,7 +1052,7 @@
}
int GetFileDescriptor(const ZipArchiveHandle handle) {
- return reinterpret_cast<ZipArchive*>(handle)->fd;
+ return reinterpret_cast<ZipArchive*>(handle)->mapped_zip.GetFileDescriptor();
}
ZipString::ZipString(const char* entry_name)
@@ -1081,3 +1061,143 @@
CHECK_LE(len, static_cast<size_t>(UINT16_MAX));
name_length = static_cast<uint16_t>(len);
}
+
+#if !defined(_WIN32)
+class ProcessWriter : public Writer {
+ public:
+ ProcessWriter(ProcessZipEntryFunction func, void* cookie) : Writer(),
+ proc_function_(func),
+ cookie_(cookie) {
+ }
+
+ virtual bool Append(uint8_t* buf, size_t buf_size) override {
+ return proc_function_(buf, buf_size, cookie_);
+ }
+
+ private:
+ ProcessZipEntryFunction proc_function_;
+ void* cookie_;
+};
+
+int32_t ProcessZipEntryContents(ZipArchiveHandle handle, ZipEntry* entry,
+ ProcessZipEntryFunction func, void* cookie) {
+ ProcessWriter writer(func, cookie);
+ return ExtractToWriter(handle, entry, &writer);
+}
+
+#endif //!defined(_WIN32)
+
+int MappedZipFile::GetFileDescriptor() const {
+ if (!has_fd_) {
+ ALOGW("Zip: MappedZipFile doesn't have a file descriptor.");
+ return -1;
+ }
+ return fd_;
+}
+
+void* MappedZipFile::GetBasePtr() const {
+ if (has_fd_) {
+ ALOGW("Zip: MappedZipFile doesn't have a base pointer.");
+ return nullptr;
+ }
+ return base_ptr_;
+}
+
+off64_t MappedZipFile::GetFileLength() const {
+ if (has_fd_) {
+ off64_t result = lseek64(fd_, 0, SEEK_END);
+ if (result == -1) {
+ ALOGE("Zip: lseek on fd %d failed: %s", fd_, strerror(errno));
+ }
+ return result;
+ } else {
+ if (base_ptr_ == nullptr) {
+ ALOGE("Zip: invalid file map\n");
+ return -1;
+ }
+ return static_cast<off64_t>(data_length_);
+ }
+}
+
+bool MappedZipFile::SeekToOffset(off64_t offset) {
+ if (has_fd_) {
+ if (lseek64(fd_, offset, SEEK_SET) != offset) {
+ ALOGE("Zip: lseek to %" PRId64 " failed: %s\n", offset, strerror(errno));
+ return false;
+ }
+ return true;
+ } else {
+ if (offset < 0 || offset > static_cast<off64_t>(data_length_)) {
+ ALOGE("Zip: invalid offset: %" PRId64 ", data length: %" PRId64 "\n" , offset,
+ data_length_);
+ return false;
+ }
+
+ read_pos_ = offset;
+ return true;
+ }
+}
+
+bool MappedZipFile::ReadData(uint8_t* buffer, size_t read_amount) {
+ if (has_fd_) {
+ if(!android::base::ReadFully(fd_, buffer, read_amount)) {
+ ALOGE("Zip: read from %d failed\n", fd_);
+ return false;
+ }
+ } else {
+ memcpy(buffer, static_cast<uint8_t*>(base_ptr_) + read_pos_, read_amount);
+ read_pos_ += read_amount;
+ }
+ return true;
+}
+
+// Attempts to read |len| bytes into |buf| at offset |off|.
+bool MappedZipFile::ReadAtOffset(uint8_t* buf, size_t len, off64_t off) {
+#if !defined(_WIN32)
+ if (has_fd_) {
+ if (static_cast<size_t>(TEMP_FAILURE_RETRY(pread64(fd_, buf, len, off))) != len) {
+ ALOGE("Zip: failed to read at offset %" PRId64 "\n", off);
+ return false;
+ }
+ return true;
+ }
+#endif
+ if (!SeekToOffset(off)) {
+ return false;
+ }
+ return ReadData(buf, len);
+
+}
+
+void CentralDirectory::Initialize(void* map_base_ptr, off64_t cd_start_offset, size_t cd_size) {
+ base_ptr_ = static_cast<uint8_t*>(map_base_ptr) + cd_start_offset;
+ length_ = cd_size;
+}
+
+bool ZipArchive::InitializeCentralDirectory(const char* debug_file_name, off64_t cd_start_offset,
+ size_t cd_size) {
+ if (mapped_zip.HasFd()) {
+ if (!directory_map->create(debug_file_name, mapped_zip.GetFileDescriptor(),
+ cd_start_offset, cd_size, true /* read only */)) {
+ return false;
+ }
+
+ CHECK_EQ(directory_map->getDataLength(), cd_size);
+ central_directory.Initialize(directory_map->getDataPtr(), 0/*offset*/, cd_size);
+ } else {
+ if (mapped_zip.GetBasePtr() == nullptr) {
+ ALOGE("Zip: Failed to map central directory, bad mapped_zip base pointer\n");
+ return false;
+ }
+ if (static_cast<off64_t>(cd_start_offset) + static_cast<off64_t>(cd_size) >
+ mapped_zip.GetFileLength()) {
+ ALOGE("Zip: Failed to map central directory, offset exceeds mapped memory region ("
+ "start_offset %" PRId64 ", cd_size %zu, mapped_region_size %" PRId64 ")",
+ static_cast<int64_t>(cd_start_offset), cd_size, mapped_zip.GetFileLength());
+ return false;
+ }
+
+ central_directory.Initialize(mapped_zip.GetBasePtr(), cd_start_offset, cd_size);
+ }
+ return true;
+}
diff --git a/libziparchive/zip_archive_private.h b/libziparchive/zip_archive_private.h
index ab52368..971db4f 100644
--- a/libziparchive/zip_archive_private.h
+++ b/libziparchive/zip_archive_private.h
@@ -21,17 +21,83 @@
#include <stdlib.h>
#include <unistd.h>
+#include <memory>
+#include <vector>
+
#include <utils/FileMap.h>
#include <ziparchive/zip_archive.h>
+class MappedZipFile {
+ public:
+ explicit MappedZipFile(const int fd) :
+ has_fd_(true),
+ fd_(fd),
+ base_ptr_(nullptr),
+ data_length_(0),
+ read_pos_(0) {}
+
+ explicit MappedZipFile(void* address, size_t length) :
+ has_fd_(false),
+ fd_(-1),
+ base_ptr_(address),
+ data_length_(static_cast<off64_t>(length)),
+ read_pos_(0) {}
+
+ bool HasFd() const {return has_fd_;}
+
+ int GetFileDescriptor() const;
+
+ void* GetBasePtr() const;
+
+ off64_t GetFileLength() const;
+
+ bool SeekToOffset(off64_t offset);
+
+ bool ReadData(uint8_t* buffer, size_t read_amount);
+
+ bool ReadAtOffset(uint8_t* buf, size_t len, off64_t off);
+
+ private:
+ // If has_fd_ is true, fd is valid and we'll read contents of a zip archive
+ // from the file. Otherwise, we're opening the archive from a memory mapped
+ // file. In that case, base_ptr_ points to the start of the memory region and
+ // data_length_ defines the file length.
+ const bool has_fd_;
+
+ const int fd_;
+
+ void* const base_ptr_;
+ const off64_t data_length_;
+ // read_pos_ is the offset to the base_ptr_ where we read data from.
+ size_t read_pos_;
+};
+
+class CentralDirectory {
+ public:
+ CentralDirectory(void) :
+ base_ptr_(nullptr),
+ length_(0) {}
+
+ const uint8_t* GetBasePtr() const {return base_ptr_;}
+
+ size_t GetMapLength() const {return length_;}
+
+ void Initialize(void* map_base_ptr, off64_t cd_start_offset, size_t cd_size);
+
+ private:
+ const uint8_t* base_ptr_;
+ size_t length_;
+};
+
struct ZipArchive {
// open Zip archive
- const int fd;
+ mutable MappedZipFile mapped_zip;
const bool close_file;
// mapped central directory area
off64_t directory_offset;
- android::FileMap directory_map;
+ CentralDirectory central_directory;
+ std::unique_ptr<android::FileMap> directory_map;
// number of entries in the Zip archive
uint16_t num_entries;
@@ -44,20 +110,36 @@
ZipString* hash_table;
ZipArchive(const int fd, bool assume_ownership) :
- fd(fd),
- close_file(assume_ownership),
- directory_offset(0),
- num_entries(0),
- hash_table_size(0),
- hash_table(NULL) {}
+ mapped_zip(fd),
+ close_file(assume_ownership),
+ directory_offset(0),
+ central_directory(),
+ directory_map(new android::FileMap()),
+ num_entries(0),
+ hash_table_size(0),
+ hash_table(nullptr) {}
+
+ ZipArchive(void* address, size_t length) :
+ mapped_zip(address, length),
+ close_file(false),
+ directory_offset(0),
+ central_directory(),
+ directory_map(new android::FileMap()),
+ num_entries(0),
+ hash_table_size(0),
+ hash_table(nullptr) {}
~ZipArchive() {
- if (close_file && fd >= 0) {
- close(fd);
+ if (close_file && mapped_zip.GetFileDescriptor() >= 0) {
+ close(mapped_zip.GetFileDescriptor());
}
free(hash_table);
}
+
+ bool InitializeCentralDirectory(const char* debug_file_name, off64_t cd_start_offset,
+ size_t cd_size);
+
};
#endif // LIBZIPARCHIVE_ZIPARCHIVE_PRIVATE_H_
diff --git a/libziparchive/zip_archive_stream_entry.cc b/libziparchive/zip_archive_stream_entry.cc
index 41988bc..64b24c3 100644
--- a/libziparchive/zip_archive_stream_entry.cc
+++ b/libziparchive/zip_archive_stream_entry.cc
@@ -39,7 +39,7 @@
bool ZipArchiveStreamEntry::Init(const ZipEntry& entry) {
ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
off64_t data_offset = entry.offset;
- if (lseek64(archive->fd, data_offset, SEEK_SET) != data_offset) {
+ if (!archive->mapped_zip.SeekToOffset(data_offset)) {
ALOGW("lseek to data at %" PRId64 " failed: %s", data_offset, strerror(errno));
return false;
}
@@ -88,7 +88,7 @@
size_t bytes = (length_ > data_.size()) ? data_.size() : length_;
ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
errno = 0;
- if (!android::base::ReadFully(archive->fd, data_.data(), bytes)) {
+ if (!archive->mapped_zip.ReadData(data_.data(), bytes)) {
if (errno != 0) {
ALOGE("Error reading from archive fd: %s", strerror(errno));
} else {
@@ -209,7 +209,7 @@
size_t bytes = (compressed_length_ > in_.size()) ? in_.size() : compressed_length_;
ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
errno = 0;
- if (!android::base::ReadFully(archive->fd, in_.data(), bytes)) {
+ if (!archive->mapped_zip.ReadData(in_.data(), bytes)) {
if (errno != 0) {
ALOGE("Error reading from archive fd: %s", strerror(errno));
} else {
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 6aee1bb..9dd6cc0 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -26,7 +26,9 @@
#include <android-base/file.h>
#include <android-base/test_utils.h>
+#include <android-base/unique_fd.h>
#include <gtest/gtest.h>
+#include <utils/FileMap.h>
#include <ziparchive/zip_archive.h>
#include <ziparchive/zip_archive_stream_entry.h>
@@ -36,6 +38,7 @@
static const std::string kValidZip = "valid.zip";
static const std::string kLargeZip = "large.zip";
static const std::string kBadCrcZip = "bad_crc.zip";
+static const std::string kUpdateZip = "dummy-update.zip";
static const std::vector<uint8_t> kATxtContents {
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
@@ -494,6 +497,32 @@
lseek64(tmp_file.fd, 0, SEEK_END));
}
+#if !defined(_WIN32)
+TEST(ziparchive, OpenFromMemory) {
+ const std::string zip_path = test_data_dir + "/" + kUpdateZip;
+ android::base::unique_fd fd(open(zip_path.c_str(), O_RDONLY | O_BINARY));
+ ASSERT_NE(-1, fd);
+ struct stat sb;
+ ASSERT_EQ(0, fstat(fd, &sb));
+
+ // Memory map the file first and open the archive from the memory region.
+ android::FileMap file_map;
+ file_map.create(zip_path.c_str(), fd, 0/*offset*/, sb.st_size, true);
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchiveFromMemory(file_map.getDataPtr(), file_map.getDataLength(),
+ zip_path.c_str(), &handle));
+
+ // Assert one entry can be found and extracted correctly.
+ std::string BINARY_PATH("META-INF/com/google/android/update-binary");
+ ZipString binary_path(BINARY_PATH.c_str());
+ ZipEntry binary_entry;
+ ASSERT_EQ(0, FindEntry(handle, binary_path, &binary_entry));
+ TemporaryFile tmp_binary;
+ ASSERT_NE(-1, tmp_binary.fd);
+ ASSERT_EQ(0, ExtractEntryToFile(handle, &binary_entry, tmp_binary.fd));
+}
+#endif
+
static void ZipArchiveStreamTest(
ZipArchiveHandle& handle, const std::string& entry_name, bool raw,
bool verified, ZipEntry* entry, std::vector<uint8_t>* read_data) {
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 107aa3e..49746b3 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -18,6 +18,7 @@
#include <arpa/inet.h>
#include <errno.h>
+#include <sched.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index d1a23ae..d0c693d 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -25,15 +25,14 @@
#include <memory>
#include <string>
-#include <android/log.h>
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <cutils/sched_policy.h>
#include <cutils/sockets.h>
#include <log/event_tag_map.h>
-#include <log/logger.h>
#include <log/logprint.h>
+#include <private/android_logger.h>
#include <system/thread_defs.h>
#include <pcrecpp.h>
@@ -83,8 +82,14 @@
static size_t g_printCount;
static bool g_printItAnyways;
+enum helpType {
+ HELP_FALSE,
+ HELP_TRUE,
+ HELP_FORMAT
+};
+
// if showHelp is set, newline required in fmt statement to transition to usage
-__noreturn static void logcat_panic(bool showHelp, const char *fmt, ...) __printflike(2,3);
+__noreturn static void logcat_panic(enum helpType showHelp, const char *fmt, ...) __printflike(2,3);
static int openLogFile (const char *pathname)
{
@@ -134,7 +139,7 @@
g_outFD = openLogFile(g_outputFileName);
if (g_outFD < 0) {
- logcat_panic(false, "couldn't open output file");
+ logcat_panic(HELP_FALSE, "couldn't open output file");
}
g_outByteCount = 0;
@@ -187,7 +192,9 @@
goto error;
}
- if (android_log_shouldPrintLine(g_logformat, entry.tag, entry.priority)) {
+ if (android_log_shouldPrintLine(g_logformat,
+ std::string(entry.tag, entry.tagLen).c_str(),
+ entry.priority)) {
bool match = regexOk(entry);
g_printCount += match;
@@ -195,7 +202,7 @@
bytesWritten = android_log_printLogLine(g_logformat, g_outFD, &entry);
if (bytesWritten < 0) {
- logcat_panic(false, "output error");
+ logcat_panic(HELP_FALSE, "output error");
}
}
}
@@ -209,7 +216,6 @@
}
error:
- //fprintf (stderr, "Error processing record\n");
return;
}
@@ -221,7 +227,7 @@
dev->printed ? "switch to" : "beginning of",
dev->device);
if (write(g_outFD, buf, strlen(buf)) < 0) {
- logcat_panic(false, "output error");
+ logcat_panic(HELP_FALSE, "output error");
}
}
dev->printed = true;
@@ -255,18 +261,18 @@
g_outFD = openLogFile (g_outputFileName);
if (g_outFD < 0) {
- logcat_panic(false, "couldn't open output file");
+ logcat_panic(HELP_FALSE, "couldn't open output file");
}
struct stat statbuf;
if (fstat(g_outFD, &statbuf) == -1) {
close(g_outFD);
- logcat_panic(false, "couldn't get output file stat\n");
+ logcat_panic(HELP_FALSE, "couldn't get output file stat\n");
}
if ((size_t) statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) {
close(g_outFD);
- logcat_panic(false, "invalid output file stat\n");
+ logcat_panic(HELP_FALSE, "invalid output file stat\n");
}
g_outByteCount = statbuf.st_size;
@@ -287,9 +293,10 @@
" the fileset and continue\n"
" -v <format>, --format=<format>\n"
" Sets log print format verb and adverbs, where <format> is:\n"
- " brief long process raw tag thread threadtime time\n"
+ " brief help long process raw tag thread threadtime time\n"
" and individually flagged modifying adverbs can be added:\n"
- " color epoch monotonic printable uid usec UTC year zone\n"
+ " color descriptive epoch monotonic printable uid\n"
+ " usec UTC year zone\n"
" -D, --dividers Print dividers between each log buffer\n"
" -c, --clear Clear (flush) the entire log and exit\n"
" if Log to File specified, clear fileset instead\n"
@@ -355,6 +362,40 @@
"or defaults to \"threadtime\"\n\n");
}
+static void show_format_help()
+{
+ fprintf(stderr,
+ "-v <format>, --format=<format> options:\n"
+ " Sets log print format verb and adverbs, where <format> is:\n"
+ " brief long process raw tag thread threadtime time\n"
+ " and individually flagged modifying adverbs can be added:\n"
+ " color descriptive epoch monotonic printable uid usec UTC year zone\n"
+ "\nSingle format verbs:\n"
+ " brief — Display priority/tag and PID of the process issuing the message.\n"
+ " long — Display all metadata fields, separate messages with blank lines.\n"
+ " process — Display PID only.\n"
+ " raw — Display the raw log message, with no other metadata fields.\n"
+ " tag — Display the priority/tag only.\n"
+ " threadtime — Display the date, invocation time, priority, tag, and the PID\n"
+ " and TID of the thread issuing the message. (the default format).\n"
+ " time — Display the date, invocation time, priority/tag, and PID of the\n"
+ " process issuing the message.\n"
+ "\nAdverb modifiers can be used in combination:\n"
+ " color — Display in highlighted color to match priority. i.e. \x1B[38;5;231mVERBOSE\n"
+ " \x1B[38;5;75mDEBUG \x1B[38;5;40mINFO \x1B[38;5;166mWARNING \x1B[38;5;196mERROR FATAL\x1B[0m\n"
+ " descriptive — events logs only, descriptions from event-log-tags database.\n"
+ " epoch — Display time as seconds since Jan 1 1970.\n"
+ " monotonic — Display time as cpu seconds since last boot.\n"
+ " printable — Ensure that any binary logging content is escaped.\n"
+ " uid — If permitted, display the UID or Android ID of logged process.\n"
+ " usec — Display time down the microsecond precision.\n"
+ " UTC — Display time as UTC.\n"
+ " year — Add the year to the displayed time.\n"
+ " zone — Add the local timezone to the displayed time.\n"
+ " \"<zone>\" — Print using this public named timezone (experimental).\n\n"
+ );
+}
+
static int setLogFormat(const char * formatString)
{
static AndroidLogPrintFormat format;
@@ -417,15 +458,23 @@
return true;
}
-static void logcat_panic(bool showHelp, const char *fmt, ...)
+static void logcat_panic(enum helpType showHelp, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
- if (showHelp) {
+ switch (showHelp) {
+ case HELP_TRUE:
show_help(getprogname());
+ break;
+ case HELP_FORMAT:
+ show_format_help();
+ break;
+ case HELP_FALSE:
+ default:
+ break;
}
exit(EXIT_FAILURE);
@@ -615,7 +664,7 @@
if (long_options[option_index].name == pid_str) {
// ToDo: determine runtime PID_MAX?
if (!getSizeTArg(optarg, &pid, 1)) {
- logcat_panic(true, "%s %s out of range\n",
+ logcat_panic(HELP_TRUE, "%s %s out of range\n",
long_options[option_index].name, optarg);
}
break;
@@ -627,7 +676,7 @@
// ToDo: implement API that supports setting a wrap timeout
size_t dummy = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT;
if (optarg && !getSizeTArg(optarg, &dummy, 1)) {
- logcat_panic(true, "%s %s out of range\n",
+ logcat_panic(HELP_TRUE, "%s %s out of range\n",
long_options[option_index].name, optarg);
}
if (dummy != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) {
@@ -674,7 +723,8 @@
if (strspn(optarg, "0123456789") != strlen(optarg)) {
char *cp = parseTime(tail_time, optarg);
if (!cp) {
- logcat_panic(false, "-%c \"%s\" not in time format\n",
+ logcat_panic(HELP_FALSE,
+ "-%c \"%s\" not in time format\n",
ret, optarg);
}
if (*cp) {
@@ -706,7 +756,7 @@
case 'm': {
char *end = NULL;
if (!getSizeTArg(optarg, &g_maxCount)) {
- logcat_panic(false, "-%c \"%s\" isn't an "
+ logcat_panic(HELP_FALSE, "-%c \"%s\" isn't an "
"integer greater than zero\n", ret, optarg);
}
}
@@ -779,7 +829,8 @@
const char *name = android_log_id_to_name(log_id);
if (strcmp(name, optarg) != 0) {
- logcat_panic(true, "unknown buffer %s\n", optarg);
+ logcat_panic(HELP_TRUE,
+ "unknown buffer %s\n", optarg);
}
idMask |= (1 << log_id);
}
@@ -840,20 +891,27 @@
case 'r':
if (!getSizeTArg(optarg, &g_logRotateSizeKBytes, 1)) {
- logcat_panic(true, "Invalid parameter %s to -r\n", optarg);
+ logcat_panic(HELP_TRUE,
+ "Invalid parameter \"%s\" to -r\n", optarg);
}
break;
case 'n':
if (!getSizeTArg(optarg, &g_maxRotatedLogs, 1)) {
- logcat_panic(true, "Invalid parameter %s to -n\n", optarg);
+ logcat_panic(HELP_TRUE,
+ "Invalid parameter \"%s\" to -n\n", optarg);
}
break;
case 'v':
- err = setLogFormat (optarg);
+ if (!strcmp(optarg, "help") || !strcmp(optarg, "--help")) {
+ show_format_help();
+ exit(0);
+ }
+ err = setLogFormat(optarg);
if (err < 0) {
- logcat_panic(true, "Invalid parameter %s to -v\n", optarg);
+ logcat_panic(HELP_FORMAT,
+ "Invalid parameter \"%s\" to -v\n", optarg);
}
hasSetLogFormat |= err;
break;
@@ -931,17 +989,20 @@
break;
case ':':
- logcat_panic(true, "Option -%c needs an argument\n", optopt);
+ logcat_panic(HELP_TRUE,
+ "Option -%c needs an argument\n", optopt);
break;
default:
- logcat_panic(true, "Unrecognized Option %c\n", optopt);
+ logcat_panic(HELP_TRUE,
+ "Unrecognized Option %c\n", optopt);
break;
}
}
if (g_maxCount && got_t) {
- logcat_panic(true, "Cannot use -m (--max-count) and -t together\n");
+ logcat_panic(HELP_TRUE,
+ "Cannot use -m (--max-count) and -t together\n");
}
if (g_printItAnyways && (!g_regex || !g_maxCount)) {
// One day it would be nice if --print -v color and --regex <expr>
@@ -967,12 +1028,12 @@
}
if (g_logRotateSizeKBytes != 0 && g_outputFileName == NULL) {
- logcat_panic(true, "-r requires -f as well\n");
+ logcat_panic(HELP_TRUE, "-r requires -f as well\n");
}
if (setId != NULL) {
if (g_outputFileName == NULL) {
- logcat_panic(true, "--id='%s' requires -f as well\n", setId);
+ logcat_panic(HELP_TRUE, "--id='%s' requires -f as well\n", setId);
}
std::string file_name = android::base::StringPrintf("%s.id", g_outputFileName);
@@ -1002,7 +1063,8 @@
if (forceFilters) {
err = android_log_addFilterString(g_logformat, forceFilters);
if (err < 0) {
- logcat_panic(false, "Invalid filter expression in logcat args\n");
+ logcat_panic(HELP_FALSE,
+ "Invalid filter expression in logcat args\n");
}
} else if (argc == optind) {
// Add from environment variable
@@ -1012,7 +1074,7 @@
err = android_log_addFilterString(g_logformat, env_tags_orig);
if (err < 0) {
- logcat_panic(true,
+ logcat_panic(HELP_TRUE,
"Invalid filter expression in ANDROID_LOG_TAGS\n");
}
}
@@ -1022,7 +1084,8 @@
err = android_log_addFilterString(g_logformat, argv[i]);
if (err < 0) {
- logcat_panic(true, "Invalid filter expression '%s'\n", argv[i]);
+ logcat_panic(HELP_TRUE,
+ "Invalid filter expression '%s'\n", argv[i]);
}
}
}
@@ -1108,17 +1171,20 @@
}
// report any errors in the above loop and exit
if (openDeviceFail) {
- logcat_panic(false, "Unable to open log device '%s'\n", openDeviceFail);
+ logcat_panic(HELP_FALSE,
+ "Unable to open log device '%s'\n", openDeviceFail);
}
if (clearFail) {
- logcat_panic(false, "failed to clear the '%s' log\n", clearFail);
+ logcat_panic(HELP_FALSE,
+ "failed to clear the '%s' log\n", clearFail);
}
if (setSizeFail) {
- logcat_panic(false, "failed to set the '%s' log size\n", setSizeFail);
+ logcat_panic(HELP_FALSE,
+ "failed to set the '%s' log size\n", setSizeFail);
}
if (getSizeFail) {
- logcat_panic(false, "failed to get the readable '%s' log size",
- getSizeFail);
+ logcat_panic(HELP_FALSE,
+ "failed to get the readable '%s' log size", getSizeFail);
}
if (setPruneList) {
@@ -1129,11 +1195,11 @@
if (asprintf(&buf, "%-*s", (int)(bLen - 1), setPruneList) > 0) {
buf[len] = '\0';
if (android_logger_set_prune_list(logger_list, buf, bLen)) {
- logcat_panic(false, "failed to set the prune list");
+ logcat_panic(HELP_FALSE, "failed to set the prune list");
}
free(buf);
} else {
- logcat_panic(false, "failed to set the prune list (alloc)");
+ logcat_panic(HELP_FALSE, "failed to set the prune list (alloc)");
}
}
@@ -1164,7 +1230,7 @@
}
if (!buf) {
- logcat_panic(false, "failed to read data");
+ logcat_panic(HELP_FALSE, "failed to read data");
}
// remove trailing FF
@@ -1216,7 +1282,7 @@
int ret = android_logger_list_read(logger_list, &log_msg);
if (ret == 0) {
- logcat_panic(false, "read: unexpected EOF!\n");
+ logcat_panic(HELP_FALSE, "read: unexpected EOF!\n");
}
if (ret < 0) {
@@ -1225,12 +1291,12 @@
}
if (ret == -EIO) {
- logcat_panic(false, "read: unexpected EOF!\n");
+ logcat_panic(HELP_FALSE, "read: unexpected EOF!\n");
}
if (ret == -EINVAL) {
- logcat_panic(false, "read: unexpected length.\n");
+ logcat_panic(HELP_FALSE, "read: unexpected length.\n");
}
- logcat_panic(false, "logcat read failure");
+ logcat_panic(HELP_FALSE, "logcat read failure");
}
for (d = devices; d; d = d->next) {
diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk
index a28664e..99c2e0a 100644
--- a/logcat/tests/Android.mk
+++ b/logcat/tests/Android.mk
@@ -25,7 +25,6 @@
-Wall -Wextra \
-Werror \
-fno-builtin \
- -std=gnu++11
# -----------------------------------------------------------------------------
# Benchmarks (actually a gTest where the result code does not matter)
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 9c9043e..18067dc 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -25,10 +25,10 @@
#include <sys/wait.h>
#include <memory>
+#include <string>
-#include <android/log.h>
#include <gtest/gtest.h>
-#include <log/logger.h>
+#include <log/log.h>
#define BIG_BUFFER (5 * 1024)
@@ -79,6 +79,26 @@
EXPECT_EQ(4, count);
}
+TEST(logcat, event_tag_filter) {
+ FILE *fp;
+
+ ASSERT_TRUE(NULL != (fp = popen(
+ "logcat -b events -d -s auditd am_proc_start am_pss am_proc_bound dvm_lock_sample am_wtf 2>/dev/null",
+ "r")));
+
+ char buffer[BIG_BUFFER];
+
+ int count = 0;
+
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ ++count;
+ }
+
+ pclose(fp);
+
+ EXPECT_LT(4, count);
+}
+
TEST(logcat, year) {
if (android_log_clockid() == CLOCK_MONOTONIC) {
@@ -570,6 +590,14 @@
EXPECT_EQ(1, signals);
}
+// meant to be handed to ASSERT_FALSE / EXPECT_FALSE to expand the message
+static testing::AssertionResult IsFalse(int ret, const char* command) {
+ return ret ?
+ (testing::AssertionSuccess() <<
+ "ret=" << ret << " command=\"" << command << "\"") :
+ testing::AssertionFailure();
+}
+
TEST(logcat, logrotate) {
static const char form[] = "/data/local/tmp/logcat.logrotate.XXXXXX";
char buf[sizeof(form)];
@@ -581,7 +609,7 @@
snprintf(command, sizeof(command), comm, buf);
int ret;
- EXPECT_FALSE((ret = system(command)));
+ EXPECT_FALSE(IsFalse(ret = system(command), command));
if (!ret) {
snprintf(command, sizeof(command), "ls -s %s 2>/dev/null", buf);
@@ -611,7 +639,7 @@
}
}
snprintf(command, sizeof(command), "rm -rf %s", buf);
- EXPECT_FALSE(system(command));
+ EXPECT_FALSE(IsFalse(system(command), command));
}
TEST(logcat, logrotate_suffix) {
@@ -625,7 +653,7 @@
snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir);
int ret;
- EXPECT_FALSE((ret = system(command)));
+ EXPECT_FALSE(IsFalse(ret = system(command), command));
if (!ret) {
snprintf(command, sizeof(command), "ls %s 2>/dev/null", tmp_out_dir);
@@ -664,7 +692,7 @@
EXPECT_EQ(11, log_file_count);
}
snprintf(command, sizeof(command), "rm -rf %s", tmp_out_dir);
- EXPECT_FALSE(system(command));
+ EXPECT_FALSE(IsFalse(system(command), command));
}
TEST(logcat, logrotate_continue) {
@@ -679,10 +707,10 @@
snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename);
int ret;
- EXPECT_FALSE((ret = system(command)));
+ EXPECT_FALSE(IsFalse(ret = system(command), command));
if (ret) {
snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(system(command));
+ EXPECT_FALSE(IsFalse(system(command), command));
return;
}
FILE *fp;
@@ -690,7 +718,7 @@
EXPECT_TRUE(NULL != ((fp = fopen(command, "r"))));
if (!fp) {
snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(system(command));
+ EXPECT_FALSE(IsFalse(system(command), command));
return;
}
char *line = NULL;
@@ -714,23 +742,23 @@
EXPECT_TRUE(NULL != second_last_line);
if (!second_last_line) {
snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(system(command));
+ EXPECT_FALSE(IsFalse(system(command), command));
return;
}
// re-run the command, it should only add a few lines more content if it
// continues where it left off.
snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename);
- EXPECT_FALSE((ret = system(command)));
+ EXPECT_FALSE(IsFalse(ret = system(command), command));
if (ret) {
snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(system(command));
+ EXPECT_FALSE(IsFalse(system(command), command));
return;
}
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir);
EXPECT_NE(nullptr, dir);
if (!dir) {
snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(system(command));
+ EXPECT_FALSE(IsFalse(system(command), command));
return;
}
struct dirent *entry;
@@ -769,7 +797,7 @@
free(second_last_line);
snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(system(command));
+ EXPECT_FALSE(IsFalse(system(command), command));
}
TEST(logcat, logrotate_clear) {
@@ -790,17 +818,17 @@
logcat_cmd, tmp_out_dir, log_filename, num_val);
int ret;
- EXPECT_FALSE((ret = system(command)));
+ EXPECT_FALSE(IsFalse(ret = system(command), command));
if (ret) {
snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(system(command));
+ EXPECT_FALSE(IsFalse(system(command), command));
return;
}
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir);
EXPECT_NE(nullptr, dir);
if (!dir) {
snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(system(command));
+ EXPECT_FALSE(IsFalse(system(command), command));
return;
}
struct dirent *entry;
@@ -819,17 +847,18 @@
strcat(command, clear_cmd);
int ret;
- EXPECT_FALSE((ret = system(command)));
+ EXPECT_FALSE(IsFalse(ret = system(command), command));
if (ret) {
snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
EXPECT_FALSE(system(command));
+ EXPECT_FALSE(IsFalse(system(command), command));
return;
}
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir);
EXPECT_NE(nullptr, dir);
if (!dir) {
snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(system(command));
+ EXPECT_FALSE(IsFalse(system(command), command));
return;
}
struct dirent *entry;
@@ -845,7 +874,7 @@
}
snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(system(command));
+ EXPECT_FALSE(IsFalse(system(command), command));
}
static int logrotate_count_id(const char *logcat_cmd, const char *tmp_out_dir) {
@@ -856,7 +885,7 @@
snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename);
int ret;
- EXPECT_FALSE((ret = system(command)));
+ EXPECT_FALSE(IsFalse(ret = system(command), command));
if (ret) {
return -1;
}
@@ -914,7 +943,7 @@
static const char cleanup_cmd[] = "rm -rf %s";
char command[strlen(cleanup_cmd) + strlen(tmp_out_dir_form)];
snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(system(command));
+ EXPECT_FALSE(IsFalse(system(command), command));
}
TEST(logcat, logrotate_nodir) {
@@ -1207,3 +1236,163 @@
ASSERT_EQ(3, count);
}
+
+static bool End_to_End(const char* tag, const char* fmt, ...)
+#if defined(__GNUC__)
+ __attribute__((__format__(printf, 2, 3)))
+#endif
+ ;
+
+static bool End_to_End(const char* tag, const char* fmt, ...) {
+ FILE *fp = popen("logcat -v brief -b events -v descriptive -t 100 2>/dev/null", "r");
+ if (!fp) return false;
+
+ char buffer[BIG_BUFFER];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(buffer, sizeof(buffer), fmt, ap);
+ va_end(ap);
+
+ char *str = NULL;
+ asprintf(&str, "I/%s ( %%d): %s%%c", tag, buffer);
+ std::string expect(str);
+ free(str);
+
+ int count = 0;
+ pid_t pid = getpid();
+ std::string lastMatch;
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ char newline;
+ int p;
+ int ret = sscanf(buffer, expect.c_str(), &p, &newline);
+ if ((2 == ret) && (p == pid) && (newline == '\n')) ++count;
+ else if ((1 == ret) && (p == pid) && (count == 0)) lastMatch = buffer;
+ }
+
+ pclose(fp);
+
+ if ((count == 0) && (lastMatch.length() > 0)) {
+ // Help us pinpoint where things went wrong ...
+ fprintf(stderr, "Closest match for\n %s\n is\n %s",
+ expect.c_str(), lastMatch.c_str());
+ }
+
+ return count == 1;
+}
+
+TEST(logcat, descriptive) {
+ struct tag {
+ uint32_t tagNo;
+ const char* tagStr;
+ };
+
+ {
+ static const struct tag hhgtg = { 42, "answer" };
+ android_log_event_context ctx(hhgtg.tagNo);
+ static const char theAnswer[] = "what is five by seven";
+ ctx << theAnswer;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(hhgtg.tagStr,
+ "to life the universe etc=%s", theAnswer));
+ }
+
+ {
+ static const struct tag sync = { 2720, "sync" };
+ static const char id[] = "logcat.decriptive";
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << id << (int32_t)42 << (int32_t)-1 << (int32_t)0;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr,
+ "[id=%s,event=42,source=-1,account=0]",
+ id));
+ }
+
+ // Partial match to description
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << id << (int32_t)43 << (int64_t)-1 << (int32_t)0;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr,
+ "[id=%s,event=43,-1,0]",
+ id));
+ }
+
+ // Negative Test of End_to_End, ensure it is working
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << id << (int32_t)44 << (int32_t)-1 << (int64_t)0;
+ ctx.write();
+ fprintf(stderr, "Expect a \"Closest match\" message\n");
+ EXPECT_FALSE(End_to_End(sync.tagStr,
+ "[id=%s,event=44,source=-1,account=0]",
+ id));
+ }
+ }
+
+ {
+ static const struct tag sync = { 2747, "contacts_aggregation" };
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << (uint64_t)30 << (int32_t)2;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr,
+ "[aggregation time=30ms,count=2]"));
+ }
+
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << (uint64_t)31570 << (int32_t)911;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr,
+ "[aggregation time=31.57s,count=911]"));
+ }
+ }
+
+ {
+ static const struct tag sync = { 75000, "sqlite_mem_alarm_current" };
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << (uint32_t)512;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr, "current=512B"));
+ }
+
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << (uint32_t)3072;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr, "current=3KB"));
+ }
+
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << (uint32_t)2097152;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr, "current=2MB"));
+ }
+
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << (uint32_t)2097153;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr, "current=2097153B"));
+ }
+
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << (uint32_t)1073741824;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr, "current=1GB"));
+ }
+
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << (uint32_t)3221225472; // 3MB, but on purpose overflowed
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr, "current=-1GB"));
+ }
+ }
+
+}
diff --git a/logd/Android.mk b/logd/Android.mk
index 81637d2..7fe48d7 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -29,7 +29,7 @@
libcutils \
libbase \
libpackagelistparser \
- libminijail
+ libcap
# This is what we want to do:
# event_logtags = $(shell \
diff --git a/logd/FlushCommand.h b/logd/FlushCommand.h
index a6cdf9d..1e7818a 100644
--- a/logd/FlushCommand.h
+++ b/logd/FlushCommand.h
@@ -16,7 +16,7 @@
#ifndef _FLUSH_COMMAND_H
#define _FLUSH_COMMAND_H
-#include <log/logger.h>
+#include <android/log.h>
#include <sysutils/SocketClientCommand.h>
class LogBufferElement;
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index cc140b0..c3ccd84 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -25,7 +25,7 @@
#include <sys/uio.h>
#include <syslog.h>
-#include <log/logger.h>
+#include <android-base/macros.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
@@ -144,7 +144,7 @@
iov[2].iov_len = strlen(newline);
}
- writev(fdDmesg, iov, sizeof(iov) / sizeof(iov[0]));
+ writev(fdDmesg, iov, arraysize(iov));
free(last_str);
last_str = NULL;
}
@@ -166,7 +166,7 @@
iov[2].iov_base = const_cast<char *>(newline);
iov[2].iov_len = strlen(newline);
- writev(fdDmesg, iov, sizeof(iov) / sizeof(iov[0]));
+ writev(fdDmesg, iov, arraysize(iov));
}
}
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 7f5fe4f..a009433 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -13,11 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+// for manual checking of stale entries during LogBuffer::erase()
+//#define DEBUG_CHECK_FOR_STALE_ENTRIES
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
+#include <sys/cdefs.h>
#include <sys/user.h>
#include <time.h>
#include <unistd.h>
@@ -25,114 +28,25 @@
#include <unordered_map>
#include <cutils/properties.h>
-#include <log/logger.h>
+#include <private/android_logger.h>
#include "LogBuffer.h"
#include "LogKlog.h"
#include "LogReader.h"
+#ifndef __predict_false
+#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
+#endif
+
// Default
-#define LOG_BUFFER_SIZE (256 * 1024) // Tuned with ro.logd.size per-platform
#define log_buffer_size(id) mMaxSize[id]
-#define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
-#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
-
-static bool valid_size(unsigned long value) {
- if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
- return false;
- }
-
- long pages = sysconf(_SC_PHYS_PAGES);
- if (pages < 1) {
- return true;
- }
-
- long pagesize = sysconf(_SC_PAGESIZE);
- if (pagesize <= 1) {
- pagesize = PAGE_SIZE;
- }
-
- // maximum memory impact a somewhat arbitrary ~3%
- pages = (pages + 31) / 32;
- unsigned long maximum = pages * pagesize;
-
- if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
- return true;
- }
-
- return value <= maximum;
-}
-
-static unsigned long property_get_size(const char *key) {
- char property[PROPERTY_VALUE_MAX];
- property_get(key, property, "");
-
- char *cp;
- unsigned long value = strtoul(property, &cp, 10);
-
- switch(*cp) {
- case 'm':
- case 'M':
- value *= 1024;
- /* FALLTHRU */
- case 'k':
- case 'K':
- value *= 1024;
- /* FALLTHRU */
- case '\0':
- break;
-
- default:
- value = 0;
- }
-
- if (!valid_size(value)) {
- value = 0;
- }
-
- return value;
-}
void LogBuffer::init() {
- static const char global_tuneable[] = "persist.logd.size"; // Settings App
- static const char global_default[] = "ro.logd.size"; // BoardConfig.mk
-
- unsigned long default_size = property_get_size(global_tuneable);
- if (!default_size) {
- default_size = property_get_size(global_default);
- if (!default_size) {
- default_size = property_get_bool("ro.config.low_ram",
- BOOL_DEFAULT_FALSE)
- ? LOG_BUFFER_MIN_SIZE // 64K
- : LOG_BUFFER_SIZE; // 256K
- }
- }
-
log_id_for_each(i) {
mLastSet[i] = false;
mLast[i] = mLogElements.begin();
- char key[PROP_NAME_MAX];
-
- snprintf(key, sizeof(key), "%s.%s",
- global_tuneable, android_log_id_to_name(i));
- unsigned long property_size = property_get_size(key);
-
- if (!property_size) {
- snprintf(key, sizeof(key), "%s.%s",
- global_default, android_log_id_to_name(i));
- property_size = property_get_size(key);
- }
-
- if (!property_size) {
- property_size = default_size;
- }
-
- if (!property_size) {
- property_size = LOG_BUFFER_SIZE;
- }
-
- if (setSize(i, property_size)) {
+ if (setSize(i, __android_logger_get_buffer_size(i))) {
setSize(i, LOG_BUFFER_MIN_SIZE);
}
}
@@ -315,6 +229,9 @@
LogBufferElement *element = *it;
log_id_t id = element->getLogId();
+ // Remove iterator references in the various lists that will become stale
+ // after the element is erased from the main logging list.
+
{ // start of scope for found iterator
int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) ?
element->getTag() : element->getUid();
@@ -324,8 +241,10 @@
}
}
- if ((id != LOG_ID_EVENTS) && (id != LOG_ID_SECURITY) && (element->getUid() == AID_SYSTEM)) {
- // start of scope for pid found iterator
+ { // start of scope for pid found iterator
+ // element->getUid() may not be AID_SYSTEM for next-best-watermark.
+ // will not assume id != LOG_ID_EVENTS or LOG_ID_SECURITY for KISS and
+ // long term code stability, find() check should be fast for those ids.
LogBufferPidIteratorMap::iterator found =
mLastWorstPidOfSystem[id].find(element->getPid());
if ((found != mLastWorstPidOfSystem[id].end())
@@ -339,18 +258,45 @@
log_id_for_each(i) {
doSetLast |= setLast[i] = mLastSet[i] && (it == mLast[i]);
}
+#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
+ LogBufferElementCollection::iterator bad = it;
+ int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) ?
+ element->getTag() : element->getUid();
+#endif
it = mLogElements.erase(it);
if (doSetLast) {
log_id_for_each(i) {
if (setLast[i]) {
- if (it == mLogElements.end()) { // unlikely
+ if (__predict_false(it == mLogElements.end())) { // impossible
mLastSet[i] = false;
+ mLast[i] = mLogElements.begin();
} else {
- mLast[i] = it;
+ mLast[i] = it; // push down the road as next-best-watermark
}
}
}
}
+#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
+ log_id_for_each(i) {
+ for(auto b : mLastWorst[i]) {
+ if (bad == b.second) {
+ android::prdebug("stale mLastWorst[%d] key=%d mykey=%d\n",
+ i, b.first, key);
+ }
+ }
+ for(auto b : mLastWorstPidOfSystem[i]) {
+ if (bad == b.second) {
+ android::prdebug("stale mLastWorstPidOfSystem[%d] pid=%d\n",
+ i, b.first);
+ }
+ }
+ if (mLastSet[i] && (bad == mLast[i])) {
+ android::prdebug("stale mLast[%d]\n", i);
+ mLastSet[i] = false;
+ mLast[i] = mLogElements.begin();
+ }
+ }
+#endif
if (coalesce) {
stats.erase(element);
} else {
@@ -509,7 +455,7 @@
LogBufferElementCollection::iterator it;
- if (caller_uid != AID_ROOT) {
+ if (__predict_false(caller_uid != AID_ROOT)) { // unlikely
// Only here if clear all request from non system source, so chatty
// filter logistics is not required.
it = mLastSet[id] ? mLast[id] : mLogElements.begin();
@@ -561,6 +507,7 @@
if ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) {
stats.sortTags(AID_ROOT, (pid_t)0, 2, id).findWorst(
worst, worst_sizes, second_worst_sizes, threshold);
+ // per-pid filter for AID_SYSTEM sources is too complex
} else {
stats.sort(AID_ROOT, (pid_t)0, 2, id).findWorst(
worst, worst_sizes, second_worst_sizes, threshold);
@@ -594,8 +541,9 @@
it = found->second;
}
}
- if (worstPid) {
- // begin scope for pid worst found iterator
+ if (worstPid) { // begin scope for pid worst found iterator
+ // FYI: worstPid only set if !LOG_ID_EVENTS and
+ // !LOG_ID_SECURITY, not going to make that assumption ...
LogBufferPidIteratorMap::iterator found
= mLastWorstPidOfSystem[id].find(worstPid);
if ((found != mLastWorstPidOfSystem[id].end())
@@ -627,6 +575,7 @@
++it;
continue;
}
+ // below this point element->getLogId() == id
if (leading && (!mLastSet[id] || ((*mLast[id])->getLogId() != id))) {
mLast[id] = it;
@@ -683,6 +632,9 @@
&& ((!gc && (element->getPid() == worstPid))
|| (mLastWorstPidOfSystem[id].find(element->getPid())
== mLastWorstPidOfSystem[id].end()))) {
+ // element->getUid() may not be AID_SYSTEM, next best
+ // watermark if current one empty. id is not LOG_ID_EVENTS
+ // or LOG_ID_SECURITY because of worstPid check.
mLastWorstPidOfSystem[id][element->getPid()] = it;
}
if ((!gc && !worstPid && (key == worst))
@@ -700,6 +652,8 @@
++it;
continue;
}
+ // key == worst below here
+ // If worstPid set, then element->getPid() == worstPid below here
pruneRows--;
if (pruneRows == 0) {
@@ -723,6 +677,9 @@
if (worstPid && (!gc
|| (mLastWorstPidOfSystem[id].find(worstPid)
== mLastWorstPidOfSystem[id].end()))) {
+ // element->getUid() may not be AID_SYSTEM, next best
+ // watermark if current one empty. id is not
+ // LOG_ID_EVENTS or LOG_ID_SECURITY because of worstPid.
mLastWorstPidOfSystem[id][worstPid] = it;
}
if ((!gc && !worstPid) ||
@@ -880,7 +837,7 @@
// set the total space allocated to "id"
int LogBuffer::setSize(log_id_t id, unsigned long size) {
// Reasonable limits ...
- if (!valid_size(size)) {
+ if (!__android_logger_valid_buffer_size(size)) {
return -1;
}
pthread_mutex_lock(&mLogElementsLock);
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index e5de11d..f5c60c7 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -22,7 +22,6 @@
#include <time.h>
#include <unistd.h>
-#include <log/logger.h>
#include <private/android_logger.h>
#include "LogBuffer.h"
@@ -37,29 +36,24 @@
LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime,
uid_t uid, pid_t pid, pid_t tid,
const char *msg, unsigned short len) :
- mLogId(log_id),
mUid(uid),
mPid(pid),
mTid(tid),
- mMsgLen(len),
mSequence(sequence.fetch_add(1, memory_order_relaxed)),
- mRealTime(realtime) {
+ mRealTime(realtime),
+ mMsgLen(len),
+ mLogId(log_id) {
mMsg = new char[len];
memcpy(mMsg, msg, len);
+ mTag = (isBinary() && (mMsgLen >= sizeof(uint32_t))) ?
+ le32toh(reinterpret_cast<android_event_header_t *>(mMsg)->tag) :
+ 0;
}
LogBufferElement::~LogBufferElement() {
delete [] mMsg;
}
-uint32_t LogBufferElement::getTag() const {
- if (((mLogId != LOG_ID_EVENTS) && (mLogId != LOG_ID_SECURITY)) ||
- !mMsg || (mMsgLen < sizeof(uint32_t))) {
- return 0;
- }
- return le32toh(reinterpret_cast<android_event_header_t *>(mMsg)->tag);
-}
-
// caller must own and free character string
char *android::tidToName(pid_t tid) {
char *retval = NULL;
@@ -165,7 +159,7 @@
size_t hdrLen;
// LOG_ID_SECURITY not strictly needed since spam filter not activated,
// but required for accuracy.
- if ((mLogId == LOG_ID_EVENTS) || (mLogId == LOG_ID_SECURITY)) {
+ if (isBinary()) {
hdrLen = sizeof(android_log_event_string_t);
} else {
hdrLen = 1 + sizeof(tag);
@@ -179,7 +173,7 @@
}
size_t retval = hdrLen + len;
- if ((mLogId == LOG_ID_EVENTS) || (mLogId == LOG_ID_SECURITY)) {
+ if (isBinary()) {
android_log_event_string_t *event =
reinterpret_cast<android_log_event_string_t *>(buffer);
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index f089550..fb7fbed 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -21,9 +21,8 @@
#include <stdlib.h>
#include <sys/types.h>
-#include <android/log.h>
+#include <log/log.h>
#include <sysutils/SocketClient.h>
-#include <log/logger.h>
class LogBuffer;
@@ -37,33 +36,40 @@
friend LogBuffer;
- const log_id_t mLogId;
- const uid_t mUid;
- const pid_t mPid;
- const pid_t mTid;
- char *mMsg;
- union {
- const unsigned short mMsgLen; // mMSg != NULL
- unsigned short mDropped; // mMsg == NULL
- };
+ // sized to match reality of incoming log packets
+ uint32_t mTag; // only valid for isBinary()
+ const uint32_t mUid;
+ const uint32_t mPid;
+ const uint32_t mTid;
const uint64_t mSequence;
log_time mRealTime;
+ char *mMsg;
+ union {
+ const uint16_t mMsgLen; // mMSg != NULL
+ uint16_t mDropped; // mMsg == NULL
+ };
+ const uint8_t mLogId;
+
static atomic_int_fast64_t sequence;
// assumption: mMsg == NULL
size_t populateDroppedMessage(char *&buffer,
LogBuffer *parent);
-
public:
LogBufferElement(log_id_t log_id, log_time realtime,
uid_t uid, pid_t pid, pid_t tid,
const char *msg, unsigned short len);
virtual ~LogBufferElement();
- log_id_t getLogId() const { return mLogId; }
+ bool isBinary(void) const {
+ return (mLogId == LOG_ID_EVENTS) || (mLogId == LOG_ID_SECURITY);
+ }
+
+ log_id_t getLogId() const { return static_cast<log_id_t>(mLogId); }
uid_t getUid(void) const { return mUid; }
pid_t getPid(void) const { return mPid; }
pid_t getTid(void) const { return mTid; }
+ uint32_t getTag() const { return mTag; }
unsigned short getDropped(void) const { return mMsg ? 0 : mDropped; }
unsigned short setDropped(unsigned short value) {
if (mMsg) {
@@ -77,8 +83,6 @@
static uint64_t getCurrentSequence(void) { return sequence.load(memory_order_relaxed); }
log_time getRealTime(void) const { return mRealTime; }
- uint32_t getTag(void) const;
-
static const uint64_t FLUSH_ERROR;
uint64_t flushTo(SocketClient *writer, LogBuffer *parent, bool privileged);
};
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index ef6c1ae..fe08846 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -25,7 +25,7 @@
#include <sys/uio.h>
#include <syslog.h>
-#include <log/logger.h>
+#include <private/android_logger.h>
#include <private/android_filesystem_config.h>
#include "LogBuffer.h"
diff --git a/logd/LogKlog.h b/logd/LogKlog.h
index 6e150e7..d812436 100644
--- a/logd/LogKlog.h
+++ b/logd/LogKlog.h
@@ -17,7 +17,7 @@
#ifndef _LOGD_LOG_KLOG_H__
#define _LOGD_LOG_KLOG_H__
-#include <log/logger.h>
+#include <private/android_logger.h>
#include <sysutils/SocketListener.h>
char *log_strntok_r(char *s, size_t *len, char **saveptr, size_t *sublen);
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index 61b7fd8..4a30e6d 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -23,7 +23,6 @@
#include <unistd.h>
#include <cutils/sockets.h>
-#include <log/logger.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 2c07984..61d4c49 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -21,6 +21,7 @@
#include <sys/types.h>
#include <cutils/sockets.h>
+#include <private/android_logger.h>
#include "FlushCommand.h"
#include "LogBuffer.h"
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index f69bc50..d4b48ef 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -23,7 +23,7 @@
#include <list>
-#include <log/logger.h>
+#include <android/log.h>
#include "LogStatistics.h"
@@ -547,6 +547,7 @@
}
spaces += spaces_total;
}
+ totalSize += sizeOf();
if (spaces < 0) spaces = 0;
output += android::base::StringPrintf("%*s%zu", spaces, "", totalSize);
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index bfaafa4..1f598af 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -42,8 +42,32 @@
std::unordered_map<TKey, TEntry> map;
+ size_t bucket_size() const {
+ size_t count = 0;
+ for (size_t idx = 0; idx < map.bucket_count(); ++idx) {
+ size_t bucket_size = map.bucket_size(idx);
+ if (bucket_size == 0) bucket_size = 1;
+ count += bucket_size;
+ }
+ float load_factor = map.max_load_factor();
+ if (load_factor < 1.0) return count;
+ return count * load_factor;
+ }
+
+ static const size_t unordered_map_per_entry_overhead = sizeof(void*);
+ static const size_t unordered_map_bucket_overhead = sizeof(void*);
+
public:
+ size_t size() const { return map.size(); }
+
+ // Estimate unordered_map memory usage.
+ size_t sizeOf() const {
+ return sizeof(*this) +
+ (size() * (sizeof(TEntry) + unordered_map_per_entry_overhead)) +
+ (bucket_size() * sizeof(size_t) + unordered_map_bucket_overhead);
+ }
+
typedef typename std::unordered_map<TKey, TEntry>::iterator iterator;
typedef typename std::unordered_map<TKey, TEntry>::const_iterator const_iterator;
@@ -155,6 +179,7 @@
}
return output;
}
+
};
namespace EntryBaseConstants {
@@ -472,7 +497,30 @@
// security tag list
tagTable_t securityTagTable;
+ size_t sizeOf() const {
+ size_t size = sizeof(*this) + pidTable.sizeOf() + tidTable.sizeOf() +
+ tagTable.sizeOf() + securityTagTable.sizeOf() +
+ (pidTable.size() * sizeof(pidTable_t::iterator)) +
+ (tagTable.size() * sizeof(tagTable_t::iterator));
+ for(auto it : pidTable) {
+ const char* name = it.second.getName();
+ if (name) size += strlen(name) + 1;
+ }
+ for(auto it : tidTable) {
+ const char* name = it.second.getName();
+ if (name) size += strlen(name) + 1;
+ }
+ log_id_for_each(id) {
+ size += uidTable[id].sizeOf();
+ size += uidTable[id].size() * sizeof(uidTable_t::iterator);
+ size += pidSystemTable[id].sizeOf();
+ size += pidSystemTable[id].size() * sizeof(pidSystemTable_t::iterator);
+ }
+ return size;
+ }
+
public:
+
LogStatistics();
void enableStatistics() { enable = true; }
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
index 8401953..12df994 100644
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -23,7 +23,7 @@
#include <list>
-#include <android/log.h>
+#include <log/log.h>
#include <sysutils/SocketClient.h>
class LogReader;
diff --git a/logd/LogUtils.h b/logd/LogUtils.h
index 6db4c51..44ac742 100644
--- a/logd/LogUtils.h
+++ b/logd/LogUtils.h
@@ -20,7 +20,7 @@
#include <sys/cdefs.h>
#include <sys/types.h>
-#include <android/log.h>
+#include <private/android_logger.h>
#include <sysutils/SocketClient.h>
// Hijack this header as a common include file used by most all sources
@@ -45,16 +45,6 @@
bool clientHasLogCredentials(uid_t uid, gid_t gid, pid_t pid);
bool clientHasLogCredentials(SocketClient *cli);
-// Furnished in main.cpp
-#define BOOL_DEFAULT_FLAG_TRUE_FALSE 0x1
-#define BOOL_DEFAULT_FALSE 0x0 // false if property not present
-#define BOOL_DEFAULT_TRUE 0x1 // true if property not present
-#define BOOL_DEFAULT_FLAG_PERSIST 0x2 // <key>, persist.<key>, ro.<key>
-#define BOOL_DEFAULT_FLAG_ENG 0x4 // off for user
-#define BOOL_DEFAULT_FLAG_SVELTE 0x8 // off for low_ram
-
-bool property_get_bool(const char *key, int def);
-
static inline bool worstUidEnabledForLogid(log_id_t id) {
return (id == LOG_ID_MAIN) || (id == LOG_ID_SYSTEM) ||
(id == LOG_ID_RADIO) || (id == LOG_ID_EVENTS);
diff --git a/logd/libaudit.c b/logd/libaudit.c
index 288a052..d2b212e 100644
--- a/logd/libaudit.c
+++ b/logd/libaudit.c
@@ -18,26 +18,20 @@
*
*/
-#define LOG_TAG "libaudit"
-
#include <errno.h>
#include <string.h>
#include <unistd.h>
-#include <android/log.h>
-
#include "libaudit.h"
/**
* Waits for an ack from the kernel
* @param fd
* The netlink socket fd
- * @param seq
- * The current sequence number were acking on
* @return
* This function returns 0 on success, else -errno.
*/
-static int get_ack(int fd, int16_t seq)
+static int get_ack(int fd)
{
int rc;
struct audit_message rep;
@@ -60,11 +54,6 @@
}
}
- if ((int16_t)rep.nlh.nlmsg_seq != seq) {
- SLOGW("Expected sequence number between user space and kernel space is out of skew, "
- "expected %u got %u", seq, rep.nlh.nlmsg_seq);
- }
-
return 0;
}
@@ -109,7 +98,6 @@
/* Ensure the message is not too big */
if (NLMSG_SPACE(size) > MAX_AUDIT_MESSAGE_LENGTH) {
- SLOGE("netlink message is too large");
return -EINVAL;
}
@@ -140,7 +128,6 @@
/* Not all the bytes were sent */
if (rc < 0) {
rc = -errno;
- SLOGE("Error sending data over the netlink socket: %s", strerror(-errno));
goto out;
} else if ((uint32_t) rc != req.nlh.nlmsg_len) {
rc = -EPROTO;
@@ -148,7 +135,7 @@
}
/* We sent all the bytes, get the ack */
- rc = get_ack(fd, sequence);
+ rc = get_ack(fd);
/* If the ack failed, return the error, else return the sequence number */
rc = (rc == 0) ? (int) sequence : rc;
@@ -156,7 +143,6 @@
out:
/* Don't let sequence roll to negative */
if (sequence < 0) {
- SLOGW("Auditd to Kernel sequence number has rolled over");
sequence = 0;
}
@@ -183,7 +169,6 @@
/* Let the kernel know this pid will be registering for audit events */
rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
if (rc < 0) {
- SLOGE("Could net set pid for audit events, error: %s", strerror(-rc));
return rc;
}
@@ -241,25 +226,21 @@
/* If request is non blocking and errno is EAGAIN, just return 0 */
return 0;
}
- SLOGE("Error receiving from netlink socket, error: %s", strerror(-rc));
return rc;
}
if (nladdrlen != sizeof(nladdr)) {
- SLOGE("Protocol fault, error: %s", strerror(EPROTO));
return -EPROTO;
}
/* Make sure the netlink message was not spoof'd */
if (nladdr.nl_pid) {
- SLOGE("Invalid netlink pid received, expected 0 got: %d", nladdr.nl_pid);
return -EINVAL;
}
/* Check if the reply from the kernel was ok */
if (!NLMSG_OK(&rep->nlh, (size_t)len)) {
rc = (len == sizeof(*rep)) ? -EFBIG : -EBADE;
- SLOGE("Bad kernel response %s", strerror(-rc));
}
return rc;
@@ -267,9 +248,5 @@
void audit_close(int fd)
{
- int rc = close(fd);
- if (rc < 0) {
- SLOGE("Attempting to close invalid fd %d, error: %s", fd, strerror(errno));
- }
- return;
+ close(fd);
}
diff --git a/logd/logd.rc b/logd/logd.rc
index 31ed4df..54349dd 100644
--- a/logd/logd.rc
+++ b/logd/logd.rc
@@ -2,10 +2,15 @@
socket logd stream 0666 logd logd
socket logdr seqpacket 0666 logd logd
socket logdw dgram 0222 logd logd
- group root system readproc
+ file /proc/kmsg r
+ file /dev/kmsg w
+ user logd
+ group logd system readproc
writepid /dev/cpuset/system-background/tasks
service logd-reinit /system/bin/logd --reinit
oneshot
disabled
+ user logd
+ group logd
writepid /dev/cpuset/system-background/tasks
diff --git a/logd/main.cpp b/logd/main.cpp
index a0cea25..d698976 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -39,12 +39,12 @@
#include <android-base/macros.h>
#include <cutils/properties.h>
#include <cutils/sched_policy.h>
+#include <cutils/files.h>
#include <cutils/sockets.h>
-#include <libminijail.h>
#include <log/event_tag_map.h>
#include <packagelistparser/packagelistparser.h>
#include <private/android_filesystem_config.h>
-#include <scoped_minijail.h>
+#include <private/android_logger.h>
#include <utils/threads.h>
#include "CommandListener.h"
@@ -89,29 +89,81 @@
// logd
//
-static int drop_privs() {
+static int drop_privs(bool klogd, bool auditd) {
+ // Tricky, if ro.build.type is "eng" then this is true because of the
+ // side effect that ro.debuggable == 1 as well, else it is false.
+ bool eng = __android_logger_property_get_bool("ro.build.type", BOOL_DEFAULT_FALSE);
+
struct sched_param param;
memset(¶m, 0, sizeof(param));
if (set_sched_policy(0, SP_BACKGROUND) < 0) {
- return -1;
+ android::prdebug("failed to set background scheduling policy");
+ if (!eng) return -1;
}
if (sched_setscheduler((pid_t) 0, SCHED_BATCH, ¶m) < 0) {
- return -1;
+ android::prdebug("failed to set batch scheduler");
+ if (!eng) return -1;
}
if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
+ android::prdebug("failed to set background cgroup");
+ if (!eng) return -1;
+ }
+
+ if (!eng && (prctl(PR_SET_DUMPABLE, 0) < 0)) {
+ android::prdebug("failed to clear PR_SET_DUMPABLE");
return -1;
}
+ if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
+ android::prdebug("failed to set PR_SET_KEEPCAPS");
+ if (!eng) return -1;
+ }
+
+ std::unique_ptr<struct _cap_struct, int(*)(void *)> caps(cap_init(), cap_free);
+ if (cap_clear(caps.get()) < 0) return -1;
+ cap_value_t cap_value[] = {
+ CAP_SETGID, // must be first for below
+ klogd ? CAP_SYSLOG : CAP_SETGID,
+ auditd ? CAP_AUDIT_CONTROL : CAP_SETGID
+ };
+ if (cap_set_flag(caps.get(), CAP_PERMITTED,
+ arraysize(cap_value), cap_value,
+ CAP_SET) < 0) return -1;
+ if (cap_set_flag(caps.get(), CAP_EFFECTIVE,
+ arraysize(cap_value), cap_value,
+ CAP_SET) < 0) return -1;
+ if (cap_set_proc(caps.get()) < 0) {
+ android::prdebug("failed to set CAP_SETGID, CAP_SYSLOG or CAP_AUDIT_CONTROL (%d)", errno);
+ if (!eng) return -1;
+ }
+
gid_t groups[] = { AID_READPROC };
- ScopedMinijail j(minijail_new());
- minijail_set_supplementary_gids(j.get(), arraysize(groups), groups);
- minijail_change_uid(j.get(), AID_LOGD);
- minijail_change_gid(j.get(), AID_LOGD);
- minijail_use_caps(j.get(), CAP_TO_MASK(CAP_SYSLOG) | CAP_TO_MASK(CAP_AUDIT_CONTROL));
- minijail_enter(j.get());
+
+ if (setgroups(arraysize(groups), groups) == -1) {
+ android::prdebug("failed to set AID_READPROC groups");
+ if (!eng) return -1;
+ }
+
+ if (setgid(AID_LOGD) != 0) {
+ android::prdebug("failed to set AID_LOGD gid");
+ if (!eng) return -1;
+ }
+
+ if (setuid(AID_LOGD) != 0) {
+ android::prdebug("failed to set AID_LOGD uid");
+ if (!eng) return -1;
+ }
+
+ if (cap_set_flag(caps.get(), CAP_PERMITTED, 1, cap_value, CAP_CLEAR) < 0) return -1;
+ if (cap_set_flag(caps.get(), CAP_EFFECTIVE, 1, cap_value, CAP_CLEAR) < 0) return -1;
+ if (cap_set_proc(caps.get()) < 0) {
+ android::prdebug("failed to clear CAP_SETGID (%d)", errno);
+ if (!eng) return -1;
+ }
+
return 0;
}
@@ -130,60 +182,6 @@
return !*cp || !!strchr(sep, *cp);
}
-bool property_get_bool(const char *key, int flag) {
- char def[PROPERTY_VALUE_MAX];
- char property[PROPERTY_VALUE_MAX];
- def[0] = '\0';
- if (flag & BOOL_DEFAULT_FLAG_PERSIST) {
- char newkey[PROPERTY_KEY_MAX];
- snprintf(newkey, sizeof(newkey), "ro.%s", key);
- property_get(newkey, property, "");
- // persist properties set by /data require inoculation with
- // logd-reinit. They may be set in init.rc early and function, but
- // otherwise are defunct unless reset. Do not rely on persist
- // properties for startup-only keys unless you are willing to restart
- // logd daemon (not advised).
- snprintf(newkey, sizeof(newkey), "persist.%s", key);
- property_get(newkey, def, property);
- }
-
- property_get(key, property, def);
-
- if (check_flag(property, "true")) {
- return true;
- }
- if (check_flag(property, "false")) {
- return false;
- }
- if (check_flag(property, "eng")) {
- flag |= BOOL_DEFAULT_FLAG_ENG;
- }
- // this is really a "not" flag
- if (check_flag(property, "svelte")) {
- flag |= BOOL_DEFAULT_FLAG_SVELTE;
- }
-
- // Sanity Check
- if (flag & (BOOL_DEFAULT_FLAG_SVELTE | BOOL_DEFAULT_FLAG_ENG)) {
- flag &= ~BOOL_DEFAULT_FLAG_TRUE_FALSE;
- flag |= BOOL_DEFAULT_TRUE;
- }
-
- if ((flag & BOOL_DEFAULT_FLAG_SVELTE)
- && property_get_bool("ro.config.low_ram",
- BOOL_DEFAULT_FALSE)) {
- return false;
- }
- if (flag & BOOL_DEFAULT_FLAG_ENG) {
- property_get("ro.debuggable", property, "");
- if (strcmp(property, "1")) {
- return false;
- }
- }
-
- return (flag & BOOL_DEFAULT_FLAG_TRUE_FALSE) != BOOL_DEFAULT_FALSE;
-}
-
static int fdDmesg = -1;
void android::prdebug(const char *fmt, ...) {
if (fdDmesg < 0) {
@@ -237,11 +235,16 @@
set_sched_policy(0, SP_BACKGROUND);
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND);
- // If we are AID_ROOT, we should drop to AID_SYSTEM, if we are anything
- // else, we have even lesser privileges and accept our fate. Not worth
- // checking for error returns setting this thread's privileges.
- (void)setgid(AID_SYSTEM);
- (void)setuid(AID_SYSTEM);
+ cap_t caps = cap_init();
+ (void)cap_clear(caps);
+ (void)cap_set_proc(caps);
+ (void)cap_free(caps);
+
+ // If we are AID_ROOT, we should drop to AID_LOGD+AID_SYSTEM, if we are
+ // anything else, we have even lesser privileges and accept our fate. Not
+ // worth checking for error returns setting this thread's privileges.
+ (void)setgid(AID_SYSTEM); // readonly access to /data/system/packages.list
+ (void)setuid(AID_LOGD); // access to everything logd.
while (reinit_running && !sem_wait(&reinit) && reinit_running) {
@@ -359,6 +362,39 @@
}
}
+static int issueReinit() {
+ cap_t caps = cap_init();
+ (void)cap_clear(caps);
+ (void)cap_set_proc(caps);
+ (void)cap_free(caps);
+
+ int sock = TEMP_FAILURE_RETRY(
+ socket_local_client("logd",
+ ANDROID_SOCKET_NAMESPACE_RESERVED,
+ SOCK_STREAM));
+ if (sock < 0) return -errno;
+
+ static const char reinitStr[] = "reinit";
+ ssize_t ret = TEMP_FAILURE_RETRY(write(sock, reinitStr, sizeof(reinitStr)));
+ if (ret < 0) return -errno;
+
+ struct pollfd p;
+ memset(&p, 0, sizeof(p));
+ p.fd = sock;
+ p.events = POLLIN;
+ ret = TEMP_FAILURE_RETRY(poll(&p, 1, 1000));
+ if (ret < 0) return -errno;
+ if ((ret == 0) || !(p.revents & POLLIN)) return -ETIME;
+
+ static const char success[] = "success";
+ char buffer[sizeof(success) - 1];
+ memset(buffer, 0, sizeof(buffer));
+ ret = TEMP_FAILURE_RETRY(read(sock, buffer, sizeof(buffer)));
+ if (ret < 0) return -errno;
+
+ return strncmp(buffer, success, sizeof(success) - 1) != 0;
+}
+
// Foreground waits for exit of the main persistent threads
// that are started here. The threads are created to manage
// UNIX domain client sockets for writing, reading and
@@ -366,50 +402,31 @@
// logging plugins like auditd and restart control. Additional
// transitory per-client threads are created for each reader.
int main(int argc, char *argv[]) {
- int fdPmesg = -1;
- bool klogd = property_get_bool("logd.kernel",
- BOOL_DEFAULT_TRUE |
- BOOL_DEFAULT_FLAG_PERSIST |
- BOOL_DEFAULT_FLAG_ENG |
- BOOL_DEFAULT_FLAG_SVELTE);
- if (klogd) {
- fdPmesg = open("/proc/kmsg", O_RDONLY | O_NDELAY);
- }
- fdDmesg = open("/dev/kmsg", O_WRONLY);
-
// issue reinit command. KISS argument parsing.
if ((argc > 1) && argv[1] && !strcmp(argv[1], "--reinit")) {
- int sock = TEMP_FAILURE_RETRY(
- socket_local_client("logd",
- ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_STREAM));
- if (sock < 0) {
- return -errno;
+ return issueReinit();
+ }
+
+ static const char dev_kmsg[] = "/dev/kmsg";
+ fdDmesg = android_get_control_file(dev_kmsg);
+ if (fdDmesg < 0) {
+ fdDmesg = TEMP_FAILURE_RETRY(open(dev_kmsg, O_WRONLY | O_CLOEXEC));
+ }
+
+ int fdPmesg = -1;
+ bool klogd = __android_logger_property_get_bool("logd.kernel",
+ BOOL_DEFAULT_TRUE |
+ BOOL_DEFAULT_FLAG_PERSIST |
+ BOOL_DEFAULT_FLAG_ENG |
+ BOOL_DEFAULT_FLAG_SVELTE);
+ if (klogd) {
+ static const char proc_kmsg[] = "/proc/kmsg";
+ fdPmesg = android_get_control_file(proc_kmsg);
+ if (fdPmesg < 0) {
+ fdPmesg = TEMP_FAILURE_RETRY(open(proc_kmsg,
+ O_RDONLY | O_NDELAY | O_CLOEXEC));
}
- static const char reinit[] = "reinit";
- ssize_t ret = TEMP_FAILURE_RETRY(write(sock, reinit, sizeof(reinit)));
- if (ret < 0) {
- return -errno;
- }
- struct pollfd p;
- memset(&p, 0, sizeof(p));
- p.fd = sock;
- p.events = POLLIN;
- ret = TEMP_FAILURE_RETRY(poll(&p, 1, 1000));
- if (ret < 0) {
- return -errno;
- }
- if ((ret == 0) || !(p.revents & POLLIN)) {
- return -ETIME;
- }
- static const char success[] = "success";
- char buffer[sizeof(success) - 1];
- memset(buffer, 0, sizeof(buffer));
- ret = TEMP_FAILURE_RETRY(read(sock, buffer, sizeof(buffer)));
- if (ret < 0) {
- return -errno;
- }
- return strncmp(buffer, success, sizeof(success) - 1) != 0;
+ if (fdPmesg < 0) android::prdebug("Failed to open %s\n", proc_kmsg);
}
// Reinit Thread
@@ -434,7 +451,10 @@
pthread_attr_destroy(&attr);
}
- if (drop_privs() != 0) {
+ bool auditd = __android_logger_property_get_bool("logd.auditd",
+ BOOL_DEFAULT_TRUE |
+ BOOL_DEFAULT_FLAG_PERSIST);
+ if (drop_privs(klogd, auditd) != 0) {
return -1;
}
@@ -451,11 +471,11 @@
signal(SIGHUP, reinit_signal_handler);
- if (property_get_bool("logd.statistics",
- BOOL_DEFAULT_TRUE |
- BOOL_DEFAULT_FLAG_PERSIST |
- BOOL_DEFAULT_FLAG_ENG |
- BOOL_DEFAULT_FLAG_SVELTE)) {
+ if (__android_logger_property_get_bool("logd.statistics",
+ BOOL_DEFAULT_TRUE |
+ BOOL_DEFAULT_FLAG_PERSIST |
+ BOOL_DEFAULT_FLAG_ENG |
+ BOOL_DEFAULT_FLAG_SVELTE)) {
logBuf->enableStatistics();
}
@@ -489,17 +509,14 @@
// initiated log messages. New log entries are added to LogBuffer
// and LogReader is notified to send updates to connected clients.
- bool auditd = property_get_bool("logd.auditd",
- BOOL_DEFAULT_TRUE |
- BOOL_DEFAULT_FLAG_PERSIST);
LogAudit *al = NULL;
if (auditd) {
al = new LogAudit(logBuf, reader,
- property_get_bool("logd.auditd.dmesg",
- BOOL_DEFAULT_TRUE |
- BOOL_DEFAULT_FLAG_PERSIST)
- ? fdDmesg
- : -1);
+ __android_logger_property_get_bool(
+ "logd.auditd.dmesg",
+ BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST)
+ ? fdDmesg
+ : -1);
}
LogKlog *kl = NULL;
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index cac8bce..254a3f8 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -23,11 +23,11 @@
#include <string>
-#include <android/log.h>
+#include <android-base/macros.h>
#include <android-base/stringprintf.h>
#include <cutils/sockets.h>
#include <gtest/gtest.h>
-#include <log/logger.h>
+#include <log/log.h>
#include "../LogReader.h" // pickup LOGD_SNDTIMEO
@@ -352,7 +352,7 @@
"/dev/log/system", "/dev/log_system",
};
- for (unsigned int i = 0; i < (sizeof(loggers) / sizeof(loggers[0])); ++i) {
+ for (unsigned int i = 0; i < arraysize(loggers); ++i) {
fd = open(loggers[i], O_RDONLY);
if (fd < 0) {
continue;
@@ -435,12 +435,12 @@
static const unsigned int log_latency = 4;
static const unsigned int log_delay = 5;
- unsigned long ns[sizeof(benchmarks) / sizeof(benchmarks[0])];
+ unsigned long ns[arraysize(benchmarks)];
memset(ns, 0, sizeof(ns));
while (fgets(buffer, sizeof(buffer), fp)) {
- for (unsigned i = 0; i < sizeof(ns) / sizeof(ns[0]); ++i) {
+ for (unsigned i = 0; i < arraysize(ns); ++i) {
char *cp = strstr(buffer, benchmarks[i]);
if (!cp) {
continue;
@@ -471,7 +471,7 @@
EXPECT_GE(20000000UL, ns[log_delay]); // 10500289 user
- for (unsigned i = 0; i < sizeof(ns) / sizeof(ns[0]); ++i) {
+ for (unsigned i = 0; i < arraysize(ns); ++i) {
EXPECT_NE(0UL, ns[i]);
}
diff --git a/logwrapper/Android.bp b/logwrapper/Android.bp
index 41f0726..7ee0464 100644
--- a/logwrapper/Android.bp
+++ b/logwrapper/Android.bp
@@ -14,7 +14,6 @@
local_include_dirs: ["include"],
cflags: [
"-Werror",
- "-std=gnu99",
],
}
@@ -31,6 +30,5 @@
],
cflags: [
"-Werror",
- "-std=gnu99",
],
}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 50ee110..4e766bb 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -295,6 +295,10 @@
# Make sure /sys/kernel/debug (if present) is labeled properly
restorecon_recursive /sys/kernel/debug
+ # On systems with tracefs, tracing is a separate mount, so make sure
+ # it too is correctly labeled
+ restorecon_recursive /sys/kernel/debug/tracing
+
# We chown/chmod /cache again so because mount is run as root + defaults
chown system cache /cache
chmod 0770 /cache
@@ -562,7 +566,7 @@
on nonencrypted
# A/B update verifier that marks a successful boot.
- exec - root -- /system/bin/update_verifier nonencrypted
+ exec - root cache -- /system/bin/update_verifier nonencrypted
class_start main
class_start late_start
@@ -585,12 +589,12 @@
on property:vold.decrypt=trigger_restart_min_framework
# A/B update verifier that marks a successful boot.
- exec - root -- /system/bin/update_verifier trigger_restart_min_framework
+ exec - root cache -- /system/bin/update_verifier trigger_restart_min_framework
class_start main
on property:vold.decrypt=trigger_restart_framework
# A/B update verifier that marks a successful boot.
- exec - root -- /system/bin/update_verifier trigger_restart_framework
+ exec - root cache -- /system/bin/update_verifier trigger_restart_framework
class_start main
class_start late_start
@@ -647,13 +651,3 @@
service flash_recovery /system/bin/install-recovery.sh
class main
oneshot
-
-service hwservicemanager /system/bin/hwservicemanager
- user system
- disabled
- group system readproc
- critical
- writepid /dev/cpuset/system-background/tasks
-
-on property:hwservicemanager.ready=true
- class_start hal
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index 807f9bc..bfddcfa 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -1,6 +1,8 @@
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
+ user root
+ group root readproc
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index 3bfa0af..1bbb007 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -1,6 +1,8 @@
service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
class main
priority -20
+ user root
+ group root readproc
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
@@ -13,6 +15,8 @@
service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
class main
priority -20
+ user root
+ group root readproc
socket zygote_secondary stream 660 root system
onrestart restart zygote
writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index 13ffd7e..6742127 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -1,6 +1,8 @@
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
+ user root
+ group root readproc
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 5640490..81a7609 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -1,6 +1,8 @@
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
class main
priority -20
+ user root
+ group root readproc
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
@@ -13,6 +15,8 @@
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
class main
priority -20
+ user root
+ group root readproc
socket zygote_secondary stream 660 root system
onrestart restart zygote
writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 4852fa4..5319ff4 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -42,7 +42,6 @@
LOCAL_CFLAGS += $(common_cflags)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/upstream-netbsd/include/
-LOCAL_CONLYFLAGS += -std=gnu99
LOCAL_SHARED_LIBRARIES := \
libcutils \
diff --git a/trusty/gatekeeper/trusty_gatekeeper_ipc.c b/trusty/gatekeeper/trusty_gatekeeper_ipc.c
index ae536c5..45e65a7 100644
--- a/trusty/gatekeeper/trusty_gatekeeper_ipc.c
+++ b/trusty/gatekeeper/trusty_gatekeeper_ipc.c
@@ -17,8 +17,10 @@
#define LOG_TAG "TrustyGateKeeper"
#include <errno.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include <android/log.h>
#include <trusty/tipc.h>
diff --git a/trusty/keymaster/trusty_keymaster_ipc.c b/trusty/keymaster/trusty_keymaster_ipc.c
index 0159bce..8755093 100644
--- a/trusty/keymaster/trusty_keymaster_ipc.c
+++ b/trusty/keymaster/trusty_keymaster_ipc.c
@@ -21,6 +21,7 @@
#include <errno.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include <android/log.h>
#include <trusty/tipc.h>
diff --git a/trusty/libtrusty/trusty.c b/trusty/libtrusty/trusty.c
index ba16bee..2398a53 100644
--- a/trusty/libtrusty/trusty.c
+++ b/trusty/libtrusty/trusty.c
@@ -22,6 +22,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
#include <android/log.h>
diff --git a/trusty/nvram/trusty_nvram_implementation.cpp b/trusty/nvram/trusty_nvram_implementation.cpp
index caa25ab..ddaf333 100644
--- a/trusty/nvram/trusty_nvram_implementation.cpp
+++ b/trusty/nvram/trusty_nvram_implementation.cpp
@@ -20,6 +20,7 @@
#include <errno.h>
#include <string.h>
+#include <unistd.h>
#include <android/log.h>
#include <hardware/nvram.h>
diff --git a/trusty/storage/proxy/ipc.c b/trusty/storage/proxy/ipc.c
index b4748e2..57cf600 100644
--- a/trusty/storage/proxy/ipc.c
+++ b/trusty/storage/proxy/ipc.c
@@ -20,6 +20,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/uio.h>
+#include <unistd.h>
#include <trusty/tipc.h>
diff --git a/trusty/storage/proxy/rpmb.c b/trusty/storage/proxy/rpmb.c
index 9130458..9c79105 100644
--- a/trusty/storage/proxy/rpmb.c
+++ b/trusty/storage/proxy/rpmb.c
@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
+#include <unistd.h>
#include <linux/major.h>
#include <linux/mmc/ioctl.h>