Merge "Revert "Revert "android_ids: move to bionic"""
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..b44c296
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1 @@
+subdirs = ["*"]
diff --git a/adb/Android.mk b/adb/Android.mk
index 16ed991..fab8c87 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -330,6 +330,7 @@
LOCAL_STATIC_LIBRARIES := \
libadbd \
libbase \
+ libbootloader_message \
libfs_mgr \
libfec \
libfec_rs \
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index ff2d76d..ec9b1c3 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -207,11 +207,6 @@
}
if (S_ISREG(st.st_mode)) {
- if (!android::base::EndsWith(path, ".adb_key")) {
- LOG(INFO) << "skipping non-adb_key '" << path << "'";
- return false;
- }
-
return read_key_file(path);
} else if (S_ISDIR(st.st_mode)) {
if (!allow_dir) {
@@ -236,7 +231,12 @@
continue;
}
- result |= read_keys((path + OS_PATH_SEPARATOR + name).c_str(), false);
+ if (!android::base::EndsWith(name, ".adb_key")) {
+ LOG(INFO) << "skipping non-adb_key '" << path << "/" << name << "'";
+ continue;
+ }
+
+ result |= read_key_file((path + OS_PATH_SEPARATOR + name));
}
return result;
}
diff --git a/adb/adb_trace.cpp b/adb/adb_trace.cpp
index 002d061..c369d60 100644
--- a/adb/adb_trace.cpp
+++ b/adb/adb_trace.cpp
@@ -109,8 +109,8 @@
}
std::unordered_map<std::string, int> trace_flags = {
- {"1", 0},
- {"all", 0},
+ {"1", -1},
+ {"all", -1},
{"adb", ADB},
{"sockets", SOCKETS},
{"packets", PACKETS},
@@ -133,8 +133,8 @@
continue;
}
- if (flag->second == 0) {
- // 0 is used for the special values "1" and "all" that enable all
+ if (flag->second == -1) {
+ // -1 is used for the special values "1" and "all" that enable all
// tracing.
adb_trace_mask = ~0;
return;
diff --git a/adb/adb_trace.h b/adb/adb_trace.h
index 5206a99..aaffa29 100644
--- a/adb/adb_trace.h
+++ b/adb/adb_trace.h
@@ -58,4 +58,8 @@
void adb_trace_init(char**);
void adb_trace_enable(AdbTrace trace_tag);
+#define ATRACE_TAG ATRACE_TAG_ADB
+#include <cutils/trace.h>
+#include <utils/Trace.h>
+
#endif /* __ADB_TRACE_H */
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 4ec0fc2..d583516 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -23,6 +23,8 @@
#include <stdlib.h>
#include <unistd.h>
+#include <thread>
+
#include <android-base/errors.h>
#include <android-base/file.h>
#include <android-base/logging.h>
@@ -33,6 +35,7 @@
#include "adb_listeners.h"
#include "adb_utils.h"
#include "commandline.h"
+#include "sysdeps/chrono.h"
#include "transport.h"
static std::string GetLogFilePath() {
@@ -113,8 +116,18 @@
local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
std::string error;
- if (install_listener(socket_spec, "*smartsocket*", nullptr, 0, nullptr, &error)) {
- fatal("could not install *smartsocket* listener: %s", error.c_str());
+
+ auto start = std::chrono::steady_clock::now();
+
+ // If we told a previous adb server to quit because of version mismatch, we can get to this
+ // point before it's finished exiting. Retry for a while to give it some time.
+ while (install_listener(socket_spec, "*smartsocket*", nullptr, 0, nullptr, &error) !=
+ INSTALL_STATUS_OK) {
+ if (std::chrono::steady_clock::now() - start > 0.5s) {
+ fatal("could not install *smartsocket* listener: %s", error.c_str());
+ }
+
+ std::this_thread::sleep_for(100ms);
}
if (is_daemon) {
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index 76119ef..271943d 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -720,13 +720,7 @@
}
static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath,
- const char* name=nullptr) {
- struct stat st;
- if (!sync_stat_fallback(sc, rpath, &st)) {
- sc.Error("stat failed when trying to receive %s: %s", rpath, strerror(errno));
- return false;
- }
-
+ const char* name, uint64_t expected_size) {
if (!sc.SendRequest(ID_RECV, rpath)) return false;
adb_unlink(lpath);
@@ -778,7 +772,7 @@
bytes_copied += msg.data.size;
sc.RecordBytesTransferred(msg.data.size);
- sc.ReportProgress(name != nullptr ? name : rpath, bytes_copied, st.st_size);
+ sc.ReportProgress(name != nullptr ? name : rpath, bytes_copied, expected_size);
}
sc.RecordFilesTransferred(1);
@@ -1121,7 +1115,7 @@
continue;
}
- if (!sync_recv(sc, ci.rpath.c_str(), ci.lpath.c_str())) {
+ if (!sync_recv(sc, ci.rpath.c_str(), ci.lpath.c_str(), nullptr, ci.size)) {
return false;
}
@@ -1232,7 +1226,7 @@
sc.NewTransfer();
sc.SetExpectedTotalBytes(src_st.st_size);
- if (!sync_recv(sc, src_path, dst_path, name)) {
+ if (!sync_recv(sc, src_path, dst_path, name, src_st.st_size)) {
success = false;
continue;
}
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index 43c877e..e667bf8 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -39,10 +39,13 @@
#include "adb.h"
#include "adb_io.h"
+#include "adb_trace.h"
#include "adb_utils.h"
#include "security_log_tags.h"
#include "sysdeps/errno.h"
+using android::base::StringPrintf;
+
static bool should_use_fs_config(const std::string& path) {
// TODO: use fs_config to configure permissions on /data.
return android::base::StartsWith(path, "/system/") ||
@@ -152,7 +155,7 @@
if (!d) goto done;
while ((de = readdir(d.get()))) {
- std::string filename(android::base::StringPrintf("%s/%s", path, de->d_name));
+ std::string filename(StringPrintf("%s/%s", path, de->d_name));
struct stat st;
if (lstat(filename.c_str(), &st) == 0) {
@@ -191,7 +194,7 @@
}
static bool SendSyncFailErrno(int fd, const std::string& reason) {
- return SendSyncFail(fd, android::base::StringPrintf("%s: %s", reason.c_str(), strerror(errno)));
+ return SendSyncFail(fd, StringPrintf("%s: %s", reason.c_str(), strerror(errno)));
}
static bool handle_send_file(int s, const char* path, uid_t uid, gid_t gid, uint64_t capabilities,
@@ -433,9 +436,31 @@
return WriteFdExactly(s, &msg.data, sizeof(msg.data));
}
+static const char* sync_id_to_name(uint32_t id) {
+ switch (id) {
+ case ID_LSTAT_V1:
+ return "lstat_v1";
+ case ID_LSTAT_V2:
+ return "lstat_v2";
+ case ID_STAT_V2:
+ return "stat_v2";
+ case ID_LIST:
+ return "list";
+ case ID_SEND:
+ return "send";
+ case ID_RECV:
+ return "recv";
+ case ID_QUIT:
+ return "quit";
+ default:
+ return "???";
+ }
+}
+
static bool handle_sync_command(int fd, std::vector<char>& buffer) {
D("sync: waiting for request");
+ ATRACE_CALL();
SyncRequest request;
if (!ReadFdExactly(fd, &request, sizeof(request))) {
SendSyncFail(fd, "command read failure");
@@ -453,9 +478,11 @@
}
name[path_length] = 0;
- const char* id = reinterpret_cast<const char*>(&request.id);
- D("sync: '%.4s' '%s'", id, name);
+ std::string id_name = sync_id_to_name(request.id);
+ std::string trace_name = StringPrintf("%s(%s)", id_name.c_str(), name);
+ ATRACE_NAME(trace_name.c_str());
+ D("sync: %s('%s')", id_name.c_str(), name);
switch (request.id) {
case ID_LSTAT_V1:
if (!do_lstat_v1(fd, name)) return false;
@@ -476,8 +503,7 @@
case ID_QUIT:
return false;
default:
- SendSyncFail(
- fd, android::base::StringPrintf("unknown command '%.4s' (%08x)", id, request.id));
+ SendSyncFail(fd, StringPrintf("unknown command %08x", request.id));
return false;
}
diff --git a/adb/services.cpp b/adb/services.cpp
index 2fbc15a..df1b134 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -39,6 +39,7 @@
#if !ADB_HOST
#include <android-base/properties.h>
+#include <bootloader_message/bootloader_message.h>
#include <cutils/android_reboot.h>
#include <private/android_logger.h>
#endif
@@ -133,17 +134,12 @@
return false;
}
- const char* const recovery_dir = "/cache/recovery";
- const char* const command_file = "/cache/recovery/command";
- // Ensure /cache/recovery exists.
- if (adb_mkdir(recovery_dir, 0770) == -1 && errno != EEXIST) {
- D("Failed to create directory '%s': %s", recovery_dir, strerror(errno));
- return false;
- }
-
- bool write_status = android::base::WriteStringToFile(
- auto_reboot ? "--sideload_auto_reboot" : "--sideload", command_file);
- if (!write_status) {
+ const std::vector<std::string> options = {
+ auto_reboot ? "--sideload_auto_reboot" : "--sideload"
+ };
+ std::string err;
+ if (!write_bootloader_message(options, &err)) {
+ D("Failed to set bootloader message: %s", err.c_str());
return false;
}
diff --git a/adb/sysdeps_win32_test.cpp b/adb/sysdeps_win32_test.cpp
old mode 100755
new mode 100644
diff --git a/adb/trace.sh b/adb/trace.sh
new file mode 100755
index 0000000..49e5026
--- /dev/null
+++ b/adb/trace.sh
@@ -0,0 +1,17 @@
+set -e
+
+if ! [ -e $ANDROID_BUILD_TOP/external/chromium-trace/systrace.py ]; then
+ echo "error: can't find systrace.py at \$ANDROID_BUILD_TOP/external/chromium-trace/systrace.py"
+ exit 1
+fi
+
+adb shell "sleep 1; atrace -b 65536 --async_start adb sched power freq idle disk mmc load"
+adb shell killall adbd
+adb wait-for-device
+echo "press enter to finish..."
+read
+TRACE_TEMP=`mktemp /tmp/trace.XXXXXX`
+echo Saving trace to ${TRACE_TEMP}, html file to ${TRACE_TEMP}.html
+adb shell atrace --async_stop -z > ${TRACE_TEMP}
+$ANDROID_BUILD_TOP/external/chromium-trace/systrace.py --from-file=${TRACE_TEMP} -o ${TRACE_TEMP}.html
+chrome ${TRACE_TEMP}.html
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 7b82b19..60f3b5c 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -37,6 +37,7 @@
#include "adb.h"
#include "adb_auth.h"
+#include "adb_trace.h"
#include "adb_utils.h"
#include "diagnose_usb.h"
@@ -52,16 +53,15 @@
const char* const kFeatureStat2 = "stat_v2";
static std::string dump_packet(const char* name, const char* func, apacket* p) {
- unsigned command = p->msg.command;
- int len = p->msg.data_length;
- char cmd[9];
- char arg0[12], arg1[12];
- int n;
+ unsigned command = p->msg.command;
+ int len = p->msg.data_length;
+ char cmd[9];
+ char arg0[12], arg1[12];
+ int n;
for (n = 0; n < 4; n++) {
- int b = (command >> (n*8)) & 255;
- if (b < 32 || b >= 127)
- break;
+ int b = (command >> (n * 8)) & 255;
+ if (b < 32 || b >= 127) break;
cmd[n] = (char)b;
}
if (n == 4) {
@@ -82,25 +82,24 @@
else
snprintf(arg1, sizeof arg1, "0x%x", p->msg.arg1);
- std::string result = android::base::StringPrintf("%s: %s: [%s] arg0=%s arg1=%s (len=%d) ",
- name, func, cmd, arg0, arg1, len);
+ std::string result = android::base::StringPrintf("%s: %s: [%s] arg0=%s arg1=%s (len=%d) ", name,
+ func, cmd, arg0, arg1, len);
result += dump_hex(p->data, len);
return result;
}
-static int
-read_packet(int fd, const char* name, apacket** ppacket)
-{
+static int read_packet(int fd, const char* name, apacket** ppacket) {
+ ATRACE_NAME("read_packet");
char buff[8];
if (!name) {
snprintf(buff, sizeof buff, "fd=%d", fd);
name = buff;
}
- char* p = reinterpret_cast<char*>(ppacket); /* really read a packet address */
+ char* p = reinterpret_cast<char*>(ppacket); /* really read a packet address */
int len = sizeof(apacket*);
- while(len > 0) {
+ while (len > 0) {
int r = adb_read(fd, p, len);
- if(r > 0) {
+ if (r > 0) {
len -= r;
p += r;
} else {
@@ -113,20 +112,19 @@
return 0;
}
-static int
-write_packet(int fd, const char* name, apacket** ppacket)
-{
+static int write_packet(int fd, const char* name, apacket** ppacket) {
+ ATRACE_NAME("write_packet");
char buff[8];
if (!name) {
snprintf(buff, sizeof buff, "fd=%d", fd);
name = buff;
}
VLOG(TRANSPORT) << dump_packet(name, "to remote", *ppacket);
- char* p = reinterpret_cast<char*>(ppacket); /* we really write the packet address */
+ char* p = reinterpret_cast<char*>(ppacket); /* we really write the packet address */
int len = sizeof(apacket*);
- while(len > 0) {
+ while (len > 0) {
int r = adb_write(fd, p, len);
- if(r > 0) {
+ if (r > 0) {
len -= r;
p += r;
} else {
@@ -137,16 +135,15 @@
return 0;
}
-static void transport_socket_events(int fd, unsigned events, void *_t)
-{
- atransport *t = reinterpret_cast<atransport*>(_t);
+static void transport_socket_events(int fd, unsigned events, void* _t) {
+ atransport* t = reinterpret_cast<atransport*>(_t);
D("transport_socket_events(fd=%d, events=%04x,...)", fd, events);
- if(events & FDE_READ){
- apacket *p = 0;
- if(read_packet(fd, t->serial, &p)){
+ if (events & FDE_READ) {
+ apacket* p = 0;
+ if (read_packet(fd, t->serial, &p)) {
D("%s: failed to read packet from transport socket on fd %d", t->serial, fd);
} else {
- handle_packet(p, (atransport *) _t);
+ handle_packet(p, (atransport*)_t);
}
}
}
@@ -180,40 +177,43 @@
// read_transport thread reads data from a transport (representing a usb/tcp connection),
// and makes the main thread call handle_packet().
static void read_transport_thread(void* _t) {
- atransport *t = reinterpret_cast<atransport*>(_t);
- apacket *p;
+ atransport* t = reinterpret_cast<atransport*>(_t);
+ apacket* p;
- adb_thread_setname(android::base::StringPrintf("<-%s",
- (t->serial != nullptr ? t->serial : "transport")));
- D("%s: starting read_transport thread on fd %d, SYNC online (%d)",
- t->serial, t->fd, t->sync_token + 1);
+ adb_thread_setname(
+ android::base::StringPrintf("<-%s", (t->serial != nullptr ? t->serial : "transport")));
+ D("%s: starting read_transport thread on fd %d, SYNC online (%d)", t->serial, t->fd,
+ t->sync_token + 1);
p = get_apacket();
p->msg.command = A_SYNC;
p->msg.arg0 = 1;
p->msg.arg1 = ++(t->sync_token);
p->msg.magic = A_SYNC ^ 0xffffffff;
- if(write_packet(t->fd, t->serial, &p)) {
+ if (write_packet(t->fd, t->serial, &p)) {
put_apacket(p);
D("%s: failed to write SYNC packet", t->serial);
goto oops;
}
D("%s: data pump started", t->serial);
- for(;;) {
+ for (;;) {
+ ATRACE_NAME("read_transport loop");
p = get_apacket();
- if(t->read_from_remote(p, t) == 0){
- D("%s: received remote packet, sending to transport",
- t->serial);
- if(write_packet(t->fd, t->serial, &p)){
+ {
+ ATRACE_NAME("read_transport read_remote");
+ if (t->read_from_remote(p, t) != 0) {
+ D("%s: remote read failed for transport", t->serial);
put_apacket(p);
- D("%s: failed to write apacket to transport", t->serial);
- goto oops;
+ break;
}
- } else {
- D("%s: remote read failed for transport", t->serial);
+ }
+
+ D("%s: received remote packet, sending to transport", t->serial);
+ if (write_packet(t->fd, t->serial, &p)) {
put_apacket(p);
- break;
+ D("%s: failed to write apacket to transport", t->serial);
+ goto oops;
}
}
@@ -223,7 +223,7 @@
p->msg.arg0 = 0;
p->msg.arg1 = 0;
p->msg.magic = A_SYNC ^ 0xffffffff;
- if(write_packet(t->fd, t->serial, &p)) {
+ if (write_packet(t->fd, t->serial, &p)) {
put_apacket(p);
D("%s: failed to write SYNC apacket to transport", t->serial);
}
@@ -237,38 +237,38 @@
// write_transport thread gets packets sent by the main thread (through send_packet()),
// and writes to a transport (representing a usb/tcp connection).
static void write_transport_thread(void* _t) {
- atransport *t = reinterpret_cast<atransport*>(_t);
- apacket *p;
+ atransport* t = reinterpret_cast<atransport*>(_t);
+ apacket* p;
int active = 0;
- adb_thread_setname(android::base::StringPrintf("->%s",
- (t->serial != nullptr ? t->serial : "transport")));
- D("%s: starting write_transport thread, reading from fd %d",
- t->serial, t->fd);
+ adb_thread_setname(
+ android::base::StringPrintf("->%s", (t->serial != nullptr ? t->serial : "transport")));
+ D("%s: starting write_transport thread, reading from fd %d", t->serial, t->fd);
- for(;;){
- if(read_packet(t->fd, t->serial, &p)) {
- D("%s: failed to read apacket from transport on fd %d",
- t->serial, t->fd );
+ for (;;) {
+ ATRACE_NAME("write_transport loop");
+ if (read_packet(t->fd, t->serial, &p)) {
+ D("%s: failed to read apacket from transport on fd %d", t->serial, t->fd);
break;
}
- if(p->msg.command == A_SYNC){
- if(p->msg.arg0 == 0) {
+
+ if (p->msg.command == A_SYNC) {
+ if (p->msg.arg0 == 0) {
D("%s: transport SYNC offline", t->serial);
put_apacket(p);
break;
} else {
- if(p->msg.arg1 == t->sync_token) {
+ if (p->msg.arg1 == t->sync_token) {
D("%s: transport SYNC online", t->serial);
active = 1;
} else {
- D("%s: transport ignoring SYNC %d != %d",
- t->serial, p->msg.arg1, t->sync_token);
+ D("%s: transport ignoring SYNC %d != %d", t->serial, p->msg.arg1, t->sync_token);
}
}
} else {
- if(active) {
+ if (active) {
D("%s: transport got packet, sending to remote", t->serial);
+ ATRACE_NAME("write_transport write_remote");
t->write_to_remote(p, t);
} else {
D("%s: transport ignoring packet while offline", t->serial);
@@ -296,7 +296,6 @@
static int transport_registration_recv = -1;
static fdevent transport_registration_fde;
-
#if ADB_HOST
/* this adds support required by the 'track-devices' service.
@@ -305,19 +304,17 @@
* live TCP connection
*/
struct device_tracker {
- asocket socket;
- int update_needed;
- device_tracker* next;
+ asocket socket;
+ int update_needed;
+ device_tracker* next;
};
/* linked list of all device trackers */
-static device_tracker* device_tracker_list;
+static device_tracker* device_tracker_list;
-static void
-device_tracker_remove( device_tracker* tracker )
-{
- device_tracker** pnode = &device_tracker_list;
- device_tracker* node = *pnode;
+static void device_tracker_remove(device_tracker* tracker) {
+ device_tracker** pnode = &device_tracker_list;
+ device_tracker* node = *pnode;
std::lock_guard<std::mutex> lock(transport_lock);
while (node) {
@@ -326,17 +323,15 @@
break;
}
pnode = &node->next;
- node = *pnode;
+ node = *pnode;
}
}
-static void
-device_tracker_close( asocket* socket )
-{
- device_tracker* tracker = (device_tracker*) socket;
- asocket* peer = socket->peer;
+static void device_tracker_close(asocket* socket) {
+ device_tracker* tracker = (device_tracker*)socket;
+ asocket* peer = socket->peer;
- D( "device tracker %p removed", tracker);
+ D("device tracker %p removed", tracker);
if (peer) {
peer->peer = NULL;
peer->close(peer);
@@ -345,9 +340,7 @@
free(tracker);
}
-static int
-device_tracker_enqueue( asocket* socket, apacket* p )
-{
+static int device_tracker_enqueue(asocket* socket, apacket* p) {
/* you can't read from a device tracker, close immediately */
put_apacket(p);
device_tracker_close(socket);
@@ -377,26 +370,23 @@
}
}
-asocket*
-create_device_tracker(void)
-{
+asocket* create_device_tracker(void) {
device_tracker* tracker = reinterpret_cast<device_tracker*>(calloc(1, sizeof(*tracker)));
if (tracker == nullptr) fatal("cannot allocate device tracker");
- D( "device tracker %p created", tracker);
+ D("device tracker %p created", tracker);
tracker->socket.enqueue = device_tracker_enqueue;
- tracker->socket.ready = device_tracker_ready;
- tracker->socket.close = device_tracker_close;
- tracker->update_needed = 1;
+ tracker->socket.ready = device_tracker_ready;
+ tracker->socket.close = device_tracker_close;
+ tracker->update_needed = 1;
- tracker->next = device_tracker_list;
+ tracker->next = device_tracker_list;
device_tracker_list = tracker;
return &tracker->socket;
}
-
// Call this function each time the transport list has changed.
void update_transports() {
std::string transports = list_transports(false);
@@ -416,26 +406,23 @@
// Nothing to do on the device side.
}
-#endif // ADB_HOST
+#endif // ADB_HOST
-struct tmsg
-{
- atransport *transport;
- int action;
+struct tmsg {
+ atransport* transport;
+ int action;
};
-static int
-transport_read_action(int fd, struct tmsg* m)
-{
- char *p = (char*)m;
- int len = sizeof(*m);
- int r;
+static int transport_read_action(int fd, struct tmsg* m) {
+ char* p = (char*)m;
+ int len = sizeof(*m);
+ int r;
- while(len > 0) {
+ while (len > 0) {
r = adb_read(fd, p, len);
- if(r > 0) {
+ if (r > 0) {
len -= r;
- p += r;
+ p += r;
} else {
D("transport_read_action: on fd %d: %s", fd, strerror(errno));
return -1;
@@ -444,18 +431,16 @@
return 0;
}
-static int
-transport_write_action(int fd, struct tmsg* m)
-{
- char *p = (char*)m;
- int len = sizeof(*m);
- int r;
+static int transport_write_action(int fd, struct tmsg* m) {
+ char* p = (char*)m;
+ int len = sizeof(*m);
+ int r;
- while(len > 0) {
+ while (len > 0) {
r = adb_write(fd, p, len);
- if(r > 0) {
+ if (r > 0) {
len -= r;
- p += r;
+ p += r;
} else {
D("transport_write_action: on fd %d: %s", fd, strerror(errno));
return -1;
@@ -464,17 +449,16 @@
return 0;
}
-static void transport_registration_func(int _fd, unsigned ev, void *data)
-{
+static void transport_registration_func(int _fd, unsigned ev, void* data) {
tmsg m;
int s[2];
- atransport *t;
+ atransport* t;
- if(!(ev & FDE_READ)) {
+ if (!(ev & FDE_READ)) {
return;
}
- if(transport_read_action(_fd, &m)) {
+ if (transport_read_action(_fd, &m)) {
fatal_errno("cannot read transport registration socket");
}
@@ -483,9 +467,9 @@
if (m.action == 0) {
D("transport: %s removing and free'ing %d", t->serial, t->transport_socket);
- /* IMPORTANT: the remove closes one half of the
- ** socket pair. The close closes the other half.
- */
+ /* IMPORTANT: the remove closes one half of the
+ ** socket pair. The close closes the other half.
+ */
fdevent_remove(&(t->transport_fde));
adb_close(t->fd);
@@ -494,16 +478,11 @@
transport_list.remove(t);
}
- if (t->product)
- free(t->product);
- if (t->serial)
- free(t->serial);
- if (t->model)
- free(t->model);
- if (t->device)
- free(t->device);
- if (t->devpath)
- free(t->devpath);
+ if (t->product) free(t->product);
+ if (t->serial) free(t->serial);
+ if (t->model) free(t->model);
+ if (t->device) free(t->device);
+ if (t->devpath) free(t->devpath);
delete t;
@@ -525,10 +504,7 @@
t->transport_socket = s[0];
t->fd = s[1];
- fdevent_install(&(t->transport_fde),
- t->transport_socket,
- transport_socket_events,
- t);
+ fdevent_install(&(t->transport_fde), t->transport_socket, transport_socket_events, t);
fdevent_set(&(t->transport_fde), FDE_READ);
@@ -550,11 +526,10 @@
update_transports();
}
-void init_transport_registration(void)
-{
+void init_transport_registration(void) {
int s[2];
- if(adb_socketpair(s)){
+ if (adb_socketpair(s)) {
fatal_errno("cannot open transport registration socketpair");
}
D("socketpair: (%d,%d)", s[0], s[1]);
@@ -562,38 +537,33 @@
transport_registration_send = s[0];
transport_registration_recv = s[1];
- fdevent_install(&transport_registration_fde,
- transport_registration_recv,
- transport_registration_func,
- 0);
+ fdevent_install(&transport_registration_fde, transport_registration_recv,
+ transport_registration_func, 0);
fdevent_set(&transport_registration_fde, FDE_READ);
}
/* the fdevent select pump is single threaded */
-static void register_transport(atransport *transport)
-{
+static void register_transport(atransport* transport) {
tmsg m;
m.transport = transport;
m.action = 1;
D("transport: %s registered", transport->serial);
- if(transport_write_action(transport_registration_send, &m)) {
+ if (transport_write_action(transport_registration_send, &m)) {
fatal_errno("cannot write transport registration socket\n");
}
}
-static void remove_transport(atransport *transport)
-{
+static void remove_transport(atransport* transport) {
tmsg m;
m.transport = transport;
m.action = 0;
D("transport: %s removed", transport->serial);
- if(transport_write_action(transport_registration_send, &m)) {
+ if (transport_write_action(transport_registration_send, &m)) {
fatal_errno("cannot write transport registration socket\n");
}
}
-
static void transport_unref(atransport* t) {
CHECK(t != nullptr);
@@ -609,37 +579,31 @@
}
}
-static int qual_match(const char *to_test,
- const char *prefix, const char *qual, bool sanitize_qual)
-{
- if (!to_test || !*to_test)
- /* Return true if both the qual and to_test are null strings. */
+static int qual_match(const char* to_test, const char* prefix, const char* qual,
+ bool sanitize_qual) {
+ if (!to_test || !*to_test) /* Return true if both the qual and to_test are null strings. */
return !qual || !*qual;
- if (!qual)
- return 0;
+ if (!qual) return 0;
if (prefix) {
while (*prefix) {
- if (*prefix++ != *to_test++)
- return 0;
+ if (*prefix++ != *to_test++) return 0;
}
}
while (*qual) {
char ch = *qual++;
- if (sanitize_qual && !isalnum(ch))
- ch = '_';
- if (ch != *to_test++)
- return 0;
+ if (sanitize_qual && !isalnum(ch)) ch = '_';
+ if (ch != *to_test++) return 0;
}
/* Everything matched so far. Return true if *to_test is a NUL. */
return !*to_test;
}
-atransport* acquire_one_transport(TransportType type, const char* serial,
- bool* is_ambiguous, std::string* error_out) {
+atransport* acquire_one_transport(TransportType type, const char* serial, bool* is_ambiguous,
+ std::string* error_out) {
atransport* result = nullptr;
if (serial) {
@@ -737,15 +701,24 @@
const std::string atransport::connection_state_name() const {
switch (connection_state) {
- case kCsOffline: return "offline";
- case kCsBootloader: return "bootloader";
- case kCsDevice: return "device";
- case kCsHost: return "host";
- case kCsRecovery: return "recovery";
- case kCsNoPerm: return UsbNoPermissionsShortHelpText();
- case kCsSideload: return "sideload";
- case kCsUnauthorized: return "unauthorized";
- default: return "unknown";
+ case kCsOffline:
+ return "offline";
+ case kCsBootloader:
+ return "bootloader";
+ case kCsDevice:
+ return "device";
+ case kCsHost:
+ return "host";
+ case kCsRecovery:
+ return "recovery";
+ case kCsNoPerm:
+ return UsbNoPermissionsShortHelpText();
+ case kCsSideload:
+ return "sideload";
+ case kCsUnauthorized:
+ return "unauthorized";
+ default:
+ return "unknown";
}
}
@@ -771,9 +744,7 @@
const FeatureSet& supported_features() {
// Local static allocation to avoid global non-POD variables.
static const FeatureSet* features = new FeatureSet{
- kFeatureShell2,
- kFeatureCmd,
- kFeatureStat2,
+ kFeatureShell2, kFeatureCmd, kFeatureStat2,
// Increment ADB_SERVER_VERSION whenever the feature list changes to
// make sure that the adb client and server features stay in sync
// (http://b/24370690).
@@ -791,14 +762,12 @@
return FeatureSet();
}
- auto names = android::base::Split(features_string,
- {kFeatureStringDelimiter});
+ auto names = android::base::Split(features_string, {kFeatureStringDelimiter});
return FeatureSet(names.begin(), names.end());
}
bool CanUseFeature(const FeatureSet& feature_set, const std::string& feature) {
- return feature_set.count(feature) > 0 &&
- supported_features().count(feature) > 0;
+ return feature_set.count(feature) > 0 && supported_features().count(feature) > 0;
}
bool atransport::has_feature(const std::string& feature) const {
@@ -834,21 +803,20 @@
// For fastboot compatibility, ignore protocol prefixes.
if (android::base::StartsWith(target, "tcp:") ||
- android::base::StartsWith(target, "udp:")) {
+ android::base::StartsWith(target, "udp:")) {
local_target_ptr += 4;
}
// Parse our |serial| and the given |target| to check if the hostnames and ports match.
std::string serial_host, error;
int serial_port = -1;
- if (android::base::ParseNetAddress(serial, &serial_host, &serial_port, nullptr,
- &error)) {
+ if (android::base::ParseNetAddress(serial, &serial_host, &serial_port, nullptr, &error)) {
// |target| may omit the port to default to ours.
std::string target_host;
int target_port = serial_port;
if (android::base::ParseNetAddress(local_target_ptr, &target_host, &target_port,
nullptr, &error) &&
- serial_host == target_host && serial_port == target_port) {
+ serial_host == target_host && serial_port == target_port) {
return true;
}
}
@@ -863,8 +831,8 @@
#if ADB_HOST
-static void append_transport_info(std::string* result, const char* key,
- const char* value, bool sanitize) {
+static void append_transport_info(std::string* result, const char* key, const char* value,
+ bool sanitize) {
if (value == nullptr || *value == '\0') {
return;
}
@@ -877,8 +845,7 @@
}
}
-static void append_transport(const atransport* t, std::string* result,
- bool long_listing) {
+static void append_transport(const atransport* t, std::string* result, bool long_listing) {
const char* serial = t->serial;
if (!serial || !serial[0]) {
serial = "(no serial number)";
@@ -889,8 +856,7 @@
*result += '\t';
*result += t->connection_state_name();
} else {
- android::base::StringAppendF(result, "%-22s %s", serial,
- t->connection_state_name().c_str());
+ android::base::StringAppendF(result, "%-22s %s", serial, t->connection_state_name().c_str());
append_transport_info(result, "", t->devpath, false);
append_transport_info(result, "product:", t->product, false);
@@ -923,9 +889,9 @@
void close_usb_devices() {
close_usb_devices([](const atransport*) { return true; });
}
-#endif // ADB_HOST
+#endif // ADB_HOST
-int register_socket_transport(int s, const char *serial, int port, int local) {
+int register_socket_transport(int s, const char* serial, int port, int local) {
atransport* t = new atransport();
if (!serial) {
@@ -944,7 +910,7 @@
for (const auto& transport : pending_list) {
if (transport->serial && strcmp(serial, transport->serial) == 0) {
VLOG(TRANSPORT) << "socket transport " << transport->serial
- << " is already in pending_list and fails to register";
+ << " is already in pending_list and fails to register";
delete t;
return -1;
}
@@ -953,7 +919,7 @@
for (const auto& transport : transport_list) {
if (transport->serial && strcmp(serial, transport->serial) == 0) {
VLOG(TRANSPORT) << "socket transport " << transport->serial
- << " is already in transport_list and fails to register";
+ << " is already in transport_list and fails to register";
delete t;
return -1;
}
@@ -969,7 +935,7 @@
}
#if ADB_HOST
-atransport *find_transport(const char *serial) {
+atransport* find_transport(const char* serial) {
atransport* result = nullptr;
std::lock_guard<std::mutex> lock(transport_lock);
@@ -998,14 +964,13 @@
#endif
-void register_usb_transport(usb_handle* usb, const char* serial,
- const char* devpath, unsigned writeable) {
+void register_usb_transport(usb_handle* usb, const char* serial, const char* devpath,
+ unsigned writeable) {
atransport* t = new atransport();
- D("transport: %p init'ing for usb_handle %p (sn='%s')", t, usb,
- serial ? serial : "");
+ D("transport: %p init'ing for usb_handle %p (sn='%s')", t, usb, serial ? serial : "");
init_usb_transport(t, usb, (writeable ? kCsOffline : kCsNoPerm));
- if(serial) {
+ if (serial) {
t->serial = strdup(serial);
}
@@ -1022,23 +987,21 @@
}
// This should only be used for transports with connection_state == kCsNoPerm.
-void unregister_usb_transport(usb_handle *usb) {
+void unregister_usb_transport(usb_handle* usb) {
std::lock_guard<std::mutex> lock(transport_lock);
- transport_list.remove_if([usb](atransport* t) {
- return t->usb == usb && t->connection_state == kCsNoPerm;
- });
+ transport_list.remove_if(
+ [usb](atransport* t) { return t->usb == usb && t->connection_state == kCsNoPerm; });
}
-int check_header(apacket *p, atransport *t)
-{
- if(p->msg.magic != (p->msg.command ^ 0xffffffff)) {
+int check_header(apacket* p, atransport* t) {
+ if (p->msg.magic != (p->msg.command ^ 0xffffffff)) {
VLOG(RWX) << "check_header(): invalid magic";
return -1;
}
- if(p->msg.data_length > t->get_max_payload()) {
- VLOG(RWX) << "check_header(): " << p->msg.data_length << " atransport::max_payload = "
- << t->get_max_payload();
+ if (p->msg.data_length > t->get_max_payload()) {
+ VLOG(RWX) << "check_header(): " << p->msg.data_length
+ << " atransport::max_payload = " << t->get_max_payload();
return -1;
}
diff --git a/base/include/android-base/memory.h b/base/include/android-base/memory.h
index 3a2f8fa..9971226 100644
--- a/base/include/android-base/memory.h
+++ b/base/include/android-base/memory.h
@@ -20,25 +20,19 @@
namespace android {
namespace base {
-// Use packed structures for access to unaligned data on targets with alignment
+// Use memcpy for access to unaligned data on targets with alignment
// restrictions. The compiler will generate appropriate code to access these
// structures without generating alignment exceptions.
template <typename T>
-static inline T get_unaligned(const T* address) {
- struct unaligned {
- T v;
- } __attribute__((packed));
- const unaligned* p = reinterpret_cast<const unaligned*>(address);
- return p->v;
+static inline T get_unaligned(const void* address) {
+ T result;
+ memcpy(&result, address, sizeof(T));
+ return result;
}
template <typename T>
-static inline void put_unaligned(T* address, T v) {
- struct unaligned {
- T v;
- } __attribute__((packed));
- unaligned* p = reinterpret_cast<unaligned*>(address);
- p->v = v;
+static inline void put_unaligned(void* address, T v) {
+ memcpy(address, &v, sizeof(T));
}
} // namespace base
diff --git a/base/include/android-base/properties.h b/base/include/android-base/properties.h
index 95d1b6a..4d7082a 100644
--- a/base/include/android-base/properties.h
+++ b/base/include/android-base/properties.h
@@ -61,4 +61,4 @@
} // namespace base
} // namespace android
-#endif // ANDROID_BASE_MEMORY_H
+#endif // ANDROID_BASE_PROPERTIES_H
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 7c0e85d..483c01d 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -207,6 +207,19 @@
return boot_complete_prefix;
}
+// Records the value of a given ro.boottime.init property in milliseconds.
+void RecordInitBootTimeProp(
+ BootEventRecordStore* boot_event_store, const char* property) {
+ std::string value = GetProperty(property);
+
+ int32_t time_in_ns;
+ if (android::base::ParseInt(value, &time_in_ns)) {
+ static constexpr int32_t kNanosecondsPerMillisecond = 1e6;
+ int32_t time_in_ms = static_cast<int32_t>(time_in_ns / kNanosecondsPerMillisecond);
+ boot_event_store->AddBootEventWithValue(property, time_in_ms);
+ }
+}
+
// Records several metrics related to the time it takes to boot the device,
// including disambiguating boot time on encrypted or non-encrypted devices.
void RecordBootComplete() {
@@ -256,6 +269,10 @@
// Record the total time from device startup to boot complete, regardless of
// encryption state.
boot_event_store.AddBootEventWithValue(boot_complete_prefix, uptime);
+
+ RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init");
+ RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init.selinux");
+ RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init.cold_boot_wait");
}
// Records the boot_reason metric by querying the ro.boot.bootreason system
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 607745d..e3bdd43 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -52,7 +52,7 @@
include $(BUILD_EXECUTABLE)
-crasher_cppflags := $(common_cppflags) -fstack-protector-all -Wno-free-nonheap-object -Wno-date-time
+crasher_cppflags := $(common_cppflags) -O0 -fstack-protector-all -Wno-free-nonheap-object
include $(CLEAR_VARS)
LOCAL_SRC_FILES := crasher.cpp
@@ -65,7 +65,7 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := optional
LOCAL_CPPFLAGS := $(crasher_cppflags)
-LOCAL_SHARED_LIBRARIES := libcutils liblog
+LOCAL_SHARED_LIBRARIES := libbase liblog
# The arm emulator has VFP but not VFPv3-D32.
ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
@@ -91,7 +91,6 @@
LOCAL_MODULE_TAGS := optional
LOCAL_CPPFLAGS := $(crasher_cppflags) -DSTATIC_CRASHER
LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_SHARED_LIBRARIES := libcutils liblog
# The arm emulator has VFP but not VFPv3-D32.
ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
@@ -103,7 +102,7 @@
LOCAL_MODULE_STEM_64 := static_crasher64
LOCAL_MULTILIB := both
-LOCAL_STATIC_LIBRARIES := libdebuggerd_client libcutils liblog
+LOCAL_STATIC_LIBRARIES := libdebuggerd_client libbase liblog
include $(BUILD_EXECUTABLE)
diff --git a/debuggerd/crasher.cpp b/debuggerd/crasher.cpp
index b0e8b17..e650f22 100644
--- a/debuggerd/crasher.cpp
+++ b/debuggerd/crasher.cpp
@@ -17,47 +17,43 @@
#define LOG_TAG "crasher"
#include <assert.h>
+#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
-#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/cdefs.h>
#include <sys/mman.h>
-#include <sys/ptrace.h>
-#include <sys/socket.h>
-#include <sys/wait.h>
#include <unistd.h>
+// We test both kinds of logging.
#include <android/log.h>
-#include <cutils/sockets.h>
+#include <android-base/logging.h>
#if defined(STATIC_CRASHER)
#include "debuggerd/client.h"
#endif
-#ifndef __unused
-#define __unused __attribute__((__unused__))
-#endif
+#define noinline __attribute__((__noinline__))
-extern const char* __progname;
+// Avoid name mangling so that stacks are more readable.
+extern "C" {
-extern "C" void crash1(void);
-extern "C" void crashnostack(void);
+void crash1(void);
+void crashnostack(void);
-static int do_action(const char* arg);
+int do_action(const char* arg);
-static void maybe_abort() {
+noinline void maybe_abort() {
if (time(0) != 42) {
abort();
}
}
-static char* smash_stack_dummy_buf;
-__attribute__ ((noinline)) static void smash_stack_dummy_function(volatile int* plen) {
+char* smash_stack_dummy_buf;
+noinline void smash_stack_dummy_function(volatile int* plen) {
smash_stack_dummy_buf[*plen] = 0;
}
@@ -65,8 +61,8 @@
// compiler generates the proper stack guards around this function.
// Assign local array address to global variable to force stack guards.
// Use another noinline function to corrupt the stack.
-__attribute__ ((noinline)) static int smash_stack(volatile int* plen) {
- printf("%s: deliberately corrupting stack...\n", __progname);
+noinline int smash_stack(volatile int* plen) {
+ printf("%s: deliberately corrupting stack...\n", getprogname());
char buf[128];
smash_stack_dummy_buf = buf;
@@ -75,91 +71,107 @@
return 0;
}
-#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Winfinite-recursion"
-#endif
-static void* global = 0; // So GCC doesn't optimize the tail recursion out of overflow_stack.
+void* global = 0; // So GCC doesn't optimize the tail recursion out of overflow_stack.
-__attribute__((noinline)) static void overflow_stack(void* p) {
+noinline void overflow_stack(void* p) {
void* buf[1];
buf[0] = p;
global = buf;
overflow_stack(&buf);
}
-#if defined(__clang__)
#pragma clang diagnostic pop
-#endif
-static void *noisy(void *x)
-{
- char c = (uintptr_t) x;
- for(;;) {
- usleep(250*1000);
- write(2, &c, 1);
- if(c == 'C') *((volatile unsigned*) 0) = 42;
- }
- return NULL;
+noinline void* thread_callback(void* raw_arg) {
+ const char* arg = reinterpret_cast<const char*>(raw_arg);
+ return reinterpret_cast<void*>(static_cast<uintptr_t>(do_action(arg)));
}
-static int ctest()
-{
- pthread_t thr;
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_create(&thr, &attr, noisy, (void*) 'A');
- pthread_create(&thr, &attr, noisy, (void*) 'B');
- pthread_create(&thr, &attr, noisy, (void*) 'C');
- for(;;) ;
- return 0;
-}
-
-static void* thread_callback(void* raw_arg)
-{
- return (void*) (uintptr_t) do_action((const char*) raw_arg);
-}
-
-static int do_action_on_thread(const char* arg)
-{
+noinline int do_action_on_thread(const char* arg) {
pthread_t t;
- pthread_create(&t, NULL, thread_callback, (void*) arg);
- void* result = NULL;
+ pthread_create(&t, nullptr, thread_callback, const_cast<char*>(arg));
+ void* result = nullptr;
pthread_join(t, &result);
- return (int) (uintptr_t) result;
+ return reinterpret_cast<uintptr_t>(result);
}
-__attribute__((noinline)) static int crash3(int a) {
- *((int*) 0xdead) = a;
+noinline int crash3(int a) {
+ *reinterpret_cast<int*>(0xdead) = a;
return a*4;
}
-__attribute__((noinline)) static int crash2(int a) {
+noinline int crash2(int a) {
a = crash3(a) + 2;
return a*3;
}
-__attribute__((noinline)) static int crash(int a) {
+noinline int crash(int a) {
a = crash2(a) + 1;
return a*2;
}
-static void abuse_heap() {
+noinline void abuse_heap() {
char buf[16];
- free((void*) buf); // GCC is smart enough to warn about this, but we're doing it deliberately.
+ free(buf); // GCC is smart enough to warn about this, but we're doing it deliberately.
}
-static void sigsegv_non_null() {
+noinline void sigsegv_non_null() {
int* a = (int *)(&do_action);
*a = 42;
}
-static int do_action(const char* arg)
-{
- fprintf(stderr, "%s: init pid=%d tid=%d\n", __progname, getpid(), gettid());
+noinline void fprintf_null() {
+ fprintf(nullptr, "oops");
+}
+noinline void readdir_null() {
+ readdir(nullptr);
+}
+
+noinline int strlen_null() {
+ char* sneaky_null = nullptr;
+ return strlen(sneaky_null);
+}
+
+static int usage() {
+ fprintf(stderr, "usage: %s KIND\n", getprogname());
+ fprintf(stderr, "\n");
+ fprintf(stderr, "where KIND is:\n");
+ fprintf(stderr, " smash-stack overwrite a -fstack-protector guard\n");
+ fprintf(stderr, " stack-overflow recurse until the stack overflows\n");
+ fprintf(stderr, " heap-corruption cause a libc abort by corrupting the heap\n");
+ fprintf(stderr, " heap-usage cause a libc abort by abusing a heap function\n");
+ fprintf(stderr, " nostack crash with a NULL stack pointer\n");
+ fprintf(stderr, " abort call abort()\n");
+ fprintf(stderr, " assert call assert() without a function\n");
+ fprintf(stderr, " assert2 call assert() with a function\n");
+ fprintf(stderr, " exit call exit(1)\n");
+ fprintf(stderr, " fortify fail a _FORTIFY_SOURCE check\n");
+ fprintf(stderr, " LOG_ALWAYS_FATAL call liblog LOG_ALWAYS_FATAL\n");
+ fprintf(stderr, " LOG_ALWAYS_FATAL_IF call liblog LOG_ALWAYS_FATAL_IF\n");
+ fprintf(stderr, " LOG-FATAL call libbase LOG(FATAL)\n");
+ fprintf(stderr, " SIGFPE cause a SIGFPE\n");
+ fprintf(stderr, " SIGSEGV cause a SIGSEGV at address 0x0 (synonym: crash)\n");
+ fprintf(stderr, " SIGSEGV-non-null cause a SIGSEGV at a non-zero address\n");
+ fprintf(stderr, " SIGSEGV-unmapped mmap/munmap a region of memory and then attempt to access it\n");
+ fprintf(stderr, " SIGTRAP cause a SIGTRAP\n");
+ fprintf(stderr, " fprintf-NULL pass a null pointer to fprintf\n");
+ fprintf(stderr, " readdir-NULL pass a null pointer to readdir\n");
+ fprintf(stderr, " strlen-NULL pass a null pointer to strlen\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "prefix any of the above with 'thread-' to run on a new 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_FAILURE;
+}
+
+noinline int do_action(const char* arg) {
+ // Prefixes.
if (!strncmp(arg, "wait-", strlen("wait-"))) {
char buf[1];
TEMP_FAILURE_RETRY(read(STDIN_FILENO, buf, sizeof(buf)));
@@ -172,82 +184,66 @@
return do_action(arg + strlen("exhaustfd-"));
} else if (!strncmp(arg, "thread-", strlen("thread-"))) {
return do_action_on_thread(arg + strlen("thread-"));
- } else if (!strcmp(arg, "SIGSEGV-non-null")) {
+ }
+
+ // Actions.
+ if (!strcasecmp(arg, "SIGSEGV-non-null")) {
sigsegv_non_null();
- } else if (!strcmp(arg, "smash-stack")) {
+ } else if (!strcasecmp(arg, "smash-stack")) {
volatile int len = 128;
return smash_stack(&len);
- } else if (!strcmp(arg, "stack-overflow")) {
- overflow_stack(NULL);
- } else if (!strcmp(arg, "nostack")) {
+ } else if (!strcasecmp(arg, "stack-overflow")) {
+ overflow_stack(nullptr);
+ } else if (!strcasecmp(arg, "nostack")) {
crashnostack();
- } else if (!strcmp(arg, "ctest")) {
- return ctest();
- } else if (!strcmp(arg, "exit")) {
+ } else if (!strcasecmp(arg, "exit")) {
exit(1);
- } else if (!strcmp(arg, "crash") || !strcmp(arg, "SIGSEGV")) {
+ } else if (!strcasecmp(arg, "crash") || !strcmp(arg, "SIGSEGV")) {
return crash(42);
- } else if (!strcmp(arg, "abort")) {
+ } else if (!strcasecmp(arg, "abort")) {
maybe_abort();
- } else if (!strcmp(arg, "assert")) {
+ } else if (!strcasecmp(arg, "assert")) {
__assert("some_file.c", 123, "false");
- } else if (!strcmp(arg, "assert2")) {
+ } else if (!strcasecmp(arg, "assert2")) {
__assert2("some_file.c", 123, "some_function", "false");
- } else if (!strcmp(arg, "fortify")) {
+ } else if (!strcasecmp(arg, "fortify")) {
char buf[10];
__read_chk(-1, buf, 32, 10);
while (true) pause();
- } else if (!strcmp(arg, "LOG_ALWAYS_FATAL")) {
+ } else if (!strcasecmp(arg, "LOG(FATAL)")) {
+ LOG(FATAL) << "hello " << 123;
+ } else if (!strcasecmp(arg, "LOG_ALWAYS_FATAL")) {
LOG_ALWAYS_FATAL("hello %s", "world");
- } else if (!strcmp(arg, "LOG_ALWAYS_FATAL_IF")) {
+ } else if (!strcasecmp(arg, "LOG_ALWAYS_FATAL_IF")) {
LOG_ALWAYS_FATAL_IF(true, "hello %s", "world");
- } else if (!strcmp(arg, "SIGFPE")) {
+ } else if (!strcasecmp(arg, "SIGFPE")) {
raise(SIGFPE);
return EXIT_SUCCESS;
- } else if (!strcmp(arg, "SIGTRAP")) {
+ } else if (!strcasecmp(arg, "SIGTRAP")) {
raise(SIGTRAP);
return EXIT_SUCCESS;
- } else if (!strcmp(arg, "heap-usage")) {
+ } else if (!strcasecmp(arg, "fprintf-NULL")) {
+ fprintf_null();
+ } else if (!strcasecmp(arg, "readdir-NULL")) {
+ readdir_null();
+ } else if (!strcasecmp(arg, "strlen-NULL")) {
+ return strlen_null();
+ } else if (!strcasecmp(arg, "heap-usage")) {
abuse_heap();
- } else if (!strcmp(arg, "SIGSEGV-unmapped")) {
- char* map = reinterpret_cast<char*>(mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0));
+ } else if (!strcasecmp(arg, "SIGSEGV-unmapped")) {
+ char* map = reinterpret_cast<char*>(mmap(nullptr, sizeof(int), PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0));
munmap(map, sizeof(int));
map[0] = '8';
+ } else {
+ return usage();
}
- fprintf(stderr, "%s OP\n", __progname);
- fprintf(stderr, "where OP is:\n");
- fprintf(stderr, " smash-stack overwrite a stack-guard canary\n");
- fprintf(stderr, " stack-overflow recurse until the stack overflows\n");
- fprintf(stderr, " heap-corruption cause a libc abort by corrupting the heap\n");
- fprintf(stderr, " heap-usage cause a libc abort by abusing a heap function\n");
- fprintf(stderr, " nostack crash with a NULL stack pointer\n");
- fprintf(stderr, " ctest (obsoleted by thread-crash?)\n");
- fprintf(stderr, " exit call exit(1)\n");
- fprintf(stderr, " abort call abort()\n");
- fprintf(stderr, " assert call assert() without a function\n");
- fprintf(stderr, " assert2 call assert() with a function\n");
- fprintf(stderr, " fortify fail a _FORTIFY_SOURCE check\n");
- fprintf(stderr, " LOG_ALWAYS_FATAL call LOG_ALWAYS_FATAL\n");
- fprintf(stderr, " LOG_ALWAYS_FATAL_IF call LOG_ALWAYS_FATAL\n");
- fprintf(stderr, " SIGFPE cause a SIGFPE\n");
- fprintf(stderr, " SIGSEGV cause a SIGSEGV at address 0x0 (synonym: crash)\n");
- fprintf(stderr, " SIGSEGV-non-null cause a SIGSEGV at a non-zero address\n");
- fprintf(stderr, " SIGSEGV-unmapped mmap/munmap a region of memory and then attempt to access it\n");
- fprintf(stderr, " SIGTRAP cause a SIGTRAP\n");
- fprintf(stderr, "prefix any of the above with 'thread-' to not run\n");
- 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");
-
+ fprintf(stderr, "%s: exiting normally!\n", getprogname());
return EXIT_SUCCESS;
}
-int main(int argc, char **argv)
-{
- fprintf(stderr, "%s: built at " __TIME__ "!@\n", __progname);
-
+int main(int argc, char** argv) {
#if defined(STATIC_CRASHER)
debuggerd_callbacks_t callbacks = {
.get_abort_message = []() {
@@ -265,11 +261,10 @@
debuggerd_init(&callbacks);
#endif
- if (argc > 1) {
- return do_action(argv[1]);
- } else {
- crash1();
- }
+ if (argc == 1) crash1();
+ else if (argc == 2) return do_action(argv[1]);
- return 0;
+ return usage();
}
+
+};
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 7f4a0dd..3f8bc8f 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -1742,6 +1742,14 @@
} else if(!strcmp(*argv, "set_active")) {
require(2);
std::string slot = verify_slot(transport, std::string(argv[1]), false);
+ // Legacy support: verify_slot() removes leading underscores, we need to put them back
+ // in for old bootloaders. Legacy bootloaders do not have the slot-count variable but
+ // do have slot-suffixes.
+ std::string var;
+ if (!fb_getvar(transport, "slot-count", &var) &&
+ fb_getvar(transport, "slot-suffixes", &var)) {
+ slot = "_" + slot;
+ }
fb_set_active(slot.c_str());
skip(2);
} else if(!strcmp(*argv, "oem")) {
diff --git a/fastboot/fastboot_protocol.txt b/fastboot/fastboot_protocol.txt
index 2801703..b12e420 100644
--- a/fastboot/fastboot_protocol.txt
+++ b/fastboot/fastboot_protocol.txt
@@ -78,7 +78,7 @@
Host: "getvar:nonexistant" request some undefined variable
-Client: "OKAY" return value ""
+Client: "FAILUnknown variable" getvar failure; see getvar details below
Host: "download:00001234" request to send 0x1234 bytes of data
@@ -113,7 +113,14 @@
"getvar:%s" Read a config/version variable from the bootloader.
The variable contents will be returned after the
- OKAY response.
+ OKAY response. If the variable is unknown, the bootloader
+ should return a FAIL response, optionally with an error
+ message.
+
+ Previous versions of this document indicated that getvar
+ should return an empty OKAY response for unknown
+ variables, so older devices might exhibit this behavior,
+ but new implementations should return FAIL instead.
"download:%08x" Write data to memory which will be later used
by "boot", "ramdisk", "flash", etc. The client
@@ -215,7 +222,7 @@
Host [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x0E]getvar:version
Device [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x07]OKAY0.4
Host [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x0B]getvar:none
-Device [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x04]OKAY
+Device [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x14]FAILUnknown variable
Host <disconnect>
@@ -364,10 +371,10 @@
0x03 0x00 0x00 0x01
0x03 0x00 0x00 0x02
0x03 0x00 0x00 0x02 OKAY0.4
-0x03 0x00 0x00 0x03 getvar:foo
+0x03 0x00 0x00 0x03 getvar:none
0x03 0x00 0x00 0x03
0x03 0x00 0x00 0x04
- 0x03 0x00 0x00 0x04 OKAY
+ 0x03 0x00 0x00 0x04 FAILUnknown var
----------------------------------------------------------------------
[fastboot "INFO" responses, S = 0x0000]
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 740720b..ba44a5a 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -22,6 +22,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/swap.h>
@@ -38,6 +39,7 @@
#include <ext4_utils/ext4_sb.h>
#include <ext4_utils/ext4_utils.h>
#include <ext4_utils/wipe.h>
+#include <linux/fs.h>
#include <linux/loop.h>
#include <logwrap/logwrap.h>
#include <private/android_filesystem_config.h>
@@ -50,8 +52,9 @@
#define KEY_IN_FOOTER "footer"
#define E2FSCK_BIN "/system/bin/e2fsck"
-#define F2FS_FSCK_BIN "/system/bin/fsck.f2fs"
+#define F2FS_FSCK_BIN "/system/bin/fsck.f2fs"
#define MKSWAP_BIN "/system/bin/mkswap"
+#define TUNE2FS_BIN "/system/bin/tune2fs"
#define FSCK_LOG_FILE "/dev/fscklogs/log"
@@ -180,6 +183,166 @@
return;
}
+/* Function to read the primary superblock */
+static int read_super_block(int fd, struct ext4_super_block *sb)
+{
+ off64_t ret;
+
+ ret = lseek64(fd, 1024, SEEK_SET);
+ if (ret < 0)
+ return ret;
+
+ ret = read(fd, sb, sizeof(*sb));
+ if (ret < 0)
+ return ret;
+ if (ret != sizeof(*sb))
+ return ret;
+
+ return 0;
+}
+
+static ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es)
+{
+ return ((ext4_fsblk_t)le32_to_cpu(es->s_blocks_count_hi) << 32) |
+ le32_to_cpu(es->s_blocks_count_lo);
+}
+
+static ext4_fsblk_t ext4_r_blocks_count(struct ext4_super_block *es)
+{
+ return ((ext4_fsblk_t)le32_to_cpu(es->s_r_blocks_count_hi) << 32) |
+ le32_to_cpu(es->s_r_blocks_count_lo);
+}
+
+static int do_quota(char *blk_device, char *fs_type, struct fstab_rec *rec)
+{
+ int force_check = 0;
+ if (!strcmp(fs_type, "ext4")) {
+ /*
+ * Some system images do not have tune2fs for licensing reasons
+ * Detect these and skip reserve blocks.
+ */
+ if (access(TUNE2FS_BIN, X_OK)) {
+ ERROR("Not running %s on %s (executable not in system image)\n",
+ TUNE2FS_BIN, blk_device);
+ } else {
+ char* arg1 = NULL;
+ char* arg2 = NULL;
+ int status = 0;
+ int ret = 0;
+ int fd = TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC));
+ if (fd >= 0) {
+ struct ext4_super_block sb;
+ ret = read_super_block(fd, &sb);
+ if (ret < 0) {
+ ERROR("Can't read '%s' super block: %s\n", blk_device, strerror(errno));
+ goto out;
+ }
+
+ int has_quota = (sb.s_feature_ro_compat
+ & cpu_to_le32(EXT4_FEATURE_RO_COMPAT_QUOTA)) != 0;
+ int want_quota = fs_mgr_is_quota(rec) != 0;
+
+ if (has_quota == want_quota) {
+ INFO("Requested quota status is match on %s\n", blk_device);
+ goto out;
+ } else if (want_quota) {
+ INFO("Enabling quota on %s\n", blk_device);
+ arg1 = "-Oquota";
+ arg2 = "-Qusrquota,grpquota";
+ force_check = 1;
+ } else {
+ INFO("Disabling quota on %s\n", blk_device);
+ arg1 = "-Q^usrquota,^grpquota";
+ arg2 = "-O^quota";
+ }
+ } else {
+ ERROR("Failed to open '%s': %s\n", blk_device, strerror(errno));
+ return force_check;
+ }
+
+ char *tune2fs_argv[] = {
+ TUNE2FS_BIN,
+ arg1,
+ arg2,
+ blk_device,
+ };
+ ret = android_fork_execvp_ext(ARRAY_SIZE(tune2fs_argv), tune2fs_argv,
+ &status, true, LOG_KLOG | LOG_FILE,
+ true, NULL, NULL, 0);
+ if (ret < 0) {
+ /* No need to check for error in fork, we can't really handle it now */
+ ERROR("Failed trying to run %s\n", TUNE2FS_BIN);
+ }
+ out:
+ close(fd);
+ }
+ }
+ return force_check;
+}
+
+static void do_reserved_size(char *blk_device, char *fs_type, struct fstab_rec *rec)
+{
+ /* Check for the types of filesystems we know how to check */
+ if (!strcmp(fs_type, "ext2") || !strcmp(fs_type, "ext3") || !strcmp(fs_type, "ext4")) {
+ /*
+ * Some system images do not have tune2fs for licensing reasons
+ * Detect these and skip reserve blocks.
+ */
+ if (access(TUNE2FS_BIN, X_OK)) {
+ ERROR("Not running %s on %s (executable not in system image)\n",
+ TUNE2FS_BIN, blk_device);
+ } else {
+ INFO("Running %s on %s\n", TUNE2FS_BIN, blk_device);
+
+ int status = 0;
+ int ret = 0;
+ unsigned long reserved_blocks = 0;
+ int fd = TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC));
+ if (fd >= 0) {
+ struct ext4_super_block sb;
+ ret = read_super_block(fd, &sb);
+ if (ret < 0) {
+ ERROR("Can't read '%s' super block: %s\n", blk_device, strerror(errno));
+ goto out;
+ }
+ reserved_blocks = rec->reserved_size / EXT4_BLOCK_SIZE(&sb);
+ unsigned long reserved_threshold = ext4_blocks_count(&sb) * 0.02;
+ if (reserved_threshold < reserved_blocks) {
+ WARNING("Reserved blocks %lu is too large\n", reserved_blocks);
+ reserved_blocks = reserved_threshold;
+ }
+
+ if (ext4_r_blocks_count(&sb) == reserved_blocks) {
+ INFO("Have reserved same blocks\n");
+ goto out;
+ }
+ } else {
+ ERROR("Failed to open '%s': %s\n", blk_device, strerror(errno));
+ return;
+ }
+
+ char buf[16] = {0};
+ snprintf(buf, sizeof (buf), "-r %lu", reserved_blocks);
+ char *tune2fs_argv[] = {
+ TUNE2FS_BIN,
+ buf,
+ blk_device,
+ };
+
+ ret = android_fork_execvp_ext(ARRAY_SIZE(tune2fs_argv), tune2fs_argv,
+ &status, true, LOG_KLOG | LOG_FILE,
+ true, NULL, NULL, 0);
+
+ if (ret < 0) {
+ /* No need to check for error in fork, we can't really handle it now */
+ ERROR("Failed trying to run %s\n", TUNE2FS_BIN);
+ }
+ out:
+ close(fd);
+ }
+ }
+}
+
static void remove_trailing_slashes(char *n)
{
int len;
@@ -301,7 +464,7 @@
if (!end_idx || !attempted_idx || start_idx >= fstab->num_entries) {
errno = EINVAL;
if (end_idx) *end_idx = start_idx;
- if (attempted_idx) *end_idx = start_idx;
+ if (attempted_idx) *attempted_idx = start_idx;
return -1;
}
@@ -321,10 +484,19 @@
continue;
}
- if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
+ int force_check = do_quota(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
+ &fstab->recs[i]);
+
+ if ((fstab->recs[i].fs_mgr_flags & MF_CHECK) || force_check) {
check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
fstab->recs[i].mount_point);
}
+
+ if (fstab->recs[i].fs_mgr_flags & MF_RESERVEDSIZE) {
+ do_reserved_size(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
+ &fstab->recs[i]);
+ }
+
if (!__mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point, &fstab->recs[i])) {
*attempted_idx = i;
mounted = 1;
@@ -685,11 +857,18 @@
wait_for_file(n_blk_device, WAIT_TIMEOUT);
}
- if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
+ int force_check = do_quota(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
+ &fstab->recs[i]);
+
+ if ((fstab->recs[i].fs_mgr_flags & MF_CHECK) || force_check) {
check_fs(n_blk_device, fstab->recs[i].fs_type,
fstab->recs[i].mount_point);
}
+ if (fstab->recs[i].fs_mgr_flags & MF_RESERVEDSIZE) {
+ do_reserved_size(n_blk_device, fstab->recs[i].fs_type, &fstab->recs[i]);
+ }
+
if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
int rc = fs_mgr_setup_verity(&fstab->recs[i]);
if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index 0bc8bef..41fb746 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -33,6 +33,7 @@
int swap_prio;
int max_comp_streams;
unsigned int zram_size;
+ uint64_t reserved_size;
unsigned int file_encryption_mode;
};
@@ -61,28 +62,31 @@
};
static struct flag_list fs_mgr_flags[] = {
- { "wait", MF_WAIT },
- { "check", MF_CHECK },
- { "encryptable=",MF_CRYPT },
- { "forceencrypt=",MF_FORCECRYPT },
- { "fileencryption=",MF_FILEENCRYPTION },
- { "forcefdeorfbe=",MF_FORCEFDEORFBE },
- { "nonremovable",MF_NONREMOVABLE },
- { "voldmanaged=",MF_VOLDMANAGED},
- { "length=", MF_LENGTH },
- { "recoveryonly",MF_RECOVERYONLY },
- { "swapprio=", MF_SWAPPRIO },
- { "zramsize=", MF_ZRAMSIZE },
- { "max_comp_streams=", MF_MAX_COMP_STREAMS },
- { "verify", MF_VERIFY },
- { "noemulatedsd", MF_NOEMULATEDSD },
- { "notrim", MF_NOTRIM },
- { "formattable", MF_FORMATTABLE },
- { "slotselect", MF_SLOTSELECT },
- { "nofail", MF_NOFAIL },
- { "latemount", MF_LATEMOUNT },
- { "defaults", 0 },
- { 0, 0 },
+ { "wait", MF_WAIT },
+ { "check", MF_CHECK },
+ { "encryptable=", MF_CRYPT },
+ { "forceencrypt=", MF_FORCECRYPT },
+ { "fileencryption=", MF_FILEENCRYPTION },
+ { "forcefdeorfbe=", MF_FORCEFDEORFBE },
+ { "nonremovable", MF_NONREMOVABLE },
+ { "voldmanaged=", MF_VOLDMANAGED},
+ { "length=", MF_LENGTH },
+ { "recoveryonly", MF_RECOVERYONLY },
+ { "swapprio=", MF_SWAPPRIO },
+ { "zramsize=", MF_ZRAMSIZE },
+ { "max_comp_streams=", MF_MAX_COMP_STREAMS },
+ { "verifyatboot", MF_VERIFYATBOOT },
+ { "verify", MF_VERIFY },
+ { "noemulatedsd", MF_NOEMULATEDSD },
+ { "notrim", MF_NOTRIM },
+ { "formattable", MF_FORMATTABLE },
+ { "slotselect", MF_SLOTSELECT },
+ { "nofail", MF_NOFAIL },
+ { "latemount", MF_LATEMOUNT },
+ { "reservedsize=", MF_RESERVEDSIZE },
+ { "quota", MF_QUOTA },
+ { "defaults", 0 },
+ { 0, 0 },
};
#define EM_SOFTWARE 1
@@ -107,6 +111,20 @@
return total;
}
+static uint64_t parse_size(const char *arg)
+{
+ char *endptr;
+ uint64_t size = strtoull(arg, &endptr, 10);
+ if (*endptr == 'k' || *endptr == 'K')
+ size *= 1024LL;
+ else if (*endptr == 'm' || *endptr == 'M')
+ size *= 1024LL * 1024LL;
+ else if (*endptr == 'g' || *endptr == 'G')
+ size *= 1024LL * 1024LL * 1024LL;
+
+ return size;
+}
+
static int parse_flags(char *flags, struct flag_list *fl,
struct fs_mgr_flag_values *flag_vals,
char *fs_options, int fs_options_len)
@@ -216,6 +234,11 @@
flag_vals->zram_size = calculate_zram_size(val);
else
flag_vals->zram_size = val;
+ } else if ((fl[i].flag == MF_RESERVEDSIZE) && flag_vals) {
+ /* The reserved flag is followed by an = and the
+ * reserved size of the partition. Get it and return it.
+ */
+ flag_vals->reserved_size = parse_size(strchr(p, '=') + 1);
}
break;
}
@@ -360,6 +383,7 @@
fstab->recs[cnt].swap_prio = flag_vals.swap_prio;
fstab->recs[cnt].max_comp_streams = flag_vals.max_comp_streams;
fstab->recs[cnt].zram_size = flag_vals.zram_size;
+ fstab->recs[cnt].reserved_size = flag_vals.reserved_size;
fstab->recs[cnt].file_encryption_mode = flag_vals.file_encryption_mode;
cnt++;
}
@@ -564,3 +588,8 @@
{
return fstab->fs_mgr_flags & MF_LATEMOUNT;
}
+
+int fs_mgr_is_quota(struct fstab_rec *fstab)
+{
+ return fstab->fs_mgr_flags & MF_QUOTA;
+}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 741f5e9..db86afa 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -65,27 +65,30 @@
*
*/
-#define MF_WAIT 0x1
-#define MF_CHECK 0x2
-#define MF_CRYPT 0x4
-#define MF_NONREMOVABLE 0x8
-#define MF_VOLDMANAGED 0x10
-#define MF_LENGTH 0x20
-#define MF_RECOVERYONLY 0x40
-#define MF_SWAPPRIO 0x80
-#define MF_ZRAMSIZE 0x100
-#define MF_VERIFY 0x200
-#define MF_FORCECRYPT 0x400
-#define MF_NOEMULATEDSD 0x800 /* no emulated sdcard daemon, sd card is the only
- external storage */
-#define MF_NOTRIM 0x1000
-#define MF_FILEENCRYPTION 0x2000
-#define MF_FORMATTABLE 0x4000
-#define MF_SLOTSELECT 0x8000
-#define MF_FORCEFDEORFBE 0x10000
-#define MF_LATEMOUNT 0x20000
-#define MF_NOFAIL 0x40000
+#define MF_WAIT 0x1
+#define MF_CHECK 0x2
+#define MF_CRYPT 0x4
+#define MF_NONREMOVABLE 0x8
+#define MF_VOLDMANAGED 0x10
+#define MF_LENGTH 0x20
+#define MF_RECOVERYONLY 0x40
+#define MF_SWAPPRIO 0x80
+#define MF_ZRAMSIZE 0x100
+#define MF_VERIFY 0x200
+#define MF_FORCECRYPT 0x400
+#define MF_NOEMULATEDSD 0x800 /* no emulated sdcard daemon, sd card is the only
+ external storage */
+#define MF_NOTRIM 0x1000
+#define MF_FILEENCRYPTION 0x2000
+#define MF_FORMATTABLE 0x4000
+#define MF_SLOTSELECT 0x8000
+#define MF_FORCEFDEORFBE 0x10000
+#define MF_LATEMOUNT 0x20000
+#define MF_NOFAIL 0x40000
+#define MF_VERIFYATBOOT 0x80000
#define MF_MAX_COMP_STREAMS 0x100000
+#define MF_RESERVEDSIZE 0x200000
+#define MF_QUOTA 0x400000
#define DM_BUF_SIZE 4096
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 9323069..e7a0a1d 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -75,6 +75,7 @@
int swap_prio;
int max_comp_streams;
unsigned int zram_size;
+ uint64_t reserved_size;
unsigned int file_encryption_mode;
};
@@ -122,6 +123,7 @@
int fs_mgr_is_formattable(struct fstab_rec *fstab);
int fs_mgr_is_nofail(struct fstab_rec *fstab);
int fs_mgr_is_latemount(struct fstab_rec *fstab);
+int fs_mgr_is_quota(struct fstab_rec *fstab);
int fs_mgr_swapon_all(struct fstab *fstab);
int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer);
diff --git a/gatekeeperd/SoftGateKeeper.h b/gatekeeperd/SoftGateKeeper.h
index 8b15d72..cb02a6f 100644
--- a/gatekeeperd/SoftGateKeeper.h
+++ b/gatekeeperd/SoftGateKeeper.h
@@ -152,7 +152,7 @@
}
bool DoVerify(const password_handle_t *expected_handle, const SizedBuffer &password) {
- uint64_t user_id = android::base::get_unaligned(&expected_handle->user_id);
+ uint64_t user_id = android::base::get_unaligned<secure_id_t>(&expected_handle->user_id);
FastHashMap::const_iterator it = fast_hash_map_.find(user_id);
if (it != fast_hash_map_.end() && VerifyFast(it->second, password)) {
return true;
diff --git a/include/cutils/multiuser.h b/include/cutils/multiuser.h
index 7e7f815..4f23776 100644
--- a/include/cutils/multiuser.h
+++ b/include/cutils/multiuser.h
@@ -23,19 +23,19 @@
extern "C" {
#endif
-// NOTE: keep in sync with android.os.UserId
-
-#define MULTIUSER_APP_PER_USER_RANGE 100000
-#define MULTIUSER_FIRST_SHARED_APPLICATION_GID 50000
-#define MULTIUSER_FIRST_APPLICATION_UID 10000
-
typedef uid_t userid_t;
typedef uid_t appid_t;
extern userid_t multiuser_get_user_id(uid_t uid);
extern appid_t multiuser_get_app_id(uid_t uid);
-extern uid_t multiuser_get_uid(userid_t userId, appid_t appId);
-extern appid_t multiuser_get_shared_app_gid(uid_t uid);
+
+extern uid_t multiuser_get_uid(userid_t user_id, appid_t app_id);
+
+extern gid_t multiuser_get_cache_gid(userid_t user_id, appid_t app_id);
+extern gid_t multiuser_get_shared_gid(userid_t user_id, appid_t app_id);
+
+/* TODO: switch callers over to multiuser_get_shared_gid() */
+extern gid_t multiuser_get_shared_app_gid(uid_t uid);
#ifdef __cplusplus
}
diff --git a/include/cutils/trace.h b/include/cutils/trace.h
index 0f00417..fcbdc9b 100644
--- a/include/cutils/trace.h
+++ b/include/cutils/trace.h
@@ -71,7 +71,8 @@
#define ATRACE_TAG_SYSTEM_SERVER (1<<19)
#define ATRACE_TAG_DATABASE (1<<20)
#define ATRACE_TAG_NETWORK (1<<21)
-#define ATRACE_TAG_LAST ATRACE_TAG_NETWORK
+#define ATRACE_TAG_ADB (1<<22)
+#define ATRACE_TAG_LAST ATRACE_TAG_ADB
// Reserved for initialization.
#define ATRACE_TAG_NOT_READY (1ULL<<63)
diff --git a/include/log/log.h b/include/log/log.h
index d6f0eb5..ece9ea6 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -24,7 +24,7 @@
#include <stdint.h> /* uint16_t, int32_t */
#include <stdio.h>
#include <sys/types.h>
-#include <time.h> /* clock_gettime */
+#include <time.h>
#include <unistd.h>
#include <android/log.h>
@@ -812,6 +812,54 @@
void __android_log_close();
#endif
+#ifndef __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE
+#ifndef __ANDROID_API__
+#define __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE 1
+#elif __ANDROID_API__ > 25 /* > OC */
+#define __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE 1
+#else
+#define __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE 0
+#endif
+#endif
+
+#if __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE
+
+/*
+ * if last is NULL, caller _must_ provide a consistent value for seconds.
+ *
+ * Return -1 if we can not acquire a lock, which below will permit the logging,
+ * error on allowing a log message through.
+ */
+int __android_log_ratelimit(time_t seconds, time_t* last);
+
+/*
+ * Usage:
+ *
+ * // Global default and state
+ * IF_ALOG_RATELIMIT() {
+ * ALOG*(...);
+ * }
+ *
+ * // local state, 10 seconds ratelimit
+ * static time_t local_state;
+ * IF_ALOG_RATELIMIT_LOCAL(10, &local_state) {
+ * ALOG*(...);
+ * }
+ */
+
+#define IF_ALOG_RATELIMIT() \
+ if (__android_log_ratelimit(0, NULL) > 0)
+#define IF_ALOG_RATELIMIT_LOCAL(seconds, state) \
+ if (__android_log_ratelimit(seconds, state) > 0)
+
+#else
+
+/* No ratelimiting as API unsupported */
+#define IF_ALOG_RATELIMIT() if (1)
+#define IF_ALOG_RATELIMIT_LOCAL(...) if (1)
+
+#endif
+
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 80802cc..eb71fb8 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -19,6 +19,33 @@
** by the device side of adb.
*/
+/*
+ * This file is consumed by build/tools/fs_config and is used
+ * for generating various files. Anything #define AID_<name>
+ * becomes the mapping for getpwnam/getpwuid, etc. The <name>
+ * field is lowercased.
+ * For example:
+ * #define AID_FOO_BAR 6666 becomes a friendly name of "foo_bar"
+ *
+ * The above holds true with the exception of:
+ * mediacodec
+ * mediaex
+ * mediadrm
+ * Whose friendly names do not match the #define statements.
+ *
+ * Additionally, AID_OEM_RESERVED_START and AID_OEM_RESERVED_END
+ * can be used to define reserved OEM ranges used for sanity checks
+ * during the build process. The rules are, they must end with START/END
+ * The proper convention is incrementing a number like so:
+ * AID_OEM_RESERVED_START
+ * AID_OEM_RESERVED_1_START
+ * AID_OEM_RESERVED_2_START
+ * ...
+ * The same applies to the END.
+ * They are not required to be in order, but must not overlap each other and
+ * must define a START and END'ing range. START must be smaller than END.
+ */
+
#ifndef _ANDROID_FILESYSTEM_CONFIG_H_
#define _ANDROID_FILESYSTEM_CONFIG_H_
@@ -130,15 +157,21 @@
#define AID_MISC 9998 /* access to misc storage */
#define AID_NOBODY 9999
-#define AID_APP 10000 /* first app user */
+#define AID_APP 10000 /* TODO: switch users over to AID_APP_START */
+#define AID_APP_START 10000 /* first app user */
+#define AID_APP_END 19999 /* last app user */
-#define AID_ISOLATED_START 99000 /* start of uids for fully isolated sandboxed processes */
-#define AID_ISOLATED_END 99999 /* end of uids for fully isolated sandboxed processes */
-
-#define AID_USER 100000 /* offset for uid ranges for each user */
+#define AID_CACHE_GID_START 20000 /* start of gids for apps to mark cached data */
+#define AID_CACHE_GID_END 29999 /* end of gids for apps to mark cached data */
#define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */
-#define AID_SHARED_GID_END 59999 /* start of gids for apps in each user to share */
+#define AID_SHARED_GID_END 59999 /* end of gids for apps in each user to share */
+
+#define AID_ISOLATED_START 99000 /* start of uids for fully isolated sandboxed processes */
+#define AID_ISOLATED_END 99999 /* end of uids for fully isolated sandboxed processes */
+
+#define AID_USER 100000 /* TODO: switch users over to AID_USER_OFFSET */
+#define AID_USER_OFFSET 100000 /* offset for uid ranges for each user */
/*
* android_ids has moved to pwd/grp functionality.
diff --git a/include/utils/FastStrcmp.h b/include/utils/FastStrcmp.h
new file mode 100644
index 0000000..3844e7d
--- /dev/null
+++ b/include/utils/FastStrcmp.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2014-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_UTILS_FASTSTRCMP_H__
+#define _ANDROID_UTILS_FASTSTRCMP_H__
+
+#ifdef __cplusplus
+
+// Optimized for instruction cache locality
+//
+// Template class fastcmp used to create more time-efficient str*cmp
+// functions by pre-checking the first character before resorting
+// to calling the underlying string function. Profiled with a
+// measurable speedup when used in hot code. Usage is of the form:
+//
+// fastcmp<strncmp>(str1, str2, len)
+//
+// NB: Does not work for the case insensitive str*cmp functions.
+// NB: Returns boolean, do not use if expecting to check negative value.
+// Thus not semantically identical to the expected function behavior.
+
+template <int (*cmp)(const char *l, const char *r, const size_t s)>
+static inline int fastcmp(const char *l, const char *r, const size_t s) {
+ return (*l != *r) || cmp(l + 1, r + 1, s - 1);
+}
+
+template <int (*cmp)(const void *l, const void *r, const size_t s)>
+static inline int fastcmp(const void *lv, const void *rv, const size_t s) {
+ const char *l = static_cast<const char *>(lv);
+ const char *r = static_cast<const char *>(rv);
+ return (*l != *r) || cmp(l + 1, r + 1, s - 1);
+}
+
+template <int (*cmp)(const char *l, const char *r)>
+static inline int fastcmp(const char *l, const char *r) {
+ return (*l != *r) || cmp(l + 1, r + 1);
+}
+
+#endif
+
+#endif // _ANDROID_UTILS_FASTSTRCMP_H__
diff --git a/include/utils/Trace.h b/include/utils/Trace.h
index 6ba68f6..eeba40d 100644
--- a/include/utils/Trace.h
+++ b/include/utils/Trace.h
@@ -33,10 +33,10 @@
// See <cutils/trace.h> for more ATRACE_* macros.
-// ATRACE_NAME traces the beginning and end of the current scope. To trace
-// the correct start and end times this macro should be declared first in the
-// scope body.
-#define ATRACE_NAME(name) android::ScopedTrace ___tracer(ATRACE_TAG, name)
+// ATRACE_NAME traces from its location until the end of its enclosing scope.
+#define _PASTE(x, y) x ## y
+#define PASTE(x, y) _PASTE(x,y)
+#define ATRACE_NAME(name) android::ScopedTrace PASTE(___tracer, __LINE__) (ATRACE_TAG, name)
// ATRACE_CALL is an ATRACE_NAME that uses the current function name.
#define ATRACE_CALL() ATRACE_NAME(__FUNCTION__)
diff --git a/include/ziparchive/zip_archive.h b/include/ziparchive/zip_archive.h
index 54946fc..31fc2df 100644
--- a/include/ziparchive/zip_archive.h
+++ b/include/ziparchive/zip_archive.h
@@ -26,8 +26,6 @@
#include <sys/types.h>
#include <utils/Compat.h>
-__BEGIN_DECLS
-
/* Zip compression methods we support */
enum {
kCompressStored = 0, // no compression
@@ -228,6 +226,4 @@
ProcessZipEntryFunction func, void* cookie);
#endif
-__END_DECLS
-
#endif // LIBZIPARCHIVE_ZIPARCHIVE_H_
diff --git a/init/Android.mk b/init/Android.mk
index ecdf5db..111fe89 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -54,7 +54,7 @@
service.cpp \
util.cpp \
-LOCAL_STATIC_LIBRARIES := libbase libselinux liblog libprocessgroup
+LOCAL_STATIC_LIBRARIES := libbase libselinux liblog libprocessgroup libnl
LOCAL_WHOLE_STATIC_LIBRARIES := libcap
LOCAL_MODULE := libinit
LOCAL_SANITIZE := integer
@@ -103,7 +103,8 @@
libdl \
libsparse_static \
libz \
- libprocessgroup
+ libprocessgroup \
+ libnl \
# Create symlinks.
LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
diff --git a/init/bootchart.cpp b/init/bootchart.cpp
index 8fb55f0..4a9c32e 100644
--- a/init/bootchart.cpp
+++ b/init/bootchart.cpp
@@ -15,7 +15,7 @@
*/
#include "bootchart.h"
-#include "log.h"
+
#include "property_service.h"
#include <dirent.h>
@@ -29,247 +29,170 @@
#include <time.h>
#include <unistd.h>
+#include <chrono>
+#include <condition_variable>
#include <memory>
+#include <mutex>
#include <string>
+#include <thread>
#include <vector>
#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
-#define LOG_ROOT "/data/bootchart"
-#define LOG_STAT LOG_ROOT"/proc_stat.log"
-#define LOG_PROCS LOG_ROOT"/proc_ps.log"
-#define LOG_DISK LOG_ROOT"/proc_diskstats.log"
-#define LOG_HEADER LOG_ROOT"/header"
-#define LOG_ACCT LOG_ROOT"/kernel_pacct"
+using android::base::StringPrintf;
+using namespace std::chrono_literals;
-#define LOG_STARTFILE LOG_ROOT"/start"
-#define LOG_STOPFILE LOG_ROOT"/stop"
+static std::thread* g_bootcharting_thread;
-// Polling period in ms.
-static const int BOOTCHART_POLLING_MS = 200;
-
-// Max polling time in seconds.
-static const int BOOTCHART_MAX_TIME_SEC = 10*60;
-
-static long long g_last_bootchart_time;
-static int g_remaining_samples;
-
-static FILE* log_stat;
-static FILE* log_procs;
-static FILE* log_disks;
+static std::mutex g_bootcharting_finished_mutex;
+static std::condition_variable g_bootcharting_finished_cv;
+static bool g_bootcharting_finished;
static long long get_uptime_jiffies() {
- std::string uptime;
- if (!android::base::ReadFileToString("/proc/uptime", &uptime)) {
- return 0;
- }
- return 100LL * strtod(uptime.c_str(), NULL);
+ std::string uptime;
+ if (!android::base::ReadFileToString("/proc/uptime", &uptime)) return 0;
+ return 100LL * strtod(uptime.c_str(), NULL);
+}
+
+static std::unique_ptr<FILE, decltype(&fclose)> fopen_unique(const char* filename,
+ const char* mode) {
+ std::unique_ptr<FILE, decltype(&fclose)> result(fopen(filename, mode), fclose);
+ if (!result) PLOG(ERROR) << "bootchart: failed to open " << filename;
+ return result;
}
static void log_header() {
- char date[32];
- time_t now_t = time(NULL);
- struct tm now = *localtime(&now_t);
- strftime(date, sizeof(date), "%F %T", &now);
+ char date[32];
+ time_t now_t = time(NULL);
+ struct tm now = *localtime(&now_t);
+ strftime(date, sizeof(date), "%F %T", &now);
- utsname uts;
- if (uname(&uts) == -1) {
- return;
- }
+ utsname uts;
+ if (uname(&uts) == -1) return;
- std::string fingerprint = property_get("ro.build.fingerprint");
- if (fingerprint.empty()) {
- return;
- }
+ std::string fingerprint = property_get("ro.build.fingerprint");
+ if (fingerprint.empty()) return;
- std::string kernel_cmdline;
- android::base::ReadFileToString("/proc/cmdline", &kernel_cmdline);
+ std::string kernel_cmdline;
+ android::base::ReadFileToString("/proc/cmdline", &kernel_cmdline);
- FILE* out = fopen(LOG_HEADER, "we");
- if (out == NULL) {
- return;
- }
- fprintf(out, "version = Android init 0.8\n");
- fprintf(out, "title = Boot chart for Android (%s)\n", date);
- fprintf(out, "system.uname = %s %s %s %s\n", uts.sysname, uts.release, uts.version, uts.machine);
- fprintf(out, "system.release = %s\n", fingerprint.c_str());
- // TODO: use /proc/cpuinfo "model name" line for x86, "Processor" line for arm.
- fprintf(out, "system.cpu = %s\n", uts.machine);
- fprintf(out, "system.kernel.options = %s\n", kernel_cmdline.c_str());
- fclose(out);
+ auto fp = fopen_unique("/data/bootchart/header", "we");
+ if (!fp) return;
+ fprintf(&*fp, "version = Android init 0.8\n");
+ fprintf(&*fp, "title = Boot chart for Android (%s)\n", date);
+ fprintf(&*fp, "system.uname = %s %s %s %s\n", uts.sysname, uts.release, uts.version, uts.machine);
+ fprintf(&*fp, "system.release = %s\n", fingerprint.c_str());
+ // TODO: use /proc/cpuinfo "model name" line for x86, "Processor" line for arm.
+ fprintf(&*fp, "system.cpu = %s\n", uts.machine);
+ fprintf(&*fp, "system.kernel.options = %s\n", kernel_cmdline.c_str());
}
-static void do_log_uptime(FILE* log) {
- fprintf(log, "%lld\n", get_uptime_jiffies());
+static void log_uptime(FILE* log) {
+ fprintf(log, "%lld\n", get_uptime_jiffies());
}
-static void do_log_file(FILE* log, const char* procfile) {
- do_log_uptime(log);
+static void log_file(FILE* log, const char* procfile) {
+ log_uptime(log);
- std::string content;
- if (android::base::ReadFileToString(procfile, &content)) {
- fprintf(log, "%s\n", content.c_str());
- }
+ std::string content;
+ if (android::base::ReadFileToString(procfile, &content)) {
+ fprintf(log, "%s\n", content.c_str());
+ }
}
-static void do_log_procs(FILE* log) {
- do_log_uptime(log);
+static void log_processes(FILE* log) {
+ log_uptime(log);
- std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir("/proc"), closedir);
- struct dirent* entry;
- while ((entry = readdir(dir.get())) != NULL) {
- // Only match numeric values.
- char* end;
- int pid = strtol(entry->d_name, &end, 10);
- if (end != NULL && end > entry->d_name && *end == 0) {
- char filename[32];
+ std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir("/proc"), closedir);
+ struct dirent* entry;
+ while ((entry = readdir(dir.get())) != NULL) {
+ // Only match numeric values.
+ int pid = atoi(entry->d_name);
+ if (pid == 0) continue;
- // /proc/<pid>/stat only has truncated task names, so get the full
- // name from /proc/<pid>/cmdline.
- snprintf(filename, sizeof(filename), "/proc/%d/cmdline", pid);
- std::string cmdline;
- android::base::ReadFileToString(filename, &cmdline);
- const char* full_name = cmdline.c_str(); // So we stop at the first NUL.
+ // /proc/<pid>/stat only has truncated task names, so get the full
+ // name from /proc/<pid>/cmdline.
+ std::string cmdline;
+ android::base::ReadFileToString(StringPrintf("/proc/%d/cmdline", pid), &cmdline);
+ const char* full_name = cmdline.c_str(); // So we stop at the first NUL.
- // Read process stat line.
- snprintf(filename, sizeof(filename), "/proc/%d/stat", pid);
- std::string stat;
- if (android::base::ReadFileToString(filename, &stat)) {
- if (!cmdline.empty()) {
- // Substitute the process name with its real name.
- size_t open = stat.find('(');
- size_t close = stat.find_last_of(')');
- if (open != std::string::npos && close != std::string::npos) {
- stat.replace(open + 1, close - open - 1, full_name);
- }
- }
- fputs(stat.c_str(), log);
- }
+ // Read process stat line.
+ std::string stat;
+ if (android::base::ReadFileToString(StringPrintf("/proc/%d/stat", pid), &stat)) {
+ if (!cmdline.empty()) {
+ // Substitute the process name with its real name.
+ size_t open = stat.find('(');
+ size_t close = stat.find_last_of(')');
+ if (open != std::string::npos && close != std::string::npos) {
+ stat.replace(open + 1, close - open - 1, full_name);
}
+ }
+ fputs(stat.c_str(), log);
}
+ }
- fputc('\n', log);
+ fputc('\n', log);
}
-static int bootchart_init() {
- int timeout = 0;
+static void bootchart_thread_main() {
+ LOG(INFO) << "Bootcharting started";
- std::string start;
- android::base::ReadFileToString(LOG_STARTFILE, &start);
- if (!start.empty()) {
- timeout = atoi(start.c_str());
- } else {
- // When running with emulator, androidboot.bootchart=<timeout>
- // might be passed by as kernel parameters to specify the bootchart
- // timeout. this is useful when using -wipe-data since the /data
- // partition is fresh.
- std::string cmdline;
- const char* s;
- android::base::ReadFileToString("/proc/cmdline", &cmdline);
-#define KERNEL_OPTION "androidboot.bootchart="
- if ((s = strstr(cmdline.c_str(), KERNEL_OPTION)) != NULL) {
- timeout = atoi(s + sizeof(KERNEL_OPTION) - 1);
- }
- }
- if (timeout == 0)
- return 0;
+ // Open log files.
+ auto stat_log = fopen_unique("/data/bootchart/proc_stat.log", "we");
+ if (!stat_log) return;
+ auto proc_log = fopen_unique("/data/bootchart/proc_ps.log", "we");
+ if (!proc_log) return;
+ auto disk_log = fopen_unique("/data/bootchart/proc_diskstats.log", "we");
+ if (!disk_log) return;
- if (timeout > BOOTCHART_MAX_TIME_SEC)
- timeout = BOOTCHART_MAX_TIME_SEC;
+ log_header();
- int count = (timeout*1000 + BOOTCHART_POLLING_MS-1)/BOOTCHART_POLLING_MS;
-
- log_stat = fopen(LOG_STAT, "we");
- if (log_stat == NULL) {
- return -1;
- }
- log_procs = fopen(LOG_PROCS, "we");
- if (log_procs == NULL) {
- fclose(log_stat);
- return -1;
- }
- log_disks = fopen(LOG_DISK, "we");
- if (log_disks == NULL) {
- fclose(log_stat);
- fclose(log_procs);
- return -1;
+ while (true) {
+ {
+ std::unique_lock<std::mutex> lock(g_bootcharting_finished_mutex);
+ g_bootcharting_finished_cv.wait_for(lock, 200ms);
+ if (g_bootcharting_finished) break;
}
- // Create kernel process accounting file.
- close(open(LOG_ACCT, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644));
- acct(LOG_ACCT);
+ log_file(&*stat_log, "/proc/stat");
+ log_file(&*disk_log, "/proc/diskstats");
+ log_processes(&*proc_log);
+ }
- log_header();
- return count;
+ LOG(INFO) << "Bootcharting finished";
}
-int do_bootchart_init(const std::vector<std::string>& args) {
- g_remaining_samples = bootchart_init();
- if (g_remaining_samples < 0) {
- PLOG(ERROR) << "Bootcharting initialization failed";
- } else if (g_remaining_samples > 0) {
- LOG(INFO) << "Bootcharting started (will run for "
- << ((g_remaining_samples * BOOTCHART_POLLING_MS) / 1000) << " s).";
- } else {
- LOG(VERBOSE) << "Not bootcharting.";
- }
+static int do_bootchart_start() {
+ // We don't care about the content, but we do care that /data/bootchart/enabled actually exists.
+ std::string start;
+ if (!android::base::ReadFileToString("/data/bootchart/enabled", &start)) {
+ LOG(VERBOSE) << "Not bootcharting";
return 0;
+ }
+
+ g_bootcharting_thread = new std::thread(bootchart_thread_main);
+ return 0;
}
-static int bootchart_step() {
- do_log_file(log_stat, "/proc/stat");
- do_log_file(log_disks, "/proc/diskstats");
- do_log_procs(log_procs);
+static int do_bootchart_stop() {
+ if (!g_bootcharting_thread) return 0;
- // Stop if /data/bootchart/stop contains 1.
- std::string stop;
- if (android::base::ReadFileToString(LOG_STOPFILE, &stop) && stop == "1") {
- return -1;
- }
+ // Tell the worker thread it's time to quit.
+ {
+ std::lock_guard<std::mutex> lock(g_bootcharting_finished_mutex);
+ g_bootcharting_finished = true;
+ g_bootcharting_finished_cv.notify_one();
+ }
- return 0;
+ g_bootcharting_thread->join();
+ delete g_bootcharting_thread;
+ g_bootcharting_thread = nullptr;
+ return 0;
}
-/* called to get time (in ms) used by bootchart */
-static long long bootchart_gettime() {
- return 10LL*get_uptime_jiffies();
-}
-
-static void bootchart_finish() {
- unlink(LOG_STOPFILE);
- fclose(log_stat);
- fclose(log_disks);
- fclose(log_procs);
- acct(NULL);
- LOG(INFO) << "Bootcharting finished";
-}
-
-void bootchart_sample(int* timeout) {
- // Do we have any more bootcharting to do?
- if (g_remaining_samples <= 0) {
- return;
- }
-
- long long current_time = bootchart_gettime();
- int elapsed_time = current_time - g_last_bootchart_time;
-
- if (elapsed_time >= BOOTCHART_POLLING_MS) {
- // 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.
- g_last_bootchart_time = current_time;
- if (bootchart_step() < 0 || g_remaining_samples <= 0) {
- bootchart_finish();
- g_remaining_samples = 0;
- }
- }
- if (g_remaining_samples > 0) {
- int remaining_time = BOOTCHART_POLLING_MS - elapsed_time;
- if (*timeout < 0 || *timeout > remaining_time) {
- *timeout = remaining_time;
- }
- }
+int do_bootchart(const std::vector<std::string>& args) {
+ if (args[1] == "start") return do_bootchart_start();
+ return do_bootchart_stop();
}
diff --git a/init/bootchart.h b/init/bootchart.h
index 47eda7a..0e3593d 100644
--- a/init/bootchart.h
+++ b/init/bootchart.h
@@ -20,7 +20,6 @@
#include <string>
#include <vector>
-int do_bootchart_init(const std::vector<std::string>& args);
-void bootchart_sample(int* timeout);
+int do_bootchart(const std::vector<std::string>& args);
#endif /* _BOOTCHART_H */
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 42dd0c6..1186e9d 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -38,6 +38,7 @@
#include <linux/loop.h>
#include <linux/module.h>
+#include <string>
#include <thread>
#include <selinux/android.h>
@@ -67,6 +68,8 @@
#include "signal_handler.h"
#include "util.h"
+using namespace std::literals::string_literals;
+
#define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW
#define UNMOUNT_CHECK_TIMES 10
@@ -139,8 +142,7 @@
}
}
-static int wipe_data_via_recovery(const std::string& reason) {
- const std::vector<std::string> options = {"--wipe_data", std::string() + "--reason=" + reason};
+static int reboot_into_recovery(const std::vector<std::string>& options) {
std::string err;
if (!write_bootloader_message(options, &err)) {
LOG(ERROR) << "failed to set bootloader message: " << err;
@@ -247,7 +249,7 @@
}
static int do_domainname(const std::vector<std::string>& args) {
- return write_file("/proc/sys/kernel/domainname", args[1].c_str());
+ return write_file("/proc/sys/kernel/domainname", args[1].c_str()) ? 0 : 1;
}
static int do_enable(const std::vector<std::string>& args) {
@@ -275,7 +277,7 @@
}
static int do_hostname(const std::vector<std::string>& args) {
- return write_file("/proc/sys/kernel/hostname", args[1].c_str());
+ return write_file("/proc/sys/kernel/hostname", args[1].c_str()) ? 0 : 1;
}
static int do_ifup(const std::vector<std::string>& args) {
@@ -338,7 +340,10 @@
if (e4crypt_is_native()) {
if (e4crypt_set_directory_policy(args[1].c_str())) {
- wipe_data_via_recovery(std::string() + "set_policy_failed:" + args[1]);
+ const std::vector<std::string> options = {
+ "--prompt_and_wipe_data",
+ "--reason=set_policy_failed:"s + args[1]};
+ reboot_into_recovery(options);
return -1;
}
}
@@ -559,7 +564,8 @@
} else if (code == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
/* Setup a wipe via recovery, and reboot into recovery */
PLOG(ERROR) << "fs_mgr_mount_all suggested recovery, so wiping data via recovery.";
- ret = wipe_data_via_recovery("wipe_data_via_recovery");
+ const std::vector<std::string> options = {"--wipe_data", "--reason=fs_mgr_mount_all" };
+ ret = reboot_into_recovery(options);
/* If reboot worked, there is no return. */
} else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
if (e4crypt_install_keyring()) {
@@ -808,7 +814,7 @@
static int do_write(const std::vector<std::string>& args) {
const char* path = args[1].c_str();
const char* value = args[2].c_str();
- return write_file(path, value);
+ return write_file(path, value) ? 0 : 1;
}
static int do_copy(const std::vector<std::string>& args) {
@@ -1028,7 +1034,7 @@
BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
static const Map builtin_functions = {
- {"bootchart_init", {0, 0, do_bootchart_init}},
+ {"bootchart", {1, 1, do_bootchart}},
{"chmod", {2, 2, do_chmod}},
{"chown", {2, 3, do_chown}},
{"class_reset", {1, 1, do_class_reset}},
diff --git a/init/capabilities.cpp b/init/capabilities.cpp
index 4592adc..b8a9ec0 100644
--- a/init/capabilities.cpp
+++ b/init/capabilities.cpp
@@ -25,8 +25,7 @@
#define CAP_MAP_ENTRY(cap) { #cap, CAP_##cap }
-namespace {
-const std::map<std::string, int> cap_map = {
+static const std::map<std::string, int> cap_map = {
CAP_MAP_ENTRY(CHOWN),
CAP_MAP_ENTRY(DAC_OVERRIDE),
CAP_MAP_ENTRY(DAC_READ_SEARCH),
@@ -69,9 +68,30 @@
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)) {
+static bool ComputeCapAmbientSupported() {
+ return prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0) >= 0;
+}
+
+static unsigned int ComputeLastValidCap() {
+ // Android does not support kernels < 3.8. 'CAP_WAKE_ALARM' has been present since 3.0, see
+ // http://lxr.free-electrons.com/source/include/linux/capability.h?v=3.0#L360.
+ unsigned int last_valid_cap = CAP_WAKE_ALARM;
+ for (; prctl(PR_CAPBSET_READ, last_valid_cap, 0, 0, 0) >= 0; ++last_valid_cap);
+
+ // |last_valid_cap| will be the first failing value.
+ return last_valid_cap - 1;
+}
+
+static bool DropBoundingSet(const CapSet& to_keep) {
+ unsigned int last_valid_cap = GetLastValidCap();
+ // When dropping the bounding set, attempt to drop capabilities reported at
+ // run-time, not at compile-time.
+ // If the run-time kernel is older than the compile-time headers, this
+ // avoids dropping an invalid capability. If the run-time kernel is newer
+ // than the headers, this guarantees all capabilities (even those unknown at
+ // compile time) will be dropped.
+ for (size_t cap = 0; cap <= last_valid_cap; ++cap) {
+ if (cap < to_keep.size() && to_keep.test(cap)) {
// No need to drop this capability.
continue;
}
@@ -83,14 +103,14 @@
return true;
}
-bool SetProcCaps(const CapSet& to_keep, bool add_setpcap) {
+static 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) {
+ 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 ||
@@ -117,7 +137,7 @@
return true;
}
-bool SetAmbientCaps(const CapSet& to_raise) {
+static 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) {
@@ -129,8 +149,6 @@
return true;
}
-} // namespace anonymous
-
int LookupCap(const std::string& cap_name) {
auto e = cap_map.find(cap_name);
if (e != cap_map.end()) {
@@ -140,6 +158,16 @@
}
}
+bool CapAmbientSupported() {
+ static bool cap_ambient_supported = ComputeCapAmbientSupported();
+ return cap_ambient_supported;
+}
+
+unsigned int GetLastValidCap() {
+ static unsigned int last_valid_cap = ComputeLastValidCap();
+ return last_valid_cap;
+}
+
bool SetCapsForExec(const CapSet& to_keep) {
// Need to keep SETPCAP to drop bounding set below.
bool add_setpcap = true;
diff --git a/init/capabilities.h b/init/capabilities.h
index 368178d..abd7fb2 100644
--- a/init/capabilities.h
+++ b/init/capabilities.h
@@ -12,6 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#ifndef _INIT_CAPABILITIES_H
+#define _INIT_CAPABILITIES_H
+
#include <linux/capability.h>
#include <bitset>
@@ -20,4 +23,8 @@
using CapSet = std::bitset<CAP_LAST_CAP + 1>;
int LookupCap(const std::string& cap_name);
+bool CapAmbientSupported();
+unsigned int GetLastValidCap();
bool SetCapsForExec(const CapSet& to_keep);
+
+#endif // _INIT_CAPABILITIES_H
diff --git a/init/grab-bootchart.sh b/init/grab-bootchart.sh
index d6082aa..c4ff6df 100755
--- a/init/grab-bootchart.sh
+++ b/init/grab-bootchart.sh
@@ -11,7 +11,7 @@
LOGROOT=/data/bootchart
TARBALL=bootchart.tgz
-FILES="header proc_stat.log proc_ps.log proc_diskstats.log kernel_pacct"
+FILES="header proc_stat.log proc_ps.log proc_diskstats.log"
for f in $FILES; do
adb "${@}" pull $LOGROOT/$f $TMPDIR/$f 2>&1 > /dev/null
diff --git a/init/init.cpp b/init/init.cpp
index 95cb62f..ee5add8 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -49,6 +49,7 @@
#include <cutils/sockets.h>
#include <private/android_filesystem_config.h>
+#include <fstream>
#include <memory>
#include "action.h"
@@ -256,6 +257,108 @@
return result;
}
+static void security_failure() {
+ LOG(ERROR) << "Security failure...";
+ panic();
+}
+
+#define MMAP_RND_PATH "/proc/sys/vm/mmap_rnd_bits"
+#define MMAP_RND_COMPAT_PATH "/proc/sys/vm/mmap_rnd_compat_bits"
+
+/* __attribute__((unused)) due to lack of mips support: see mips block
+ * in set_mmap_rnd_bits_action */
+static bool __attribute__((unused)) set_mmap_rnd_bits_min(int start, int min, bool compat) {
+ std::string path;
+ if (compat) {
+ path = MMAP_RND_COMPAT_PATH;
+ } else {
+ path = MMAP_RND_PATH;
+ }
+ std::ifstream inf(path, std::fstream::in);
+ if (!inf) {
+ LOG(ERROR) << "Cannot open for reading: " << path;
+ return false;
+ }
+ while (start >= min) {
+ // try to write out new value
+ std::string str_val = std::to_string(start);
+ std::ofstream of(path, std::fstream::out);
+ if (!of) {
+ LOG(ERROR) << "Cannot open for writing: " << path;
+ return false;
+ }
+ of << str_val << std::endl;
+ of.close();
+
+ // check to make sure it was recorded
+ inf.seekg(0);
+ std::string str_rec;
+ inf >> str_rec;
+ if (str_val.compare(str_rec) == 0) {
+ break;
+ }
+ start--;
+ }
+ inf.close();
+ if (start < min) {
+ LOG(ERROR) << "Unable to set minimum required entropy " << min << " in " << path;
+ return false;
+ }
+ return true;
+}
+
+/*
+ * Set /proc/sys/vm/mmap_rnd_bits and potentially
+ * /proc/sys/vm/mmap_rnd_compat_bits to the maximum supported values.
+ * Returns -1 if unable to set these to an acceptable value.
+ *
+ * To support this sysctl, the following upstream commits are needed:
+ *
+ * d07e22597d1d mm: mmap: add new /proc tunable for mmap_base ASLR
+ * e0c25d958f78 arm: mm: support ARCH_MMAP_RND_BITS
+ * 8f0d3aa9de57 arm64: mm: support ARCH_MMAP_RND_BITS
+ * 9e08f57d684a x86: mm: support ARCH_MMAP_RND_BITS
+ * ec9ee4acd97c drivers: char: random: add get_random_long()
+ * 5ef11c35ce86 mm: ASLR: use get_random_long()
+ */
+static int set_mmap_rnd_bits_action(const std::vector<std::string>& args)
+{
+ int ret = -1;
+
+ /* values are arch-dependent */
+#if defined(__aarch64__)
+ /* arm64 supports 18 - 33 bits depending on pagesize and VA_SIZE */
+ if (set_mmap_rnd_bits_min(33, 24, false)
+ && set_mmap_rnd_bits_min(16, 16, true)) {
+ ret = 0;
+ }
+#elif defined(__x86_64__)
+ /* x86_64 supports 28 - 32 bits */
+ if (set_mmap_rnd_bits_min(32, 32, false)
+ && set_mmap_rnd_bits_min(16, 16, true)) {
+ ret = 0;
+ }
+#elif defined(__arm__) || defined(__i386__)
+ /* check to see if we're running on 64-bit kernel */
+ bool h64 = !access(MMAP_RND_COMPAT_PATH, F_OK);
+ /* supported 32-bit architecture must have 16 bits set */
+ if (set_mmap_rnd_bits_min(16, 16, h64)) {
+ ret = 0;
+ }
+#elif defined(__mips__) || defined(__mips64__)
+ // TODO: add mips support b/27788820
+ ret = 0;
+#else
+ LOG(ERROR) << "Unknown architecture";
+#endif
+
+ if (ret == -1) {
+ LOG(ERROR) << "Unable to set adequate mmap entropy value!";
+ security_failure();
+ }
+ return ret;
+}
+
static int keychord_init_action(const std::vector<std::string>& args)
{
keychord_init();
@@ -414,11 +517,6 @@
return 0;
}
-static void security_failure() {
- LOG(ERROR) << "Security failure...";
- panic();
-}
-
static void selinux_initialize(bool in_kernel_domain) {
Timer t;
@@ -444,7 +542,7 @@
}
}
- if (write_file("/sys/fs/selinux/checkreqprot", "0") == -1) {
+ if (!write_file("/sys/fs/selinux/checkreqprot", "0")) {
security_failure();
}
@@ -712,6 +810,7 @@
am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
// ... so that we can start queuing up actions that require stuff from /dev.
am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
+ am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits");
am.QueueBuiltinAction(keychord_init_action, "keychord_init");
am.QueueBuiltinAction(console_init_action, "console_init");
@@ -751,8 +850,6 @@
// If there's more work to do, wake up again immediately.
if (am.HasMoreCommands()) epoll_timeout_ms = 0;
- bootchart_sample(&epoll_timeout_ms);
-
epoll_event ev;
int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms));
if (nr == -1) {
diff --git a/init/log.cpp b/init/log.cpp
index 8618340..6b32526 100644
--- a/init/log.cpp
+++ b/init/log.cpp
@@ -19,6 +19,8 @@
#include <fcntl.h>
#include <string.h>
+#include <linux/audit.h>
+#include <netlink/netlink.h>
#include <selinux/selinux.h>
void InitKernelLogging(char* argv[]) {
@@ -38,6 +40,24 @@
android::base::InitLogging(argv, &android::base::KernelLogger);
}
+static void selinux_avc_log(char* buf, size_t buf_len) {
+ size_t str_len = strnlen(buf, buf_len);
+
+ // trim newline at end of string
+ buf[str_len - 1] = '\0';
+
+ struct nl_sock* sk = nl_socket_alloc();
+ if (sk == NULL) {
+ return;
+ }
+ nl_connect(sk, NETLINK_AUDIT);
+ int result;
+ do {
+ result = nl_send_simple(sk, AUDIT_USER_AVC, 0, buf, str_len);
+ } while (result == -NLE_INTR);
+ nl_socket_free(sk);
+}
+
int selinux_klog_callback(int type, const char *fmt, ...) {
android::base::LogSeverity severity = android::base::ERROR;
if (type == SELINUX_WARNING) {
@@ -48,8 +68,15 @@
char buf[1024];
va_list ap;
va_start(ap, fmt);
- vsnprintf(buf, sizeof(buf), fmt, ap);
+ int res = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
- android::base::KernelLogger(android::base::MAIN, severity, "selinux", nullptr, 0, buf);
+ if (res <= 0) {
+ return 0;
+ }
+ if (type == SELINUX_AVC) {
+ selinux_avc_log(buf, sizeof(buf));
+ } else {
+ android::base::KernelLogger(android::base::MAIN, severity, "selinux", nullptr, 0, buf);
+ }
return 0;
}
diff --git a/init/readme.txt b/init/readme.txt
index 6f40d6b..530b392 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -253,9 +253,10 @@
Commands
--------
-bootchart_init
- Start bootcharting if configured (see below).
- This is included in the default init.rc.
+bootchart [start|stop]
+ Start/stop bootcharting. These are present in the default init.rc files,
+ but bootcharting is only active if the file /data/bootchart/enabled exists;
+ otherwise bootchart start/stop are no-ops.
chmod <octal-mode> <path>
Change file access permissions.
@@ -471,19 +472,11 @@
On the emulator, use the -bootchart <timeout> option to boot with bootcharting
activated for <timeout> seconds.
-On a device, create /data/bootchart/start with a command like the following:
+On a device:
- adb shell 'echo $TIMEOUT > /data/bootchart/start'
+ adb shell 'touch /data/bootchart/enabled'
-Where the value of $TIMEOUT corresponds to the desired bootcharted period in
-seconds. Bootcharting will stop after that many seconds have elapsed.
-You can also stop the bootcharting at any moment by doing the following:
-
- adb shell 'echo 1 > /data/bootchart/stop'
-
-Note that /data/bootchart/stop is deleted automatically by init at the end of
-the bootcharting. This is not the case with /data/bootchart/start, so don't
-forget to delete it when you're done collecting data.
+Don't forget to delete this file when you're done collecting data!
The log files are written to /data/bootchart/. A script is provided to
retrieve them and create a bootchart.tgz file that can be used with the
diff --git a/init/service.cpp b/init/service.cpp
index a7eaf66..0f7f62f 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -312,13 +312,28 @@
bool Service::ParseCapabilities(const std::vector<std::string>& args, std::string* err) {
capabilities_ = 0;
+ if (!CapAmbientSupported()) {
+ *err = "capabilities requested but the kernel does not support ambient capabilities";
+ return false;
+ }
+
+ unsigned int last_valid_cap = GetLastValidCap();
+ if (last_valid_cap >= capabilities_.size()) {
+ LOG(WARNING) << "last valid run-time capability is larger than CAP_LAST_CAP";
+ }
+
for (size_t i = 1; i < args.size(); i++) {
const std::string& arg = args[i];
- int cap = LookupCap(arg);
- if (cap == -1) {
+ int res = LookupCap(arg);
+ if (res < 0) {
*err = StringPrintf("invalid capability '%s'", arg.c_str());
return false;
}
+ unsigned int cap = static_cast<unsigned int>(res); // |res| is >= 0.
+ if (cap > last_valid_cap) {
+ *err = StringPrintf("capability '%s' not supported by the kernel", arg.c_str());
+ return false;
+ }
capabilities_[cap] = true;
}
return true;
@@ -567,12 +582,15 @@
console_ = default_console;
}
- bool have_console = (open(console_.c_str(), O_RDWR | O_CLOEXEC) != -1);
- if (!have_console) {
+ // Make sure that open call succeeds to ensure a console driver is
+ // properly registered for the device node
+ int console_fd = open(console_.c_str(), O_RDWR | O_CLOEXEC);
+ if (console_fd < 0) {
PLOG(ERROR) << "service '" << name_ << "' couldn't open console '" << console_ << "'";
flags_ |= SVC_DISABLED;
return false;
}
+ close(console_fd);
}
struct stat sb;
diff --git a/init/util.cpp b/init/util.cpp
index a79a419..888a366 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -185,18 +185,18 @@
return okay;
}
-int write_file(const char* path, const char* content) {
+bool write_file(const char* path, const char* content) {
int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY|O_CREAT|O_NOFOLLOW|O_CLOEXEC, 0600));
if (fd == -1) {
PLOG(ERROR) << "write_file: Unable to open '" << path << "'";
- return -1;
+ return false;
}
- int result = android::base::WriteStringToFd(content, fd) ? 0 : -1;
- if (result == -1) {
+ bool success = android::base::WriteStringToFd(content, fd);
+ if (!success) {
PLOG(ERROR) << "write_file: Unable to write to '" << path << "'";
}
close(fd);
- return result;
+ return success;
}
boot_clock::time_point boot_clock::now() {
diff --git a/init/util.h b/init/util.h
index e63c469..009413d 100644
--- a/init/util.h
+++ b/init/util.h
@@ -33,7 +33,7 @@
uid_t uid, gid_t gid, const char *socketcon);
bool read_file(const char* path, std::string* content);
-int write_file(const char* path, const char* content);
+bool write_file(const char* path, const char* content);
// A std::chrono clock based on CLOCK_BOOTTIME.
class boot_clock {
diff --git a/libappfuse/FuseBuffer.cc b/libappfuse/FuseBuffer.cc
index 3ade31c..8fb2dbc 100644
--- a/libappfuse/FuseBuffer.cc
+++ b/libappfuse/FuseBuffer.cc
@@ -23,6 +23,7 @@
#include <algorithm>
#include <type_traits>
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/macros.h>
@@ -34,44 +35,65 @@
"FuseBuffer must be standard layout union.");
template <typename T>
-bool FuseMessage<T>::CheckHeaderLength() const {
+bool FuseMessage<T>::CheckHeaderLength(const char* name) const {
const auto& header = static_cast<const T*>(this)->header;
- if (sizeof(header) <= header.len && header.len <= sizeof(T)) {
+ if (header.len >= sizeof(header) && header.len <= sizeof(T)) {
return true;
} else {
- LOG(ERROR) << "Packet size is invalid=" << header.len;
- return false;
- }
-}
-
-template <typename T>
-bool FuseMessage<T>::CheckResult(
- int result, const char* operation_name) const {
- const auto& header = static_cast<const T*>(this)->header;
- if (result >= 0 && static_cast<uint32_t>(result) == header.len) {
- return true;
- } else {
- PLOG(ERROR) << "Failed to " << operation_name
- << " a packet. result=" << result << " header.len="
- << header.len;
+ LOG(ERROR) << "Invalid header length is found in " << name << ": " <<
+ header.len;
return false;
}
}
template <typename T>
bool FuseMessage<T>::Read(int fd) {
- const ssize_t result = TEMP_FAILURE_RETRY(::read(fd, this, sizeof(T)));
- return CheckHeaderLength() && CheckResult(result, "read");
+ char* const buf = reinterpret_cast<char*>(this);
+ const ssize_t result = TEMP_FAILURE_RETRY(::read(fd, buf, sizeof(T)));
+ if (result < 0) {
+ PLOG(ERROR) << "Failed to read a FUSE message";
+ return false;
+ }
+
+ const auto& header = static_cast<const T*>(this)->header;
+ if (result < static_cast<ssize_t>(sizeof(header))) {
+ LOG(ERROR) << "Read bytes " << result << " are shorter than header size " <<
+ sizeof(header);
+ return false;
+ }
+
+ if (!CheckHeaderLength("Read")) {
+ return false;
+ }
+
+ if (static_cast<uint32_t>(result) > header.len) {
+ LOG(ERROR) << "Read bytes " << result << " are longer than header.len " <<
+ header.len;
+ return false;
+ }
+
+ if (!base::ReadFully(fd, buf + result, header.len - result)) {
+ PLOG(ERROR) << "ReadFully failed";
+ return false;
+ }
+
+ return true;
}
template <typename T>
bool FuseMessage<T>::Write(int fd) const {
- const auto& header = static_cast<const T*>(this)->header;
- if (!CheckHeaderLength()) {
+ if (!CheckHeaderLength("Write")) {
return false;
}
- const ssize_t result = TEMP_FAILURE_RETRY(::write(fd, this, header.len));
- return CheckResult(result, "write");
+
+ const char* const buf = reinterpret_cast<const char*>(this);
+ const auto& header = static_cast<const T*>(this)->header;
+ if (!base::WriteFully(fd, buf, header.len)) {
+ PLOG(ERROR) << "WriteFully failed";
+ return false;
+ }
+
+ return true;
}
template class FuseMessage<FuseRequest>;
diff --git a/libappfuse/include/libappfuse/FuseBuffer.h b/libappfuse/include/libappfuse/FuseBuffer.h
index e7f620c..7abd2fa 100644
--- a/libappfuse/include/libappfuse/FuseBuffer.h
+++ b/libappfuse/include/libappfuse/FuseBuffer.h
@@ -34,8 +34,7 @@
bool Read(int fd);
bool Write(int fd) const;
private:
- bool CheckHeaderLength() const;
- bool CheckResult(int result, const char* operation_name) const;
+ bool CheckHeaderLength(const char* name) const;
};
// FuseRequest represents file operation requests from /dev/fuse. It starts
diff --git a/libappfuse/tests/FuseBufferTest.cc b/libappfuse/tests/FuseBufferTest.cc
index c822135..db35d33 100644
--- a/libappfuse/tests/FuseBufferTest.cc
+++ b/libappfuse/tests/FuseBufferTest.cc
@@ -20,6 +20,8 @@
#include <string.h>
#include <sys/socket.h>
+#include <thread>
+
#include <android-base/unique_fd.h>
#include <gtest/gtest.h>
@@ -110,6 +112,30 @@
TestWriteInvalidLength(sizeof(fuse_in_header) - 1);
}
+TEST(FuseMessageTest, ShortWriteAndRead) {
+ int raw_fds[2];
+ ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, raw_fds));
+
+ android::base::unique_fd fds[2];
+ fds[0].reset(raw_fds[0]);
+ fds[1].reset(raw_fds[1]);
+
+ const int send_buffer_size = 1024;
+ ASSERT_EQ(0, setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, &send_buffer_size,
+ sizeof(int)));
+
+ bool succeed = false;
+ const int sender_fd = fds[0].get();
+ std::thread thread([sender_fd, &succeed] {
+ FuseRequest request;
+ request.header.len = 1024 * 4;
+ succeed = request.Write(sender_fd);
+ });
+ thread.detach();
+ FuseRequest request;
+ ASSERT_TRUE(request.Read(fds[1]));
+}
+
TEST(FuseResponseTest, Reset) {
FuseResponse response;
// Write 1 to the first ten bytes.
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 200b6d6..5b31ecb 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -22,27 +22,13 @@
"-Werror",
],
+ // The latest clang (r230699) does not allow SP/PC to be declared in inline asm lists.
clang_cflags: ["-Wno-inline-asm"],
- // The latest clang (r230699) does not allow SP/PC to be declared in inline asm lists.
include_dirs: ["external/libunwind/include/tdep"],
- // TODO: LLVM_DEVICE_BUILD_MK
- // TODO: LLVM_HOST_BUILD_MK
target: {
- host: {
- // -fno-omit-frame-pointer should be set for host build. Because currently
- // libunwind can't recognize .debug_frame using dwarf version 4, and it relies
- // on stack frame pointer to do unwinding on x86.
- // $(LLVM_HOST_BUILD_MK) overwrites -fno-omit-frame-pointer. so the below line
- // must be after the include.
- cflags: [
- "-Wno-extern-c-compat",
- "-fno-omit-frame-pointer",
- ],
- },
-
darwin: {
enabled: false,
},
@@ -130,4 +116,95 @@
],
},
}
-}
\ No newline at end of file
+}
+
+//-------------------------------------------------------------------------
+// The libbacktrace_offline static library.
+//-------------------------------------------------------------------------
+cc_library_static {
+ name: "libbacktrace_offline",
+ defaults: ["libbacktrace_common"],
+ host_supported: true,
+ srcs: ["BacktraceOffline.cpp"],
+
+ cflags: [
+ "-D__STDC_CONSTANT_MACROS",
+ "-D__STDC_LIMIT_MACROS",
+ "-D__STDC_FORMAT_MACROS",
+ ],
+
+ header_libs: ["llvm-headers"],
+
+ // Use shared libraries so their headers get included during build.
+ shared_libs = [
+ "libbase",
+ "libunwind",
+ ],
+}
+
+//-------------------------------------------------------------------------
+// The backtrace_test executable.
+//-------------------------------------------------------------------------
+cc_test {
+ name: "backtrace_test",
+ defaults: ["libbacktrace_common"],
+ host_supported: true,
+ srcs: [
+ "backtrace_offline_test.cpp",
+ "backtrace_test.cpp",
+ "GetPss.cpp",
+ "thread_utils.c",
+ ],
+
+ cflags: [
+ "-fno-builtin",
+ "-O0",
+ "-g",
+ ],
+
+ shared_libs: [
+ "libbacktrace_test",
+ "libbacktrace",
+ "libbase",
+ "libcutils",
+ "liblog",
+ "libunwind",
+ ],
+
+ group_static_libs: true,
+
+ // Statically link LLVMlibraries to remove dependency on llvm shared library.
+ static_libs = [
+ "libbacktrace_offline",
+ "libLLVMObject",
+ "libLLVMBitReader",
+ "libLLVMMC",
+ "libLLVMMCParser",
+ "libLLVMCore",
+ "libLLVMSupport",
+
+ "libziparchive",
+ "libz",
+ ],
+
+ header_libs: ["llvm-headers"],
+
+ target: {
+ android: {
+ cflags: ["-DENABLE_PSS_TESTS"],
+ shared_libs: [
+ "libdl",
+ "libutils",
+ ],
+ },
+ linux: {
+ host_ldlibs: [
+ "-lpthread",
+ "-lrt",
+ "-ldl",
+ "-lncurses",
+ ],
+ static_libs: ["libutils"],
+ },
+ },
+}
diff --git a/libbacktrace/Android.build.mk b/libbacktrace/Android.build.mk
deleted file mode 100644
index 2467f3e..0000000
--- a/libbacktrace/Android.build.mk
+++ /dev/null
@@ -1,95 +0,0 @@
-#
-# Copyright (C) 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.
-#
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := $(module)
-LOCAL_MODULE_TAGS := $(module_tag)
-LOCAL_MULTILIB := $($(module)_multilib)
-ifeq ($(LOCAL_MULTILIB),both)
-ifneq ($(build_target),$(filter $(build_target),SHARED_LIBRARY STATIC_LIBRARY))
- LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
- LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-endif
-endif
-
-ifeq ($(build_type),target)
- include $(LLVM_DEVICE_BUILD_MK)
-else
- include $(LLVM_HOST_BUILD_MK)
-endif
-
-LOCAL_ADDITIONAL_DEPENDENCIES += \
- $(LOCAL_PATH)/Android.mk \
- $(LOCAL_PATH)/Android.build.mk \
-
-LOCAL_CFLAGS += \
- $(libbacktrace_common_cflags) \
- $($(module)_cflags) \
- $($(module)_cflags_$(build_type)) \
-
-LOCAL_CLANG_CFLAGS += \
- $(libbacktrace_common_clang_cflags) \
-
-LOCAL_CONLYFLAGS += \
- $(libbacktrace_common_conlyflags) \
- $($(module)_conlyflags) \
- $($(module)_conlyflags_$(build_type)) \
-
-LOCAL_CPPFLAGS += \
- $(libbacktrace_common_cppflags) \
- $($(module)_cppflags) \
- $($(module)_cppflags_$(build_type)) \
-
-LOCAL_C_INCLUDES += \
- $(libbacktrace_common_c_includes) \
- $($(module)_c_includes) \
- $($(module)_c_includes_$(build_type)) \
-
-LOCAL_SRC_FILES := \
- $($(module)_src_files) \
- $($(module)_src_files_$(build_type)) \
-
-LOCAL_STATIC_LIBRARIES += \
- $($(module)_static_libraries) \
- $($(module)_static_libraries_$(build_type)) \
-
-LOCAL_SHARED_LIBRARIES += \
- $($(module)_shared_libraries) \
- $($(module)_shared_libraries_$(build_type)) \
-
-LOCAL_LDLIBS += \
- $($(module)_ldlibs) \
- $($(module)_ldlibs_$(build_type)) \
-
-LOCAL_STRIP_MODULE := $($(module)_strip_module)
-
-ifeq ($(build_type),target)
- include $(BUILD_$(build_target))
-endif
-
-ifeq ($(build_type),host)
- # Only build if host builds are supported.
- ifeq ($(build_host),true)
- # -fno-omit-frame-pointer should be set for host build. Because currently
- # libunwind can't recognize .debug_frame using dwarf version 4, and it relies
- # on stack frame pointer to do unwinding on x86.
- # $(LLVM_HOST_BUILD_MK) overwrites -fno-omit-frame-pointer. so the below line
- # must be after the include.
- LOCAL_CFLAGS += -Wno-extern-c-compat -fno-omit-frame-pointer
- include $(BUILD_HOST_$(build_target))
- endif
-endif
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
deleted file mode 100644
index f4976e9..0000000
--- a/libbacktrace/Android.mk
+++ /dev/null
@@ -1,121 +0,0 @@
-#
-# Copyright (C) 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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-libbacktrace_common_cflags := \
- -Wall \
- -Werror \
-
-libbacktrace_common_c_includes := \
- external/libunwind/include/tdep \
-
-# The latest clang (r230699) does not allow SP/PC to be declared in inline asm lists.
-libbacktrace_common_clang_cflags += \
- -Wno-inline-asm
-
-build_host := false
-ifeq ($(HOST_OS),linux)
-ifeq ($(HOST_ARCH),$(filter $(HOST_ARCH),x86 x86_64))
-build_host := true
-endif
-endif
-
-LLVM_ROOT_PATH := external/llvm
-include $(LLVM_ROOT_PATH)/llvm.mk
-
-#-------------------------------------------------------------------------
-# The libbacktrace_offline static library.
-#-------------------------------------------------------------------------
-libbacktrace_offline_src_files := \
- BacktraceOffline.cpp \
-
-# Use shared libraries so their headers get included during build.
-libbacktrace_offline_shared_libraries := \
- libbase \
- libunwind \
-
-module := libbacktrace_offline
-build_type := target
-build_target := STATIC_LIBRARY
-libbacktrace_offline_multilib := both
-include $(LOCAL_PATH)/Android.build.mk
-build_type := host
-include $(LOCAL_PATH)/Android.build.mk
-
-#-------------------------------------------------------------------------
-# The backtrace_test executable.
-#-------------------------------------------------------------------------
-backtrace_test_cflags := \
- -fno-builtin \
- -O0 \
- -g \
-
-backtrace_test_cflags_target := \
- -DENABLE_PSS_TESTS \
-
-backtrace_test_src_files := \
- backtrace_offline_test.cpp \
- backtrace_test.cpp \
- GetPss.cpp \
- thread_utils.c \
-
-backtrace_test_ldlibs_host := \
- -lpthread \
- -lrt \
-
-backtrace_test_shared_libraries := \
- libbacktrace_test \
- libbacktrace \
- libbase \
- libcutils \
- liblog \
- libunwind \
-
-backtrace_test_shared_libraries_target += \
- libdl \
- libutils \
-
-# Statically link LLVMlibraries to remove dependency on llvm shared library.
-backtrace_test_static_libraries := \
- libbacktrace_offline \
- libLLVMObject \
- libLLVMBitReader \
- libLLVMMC \
- libLLVMMCParser \
- libLLVMCore \
- libLLVMSupport \
-
-backtrace_test_static_libraries_target := \
- libziparchive \
- libz \
-
-backtrace_test_static_libraries_host := \
- libziparchive \
- libz \
- libutils \
-
-backtrace_test_ldlibs_host += \
- -ldl \
-
-module := backtrace_test
-module_tag := debug
-build_type := target
-build_target := NATIVE_TEST
-backtrace_test_multilib := both
-include $(LOCAL_PATH)/Android.build.mk
-build_type := host
-include $(LOCAL_PATH)/Android.build.mk
diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp
index 9e95563..5e54328 100644
--- a/libbacktrace/BacktraceOffline.cpp
+++ b/libbacktrace/BacktraceOffline.cpp
@@ -34,6 +34,7 @@
#include <vector>
#include <android-base/file.h>
+#include <android-base/macros.h>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
#include <ziparchive/zip_archive.h>
@@ -534,6 +535,10 @@
default:
result = false;
}
+#else
+ UNUSED(reg);
+ UNUSED(value);
+ result = false;
#endif
return result;
}
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 032e361..6155d16 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -188,6 +188,9 @@
{ 00750, AID_ROOT, AID_SHELL, 0, "init*" },
{ 00750, AID_ROOT, AID_SHELL, 0, "sbin/fs_mgr" },
{ 00640, AID_ROOT, AID_SHELL, 0, "fstab.*" },
+ { 00600, AID_ROOT, AID_ROOT, 0, "system/build.prop" },
+ { 00600, AID_ROOT, AID_ROOT, 0, "vendor/build.prop" },
+ { 00600, AID_ROOT, AID_ROOT, 0, "default.prop" },
{ 00644, AID_ROOT, AID_ROOT, 0, 0 },
};
diff --git a/libcutils/multiuser.c b/libcutils/multiuser.c
index 0f4427b..0ef337d 100644
--- a/libcutils/multiuser.c
+++ b/libcutils/multiuser.c
@@ -15,21 +15,36 @@
*/
#include <cutils/multiuser.h>
+#include <private/android_filesystem_config.h>
userid_t multiuser_get_user_id(uid_t uid) {
- return uid / MULTIUSER_APP_PER_USER_RANGE;
+ return uid / AID_USER_OFFSET;
}
appid_t multiuser_get_app_id(uid_t uid) {
- return uid % MULTIUSER_APP_PER_USER_RANGE;
+ return uid % AID_USER_OFFSET;
}
-uid_t multiuser_get_uid(userid_t userId, appid_t appId) {
- return userId * MULTIUSER_APP_PER_USER_RANGE + (appId % MULTIUSER_APP_PER_USER_RANGE);
+uid_t multiuser_get_uid(userid_t user_id, appid_t app_id) {
+ return (user_id * AID_USER_OFFSET) + (app_id % AID_USER_OFFSET);
}
-appid_t multiuser_get_shared_app_gid(uid_t id) {
- return MULTIUSER_FIRST_SHARED_APPLICATION_GID + (id % MULTIUSER_APP_PER_USER_RANGE)
- - MULTIUSER_FIRST_APPLICATION_UID;
+gid_t multiuser_get_cache_gid(userid_t user_id, appid_t app_id) {
+ if (app_id >= AID_APP_START && app_id <= AID_APP_END) {
+ return multiuser_get_uid(user_id, (app_id - AID_APP_START) + AID_CACHE_GID_START);
+ } else {
+ return -1;
+ }
+}
+gid_t multiuser_get_shared_gid(userid_t user_id, appid_t app_id) {
+ if (app_id >= AID_APP_START && app_id <= AID_APP_END) {
+ return multiuser_get_uid(user_id, (app_id - AID_APP_START) + AID_SHARED_GID_START);
+ } else {
+ return -1;
+ }
+}
+
+gid_t multiuser_get_shared_app_gid(uid_t uid) {
+ return multiuser_get_shared_gid(multiuser_get_user_id(uid), multiuser_get_app_id(uid));
}
diff --git a/libcutils/properties.c b/libcutils/properties.c
index 5aa6371..740c7a9 100644
--- a/libcutils/properties.c
+++ b/libcutils/properties.c
@@ -36,7 +36,7 @@
}
int8_t result = default_value;
- char buf[PROPERTY_VALUE_MAX] = {'\0',};
+ char buf[PROPERTY_VALUE_MAX] = {'\0'};
int len = property_get(key, buf, "");
if (len == 1) {
@@ -47,7 +47,7 @@
result = true;
}
} else if (len > 1) {
- if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) {
+ if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) {
result = false;
} else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on")) {
result = true;
@@ -59,13 +59,13 @@
// Convert string property to int (default if fails); return default value if out of bounds
static intmax_t property_get_imax(const char *key, intmax_t lower_bound, intmax_t upper_bound,
- intmax_t default_value) {
+ intmax_t default_value) {
if (!key) {
return default_value;
}
intmax_t result = default_value;
- char buf[PROPERTY_VALUE_MAX] = {'\0',};
+ char buf[PROPERTY_VALUE_MAX] = {'\0'};
char *end = NULL;
int len = property_get(key, buf, "");
@@ -74,7 +74,7 @@
errno = 0;
// Infer base automatically
- result = strtoimax(buf, &end, /*base*/0);
+ result = strtoimax(buf, &end, /*base*/ 0);
if ((result == INTMAX_MIN || result == INTMAX_MAX) && errno == ERANGE) {
// Over or underflow
result = default_value;
@@ -86,8 +86,8 @@
} else if (end == buf) {
// Numeric conversion failed
result = default_value;
- ALOGV("%s(%s,%" PRIdMAX ") - numeric conversion failed",
- __FUNCTION__, key, default_value);
+ ALOGV("%s(%s,%" PRIdMAX ") - numeric conversion failed", __FUNCTION__, key,
+ default_value);
}
errno = tmp;
@@ -107,38 +107,31 @@
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
-int property_set(const char *key, const char *value)
-{
+int property_set(const char *key, const char *value) {
return __system_property_set(key, value);
}
-int property_get(const char *key, char *value, const char *default_value)
-{
+int property_get(const char *key, char *value, const char *default_value) {
int len;
len = __system_property_get(key, value);
- if(len > 0) {
+ if (len > 0) {
return len;
}
- if(default_value) {
- len = strlen(default_value);
- if (len >= PROPERTY_VALUE_MAX) {
- len = PROPERTY_VALUE_MAX - 1;
- }
+ if (default_value) {
+ len = strnlen(default_value, PROPERTY_VALUE_MAX - 1);
memcpy(value, default_value, len);
value[len] = '\0';
}
return len;
}
-struct property_list_callback_data
-{
+struct property_list_callback_data {
void (*propfn)(const char *key, const char *value, void *cookie);
void *cookie;
};
-static void property_list_callback(const prop_info *pi, void *cookie)
-{
+static void property_list_callback(const prop_info *pi, void *cookie) {
char name[PROP_NAME_MAX];
char value[PROP_VALUE_MAX];
struct property_list_callback_data *data = cookie;
@@ -147,10 +140,7 @@
data->propfn(name, value, data->cookie);
}
-int property_list(
- void (*propfn)(const char *key, const char *value, void *cookie),
- void *cookie)
-{
- struct property_list_callback_data data = { propfn, cookie };
+int property_list(void (*propfn)(const char *key, const char *value, void *cookie), void *cookie) {
+ struct property_list_callback_data data = {propfn, cookie};
return __system_property_foreach(property_list_callback, &data);
}
diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp
index abe3c21..0b0dc09 100644
--- a/libcutils/tests/Android.bp
+++ b/libcutils/tests/Android.bp
@@ -26,7 +26,8 @@
"trace-dev_test.cpp",
"test_str_parms.cpp",
"android_get_control_socket_test.cpp",
- "android_get_control_file_test.cpp"
+ "android_get_control_file_test.cpp",
+ "multiuser_test.cpp"
],
},
diff --git a/libcutils/tests/PropertiesTest.cpp b/libcutils/tests/PropertiesTest.cpp
index f0cdffd..7921972 100644
--- a/libcutils/tests/PropertiesTest.cpp
+++ b/libcutils/tests/PropertiesTest.cpp
@@ -159,19 +159,68 @@
TEST_F(PropertiesTest, GetString) {
- // Try to use a default value that's too long => set fails
+ // Try to use a default value that's too long => get truncates the value
{
ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
- std::string maxLengthString = std::string(PROPERTY_VALUE_MAX-1, 'a');
+ std::string maxLengthString = std::string(PROPERTY_VALUE_MAX - 1, 'a');
std::string oneLongerString = std::string(PROPERTY_VALUE_MAX, 'a');
// Expect that the value is truncated since it's too long (by 1)
int len = property_get(PROPERTY_TEST_KEY, mValue, oneLongerString.c_str());
- EXPECT_EQ(PROPERTY_VALUE_MAX-1, len);
+ EXPECT_EQ(PROPERTY_VALUE_MAX - 1, len);
EXPECT_STREQ(maxLengthString.c_str(), mValue);
ResetValue();
}
+
+ // Try to use a default value that's the max length => get succeeds
+ {
+ ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
+
+ std::string maxLengthString = std::string(PROPERTY_VALUE_MAX - 1, 'b');
+
+ // Expect that the value matches maxLengthString
+ int len = property_get(PROPERTY_TEST_KEY, mValue, maxLengthString.c_str());
+ EXPECT_EQ(PROPERTY_VALUE_MAX - 1, len);
+ EXPECT_STREQ(maxLengthString.c_str(), mValue);
+ ResetValue();
+ }
+
+ // Try to use a default value of length one => get succeeds
+ {
+ ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
+
+ std::string oneCharString = std::string(1, 'c');
+
+ // Expect that the value matches oneCharString
+ int len = property_get(PROPERTY_TEST_KEY, mValue, oneCharString.c_str());
+ EXPECT_EQ(1, len);
+ EXPECT_STREQ(oneCharString.c_str(), mValue);
+ ResetValue();
+ }
+
+ // Try to use a default value of length zero => get succeeds
+ {
+ ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
+
+ std::string zeroCharString = std::string(0, 'd');
+
+ // Expect that the value matches oneCharString
+ int len = property_get(PROPERTY_TEST_KEY, mValue, zeroCharString.c_str());
+ EXPECT_EQ(0, len);
+ EXPECT_STREQ(zeroCharString.c_str(), mValue);
+ ResetValue();
+ }
+
+ // Try to use a NULL default value => get returns 0
+ {
+ ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
+
+ // Expect a return value of 0
+ int len = property_get(PROPERTY_TEST_KEY, mValue, NULL);
+ EXPECT_EQ(0, len);
+ ResetValue();
+ }
}
TEST_F(PropertiesTest, GetBool) {
diff --git a/libcutils/tests/multiuser_test.cpp b/libcutils/tests/multiuser_test.cpp
new file mode 100644
index 0000000..2307ea8
--- /dev/null
+++ b/libcutils/tests/multiuser_test.cpp
@@ -0,0 +1,67 @@
+/*
+ * 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 <cutils/multiuser.h>
+#include <gtest/gtest.h>
+
+TEST(MultiuserTest, TestMerge) {
+ EXPECT_EQ(0, multiuser_get_uid(0, 0));
+ EXPECT_EQ(1000, multiuser_get_uid(0, 1000));
+ EXPECT_EQ(10000, multiuser_get_uid(0, 10000));
+ EXPECT_EQ(50000, multiuser_get_uid(0, 50000));
+ EXPECT_EQ(1000000, multiuser_get_uid(10, 0));
+ EXPECT_EQ(1001000, multiuser_get_uid(10, 1000));
+ EXPECT_EQ(1010000, multiuser_get_uid(10, 10000));
+ EXPECT_EQ(1050000, multiuser_get_uid(10, 50000));
+}
+
+TEST(MultiuserTest, TestSplitUser) {
+ EXPECT_EQ(0, multiuser_get_user_id(0));
+ EXPECT_EQ(0, multiuser_get_user_id(1000));
+ EXPECT_EQ(0, multiuser_get_user_id(10000));
+ EXPECT_EQ(0, multiuser_get_user_id(50000));
+ EXPECT_EQ(10, multiuser_get_user_id(1000000));
+ EXPECT_EQ(10, multiuser_get_user_id(1001000));
+ EXPECT_EQ(10, multiuser_get_user_id(1010000));
+ EXPECT_EQ(10, multiuser_get_user_id(1050000));
+}
+
+TEST(MultiuserTest, TestSplitApp) {
+ EXPECT_EQ(0, multiuser_get_app_id(0));
+ EXPECT_EQ(1000, multiuser_get_app_id(1000));
+ EXPECT_EQ(10000, multiuser_get_app_id(10000));
+ EXPECT_EQ(50000, multiuser_get_app_id(50000));
+ EXPECT_EQ(0, multiuser_get_app_id(1000000));
+ EXPECT_EQ(1000, multiuser_get_app_id(1001000));
+ EXPECT_EQ(10000, multiuser_get_app_id(1010000));
+ EXPECT_EQ(50000, multiuser_get_app_id(1050000));
+}
+
+TEST(MultiuserTest, TestCache) {
+ EXPECT_EQ(-1, multiuser_get_cache_gid(0, 0));
+ EXPECT_EQ(-1, multiuser_get_cache_gid(0, 1000));
+ EXPECT_EQ(20000, multiuser_get_cache_gid(0, 10000));
+ EXPECT_EQ(-1, multiuser_get_cache_gid(0, 50000));
+ EXPECT_EQ(1020000, multiuser_get_cache_gid(10, 10000));
+}
+
+TEST(MultiuserTest, TestShared) {
+ EXPECT_EQ(-1, multiuser_get_shared_gid(0, 0));
+ EXPECT_EQ(-1, multiuser_get_shared_gid(0, 1000));
+ EXPECT_EQ(50000, multiuser_get_shared_gid(0, 10000));
+ EXPECT_EQ(-1, multiuser_get_shared_gid(0, 50000));
+ EXPECT_EQ(1050000, multiuser_get_shared_gid(10, 10000));
+}
diff --git a/libcutils/uevent.c b/libcutils/uevent.c
index de5d227..f548dca 100644
--- a/libcutils/uevent.c
+++ b/libcutils/uevent.c
@@ -116,7 +116,12 @@
if(s < 0)
return -1;
- setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &buf_sz, sizeof(buf_sz));
+ /* buf_sz should be less than net.core.rmem_max for this to succeed */
+ if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &buf_sz, sizeof(buf_sz)) < 0) {
+ close(s);
+ return -1;
+ }
+
setsockopt(s, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
diff --git a/liblog/Android.bp b/liblog/Android.bp
index e59a460..bbe7d79 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -21,6 +21,7 @@
"config_write.c",
"logger_name.c",
"logger_lock.c",
+ "log_ratelimit.cpp",
]
liblog_host_sources = [
"fake_log_device.c",
@@ -30,7 +31,7 @@
"event_tag_map.cpp",
"config_read.c",
"log_time.cpp",
- "log_is_loggable.c",
+ "properties.c",
"logprint.c",
"pmsg_reader.c",
"pmsg_writer.c",
@@ -114,4 +115,5 @@
name: "liblog.ndk",
symbol_file: "liblog.map.txt",
first_version: "9",
+ unversioned_until: "current",
}
diff --git a/liblog/event_tag_map.cpp b/liblog/event_tag_map.cpp
index e8e0335..1155422 100644
--- a/liblog/event_tag_map.cpp
+++ b/liblog/event_tag_map.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2007-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.
@@ -24,362 +24,106 @@
#include <string.h>
#include <sys/mman.h>
-#include <android/log.h>
+#include <experimental/string_view>
+#include <functional>
+#include <unordered_map>
+
#include <log/event_tag_map.h>
#include "log_portability.h"
#define OUT_TAG "EventTagMap"
-/*
- * Single entry.
- */
-typedef struct EventTag {
- uint32_t tagIndex;
- char* tagStr;
- size_t tagLen;
- char* fmtStr;
- size_t fmtLen;
-} EventTag;
+typedef std::experimental::string_view MapString;
-/*
- * Map.
- */
-struct EventTagMap {
- /* memory-mapped source file; we get strings from here */
- void* mapAddr;
- size_t mapLen;
+typedef std::pair<MapString, MapString> TagFmt;
- /* array of event tags, sorted numerically by tag index */
- EventTag* tagArray;
- int numTags;
+template <> struct _LIBCPP_TYPE_VIS_ONLY std::hash<TagFmt>
+ : public std::unary_function<const TagFmt&, size_t> {
+ _LIBCPP_INLINE_VISIBILITY
+ size_t operator()(const TagFmt& __t) const _NOEXCEPT {
+ // Tag is typically unique. Will cost us an extra 100ns for the
+ // unordered_map lookup if we instead did a hash that combined
+ // both of tag and fmt members, e.g.:
+ //
+ // return std::hash<MapString>()(__t.first) ^
+ // std::hash<MapString>()(__t.second);
+ return std::hash<MapString>()(__t.first);
+ }
};
-/* fwd */
-static int processFile(EventTagMap* map);
-static int countMapLines(const EventTagMap* map);
-static int parseMapLines(EventTagMap* map);
-static int scanTagLine(char** pData, EventTag* tag, int lineNum);
-static int sortTags(EventTagMap* map);
+// Map
+struct EventTagMap {
+ // memory-mapped source file; we get strings from here
+ void* mapAddr;
+ size_t mapLen;
-/*
- * Open the map file and allocate a structure to manage it.
- *
- * We create a private mapping because we want to terminate the log tag
- * strings with '\0'.
- */
-LIBLOG_ABI_PUBLIC EventTagMap* android_openEventTagMap(const char* fileName)
-{
- EventTagMap* newTagMap;
- off_t end;
- int save_errno;
- const char* tagfile = fileName ? fileName : EVENT_TAG_MAP_FILE;
+private:
+ std::unordered_map<uint32_t, TagFmt> Idx2TagFmt;
- int fd = open(tagfile, O_RDONLY | O_CLOEXEC);
- if (fd < 0) {
- save_errno = errno;
- fprintf(stderr, "%s: unable to open map '%s': %s\n",
- OUT_TAG, tagfile, strerror(save_errno));
- goto fail_errno;
- }
+public:
+ EventTagMap() : mapAddr(NULL), mapLen(0) { }
- end = lseek(fd, 0L, SEEK_END);
- save_errno = errno;
- (void) lseek(fd, 0L, SEEK_SET);
- if (end < 0) {
- fprintf(stderr, "%s: unable to seek map '%s' %s\n",
- OUT_TAG, tagfile, strerror(save_errno));
- goto fail_close;
- }
-
- newTagMap = (EventTagMap*)calloc(1, sizeof(EventTagMap));
- if (newTagMap == NULL) {
- save_errno = errno;
- goto fail_close;
- }
-
- newTagMap->mapAddr = mmap(NULL, end, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
- save_errno = errno;
- close(fd);
- fd = -1;
- if ((newTagMap->mapAddr == MAP_FAILED) || (newTagMap->mapAddr == NULL)) {
- fprintf(stderr, "%s: mmap(%s) failed: %s\n",
- OUT_TAG, tagfile, strerror(save_errno));
- goto fail_free;
- }
-
- newTagMap->mapLen = end;
-
- if (processFile(newTagMap) != 0) goto fail_unmap;
-
- return newTagMap;
-
-fail_unmap:
- munmap(newTagMap->mapAddr, newTagMap->mapLen);
- save_errno = EINVAL;
-fail_free:
- free(newTagMap);
-fail_close:
- close(fd);
-fail_errno:
- errno = save_errno;
-fail:
- return NULL;
-}
-
-/*
- * Close the map.
- */
-LIBLOG_ABI_PUBLIC void android_closeEventTagMap(EventTagMap* map)
-{
- if (map == NULL) return;
-
- munmap(map->mapAddr, map->mapLen);
- free(map->tagArray);
- free(map);
-}
-
-/*
- * 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_lookupEventTag_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].tagLen;
- /*
- * b/31456426 to check if gTest can detect copy-on-write issue
- * add the following line to break us:
- * map->tagArray[mid].tagStr[map->tagArray[mid].tagLen] = '\0';
- * or explicitly use deprecated android_lookupEventTag().
- */
- return map->tagArray[mid].tagStr;
+ ~EventTagMap() {
+ Idx2TagFmt.clear();
+ if (mapAddr) {
+ munmap(mapAddr, mapLen);
+ mapAddr = 0;
}
}
- errno = ENOENT;
- if (len) *len = 0;
- return NULL;
-}
+ bool emplaceUnique(uint32_t tag, const TagFmt& tagfmt, bool verbose = false);
+ const TagFmt* find(uint32_t tag) const;
+};
-/*
- * 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;
+bool EventTagMap::emplaceUnique(uint32_t tag, const TagFmt& tagfmt, bool verbose) {
+ std::unordered_map<uint32_t, TagFmt>::const_iterator it;
+ it = Idx2TagFmt.find(tag);
+ if (it != Idx2TagFmt.end()) {
+ if (verbose) {
+ fprintf(stderr,
+ OUT_TAG ": duplicate tag entries %" PRIu32
+ ":%.*s:%.*s and %" PRIu32 ":%.*s:%.*s)\n",
+ it->first,
+ (int)it->second.first.length(), it->second.first.data(),
+ (int)it->second.second.length(), it->second.second.data(),
+ tag,
+ (int)tagfmt.first.length(), tagfmt.first.data(),
+ (int)tagfmt.second.length(), tagfmt.second.data());
}
+ return false;
}
- errno = ENOENT;
- if (len) *len = 0;
- return NULL;
+ Idx2TagFmt.emplace(std::make_pair(tag, tagfmt));
+ return true;
}
-LIBLOG_ABI_PUBLIC const char* android_lookupEventTag(const EventTagMap* map,
- unsigned int tag)
-{
- size_t len;
- const char* tagStr = android_lookupEventTag_len(map, &len, tag);
+const TagFmt* EventTagMap::find(uint32_t tag) const {
+ std::unordered_map<uint32_t, TagFmt>::const_iterator it;
+ it = Idx2TagFmt.find(tag);
+ if (it == Idx2TagFmt.end()) return NULL;
+ return &(it->second);
+}
+
+// Scan one tag line.
+//
+// "*pData" should be pointing to the first digit in the tag number. On
+// successful return, it will be pointing to the last character in the
+// tag line (i.e. the character before the start of the next line).
+//
+// Returns 0 on success, nonzero on failure.
+static int scanTagLine(EventTagMap* map, char** pData, int lineNum) {
char* cp;
-
- if (!tagStr) return tagStr;
- cp = (char*)tagStr;
- cp += len;
- if (*cp) *cp = '\0'; /* Trigger copy on write :-( */
- return tagStr;
-}
-
-/*
- * Crunch through the file, parsing the contents and creating a tag index.
- */
-static int processFile(EventTagMap* map)
-{
- /* get a tag count */
- map->numTags = countMapLines(map);
- if (map->numTags < 0) {
- errno = ENOENT;
- return -1;
- }
-
- /* allocate storage for the tag index array */
- map->tagArray = (EventTag*)calloc(1, sizeof(EventTag) * map->numTags);
- if (map->tagArray == NULL) return -1;
-
- /* parse the file, null-terminating tag strings */
- if (parseMapLines(map) != 0) return -1;
-
- /* sort the tags and check for duplicates */
- if (sortTags(map) != 0) return -1;
-
- return 0;
-}
-
-/*
- * Run through all lines in the file, determining whether they're blank,
- * comments, or possibly have a tag entry.
- *
- * This is a very "loose" scan. We don't try to detect syntax errors here.
- * The later pass is more careful, but the number of tags found there must
- * match the number of tags found here.
- *
- * Returns the number of potential tag entries found.
- */
-static int countMapLines(const EventTagMap* map)
-{
- const char* cp = (const char*) map->mapAddr;
- const char* endp = cp + map->mapLen;
- int numTags = 0;
- int unknown = 1;
-
- while (cp < endp) {
- if (*cp == '\n') {
- unknown = 1;
- } else if (unknown) {
- if (isdigit(*cp)) {
- /* looks like a tag to me */
- numTags++;
- unknown = 0;
- } else if (isspace(*cp)) {
- /* might be leading whitespace before tag num, keep going */
- } else {
- /* assume comment; second pass can complain in detail */
- unknown = 0;
- }
- } else {
- /* we've made up our mind; just scan to end of line */
- }
- cp++;
- }
-
- return numTags;
-}
-
-/*
- * Parse the tags out of the file.
- */
-static int parseMapLines(EventTagMap* map)
-{
- int tagNum, lineStart, lineNum;
- char* cp = (char*) map->mapAddr;
- char* endp = cp + map->mapLen;
-
- /* insist on EOL at EOF; simplifies parsing and null-termination */
- if (*(endp - 1) != '\n') {
- fprintf(stderr, "%s: map file missing EOL on last line\n", OUT_TAG);
- errno = EINVAL;
- return -1;
- }
-
- tagNum = 0;
- lineStart = 1;
- lineNum = 1;
- while (cp < endp) {
- if (*cp == '\n') {
- lineStart = 1;
- lineNum++;
- } else if (lineStart) {
- if (*cp == '#') {
- /* comment; just scan to end */
- lineStart = 0;
- } else if (isdigit(*cp)) {
- /* looks like a tag; scan it out */
- if (tagNum >= map->numTags) {
- fprintf(stderr,
- "%s: more tags than expected (%d)\n", OUT_TAG, tagNum);
- errno = EMFILE;
- return -1;
- }
- if (scanTagLine(&cp, &map->tagArray[tagNum], lineNum) != 0) {
- return -1;
- }
- tagNum++;
- lineNum++; // we eat the '\n'
- /* leave lineStart==1 */
- } else if (isspace(*cp)) {
- /* looks like leading whitespace; keep scanning */
- } else {
- fprintf(stderr,
- "%s: unexpected chars (0x%02x) in tag number on line %d\n",
- OUT_TAG, *cp, lineNum);
- errno = EINVAL;
- return -1;
- }
- } else {
- /* this is a blank or comment line */
- }
- cp++;
- }
-
- if (tagNum != map->numTags) {
- fprintf(stderr, "%s: parsed %d tags, expected %d\n",
- OUT_TAG, tagNum, map->numTags);
- errno = EINVAL;
- return -1;
- }
-
- return 0;
-}
-
-/*
- * Scan one tag line.
- *
- * "*pData" should be pointing to the first digit in the tag number. On
- * successful return, it will be pointing to the last character in the
- * tag line (i.e. the character before the start of the next line).
- *
- * Returns 0 on success, nonzero on failure.
- */
-static int scanTagLine(char** pData, EventTag* tag, int lineNum)
-{
- char* cp;
-
unsigned long val = strtoul(*pData, &cp, 10);
if (cp == *pData) {
- fprintf(stderr, "%s: malformed tag number on line %d\n", OUT_TAG, lineNum);
+ fprintf(stderr, OUT_TAG ": malformed tag number on line %d\n", lineNum);
errno = EINVAL;
return -1;
}
- tag->tagIndex = val;
- if (tag->tagIndex != val) {
- fprintf(stderr, "%s: tag number too large on line %d\n", OUT_TAG, lineNum);
+ uint32_t tagIndex = val;
+ if (tagIndex != val) {
+ fprintf(stderr, OUT_TAG ": tag number too large on line %d\n", lineNum);
errno = ERANGE;
return -1;
}
@@ -388,76 +132,192 @@
}
if (*cp == '\n') {
- fprintf(stderr, "%s: missing tag string on line %d\n", OUT_TAG, lineNum);
+ fprintf(stderr, OUT_TAG ": missing tag string on line %d\n", lineNum);
errno = EINVAL;
return -1;
}
- tag->tagStr = cp;
-
- /* Determine whether "c" is a valid tag char. */
- while (isalnum(*++cp) || (*cp == '_')) {
- }
- tag->tagLen = cp - tag->tagStr;
+ const char* tag = cp;
+ // Determine whether "c" is a valid tag char.
+ while (isalnum(*++cp) || (*cp == '_')) { }
+ size_t tagLen = cp - tag;
if (!isspace(*cp)) {
- fprintf(stderr, "%s: invalid tag chars on line %d\n", OUT_TAG, lineNum);
+ fprintf(stderr, OUT_TAG ": invalid tag chars on line %d\n", lineNum);
errno = EINVAL;
return -1;
}
while (isspace(*cp) && (*cp != '\n')) ++cp;
+ const char* fmt = NULL;
+ size_t fmtLen = 0;
if (*cp != '#') {
- tag->fmtStr = cp;
+ fmt = cp;
while ((*cp != '\n') && (*cp != '#')) ++cp;
- while ((cp > tag->fmtStr) && isspace(*(cp - 1))) --cp;
- tag->fmtLen = cp - tag->fmtStr;
+ while ((cp > fmt) && isspace(*(cp - 1))) --cp;
+ fmtLen = cp - fmt;
}
while (*cp != '\n') ++cp;
+#ifdef DEBUG
+ fprintf(stderr, "%d: %p: %.*s\n", lineNum, tag, (int)(cp - *pData), *pData);
+#endif
*pData = cp;
- return 0;
+ if (map->emplaceUnique(tagIndex, TagFmt(std::make_pair(
+ MapString(tag, tagLen), MapString(fmt, fmtLen))), true)) {
+ return 0;
+ }
+ errno = EMLINK;
+ return -1;
}
-/*
- * Compare two EventTags.
- */
-static int compareEventTags(const void* v1, const void* v2)
-{
- const EventTag* tag1 = (const EventTag*) v1;
- const EventTag* tag2 = (const EventTag*) v2;
+// Parse the tags out of the file.
+static int parseMapLines(EventTagMap* map) {
+ char* cp = static_cast<char*>(map->mapAddr);
+ size_t len = map->mapLen;
+ char* endp = cp + len;
- return tag1->tagIndex - tag2->tagIndex;
-}
+ // insist on EOL at EOF; simplifies parsing and null-termination
+ if (!len || (*(endp - 1) != '\n')) {
+#ifdef DEBUG
+ fprintf(stderr, OUT_TAG ": map file missing EOL on last line\n");
+#endif
+ errno = EINVAL;
+ return -1;
+ }
-/*
- * Sort the EventTag array so we can do fast lookups by tag index. After
- * the sort we do a quick check for duplicate tag indices.
- *
- * Returns 0 on success.
- */
-static int sortTags(EventTagMap* map)
-{
- int i;
-
- qsort(map->tagArray, map->numTags, sizeof(EventTag), compareEventTags);
-
- 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:%.*s and %" PRIu32 ":%.*s:%.*s)\n",
- OUT_TAG,
- 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;
+ bool lineStart = true;
+ int lineNum = 1;
+ while (cp < endp) {
+ if (*cp == '\n') {
+ lineStart = true;
+ lineNum++;
+ } else if (lineStart) {
+ if (*cp == '#') {
+ // comment; just scan to end
+ lineStart = false;
+ } else if (isdigit(*cp)) {
+ // looks like a tag; scan it out
+ if (scanTagLine(map, &cp, lineNum) != 0) {
+ return -1;
+ }
+ lineNum++; // we eat the '\n'
+ // leave lineStart==true
+ } else if (isspace(*cp)) {
+ // looks like leading whitespace; keep scanning
+ } else {
+ fprintf(stderr,
+ OUT_TAG ": unexpected chars (0x%02x) in tag number on line %d\n",
+ *cp, lineNum);
+ errno = EINVAL;
+ return -1;
+ }
+ } else {
+ // this is a blank or comment line
}
+ cp++;
}
return 0;
}
+
+// Open the map file and allocate a structure to manage it.
+//
+// We create a private mapping because we want to terminate the log tag
+// strings with '\0'.
+LIBLOG_ABI_PUBLIC EventTagMap* android_openEventTagMap(const char* fileName) {
+ int save_errno;
+
+ const char* tagfile = fileName ? fileName : EVENT_TAG_MAP_FILE;
+ int fd = open(tagfile, O_RDONLY | O_CLOEXEC);
+ if (fd < 0) {
+ save_errno = errno;
+ fprintf(stderr, OUT_TAG ": unable to open map '%s': %s\n",
+ tagfile, strerror(save_errno));
+ errno = save_errno;
+ return NULL;
+ }
+ off_t end = lseek(fd, 0L, SEEK_END);
+ save_errno = errno;
+ (void)lseek(fd, 0L, SEEK_SET);
+ if (end < 0) {
+ fprintf(stderr, OUT_TAG ": unable to seek map '%s' %s\n",
+ tagfile, strerror(save_errno));
+ close(fd);
+ errno = save_errno;
+ return NULL;
+ }
+
+ EventTagMap* newTagMap = new EventTagMap;
+ if (newTagMap == NULL) {
+ save_errno = errno;
+ close(fd);
+ errno = save_errno;
+ return NULL;
+ }
+
+ newTagMap->mapAddr = mmap(NULL, end, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE, fd, 0);
+ save_errno = errno;
+ close(fd);
+ fd = -1;
+ if ((newTagMap->mapAddr == MAP_FAILED) || (newTagMap->mapAddr == NULL)) {
+ fprintf(stderr, OUT_TAG ": mmap(%s) failed: %s\n",
+ tagfile, strerror(save_errno));
+ delete newTagMap;
+ errno = save_errno;
+ return NULL;
+ }
+
+ newTagMap->mapLen = end;
+
+ if (parseMapLines(newTagMap) != 0) {
+ delete newTagMap;
+ return NULL;
+ }
+
+ return newTagMap;
+}
+
+// Close the map.
+LIBLOG_ABI_PUBLIC void android_closeEventTagMap(EventTagMap* map) {
+ if (map) delete map;
+}
+
+// Look up an entry in the map.
+LIBLOG_ABI_PUBLIC const char* android_lookupEventTag_len(const EventTagMap* map,
+ size_t *len,
+ unsigned int tag) {
+ if (len) *len = 0;
+ const TagFmt* str = map->find(tag);
+ if (!str) return NULL;
+ if (len) *len = str->first.length();
+ return str->first.data();
+}
+
+// Look up an entry in the map.
+LIBLOG_ABI_PUBLIC const char* android_lookupEventFormat_len(
+ const EventTagMap* map, size_t *len, unsigned int tag) {
+ if (len) *len = 0;
+ const TagFmt* str = map->find(tag);
+ if (!str) return NULL;
+ if (len) *len = str->second.length();
+ return str->second.data();
+}
+
+// This function is deprecated and replaced with android_lookupEventTag_len
+// since it will cause the map to change from Shared and backed by a file,
+// to Private Dirty and backed up by swap, albeit highly compressible. By
+// deprecating this function everywhere, we save 100s of MB of memory space.
+LIBLOG_ABI_PUBLIC const char* android_lookupEventTag(const EventTagMap* map,
+ unsigned int tag) {
+ size_t len;
+ const char* tagStr = android_lookupEventTag_len(map, &len, tag);
+
+ if (!tagStr) return tagStr;
+ char* cp = const_cast<char*>(tagStr);
+ cp += len;
+ if (*cp) *cp = '\0'; // Trigger copy on write :-( and why deprecated.
+ return tagStr;
+}
diff --git a/liblog/legacy-ndk-includes/log.h b/liblog/legacy-ndk-includes/log.h
index 0ea4c29..d40d6fa 100644
--- a/liblog/legacy-ndk-includes/log.h
+++ b/liblog/legacy-ndk-includes/log.h
@@ -98,7 +98,7 @@
*/
int __android_log_print(int prio, const char *tag, const char *fmt, ...)
#if defined(__GNUC__)
- __attribute__ ((format(printf, 3, 4)))
+ __attribute__((__format__(printf, 3, 4)))
#endif
;
@@ -116,8 +116,8 @@
void __android_log_assert(const char *cond, const char *tag,
const char *fmt, ...)
#if defined(__GNUC__)
- __attribute__ ((noreturn))
- __attribute__ ((format(printf, 3, 4)))
+ __attribute__((__noreturn__))
+ __attribute__((__format__(printf, 3, 4)))
#endif
;
diff --git a/liblog/log_ratelimit.cpp b/liblog/log_ratelimit.cpp
new file mode 100644
index 0000000..dfd4b8f
--- /dev/null
+++ b/liblog/log_ratelimit.cpp
@@ -0,0 +1,86 @@
+/*
+** Copyright 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 <errno.h>
+#include <pthread.h>
+#include <time.h>
+
+#include <log/log.h>
+
+#include "log_portability.h"
+
+// Global default if 'last' argument in __android_log_ratelimit is NULL
+static time_t g_last_clock;
+// Global above can not deal well with callers playing games with the
+// seconds argument, so we will also hold on to the maximum value
+// ever provided and use that to gain consistency. If the caller
+// provides their own 'last' argument, then they can play such games
+// of varying the 'seconds' argument to their pleasure.
+static time_t g_last_seconds;
+static const time_t last_seconds_default = 10;
+static const time_t last_seconds_max = 24 * 60 * 60; // maximum of a day
+static const time_t last_seconds_min = 2; // granularity
+// Lock to protect last_clock and last_seconds, but also 'last'
+// argument (not NULL) as supplied to __android_log_ratelimit.
+static pthread_mutex_t lock_ratelimit = PTHREAD_MUTEX_INITIALIZER;
+
+// if last is NULL, caller _must_ provide a consistent value for
+// seconds, otherwise we will take the maximum ever issued and hold
+// on to that. Preserves value of non-zero errno. Return -1 if we
+// can not acquire a lock, 0 if we are not to log a message, and 1
+// if we are ok to log a message. Caller should check > 0 for true.
+LIBLOG_ABI_PUBLIC int __android_log_ratelimit(time_t seconds, time_t* last) {
+ int save_errno = errno;
+
+ // Two reasons for trylock failure:
+ // 1. In a signal handler. Must prevent deadlock
+ // 2. Too many threads calling __android_log_ratelimit.
+ // Bonus to not print if they race here because that
+ // dovetails the goal of ratelimiting. One may print
+ // and the others will wait their turn ...
+ if (pthread_mutex_trylock(&lock_ratelimit)) {
+ if (save_errno) errno = save_errno;
+ return -1;
+ }
+
+ if (seconds == 0) {
+ seconds = last_seconds_default;
+ } else if (seconds < last_seconds_min) {
+ seconds = last_seconds_min;
+ } else if (seconds > last_seconds_max) {
+ seconds = last_seconds_max;
+ }
+
+ if (!last) {
+ if (g_last_seconds > seconds) {
+ seconds = g_last_seconds;
+ } else if (g_last_seconds < seconds) {
+ g_last_seconds = seconds;
+ }
+ last = &g_last_clock;
+ }
+
+ time_t now = time(NULL);
+ if ((now == (time_t)-1) || ((*last + seconds) > now)) {
+ pthread_mutex_unlock(&lock_ratelimit);
+ if (save_errno) errno = save_errno;
+ return 0;
+ }
+ *last = now;
+ pthread_mutex_unlock(&lock_ratelimit);
+ if (save_errno) errno = save_errno;
+ return 1;
+}
diff --git a/liblog/logd_writer.c b/liblog/logd_writer.c
index 8fdfb92..2bab92e 100644
--- a/liblog/logd_writer.c
+++ b/liblog/logd_writer.c
@@ -50,7 +50,7 @@
LIBLOG_HIDDEN struct android_log_transport_write logdLoggerWrite = {
.node = { &logdLoggerWrite.node, &logdLoggerWrite.node },
- .context.sock = -1,
+ .context.sock = -EBADF,
.name = "logd",
.available = logdAvailable,
.open = logdOpen,
@@ -65,8 +65,10 @@
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) {
+ int sock = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM |
+ SOCK_CLOEXEC |
+ SOCK_NONBLOCK, 0));
+ if (sock < 0) {
ret = -errno;
} else {
struct sockaddr_un un;
@@ -74,13 +76,22 @@
un.sun_family = AF_UNIX;
strcpy(un.sun_path, "/dev/socket/logdw");
- if (TEMP_FAILURE_RETRY(connect(i, (struct sockaddr *)&un,
+ if (TEMP_FAILURE_RETRY(connect(sock, (struct sockaddr *)&un,
sizeof(struct sockaddr_un))) < 0) {
ret = -errno;
- close(i);
+ switch (ret) {
+ case -ENOTCONN:
+ case -ECONNREFUSED:
+ case -ENOENT:
+ i = atomic_exchange(&logdLoggerWrite.context.sock, ret);
+ /* FALLTHRU */
+ default:
+ break;
+ }
+ close(sock);
} else {
- ret = atomic_exchange(&logdLoggerWrite.context.sock, i);
- if ((ret >= 0) && (ret != i)) {
+ ret = atomic_exchange(&logdLoggerWrite.context.sock, sock);
+ if ((ret >= 0) && (ret != sock)) {
close(ret);
}
ret = 0;
@@ -91,14 +102,19 @@
return ret;
}
-static void logdClose()
+static void __logdClose(int negative_errno)
{
- int sock = atomic_exchange(&logdLoggerWrite.context.sock, -1);
+ int sock = atomic_exchange(&logdLoggerWrite.context.sock, negative_errno);
if (sock >= 0) {
close(sock);
}
}
+static void logdClose()
+{
+ __logdClose(-EBADF);
+}
+
static int logdAvailable(log_id_t logId)
{
if (logId > LOG_ID_SECURITY) {
@@ -117,6 +133,7 @@
struct iovec *vec, size_t nr)
{
ssize_t ret;
+ int sock;
static const unsigned headerLength = 1;
struct iovec newVec[nr + headerLength];
android_log_header_t header;
@@ -124,7 +141,13 @@
static atomic_int_fast32_t dropped;
static atomic_int_fast32_t droppedSecurity;
- if (atomic_load(&logdLoggerWrite.context.sock) < 0) {
+ sock = atomic_load(&logdLoggerWrite.context.sock);
+ if (sock < 0) switch (sock) {
+ case -ENOTCONN:
+ case -ECONNREFUSED:
+ case -ENOENT:
+ break;
+ default:
return -EBADF;
}
@@ -163,7 +186,7 @@
newVec[0].iov_base = (unsigned char *)&header;
newVec[0].iov_len = sizeof(header);
- if (atomic_load(&logdLoggerWrite.context.sock) > 0) {
+ if (sock >= 0) {
int32_t snapshot = atomic_exchange_explicit(&droppedSecurity, 0,
memory_order_relaxed);
if (snapshot) {
@@ -177,8 +200,7 @@
newVec[headerLength].iov_base = &buffer;
newVec[headerLength].iov_len = sizeof(buffer);
- ret = TEMP_FAILURE_RETRY(writev(
- atomic_load(&logdLoggerWrite.context.sock), newVec, 2));
+ ret = TEMP_FAILURE_RETRY(writev(sock, newVec, 2));
if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
atomic_fetch_add_explicit(&droppedSecurity, snapshot,
memory_order_relaxed);
@@ -186,7 +208,8 @@
}
snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
if (snapshot && __android_log_is_loggable_len(ANDROID_LOG_INFO,
- "liblog", strlen("liblog"),
+ "liblog",
+ strlen("liblog"),
ANDROID_LOG_VERBOSE)) {
android_log_event_int_t buffer;
@@ -198,8 +221,7 @@
newVec[headerLength].iov_base = &buffer;
newVec[headerLength].iov_len = sizeof(buffer);
- ret = TEMP_FAILURE_RETRY(writev(
- atomic_load(&logdLoggerWrite.context.sock), newVec, 2));
+ ret = TEMP_FAILURE_RETRY(writev(sock, newVec, 2));
if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
atomic_fetch_add_explicit(&dropped, snapshot,
memory_order_relaxed);
@@ -225,30 +247,43 @@
/*
* The write below could be lost, but will never block.
*
- * ENOTCONN occurs if logd dies.
+ * ENOTCONN occurs if logd has died.
+ * ENOENT occurs if logd is not running and socket is missing.
+ * ECONNREFUSED occurs if we can not reconnect to logd.
* EAGAIN occurs if logd is overloaded.
*/
- ret = TEMP_FAILURE_RETRY(writev(
- atomic_load(&logdLoggerWrite.context.sock), newVec, i));
- if (ret < 0) {
- ret = -errno;
- if (ret == -ENOTCONN) {
- __android_log_lock();
- logdClose();
- ret = logdOpen();
- __android_log_unlock();
-
- if (ret < 0) {
- return ret;
- }
-
- ret = TEMP_FAILURE_RETRY(writev(
- atomic_load(&logdLoggerWrite.context.sock), newVec, i));
- if (ret < 0) {
- ret = -errno;
- }
+ if (sock < 0) {
+ ret = sock;
+ } else {
+ ret = TEMP_FAILURE_RETRY(writev(sock, newVec, i));
+ if (ret < 0) {
+ ret = -errno;
}
}
+ switch(ret) {
+ case -ENOTCONN:
+ case -ECONNREFUSED:
+ case -ENOENT:
+ if (__android_log_trylock()) {
+ return ret; /* in a signal handler? try again when less stressed */
+ }
+ __logdClose(ret);
+ ret = logdOpen();
+ __android_log_unlock();
+
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = TEMP_FAILURE_RETRY(writev(
+ atomic_load(&logdLoggerWrite.context.sock), newVec, i));
+ if (ret < 0) {
+ ret = -errno;
+ }
+ /* FALLTHRU */
+ default:
+ break;
+ }
if (ret > (ssize_t)sizeof(header)) {
ret -= sizeof(header);
diff --git a/liblog/pmsg_reader.c b/liblog/pmsg_reader.c
index a0a69c1..e1b81aa 100644
--- a/liblog/pmsg_reader.c
+++ b/liblog/pmsg_reader.c
@@ -70,7 +70,7 @@
/* Determine the credentials of the caller */
static bool uid_has_log_permission(uid_t uid)
{
- return (uid == AID_SYSTEM) || (uid == AID_LOG) || (uid == AID_ROOT);
+ return (uid == AID_SYSTEM) || (uid == AID_LOG) || (uid == AID_ROOT) || (uid == AID_LOGD);
}
static uid_t get_best_effective_uid()
diff --git a/liblog/log_is_loggable.c b/liblog/properties.c
similarity index 100%
rename from liblog/log_is_loggable.c
rename to liblog/properties.c
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index d80f8b2..02feb97 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -214,6 +214,8 @@
}
return false;
}
+
+bool tested__android_log_close;
#endif
TEST(liblog, __android_log_btwrite__android_logger_list_read) {
@@ -228,22 +230,33 @@
// 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);
+ bool pmsgActiveAfter__android_log_btwrite;
+ bool logdwActiveAfter__android_log_btwrite;
+ if (getuid() == AID_ROOT) {
+ tested__android_log_close = true;
+ pmsgActiveAfter__android_log_btwrite = isPmsgActive();
+ logdwActiveAfter__android_log_btwrite = isLogdwActive();
+ EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
+ EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
+ } else if (!tested__android_log_close) {
+ fprintf(stderr, "WARNING: can not test __android_log_close()\n");
+ }
__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);
+ if (getuid() == AID_ROOT) {
+ 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);
+ if (getuid() == AID_ROOT) {
+ 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;
@@ -257,18 +270,19 @@
ASSERT_EQ(log_msg.entry.pid, pid);
- if ((log_msg.entry.len != (4 + 1 + 8))
+ if ((log_msg.entry.len != sizeof(android_log_event_long_t))
|| (log_msg.id() != LOG_ID_EVENTS)) {
continue;
}
- char *eventData = log_msg.msg();
+ android_log_event_long_t* eventData;
+ eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
- if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
+ if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
continue;
}
- log_time tx(eventData + 4 + 1);
+ log_time tx(reinterpret_cast<char*>(&eventData->payload.data));
if (ts == tx) {
++count;
} else if (ts1 == tx) {
@@ -339,18 +353,20 @@
if ((log_msg.entry.sec < (ts.tv_sec - 1))
|| ((ts.tv_sec + 1) < log_msg.entry.sec)
- || ((size_t)log_msg.entry.len != (4 + 1 + 4 + length))
+ || ((size_t)log_msg.entry.len != (sizeof(android_log_event_string_t) +
+ length))
|| (log_msg.id() != LOG_ID_EVENTS)) {
continue;
}
- char *eventData = log_msg.msg();
+ android_log_event_string_t* eventData;
+ eventData = reinterpret_cast<android_log_event_string_t*>(log_msg.msg());
- if (!eventData || (eventData[4] != EVENT_TYPE_STRING)) {
+ if (!eventData || (eventData->type != EVENT_TYPE_STRING)) {
continue;
}
- size_t len = get4LE(eventData + 4 + 1);
+ size_t len = get4LE(reinterpret_cast<char*>(&eventData->length));
if (len == total) {
++count;
@@ -488,187 +504,6 @@
buf_write_test("\n Hello World \n");
}
-TEST(liblog, __security) {
-#ifdef __ANDROID__
- static const char persist_key[] = "persist.logd.security";
- static const char readonly_key[] = "ro.device_owner";
- static const char nothing_val[] = "_NOTHING_TO_SEE_HERE_";
- char persist[PROP_VALUE_MAX];
- char readonly[PROP_VALUE_MAX];
-
- property_get(persist_key, persist, "");
- property_get(readonly_key, readonly, nothing_val);
-
- if (!strcmp(readonly, nothing_val)) {
- EXPECT_FALSE(__android_log_security());
- fprintf(stderr, "Warning, setting ro.device_owner to a domain\n");
- property_set(readonly_key, "com.google.android.SecOps.DeviceOwner");
- } else if (!strcasecmp(readonly, "false") || !readonly[0]) {
- EXPECT_FALSE(__android_log_security());
- return;
- }
-
- if (!strcasecmp(persist, "true")) {
- EXPECT_TRUE(__android_log_security());
- } else {
- EXPECT_FALSE(__android_log_security());
- }
- property_set(persist_key, "TRUE");
- EXPECT_TRUE(__android_log_security());
- property_set(persist_key, "FALSE");
- EXPECT_FALSE(__android_log_security());
- property_set(persist_key, "true");
- EXPECT_TRUE(__android_log_security());
- property_set(persist_key, "false");
- EXPECT_FALSE(__android_log_security());
- property_set(persist_key, "");
- EXPECT_FALSE(__android_log_security());
- property_set(persist_key, persist);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, __security_buffer) {
-#ifdef __ANDROID__
- struct logger_list *logger_list;
- android_event_long_t buffer;
-
- static const char persist_key[] = "persist.logd.security";
- char persist[PROP_VALUE_MAX];
- bool set_persist = false;
- bool allow_security = false;
-
- if (__android_log_security()) {
- allow_security = true;
- } else {
- property_get(persist_key, persist, "");
- if (strcasecmp(persist, "true")) {
- property_set(persist_key, "TRUE");
- if (__android_log_security()) {
- allow_security = true;
- set_persist = true;
- } else {
- property_set(persist_key, persist);
- }
- }
- }
-
- if (!allow_security) {
- fprintf(stderr, "WARNING: "
- "security buffer disabled, bypassing end-to-end test\n");
-
- log_time ts(CLOCK_MONOTONIC);
-
- buffer.type = EVENT_TYPE_LONG;
- buffer.data = *(static_cast<uint64_t *>((void *)&ts));
-
- // expect failure!
- ASSERT_GE(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
-
- return;
- }
-
- /* Matches clientHasLogCredentials() in logd */
- uid_t uid = getuid();
- gid_t gid = getgid();
- bool clientHasLogCredentials = true;
- if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)
- && (gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) {
- uid_t euid = geteuid();
- if ((euid != AID_SYSTEM) && (euid != AID_ROOT) && (euid != AID_LOG)) {
- gid_t egid = getegid();
- if ((egid != AID_SYSTEM) && (egid != AID_ROOT) && (egid != AID_LOG)) {
- int num_groups = getgroups(0, NULL);
- if (num_groups > 0) {
- gid_t groups[num_groups];
- num_groups = getgroups(num_groups, groups);
- while (num_groups > 0) {
- if (groups[num_groups - 1] == AID_LOG) {
- break;
- }
- --num_groups;
- }
- }
- if (num_groups <= 0) {
- clientHasLogCredentials = false;
- }
- }
- }
- }
- if (!clientHasLogCredentials) {
- fprintf(stderr, "WARNING: "
- "not in system context, bypassing end-to-end test\n");
-
- log_time ts(CLOCK_MONOTONIC);
-
- buffer.type = EVENT_TYPE_LONG;
- buffer.data = *(static_cast<uint64_t *>((void *)&ts));
-
- // expect failure!
- ASSERT_GE(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
-
- return;
- }
-
- pid_t pid = getpid();
-
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_SECURITY, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
- 1000, pid)));
-
- log_time ts(CLOCK_MONOTONIC);
-
- buffer.type = EVENT_TYPE_LONG;
- buffer.data = *(static_cast<uint64_t *>((void *)&ts));
-
- ASSERT_LT(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
- usleep(1000000);
-
- int count = 0;
-
- for (;;) {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) {
- break;
- }
-
- ASSERT_EQ(log_msg.entry.pid, pid);
-
- if ((log_msg.entry.len != (4 + 1 + 8))
- || (log_msg.id() != LOG_ID_SECURITY)) {
- continue;
- }
-
- char *eventData = log_msg.msg();
-
- if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
- continue;
- }
-
- log_time tx(eventData + 4 + 1);
- if (ts == tx) {
- ++count;
- }
- }
-
- if (set_persist) {
- property_set(persist_key, persist);
- }
-
- android_logger_list_close(logger_list);
-
- bool clientHasSecurityCredentials = (uid == AID_SYSTEM) || (gid == AID_SYSTEM);
- if (!clientHasSecurityCredentials) {
- fprintf(stderr, "WARNING: "
- "not system, content submitted but can not check end-to-end\n");
- }
- EXPECT_EQ(clientHasSecurityCredentials ? 1 : 0, count);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
#ifdef __ANDROID__
static unsigned signaled;
static log_time signal_time;
@@ -771,25 +606,27 @@
ASSERT_EQ(log_msg.entry.pid, pid);
- if ((log_msg.entry.len != (4 + 1 + 8))
+ if ((log_msg.entry.len != sizeof(android_log_event_long_t))
|| (log_msg.id() != LOG_ID_EVENTS)) {
continue;
}
- char *eventData = log_msg.msg();
+ android_log_event_long_t* eventData;
+ eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
- if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
+ if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
continue;
}
- unsigned long long l = eventData[4 + 1 + 0] & 0xFF;
- l |= (unsigned long long) (eventData[4 + 1 + 1] & 0xFF) << 8;
- l |= (unsigned long long) (eventData[4 + 1 + 2] & 0xFF) << 16;
- l |= (unsigned long long) (eventData[4 + 1 + 3] & 0xFF) << 24;
- l |= (unsigned long long) (eventData[4 + 1 + 4] & 0xFF) << 32;
- l |= (unsigned long long) (eventData[4 + 1 + 5] & 0xFF) << 40;
- l |= (unsigned long long) (eventData[4 + 1 + 6] & 0xFF) << 48;
- l |= (unsigned long long) (eventData[4 + 1 + 7] & 0xFF) << 56;
+ char* cp = reinterpret_cast<char*>(&eventData->payload.data);
+ unsigned long long l = cp[0] & 0xFF;
+ l |= (unsigned long long) (cp[1] & 0xFF) << 8;
+ l |= (unsigned long long) (cp[2] & 0xFF) << 16;
+ l |= (unsigned long long) (cp[3] & 0xFF) << 24;
+ l |= (unsigned long long) (cp[4] & 0xFF) << 32;
+ l |= (unsigned long long) (cp[5] & 0xFF) << 40;
+ l |= (unsigned long long) (cp[6] & 0xFF) << 48;
+ l |= (unsigned long long) (cp[7] & 0xFF) << 56;
if (l == v) {
++signals;
@@ -928,25 +765,27 @@
ASSERT_EQ(log_msg.entry.pid, pid);
- if ((log_msg.entry.len != (4 + 1 + 8))
+ if ((log_msg.entry.len != sizeof(android_log_event_long_t))
|| (log_msg.id() != LOG_ID_EVENTS)) {
continue;
}
- char *eventData = log_msg.msg();
+ android_log_event_long_t* eventData;
+ eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
- if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
+ if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
continue;
}
- unsigned long long l = eventData[4 + 1 + 0] & 0xFF;
- l |= (unsigned long long) (eventData[4 + 1 + 1] & 0xFF) << 8;
- l |= (unsigned long long) (eventData[4 + 1 + 2] & 0xFF) << 16;
- l |= (unsigned long long) (eventData[4 + 1 + 3] & 0xFF) << 24;
- l |= (unsigned long long) (eventData[4 + 1 + 4] & 0xFF) << 32;
- l |= (unsigned long long) (eventData[4 + 1 + 5] & 0xFF) << 40;
- l |= (unsigned long long) (eventData[4 + 1 + 6] & 0xFF) << 48;
- l |= (unsigned long long) (eventData[4 + 1 + 7] & 0xFF) << 56;
+ char* cp = reinterpret_cast<char*>(&eventData->payload.data);
+ unsigned long long l = cp[0] & 0xFF;
+ l |= (unsigned long long) (cp[1] & 0xFF) << 8;
+ l |= (unsigned long long) (cp[2] & 0xFF) << 16;
+ l |= (unsigned long long) (cp[3] & 0xFF) << 24;
+ l |= (unsigned long long) (cp[4] & 0xFF) << 32;
+ l |= (unsigned long long) (cp[5] & 0xFF) << 40;
+ l |= (unsigned long long) (cp[6] & 0xFF) << 48;
+ l |= (unsigned long long) (cp[7] & 0xFF) << 56;
if (l == v) {
++signals;
@@ -1352,6 +1191,9 @@
TEST(liblog, android_logger_get_) {
#ifdef __ANDROID__
+ // This test assumes the log buffers are filled with noise from
+ // normal operations. It will fail if done immediately after a
+ // logcat -c.
struct logger_list * logger_list = android_logger_list_alloc(ANDROID_LOG_WRONLY, 0, 0);
for(int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
@@ -1762,23 +1604,248 @@
#endif
}
-TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__typical) {
#ifdef __ANDROID__
- const int TAG = 123456781;
- const char SUBTAG[] = "test-subtag";
- const int UID = -1;
- const int DATA_LEN = 200;
+// helper to liblog.enoent to count end-to-end matching logging messages.
+static int count_matching_ts(log_time ts) {
+ usleep(1000000);
+
+ pid_t pid = getpid();
+
+ struct logger_list* logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid);
+
+ int count = 0;
+ if (logger_list == NULL) return count;
+
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) break;
+
+ if (log_msg.entry.len != sizeof(android_log_event_long_t)) continue;
+ if (log_msg.id() != LOG_ID_EVENTS) continue;
+
+ android_log_event_long_t* eventData;
+ eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
+ if (!eventData) continue;
+ if (eventData->payload.type != EVENT_TYPE_LONG) continue;
+
+ log_time tx(reinterpret_cast<char*>(&eventData->payload.data));
+ if (ts != tx) continue;
+
+ // found event message with matching timestamp signature in payload
+ ++count;
+ }
+ android_logger_list_close(logger_list);
+
+ return count;
+}
+
+// meant to be handed to ASSERT_TRUE / EXPECT_TRUE only to expand the message
+static testing::AssertionResult IsOk(bool ok, std::string &message) {
+ return ok ?
+ testing::AssertionSuccess() :
+ (testing::AssertionFailure() << message);
+}
+#endif
+
+TEST(liblog, enoent) {
+#ifdef __ANDROID__
+ log_time ts(CLOCK_MONOTONIC);
+ EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
+ EXPECT_EQ(1, count_matching_ts(ts));
+
+ // This call will fail if we are setuid(AID_SYSTEM), beware of any
+ // test prior to this one playing with setuid and causing interference.
+ // We need to run before these tests so that they do not interfere with
+ // this test.
+ //
+ // Stopping the logger can affect some other test's expectations as they
+ // count on the log buffers filled with existing content, and this
+ // effectively does a logcat -c emptying it. So we want this test to be
+ // as near as possible to the bottom of the file. For example
+ // liblog.android_logger_get_ is one of those tests that has no recourse
+ // and that would be adversely affected by emptying the log if it was run
+ // right after this test.
+ system("stop logd");
+ usleep(1000000);
+
+ // A clean stop like we are testing returns -ENOENT, but in the _real_
+ // world we could get -ENOTCONN or -ECONNREFUSED depending on timing.
+ // Alas we can not test these other return values; accept that they
+ // are treated equally within the open-retry logic in liblog.
+ ts = log_time(CLOCK_MONOTONIC);
+ int ret = __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts));
+ std::string content = android::base::StringPrintf(
+ "__android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)) = %d %s\n",
+ ret, strerror(-ret));
+ EXPECT_TRUE(IsOk((ret == -ENOENT) ||
+ (ret == -ENOTCONN) ||
+ (ret == -ECONNREFUSED), content));
+ ret = __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts));
+ content = android::base::StringPrintf(
+ "__android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)) = %d %s\n",
+ ret, strerror(-ret));
+ EXPECT_TRUE(IsOk((ret == -ENOENT) ||
+ (ret == -ENOTCONN) ||
+ (ret == -ECONNREFUSED), content));
+ EXPECT_EQ(0, count_matching_ts(ts));
+
+ system("start logd");
+ usleep(1000000);
+
+ EXPECT_EQ(0, count_matching_ts(ts));
+
+ ts = log_time(CLOCK_MONOTONIC);
+ EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
+ EXPECT_EQ(1, count_matching_ts(ts));
+
+#else
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}
+
+// Below this point we run risks of setuid(AID_SYSTEM) which may affect others.
+
+TEST(liblog, __security) {
+#ifdef __ANDROID__
+ static const char persist_key[] = "persist.logd.security";
+ static const char readonly_key[] = "ro.device_owner";
+ // A silly default value that can never be in readonly_key so
+ // that it can be determined the property is not set.
+ static const char nothing_val[] = "_NOTHING_TO_SEE_HERE_";
+ char persist[PROP_VALUE_MAX];
+ char readonly[PROP_VALUE_MAX];
+
+ property_get(persist_key, persist, "");
+ property_get(readonly_key, readonly, nothing_val);
+
+ if (!strcmp(readonly, nothing_val)) {
+ EXPECT_FALSE(__android_log_security());
+ fprintf(stderr, "Warning, setting ro.device_owner to a domain\n");
+ property_set(readonly_key, "com.google.android.SecOps.DeviceOwner");
+ } else if (!strcasecmp(readonly, "false") || !readonly[0]) {
+ EXPECT_FALSE(__android_log_security());
+ return;
+ }
+
+ if (!strcasecmp(persist, "true")) {
+ EXPECT_TRUE(__android_log_security());
+ } else {
+ EXPECT_FALSE(__android_log_security());
+ }
+ property_set(persist_key, "TRUE");
+ EXPECT_TRUE(__android_log_security());
+ property_set(persist_key, "FALSE");
+ EXPECT_FALSE(__android_log_security());
+ property_set(persist_key, "true");
+ EXPECT_TRUE(__android_log_security());
+ property_set(persist_key, "false");
+ EXPECT_FALSE(__android_log_security());
+ property_set(persist_key, "");
+ EXPECT_FALSE(__android_log_security());
+ property_set(persist_key, persist);
+#else
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}
+
+TEST(liblog, __security_buffer) {
+#ifdef __ANDROID__
struct logger_list *logger_list;
+ android_event_long_t buffer;
+
+ static const char persist_key[] = "persist.logd.security";
+ char persist[PROP_VALUE_MAX];
+ bool set_persist = false;
+ bool allow_security = false;
+
+ if (__android_log_security()) {
+ allow_security = true;
+ } else {
+ property_get(persist_key, persist, "");
+ if (strcasecmp(persist, "true")) {
+ property_set(persist_key, "TRUE");
+ if (__android_log_security()) {
+ allow_security = true;
+ set_persist = true;
+ } else {
+ property_set(persist_key, persist);
+ }
+ }
+ }
+
+ if (!allow_security) {
+ fprintf(stderr, "WARNING: "
+ "security buffer disabled, bypassing end-to-end test\n");
+
+ log_time ts(CLOCK_MONOTONIC);
+
+ buffer.type = EVENT_TYPE_LONG;
+ buffer.data = *(static_cast<uint64_t *>((void *)&ts));
+
+ // expect failure!
+ ASSERT_GE(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
+
+ return;
+ }
+
+ /* Matches clientHasLogCredentials() in logd */
+ uid_t uid = getuid();
+ gid_t gid = getgid();
+ bool clientHasLogCredentials = true;
+ if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)
+ && (gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) {
+ uid_t euid = geteuid();
+ if ((euid != AID_SYSTEM) && (euid != AID_ROOT) && (euid != AID_LOG)) {
+ gid_t egid = getegid();
+ if ((egid != AID_SYSTEM) && (egid != AID_ROOT) && (egid != AID_LOG)) {
+ int num_groups = getgroups(0, NULL);
+ if (num_groups > 0) {
+ gid_t groups[num_groups];
+ num_groups = getgroups(num_groups, groups);
+ while (num_groups > 0) {
+ if (groups[num_groups - 1] == AID_LOG) {
+ break;
+ }
+ --num_groups;
+ }
+ }
+ if (num_groups <= 0) {
+ clientHasLogCredentials = false;
+ }
+ }
+ }
+ }
+ if (!clientHasLogCredentials) {
+ fprintf(stderr, "WARNING: "
+ "not in system context, bypassing end-to-end test\n");
+
+ log_time ts(CLOCK_MONOTONIC);
+
+ buffer.type = EVENT_TYPE_LONG;
+ buffer.data = *(static_cast<uint64_t *>((void *)&ts));
+
+ // expect failure!
+ ASSERT_GE(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
+
+ return;
+ }
+
+ setuid(AID_SYSTEM); // only one that can read security buffer
pid_t pid = getpid();
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+ LOG_ID_SECURITY, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
+ 1000, pid)));
- ASSERT_LT(0, android_errorWriteWithInfoLog(
- TAG, SUBTAG, UID, max_payload_buf, DATA_LEN));
+ log_time ts(CLOCK_MONOTONIC);
- sleep(2);
+ buffer.type = EVENT_TYPE_LONG;
+ buffer.data = *(static_cast<uint64_t *>((void *)&ts));
+
+ ASSERT_LT(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
+ usleep(1000000);
int count = 0;
@@ -1788,74 +1855,47 @@
break;
}
- char *eventData = log_msg.msg();
- if (!eventData) {
+ ASSERT_EQ(log_msg.entry.pid, pid);
+
+ if ((log_msg.entry.len != sizeof(android_log_event_long_t))
+ || (log_msg.id() != LOG_ID_SECURITY)) {
continue;
}
- // Tag
- int tag = get4LE(eventData);
- eventData += 4;
+ android_log_event_long_t* eventData;
+ eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
- if (tag != TAG) {
+ if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
continue;
}
- // List type
- ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
- eventData++;
-
- // Number of elements in list
- ASSERT_EQ(3, eventData[0]);
- eventData++;
-
- // Element #1: string type for subtag
- ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
- eventData++;
-
- ASSERT_EQ((int) strlen(SUBTAG), get4LE(eventData));
- eventData +=4;
-
- if (memcmp(SUBTAG, eventData, strlen(SUBTAG))) {
- continue;
+ log_time tx(reinterpret_cast<char*>(&eventData->payload.data));
+ if (ts == tx) {
+ ++count;
}
- eventData += strlen(SUBTAG);
-
- // Element #2: int type for uid
- ASSERT_EQ(EVENT_TYPE_INT, eventData[0]);
- eventData++;
-
- ASSERT_EQ(UID, get4LE(eventData));
- eventData += 4;
-
- // Element #3: string type for data
- ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
- eventData++;
-
- ASSERT_EQ(DATA_LEN, get4LE(eventData));
- eventData += 4;
-
- if (memcmp(max_payload_buf, eventData, DATA_LEN)) {
- continue;
- }
-
- ++count;
}
- EXPECT_EQ(1, count);
+ if (set_persist) {
+ property_set(persist_key, persist);
+ }
android_logger_list_close(logger_list);
+
+ bool clientHasSecurityCredentials = (uid == AID_SYSTEM) || (gid == AID_SYSTEM);
+ if (!clientHasSecurityCredentials) {
+ fprintf(stderr, "WARNING: "
+ "not system, content submitted but can not check end-to-end\n");
+ }
+ EXPECT_EQ(clientHasSecurityCredentials ? 1 : 0, count);
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
-TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__data_too_large) {
#ifdef __ANDROID__
- const int TAG = 123456782;
- const char SUBTAG[] = "test-subtag";
- const int UID = -1;
- const int DATA_LEN = sizeof(max_payload_buf);
+static void android_errorWriteWithInfoLog_helper(int TAG, const char* SUBTAG,
+ int UID, const char* payload,
+ int DATA_LEN, int& count) {
struct logger_list *logger_list;
pid_t pid = getpid();
@@ -1863,12 +1903,17 @@
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
- ASSERT_LT(0, android_errorWriteWithInfoLog(
- TAG, SUBTAG, UID, max_payload_buf, DATA_LEN));
+ int retval_android_errorWriteWithinInfoLog = android_errorWriteWithInfoLog(
+ TAG, SUBTAG, UID, payload, DATA_LEN);
+ if (payload) {
+ ASSERT_LT(0, retval_android_errorWriteWithinInfoLog);
+ } else {
+ ASSERT_GT(0, retval_android_errorWriteWithinInfoLog);
+ }
sleep(2);
- int count = 0;
+ count = 0;
for (;;) {
log_msg log_msg;
@@ -1891,6 +1936,12 @@
continue;
}
+ if (!payload) {
+ // This tag should not have been written because the data was null
+ ++count;
+ break;
+ }
+
// List type
ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
eventData++;
@@ -1903,13 +1954,15 @@
ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
eventData++;
- ASSERT_EQ((int) strlen(SUBTAG), get4LE(eventData));
- eventData +=4;
+ int subtag_len = strlen(SUBTAG);
+ if (subtag_len > 32) subtag_len = 32;
+ ASSERT_EQ(subtag_len, get4LE(eventData));
+ eventData += 4;
- if (memcmp(SUBTAG, eventData, strlen(SUBTAG))) {
+ if (memcmp(SUBTAG, eventData, subtag_len)) {
continue;
}
- eventData += strlen(SUBTAG);
+ eventData += subtag_len;
// Element #2: int type for uid
ASSERT_EQ(EVENT_TYPE_INT, eventData[0]);
@@ -1924,22 +1977,53 @@
size_t dataLen = get4LE(eventData);
eventData += 4;
+ if (DATA_LEN < 512) ASSERT_EQ(DATA_LEN, (int)dataLen);
- if (memcmp(max_payload_buf, eventData, dataLen)) {
+ if (memcmp(payload, eventData, dataLen)) {
continue;
}
- eventData += dataLen;
- // 4 bytes for the tag, and max_payload_buf should be truncated.
- ASSERT_LE(4 + 512, eventData - original); // worst expectations
- ASSERT_GT(4 + DATA_LEN, eventData - original); // must be truncated
+ if (DATA_LEN >= 512) {
+ eventData += dataLen;
+ // 4 bytes for the tag, and max_payload_buf should be truncated.
+ ASSERT_LE(4 + 512, eventData - original); // worst expectations
+ ASSERT_GT(4 + DATA_LEN, eventData - original); // must be truncated
+ }
++count;
}
- EXPECT_EQ(1, count);
-
android_logger_list_close(logger_list);
+}
+#endif
+
+TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__typical) {
+#ifdef __ANDROID__
+ int count;
+ android_errorWriteWithInfoLog_helper(
+ 123456781,
+ "test-subtag",
+ -1,
+ max_payload_buf,
+ 200,
+ count);
+ EXPECT_EQ(1, count);
+#else
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}
+
+TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__data_too_large) {
+#ifdef __ANDROID__
+ int count;
+ android_errorWriteWithInfoLog_helper(
+ 123456782,
+ "test-subtag",
+ -1,
+ max_payload_buf,
+ sizeof(max_payload_buf),
+ count);
+ EXPECT_EQ(1, count);
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
@@ -1947,49 +2031,15 @@
TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__null_data) {
#ifdef __ANDROID__
- const int TAG = 123456783;
- const char SUBTAG[] = "test-subtag";
- const int UID = -1;
- const int DATA_LEN = 200;
- struct logger_list *logger_list;
-
- pid_t pid = getpid();
-
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
-
- ASSERT_GT(0, android_errorWriteWithInfoLog(
- TAG, SUBTAG, UID, NULL, DATA_LEN));
-
- sleep(2);
-
- int count = 0;
-
- for (;;) {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) {
- break;
- }
-
- char *eventData = log_msg.msg();
- if (!eventData) {
- continue;
- }
-
- // Tag
- int tag = get4LE(eventData);
- eventData += 4;
-
- if (tag == TAG) {
- // This tag should not have been written because the data was null
- count++;
- break;
- }
- }
-
+ int count;
+ android_errorWriteWithInfoLog_helper(
+ 123456783,
+ "test-subtag",
+ -1,
+ NULL,
+ 200,
+ count);
EXPECT_EQ(0, count);
-
- android_logger_list_close(logger_list);
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
@@ -1997,88 +2047,15 @@
TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__subtag_too_long) {
#ifdef __ANDROID__
- const int TAG = 123456784;
- const char SUBTAG[] = "abcdefghijklmnopqrstuvwxyz now i know my abc";
- const int UID = -1;
- const int DATA_LEN = 200;
- struct logger_list *logger_list;
-
- pid_t pid = getpid();
-
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
-
- ASSERT_LT(0, android_errorWriteWithInfoLog(
- TAG, SUBTAG, UID, max_payload_buf, DATA_LEN));
-
- sleep(2);
-
- int count = 0;
-
- for (;;) {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) {
- break;
- }
-
- char *eventData = log_msg.msg();
- if (!eventData) {
- continue;
- }
-
- // Tag
- int tag = get4LE(eventData);
- eventData += 4;
-
- if (tag != TAG) {
- continue;
- }
-
- // List type
- ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
- eventData++;
-
- // Number of elements in list
- ASSERT_EQ(3, eventData[0]);
- eventData++;
-
- // Element #1: string type for subtag
- ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
- eventData++;
-
- // The subtag is longer than 32 and should be truncated to that.
- ASSERT_EQ(32, get4LE(eventData));
- eventData +=4;
-
- if (memcmp(SUBTAG, eventData, 32)) {
- continue;
- }
- eventData += 32;
-
- // Element #2: int type for uid
- ASSERT_EQ(EVENT_TYPE_INT, eventData[0]);
- eventData++;
-
- ASSERT_EQ(UID, get4LE(eventData));
- eventData += 4;
-
- // Element #3: string type for data
- ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
- eventData++;
-
- ASSERT_EQ(DATA_LEN, get4LE(eventData));
- eventData += 4;
-
- if (memcmp(max_payload_buf, eventData, DATA_LEN)) {
- continue;
- }
-
- ++count;
- }
-
+ int count;
+ android_errorWriteWithInfoLog_helper(
+ 123456784,
+ "abcdefghijklmnopqrstuvwxyz now i know my abc",
+ -1,
+ max_payload_buf,
+ 200,
+ count);
EXPECT_EQ(1, count);
-
- android_logger_list_close(logger_list);
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
@@ -2092,10 +2069,8 @@
buf_write_test(max_payload_buf);
}
-TEST(liblog, android_errorWriteLog__android_logger_list_read__success) {
#ifdef __ANDROID__
- const int TAG = 123456785;
- const char SUBTAG[] = "test-subtag";
+static void android_errorWriteLog_helper(int TAG, const char *SUBTAG, int& count) {
struct logger_list *logger_list;
pid_t pid = getpid();
@@ -2103,11 +2078,16 @@
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
- ASSERT_LT(0, android_errorWriteLog(TAG, SUBTAG));
+ int retval_android_errorWriteLog = android_errorWriteLog(TAG, SUBTAG);
+ if (SUBTAG) {
+ ASSERT_LT(0, retval_android_errorWriteLog);
+ } else {
+ ASSERT_GT(0, retval_android_errorWriteLog);
+ }
sleep(2);
- int count = 0;
+ count = 0;
for (;;) {
log_msg log_msg;
@@ -2128,6 +2108,12 @@
continue;
}
+ if (!SUBTAG) {
+ // This tag should not have been written because the data was null
+ ++count;
+ break;
+ }
+
// List type
ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
eventData++;
@@ -2149,9 +2135,15 @@
++count;
}
- EXPECT_EQ(1, count);
-
android_logger_list_close(logger_list);
+}
+#endif
+
+TEST(liblog, android_errorWriteLog__android_logger_list_read__success) {
+#ifdef __ANDROID__
+ int count;
+ android_errorWriteLog_helper(123456785, "test-subtag", count);
+ EXPECT_EQ(1, count);
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
@@ -2159,45 +2151,9 @@
TEST(liblog, android_errorWriteLog__android_logger_list_read__null_subtag) {
#ifdef __ANDROID__
- const int TAG = 123456786;
- struct logger_list *logger_list;
-
- pid_t pid = getpid();
-
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
-
- ASSERT_GT(0, android_errorWriteLog(TAG, NULL));
-
- sleep(2);
-
- int count = 0;
-
- for (;;) {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) {
- break;
- }
-
- char *eventData = log_msg.msg();
- if (!eventData) {
- continue;
- }
-
- // Tag
- int tag = get4LE(eventData);
- eventData += 4;
-
- if (tag == TAG) {
- // This tag should not have been written because the data was null
- count++;
- break;
- }
- }
-
+ int count;
+ android_errorWriteLog_helper(123456786, NULL, count);
EXPECT_EQ(0, count);
-
- android_logger_list_close(logger_list);
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
@@ -2835,10 +2791,15 @@
TEST(liblog, __android_log_pmsg_file_write) {
#ifdef __ANDROID__
__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);
+ if (getuid() == AID_ROOT) {
+ tested__android_log_close = true;
+ bool pmsgActiveAfter__android_log_close = isPmsgActive();
+ bool logdwActiveAfter__android_log_close = isLogdwActive();
+ EXPECT_FALSE(pmsgActiveAfter__android_log_close);
+ EXPECT_FALSE(logdwActiveAfter__android_log_close);
+ } else if (!tested__android_log_close) {
+ fprintf(stderr, "WARNING: can not test __android_log_close()\n");
+ }
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));
@@ -2852,24 +2813,32 @@
"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);
+ bool pmsgActiveAfter__android_pmsg_file_write;
+ bool logdwActiveAfter__android_pmsg_file_write;
+ if (getuid() == AID_ROOT) {
+ pmsgActiveAfter__android_pmsg_file_write = isPmsgActive();
+ 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);
+ if (getuid() == AID_ROOT) {
+ 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)));
- 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);
+ if (getuid() == AID_ROOT) {
+ 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);
+ }
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
@@ -2904,19 +2873,26 @@
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);
+ if (getuid() == AID_ROOT) {
+ tested__android_log_close = true;
+ bool pmsgActiveAfter__android_log_close = isPmsgActive();
+ bool logdwActiveAfter__android_log_close = isLogdwActive();
+ EXPECT_FALSE(pmsgActiveAfter__android_log_close);
+ EXPECT_FALSE(logdwActiveAfter__android_log_close);
+ } else if (!tested__android_log_close) {
+ fprintf(stderr, "WARNING: can not test __android_log_close()\n");
+ }
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 (getuid() == AID_ROOT) {
+ 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,
@@ -2934,13 +2910,6 @@
}
#ifdef __ANDROID__
-// meant to be handed to ASSERT_TRUE / EXPECT_TRUE only to expand the message
-static testing::AssertionResult IsOk(bool ok, std::string &message) {
- return ok ?
- testing::AssertionSuccess() :
- (testing::AssertionFailure() << message);
-}
-
// must be: '<needle:> 0 kB'
static bool isZero(const std::string &content, std::string::size_type pos,
const char* needle) {
@@ -3043,3 +3012,35 @@
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
+
+TEST(liblog, __android_log_ratelimit) {
+ time_t state = 0;
+
+ errno = 42;
+ // Prime
+ __android_log_ratelimit(3, &state);
+ EXPECT_EQ(errno, 42);
+ // Check
+ EXPECT_FALSE(__android_log_ratelimit(3, &state));
+ sleep(1);
+ EXPECT_FALSE(__android_log_ratelimit(3, &state));
+ sleep(4);
+ EXPECT_TRUE(__android_log_ratelimit(3, &state));
+ sleep(5);
+ EXPECT_TRUE(__android_log_ratelimit(3, &state));
+
+ // API checks
+ IF_ALOG_RATELIMIT_LOCAL(3, &state) {
+ EXPECT_FALSE(0 != "IF_ALOG_RATELIMIT_LOCAL(3, &state)");
+ }
+
+ IF_ALOG_RATELIMIT() {
+ ;
+ } else {
+ EXPECT_TRUE(0 == "IF_ALOG_RATELIMIT()");
+ }
+ IF_ALOG_RATELIMIT() {
+ EXPECT_FALSE(0 != "IF_ALOG_RATELIMIT()");
+ }
+ // Do not test default seconds, to allow liblog to tune freely
+}
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp
index 9d33899..c1133fb 100644
--- a/libnativeloader/Android.bp
+++ b/libnativeloader/Android.bp
@@ -9,8 +9,8 @@
"liblog",
"libcutils",
"libnativebridge",
+ "libbase",
],
- static_libs: ["libbase"],
target: {
android: {
shared_libs: ["libdl"],
diff --git a/libsync/sync.c b/libsync/sync.c
index 169dc36..6281b20 100644
--- a/libsync/sync.c
+++ b/libsync/sync.c
@@ -21,8 +21,6 @@
#include <stdint.h>
#include <string.h>
-#include <linux/sw_sync.h>
-
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -42,6 +40,16 @@
#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 1, struct sync_merge_data)
#define SYNC_IOC_FENCE_INFO _IOWR(SYNC_IOC_MAGIC, 2, struct sync_fence_info_data)
+struct sw_sync_create_fence_data {
+ __u32 value;
+ char name[32];
+ __s32 fence;
+};
+
+#define SW_SYNC_IOC_MAGIC 'W'
+#define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0, struct sw_sync_create_fence_data)
+#define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32)
+
int sync_wait(int fd, int timeout)
{
__s32 to = timeout;
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index fce1378..44daf36 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -20,6 +20,7 @@
"-DZLIB_CONST",
"-Werror",
"-Wall",
+ "-D_FILE_OFFSET_BITS=64",
],
cppflags: [
"-Wold-style-cast",
@@ -56,11 +57,13 @@
name: "libziparchive",
host_supported: true,
defaults: ["libziparchive_defaults", "libziparchive_flags"],
- static_libs: ["libutils"],
shared_libs: ["liblog", "libbase"],
target: {
android: {
- static_libs: ["libz"],
+ shared_libs: ["libz", "libutils"],
+ },
+ host: {
+ static_libs: ["libutils"],
},
linux_bionic: {
static_libs: ["libz"],
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 11cffe6..725d76e 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -451,11 +451,12 @@
"logcat -v brief -b radio,events,bogo,system,main -g 2>/dev/null"));
}
-static void caught_blocking(int /*signum*/)
+static void caught_blocking(int signum)
{
unsigned long long v = 0xDEADBEEFA55A0000ULL;
v += getpid() & 0xFFFF;
+ if (signum == 0) ++v;
LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
}
@@ -520,11 +521,12 @@
EXPECT_EQ(1, signals);
}
-static void caught_blocking_tail(int /*signum*/)
+static void caught_blocking_tail(int signum)
{
unsigned long long v = 0xA55ADEADBEEF0000ULL;
v += getpid() & 0xFFFF;
+ if (signum == 0) ++v;
LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
}
@@ -955,10 +957,11 @@
" -n 256 -r 1024"));
}
-static void caught_blocking_clear(int /*signum*/) {
+static void caught_blocking_clear(int signum) {
unsigned long long v = 0xDEADBEEFA55C0000ULL;
v += getpid() & 0xFFFF;
+ if (signum == 0) ++v;
LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
}
diff --git a/logd/Android.mk b/logd/Android.mk
index 7fe48d7..2da9782 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -40,6 +40,7 @@
# event_flag += $(call event_logtags,logd)
# so make sure we do not regret hard-coding it as follows:
event_flag := -DAUDITD_LOG_TAG=1003 -DCHATTY_LOG_TAG=1004
+event_flag += -DLIBLOG_LOG_TAG=1006
LOCAL_CFLAGS := -Werror $(event_flag)
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index c3ccd84..92d957f 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -34,6 +34,7 @@
#include "LogBuffer.h"
#include "LogKlog.h"
#include "LogReader.h"
+#include "LogUtils.h"
#define KMSG_PRIORITY(PRI) \
'<', \
@@ -42,23 +43,70 @@
'>'
LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg) :
- SocketListener(getLogSocket(), false),
+ SocketListener(mSock = getLogSocket(), false),
logbuf(buf),
reader(reader),
fdDmesg(fdDmesg),
- initialized(false) {
+ main(__android_logger_property_get_bool("ro.logd.auditd.main",
+ BOOL_DEFAULT_TRUE)),
+ events(__android_logger_property_get_bool("ro.logd.auditd.events",
+ BOOL_DEFAULT_TRUE)),
+ initialized(false),
+ tooFast(false) {
static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO),
'l', 'o', 'g', 'd', '.', 'a', 'u', 'd', 'i', 't', 'd', ':',
' ', 's', 't', 'a', 'r', 't', '\n' };
write(fdDmesg, auditd_message, sizeof(auditd_message));
}
+void LogAudit::checkRateLimit() {
+
+ // trim list for AUDIT_RATE_LIMIT_BURST_DURATION of history
+ log_time oldest(AUDIT_RATE_LIMIT_BURST_DURATION, 0);
+ bucket.emplace(android_log_clockid());
+ oldest = bucket.back() - oldest;
+ while (bucket.front() < oldest) bucket.pop();
+
+ static const size_t upperThreshold =
+ ((AUDIT_RATE_LIMIT_BURST_DURATION *
+ (AUDIT_RATE_LIMIT_DEFAULT + AUDIT_RATE_LIMIT_MAX)) + 1) /
+ 2;
+ if (bucket.size() >= upperThreshold) {
+ // Hit peak, slow down source
+ if (!tooFast) {
+ tooFast = true;
+ audit_rate_limit(mSock, AUDIT_RATE_LIMIT_MAX);
+ }
+
+ // We do not need to hold on to the full set of timing data history,
+ // let's ensure it does not grow without bounds. This also ensures
+ // that std::dequeue underneath behaves almost like a ring buffer.
+ do {
+ bucket.pop();
+ } while (bucket.size() >= upperThreshold);
+ return;
+ }
+
+ if (!tooFast) return;
+
+ static const size_t lowerThreshold = AUDIT_RATE_LIMIT_BURST_DURATION *
+ AUDIT_RATE_LIMIT_MAX;
+
+ if (bucket.size() >= lowerThreshold) return;
+
+ tooFast = false;
+ // Went below max sustained rate, allow source to speed up
+ audit_rate_limit(mSock, AUDIT_RATE_LIMIT_DEFAULT);
+}
+
bool LogAudit::onDataAvailable(SocketClient *cli) {
if (!initialized) {
prctl(PR_SET_NAME, "logd.auditd");
initialized = true;
}
+ checkRateLimit();
+
struct audit_message rep;
rep.nlh.nlmsg_type = 0;
@@ -70,8 +118,7 @@
return false;
}
- logPrint("type=%d %.*s",
- rep.nlh.nlmsg_type, rep.nlh.nlmsg_len, rep.data);
+ logPrint("type=%d %.*s", rep.nlh.nlmsg_type, rep.nlh.nlmsg_len, rep.data);
return true;
}
@@ -93,6 +140,13 @@
}
char *cp;
+ // Work around kernels missing
+ // https://github.com/torvalds/linux/commit/b8f89caafeb55fba75b74bea25adc4e4cd91be67
+ // Such kernels improperly add newlines inside audit messages.
+ while ((cp = strchr(str, '\n'))) {
+ *cp = ' ';
+ }
+
while ((cp = strstr(str, " "))) {
memmove(cp, cp + 1, strlen(cp + 1) + 1);
}
@@ -117,7 +171,8 @@
if (avcl) {
char *avcr = strstr(str, avc);
- skip = avcr && !strcmp(avcl + strlen(avc), avcr + strlen(avc));
+ skip = avcr && !fastcmp<strcmp>(avcl + strlen(avc),
+ avcr + strlen(avc));
if (skip) {
++count;
free(last_str);
@@ -170,6 +225,11 @@
}
}
+ if (!main && !events) {
+ free(str);
+ return 0;
+ }
+
pid_t pid = getpid();
pid_t tid = gettid();
uid_t uid = AID_LOGD;
@@ -220,7 +280,7 @@
bool notify = false;
- { // begin scope for event buffer
+ if (events) { // begin scope for event buffer
uint32_t buffer[(n + sizeof(uint32_t) - 1) / sizeof(uint32_t)];
android_log_event_string_t *event
@@ -275,7 +335,7 @@
size_t e = strnlen(ecomm, LOGGER_ENTRY_MAX_PAYLOAD - b);
n = b + e + l + 2;
- { // begin scope for main buffer
+ if (main) { // begin scope for main buffer
char newstr[n];
*newstr = info ? ANDROID_LOG_INFO : ANDROID_LOG_WARN;
@@ -333,5 +393,6 @@
audit_close(fd);
fd = -1;
}
+ (void)audit_rate_limit(fd, AUDIT_RATE_LIMIT_DEFAULT);
return fd;
}
diff --git a/logd/LogAudit.h b/logd/LogAudit.h
index ab30e28..045d631 100644
--- a/logd/LogAudit.h
+++ b/logd/LogAudit.h
@@ -17,6 +17,8 @@
#ifndef _LOGD_LOG_AUDIT_H__
#define _LOGD_LOG_AUDIT_H__
+#include <queue>
+
#include <sysutils/SocketListener.h>
#include "LogBuffer.h"
@@ -26,9 +28,16 @@
class LogAudit : public SocketListener {
LogBuffer *logbuf;
LogReader *reader;
- int fdDmesg;
+ int fdDmesg; // fdDmesg >= 0 is functionally bool dmesg
+ bool main;
+ bool events;
bool initialized;
+ bool tooFast;
+ int mSock;
+ std::queue<log_time> bucket;
+ void checkRateLimit();
+
public:
LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg);
int log(char *buf, size_t len);
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index a009433..cc65d47 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -17,6 +17,7 @@
//#define DEBUG_CHECK_FOR_STALE_ENTRIES
#include <ctype.h>
+#include <endian.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
@@ -33,6 +34,7 @@
#include "LogBuffer.h"
#include "LogKlog.h"
#include "LogReader.h"
+#include "LogUtils.h"
#ifndef __predict_false
#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
@@ -110,9 +112,81 @@
mTimes(*times) {
pthread_mutex_init(&mLogElementsLock, NULL);
+ log_id_for_each(i) {
+ lastLoggedElements[i] = NULL;
+ droppedElements[i] = NULL;
+ }
+
init();
}
+LogBuffer::~LogBuffer() {
+ log_id_for_each(i) {
+ delete lastLoggedElements[i];
+ delete droppedElements[i];
+ }
+}
+
+enum match_type {
+ DIFFERENT,
+ SAME,
+ SAME_LIBLOG
+};
+
+static enum match_type identical(LogBufferElement* elem, LogBufferElement* last) {
+ // is it mostly identical?
+// if (!elem) return DIFFERENT;
+ unsigned short lenl = elem->getMsgLen();
+ if (!lenl) return DIFFERENT;
+// if (!last) return DIFFERENT;
+ unsigned short lenr = last->getMsgLen();
+ if (!lenr) return DIFFERENT;
+// if (elem->getLogId() != last->getLogId()) return DIFFERENT;
+ if (elem->getUid() != last->getUid()) return DIFFERENT;
+ if (elem->getPid() != last->getPid()) return DIFFERENT;
+ if (elem->getTid() != last->getTid()) return DIFFERENT;
+
+ // last is more than a minute old, stop squashing identical messages
+ if (elem->getRealTime().nsec() >
+ (last->getRealTime().nsec() + 60 * NS_PER_SEC)) return DIFFERENT;
+
+ // Identical message
+ const char* msgl = elem->getMsg();
+ const char* msgr = last->getMsg();
+ if (lenl == lenr) {
+ if (!fastcmp<memcmp>(msgl, msgr, lenl)) return SAME;
+ // liblog tagged messages (content gets summed)
+ if ((elem->getLogId() == LOG_ID_EVENTS) &&
+ (lenl == sizeof(android_log_event_int_t)) &&
+ !fastcmp<memcmp>(msgl, msgr,
+ sizeof(android_log_event_int_t) - sizeof(int32_t)) &&
+ (elem->getTag() == LIBLOG_LOG_TAG)) return SAME_LIBLOG;
+ }
+
+ // audit message (except sequence number) identical?
+ static const char avc[] = "): avc: ";
+
+ if (last->isBinary()) {
+ if (fastcmp<memcmp>(msgl, msgr,
+ sizeof(android_log_event_string_t) -
+ sizeof(int32_t))) return DIFFERENT;
+ msgl += sizeof(android_log_event_string_t);
+ lenl -= sizeof(android_log_event_string_t);
+ msgr += sizeof(android_log_event_string_t);
+ lenr -= sizeof(android_log_event_string_t);
+ }
+ const char *avcl = android::strnstr(msgl, lenl, avc);
+ if (!avcl) return DIFFERENT;
+ lenl -= avcl - msgl;
+ const char *avcr = android::strnstr(msgr, lenr, avc);
+ if (!avcr) return DIFFERENT;
+ lenr -= avcr - msgr;
+ if (lenl != lenr) return DIFFERENT;
+ if (fastcmp<memcmp>(avcl + strlen(avc),
+ avcr + strlen(avc), lenl)) return DIFFERENT;
+ return SAME;
+}
+
int LogBuffer::log(log_id_t log_id, log_time realtime,
uid_t uid, pid_t pid, pid_t tid,
const char *msg, unsigned short len) {
@@ -145,14 +219,164 @@
}
pthread_mutex_lock(&mLogElementsLock);
+ LogBufferElement* currentLast = lastLoggedElements[log_id];
+ if (currentLast) {
+ LogBufferElement *dropped = droppedElements[log_id];
+ unsigned short count = dropped ? dropped->getDropped() : 0;
+ //
+ // State Init
+ // incoming:
+ // dropped = NULL
+ // currentLast = NULL;
+ // elem = incoming message
+ // outgoing:
+ // dropped = NULL -> State 0
+ // currentLast = copy of elem
+ // log elem
+ // State 0
+ // incoming:
+ // count = 0
+ // dropped = NULL
+ // currentLast = copy of last message
+ // elem = incoming message
+ // outgoing: if match != DIFFERENT
+ // dropped = copy of first identical message -> State 1
+ // currentLast = reference to elem
+ // break: if match == DIFFERENT
+ // dropped = NULL -> State 0
+ // delete copy of last message (incoming currentLast)
+ // currentLast = copy of elem
+ // log elem
+ // State 1
+ // incoming:
+ // count = 0
+ // dropped = copy of first identical message
+ // currentLast = reference to last held-back incoming
+ // message
+ // elem = incoming message
+ // outgoing: if match == SAME
+ // delete copy of first identical message (dropped)
+ // dropped = reference to last held-back incoming
+ // message set to chatty count of 1 -> State 2
+ // currentLast = reference to elem
+ // outgoing: if match == SAME_LIBLOG
+ // dropped = copy of first identical message -> State 1
+ // take sum of currentLast and elem
+ // if sum overflows:
+ // log currentLast
+ // currentLast = reference to elem
+ // else
+ // delete currentLast
+ // currentLast = reference to elem, sum liblog.
+ // break: if match == DIFFERENT
+ // delete dropped
+ // dropped = NULL -> State 0
+ // log reference to last held-back (currentLast)
+ // currentLast = copy of elem
+ // log elem
+ // State 2
+ // incoming:
+ // count = chatty count
+ // dropped = chatty message holding count
+ // currentLast = reference to last held-back incoming
+ // message.
+ // dropped = chatty message holding count
+ // elem = incoming message
+ // outgoing: if match != DIFFERENT
+ // delete chatty message holding count
+ // dropped = reference to last held-back incoming
+ // message, set to chatty count + 1
+ // currentLast = reference to elem
+ // break: if match == DIFFERENT
+ // log dropped (chatty message)
+ // dropped = NULL -> State 0
+ // log reference to last held-back (currentLast)
+ // currentLast = copy of elem
+ // log elem
+ //
+ enum match_type match = identical(elem, currentLast);
+ if (match != DIFFERENT) {
+ if (dropped) {
+ // Sum up liblog tag messages?
+ if ((count == 0) /* at Pass 1 */ && (match == SAME_LIBLOG)) {
+ android_log_event_int_t* event =
+ reinterpret_cast<android_log_event_int_t*>(
+ const_cast<char*>(currentLast->getMsg()));
+ //
+ // To unit test, differentiate with something like:
+ // event->header.tag = htole32(CHATTY_LOG_TAG);
+ // here, then instead of delete currentLast below,
+ // log(currentLast) to see the incremental sums form.
+ //
+ uint32_t swab = event->payload.data;
+ unsigned long long total = htole32(swab);
+ event = reinterpret_cast<android_log_event_int_t*>(
+ const_cast<char*>(elem->getMsg()));
+ swab = event->payload.data;
+ lastLoggedElements[LOG_ID_EVENTS] = elem;
+ total += htole32(swab);
+ // check for overflow
+ if (total >= UINT32_MAX) {
+ log(currentLast);
+ pthread_mutex_unlock(&mLogElementsLock);
+ return len;
+ }
+ stats.add(currentLast);
+ stats.subtract(currentLast);
+ delete currentLast;
+ swab = total;
+ event->payload.data = htole32(swab);
+ pthread_mutex_unlock(&mLogElementsLock);
+ return len;
+ }
+ if (count == USHRT_MAX) {
+ log(dropped);
+ count = 1;
+ } else {
+ delete dropped;
+ ++count;
+ }
+ }
+ if (count) {
+ stats.add(currentLast);
+ stats.subtract(currentLast);
+ currentLast->setDropped(count);
+ }
+ droppedElements[log_id] = currentLast;
+ lastLoggedElements[log_id] = elem;
+ pthread_mutex_unlock(&mLogElementsLock);
+ return len;
+ }
+ if (dropped) { // State 1 or 2
+ if (count) { // State 2
+ log(dropped); // report chatty
+ } else { // State 1
+ delete dropped;
+ }
+ droppedElements[log_id] = NULL;
+ log(currentLast); // report last message in the series
+ } else { // State 0
+ delete currentLast;
+ }
+ }
+ lastLoggedElements[log_id] = new LogBufferElement(*elem);
+
+ log(elem);
+ pthread_mutex_unlock(&mLogElementsLock);
+
+ return len;
+}
+
+// assumes mLogElementsLock held, owns elem, will look after garbage collection
+void LogBuffer::log(LogBufferElement* elem) {
// Insert elements in time sorted order if possible
// NB: if end is region locked, place element at end of list
LogBufferElementCollection::iterator it = mLogElements.end();
LogBufferElementCollection::iterator last = it;
while (last != mLogElements.begin()) {
--it;
- if ((*it)->getRealTime() <= realtime) {
+ if ((*it)->getRealTime() <= elem->getRealTime()) {
break;
}
last = it;
@@ -169,7 +393,7 @@
LastLogTimes::iterator times = mTimes.begin();
while(times != mTimes.end()) {
- LogTimeEntry *entry = (*times);
+ LogTimeEntry* entry = (*times);
if (entry->owned_Locked()) {
if (!entry->mNonBlock) {
end_always = true;
@@ -187,17 +411,14 @@
|| (end_set && (end >= (*last)->getSequence()))) {
mLogElements.push_back(elem);
} else {
- mLogElements.insert(last,elem);
+ mLogElements.insert(last, elem);
}
LogTimeEntry::unlock();
}
stats.add(elem);
- maybePrune(log_id);
- pthread_mutex_unlock(&mLogElementsLock);
-
- return len;
+ maybePrune(elem->getLogId());
}
// Prune at most 10% of the log entries or maxPrune, whichever is less.
@@ -313,10 +534,9 @@
class LogBufferElementKey {
const union {
struct {
- uint16_t uid;
+ uint32_t uid;
uint16_t pid;
uint16_t tid;
- uint16_t padding;
} __packed;
uint64_t value;
} __packed;
@@ -325,8 +545,8 @@
LogBufferElementKey(uid_t uid, pid_t pid, pid_t tid):
uid(uid),
pid(pid),
- tid(tid),
- padding(0) {
+ tid(tid)
+ {
}
explicit LogBufferElementKey(uint64_t key):value(key) { }
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index ff9692e..932d55f 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -99,10 +99,15 @@
bool monotonic;
+ LogBufferElement* lastLoggedElements[LOG_ID_MAX];
+ LogBufferElement* droppedElements[LOG_ID_MAX];
+ void log(LogBufferElement* elem);
+
public:
LastLogTimes &mTimes;
explicit LogBuffer(LastLogTimes *times);
+ ~LogBuffer();
void init();
bool isMonotonic() { return monotonic; }
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index f5c60c7..5e37a30 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -50,6 +50,19 @@
0;
}
+LogBufferElement::LogBufferElement(const LogBufferElement &elem) :
+ mTag(elem.mTag),
+ mUid(elem.mUid),
+ mPid(elem.mPid),
+ mTid(elem.mTid),
+ mSequence(elem.mSequence),
+ mRealTime(elem.mRealTime),
+ mMsgLen(elem.mMsgLen),
+ mLogId(elem.mLogId) {
+ mMsg = new char[mMsgLen];
+ memcpy(mMsg, elem.mMsg, mMsgLen);
+}
+
LogBufferElement::~LogBufferElement() {
delete [] mMsg;
}
@@ -89,7 +102,7 @@
size_t name_len = strlen(name);
// KISS: ToDo: Only checks prefix truncated, not suffix, or both
if ((retval_len < name_len)
- && !fast<strcmp>(retval, name + name_len - retval_len)) {
+ && !fastcmp<strcmp>(retval, name + name_len - retval_len)) {
free(retval);
retval = name;
} else {
@@ -157,8 +170,6 @@
mDropped, (mDropped > 1) ? "s" : "");
size_t hdrLen;
- // LOG_ID_SECURITY not strictly needed since spam filter not activated,
- // but required for accuracy.
if (isBinary()) {
hdrLen = sizeof(android_log_event_string_t);
} else {
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index fb7fbed..f8ffacd 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -59,6 +59,7 @@
LogBufferElement(log_id_t log_id, log_time realtime,
uid_t uid, pid_t pid, pid_t tid,
const char *msg, unsigned short len);
+ LogBufferElement(const LogBufferElement &elem);
virtual ~LogBufferElement();
bool isBinary(void) const {
@@ -79,6 +80,7 @@
return mDropped = value;
}
unsigned short getMsgLen() const { return mMsg ? mMsgLen : 0; }
+ const char* getMsg() const { return mMsg; }
uint64_t getSequence(void) const { return mSequence; }
static uint64_t getCurrentSequence(void) { return sequence.load(memory_order_relaxed); }
log_time getRealTime(void) const { return mRealTime; }
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index 7073535..f224079 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -306,22 +306,18 @@
static const char resumeStr[] = "PM: suspend exit ";
static const char suspendedStr[] = "Suspended for ";
-static const char *strnstr(const char *s, size_t len, const char *needle) {
+const char* android::strnstr(const char* s, size_t len, const char* needle) {
char c;
- if (!len) {
- return NULL;
- }
+ if (!len) return NULL;
if ((c = *needle++) != 0) {
size_t needleLen = strlen(needle);
do {
do {
- if (len <= needleLen) {
- return NULL;
- }
+ if (len <= needleLen) return NULL;
--len;
} while (*s++ != c);
- } while (fast<memcmp>(s, needle, needleLen));
+ } while (fastcmp<memcmp>(s, needle, needleLen));
s--;
}
return s;
@@ -349,25 +345,25 @@
return;
}
- const char *b;
- if (((b = strnstr(cp, len, suspendStr)))
+ const char* b;
+ if (((b = android::strnstr(cp, len, suspendStr)))
&& ((size_t)((b += sizeof(suspendStr) - 1) - cp) < len)) {
len -= b - cp;
calculateCorrection(now, b, len);
- } else if (((b = strnstr(cp, len, resumeStr)))
+ } else if (((b = android::strnstr(cp, len, resumeStr)))
&& ((size_t)((b += sizeof(resumeStr) - 1) - cp) < len)) {
len -= b - cp;
calculateCorrection(now, b, len);
- } else if (((b = strnstr(cp, len, healthd)))
+ } else if (((b = android::strnstr(cp, len, healthd)))
&& ((size_t)((b += sizeof(healthd) - 1) - cp) < len)
- && ((b = strnstr(b, len -= b - cp, battery)))
+ && ((b = android::strnstr(b, len -= b - cp, battery)))
&& ((size_t)((b += sizeof(battery) - 1) - cp) < len)) {
// NB: healthd is roughly 150us late, so we use it instead to
// trigger a check for ntp-induced or hardware clock drift.
log_time real(CLOCK_REALTIME);
log_time mono(CLOCK_MONOTONIC);
correction = (real < mono) ? log_time::EPOCH : (real - mono);
- } else if (((b = strnstr(cp, len, suspendedStr)))
+ } else if (((b = android::strnstr(cp, len, suspendedStr)))
&& ((size_t)((b += sizeof(suspendStr) - 1) - cp) < len)) {
len -= b - cp;
log_time real;
@@ -466,18 +462,14 @@
// Passed the entire SYSLOG_ACTION_READ_ALL buffer and interpret a
// compensated start time.
-void LogKlog::synchronize(const char *buf, size_t len) {
- const char *cp = strnstr(buf, len, suspendStr);
+void LogKlog::synchronize(const char* buf, size_t len) {
+ const char* cp = android::strnstr(buf, len, suspendStr);
if (!cp) {
- cp = strnstr(buf, len, resumeStr);
- if (!cp) {
- return;
- }
+ cp = android::strnstr(buf, len, resumeStr);
+ if (!cp) return;
} else {
- const char *rp = strnstr(buf, len, resumeStr);
- if (rp && (rp < cp)) {
- cp = rp;
- }
+ const char* rp = android::strnstr(buf, len, resumeStr);
+ if (rp && (rp < cp)) cp = rp;
}
do {
@@ -491,7 +483,7 @@
log_time now;
sniffTime(now, &cp, len - (cp - buf), true);
- const char *suspended = strnstr(buf, len, suspendedStr);
+ const char* suspended = android::strnstr(buf, len, suspendedStr);
if (!suspended || (suspended > cp)) {
return;
}
@@ -581,12 +573,12 @@
// logd.klogd:
// return -1 if message logd.klogd: <signature>
//
-int LogKlog::log(const char *buf, size_t len) {
- if (auditd && strnstr(buf, len, " audit(")) {
+int LogKlog::log(const char* buf, size_t len) {
+ if (auditd && android::strnstr(buf, len, " audit(")) {
return 0;
}
- const char *p = buf;
+ const char* p = buf;
int pri = parseKernelPrio(&p, len);
log_time now;
@@ -594,7 +586,7 @@
// sniff for start marker
const char klogd_message[] = "logd.klogd: ";
- const char *start = strnstr(p, len - (p - buf), klogd_message);
+ const char* start = android::strnstr(p, len - (p - buf), klogd_message);
if (start) {
uint64_t sig = strtoll(start + sizeof(klogd_message) - 1, NULL, 10);
if (sig == signature.nsec()) {
@@ -640,7 +632,7 @@
static const char infoBrace[] = "[INFO]";
static const size_t infoBraceLen = strlen(infoBrace);
- if ((taglen >= infoBraceLen) && !fast<strncmp>(p, infoBrace, infoBraceLen)) {
+ if ((taglen >= infoBraceLen) && !fastcmp<strncmp>(p, infoBrace, infoBraceLen)) {
// <PRI>[<TIME>] "[INFO]"<tag> ":" message
bt = p + infoBraceLen;
taglen -= infoBraceLen;
@@ -675,7 +667,7 @@
p = cp + 1;
} else if ((taglen > size) && (tolower(*bt) == tolower(*cp))) {
// clean up any tag stutter
- if (!fast<strncasecmp>(bt + 1, cp + 1, size - 1)) { // no match
+ if (!fastcmp<strncasecmp>(bt + 1, cp + 1, size - 1)) { // no match
// <PRI>[<TIME>] <tag> <tag> : message
// <PRI>[<TIME>] <tag> <tag>: message
// <PRI>[<TIME>] <tag> '<tag>.<num>' : message
@@ -697,8 +689,8 @@
static const char host[] = "_host";
static const size_t hostlen = strlen(host);
if ((size > hostlen) &&
- !fast<strncmp>(bt + size - hostlen, host, hostlen) &&
- !fast<strncmp>(bt + 1, cp + 1, size - hostlen - 1)) {
+ !fastcmp<strncmp>(bt + size - hostlen, host, hostlen) &&
+ !fastcmp<strncmp>(bt + 1, cp + 1, size - hostlen - 1)) {
const char *b = cp;
cp += size - hostlen;
taglen -= size - hostlen;
@@ -746,10 +738,10 @@
// register names like x18 but not driver names like en0
|| ((size == 3) && (isdigit(tag[1]) && isdigit(tag[2])))
// blacklist
- || ((size == cpuLen) && !fast<strncmp>(tag, cpu, cpuLen))
- || ((size == warningLen) && !fast<strncasecmp>(tag, warning, warningLen))
- || ((size == errorLen) && !fast<strncasecmp>(tag, error, errorLen))
- || ((size == infoLen) && !fast<strncasecmp>(tag, info, infoLen))) {
+ || ((size == cpuLen) && !fastcmp<strncmp>(tag, cpu, cpuLen))
+ || ((size == warningLen) && !fastcmp<strncasecmp>(tag, warning, warningLen))
+ || ((size == errorLen) && !fastcmp<strncasecmp>(tag, error, errorLen))
+ || ((size == infoLen) && !fastcmp<strncasecmp>(tag, info, infoLen))) {
p = start;
etag = tag = "";
}
@@ -761,7 +753,7 @@
const char *mp = strnrchr(tag, ']', taglen);
if (mp && (++mp < etag)) {
size_t s = etag - mp;
- if (((s + s) < taglen) && !fast<memcmp>(mp, mp - 1 - s, s)) {
+ if (((s + s) < taglen) && !fastcmp<memcmp>(mp, mp - 1 - s, s)) {
taglen = mp - tag;
}
}
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 61d4c49..1b50b4e 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -108,7 +108,7 @@
}
bool nonBlock = false;
- if (!fast<strncmp>(buffer, "dumpAndClose", 12)) {
+ if (!fastcmp<strncmp>(buffer, "dumpAndClose", 12)) {
// Allow writer to get some cycles, and wait for pending notifications
sched_yield();
LogTimeEntry::lock();
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index d4b48ef..273150e 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -27,6 +27,8 @@
#include "LogStatistics.h"
+size_t LogStatistics::SizesTotal;
+
LogStatistics::LogStatistics() : enable(false) {
log_id_for_each(id) {
mSizes[id] = 0;
@@ -39,6 +41,8 @@
namespace android {
+size_t sizesTotal() { return LogStatistics::sizesTotal(); }
+
// caller must own and free character string
char *pidToName(pid_t pid) {
char *retval = NULL;
@@ -53,7 +57,7 @@
if (ret > 0) {
buffer[sizeof(buffer)-1] = '\0';
// frameworks intermediate state
- if (fast<strcmp>(buffer, "<pre-initialized>")) {
+ if (fastcmp<strcmp>(buffer, "<pre-initialized>")) {
retval = strdup(buffer);
}
}
@@ -71,8 +75,18 @@
mSizes[log_id] += size;
++mElements[log_id];
- mSizesTotal[log_id] += size;
- ++mElementsTotal[log_id];
+ if (element->getDropped()) {
+ ++mDroppedElements[log_id];
+ } else {
+ // When caller adding a chatty entry, they will have already
+ // called add() and subtract() for each entry as they are
+ // evaluated and trimmed, thus recording size and number of
+ // elements, but we must recognize the manufactured dropped
+ // entry as not contributing to the lifetime totals.
+ mSizesTotal[log_id] += size;
+ SizesTotal += size;
+ ++mElementsTotal[log_id];
+ }
if (log_id == LOG_ID_KERNEL) {
return;
@@ -182,7 +196,7 @@
}
// Parse /data/system/packages.list
- uid_t userId = uid % AID_USER;
+ uid_t userId = uid % AID_USER_OFFSET;
const char *name = android::uidToName(userId);
if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) {
name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP));
@@ -209,7 +223,7 @@
if (nameTmp) {
if (!name) {
name = strdup(nameTmp);
- } else if (fast<strcmp>(name, nameTmp)) {
+ } else if (fastcmp<strcmp>(name, nameTmp)) {
free(const_cast<char *>(name));
name = NULL;
break;
@@ -295,7 +309,7 @@
if ((spaces <= 0) && pruned.length()) {
spaces = 1;
}
- if ((spaces > 0) && (pruned.length() != 0)) {
+ if (spaces > 0) {
change += android::base::StringPrintf("%*s", (int)spaces, "");
}
pruned = change + pruned;
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 1f598af..7acef6d 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -17,11 +17,12 @@
#ifndef _LOGD_LOG_STATISTICS_H__
#define _LOGD_LOG_STATISTICS_H__
-#include <memory>
+#include <ctype.h>
#include <stdlib.h>
#include <sys/types.h>
#include <algorithm> // std::max
+#include <memory>
#include <string> // std::string
#include <unordered_map>
@@ -211,14 +212,16 @@
EntryBaseConstants::total_len
- name.length() - drop_len - 1);
- if (pruned.length()) {
- return android::base::StringPrintf("%s%*s%*s\n", name.c_str(),
- (int)size_len, size.c_str(),
- (int)drop_len, pruned.c_str());
- } else {
- return android::base::StringPrintf("%s%*s\n", name.c_str(),
- (int)size_len, size.c_str());
- }
+ std::string ret = android::base::StringPrintf("%s%*s%*s",
+ name.c_str(),
+ (int)size_len, size.c_str(),
+ (int)drop_len, pruned.c_str());
+ // remove any trailing spaces
+ size_t pos = ret.size();
+ size_t len = 0;
+ while (pos && isspace(ret[--pos])) ++len;
+ if (len) ret.erase(pos + 1, len);
+ return ret + "\n";
}
};
@@ -265,7 +268,7 @@
if (pid != element->getPid()) {
pid = -1;
}
- EntryBase::add(element);
+ EntryBaseDropped::add(element);
}
std::string formatHeader(const std::string &name, log_id_t id) const;
@@ -307,7 +310,7 @@
const char*getName() const { return name; }
inline void add(pid_t newPid) {
- if (name && !fast<strncmp>(name, "zygote", 6)) {
+ if (name && !fastcmp<strncmp>(name, "zygote", 6)) {
free(name);
name = NULL;
}
@@ -368,7 +371,7 @@
const char*getName() const { return name; }
inline void add(pid_t incomingTid) {
- if (name && !fast<strncmp>(name, "zygote", 6)) {
+ if (name && !fastcmp<strncmp>(name, "zygote", 6)) {
free(name);
name = NULL;
}
@@ -419,7 +422,7 @@
if (pid != element->getPid()) {
pid = -1;
}
- EntryBase::add(element);
+ EntryBaseDropped::add(element);
}
std::string formatHeader(const std::string &name, log_id_t id) const;
@@ -472,6 +475,7 @@
size_t mDroppedElements[LOG_ID_MAX];
size_t mSizesTotal[LOG_ID_MAX];
size_t mElementsTotal[LOG_ID_MAX];
+ static size_t SizesTotal;
bool enable;
// uid to size list
@@ -554,6 +558,7 @@
}
size_t sizesTotal(log_id_t id) const { return mSizesTotal[id]; }
size_t elementsTotal(log_id_t id) const { return mElementsTotal[id]; }
+ static size_t sizesTotal() { return SizesTotal; }
std::string format(uid_t uid, pid_t pid, unsigned int logMask) const;
diff --git a/logd/LogUtils.h b/logd/LogUtils.h
index 44ac742..70f24e4 100644
--- a/logd/LogUtils.h
+++ b/logd/LogUtils.h
@@ -20,6 +20,7 @@
#include <sys/cdefs.h>
#include <sys/types.h>
+#include <utils/FastStrcmp.h>
#include <private/android_logger.h>
#include <sysutils/SocketClient.h>
@@ -32,13 +33,18 @@
char *uidToName(uid_t uid);
void prdebug(const char *fmt, ...) __printflike(1, 2);
-// Furnished in LogStatistics.cpp. Caller must own and free returned value
+// Furnished in LogStatistics.cpp.
+size_t sizesTotal();
+// Caller must own and free returned value
char *pidToName(pid_t pid);
char *tidToName(pid_t tid);
// Furnished in main.cpp. Thread safe.
const char *tagToName(size_t *len, uint32_t tag);
+// Furnished by LogKlog.cpp.
+const char* strnstr(const char* s, size_t len, const char* needle);
+
}
// Furnished in LogCommand.cpp
@@ -50,21 +56,4 @@
(id == LOG_ID_RADIO) || (id == LOG_ID_EVENTS);
}
-template <int (*cmp)(const char *l, const char *r, const size_t s)>
-static inline int fast(const char *l, const char *r, const size_t s) {
- return (*l != *r) || cmp(l + 1, r + 1, s - 1);
-}
-
-template <int (*cmp)(const void *l, const void *r, const size_t s)>
-static inline int fast(const void *lv, const void *rv, const size_t s) {
- const char *l = static_cast<const char *>(lv);
- const char *r = static_cast<const char *>(rv);
- return (*l != *r) || cmp(l + 1, r + 1, s - 1);
-}
-
-template <int (*cmp)(const char *l, const char *r)>
-static inline int fast(const char *l, const char *r) {
- return (*l != *r) || cmp(l + 1, r + 1);
-}
-
#endif // _LOGD_LOG_UTILS_H__
diff --git a/logd/README.property b/logd/README.property
index 791b1d5..de6767a 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -2,8 +2,9 @@
name type default description
ro.logd.auditd bool true Enable selinux audit daemon
-ro.logd.auditd.dmesg bool true selinux audit messages duplicated and
- sent on to dmesg log
+ro.logd.auditd.dmesg bool true selinux audit messages sent to dmesg.
+ro.logd.auditd.main bool true selinux audit messages sent to main.
+ro.logd.auditd.events bool true selinux audit messages sent to events.
persist.logd.security bool false Enable security buffer.
ro.device_owner bool false Override persist.logd.security to false
ro.logd.kernel bool+ svelte+ Enable klogd daemon
diff --git a/logd/libaudit.c b/logd/libaudit.c
index d2b212e..216f1a1 100644
--- a/logd/libaudit.c
+++ b/logd/libaudit.c
@@ -149,7 +149,7 @@
return rc;
}
-int audit_setup(int fd, uint32_t pid)
+int audit_setup(int fd, pid_t pid)
{
int rc;
struct audit_message rep;
@@ -163,8 +163,7 @@
* and the the mask set to AUDIT_STATUS_PID
*/
status.pid = pid;
- status.mask = AUDIT_STATUS_PID | AUDIT_STATUS_RATE_LIMIT;
- status.rate_limit = 20; // audit entries per second
+ status.mask = AUDIT_STATUS_PID;
/* Let the kernel know this pid will be registering for audit events */
rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
@@ -187,6 +186,27 @@
return 0;
}
+int audit_rate_limit(int fd, unsigned rate_limit)
+{
+ int rc;
+ struct audit_message rep;
+ struct audit_status status;
+
+ memset(&status, 0, sizeof(status));
+
+ status.mask = AUDIT_STATUS_RATE_LIMIT;
+ status.rate_limit = rate_limit; /* audit entries per second */
+
+ rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
+ if (rc < 0) {
+ return rc;
+ }
+
+ audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0);
+
+ return 0;
+}
+
int audit_open()
{
return socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_AUDIT);
diff --git a/logd/libaudit.h b/logd/libaudit.h
index b9e330d..9865d43 100644
--- a/logd/libaudit.h
+++ b/logd/libaudit.h
@@ -33,7 +33,7 @@
#define MAX_AUDIT_MESSAGE_LENGTH 8970
typedef enum {
- GET_REPLY_BLOCKING=0,
+ GET_REPLY_BLOCKING = 0,
GET_REPLY_NONBLOCKING
} reply_t;
@@ -55,7 +55,7 @@
* A valid fd on success or < 0 on error with errno set.
* Returns the same errors as man 2 socket.
*/
-extern int audit_open(void);
+extern int audit_open(void);
/**
* Closes the fd returned from audit_open()
@@ -78,19 +78,36 @@
* @return
* This function returns 0 on success, else -errno.
*/
-extern int audit_get_reply(int fd, struct audit_message *rep, reply_t block,
- int peek);
+extern int audit_get_reply(int fd, struct audit_message *rep, reply_t block,
+ int peek);
/**
- * Sets a pid to recieve audit netlink events from the kernel
+ * Sets a pid to receive audit netlink events from the kernel
* @param fd
* The fd returned by a call to audit_open()
* @param pid
- * The pid whom to set as the reciever of audit messages
+ * The pid whom to set as the receiver of audit messages
* @return
* This function returns 0 on success, -errno on error.
*/
-extern int audit_setup(int fd, uint32_t pid);
+extern int audit_setup(int fd, pid_t pid);
+
+/**
+ * Sets the rate limit to receive audit netlink events from the kernel
+ * @param fd
+ * The fd returned by a call to audit_open()
+ * @param max_rate
+ * The cap of the maximum number of audit messages a second
+ * @return
+ * This function returns 0 on success, -errno on error.
+ */
+
+/* Guidelines to follow for dynamic rate_limit */
+#define AUDIT_RATE_LIMIT_DEFAULT 20 /* acceptable burst rate */
+#define AUDIT_RATE_LIMIT_BURST_DURATION 10 /* number of seconds of burst */
+#define AUDIT_RATE_LIMIT_MAX 5 /* acceptable sustained rate */
+
+extern int audit_rate_limit(int fd, unsigned rate_limit);
__END_DECLS
diff --git a/logd/main.cpp b/logd/main.cpp
index c3343d7..5878f15 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -451,9 +451,8 @@
pthread_attr_destroy(&attr);
}
- bool auditd = __android_logger_property_get_bool("logd.auditd",
- BOOL_DEFAULT_TRUE |
- BOOL_DEFAULT_FLAG_PERSIST);
+ bool auditd = __android_logger_property_get_bool("ro.logd.auditd",
+ BOOL_DEFAULT_TRUE);
if (drop_privs(klogd, auditd) != 0) {
return -1;
}
@@ -513,8 +512,8 @@
if (auditd) {
al = new LogAudit(logBuf, reader,
__android_logger_property_get_bool(
- "logd.auditd.dmesg",
- BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST)
+ "ro.logd.auditd.dmesg",
+ BOOL_DEFAULT_TRUE)
? fdDmesg
: -1);
}
diff --git a/logd/tests/Android.mk b/logd/tests/Android.mk
index 808087a..c053993 100644
--- a/logd/tests/Android.mk
+++ b/logd/tests/Android.mk
@@ -27,12 +27,15 @@
# Unit tests.
# -----------------------------------------------------------------------------
+event_flag := -DAUDITD_LOG_TAG=1003 -DCHATTY_LOG_TAG=1004
+
test_c_flags := \
-fstack-protector-all \
-g \
-Wall -Wextra \
-Werror \
-fno-builtin \
+ $(event_flag)
test_src_files := \
logd_test.cpp
@@ -43,6 +46,6 @@
LOCAL_MODULE := $(test_module_prefix)unit-tests
LOCAL_MODULE_TAGS := $(test_tags)
LOCAL_CFLAGS += $(test_c_flags)
-LOCAL_SHARED_LIBRARIES := libbase libcutils liblog
+LOCAL_SHARED_LIBRARIES := libbase libcutils liblog libselinux
LOCAL_SRC_FILES := $(test_src_files)
include $(BUILD_NATIVE_TEST)
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 254a3f8..703c0fb 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -20,6 +20,9 @@
#include <signal.h>
#include <stdio.h>
#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
#include <string>
@@ -28,7 +31,12 @@
#include <cutils/sockets.h>
#include <gtest/gtest.h>
#include <log/log.h>
+#include <private/android_filesystem_config.h>
+#ifdef __ANDROID__
+#include <selinux/selinux.h>
+#endif
+#include "../libaudit.h" // pickup AUDIT_RATE_LIMIT_*
#include "../LogReader.h" // pickup LOGD_SNDTIMEO
/*
@@ -415,7 +423,13 @@
// Introduce some extreme spam for the worst UID filter
ASSERT_TRUE(NULL != (fp = popen(
- "/data/nativetest/liblog-benchmarks/liblog-benchmarks",
+ "/data/nativetest/liblog-benchmarks/liblog-benchmarks"
+ " BM_log_maximum_retry"
+ " BM_log_maximum"
+ " BM_clock_overhead"
+ " BM_log_overhead"
+ " BM_log_latency"
+ " BM_log_delay",
"r")));
char buffer[5120];
@@ -581,10 +595,12 @@
continue;
}
+ // alarm triggers at 50% of the --wrap time out
content_wrap = recv(fd, msg_wrap.buf, sizeof(msg_wrap), 0) > 0;
alarm_wrap = alarm(5);
+ // alarm triggers at 133% of the --wrap time out
content_timeout = recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
if (!content_timeout) { // make sure we hit dumpAndClose
content_timeout = recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
@@ -629,11 +645,24 @@
// b/26447386 refined behavior
TEST(logd, timeout) {
+ // b/33962045 This test interferes with other log reader tests that
+ // follow because of file descriptor socket persistence in the same
+ // process. So let's fork it to isolate it from giving us pain.
+
+ pid_t pid = fork();
+
+ if (pid) {
+ siginfo_t info = {};
+ ASSERT_EQ(0, TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, WEXITED)));
+ ASSERT_EQ(0, info.si_status);
+ return;
+ }
+
log_msg msg_wrap, msg_timeout;
bool content_wrap = false, content_timeout = false, written = false;
unsigned int alarm_wrap = 0, alarm_timeout = 0;
// A few tries to get it right just in case wrap kicks in due to
- // content providers being active during the test
+ // content providers being active during the test.
int i = 5;
log_time now(android_log_clockid());
now.tv_sec -= 30; // reach back a moderate period of time
@@ -642,7 +671,8 @@
int fd = socket_local_client("logdr",
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_SEQPACKET);
- ASSERT_LT(0, fd);
+ EXPECT_LT(0, fd);
+ if (fd < 0) _exit(fd);
std::string ask = android::base::StringPrintf(
"dumpAndClose lids=0,1,2,3,4,5 timeout=6 start=%"
@@ -665,10 +695,12 @@
continue;
}
+ // alarm triggers at 50% of the --wrap time out
content_wrap = recv(fd, msg_wrap.buf, sizeof(msg_wrap), 0) > 0;
alarm_wrap = alarm(5);
+ // alarm triggers at 133% of the --wrap time out
content_timeout = recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
if (!content_timeout) { // make sure we hit dumpAndClose
content_timeout = recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
@@ -692,6 +724,7 @@
if (content_timeout) {
log_time msg(msg_timeout.entry.sec, msg_timeout.entry.nsec);
EXPECT_FALSE(msg < now);
+ if (msg < now) _exit(-1);
if (msg > now) {
now = msg;
now.tv_sec += 30;
@@ -724,6 +757,8 @@
EXPECT_EQ(0U, alarm_wrap);
EXPECT_TRUE(content_timeout);
EXPECT_NE(0U, alarm_timeout);
+
+ _exit(!written + content_wrap + alarm_wrap + !content_timeout + !alarm_timeout);
}
// b/27242723 confirmed fixed
@@ -778,3 +813,257 @@
close(fd);
}
+
+static inline int32_t get4LE(const char* src)
+{
+ return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+}
+
+void __android_log_btwrite_multiple__helper(int count) {
+ log_time ts(CLOCK_MONOTONIC);
+
+ log_time ts1(CLOCK_MONOTONIC);
+
+ // We fork to create a unique pid for the submitted log messages
+ // so that we do not collide with the other _multiple_ tests.
+
+ pid_t pid = fork();
+
+ if (pid == 0) {
+ // child
+ for (int i = count; i; --i) {
+ ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
+ usleep(100);
+ }
+ ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1)));
+ usleep(1000000);
+
+ _exit(0);
+ }
+
+ siginfo_t info = {};
+ ASSERT_EQ(0, TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, WEXITED)));
+ ASSERT_EQ(0, info.si_status);
+
+ struct logger_list *logger_list;
+ ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, pid)));
+
+ int expected_count = (count < 2) ? count : 2;
+ int expected_chatty_count = (count <= 2) ? 0 : 1;
+ int expected_expire_count = (count < 2) ? 0 : (count - 2);
+
+ count = 0;
+ int second_count = 0;
+ int chatty_count = 0;
+ int expire_count = 0;
+
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) break;
+
+ if ((log_msg.entry.pid != pid) ||
+ (log_msg.entry.len < (4 + 1 + 8)) ||
+ (log_msg.id() != LOG_ID_EVENTS)) continue;
+
+ char *eventData = log_msg.msg();
+ if (!eventData) continue;
+
+ uint32_t tag = get4LE(eventData);
+
+ if ((eventData[4] == EVENT_TYPE_LONG) && (log_msg.entry.len == (4 + 1 + 8))) {
+ if (tag != 0) continue;
+
+ log_time tx(eventData + 4 + 1);
+ if (ts == tx) {
+ ++count;
+ } else if (ts1 == tx) {
+ ++second_count;
+ }
+ } else if (eventData[4] == EVENT_TYPE_STRING) {
+ if (tag != CHATTY_LOG_TAG) continue;
+ ++chatty_count;
+ // int len = get4LE(eventData + 4 + 1);
+ log_msg.buf[LOGGER_ENTRY_MAX_LEN] = '\0';
+ const char *cp = strstr(eventData + 4 + 1 + 4, " expire ");
+ if (!cp) continue;
+ unsigned val = 0;
+ sscanf(cp, " expire %u lines", &val);
+ expire_count += val;
+ }
+ }
+
+ android_logger_list_close(logger_list);
+
+ EXPECT_EQ(expected_count, count);
+ EXPECT_EQ(1, second_count);
+ EXPECT_EQ(expected_chatty_count, chatty_count);
+ EXPECT_EQ(expected_expire_count, expire_count);
+}
+
+TEST(logd, multiple_test_1) {
+ __android_log_btwrite_multiple__helper(1);
+}
+
+TEST(logd, multiple_test_2) {
+ __android_log_btwrite_multiple__helper(2);
+}
+
+TEST(logd, multiple_test_3) {
+ __android_log_btwrite_multiple__helper(3);
+}
+
+TEST(logd, multiple_test_10) {
+ __android_log_btwrite_multiple__helper(10);
+}
+
+#ifdef __ANDROID__
+// returns violating pid
+static pid_t sepolicy_rate(unsigned rate, unsigned num) {
+ pid_t pid = fork();
+
+ if (pid) {
+ siginfo_t info = {};
+ if (TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, WEXITED))) return 0;
+ if (info.si_status) return 0;
+ return pid;
+ }
+
+ // We may have DAC, but let's not have MAC
+ if (setcon("u:object_r:shell:s0") < 0) {
+ int save_errno = errno;
+ security_context_t context;
+ getcon(&context);
+ fprintf(stderr, "setcon(\"u:r:shell:s0\") failed @\"%s\" %s\n",
+ context, strerror(save_errno));
+ freecon(context);
+ _exit(-1);
+ // NOTREACHED
+ return 0;
+ }
+
+ // Requests dac_read_search, falls back to request dac_override
+ rate /= 2;
+ useconds_t usec;
+ if (rate == 0) {
+ rate = 1;
+ usec = 2000000;
+ } else {
+ usec = (1000000 + (rate / 2)) / rate;
+ }
+ num = (num + 1) / 2;
+
+ if (usec < 2) usec = 2;
+
+ while (num > 0) {
+ if (access(android::base::StringPrintf(
+ "/data/misc/logd/cannot_access_directory_%u",
+ num).c_str(),
+ F_OK) == 0) {
+ _exit(-1);
+ // NOTREACHED
+ return 0;
+ }
+ usleep(usec);
+ --num;
+ }
+ _exit(0);
+ // NOTREACHED
+ return 0;
+}
+
+static int count_avc(pid_t pid) {
+ int count = 0;
+
+ if (pid == 0) return count;
+
+ struct logger_list *logger_list;
+ if (!(logger_list = android_logger_list_open(LOG_ID_EVENTS,
+ ANDROID_LOG_RDONLY |
+ ANDROID_LOG_NONBLOCK,
+ 0,
+ pid))) return count;
+ for (;;) {
+ log_msg log_msg;
+
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) break;
+
+ if ((log_msg.entry.pid != pid) ||
+ (log_msg.entry.len < (4 + 1 + 8)) ||
+ (log_msg.id() != LOG_ID_EVENTS)) continue;
+
+ char *eventData = log_msg.msg();
+ if (!eventData) continue;
+
+ uint32_t tag = get4LE(eventData);
+ if (tag != AUDITD_LOG_TAG) continue;
+
+ if (eventData[4] != EVENT_TYPE_STRING) continue;
+
+ // int len = get4LE(eventData + 4 + 1);
+ log_msg.buf[LOGGER_ENTRY_MAX_LEN] = '\0';
+ const char *cp = strstr(eventData + 4 + 1 + 4, "): avc: ");
+ if (!cp) continue;
+
+ ++count;
+ }
+
+ android_logger_list_close(logger_list);
+
+ return count;
+}
+#endif
+
+TEST(logd, sepolicy_rate_limiter_maximum) {
+#ifdef __ANDROID__
+ static const int rate = AUDIT_RATE_LIMIT_MAX;
+ static const int duration = 2;
+ // Two seconds of a liveable sustained rate
+ EXPECT_EQ(rate * duration, count_avc(sepolicy_rate(rate, rate * duration)));
+#else
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}
+
+TEST(logd, sepolicy_rate_limiter_sub_burst) {
+#ifdef __ANDROID__
+ // maximum period below half way between sustainable and burst rate.
+ static const int threshold = ((AUDIT_RATE_LIMIT_BURST_DURATION *
+ (AUDIT_RATE_LIMIT_DEFAULT +
+ AUDIT_RATE_LIMIT_MAX)) +
+ 1) / 2;
+ static const int rate = (threshold / AUDIT_RATE_LIMIT_BURST_DURATION) - 1;
+ static const int duration = AUDIT_RATE_LIMIT_BURST_DURATION;
+ EXPECT_EQ(rate * duration, count_avc(sepolicy_rate(rate, rate * duration)));
+#else
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}
+
+TEST(logd, sepolicy_rate_limiter_spam) {
+#ifdef __ANDROID__
+ // maximum period of double the maximum burst rate
+ static const int threshold = ((AUDIT_RATE_LIMIT_BURST_DURATION *
+ (AUDIT_RATE_LIMIT_DEFAULT +
+ AUDIT_RATE_LIMIT_MAX)) +
+ 1) / 2;
+ static const int rate = AUDIT_RATE_LIMIT_DEFAULT * 2;
+ static const int duration = threshold / AUDIT_RATE_LIMIT_DEFAULT;
+ EXPECT_GE(((AUDIT_RATE_LIMIT_DEFAULT * duration) * 115) /
+ 100, // +15% margin
+ count_avc(sepolicy_rate(rate, rate * duration)));
+ // give logd another 3 seconds to react to the burst before checking
+ sepolicy_rate(rate, rate * 3);
+ // maximum period at double the maximum burst rate (spam filter kicked in)
+ EXPECT_GE(((AUDIT_RATE_LIMIT_MAX * AUDIT_RATE_LIMIT_BURST_DURATION) * 130) /
+ 100, // +30% margin
+ count_avc(sepolicy_rate(rate,
+ rate * AUDIT_RATE_LIMIT_BURST_DURATION)));
+ // cool down, and check unspammy rate still works
+ sleep(2);
+ EXPECT_LE(AUDIT_RATE_LIMIT_BURST_DURATION - 1, // allow _one_ to be lost
+ count_avc(sepolicy_rate(1, AUDIT_RATE_LIMIT_BURST_DURATION)));
+#else
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 8903255..c0a0fce 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -125,6 +125,12 @@
write /proc/sys/kernel/sched_rt_runtime_us 950000
write /proc/sys/kernel/sched_rt_period_us 1000000
+ # Assign reasonable ceiling values for socket rcv/snd buffers.
+ # These should almost always be overridden by the target per the
+ # the corresponding technology maximums.
+ write /proc/sys/net/core/rmem_max 262144
+ write /proc/sys/net/core/wmem_max 262144
+
# reflect fwmark from incoming packets onto generated replies
write /proc/sys/net/ipv4/fwmark_reflect 1
write /proc/sys/net/ipv6/fwmark_reflect 1
@@ -360,7 +366,7 @@
# Start bootcharting as soon as possible after the data partition is
# mounted to collect more data.
mkdir /data/bootchart 0755 shell shell
- bootchart_init
+ bootchart start
# Avoid predictable entropy pool. Carry over entropy from previous boot.
copy /data/system/entropy.dat /dev/urandom
@@ -618,6 +624,9 @@
on property:sys.powerctl=*
powerctl ${sys.powerctl}
+on property:sys.boot_completed=1
+ bootchart stop
+
# system server cannot write to /proc/sys files,
# and chown/chmod does not work for /proc/sys/ entries.
# So proxy writes through init.
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index eedeba8..d836c4e 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -10,4 +10,5 @@
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
+ onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index 84a907f..ed11164 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -10,6 +10,7 @@
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
+ onrestart restart wificond
writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index 76e2b79..05ec16f 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -10,4 +10,5 @@
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
+ onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index e918b67..66e7750 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -10,6 +10,7 @@
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
+ onrestart restart wificond
writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
diff --git a/run-as/run-as.cpp b/run-as/run-as.cpp
index aec51f4..e7b8cc2 100644
--- a/run-as/run-as.cpp
+++ b/run-as/run-as.cpp
@@ -165,12 +165,12 @@
if (setegid(old_egid) == -1) error(1, errno, "couldn't restore egid");
// Verify that user id is not too big.
- if ((UID_MAX - info.uid) / AID_USER < (uid_t)userId) {
+ if ((UID_MAX - info.uid) / AID_USER_OFFSET < (uid_t)userId) {
error(1, 0, "user id too big: %d", userId);
}
// Calculate user app ID.
- uid_t userAppId = (AID_USER * userId) + info.uid;
+ uid_t userAppId = (AID_USER_OFFSET * userId) + info.uid;
// Reject system packages.
if (userAppId < AID_APP) {