Merge "init: Use android::base::boot_clock instead of /proc/uptime"
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 65fa2e7..4fbfafb 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -257,7 +257,7 @@
<< connection_str.length() << ")";
}
- cp->payload = std::move(connection_str);
+ cp->payload.assign(connection_str.begin(), connection_str.end());
cp->msg.data_length = cp->payload.size();
send_packet(cp, t);
@@ -329,7 +329,8 @@
handle_offline(t);
t->update_version(p->msg.arg0, p->msg.arg1);
- parse_banner(p->payload, t);
+ std::string banner(p->payload.begin(), p->payload.end());
+ parse_banner(banner, t);
#if ADB_HOST
handle_online(t);
@@ -369,8 +370,10 @@
send_auth_response(p->payload.data(), p->msg.data_length, t);
break;
#else
- case ADB_AUTH_SIGNATURE:
- if (adbd_auth_verify(t->token, sizeof(t->token), p->payload)) {
+ case ADB_AUTH_SIGNATURE: {
+ // TODO: Switch to string_view.
+ std::string signature(p->payload.begin(), p->payload.end());
+ if (adbd_auth_verify(t->token, sizeof(t->token), signature)) {
adbd_auth_verified(t);
t->failed_auth_attempts = 0;
} else {
@@ -378,6 +381,7 @@
send_auth_request(t);
}
break;
+ }
case ADB_AUTH_RSAPUBLICKEY:
adbd_auth_confirm_key(p->payload.data(), p->msg.data_length, t);
@@ -392,7 +396,9 @@
case A_OPEN: /* OPEN(local-id, 0, "destination") */
if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) {
- asocket* s = create_local_service_socket(p->payload.c_str(), t);
+ // TODO: Switch to string_view.
+ std::string address(p->payload.begin(), p->payload.end());
+ asocket* s = create_local_service_socket(address.c_str(), t);
if (s == nullptr) {
send_close(0, p->msg.arg0, t);
} else {
@@ -927,8 +933,7 @@
// Try to handle a network forwarding request.
// This returns 1 on success, 0 on failure, and -1 to indicate this is not
// a forwarding-related request.
-int handle_forward_request(const char* service, TransportType type, const char* serial,
- TransportId transport_id, int reply_fd) {
+int handle_forward_request(const char* service, atransport* transport, int reply_fd) {
if (!strcmp(service, "list-forward")) {
// Create the list of forward redirections.
std::string listeners = format_listeners();
@@ -980,14 +985,6 @@
}
}
- std::string error_msg;
- atransport* transport =
- acquire_one_transport(type, serial, transport_id, nullptr, &error_msg);
- if (!transport) {
- SendFail(reply_fd, error_msg);
- return 1;
- }
-
std::string error;
InstallStatus r;
int resolved_tcp_port = 0;
@@ -1221,7 +1218,13 @@
return SendOkay(reply_fd, response);
}
- int ret = handle_forward_request(service, type, serial, transport_id, reply_fd);
+ std::string error;
+ atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &error);
+ if (!t) {
+ return SendFail(reply_fd, error);
+ }
+
+ int ret = handle_forward_request(service, t, reply_fd);
if (ret >= 0)
return ret - 1;
return -1;
diff --git a/adb/adb.h b/adb/adb.h
index c74fa99..1e58ee1 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -28,6 +28,7 @@
#include "adb_trace.h"
#include "fdevent.h"
#include "socket.h"
+#include "types.h"
#include "usb.h"
constexpr size_t MAX_PAYLOAD_V1 = 4 * 1024;
@@ -63,20 +64,6 @@
using TransportId = uint64_t;
class atransport;
-struct amessage {
- uint32_t command; /* command identifier constant */
- uint32_t arg0; /* first argument */
- uint32_t arg1; /* second argument */
- uint32_t data_length; /* length of payload (0 is allowed) */
- uint32_t data_check; /* checksum of data payload */
- uint32_t magic; /* command ^ 0xffffffff */
-};
-
-struct apacket {
- amessage msg;
- std::string payload;
-};
-
uint32_t calculate_apacket_checksum(const apacket* packet);
/* the adisconnect structure is used to record a callback that
@@ -140,7 +127,7 @@
atransport* find_emulator_transport_by_console_port(int console_port);
#endif
-int service_to_fd(const char* name, const atransport* transport);
+int service_to_fd(const char* name, atransport* transport);
#if ADB_HOST
asocket* host_service_to_socket(const char* name, const char* serial, TransportId transport_id);
#endif
@@ -152,8 +139,7 @@
int create_jdwp_connection_fd(int jdwp_pid);
#endif
-int handle_forward_request(const char* service, TransportType type, const char* serial,
- TransportId transport_id, int reply_fd);
+int handle_forward_request(const char* service, atransport* transport, int reply_fd);
#if !ADB_HOST
void framebuffer_service(int fd, void* cookie);
diff --git a/adb/client/auth.cpp b/adb/client/auth.cpp
index c3aef16..ade2623 100644
--- a/adb/client/auth.cpp
+++ b/adb/client/auth.cpp
@@ -454,10 +454,8 @@
p->msg.command = A_AUTH;
p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
- p->payload = std::move(key);
-
// adbd expects a null-terminated string.
- p->payload.push_back('\0');
+ p->payload.assign(key.data(), key.data() + key.size() + 1);
p->msg.data_length = p->payload.size();
send_packet(p, t);
}
@@ -482,7 +480,7 @@
p->msg.command = A_AUTH;
p->msg.arg0 = ADB_AUTH_SIGNATURE;
- p->payload = std::move(result);
+ p->payload.assign(result.begin(), result.end());
p->msg.data_length = p->payload.size();
send_packet(p, t);
}
diff --git a/adb/daemon/jdwp_service.cpp b/adb/daemon/jdwp_service.cpp
index 9761558..89577cb 100644
--- a/adb/daemon/jdwp_service.cpp
+++ b/adb/daemon/jdwp_service.cpp
@@ -459,7 +459,7 @@
delete s;
}
-static int jdwp_socket_enqueue(asocket* s, std::string) {
+static int jdwp_socket_enqueue(asocket* s, apacket::payload_type) {
/* you can't write to this asocket */
D("LS(%d): JDWP socket received data?", s->id);
s->peer->close(s->peer);
@@ -474,7 +474,7 @@
* on the second one, close the connection
*/
if (!jdwp->pass) {
- std::string data;
+ apacket::payload_type data;
data.resize(s->get_max_payload());
size_t len = jdwp_process_list(&data[0], data.size());
data.resize(len);
@@ -521,7 +521,8 @@
for (auto& t : _jdwp_trackers) {
if (t->peer) {
// The tracker might not have been connected yet.
- t->peer->enqueue(t->peer, data);
+ apacket::payload_type payload(data.begin(), data.end());
+ t->peer->enqueue(t->peer, std::move(payload));
}
}
}
@@ -547,7 +548,7 @@
JdwpTracker* t = (JdwpTracker*)s;
if (t->need_initial) {
- std::string data;
+ apacket::payload_type data;
data.resize(s->get_max_payload());
data.resize(jdwp_process_list_msg(&data[0], data.size()));
t->need_initial = false;
@@ -555,7 +556,7 @@
}
}
-static int jdwp_tracker_enqueue(asocket* s, std::string) {
+static int jdwp_tracker_enqueue(asocket* s, apacket::payload_type) {
/* you can't write to this socket */
D("LS(%d): JDWP tracker received data?", s->id);
s->peer->close(s->peer);
diff --git a/adb/range.h b/adb/range.h
deleted file mode 100644
index 7a0b822..0000000
--- a/adb/range.h
+++ /dev/null
@@ -1,65 +0,0 @@
-#pragma once
-
-/*
- * Copyright (C) 2018 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 <string>
-
-#include <android-base/logging.h>
-
-struct Range {
- explicit Range(std::string data) : data_(std::move(data)) {}
-
- Range(const Range& copy) = delete;
- Range& operator=(const Range& copy) = delete;
-
- Range(Range&& move) = default;
- Range& operator=(Range&& move) = default;
-
- bool empty() const {
- return size() == 0;
- }
-
- size_t size() const {
- return data_.size() - begin_offset_ - end_offset_;
- };
-
- void drop_front(size_t n) {
- CHECK_GE(size(), n);
- begin_offset_ += n;
- }
-
- void drop_end(size_t n) {
- CHECK_GE(size(), n);
- end_offset_ += n;
- }
-
- char* data() {
- return &data_[0] + begin_offset_;
- }
-
- std::string::iterator begin() {
- return data_.begin() + begin_offset_;
- }
-
- std::string::iterator end() {
- return data_.end() - end_offset_;
- }
-
- std::string data_;
- size_t begin_offset_ = 0;
- size_t end_offset_ = 0;
-};
diff --git a/adb/services.cpp b/adb/services.cpp
index fe74eb6..0b0c161 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -181,14 +181,14 @@
kick_transport(t);
}
-int reverse_service(const char* command) {
+int reverse_service(const char* command, atransport* transport) {
int s[2];
if (adb_socketpair(s)) {
PLOG(ERROR) << "cannot create service socket pair.";
return -1;
}
VLOG(SERVICES) << "service socketpair: " << s[0] << ", " << s[1];
- if (handle_forward_request(command, kTransportAny, nullptr, 0, s[1]) < 0) {
+ if (handle_forward_request(command, transport, s[1]) < 0) {
SendFail(s[1], "not a reverse forwarding command");
}
adb_close(s[1]);
@@ -268,7 +268,7 @@
return s[0];
}
-int service_to_fd(const char* name, const atransport* transport) {
+int service_to_fd(const char* name, atransport* transport) {
int ret = -1;
if (is_socket_spec(name)) {
@@ -317,7 +317,7 @@
} else if(!strncmp(name, "usb:", 4)) {
ret = create_service_thread("usb", restart_usb_service, nullptr);
} else if (!strncmp(name, "reverse:", 8)) {
- ret = reverse_service(name + 8);
+ ret = reverse_service(name + 8, transport);
} else if(!strncmp(name, "disable-verity:", 15)) {
ret = create_service_thread("verity-on", set_verity_enabled_state_service,
reinterpret_cast<void*>(0));
@@ -325,8 +325,7 @@
ret = create_service_thread("verity-off", set_verity_enabled_state_service,
reinterpret_cast<void*>(1));
} else if (!strcmp(name, "reconnect")) {
- ret = create_service_thread("reconnect", reconnect_service,
- const_cast<atransport*>(transport));
+ ret = create_service_thread("reconnect", reconnect_service, transport);
#endif
}
if (ret >= 0) {
diff --git a/adb/socket.h b/adb/socket.h
index 2f09080..e0fd87f 100644
--- a/adb/socket.h
+++ b/adb/socket.h
@@ -24,9 +24,8 @@
#include <string>
#include "fdevent.h"
-#include "range.h"
+#include "types.h"
-struct apacket;
class atransport;
/* An asocket represents one half of a connection between a local and
@@ -73,7 +72,7 @@
* peer->ready() when we once again are ready to
* receive data.
*/
- int (*enqueue)(asocket* s, std::string data) = nullptr;
+ int (*enqueue)(asocket* s, apacket::payload_type data) = nullptr;
/* ready is called by the peer when it is ready for
* us to send data via enqueue again
@@ -104,8 +103,7 @@
void close_all_sockets(atransport *t);
asocket *create_local_socket(int fd);
-asocket *create_local_service_socket(const char* destination,
- const atransport* transport);
+asocket* create_local_service_socket(const char* destination, atransport* transport);
asocket *create_remote_socket(unsigned id, atransport *t);
void connect_to_remote(asocket *s, const char *destination);
diff --git a/adb/socket_test.cpp b/adb/socket_test.cpp
index 6c4a8b2..04214a2 100644
--- a/adb/socket_test.cpp
+++ b/adb/socket_test.cpp
@@ -118,7 +118,7 @@
// each write to give the underlying implementation time to flush.
bool socket_filled = false;
for (int i = 0; i < 128; ++i) {
- std::string data;
+ apacket::payload_type data;
data.resize(MAX_PAYLOAD);
arg->bytes_written += data.size();
int ret = s->enqueue(s, std::move(data));
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 0887e6f..7bc0165 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -37,8 +37,8 @@
#include "adb.h"
#include "adb_io.h"
-#include "range.h"
#include "transport.h"
+#include "types.h"
static std::recursive_mutex& local_socket_list_lock = *new std::recursive_mutex();
static unsigned local_socket_next_id = 1;
@@ -147,7 +147,7 @@
// Returns false if the socket has been closed and destroyed as a side-effect of this function.
static bool local_socket_flush_outgoing(asocket* s) {
const size_t max_payload = s->get_max_payload();
- std::string data;
+ apacket::payload_type data;
data.resize(max_payload);
char* x = &data[0];
size_t avail = max_payload;
@@ -214,7 +214,7 @@
return true;
}
-static int local_socket_enqueue(asocket* s, std::string data) {
+static int local_socket_enqueue(asocket* s, apacket::payload_type data) {
D("LS(%d): enqueue %zu", s->id, data.size());
Range r(std::move(data));
@@ -348,7 +348,7 @@
return s;
}
-asocket* create_local_service_socket(const char* name, const atransport* transport) {
+asocket* create_local_service_socket(const char* name, atransport* transport) {
#if !ADB_HOST
if (!strcmp(name, "jdwp")) {
return create_jdwp_service_socket();
@@ -394,7 +394,7 @@
}
#endif /* ADB_HOST */
-static int remote_socket_enqueue(asocket* s, std::string data) {
+static int remote_socket_enqueue(asocket* s, apacket::payload_type data) {
D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d", s->id, s->fd, s->peer->fd);
apacket* p = get_apacket();
@@ -476,8 +476,7 @@
p->msg.arg0 = s->id;
// adbd expects a null-terminated string.
- p->payload = destination;
- p->payload.push_back('\0');
+ p->payload.assign(destination, destination + strlen(destination) + 1);
p->msg.data_length = p->payload.size();
if (p->msg.data_length > s->get_max_payload()) {
@@ -612,7 +611,7 @@
#endif // ADB_HOST
-static int smart_socket_enqueue(asocket* s, std::string data) {
+static int smart_socket_enqueue(asocket* s, apacket::payload_type data) {
#if ADB_HOST
char* service = nullptr;
char* serial = nullptr;
@@ -623,7 +622,8 @@
D("SS(%d): enqueue %zu", s->id, data.size());
if (s->smart_socket_data.empty()) {
- s->smart_socket_data = std::move(data);
+ // TODO: Make this a BlockChain?
+ s->smart_socket_data.assign(data.begin(), data.end());
} else {
std::copy(data.begin(), data.end(), std::back_inserter(s->smart_socket_data));
}
diff --git a/adb/sysdeps/uio.h b/adb/sysdeps/uio.h
new file mode 100644
index 0000000..d06ef89
--- /dev/null
+++ b/adb/sysdeps/uio.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include <sys/types.h>
+
+#if defined(_WIN32)
+
+// Layout of this struct must match struct WSABUF (verified via static assert in sysdeps_win32.cpp)
+struct adb_iovec {
+ size_t iov_len;
+ void* iov_base;
+};
+
+ssize_t adb_writev(int fd, const adb_iovec* iov, int iovcnt);
+
+#else
+
+#include <sys/uio.h>
+using adb_iovec = struct iovec;
+#define adb_writev writev
+
+#endif
+
+#pragma GCC poison writev
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index 7d35fb6..bfac342 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -36,6 +36,7 @@
#include <android-base/errors.h>
#include <android-base/logging.h>
+#include <android-base/macros.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/utf8.h>
@@ -43,6 +44,8 @@
#include "adb.h"
#include "adb_utils.h"
+#include "sysdeps/uio.h"
+
extern void fatal(const char *fmt, ...);
/* forward declarations */
@@ -57,6 +60,7 @@
int (*_fh_lseek)(FH, int, int);
int (*_fh_read)(FH, void*, int);
int (*_fh_write)(FH, const void*, int);
+ int (*_fh_writev)(FH, const adb_iovec*, int);
} FHClassRec;
static void _fh_file_init(FH);
@@ -64,6 +68,7 @@
static int _fh_file_lseek(FH, int, int);
static int _fh_file_read(FH, void*, int);
static int _fh_file_write(FH, const void*, int);
+static int _fh_file_writev(FH, const adb_iovec*, int);
static const FHClassRec _fh_file_class = {
_fh_file_init,
@@ -71,6 +76,7 @@
_fh_file_lseek,
_fh_file_read,
_fh_file_write,
+ _fh_file_writev,
};
static void _fh_socket_init(FH);
@@ -78,6 +84,7 @@
static int _fh_socket_lseek(FH, int, int);
static int _fh_socket_read(FH, void*, int);
static int _fh_socket_write(FH, const void*, int);
+static int _fh_socket_writev(FH, const adb_iovec*, int);
static const FHClassRec _fh_socket_class = {
_fh_socket_init,
@@ -85,6 +92,7 @@
_fh_socket_lseek,
_fh_socket_read,
_fh_socket_write,
+ _fh_socket_writev,
};
#define assert(cond) \
@@ -248,57 +256,88 @@
/**************************************************************************/
/**************************************************************************/
-static void _fh_file_init( FH f ) {
+static void _fh_file_init(FH f) {
f->fh_handle = INVALID_HANDLE_VALUE;
}
-static int _fh_file_close( FH f ) {
- CloseHandle( f->fh_handle );
+static int _fh_file_close(FH f) {
+ CloseHandle(f->fh_handle);
f->fh_handle = INVALID_HANDLE_VALUE;
return 0;
}
-static int _fh_file_read( FH f, void* buf, int len ) {
- DWORD read_bytes;
+static int _fh_file_read(FH f, void* buf, int len) {
+ DWORD read_bytes;
- if ( !ReadFile( f->fh_handle, buf, (DWORD)len, &read_bytes, NULL ) ) {
- D( "adb_read: could not read %d bytes from %s", len, f->name );
+ if (!ReadFile(f->fh_handle, buf, (DWORD)len, &read_bytes, NULL)) {
+ D("adb_read: could not read %d bytes from %s", len, f->name);
errno = EIO;
return -1;
} else if (read_bytes < (DWORD)len) {
f->eof = 1;
}
- return (int)read_bytes;
+ return read_bytes;
}
-static int _fh_file_write( FH f, const void* buf, int len ) {
- DWORD wrote_bytes;
+static int _fh_file_write(FH f, const void* buf, int len) {
+ DWORD wrote_bytes;
- if ( !WriteFile( f->fh_handle, buf, (DWORD)len, &wrote_bytes, NULL ) ) {
- D( "adb_file_write: could not write %d bytes from %s", len, f->name );
+ if (!WriteFile(f->fh_handle, buf, (DWORD)len, &wrote_bytes, NULL)) {
+ D("adb_file_write: could not write %d bytes from %s", len, f->name);
errno = EIO;
return -1;
} else if (wrote_bytes < (DWORD)len) {
f->eof = 1;
}
- return (int)wrote_bytes;
+ return wrote_bytes;
}
-static int _fh_file_lseek( FH f, int pos, int origin ) {
- DWORD method;
- DWORD result;
+static int _fh_file_writev(FH f, const adb_iovec* iov, int iovcnt) {
+ if (iovcnt <= 0) {
+ errno = EINVAL;
+ return -1;
+ }
- switch (origin)
- {
- case SEEK_SET: method = FILE_BEGIN; break;
- case SEEK_CUR: method = FILE_CURRENT; break;
- case SEEK_END: method = FILE_END; break;
+ DWORD wrote_bytes = 0;
+
+ for (int i = 0; i < iovcnt; ++i) {
+ ssize_t rc = _fh_file_write(f, iov[i].iov_base, iov[i].iov_len);
+ if (rc == -1) {
+ return wrote_bytes > 0 ? wrote_bytes : -1;
+ } else if (rc == 0) {
+ return wrote_bytes;
+ }
+
+ wrote_bytes += rc;
+
+ if (static_cast<size_t>(rc) < iov[i].iov_len) {
+ return wrote_bytes;
+ }
+ }
+
+ return wrote_bytes;
+}
+
+static int _fh_file_lseek(FH f, int pos, int origin) {
+ DWORD method;
+ DWORD result;
+
+ switch (origin) {
+ case SEEK_SET:
+ method = FILE_BEGIN;
+ break;
+ case SEEK_CUR:
+ method = FILE_CURRENT;
+ break;
+ case SEEK_END:
+ method = FILE_END;
+ break;
default:
errno = EINVAL;
return -1;
}
- result = SetFilePointer( f->fh_handle, pos, NULL, method );
+ result = SetFilePointer(f->fh_handle, pos, NULL, method);
if (result == INVALID_SET_FILE_POINTER) {
errno = EIO;
return -1;
@@ -308,7 +347,6 @@
return (int)result;
}
-
/**************************************************************************/
/**************************************************************************/
/***** *****/
@@ -317,12 +355,11 @@
/**************************************************************************/
/**************************************************************************/
-int adb_open(const char* path, int options)
-{
- FH f;
+int adb_open(const char* path, int options) {
+ FH f;
- DWORD desiredAccess = 0;
- DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ DWORD desiredAccess = 0;
+ DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
switch (options) {
case O_RDONLY:
@@ -340,8 +377,8 @@
return -1;
}
- f = _fh_alloc( &_fh_file_class );
- if ( !f ) {
+ f = _fh_alloc(&_fh_file_class);
+ if (!f) {
return -1;
}
@@ -349,21 +386,21 @@
if (!android::base::UTF8ToWide(path, &path_wide)) {
return -1;
}
- f->fh_handle = CreateFileW( path_wide.c_str(), desiredAccess, shareMode,
- NULL, OPEN_EXISTING, 0, NULL );
+ f->fh_handle =
+ CreateFileW(path_wide.c_str(), desiredAccess, shareMode, NULL, OPEN_EXISTING, 0, NULL);
- if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
+ if (f->fh_handle == INVALID_HANDLE_VALUE) {
const DWORD err = GetLastError();
_fh_close(f);
- D( "adb_open: could not open '%s': ", path );
+ D("adb_open: could not open '%s': ", path);
switch (err) {
case ERROR_FILE_NOT_FOUND:
- D( "file not found" );
+ D("file not found");
errno = ENOENT;
return -1;
case ERROR_PATH_NOT_FOUND:
- D( "path not found" );
+ D("path not found");
errno = ENOTDIR;
return -1;
@@ -374,18 +411,17 @@
}
}
- snprintf( f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path );
- D( "adb_open: '%s' => fd %d", path, _fh_to_int(f) );
+ snprintf(f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path);
+ D("adb_open: '%s' => fd %d", path, _fh_to_int(f));
return _fh_to_int(f);
}
/* ignore mode on Win32 */
-int adb_creat(const char* path, int mode)
-{
- FH f;
+int adb_creat(const char* path, int mode) {
+ FH f;
- f = _fh_alloc( &_fh_file_class );
- if ( !f ) {
+ f = _fh_alloc(&_fh_file_class);
+ if (!f) {
return -1;
}
@@ -393,23 +429,21 @@
if (!android::base::UTF8ToWide(path, &path_wide)) {
return -1;
}
- f->fh_handle = CreateFileW( path_wide.c_str(), GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
- NULL );
+ f->fh_handle = CreateFileW(path_wide.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
+ if (f->fh_handle == INVALID_HANDLE_VALUE) {
const DWORD err = GetLastError();
_fh_close(f);
- D( "adb_creat: could not open '%s': ", path );
+ D("adb_creat: could not open '%s': ", path);
switch (err) {
case ERROR_FILE_NOT_FOUND:
- D( "file not found" );
+ D("file not found");
errno = ENOENT;
return -1;
case ERROR_PATH_NOT_FOUND:
- D( "path not found" );
+ D("path not found");
errno = ENOTDIR;
return -1;
@@ -419,57 +453,64 @@
return -1;
}
}
- snprintf( f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path );
- D( "adb_creat: '%s' => fd %d", path, _fh_to_int(f) );
+ snprintf(f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path);
+ D("adb_creat: '%s' => fd %d", path, _fh_to_int(f));
return _fh_to_int(f);
}
-
-int adb_read(int fd, void* buf, int len)
-{
- FH f = _fh_from_int(fd, __func__);
+int adb_read(int fd, void* buf, int len) {
+ FH f = _fh_from_int(fd, __func__);
if (f == NULL) {
+ errno = EBADF;
return -1;
}
- return f->clazz->_fh_read( f, buf, len );
+ return f->clazz->_fh_read(f, buf, len);
}
-
-int adb_write(int fd, const void* buf, int len)
-{
- FH f = _fh_from_int(fd, __func__);
+int adb_write(int fd, const void* buf, int len) {
+ FH f = _fh_from_int(fd, __func__);
if (f == NULL) {
+ errno = EBADF;
return -1;
}
return f->clazz->_fh_write(f, buf, len);
}
+ssize_t adb_writev(int fd, const adb_iovec* iov, int iovcnt) {
+ FH f = _fh_from_int(fd, __func__);
-int adb_lseek(int fd, int pos, int where)
-{
- FH f = _fh_from_int(fd, __func__);
+ if (f == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+
+ return f->clazz->_fh_writev(f, iov, iovcnt);
+}
+
+int adb_lseek(int fd, int pos, int where) {
+ FH f = _fh_from_int(fd, __func__);
if (!f) {
+ errno = EBADF;
return -1;
}
return f->clazz->_fh_lseek(f, pos, where);
}
-
-int adb_close(int fd)
-{
- FH f = _fh_from_int(fd, __func__);
+int adb_close(int fd) {
+ FH f = _fh_from_int(fd, __func__);
if (!f) {
+ errno = EBADF;
return -1;
}
- D( "adb_close: %s", f->name);
+ D("adb_close: %s", f->name);
_fh_close(f);
return 0;
}
@@ -582,7 +623,7 @@
f->fh_socket = INVALID_SOCKET;
}
-static int _fh_socket_close( FH f ) {
+static int _fh_socket_close(FH f) {
if (f->fh_socket != INVALID_SOCKET) {
/* gently tell any peer that we're closing the socket */
if (shutdown(f->fh_socket, SD_BOTH) == SOCKET_ERROR) {
@@ -603,13 +644,13 @@
return 0;
}
-static int _fh_socket_lseek( FH f, int pos, int origin ) {
+static int _fh_socket_lseek(FH f, int pos, int origin) {
errno = EPIPE;
return -1;
}
static int _fh_socket_read(FH f, void* buf, int len) {
- int result = recv(f->fh_socket, reinterpret_cast<char*>(buf), len, 0);
+ int result = recv(f->fh_socket, reinterpret_cast<char*>(buf), len, 0);
if (result == SOCKET_ERROR) {
const DWORD err = WSAGetLastError();
// WSAEWOULDBLOCK is normal with a non-blocking socket, so don't trace
@@ -621,11 +662,11 @@
_socket_set_errno(err);
result = -1;
}
- return result;
+ return result;
}
static int _fh_socket_write(FH f, const void* buf, int len) {
- int result = send(f->fh_socket, reinterpret_cast<const char*>(buf), len, 0);
+ int result = send(f->fh_socket, reinterpret_cast<const char*>(buf), len, 0);
if (result == SOCKET_ERROR) {
const DWORD err = WSAGetLastError();
// WSAEWOULDBLOCK is normal with a non-blocking socket, so don't trace
@@ -639,13 +680,44 @@
} else {
// According to https://code.google.com/p/chromium/issues/detail?id=27870
// Winsock Layered Service Providers may cause this.
- CHECK_LE(result, len) << "Tried to write " << len << " bytes to "
- << f->name << ", but " << result
- << " bytes reportedly written";
+ CHECK_LE(result, len) << "Tried to write " << len << " bytes to " << f->name << ", but "
+ << result << " bytes reportedly written";
}
return result;
}
+// Make sure that adb_iovec is compatible with WSABUF.
+static_assert(sizeof(adb_iovec) == sizeof(WSABUF), "");
+static_assert(SIZEOF_MEMBER(adb_iovec, iov_len) == SIZEOF_MEMBER(WSABUF, len), "");
+static_assert(offsetof(adb_iovec, iov_len) == offsetof(WSABUF, len), "");
+
+static_assert(SIZEOF_MEMBER(adb_iovec, iov_base) == SIZEOF_MEMBER(WSABUF, buf), "");
+static_assert(offsetof(adb_iovec, iov_base) == offsetof(WSABUF, buf), "");
+
+static int _fh_socket_writev(FH f, const adb_iovec* iov, int iovcnt) {
+ if (iovcnt <= 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ WSABUF* wsabuf = reinterpret_cast<WSABUF*>(const_cast<adb_iovec*>(iov));
+ DWORD bytes_written = 0;
+ int result = WSASend(f->fh_socket, wsabuf, iovcnt, &bytes_written, 0, nullptr, nullptr);
+ if (result == SOCKET_ERROR) {
+ const DWORD err = WSAGetLastError();
+ // WSAEWOULDBLOCK is normal with a non-blocking socket, so don't trace
+ // that to reduce spam and confusion.
+ if (err != WSAEWOULDBLOCK) {
+ D("send fd %d failed: %s", _fh_to_int(f),
+ android::base::SystemErrorCodeToString(err).c_str());
+ }
+ _socket_set_errno(err);
+ result = -1;
+ }
+ CHECK_GE(static_cast<DWORD>(std::numeric_limits<int>::max()), bytes_written);
+ return static_cast<int>(bytes_written);
+}
+
/**************************************************************************/
/**************************************************************************/
/***** *****/
@@ -654,23 +726,15 @@
/**************************************************************************/
/**************************************************************************/
-#include <winsock2.h>
-
-static int _winsock_init;
-
-static void
-_init_winsock( void )
-{
- // TODO: Multiple threads calling this may potentially cause multiple calls
- // to WSAStartup() which offers no real benefit.
- if (!_winsock_init) {
- WSADATA wsaData;
- int rc = WSAStartup( MAKEWORD(2,2), &wsaData);
+static int _init_winsock(void) {
+ static std::once_flag once;
+ std::call_once(once, []() {
+ WSADATA wsaData;
+ int rc = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (rc != 0) {
fatal("adb: could not initialize Winsock: %s",
android::base::SystemErrorCodeToString(rc).c_str());
}
- _winsock_init = 1;
// Note that we do not call atexit() to register WSACleanup to be called
// at normal process termination because:
@@ -685,9 +749,12 @@
// setupapi.dll which tries to load wintrust.dll which tries to load
// crypt32.dll which calls atexit() which tries to acquire the C
// Runtime lock that the other thread holds.
- }
+ });
+ return 0;
}
+static int _winsock_init = _init_winsock();
+
// Map a socket type to an explicit socket protocol instead of using the socket
// protocol of 0. Explicit socket protocols are used by most apps and we should
// do the same to reduce the chance of exercising uncommon code-paths that might
@@ -715,8 +782,6 @@
return -1;
}
- if (!_winsock_init) _init_winsock();
-
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
@@ -765,8 +830,6 @@
return -1;
}
- if (!_winsock_init) _init_winsock();
-
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
@@ -843,8 +906,6 @@
return -1;
}
- if (!_winsock_init) _init_winsock();
-
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
@@ -912,52 +973,49 @@
return fd;
}
-int adb_register_socket(SOCKET s) {
- FH f = _fh_alloc( &_fh_socket_class );
+int adb_register_socket(SOCKET s) {
+ FH f = _fh_alloc(&_fh_socket_class);
f->fh_socket = s;
return _fh_to_int(f);
}
#undef accept
-int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen)
-{
- FH serverfh = _fh_from_int(serverfd, __func__);
+int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t* addrlen) {
+ FH serverfh = _fh_from_int(serverfd, __func__);
- if ( !serverfh || serverfh->clazz != &_fh_socket_class ) {
+ if (!serverfh || serverfh->clazz != &_fh_socket_class) {
D("adb_socket_accept: invalid fd %d", serverfd);
errno = EBADF;
return -1;
}
- unique_fh fh(_fh_alloc( &_fh_socket_class ));
+ unique_fh fh(_fh_alloc(&_fh_socket_class));
if (!fh) {
PLOG(ERROR) << "adb_socket_accept: failed to allocate accepted socket "
"descriptor";
return -1;
}
- fh->fh_socket = accept( serverfh->fh_socket, addr, addrlen );
+ fh->fh_socket = accept(serverfh->fh_socket, addr, addrlen);
if (fh->fh_socket == INVALID_SOCKET) {
const DWORD err = WSAGetLastError();
- LOG(ERROR) << "adb_socket_accept: accept on fd " << serverfd <<
- " failed: " + android::base::SystemErrorCodeToString(err);
- _socket_set_errno( err );
+ LOG(ERROR) << "adb_socket_accept: accept on fd " << serverfd
+ << " failed: " + android::base::SystemErrorCodeToString(err);
+ _socket_set_errno(err);
return -1;
}
const int fd = _fh_to_int(fh.get());
- snprintf( fh->name, sizeof(fh->name), "%d(accept:%s)", fd, serverfh->name );
- D( "adb_socket_accept on fd %d returns fd %d", serverfd, fd );
+ snprintf(fh->name, sizeof(fh->name), "%d(accept:%s)", fd, serverfh->name);
+ D("adb_socket_accept on fd %d returns fd %d", serverfd, fd);
fh.release();
- return fd;
+ return fd;
}
+int adb_setsockopt(int fd, int level, int optname, const void* optval, socklen_t optlen) {
+ FH fh = _fh_from_int(fd, __func__);
-int adb_setsockopt( int fd, int level, int optname, const void* optval, socklen_t optlen )
-{
- FH fh = _fh_from_int(fd, __func__);
-
- if ( !fh || fh->clazz != &_fh_socket_class ) {
+ if (!fh || fh->clazz != &_fh_socket_class) {
D("adb_setsockopt: invalid fd %d", fd);
errno = EBADF;
return -1;
@@ -967,13 +1025,13 @@
// to set SOL_SOCKET, SO_SNDBUF/SO_RCVBUF, ignore it since the OS has
// auto-tuning.
- int result = setsockopt( fh->fh_socket, level, optname,
- reinterpret_cast<const char*>(optval), optlen );
- if ( result == SOCKET_ERROR ) {
+ int result =
+ setsockopt(fh->fh_socket, level, optname, reinterpret_cast<const char*>(optval), optlen);
+ if (result == SOCKET_ERROR) {
const DWORD err = WSAGetLastError();
- D("adb_setsockopt: setsockopt on fd %d level %d optname %d failed: %s\n",
- fd, level, optname, android::base::SystemErrorCodeToString(err).c_str());
- _socket_set_errno( err );
+ D("adb_setsockopt: setsockopt on fd %d level %d optname %d failed: %s\n", fd, level,
+ optname, android::base::SystemErrorCodeToString(err).c_str());
+ _socket_set_errno(err);
result = -1;
}
return result;
diff --git a/adb/test_device.py b/adb/test_device.py
index b1ad043..f995be2 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -188,8 +188,6 @@
finally:
self.device.reverse_remove_all()
- # Note: If you run this test when adb connect'd to a physical device over
- # TCP, it will fail in adb reverse due to https://code.google.com/p/android/issues/detail?id=189821
def test_forward_reverse_echo(self):
"""Send data through adb forward and read it back via adb reverse"""
forward_port = 12345
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 2867d38..92c52e2 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -335,7 +335,7 @@
delete tracker;
}
-static int device_tracker_enqueue(asocket* socket, std::string) {
+static int device_tracker_enqueue(asocket* socket, apacket::payload_type) {
/* you can't read from a device tracker, close immediately */
device_tracker_close(socket);
return -1;
@@ -344,7 +344,7 @@
static int device_tracker_send(device_tracker* tracker, const std::string& string) {
asocket* peer = tracker->socket.peer;
- std::string data;
+ apacket::payload_type data;
data.resize(4 + string.size());
char buf[5];
snprintf(buf, sizeof(buf), "%04x", static_cast<int>(string.size()));
diff --git a/adb/types.h b/adb/types.h
new file mode 100644
index 0000000..dd3e063
--- /dev/null
+++ b/adb/types.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <utility>
+
+#include <android-base/logging.h>
+
+#include "sysdeps/memory.h"
+
+// Essentially std::vector<char>, except without zero initialization or reallocation.
+struct Block {
+ using iterator = char*;
+
+ Block() {}
+
+ explicit Block(size_t size) { allocate(size); }
+
+ template <typename Iterator>
+ Block(Iterator begin, Iterator end) : Block(end - begin) {
+ std::copy(begin, end, data_);
+ }
+
+ Block(const Block& copy) = delete;
+ Block(Block&& move) {
+ std::swap(data_, move.data_);
+ std::swap(capacity_, move.capacity_);
+ std::swap(size_, move.size_);
+ }
+
+ Block& operator=(const Block& copy) = delete;
+ Block& operator=(Block&& move) {
+ clear();
+
+ std::swap(data_, move.data_);
+ std::swap(capacity_, move.capacity_);
+ std::swap(size_, move.size_);
+
+ return *this;
+ }
+
+ ~Block() { clear(); }
+
+ void resize(size_t new_size) {
+ if (!data_) {
+ allocate(new_size);
+ } else {
+ CHECK_GE(capacity_, new_size);
+ size_ = new_size;
+ }
+ }
+
+ template <typename InputIt>
+ void assign(InputIt begin, InputIt end) {
+ clear();
+ allocate(end - begin);
+ std::copy(begin, end, data_);
+ }
+
+ void clear() {
+ free(data_);
+ capacity_ = 0;
+ size_ = 0;
+ }
+
+ size_t capacity() const { return capacity_; }
+ size_t size() const { return size_; }
+ bool empty() const { return size() == 0; }
+
+ char* data() { return data_; }
+ const char* data() const { return data_; }
+
+ char* begin() { return data_; }
+ const char* begin() const { return data_; }
+
+ char* end() { return data() + size_; }
+ const char* end() const { return data() + size_; }
+
+ char& operator[](size_t idx) { return data()[idx]; }
+ const char& operator[](size_t idx) const { return data()[idx]; }
+
+ bool operator==(const Block& rhs) const {
+ return size() == rhs.size() && memcmp(data(), rhs.data(), size()) == 0;
+ }
+
+ private:
+ void allocate(size_t size) {
+ CHECK(data_ == nullptr);
+ CHECK_EQ(0ULL, capacity_);
+ CHECK_EQ(0ULL, size_);
+ if (size != 0) {
+ data_ = static_cast<char*>(malloc(size));
+ capacity_ = size;
+ size_ = size;
+ }
+ }
+
+ char* data_ = nullptr;
+ size_t capacity_ = 0;
+ size_t size_ = 0;
+};
+
+struct amessage {
+ uint32_t command; /* command identifier constant */
+ uint32_t arg0; /* first argument */
+ uint32_t arg1; /* second argument */
+ uint32_t data_length; /* length of payload (0 is allowed) */
+ uint32_t data_check; /* checksum of data payload */
+ uint32_t magic; /* command ^ 0xffffffff */
+};
+
+struct apacket {
+ using payload_type = Block;
+ amessage msg;
+ payload_type payload;
+};
+
+struct Range {
+ explicit Range(apacket::payload_type data) : data_(std::move(data)) {}
+
+ Range(const Range& copy) = delete;
+ Range& operator=(const Range& copy) = delete;
+
+ Range(Range&& move) = default;
+ Range& operator=(Range&& move) = default;
+
+ size_t size() const { return data_.size() - begin_offset_ - end_offset_; };
+ bool empty() const { return size() == 0; }
+
+ void drop_front(size_t n) {
+ CHECK_GE(size(), n);
+ begin_offset_ += n;
+ }
+
+ void drop_end(size_t n) {
+ CHECK_GE(size(), n);
+ end_offset_ += n;
+ }
+
+ char* data() { return &data_[0] + begin_offset_; }
+
+ apacket::payload_type::iterator begin() { return data_.begin() + begin_offset_; }
+ apacket::payload_type::iterator end() { return data_.end() - end_offset_; }
+
+ apacket::payload_type data_;
+ size_t begin_offset_ = 0;
+ size_t end_offset_ = 0;
+};
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index e60e6be..c2688e9 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -38,6 +38,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
+#include <android-base/properties.h>
#include <android-base/strings.h>
#include <android/log.h>
#include <cutils/android_reboot.h>
@@ -1096,14 +1097,28 @@
boot_event_store->AddBootEventWithValue("absolute_boot_time", absolute_total.count());
}
+// Gets the boot time offset. This is useful when Android is running in a
+// container, because the boot_clock is not reset when Android reboots.
+std::chrono::nanoseconds GetBootTimeOffset() {
+ static const int64_t boottime_offset =
+ android::base::GetIntProperty<int64_t>("ro.boot.boottime_offset", 0);
+ return std::chrono::nanoseconds(boottime_offset);
+}
+
+// Returns the current uptime, accounting for any offset in the CLOCK_BOOTTIME
+// clock.
+android::base::boot_clock::duration GetUptime() {
+ return android::base::boot_clock::now().time_since_epoch() - GetBootTimeOffset();
+}
+
// 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() {
BootEventRecordStore boot_event_store;
BootEventRecordStore::BootEventRecord record;
- auto time_since_epoch = android::base::boot_clock::now().time_since_epoch();
- auto uptime = std::chrono::duration_cast<std::chrono::seconds>(time_since_epoch);
+ auto uptime_ns = GetUptime();
+ auto uptime_s = std::chrono::duration_cast<std::chrono::seconds>(uptime_ns);
time_t current_time_utc = time(nullptr);
if (boot_event_store.GetBootEvent("last_boot_time_utc", &record)) {
@@ -1128,19 +1143,20 @@
// Log the amount of time elapsed until the device is decrypted, which
// includes the variable amount of time the user takes to enter the
// decryption password.
- boot_event_store.AddBootEventWithValue("boot_decryption_complete", uptime.count());
+ boot_event_store.AddBootEventWithValue("boot_decryption_complete", uptime_s.count());
// Subtract the decryption time to normalize the boot cycle timing.
- std::chrono::seconds boot_complete = std::chrono::seconds(uptime.count() - record.second);
+ std::chrono::seconds boot_complete = std::chrono::seconds(uptime_s.count() - record.second);
boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_post_decrypt",
boot_complete.count());
} else {
- boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_no_encryption", uptime.count());
+ boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_no_encryption",
+ uptime_s.count());
}
// Record the total time from device startup to boot complete, regardless of
// encryption state.
- boot_event_store.AddBootEventWithValue(boot_complete_prefix, uptime.count());
+ boot_event_store.AddBootEventWithValue(boot_complete_prefix, uptime_s.count());
RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init");
RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init.selinux");
@@ -1149,7 +1165,7 @@
const BootloaderTimingMap bootloader_timings = GetBootLoaderTimings();
RecordBootloaderTimings(&boot_event_store, bootloader_timings);
- auto uptime_ms = std::chrono::duration_cast<std::chrono::milliseconds>(time_since_epoch);
+ auto uptime_ms = std::chrono::duration_cast<std::chrono::milliseconds>(uptime_ns);
RecordAbsoluteBootTime(&boot_event_store, bootloader_timings, uptime_ms);
}
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 397ff2f..e410be9 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -354,7 +354,14 @@
int intercept_result;
unique_fd output_fd;
StartProcess([]() {
- android_set_abort_message("abort message goes here");
+ // Arrived at experimentally;
+ // logd truncates at 4062.
+ // strlen("Abort message: ''") is 17.
+ // That's 4045, but we also want a NUL.
+ char buf[4045 + 1];
+ memset(buf, 'x', sizeof(buf));
+ buf[sizeof(buf) - 1] = '\0';
+ android_set_abort_message(buf);
abort();
});
StartIntercept(&output_fd);
@@ -366,7 +373,7 @@
std::string result;
ConsumeFd(std::move(output_fd), &result);
- ASSERT_MATCH(result, R"(Abort message: 'abort message goes here')");
+ ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
}
TEST_F(CrasherTest, abort_message_backtrace) {
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 140ef6d..55d6204 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -239,19 +239,23 @@
return;
}
- char msg[512];
- if (length >= sizeof(msg)) {
- _LOG(log, logtype::HEADER, "Abort message too long: claimed length = %zd\n", length);
+ // The length field includes the length of the length field itself.
+ if (length < sizeof(size_t)) {
+ _LOG(log, logtype::HEADER, "Abort message header malformed: claimed length = %zd\n", length);
return;
}
- if (!process_memory->ReadFully(address + sizeof(length), msg, length)) {
+ length -= sizeof(size_t);
+
+ std::vector<char> msg(length);
+ if (!process_memory->ReadFully(address + sizeof(length), &msg[0], length)) {
_LOG(log, logtype::HEADER, "Failed to read abort message: %s\n", strerror(errno));
return;
}
+ // The abort message should be null terminated already, but just in case...
msg[length] = '\0';
- _LOG(log, logtype::HEADER, "Abort message: '%s'\n", msg);
+ _LOG(log, logtype::HEADER, "Abort message: '%s'\n", &msg[0]);
}
static void dump_all_maps(log_t* log, BacktraceMap* map, Memory* process_memory, uint64_t addr) {
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index d153865..1ad1800 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -74,25 +74,22 @@
&& (log->crashed_tid == log->current_tid);
static bool write_to_kmsg = should_write_to_kmsg();
- char buf[512];
+ std::string msg;
va_list ap;
va_start(ap, fmt);
- vsnprintf(buf, sizeof(buf), fmt, ap);
+ android::base::StringAppendV(&msg, fmt, ap);
va_end(ap);
- size_t len = strlen(buf);
- if (len <= 0) {
- return;
- }
+ if (msg.empty()) return;
if (write_to_tombstone) {
- TEMP_FAILURE_RETRY(write(log->tfd, buf, len));
+ TEMP_FAILURE_RETRY(write(log->tfd, msg.c_str(), msg.size()));
}
if (write_to_logcat) {
- __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_FATAL, LOG_TAG, buf);
+ __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_FATAL, LOG_TAG, msg.c_str());
if (log->amfd_data != nullptr) {
- *log->amfd_data += buf;
+ *log->amfd_data += msg;
}
if (write_to_kmsg) {
@@ -100,11 +97,11 @@
if (kmsg_fd.get() >= 0) {
// Our output might contain newlines which would otherwise be handled by the android logger.
// Split the lines up ourselves before sending to the kernel logger.
- if (buf[len - 1] == '\n') {
- buf[len - 1] = '\0';
+ if (msg.back() == '\n') {
+ msg.back() = '\0';
}
- std::vector<std::string> fragments = android::base::Split(buf, "\n");
+ std::vector<std::string> fragments = android::base::Split(msg, "\n");
for (const std::string& fragment : fragments) {
static constexpr char prefix[] = "<3>DEBUG: ";
struct iovec iov[3];
diff --git a/fastboot/bootimg_utils.cpp b/fastboot/bootimg_utils.cpp
index feacaa1..c9814e4 100644
--- a/fastboot/bootimg_utils.cpp
+++ b/fastboot/bootimg_utils.cpp
@@ -44,7 +44,7 @@
const boot_img_hdr_v1& src, int64_t* bootimg_size) {
const size_t page_mask = src.page_size - 1;
- int64_t header_actual = sizeof(boot_img_hdr_v1) & (~page_mask);
+ int64_t header_actual = (sizeof(boot_img_hdr_v1) + page_mask) & (~page_mask);
int64_t kernel_actual = (kernel_size + page_mask) & (~page_mask);
int64_t ramdisk_actual = (ramdisk_size + page_mask) & (~page_mask);
int64_t second_actual = (second_size + page_mask) & (~page_mask);
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 3a3503e..41a3d6b 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -410,12 +410,6 @@
if (!g_cmdline.empty()) {
bootimg_set_cmdline(reinterpret_cast<boot_img_hdr_v1*>(kdata), g_cmdline);
}
- uint32_t header_version_existing =
- reinterpret_cast<boot_img_hdr_v1*>(kdata)->header_version;
- if (g_boot_img_hdr.header_version != header_version_existing) {
- die("header version mismatch, expected: %" PRIu32 " found %" PRIu32 "",
- g_boot_img_hdr.header_version, header_version_existing);
- }
if (!ramdisk.empty()) die("cannot boot a boot.img *and* ramdisk");
diff --git a/init/README.md b/init/README.md
index 59ddd77..b14521c 100644
--- a/init/README.md
+++ b/init/README.md
@@ -282,6 +282,10 @@
"shutdown critical" will be killed. When the service tagged with "shutdown critical"
is not running when shut down starts, it will be started.
+`sigstop`
+> Send SIGSTOP to the service immediately before exec is called. This is intended for debugging.
+ See the below section on debugging for how this can be used.
+
`socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]`
> Create a unix domain socket named /dev/socket/_name_ and pass its fd to the
launched process. _type_ must be "dgram", "stream" or "seqpacket". User and
@@ -708,23 +712,39 @@
Debugging init
--------------
-By default, programs executed by init will drop stdout and stderr into
-/dev/null. To help with debugging, you can execute your program via the
-Android program logwrapper. This will redirect stdout/stderr into the
-Android logging system (accessed via logcat).
+Launching init services without init is not recommended as init sets up a significant amount of
+environment (user, groups, security label, capabilities, etc) that is hard to replicate manually.
-For example
-service akmd /system/bin/logwrapper /sbin/akmd
+If it is required to debug a service from its very start, the `sigstop` service option is added.
+This option will send SIGSTOP to a service immediately before calling exec. This gives a window
+where developers can attach a debugger, strace, etc before continuing the service with SIGCONT.
-For quicker turnaround when working on init itself, use:
+This flag can also be dynamically controled via the ctl.sigstop_on and ctl.sigstop_off properties.
- mm -j &&
- m ramdisk-nodeps &&
- m bootimage-nodeps &&
- adb reboot bootloader &&
- fastboot boot $ANDROID_PRODUCT_OUT/boot.img
+Below is an example of dynamically debugging logd via the above:
-Alternatively, use the emulator:
+ stop logd
+ setprop ctl.sigstop_on logd
+ start logd
+ ps -e | grep logd
+ > logd 4343 1 18156 1684 do_signal_stop 538280 T init
+ gdbclient.py -p 4343
+ b main
+ c
+ c
+ c
+ > Breakpoint 1, main (argc=1, argv=0x7ff8c9a488) at system/core/logd/main.cpp:427
- emulator -partition-size 1024 \
- -verbose -show-kernel -no-window
+Below is an example of doing the same but with strace
+
+ stop logd
+ setprop ctl.sigstop_on logd
+ start logd
+ ps -e | grep logd
+ > logd 4343 1 18156 1684 do_signal_stop 538280 T init
+ strace -p 4343
+
+ (From a different shell)
+ kill -SIGCONT 4343
+
+ > strace runs
diff --git a/init/builtins.cpp b/init/builtins.cpp
index fc74dda..8bd92cc 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -82,6 +82,7 @@
static constexpr std::chrono::nanoseconds kCommandRetryTimeout = 5s;
static Result<Success> reboot_into_recovery(const std::vector<std::string>& options) {
+ LOG(ERROR) << "Rebooting into recovery";
std::string err;
if (!write_bootloader_message(options, &err)) {
return Error() << "Failed to set bootloader message: " << err;
@@ -285,11 +286,8 @@
if (e4crypt_is_native()) {
if (e4crypt_set_directory_policy(args[1].c_str())) {
- const std::vector<std::string> options = {
- "--prompt_and_wipe_data",
- "--reason=set_policy_failed:"s + args[1]};
- reboot_into_recovery(options);
- return Success();
+ return reboot_into_recovery(
+ {"--prompt_and_wipe_data", "--reason=set_policy_failed:"s + args[1]});
}
}
return Success();
@@ -493,8 +491,7 @@
/* Setup a wipe via recovery, and reboot into recovery */
PLOG(ERROR) << "fs_mgr_mount_all suggested recovery, so wiping data via recovery.";
const std::vector<std::string> options = {"--wipe_data", "--reason=fs_mgr_mount_all" };
- reboot_into_recovery(options);
- return Success();
+ return reboot_into_recovery(options);
/* If reboot worked, there is no return. */
} else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
if (e4crypt_install_keyring()) {
@@ -522,6 +519,7 @@
if (e4crypt_install_keyring()) {
return Error() << "e4crypt_install_keyring() failed";
}
+ property_set("ro.crypto.state", "encrypted");
property_set("ro.crypto.type", "file");
// Although encrypted, vold has already set the device up, so we do not need to
@@ -987,6 +985,29 @@
return android::base::GetProperty("ro.crypto.type", "") == "file";
}
+static Result<Success> ExecWithRebootOnFailure(const std::string& reboot_reason,
+ const BuiltinArguments& args) {
+ auto service = Service::MakeTemporaryOneshotService(args.args);
+ if (!service) {
+ return Error() << "Could not create exec service";
+ }
+ service->AddReapCallback([reboot_reason](const siginfo_t& siginfo) {
+ if (siginfo.si_code != CLD_EXITED || siginfo.si_status != 0) {
+ if (e4crypt_is_native()) {
+ LOG(ERROR) << "Rebooting into recovery, reason: " << reboot_reason;
+ reboot_into_recovery({"--prompt_and_wipe_data", "--reason="s + reboot_reason});
+ } else {
+ LOG(ERROR) << "Failure (reboot suppressed): " << reboot_reason;
+ }
+ }
+ });
+ if (auto result = service->ExecStart(); !result) {
+ return Error() << "Could not start exec service: " << result.error();
+ }
+ ServiceList::GetInstance().AddService(std::move(service));
+ return Success();
+}
+
static Result<Success> do_installkey(const BuiltinArguments& args) {
if (!is_file_crypto()) return Success();
@@ -994,15 +1015,15 @@
if (!make_dir(unencrypted_dir, 0700) && errno != EEXIST) {
return ErrnoError() << "Failed to create " << unencrypted_dir;
}
- std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs",
- "enablefilecrypto"};
- return do_exec({std::move(exec_args), args.context});
+ return ExecWithRebootOnFailure(
+ "enablefilecrypto_failed",
+ {{"exec", "/system/bin/vdc", "--wait", "cryptfs", "enablefilecrypto"}, args.context});
}
static Result<Success> do_init_user0(const BuiltinArguments& args) {
- std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs",
- "init_user0"};
- return do_exec({std::move(exec_args), args.context});
+ return ExecWithRebootOnFailure(
+ "init_user0_failed",
+ {{"exec", "/system/bin/vdc", "--wait", "cryptfs", "init_user0"}, args.context});
}
// Builtin-function-map start
diff --git a/init/host_init_stubs.h b/init/host_init_stubs.h
index f31ece6..ddfb7ae 100644
--- a/init/host_init_stubs.h
+++ b/init/host_init_stubs.h
@@ -35,6 +35,11 @@
std::string GetProperty(const std::string& key, const std::string& default_value);
bool GetBoolProperty(const std::string& key, bool default_value);
+template <typename T>
+T GetIntProperty(const std::string&, T default_value, T = std::numeric_limits<T>::min(),
+ T = std::numeric_limits<T>::max()) {
+ return default_value;
+}
} // namespace base
} // namespace android
diff --git a/init/init.cpp b/init/init.cpp
index efb9c1d..0d5690b 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -79,7 +79,7 @@
std::string default_console = "/dev/console";
static int epoll_fd = -1;
-static int sigterm_signal_fd = -1;
+static int signal_fd = -1;
static std::unique_ptr<Timer> waiting_for_prop(nullptr);
static std::string wait_prop_name;
@@ -238,6 +238,10 @@
static const std::map<std::string, ControlMessageFunction>& get_control_message_map() {
// clang-format off
static const std::map<std::string, ControlMessageFunction> control_message_functions = {
+ {"sigstop_on", {ControlTarget::SERVICE,
+ [](auto* service) { service->set_sigstop(true); return Success(); }}},
+ {"sigstop_off", {ControlTarget::SERVICE,
+ [](auto* service) { service->set_sigstop(false); return Success(); }}},
{"start", {ControlTarget::SERVICE, DoControlStart}},
{"stop", {ControlTarget::SERVICE, DoControlStop}},
{"restart", {ControlTarget::SERVICE, DoControlRestart}},
@@ -492,14 +496,7 @@
sigaction(SIGTRAP, &action, nullptr);
}
-static void HandleSigtermSignal() {
- signalfd_siginfo siginfo;
- ssize_t bytes_read = TEMP_FAILURE_RETRY(read(sigterm_signal_fd, &siginfo, sizeof(siginfo)));
- if (bytes_read != sizeof(siginfo)) {
- PLOG(ERROR) << "Failed to read siginfo from sigterm_signal_fd";
- return;
- }
-
+static void HandleSigtermSignal(const signalfd_siginfo& siginfo) {
if (siginfo.ssi_pid != 0) {
// Drop any userspace SIGTERM requests.
LOG(DEBUG) << "Ignoring SIGTERM from pid " << siginfo.ssi_pid;
@@ -509,37 +506,73 @@
HandlePowerctlMessage("shutdown,container");
}
-static void UnblockSigterm() {
- sigset_t mask;
- sigemptyset(&mask);
- sigaddset(&mask, SIGTERM);
+static void HandleSignalFd() {
+ signalfd_siginfo siginfo;
+ ssize_t bytes_read = TEMP_FAILURE_RETRY(read(signal_fd, &siginfo, sizeof(siginfo)));
+ if (bytes_read != sizeof(siginfo)) {
+ PLOG(ERROR) << "Failed to read siginfo from signal_fd";
+ return;
+ }
- if (sigprocmask(SIG_UNBLOCK, &mask, nullptr) == -1) {
- PLOG(FATAL) << "failed to unblock SIGTERM for PID " << getpid();
+ switch (siginfo.ssi_signo) {
+ case SIGCHLD:
+ ReapAnyOutstandingChildren();
+ break;
+ case SIGTERM:
+ HandleSigtermSignal(siginfo);
+ break;
+ default:
+ PLOG(ERROR) << "signal_fd: received unexpected signal " << siginfo.ssi_signo;
+ break;
}
}
-static void InstallSigtermHandler() {
+static void UnblockSignals() {
+ const struct sigaction act { .sa_handler = SIG_DFL };
+ sigaction(SIGCHLD, &act, nullptr);
+
sigset_t mask;
sigemptyset(&mask);
+ sigaddset(&mask, SIGCHLD);
sigaddset(&mask, SIGTERM);
- if (sigprocmask(SIG_BLOCK, &mask, nullptr) == -1) {
- PLOG(FATAL) << "failed to block SIGTERM";
+ if (sigprocmask(SIG_UNBLOCK, &mask, nullptr) == -1) {
+ PLOG(FATAL) << "failed to unblock signals for PID " << getpid();
+ }
+}
+
+static void InstallSignalFdHandler() {
+ // Applying SA_NOCLDSTOP to a defaulted SIGCHLD handler prevents the signalfd from receiving
+ // SIGCHLD when a child process stops or continues (b/77867680#comment9).
+ const struct sigaction act { .sa_handler = SIG_DFL, .sa_flags = SA_NOCLDSTOP };
+ sigaction(SIGCHLD, &act, nullptr);
+
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGCHLD);
+
+ if (!IsRebootCapable()) {
+ // If init does not have the CAP_SYS_BOOT capability, it is running in a container.
+ // In that case, receiving SIGTERM will cause the system to shut down.
+ sigaddset(&mask, SIGTERM);
}
- // Register a handler to unblock SIGTERM in the child processes.
- const int result = pthread_atfork(nullptr, nullptr, &UnblockSigterm);
+ if (sigprocmask(SIG_BLOCK, &mask, nullptr) == -1) {
+ PLOG(FATAL) << "failed to block signals";
+ }
+
+ // Register a handler to unblock signals in the child processes.
+ const int result = pthread_atfork(nullptr, nullptr, &UnblockSignals);
if (result != 0) {
LOG(FATAL) << "Failed to register a fork handler: " << strerror(result);
}
- sigterm_signal_fd = signalfd(-1, &mask, SFD_CLOEXEC);
- if (sigterm_signal_fd == -1) {
- PLOG(FATAL) << "failed to create signalfd for SIGTERM";
+ signal_fd = signalfd(-1, &mask, SFD_CLOEXEC);
+ if (signal_fd == -1) {
+ PLOG(FATAL) << "failed to create signalfd";
}
- register_epoll_handler(sigterm_signal_fd, HandleSigtermSignal);
+ register_epoll_handler(signal_fd, HandleSignalFd);
}
int main(int argc, char** argv) {
@@ -595,6 +628,14 @@
mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));
+ // Mount staging areas for devices managed by vold
+ // See storage config details at http://source.android.com/devices/storage/
+ mount("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
+ "mode=0755,uid=0,gid=1000");
+ // /mnt/vendor is used to mount vendor-specific partitions that can not be
+ // part of the vendor partition, e.g. because they are mounted read-write.
+ mkdir("/mnt/vendor", 0755);
+
// Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
// talk to the outside world...
InitKernelLogging(argv);
@@ -682,13 +723,7 @@
PLOG(FATAL) << "epoll_create1 failed";
}
- sigchld_handler_init();
-
- if (!IsRebootCapable()) {
- // If init does not have the CAP_SYS_BOOT capability, it is running in a container.
- // In that case, receiving SIGTERM will cause the system to shut down.
- InstallSigtermHandler();
- }
+ InstallSignalFdHandler();
property_load_boot_defaults();
export_oem_lock_status();
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 95ef35c..99d3c83 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -64,6 +64,7 @@
using namespace std::literals;
+using android::base::GetIntProperty;
using android::base::ReadFileToString;
using android::base::Split;
using android::base::StartsWith;
@@ -541,9 +542,11 @@
size_t flen = 0;
const char* context = kInitContext.c_str();
- for (const auto& [path_prefix, secontext] : paths_and_secontexts) {
- if (StartsWith(filename, path_prefix)) {
- context = secontext;
+ if (GetIntProperty("ro.vndk.version", 28) >= 28) {
+ for (const auto& [path_prefix, secontext] : paths_and_secontexts) {
+ if (StartsWith(filename, path_prefix)) {
+ context = secontext;
+ }
}
}
diff --git a/init/service.cpp b/init/service.cpp
index 694e5e7..03c2cee 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -155,7 +155,7 @@
}
}
-static bool ExpandArgsAndExecv(const std::vector<std::string>& args) {
+static bool ExpandArgsAndExecv(const std::vector<std::string>& args, bool sigstop) {
std::vector<std::string> expanded_args;
std::vector<char*> c_strings;
@@ -169,6 +169,10 @@
}
c_strings.push_back(nullptr);
+ if (sigstop) {
+ kill(getpid(), SIGSTOP);
+ }
+
return execv(c_strings[0], c_strings.data()) == 0;
}
@@ -303,7 +307,7 @@
}
}
-void Service::Reap() {
+void Service::Reap(const siginfo_t& siginfo) {
if (!(flags_ & SVC_ONESHOT) || (flags_ & SVC_RESTART)) {
KillProcessGroup(SIGKILL);
}
@@ -312,6 +316,10 @@
std::for_each(descriptors_.begin(), descriptors_.end(),
std::bind(&DescriptorInfo::Clean, std::placeholders::_1));
+ for (const auto& f : reap_callbacks_) {
+ f(siginfo);
+ }
+
if (flags_ & SVC_EXEC) UnSetExec();
if (flags_ & SVC_TEMPORARY) return;
@@ -578,6 +586,11 @@
return Success();
}
+Result<Success> Service::ParseSigstop(const std::vector<std::string>& args) {
+ sigstop_ = true;
+ return Success();
+}
+
Result<Success> Service::ParseSetenv(const std::vector<std::string>& args) {
environment_vars_.emplace_back(args[1], args[2]);
return Success();
@@ -700,6 +713,7 @@
{"seclabel", {1, 1, &Service::ParseSeclabel}},
{"setenv", {2, 2, &Service::ParseSetenv}},
{"shutdown", {1, 1, &Service::ParseShutdown}},
+ {"sigstop", {0, 0, &Service::ParseSigstop}},
{"socket", {3, 6, &Service::ParseSocket}},
{"user", {1, 1, &Service::ParseUser}},
{"writepid", {1, kMax, &Service::ParseWritepid}},
@@ -858,7 +872,7 @@
// priority. Aborts on failure.
SetProcessAttributes();
- if (!ExpandArgsAndExecv(args_)) {
+ if (!ExpandArgsAndExecv(args_, sigstop_)) {
PLOG(ERROR) << "cannot execve('" << args_[0] << "')";
}
diff --git a/init/service.h b/init/service.h
index d46a413..cf38f69 100644
--- a/init/service.h
+++ b/init/service.h
@@ -17,6 +17,7 @@
#ifndef _INIT_SERVICE_H
#define _INIT_SERVICE_H
+#include <signal.h>
#include <sys/resource.h>
#include <sys/types.h>
@@ -81,7 +82,7 @@
void Stop();
void Terminate();
void Restart();
- void Reap();
+ void Reap(const siginfo_t& siginfo);
void DumpState() const;
void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
bool IsShutdownCritical() const { return (flags_ & SVC_SHUTDOWN_CRITICAL) != 0; }
@@ -89,6 +90,9 @@
is_exec_service_running_ = false;
flags_ &= ~SVC_EXEC;
}
+ void AddReapCallback(std::function<void(const siginfo_t& siginfo)> callback) {
+ reap_callbacks_.emplace_back(std::move(callback));
+ }
static bool is_exec_service_running() { return is_exec_service_running_; }
@@ -114,6 +118,7 @@
bool is_override() const { return override_; }
bool process_cgroup_empty() const { return process_cgroup_empty_; }
unsigned long start_order() const { return start_order_; }
+ void set_sigstop(bool value) { sigstop_ = value; }
const std::vector<std::string>& args() const { return args_; }
private:
@@ -149,6 +154,7 @@
Result<Success> ParseSeclabel(const std::vector<std::string>& args);
Result<Success> ParseSetenv(const std::vector<std::string>& args);
Result<Success> ParseShutdown(const std::vector<std::string>& args);
+ Result<Success> ParseSigstop(const std::vector<std::string>& args);
Result<Success> ParseSocket(const std::vector<std::string>& args);
Result<Success> ParseFile(const std::vector<std::string>& args);
Result<Success> ParseUser(const std::vector<std::string>& args);
@@ -209,7 +215,11 @@
std::vector<std::pair<int, rlimit>> rlimits_;
+ bool sigstop_ = false;
+
std::vector<std::string> args_;
+
+ std::vector<std::function<void(const siginfo_t& siginfo)>> reap_callbacks_;
};
class ServiceList {
diff --git a/init/sigchld_handler.cpp b/init/sigchld_handler.cpp
index 072a0fb..0b03324 100644
--- a/init/sigchld_handler.cpp
+++ b/init/sigchld_handler.cpp
@@ -39,9 +39,6 @@
namespace android {
namespace init {
-static int signal_write_fd = -1;
-static int signal_read_fd = -1;
-
static bool ReapOneProcess() {
siginfo_t siginfo = {};
// This returns a zombie pid or informs us that there are no zombies left to be reaped.
@@ -84,16 +81,15 @@
}
}
- auto status = siginfo.si_status;
- if (WIFEXITED(status)) {
- LOG(INFO) << name << " exited with status " << WEXITSTATUS(status) << wait_string;
- } else if (WIFSIGNALED(status)) {
- LOG(INFO) << name << " killed by signal " << WTERMSIG(status) << wait_string;
+ if (siginfo.si_code == CLD_EXITED) {
+ LOG(INFO) << name << " exited with status " << siginfo.si_status << wait_string;
+ } else {
+ LOG(INFO) << name << " received signal " << siginfo.si_status << wait_string;
}
if (!service) return true;
- service->Reap();
+ service->Reap(siginfo);
if (service->flags() & SVC_TEMPORARY) {
ServiceList::GetInstance().RemoveService(*service);
@@ -102,46 +98,10 @@
return true;
}
-static void handle_signal() {
- // Clear outstanding requests.
- char buf[32];
- read(signal_read_fd, buf, sizeof(buf));
-
- ReapAnyOutstandingChildren();
-}
-
-static void SIGCHLD_handler(int) {
- if (TEMP_FAILURE_RETRY(write(signal_write_fd, "1", 1)) == -1) {
- PLOG(ERROR) << "write(signal_write_fd) failed";
- }
-}
-
void ReapAnyOutstandingChildren() {
while (ReapOneProcess()) {
}
}
-void sigchld_handler_init() {
- // Create a signalling mechanism for SIGCHLD.
- int s[2];
- if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) {
- PLOG(FATAL) << "socketpair failed in sigchld_handler_init";
- }
-
- signal_write_fd = s[0];
- signal_read_fd = s[1];
-
- // Write to signal_write_fd if we catch SIGCHLD.
- struct sigaction act;
- memset(&act, 0, sizeof(act));
- act.sa_handler = SIGCHLD_handler;
- act.sa_flags = SA_NOCLDSTOP;
- sigaction(SIGCHLD, &act, 0);
-
- ReapAnyOutstandingChildren();
-
- register_epoll_handler(signal_read_fd, handle_signal);
-}
-
} // namespace init
} // namespace android
diff --git a/init/sigchld_handler.h b/init/sigchld_handler.h
index c86dc8d..30063f2 100644
--- a/init/sigchld_handler.h
+++ b/init/sigchld_handler.h
@@ -22,8 +22,6 @@
void ReapAnyOutstandingChildren();
-void sigchld_handler_init(void);
-
} // namespace init
} // namespace android
diff --git a/init/stable_properties.h b/init/stable_properties.h
index cc25607..05b2acb 100644
--- a/init/stable_properties.h
+++ b/init/stable_properties.h
@@ -29,6 +29,7 @@
};
static const std::set<std::string> kExportedActionableProperties = {
+ "dev.bootcomplete",
"init.svc.console",
"init.svc.mediadrm",
"init.svc.surfaceflinger",
@@ -39,6 +40,8 @@
"ro.board.platform",
"ro.bootmode",
"ro.build.type",
+ "ro.crypto.state",
+ "ro.crypto.type",
"ro.debuggable",
"sys.boot_completed",
"sys.boot_from_charger_mode",
@@ -50,6 +53,8 @@
"sys.usb.ffs.ready",
"sys.user.0.ce_available",
"sys.vdso",
+ "vold.decrypt",
+ "vold.post_fs_data_done",
"vts.native_server.on",
"wlan.driver.status",
};
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index c1846f7..9c0c0bb 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -30,6 +30,8 @@
#include "util.h"
#if defined(__ANDROID__)
+#include <android-base/properties.h>
+
#include "property_service.h"
#include "selinux.h"
#else
@@ -37,6 +39,7 @@
#endif
using android::base::GetExecutablePath;
+using android::base::GetIntProperty;
using android::base::Join;
using android::base::Socketpair;
using android::base::Split;
@@ -354,8 +357,10 @@
static std::vector<Subcontext> subcontexts;
std::vector<Subcontext>* InitializeSubcontexts() {
- for (const auto& [path_prefix, secontext] : paths_and_secontexts) {
- subcontexts.emplace_back(path_prefix, secontext);
+ if (GetIntProperty("ro.vndk.version", 28) >= 28) {
+ for (const auto& [path_prefix, secontext] : paths_and_secontexts) {
+ subcontexts.emplace_back(path_prefix, secontext);
+ }
}
return &subcontexts;
}
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 5d17698..8209167 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -129,6 +129,7 @@
#define AID_STATSD 1066 /* statsd daemon */
#define AID_INCIDENTD 1067 /* incidentd daemon */
#define AID_SECURE_ELEMENT 1068 /* secure element subsystem */
+#define AID_LMKD 1069 /* low memory killer daemon */
/* Changes to this file must be made in AOSP, *not* in internal branches. */
#define AID_SHELL 2000 /* adb and debug shell user */
diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h
index 28c87e4..52cbe8b 100644
--- a/liblog/include/android/log.h
+++ b/liblog/include/android/log.h
@@ -35,6 +35,11 @@
*/
/**
+ * @addtogroup Logging
+ * @{
+ */
+
+/**
* \file
*
* Support routines to send messages to the Android log buffer,
@@ -205,4 +210,6 @@
}
#endif
+/** @} */
+
#endif /* _ANDROID_LOG_H */
diff --git a/libmemunreachable/Android.bp b/libmemunreachable/Android.bp
index f872d0f..619ee34 100644
--- a/libmemunreachable/Android.bp
+++ b/libmemunreachable/Android.bp
@@ -46,6 +46,12 @@
static_libs: ["libunwind_llvm"],
},
},
+
+ // TODO(b/78118944), clang lld link flags do not work with special link
+ // rules for libunwind_llvm yet. Linked aosp_arm-eng image failed to
+ // boot up in the emulator.
+ use_clang_lld: false,
+
export_include_dirs: ["include"],
local_include_dirs: ["include"],
}
diff --git a/libsync/include/ndk/sync.h b/libsync/include/ndk/sync.h
index 3c55783..a786d3e 100644
--- a/libsync/include/ndk/sync.h
+++ b/libsync/include/ndk/sync.h
@@ -14,6 +14,15 @@
* limitations under the License.
*/
+/**
+ * @addtogroup Sync
+ * @{
+ */
+
+/**
+ * @file sync.h
+ */
+
#ifndef ANDROID_SYNC_H
#define ANDROID_SYNC_H
@@ -86,3 +95,5 @@
__END_DECLS
#endif /* ANDROID_SYNC_H */
+
+/** @} */
diff --git a/libutils/SharedBuffer.h b/libutils/SharedBuffer.h
index 48358cd..81cadff 100644
--- a/libutils/SharedBuffer.h
+++ b/libutils/SharedBuffer.h
@@ -139,7 +139,7 @@
return (mRefs.load(std::memory_order_acquire) == 1);
}
-}; // namespace android
+} // namespace android
// ---------------------------------------------------------------------------
diff --git a/libutils/include/utils/AndroidThreads.h b/libutils/include/utils/AndroidThreads.h
index 4c2dd49..dab888d 100644
--- a/libutils/include/utils/AndroidThreads.h
+++ b/libutils/include/utils/AndroidThreads.h
@@ -118,7 +118,7 @@
}
// ----------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
#endif // __cplusplus
// ----------------------------------------------------------------------------
diff --git a/libutils/include/utils/CallStack.h b/libutils/include/utils/CallStack.h
index 27e89f4..9622142 100644
--- a/libutils/include/utils/CallStack.h
+++ b/libutils/include/utils/CallStack.h
@@ -67,6 +67,6 @@
Vector<String8> mFrameLines;
};
-}; // namespace android
+} // namespace android
#endif // ANDROID_CALLSTACK_H
diff --git a/libutils/include/utils/Condition.h b/libutils/include/utils/Condition.h
index 9bf82eb..c8da67c 100644
--- a/libutils/include/utils/Condition.h
+++ b/libutils/include/utils/Condition.h
@@ -159,7 +159,7 @@
#endif // !defined(_WIN32)
// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
// ---------------------------------------------------------------------------
#endif // _LIBS_UTILS_CONDITON_H
diff --git a/libutils/include/utils/Debug.h b/libutils/include/utils/Debug.h
index 4cbb462..96bd70e 100644
--- a/libutils/include/utils/Debug.h
+++ b/libutils/include/utils/Debug.h
@@ -35,6 +35,6 @@
CompileTimeAssert<( _exp )>();
// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
#endif // ANDROID_UTILS_DEBUG_H
diff --git a/libutils/include/utils/FileMap.h b/libutils/include/utils/FileMap.h
index 7d372e1..8d402a3 100644
--- a/libutils/include/utils/FileMap.h
+++ b/libutils/include/utils/FileMap.h
@@ -124,6 +124,6 @@
static long mPageSize;
};
-}; // namespace android
+} // namespace android
#endif // __LIBS_FILE_MAP_H
diff --git a/libutils/include/utils/Flattenable.h b/libutils/include/utils/Flattenable.h
index 675e211..0a19019 100644
--- a/libutils/include/utils/Flattenable.h
+++ b/libutils/include/utils/Flattenable.h
@@ -198,8 +198,6 @@
}
};
-
-}; // namespace android
-
+} // namespace android
#endif /* ANDROID_UTILS_FLATTENABLE_H */
diff --git a/libutils/include/utils/Functor.h b/libutils/include/utils/Functor.h
index 3182a9c..c0c8d57 100644
--- a/libutils/include/utils/Functor.h
+++ b/libutils/include/utils/Functor.h
@@ -32,6 +32,6 @@
virtual status_t operator ()(int /*what*/, void* /*data*/) { return NO_ERROR; }
};
-}; // namespace android
+} // namespace android
#endif // ANDROID_FUNCTOR_H
diff --git a/libutils/include/utils/KeyedVector.h b/libutils/include/utils/KeyedVector.h
index 03bfe27..7bda99b 100644
--- a/libutils/include/utils/KeyedVector.h
+++ b/libutils/include/utils/KeyedVector.h
@@ -211,7 +211,7 @@
return i >= 0 ? KeyedVector<KEY,VALUE>::valueAt(i) : mDefault;
}
-}; // namespace android
+} // namespace android
// ---------------------------------------------------------------------------
diff --git a/libutils/include/utils/List.h b/libutils/include/utils/List.h
index daca016..25b56fd 100644
--- a/libutils/include/utils/List.h
+++ b/libutils/include/utils/List.h
@@ -329,6 +329,6 @@
return *this;
}
-}; // namespace android
+} // namespace android
#endif // _LIBS_UTILS_LIST_H
diff --git a/libutils/include/utils/Mutex.h b/libutils/include/utils/Mutex.h
index af6076c..1228df4 100644
--- a/libutils/include/utils/Mutex.h
+++ b/libutils/include/utils/Mutex.h
@@ -212,7 +212,7 @@
typedef Mutex::Autolock AutoMutex;
// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
// ---------------------------------------------------------------------------
#endif // _LIBS_UTILS_MUTEX_H
diff --git a/libutils/include/utils/Printer.h b/libutils/include/utils/Printer.h
index bb66287..a6f6928 100644
--- a/libutils/include/utils/Printer.h
+++ b/libutils/include/utils/Printer.h
@@ -114,6 +114,6 @@
const char* mPrefix;
};
-}; // namespace android
+} // namespace android
#endif // ANDROID_PRINTER_H
diff --git a/libutils/include/utils/ProcessCallStack.h b/libutils/include/utils/ProcessCallStack.h
index 32458b8..b5f2edc 100644
--- a/libutils/include/utils/ProcessCallStack.h
+++ b/libutils/include/utils/ProcessCallStack.h
@@ -74,6 +74,6 @@
struct tm mTimeUpdated;
};
-}; // namespace android
+} // namespace android
#endif // ANDROID_PROCESS_CALLSTACK_H
diff --git a/libutils/include/utils/RWLock.h b/libutils/include/utils/RWLock.h
index d5b81d3..7d43e69 100644
--- a/libutils/include/utils/RWLock.h
+++ b/libutils/include/utils/RWLock.h
@@ -120,7 +120,7 @@
#endif // !defined(_WIN32)
// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
// ---------------------------------------------------------------------------
#endif // _LIBS_UTILS_RWLOCK_H
diff --git a/libutils/include/utils/Singleton.h b/libutils/include/utils/Singleton.h
index bc47a5c..2dd5a47 100644
--- a/libutils/include/utils/Singleton.h
+++ b/libutils/include/utils/Singleton.h
@@ -95,7 +95,7 @@
// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
#endif // ANDROID_UTILS_SINGLETON_H
diff --git a/libutils/include/utils/SortedVector.h b/libutils/include/utils/SortedVector.h
index 47c1376..394db12 100644
--- a/libutils/include/utils/SortedVector.h
+++ b/libutils/include/utils/SortedVector.h
@@ -288,8 +288,7 @@
return compare_type( *reinterpret_cast<const TYPE*>(lhs), *reinterpret_cast<const TYPE*>(rhs) );
}
-}; // namespace android
-
+} // namespace android
// ---------------------------------------------------------------------------
diff --git a/libutils/include/utils/StopWatch.h b/libutils/include/utils/StopWatch.h
index 76d78d0..9b14ac8 100644
--- a/libutils/include/utils/StopWatch.h
+++ b/libutils/include/utils/StopWatch.h
@@ -52,9 +52,7 @@
int mNumLaps;
};
-
-}; // namespace android
-
+} // namespace android
// ---------------------------------------------------------------------------
diff --git a/libutils/include/utils/SystemClock.h b/libutils/include/utils/SystemClock.h
index 01db340..f816fba 100644
--- a/libutils/include/utils/SystemClock.h
+++ b/libutils/include/utils/SystemClock.h
@@ -26,7 +26,7 @@
int64_t elapsedRealtime();
int64_t elapsedRealtimeNano();
-}; // namespace android
+} // namespace android
#endif // ANDROID_UTILS_SYSTEMCLOCK_H
diff --git a/libutils/include/utils/Thread.h b/libutils/include/utils/Thread.h
index 598298d..3525138 100644
--- a/libutils/include/utils/Thread.h
+++ b/libutils/include/utils/Thread.h
@@ -110,8 +110,7 @@
#endif
};
-
-}; // namespace android
+} // namespace android
// ---------------------------------------------------------------------------
#endif // _LIBS_UTILS_THREAD_H
diff --git a/libutils/include/utils/ThreadDefs.h b/libutils/include/utils/ThreadDefs.h
index ae091e4..8eb3d1c 100644
--- a/libutils/include/utils/ThreadDefs.h
+++ b/libutils/include/utils/ThreadDefs.h
@@ -66,9 +66,8 @@
};
// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
#endif // __cplusplus
// ---------------------------------------------------------------------------
-
#endif // _LIBS_UTILS_THREAD_DEFS_H
diff --git a/libutils/include/utils/Trace.h b/libutils/include/utils/Trace.h
index 5e9229c..4b9c91e 100644
--- a/libutils/include/utils/Trace.h
+++ b/libutils/include/utils/Trace.h
@@ -49,7 +49,7 @@
uint64_t mTag;
};
-}; // namespace android
+} // namespace android
#else // !__ANDROID__
diff --git a/libutils/include/utils/Vector.h b/libutils/include/utils/Vector.h
index a1a0234..ddf71de 100644
--- a/libutils/include/utils/Vector.h
+++ b/libutils/include/utils/Vector.h
@@ -425,8 +425,7 @@
move_backward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
}
-}; // namespace android
-
+} // namespace android
// ---------------------------------------------------------------------------
diff --git a/libutils/include/utils/VectorImpl.h b/libutils/include/utils/VectorImpl.h
index 4dd91fd..55d5d98 100644
--- a/libutils/include/utils/VectorImpl.h
+++ b/libutils/include/utils/VectorImpl.h
@@ -175,8 +175,7 @@
ssize_t replaceAt(const void* item, size_t index);
};
-}; // namespace android
-
+} // namespace android
// ---------------------------------------------------------------------------
diff --git a/lmkd/README.md b/lmkd/README.md
new file mode 100644
index 0000000..656a6ea
--- /dev/null
+++ b/lmkd/README.md
@@ -0,0 +1,65 @@
+Android Low Memory Killer Daemon
+================================
+
+
+Introduction
+------------
+
+Android Low Memory Killer Daemon (lmkd) is a process monitoring memory
+state of a running Android system and reacting to high memory pressure
+by killing the least essential process(es) to keep system performing
+at acceptable levels.
+
+
+Background
+----------
+
+Historically on Android systems memory monitoring and killing of
+non-essential processes was handled by a kernel lowmemorykiller driver.
+Since Linux Kernel 4.12 the lowmemorykiller driver has been removed and
+instead userspace lmkd daemon performs these tasks.
+
+
+Android Properties
+------------------
+
+lmkd can be configured on a particular system using the following Android
+properties:
+
+ ro.config.low_ram: choose between low-memory vs high-performance
+ device. Default = false.
+
+ ro.lmk.use_minfree_levels: use free memory and file cache thresholds for
+ making decisions when to kill. This mode works
+ the same way kernel lowmemorykiller driver used
+ to work. Default = false
+
+ ro.lmk.low: min oom_adj score for processes eligible to be
+ killed at low vmpressure level. Default = 1001
+ (disabled)
+
+ ro.lmk.medium: min oom_adj score for processes eligible to be
+ killed at medium vmpressure level. Default = 800
+ (non-essential processes)
+
+ ro.lmk.critical: min oom_adj score for processes eligible to be
+ killed at critical vmpressure level. Default = 0
+ (all processes)
+
+ ro.lmk.critical_upgrade: enables upgrade to critical level. Default = false
+
+ ro.lmk.upgrade_pressure: max mem_pressure at which level will be upgraded
+ because system is swapping too much. Default = 100
+ (disabled)
+
+ ro.lmk.downgrade_pressure: min mem_pressure at which vmpressure event will
+ be ignored because enough free memory is still
+ available. Default = 100 (disabled)
+
+ ro.lmk.kill_heaviest_task: kill heaviest eligible task (best decision) vs.
+ any eligible task (fast decision). Default = false
+
+ ro.lmk.kill_timeout_ms: duration in ms after a kill when no additional
+ kill will be done, Default = 0 (disabled)
+
+ ro.lmk.debug: enable lmkd debug logs, Default = false
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index f7c90ec..80711bc 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -65,8 +65,10 @@
#define MEMCG_MEMORY_USAGE "/dev/memcg/memory.usage_in_bytes"
#define MEMCG_MEMORYSW_USAGE "/dev/memcg/memory.memsw.usage_in_bytes"
#define ZONEINFO_PATH "/proc/zoneinfo"
+#define MEMINFO_PATH "/proc/meminfo"
#define LINE_MAX 128
+/* gid containing AID_SYSTEM required */
#define INKERNEL_MINFREE_PATH "/sys/module/lowmemorykiller/parameters/minfree"
#define INKERNEL_ADJ_PATH "/sys/module/lowmemorykiller/parameters/adj"
@@ -94,14 +96,9 @@
"critical"
};
-struct mem_size {
- int free_mem;
- int free_swap;
-};
-
struct {
- int min_free; /* recorded but not used yet */
- int max_free;
+ int64_t min_nr_free_pages; /* recorded but not used yet */
+ int64_t max_nr_free_pages;
} low_pressure_mem = { -1, -1 };
static int level_oomadj[VMPRESS_LEVEL_COUNT];
@@ -110,9 +107,10 @@
static bool enable_pressure_upgrade;
static int64_t upgrade_pressure;
static int64_t downgrade_pressure;
-static bool is_go_device;
+static bool low_ram_device;
static bool kill_heaviest_task;
static unsigned long kill_timeout_ms;
+static bool use_minfree_levels;
/* data required to handle events */
struct event_handler_info {
@@ -149,11 +147,84 @@
static int lowmem_minfree[MAX_TARGETS];
static int lowmem_targets_size;
-struct sysmeminfo {
- int nr_free_pages;
- int nr_file_pages;
- int nr_shmem;
- int totalreserve_pages;
+/* Fields to parse in /proc/zoneinfo */
+enum zoneinfo_field {
+ ZI_NR_FREE_PAGES = 0,
+ ZI_NR_FILE_PAGES,
+ ZI_NR_SHMEM,
+ ZI_NR_UNEVICTABLE,
+ ZI_WORKINGSET_REFAULT,
+ ZI_HIGH,
+ ZI_FIELD_COUNT
+};
+
+static const char* const zoneinfo_field_names[ZI_FIELD_COUNT] = {
+ "nr_free_pages",
+ "nr_file_pages",
+ "nr_shmem",
+ "nr_unevictable",
+ "workingset_refault",
+ "high",
+};
+
+union zoneinfo {
+ struct {
+ int64_t nr_free_pages;
+ int64_t nr_file_pages;
+ int64_t nr_shmem;
+ int64_t nr_unevictable;
+ int64_t workingset_refault;
+ int64_t high;
+ /* fields below are calculated rather than read from the file */
+ int64_t totalreserve_pages;
+ } field;
+ int64_t arr[ZI_FIELD_COUNT];
+};
+
+/* Fields to parse in /proc/meminfo */
+enum meminfo_field {
+ MI_NR_FREE_PAGES = 0,
+ MI_CACHED,
+ MI_SWAP_CACHED,
+ MI_BUFFERS,
+ MI_SHMEM,
+ MI_UNEVICTABLE,
+ MI_FREE_SWAP,
+ MI_DIRTY,
+ MI_FIELD_COUNT
+};
+
+static const char* const meminfo_field_names[MI_FIELD_COUNT] = {
+ "MemFree:",
+ "Cached:",
+ "SwapCached:",
+ "Buffers:",
+ "Shmem:",
+ "Unevictable:",
+ "SwapFree:",
+ "Dirty:",
+};
+
+union meminfo {
+ struct {
+ int64_t nr_free_pages;
+ int64_t cached;
+ int64_t swap_cached;
+ int64_t buffers;
+ int64_t shmem;
+ int64_t unevictable;
+ int64_t free_swap;
+ int64_t dirty;
+ /* fields below are calculated rather than read from the file */
+ int64_t nr_file_pages;
+ } field;
+ int64_t arr[MI_FIELD_COUNT];
+};
+
+enum field_match_result {
+ NO_MATCH,
+ PARSE_FAIL,
+ PARSE_SUCCESS
};
struct adjslot_list {
@@ -169,6 +240,11 @@
struct proc *pidhash_next;
};
+struct reread_data {
+ const char* const filename;
+ int fd;
+};
+
#define PIDHASH_SZ 1024
static struct proc *pidhash[PIDHASH_SZ];
#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
@@ -179,12 +255,43 @@
/* PAGE_SIZE / 1024 */
static long page_k;
+static bool parse_int64(const char* str, int64_t* ret) {
+ char* endptr;
+ long long val = strtoll(str, &endptr, 10);
+ if (str == endptr || val > INT64_MAX) {
+ return false;
+ }
+ *ret = (int64_t)val;
+ return true;
+}
+
+static enum field_match_result match_field(const char* cp, const char* ap,
+ const char* const field_names[],
+ int field_count, int64_t* field,
+ int *field_idx) {
+ int64_t val;
+ int i;
+
+ for (i = 0; i < field_count; i++) {
+ if (!strcmp(cp, field_names[i])) {
+ *field_idx = i;
+ return parse_int64(ap, field) ? PARSE_SUCCESS : PARSE_FAIL;
+ }
+ }
+ return NO_MATCH;
+}
+
+/*
+ * Read file content from the beginning up to max_len bytes or EOF
+ * whichever happens first.
+ */
static ssize_t read_all(int fd, char *buf, size_t max_len)
{
ssize_t ret = 0;
+ off_t offset = 0;
while (max_len > 0) {
- ssize_t r = read(fd, buf, max_len);
+ ssize_t r = TEMP_FAILURE_RETRY(pread(fd, buf, max_len, offset));
if (r == 0) {
break;
}
@@ -193,12 +300,44 @@
}
ret += r;
buf += r;
+ offset += r;
max_len -= r;
}
return ret;
}
+/*
+ * Read a new or already opened file from the beginning.
+ * If the file has not been opened yet data->fd should be set to -1.
+ * To be used with files which are read often and possibly during high
+ * memory pressure to minimize file opening which by itself requires kernel
+ * memory allocation and might result in a stall on memory stressed system.
+ */
+static int reread_file(struct reread_data *data, char *buf, size_t buf_size) {
+ ssize_t size;
+
+ if (data->fd == -1) {
+ data->fd = open(data->filename, O_RDONLY | O_CLOEXEC);
+ if (data->fd == -1) {
+ ALOGE("%s open: %s", data->filename, strerror(errno));
+ return -1;
+ }
+ }
+
+ size = read_all(data->fd, buf, buf_size - 1);
+ if (size < 0) {
+ ALOGE("%s read: %s", data->filename, strerror(errno));
+ close(data->fd);
+ data->fd = -1;
+ return -1;
+ }
+ ALOG_ASSERT((size_t)size < buf_size - 1, data->filename " too large");
+ buf[size] = 0;
+
+ return 0;
+}
+
static struct proc *pid_lookup(int pid) {
struct proc *procp;
@@ -317,6 +456,9 @@
return;
}
+ /* gid containing AID_READPROC required */
+ /* CAP_SYS_RESOURCE required */
+ /* CAP_DAC_OVERRIDE required */
snprintf(path, sizeof(path), "/proc/%d/oom_score_adj", params.pid);
snprintf(val, sizeof(val), "%d", params.oomadj);
if (!writefilestring(path, val, false)) {
@@ -358,8 +500,7 @@
soft_limit_mult = 64;
}
- snprintf(path, sizeof(path),
- "/dev/memcg/apps/uid_%d/pid_%d/memory.soft_limit_in_bytes",
+ snprintf(path, sizeof(path), MEMCG_SYSFS_PATH "apps/uid_%d/pid_%d/memory.soft_limit_in_bytes",
params.uid, params.pid);
snprintf(val, sizeof(val), "%d", soft_limit_mult * EIGHT_MEGA);
@@ -460,7 +601,7 @@
static int ctrl_data_read(int dsock_idx, char *buf, size_t bufsz) {
int ret = 0;
- ret = read(data_sock[dsock_idx].sock, buf, bufsz);
+ ret = TEMP_FAILURE_RETRY(read(data_sock[dsock_idx].sock, buf, bufsz));
if (ret == -1) {
ALOGE("control data socket read failed; errno=%d", errno);
@@ -574,84 +715,141 @@
maxevents++;
}
-static int zoneinfo_parse_protection(char *cp) {
- int max = 0;
- int zoneval;
+/* /prop/zoneinfo parsing routines */
+static int64_t zoneinfo_parse_protection(char *cp) {
+ int64_t max = 0;
+ long long zoneval;
char *save_ptr;
- for (cp = strtok_r(cp, "(), ", &save_ptr); cp; cp = strtok_r(NULL, "), ", &save_ptr)) {
- zoneval = strtol(cp, &cp, 0);
- if (zoneval > max)
- max = zoneval;
+ for (cp = strtok_r(cp, "(), ", &save_ptr); cp;
+ cp = strtok_r(NULL, "), ", &save_ptr)) {
+ zoneval = strtoll(cp, &cp, 0);
+ if (zoneval > max) {
+ max = (zoneval > INT64_MAX) ? INT64_MAX : zoneval;
+ }
}
return max;
}
-static void zoneinfo_parse_line(char *line, struct sysmeminfo *mip) {
+static bool zoneinfo_parse_line(char *line, union zoneinfo *zi) {
char *cp = line;
char *ap;
char *save_ptr;
+ int64_t val;
+ int field_idx;
cp = strtok_r(line, " ", &save_ptr);
- if (!cp)
- return;
+ if (!cp) {
+ return true;
+ }
- ap = strtok_r(NULL, " ", &save_ptr);
- if (!ap)
- return;
+ if (!strcmp(cp, "protection:")) {
+ ap = strtok_r(NULL, ")", &save_ptr);
+ } else {
+ ap = strtok_r(NULL, " ", &save_ptr);
+ }
- if (!strcmp(cp, "nr_free_pages"))
- mip->nr_free_pages += strtol(ap, NULL, 0);
- else if (!strcmp(cp, "nr_file_pages"))
- mip->nr_file_pages += strtol(ap, NULL, 0);
- else if (!strcmp(cp, "nr_shmem"))
- mip->nr_shmem += strtol(ap, NULL, 0);
- else if (!strcmp(cp, "high"))
- mip->totalreserve_pages += strtol(ap, NULL, 0);
- else if (!strcmp(cp, "protection:"))
- mip->totalreserve_pages += zoneinfo_parse_protection(ap);
+ if (!ap) {
+ return true;
+ }
+
+ switch (match_field(cp, ap, zoneinfo_field_names,
+ ZI_FIELD_COUNT, &val, &field_idx)) {
+ case (PARSE_SUCCESS):
+ zi->arr[field_idx] += val;
+ break;
+ case (NO_MATCH):
+ if (!strcmp(cp, "protection:")) {
+ zi->field.totalreserve_pages +=
+ zoneinfo_parse_protection(ap);
+ }
+ break;
+ case (PARSE_FAIL):
+ default:
+ return false;
+ }
+ return true;
}
-static int zoneinfo_parse(struct sysmeminfo *mip) {
- int fd;
- ssize_t size;
+static int zoneinfo_parse(union zoneinfo *zi) {
+ static struct reread_data file_data = {
+ .filename = ZONEINFO_PATH,
+ .fd = -1,
+ };
char buf[PAGE_SIZE];
char *save_ptr;
char *line;
- memset(mip, 0, sizeof(struct sysmeminfo));
+ memset(zi, 0, sizeof(union zoneinfo));
- fd = open(ZONEINFO_PATH, O_RDONLY | O_CLOEXEC);
- if (fd == -1) {
- ALOGE("%s open: errno=%d", ZONEINFO_PATH, errno);
+ if (reread_file(&file_data, buf, sizeof(buf)) < 0) {
return -1;
}
- size = read_all(fd, buf, sizeof(buf) - 1);
- if (size < 0) {
- ALOGE("%s read: errno=%d", ZONEINFO_PATH, errno);
- close(fd);
- return -1;
+ for (line = strtok_r(buf, "\n", &save_ptr); line;
+ line = strtok_r(NULL, "\n", &save_ptr)) {
+ if (!zoneinfo_parse_line(line, zi)) {
+ ALOGE("%s parse error", file_data.filename);
+ return -1;
+ }
}
- ALOG_ASSERT((size_t)size < sizeof(buf) - 1, "/proc/zoneinfo too large");
- buf[size] = 0;
+ zi->field.totalreserve_pages += zi->field.high;
- for (line = strtok_r(buf, "\n", &save_ptr); line; line = strtok_r(NULL, "\n", &save_ptr))
- zoneinfo_parse_line(line, mip);
-
- close(fd);
return 0;
}
-static int get_free_memory(struct mem_size *ms) {
- struct sysinfo si;
+/* /prop/meminfo parsing routines */
+static bool meminfo_parse_line(char *line, union meminfo *mi) {
+ char *cp = line;
+ char *ap;
+ char *save_ptr;
+ int64_t val;
+ int field_idx;
+ enum field_match_result match_res;
- if (sysinfo(&si) < 0)
+ cp = strtok_r(line, " ", &save_ptr);
+ if (!cp) {
+ return false;
+ }
+
+ ap = strtok_r(NULL, " ", &save_ptr);
+ if (!ap) {
+ return false;
+ }
+
+ match_res = match_field(cp, ap, meminfo_field_names, MI_FIELD_COUNT,
+ &val, &field_idx);
+ if (match_res == PARSE_SUCCESS) {
+ mi->arr[field_idx] = val / page_k;
+ }
+ return (match_res != PARSE_FAIL);
+}
+
+static int meminfo_parse(union meminfo *mi) {
+ static struct reread_data file_data = {
+ .filename = MEMINFO_PATH,
+ .fd = -1,
+ };
+ char buf[PAGE_SIZE];
+ char *save_ptr;
+ char *line;
+
+ memset(mi, 0, sizeof(union meminfo));
+
+ if (reread_file(&file_data, buf, sizeof(buf)) < 0) {
return -1;
+ }
- ms->free_mem = (int)(si.freeram * si.mem_unit / PAGE_SIZE);
- ms->free_swap = (int)(si.freeswap * si.mem_unit / PAGE_SIZE);
+ for (line = strtok_r(buf, "\n", &save_ptr); line;
+ line = strtok_r(NULL, "\n", &save_ptr)) {
+ if (!meminfo_parse_line(line, mi)) {
+ ALOGE("%s parse error", file_data.filename);
+ return -1;
+ }
+ }
+ mi->field.nr_file_pages = mi->field.cached + mi->field.swap_cached +
+ mi->field.buffers;
return 0;
}
@@ -664,6 +862,7 @@
int total;
ssize_t ret;
+ /* gid containing AID_READPROC required */
snprintf(path, PATH_MAX, "/proc/%d/statm", pid);
fd = open(path, O_RDONLY | O_CLOEXEC);
if (fd == -1)
@@ -687,6 +886,7 @@
char *cp;
ssize_t ret;
+ /* gid containing AID_READPROC required */
snprintf(path, PATH_MAX, "/proc/%d/cmdline", pid);
fd = open(path, O_RDONLY | O_CLOEXEC);
if (fd == -1)
@@ -754,6 +954,7 @@
TRACE_KILL_START(pid);
+ /* CAP_KILL required */
r = kill(pid, SIGKILL);
ALOGI(
"Killing '%s' (%d), uid %d, adj %d\n"
@@ -778,20 +979,17 @@
* Returns the size of the killed processes.
*/
static int find_and_kill_processes(enum vmpressure_level level,
- int pages_to_free) {
+ int min_score_adj, int pages_to_free) {
int i;
int killed_size;
int pages_freed = 0;
- int min_score_adj = level_oomadj[level];
for (i = OOM_SCORE_ADJ_MAX; i >= min_score_adj; i--) {
struct proc *procp;
while (true) {
- if (is_go_device)
- procp = proc_adj_lru(i);
- else
- procp = proc_get_heaviest(i);
+ procp = kill_heaviest_task ?
+ proc_get_heaviest(i) : proc_adj_lru(i);
if (!procp)
break;
@@ -809,23 +1007,19 @@
return pages_freed;
}
-static int64_t get_memory_usage(const char* path) {
+static int64_t get_memory_usage(struct reread_data *file_data) {
int ret;
int64_t mem_usage;
char buf[32];
- int fd = open(path, O_RDONLY | O_CLOEXEC);
- if (fd == -1) {
- ALOGE("%s open: errno=%d", path, errno);
+
+ if (reread_file(file_data, buf, sizeof(buf)) < 0) {
return -1;
}
- ret = read_all(fd, buf, sizeof(buf) - 1);
- close(fd);
- if (ret < 0) {
- ALOGE("%s error: errno=%d", path, errno);
+ if (!parse_int64(buf, &mem_usage)) {
+ ALOGE("%s parse error", file_data->filename);
return -1;
}
- sscanf(buf, "%" SCNd64, &mem_usage);
if (mem_usage == 0) {
ALOGE("No memory!");
return -1;
@@ -833,29 +1027,30 @@
return mem_usage;
}
-void record_low_pressure_levels(struct mem_size *free_mem) {
- if (low_pressure_mem.min_free == -1 ||
- low_pressure_mem.min_free > free_mem->free_mem) {
+void record_low_pressure_levels(union meminfo *mi) {
+ if (low_pressure_mem.min_nr_free_pages == -1 ||
+ low_pressure_mem.min_nr_free_pages > mi->field.nr_free_pages) {
if (debug_process_killing) {
- ALOGI("Low pressure min memory update from %d to %d",
- low_pressure_mem.min_free, free_mem->free_mem);
+ ALOGI("Low pressure min memory update from %" PRId64 " to %" PRId64,
+ low_pressure_mem.min_nr_free_pages, mi->field.nr_free_pages);
}
- low_pressure_mem.min_free = free_mem->free_mem;
+ low_pressure_mem.min_nr_free_pages = mi->field.nr_free_pages;
}
/*
* Free memory at low vmpressure events occasionally gets spikes,
* possibly a stale low vmpressure event with memory already
* freed up (no memory pressure should have been reported).
- * Ignore large jumps in max_free that would mess up our stats.
+ * Ignore large jumps in max_nr_free_pages that would mess up our stats.
*/
- if (low_pressure_mem.max_free == -1 ||
- (low_pressure_mem.max_free < free_mem->free_mem &&
- free_mem->free_mem - low_pressure_mem.max_free < low_pressure_mem.max_free * 0.1)) {
+ if (low_pressure_mem.max_nr_free_pages == -1 ||
+ (low_pressure_mem.max_nr_free_pages < mi->field.nr_free_pages &&
+ mi->field.nr_free_pages - low_pressure_mem.max_nr_free_pages <
+ low_pressure_mem.max_nr_free_pages * 0.1)) {
if (debug_process_killing) {
- ALOGI("Low pressure max memory update from %d to %d",
- low_pressure_mem.max_free, free_mem->free_mem);
+ ALOGI("Low pressure max memory update from %" PRId64 " to %" PRId64,
+ low_pressure_mem.max_nr_free_pages, mi->field.nr_free_pages);
}
- low_pressure_mem.max_free = free_mem->free_mem;
+ low_pressure_mem.max_nr_free_pages = mi->field.nr_free_pages;
}
}
@@ -881,10 +1076,23 @@
int64_t mem_usage, memsw_usage;
int64_t mem_pressure;
enum vmpressure_level lvl;
- struct mem_size free_mem;
+ union meminfo mi;
+ union zoneinfo zi;
static struct timeval last_report_tm;
static unsigned long skip_count = 0;
enum vmpressure_level level = (enum vmpressure_level)data;
+ long other_free = 0, other_file = 0;
+ int min_score_adj;
+ int pages_to_free = 0;
+ int minfree = 0;
+ static struct reread_data mem_usage_file_data = {
+ .filename = MEMCG_MEMORY_USAGE,
+ .fd = -1,
+ };
+ static struct reread_data memsw_usage_file_data = {
+ .filename = MEMCG_MEMORYSW_USAGE,
+ .fd = -1,
+ };
/*
* Check all event counters from low to critical
@@ -893,7 +1101,8 @@
*/
for (lvl = VMPRESS_LEVEL_LOW; lvl < VMPRESS_LEVEL_COUNT; lvl++) {
if (mpevfd[lvl] != -1 &&
- read(mpevfd[lvl], &evcount, sizeof(evcount)) > 0 &&
+ TEMP_FAILURE_RETRY(read(mpevfd[lvl],
+ &evcount, sizeof(evcount))) > 0 &&
evcount > 0 && lvl > level) {
level = lvl;
}
@@ -916,23 +1125,53 @@
skip_count = 0;
}
- if (get_free_memory(&free_mem) == 0) {
- if (level == VMPRESS_LEVEL_LOW) {
- record_low_pressure_levels(&free_mem);
- }
- } else {
+ if (meminfo_parse(&mi) < 0 || zoneinfo_parse(&zi) < 0) {
ALOGE("Failed to get free memory!");
return;
}
+ if (use_minfree_levels) {
+ int i;
+
+ other_free = mi.field.nr_free_pages - zi.field.totalreserve_pages;
+ if (mi.field.nr_file_pages > (mi.field.shmem + mi.field.unevictable + mi.field.swap_cached)) {
+ other_file = (mi.field.nr_file_pages - mi.field.shmem -
+ mi.field.unevictable - mi.field.swap_cached);
+ } else {
+ other_file = 0;
+ }
+
+ min_score_adj = OOM_SCORE_ADJ_MAX + 1;
+ for (i = 0; i < lowmem_targets_size; i++) {
+ minfree = lowmem_minfree[i];
+ if (other_free < minfree && other_file < minfree) {
+ min_score_adj = lowmem_adj[i];
+ break;
+ }
+ }
+
+ if (min_score_adj == OOM_SCORE_ADJ_MAX + 1)
+ return;
+
+ /* Free up enough pages to push over the highest minfree level */
+ pages_to_free = lowmem_minfree[lowmem_targets_size - 1] -
+ ((other_free < other_file) ? other_free : other_file);
+ goto do_kill;
+ }
+
+ if (level == VMPRESS_LEVEL_LOW) {
+ record_low_pressure_levels(&mi);
+ }
+
if (level_oomadj[level] > OOM_SCORE_ADJ_MAX) {
/* Do not monitor this pressure level */
return;
}
- mem_usage = get_memory_usage(MEMCG_MEMORY_USAGE);
- memsw_usage = get_memory_usage(MEMCG_MEMORYSW_USAGE);
- if (memsw_usage < 0 || mem_usage < 0) {
+ if ((mem_usage = get_memory_usage(&mem_usage_file_data)) < 0) {
+ goto do_kill;
+ }
+ if ((memsw_usage = get_memory_usage(&memsw_usage_file_data)) < 0) {
goto do_kill;
}
@@ -966,37 +1205,60 @@
}
do_kill:
- if (is_go_device) {
+ if (low_ram_device) {
/* For Go devices kill only one task */
- if (find_and_kill_processes(level, 0) == 0) {
+ if (find_and_kill_processes(level, level_oomadj[level], 0) == 0) {
if (debug_process_killing) {
ALOGI("Nothing to kill");
}
}
} else {
- /* If pressure level is less than critical and enough free swap then ignore */
- if (level < VMPRESS_LEVEL_CRITICAL && free_mem.free_swap > low_pressure_mem.max_free) {
- if (debug_process_killing) {
- ALOGI("Ignoring pressure since %d swap pages are available ", free_mem.free_swap);
+ int pages_freed;
+
+ if (!use_minfree_levels) {
+ /* If pressure level is less than critical and enough free swap then ignore */
+ if (level < VMPRESS_LEVEL_CRITICAL &&
+ mi.field.free_swap > low_pressure_mem.max_nr_free_pages) {
+ if (debug_process_killing) {
+ ALOGI("Ignoring pressure since %" PRId64
+ " swap pages are available ",
+ mi.field.free_swap);
+ }
+ return;
}
- return;
+ /* Free up enough memory to downgrate the memory pressure to low level */
+ if (mi.field.nr_free_pages < low_pressure_mem.max_nr_free_pages) {
+ pages_to_free = low_pressure_mem.max_nr_free_pages -
+ mi.field.nr_free_pages;
+ } else {
+ if (debug_process_killing) {
+ ALOGI("Ignoring pressure since more memory is "
+ "available (%" PRId64 ") than watermark (%" PRId64 ")",
+ mi.field.nr_free_pages, low_pressure_mem.max_nr_free_pages);
+ }
+ return;
+ }
+ min_score_adj = level_oomadj[level];
+ } else {
+ if (debug_process_killing) {
+ ALOGI("Killing because cache %ldkB is below "
+ "limit %ldkB for oom_adj %d\n"
+ " Free memory is %ldkB %s reserved",
+ other_file * page_k, minfree * page_k, min_score_adj,
+ other_free * page_k, other_free >= 0 ? "above" : "below");
+ }
}
- /* Free up enough memory to downgrate the memory pressure to low level */
- if (free_mem.free_mem < low_pressure_mem.max_free) {
- int pages_to_free = low_pressure_mem.max_free - free_mem.free_mem;
+ if (debug_process_killing) {
+ ALOGI("Trying to free %d pages", pages_to_free);
+ }
+ pages_freed = find_and_kill_processes(level, min_score_adj, pages_to_free);
+ if (pages_freed < pages_to_free) {
if (debug_process_killing) {
- ALOGI("Trying to free %d pages", pages_to_free);
+ ALOGI("Unable to free enough memory (pages freed=%d)", pages_freed);
}
- int pages_freed = find_and_kill_processes(level, pages_to_free);
- if (pages_freed < pages_to_free) {
- if (debug_process_killing) {
- ALOGI("Unable to free enough memory (pages freed=%d)",
- pages_freed);
- }
- } else {
- gettimeofday(&last_report_tm, NULL);
- }
+ } else {
+ gettimeofday(&last_report_tm, NULL);
}
}
}
@@ -1011,6 +1273,7 @@
int level_idx = (int)level;
const char *levelstr = level_name[level_idx];
+ /* gid containing AID_SYSTEM required */
mpfd = open(MEMCG_SYSFS_PATH "memory.pressure_level", O_RDONLY | O_CLOEXEC);
if (mpfd < 0) {
ALOGI("No kernel memory.pressure_level support (errno=%d)", errno);
@@ -1202,10 +1465,12 @@
downgrade_pressure =
(int64_t)property_get_int32("ro.lmk.downgrade_pressure", 100);
kill_heaviest_task =
- property_get_bool("ro.lmk.kill_heaviest_task", true);
- is_go_device = property_get_bool("ro.config.low_ram", false);
+ property_get_bool("ro.lmk.kill_heaviest_task", false);
+ low_ram_device = property_get_bool("ro.config.low_ram", false);
kill_timeout_ms =
(unsigned long)property_get_int32("ro.lmk.kill_timeout_ms", 0);
+ use_minfree_levels =
+ property_get_bool("ro.lmk.use_minfree_levels", false);
if (!init()) {
if (!use_inkernel_interface) {
@@ -1220,11 +1485,15 @@
* pins ⊆ MCL_CURRENT, converging to just MCL_CURRENT as we fault
* in pages.
*/
+ /* CAP_IPC_LOCK required */
if (mlockall(MCL_CURRENT | MCL_FUTURE | MCL_ONFAULT) && (errno != EINVAL)) {
ALOGW("mlockall failed %s", strerror(errno));
}
- sched_setscheduler(0, SCHED_FIFO, ¶m);
+ /* CAP_NICE required */
+ if (sched_setscheduler(0, SCHED_FIFO, ¶m)) {
+ ALOGW("set SCHED_FIFO failed %s", strerror(errno));
+ }
}
mainloop();
diff --git a/lmkd/lmkd.rc b/lmkd/lmkd.rc
index 3bb84ab..76b6055 100644
--- a/lmkd/lmkd.rc
+++ b/lmkd/lmkd.rc
@@ -1,6 +1,8 @@
service lmkd /system/bin/lmkd
class core
- group root readproc
+ user lmkd
+ group lmkd system readproc
+ capabilities DAC_OVERRIDE KILL IPC_LOCK SYS_NICE SYS_RESOURCE
critical
socket lmkd seqpacket 0660 system system
writepid /dev/cpuset/system-background/tasks
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 1462570..d3504ad 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -21,9 +21,6 @@
# Set the security context of /adb_keys if present.
restorecon /adb_keys
- # Shouldn't be necessary, but sdcard won't start without it. http://b/22568628.
- mkdir /mnt 0775 root system
-
# Set the security context of /postinstall if present.
restorecon /postinstall
@@ -34,6 +31,9 @@
# root memory control cgroup, used by lmkd
mkdir /dev/memcg 0700 root system
mount cgroup none /dev/memcg nodev noexec nosuid memory
+ # memory.pressure_level used by lmkd
+ chown root system /dev/memcg/memory.pressure_level
+ chmod 0040 /dev/memcg/memory.pressure_level
# app mem cgroups, used by activity manager, lmkd and zygote
mkdir /dev/memcg/apps/ 0755 system system
# cgroup for system_server and surfaceflinger
@@ -80,9 +80,6 @@
chmod 0664 /dev/stune/top-app/tasks
chmod 0664 /dev/stune/rt/tasks
- # Mount staging areas for devices managed by vold
- # See storage config details at http://source.android.com/tech/storage/
- mount tmpfs tmpfs /mnt nodev noexec nosuid mode=0755,uid=0,gid=1000
restorecon_recursive /mnt
mount configfs none /config nodev noexec nosuid
@@ -509,6 +506,7 @@
mkdir /data/ss 0700 system system
mkdir /data/system 0775 system system
+ mkdir /data/system/dropbox 0700 system system
mkdir /data/system/heapdump 0700 system system
mkdir /data/system/users 0775 system system
diff --git a/storaged/OWNERS b/storaged/OWNERS
index c6feee8..d033f00 100644
--- a/storaged/OWNERS
+++ b/storaged/OWNERS
@@ -1,2 +1,2 @@
-jinqian@google.com
salyzyn@google.com
+dvander@google.com
diff --git a/storaged/storaged.rc b/storaged/storaged.rc
index a24c7fb..ed2cf14 100644
--- a/storaged/storaged.rc
+++ b/storaged/storaged.rc
@@ -1,5 +1,6 @@
service storaged /system/bin/storaged
class main
+ capabilities DAC_READ_SEARCH
priority 10
file /d/mmc0/mmc0:0001/ext_csd r
writepid /dev/cpuset/system-background/tasks