Merge "Add fiemap_writer_test to VTS."
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 3c07882..e417f05 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -1114,7 +1114,7 @@
return true;
}
return false;
- });
+ }, true);
if (!response.empty()) {
response.resize(response.size() - 1);
}
@@ -1229,7 +1229,7 @@
std::string response;
atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &response, true);
if (t != nullptr) {
- kick_transport(t);
+ kick_transport(t, true);
response =
"reconnecting " + t->serial_name() + " [" + t->connection_state_name() + "]\n";
}
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 6960345..9791769 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -312,7 +312,7 @@
std::string android_dir = user_dir + OS_PATH_SEPARATOR + ".android";
struct stat buf;
if (stat(android_dir.c_str(), &buf) == -1) {
- if (adb_mkdir(android_dir.c_str(), 0750) == -1) {
+ if (adb_mkdir(android_dir, 0750) == -1) {
PLOG(FATAL) << "Cannot mkdir '" << android_dir << "'";
}
}
diff --git a/adb/bugreport_test.cpp b/adb/bugreport_test.cpp
index 72ca59a..a6be203 100644
--- a/adb/bugreport_test.cpp
+++ b/adb/bugreport_test.cpp
@@ -136,7 +136,7 @@
void ExpectBugreportzVersion(const std::string& version) {
EXPECT_CALL(br_, SendShellCommand("bugreportz -v", false, _))
- .WillOnce(DoAll(WithArg<2>(WriteOnStderr(version.c_str())),
+ .WillOnce(DoAll(WithArg<2>(WriteOnStderr(version)),
WithArg<2>(ReturnCallbackDone(0))));
}
diff --git a/adb/client/auth.cpp b/adb/client/auth.cpp
index bcb829b..3eee426 100644
--- a/adb/client/auth.cpp
+++ b/adb/client/auth.cpp
@@ -416,7 +416,7 @@
#endif
for (const std::string& path : key_paths) {
- load_keys(path.c_str());
+ load_keys(path);
}
}
diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp
index 7e470e1..5d10238 100644
--- a/adb/client/file_sync_client.cpp
+++ b/adb/client/file_sync_client.cpp
@@ -1012,7 +1012,7 @@
dst_dir.append(android::base::Basename(src_path));
}
- success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(), sync, false);
+ success &= copy_local_dir_remote(sc, src_path, dst_dir, sync, false);
continue;
} else if (!should_push_file(st.st_mode)) {
sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, st.st_mode);
@@ -1128,7 +1128,7 @@
// Recursively build the list of files to copy.
sc.Printf("pull: building file list...");
std::vector<copyinfo> file_list;
- if (!remote_build_list(sc, &file_list, rpath.c_str(), lpath.c_str())) {
+ if (!remote_build_list(sc, &file_list, rpath, lpath)) {
return false;
}
@@ -1240,7 +1240,7 @@
dst_dir.append(android::base::Basename(src_path));
}
- success &= copy_remote_dir_local(sc, src_path, dst_dir.c_str(), copy_attrs);
+ success &= copy_remote_dir_local(sc, src_path, dst_dir, copy_attrs);
continue;
} else if (!should_pull_file(src_st.st_mode)) {
sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, src_st.st_mode);
diff --git a/adb/client/usb_dispatch.cpp b/adb/client/usb_dispatch.cpp
index ce57731..f55ae90 100644
--- a/adb/client/usb_dispatch.cpp
+++ b/adb/client/usb_dispatch.cpp
@@ -52,6 +52,11 @@
: native::usb_close(reinterpret_cast<native::usb_handle*>(h));
}
+void usb_reset(usb_handle* h) {
+ should_use_libusb() ? libusb::usb_reset(reinterpret_cast<libusb::usb_handle*>(h))
+ : native::usb_reset(reinterpret_cast<native::usb_handle*>(h));
+}
+
void usb_kick(usb_handle* h) {
should_use_libusb() ? libusb::usb_kick(reinterpret_cast<libusb::usb_handle*>(h))
: native::usb_kick(reinterpret_cast<native::usb_handle*>(h));
diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp
index f2ca63b..53f01a0 100644
--- a/adb/client/usb_libusb.cpp
+++ b/adb/client/usb_libusb.cpp
@@ -622,6 +622,11 @@
return 0;
}
+void usb_reset(usb_handle* h) {
+ libusb_reset_device(h->device_handle);
+ usb_kick(h);
+}
+
void usb_kick(usb_handle* h) {
h->Close();
}
diff --git a/adb/client/usb_linux.cpp b/adb/client/usb_linux.cpp
index 1168958..81b8306 100644
--- a/adb/client/usb_linux.cpp
+++ b/adb/client/usb_linux.cpp
@@ -458,6 +458,11 @@
return orig_len - len;
}
+void usb_reset(usb_handle* h) {
+ ioctl(h->fd, USBDEVFS_RESET);
+ usb_kick(h);
+}
+
void usb_kick(usb_handle* h) {
std::lock_guard<std::mutex> lock(h->mutex);
D("[ kicking %p (fd = %d) ]", h, h->fd);
diff --git a/adb/client/usb_osx.cpp b/adb/client/usb_osx.cpp
index e380c84..5c0da47 100644
--- a/adb/client/usb_osx.cpp
+++ b/adb/client/usb_osx.cpp
@@ -556,6 +556,11 @@
return 0;
}
+void usb_reset(usb_handle* handle) {
+ // Unimplemented on OS X.
+ usb_kick(handle);
+}
+
static void usb_kick_locked(usb_handle *handle)
{
LOG(INFO) << "Kicking handle";
diff --git a/adb/client/usb_windows.cpp b/adb/client/usb_windows.cpp
index cfa5cf4..f23c3a5 100644
--- a/adb/client/usb_windows.cpp
+++ b/adb/client/usb_windows.cpp
@@ -448,6 +448,11 @@
}
}
+void usb_reset(usb_handle* handle) {
+ // Unimplemented on Windows.
+ usb_kick(handle);
+}
+
static void usb_kick_locked(usb_handle* handle) {
// The reason the lock must be acquired before calling this function is in
// case multiple threads are trying to kick the same device at the same time.
diff --git a/adb/daemon/file_sync_service.cpp b/adb/daemon/file_sync_service.cpp
index 29bd798..e82a51f 100644
--- a/adb/daemon/file_sync_service.cpp
+++ b/adb/daemon/file_sync_service.cpp
@@ -422,7 +422,7 @@
bool result;
uint32_t timestamp;
if (S_ISLNK(mode)) {
- result = handle_send_link(s, path.c_str(), ×tamp, buffer);
+ result = handle_send_link(s, path, ×tamp, buffer);
} else {
// Copy user permission bits to "group" and "other" permissions.
mode &= 0777;
diff --git a/adb/daemon/shell_service.cpp b/adb/daemon/shell_service.cpp
index e9d9c63..3c8f393 100644
--- a/adb/daemon/shell_service.cpp
+++ b/adb/daemon/shell_service.cpp
@@ -406,11 +406,16 @@
strerror(errno));
return false;
}
- // Raw subprocess + shell protocol allows for splitting stderr.
- if (!CreateSocketpair(&stderr_sfd_, &child_stderr_sfd)) {
- *error = android::base::StringPrintf("failed to create socketpair for stderr: %s",
- strerror(errno));
- return false;
+ if (protocol_ == SubprocessProtocol::kShell) {
+ // Shell protocol allows for splitting stderr.
+ if (!CreateSocketpair(&stderr_sfd_, &child_stderr_sfd)) {
+ *error = android::base::StringPrintf("failed to create socketpair for stderr: %s",
+ strerror(errno));
+ return false;
+ }
+ } else {
+ // Raw protocol doesn't support multiple output streams, so combine stdout and stderr.
+ child_stderr_sfd.reset(dup(child_stdinout_sfd));
}
D("execinprocess: stdin/stdout FD = %d, stderr FD = %d", stdinout_sfd_.get(),
diff --git a/adb/daemon/shell_service_test.cpp b/adb/daemon/shell_service_test.cpp
index 323bcec..dc79d12 100644
--- a/adb/daemon/shell_service_test.cpp
+++ b/adb/daemon/shell_service_test.cpp
@@ -35,7 +35,6 @@
static void SetUpTestCase() {
// This is normally done in main.cpp.
saved_sigpipe_handler_ = signal(SIGPIPE, SIG_IGN);
-
}
static void TearDownTestCase() {
@@ -49,26 +48,32 @@
SubprocessProtocol protocol);
void CleanupTestSubprocess();
- virtual void TearDown() override {
- void CleanupTestSubprocess();
- }
+ void StartTestCommandInProcess(std::string name, Command command, SubprocessProtocol protocol);
+
+ virtual void TearDown() override { CleanupTestSubprocess(); }
static sighandler_t saved_sigpipe_handler_;
- unique_fd subprocess_fd_;
+ unique_fd command_fd_;
};
sighandler_t ShellServiceTest::saved_sigpipe_handler_ = nullptr;
void ShellServiceTest::StartTestSubprocess(
const char* command, SubprocessType type, SubprocessProtocol protocol) {
- subprocess_fd_ = StartSubprocess(command, nullptr, type, protocol);
- ASSERT_TRUE(subprocess_fd_ >= 0);
+ command_fd_ = StartSubprocess(command, nullptr, type, protocol);
+ ASSERT_TRUE(command_fd_ >= 0);
}
void ShellServiceTest::CleanupTestSubprocess() {
}
+void ShellServiceTest::StartTestCommandInProcess(std::string name, Command command,
+ SubprocessProtocol protocol) {
+ command_fd_ = StartCommandInProcess(std::move(name), std::move(command), protocol);
+ ASSERT_TRUE(command_fd_ >= 0);
+}
+
namespace {
// Reads raw data from |fd| until it closes or errors.
@@ -93,7 +98,7 @@
stdout->clear();
stderr->clear();
- ShellProtocol* protocol = new ShellProtocol(fd);
+ auto protocol = std::make_unique<ShellProtocol>(fd);
while (protocol->Read()) {
switch (protocol->id()) {
case ShellProtocol::kIdStdout:
@@ -111,7 +116,6 @@
ADD_FAILURE() << "Unidentified packet ID: " << protocol->id();
}
}
- delete protocol;
return exit_code;
}
@@ -154,7 +158,7 @@
// [ -t 0 ] == 0 means we have a terminal (PTY). Even when requesting a raw subprocess, without
// the shell protocol we should always force a PTY to ensure proper cleanup.
- ExpectLinesEqual(ReadRaw(subprocess_fd_), {"foo", "bar", "0"});
+ ExpectLinesEqual(ReadRaw(command_fd_), {"foo", "bar", "0"});
}
// Tests a PTY subprocess with no protocol.
@@ -165,7 +169,7 @@
SubprocessType::kPty, SubprocessProtocol::kNone));
// [ -t 0 ] == 0 means we have a terminal (PTY).
- ExpectLinesEqual(ReadRaw(subprocess_fd_), {"foo", "bar", "0"});
+ ExpectLinesEqual(ReadRaw(command_fd_), {"foo", "bar", "0"});
}
// Tests a raw subprocess with the shell protocol.
@@ -175,7 +179,7 @@
SubprocessType::kRaw, SubprocessProtocol::kShell));
std::string stdout, stderr;
- EXPECT_EQ(24, ReadShellProtocol(subprocess_fd_, &stdout, &stderr));
+ EXPECT_EQ(24, ReadShellProtocol(command_fd_, &stdout, &stderr));
ExpectLinesEqual(stdout, {"foo", "baz"});
ExpectLinesEqual(stderr, {"bar"});
}
@@ -189,7 +193,7 @@
// PTY always combines stdout and stderr but the shell protocol should
// still give us an exit code.
std::string stdout, stderr;
- EXPECT_EQ(50, ReadShellProtocol(subprocess_fd_, &stdout, &stderr));
+ EXPECT_EQ(50, ReadShellProtocol(command_fd_, &stdout, &stderr));
ExpectLinesEqual(stdout, {"foo", "bar", "baz"});
ExpectLinesEqual(stderr, {});
}
@@ -204,7 +208,7 @@
"echo --${TEST_STR}--",
"exit"};
- ShellProtocol* protocol = new ShellProtocol(subprocess_fd_);
+ ShellProtocol* protocol = new ShellProtocol(command_fd_);
for (std::string command : commands) {
// Interactive shell requires a newline to complete each command.
command.push_back('\n');
@@ -214,7 +218,7 @@
delete protocol;
std::string stdout, stderr;
- EXPECT_EQ(0, ReadShellProtocol(subprocess_fd_, &stdout, &stderr));
+ EXPECT_EQ(0, ReadShellProtocol(command_fd_, &stdout, &stderr));
// An unpredictable command prompt makes parsing exact output difficult but
// it should at least contain echoed input and the expected output.
for (const char* command : commands) {
@@ -230,14 +234,14 @@
SubprocessType::kRaw, SubprocessProtocol::kShell));
std::string input = "foo\nbar";
- ShellProtocol* protocol = new ShellProtocol(subprocess_fd_);
+ ShellProtocol* protocol = new ShellProtocol(command_fd_);
memcpy(protocol->data(), input.data(), input.length());
ASSERT_TRUE(protocol->Write(ShellProtocol::kIdStdin, input.length()));
ASSERT_TRUE(protocol->Write(ShellProtocol::kIdCloseStdin, 0));
delete protocol;
std::string stdout, stderr;
- EXPECT_EQ(0, ReadShellProtocol(subprocess_fd_, &stdout, &stderr));
+ EXPECT_EQ(0, ReadShellProtocol(command_fd_, &stdout, &stderr));
ExpectLinesEqual(stdout, {"foo", "barTEST_DONE"});
ExpectLinesEqual(stderr, {});
}
@@ -249,7 +253,7 @@
SubprocessType::kRaw, SubprocessProtocol::kShell));
std::string stdout, stderr;
- EXPECT_EQ(0, ReadShellProtocol(subprocess_fd_, &stdout, &stderr));
+ EXPECT_EQ(0, ReadShellProtocol(command_fd_, &stdout, &stderr));
ExpectLinesEqual(stdout, {});
ExpectLinesEqual(stderr, {"bar"});
}
@@ -261,7 +265,56 @@
SubprocessType::kRaw, SubprocessProtocol::kShell));
std::string stdout, stderr;
- EXPECT_EQ(0, ReadShellProtocol(subprocess_fd_, &stdout, &stderr));
+ EXPECT_EQ(0, ReadShellProtocol(command_fd_, &stdout, &stderr));
ExpectLinesEqual(stdout, {"foo"});
ExpectLinesEqual(stderr, {});
}
+
+// Tests an inprocess command with no protocol.
+TEST_F(ShellServiceTest, RawNoProtocolInprocess) {
+ ASSERT_NO_FATAL_FAILURE(
+ StartTestCommandInProcess("123",
+ [](auto args, auto in, auto out, auto err) -> int {
+ EXPECT_EQ("123", args);
+ char input[10];
+ EXPECT_TRUE(ReadFdExactly(in, input, 2));
+ input[2] = 0;
+ EXPECT_STREQ("in", input);
+ WriteFdExactly(out, "out\n");
+ WriteFdExactly(err, "err\n");
+ return 0;
+ },
+ SubprocessProtocol::kNone));
+
+ WriteFdExactly(command_fd_, "in");
+ ExpectLinesEqual(ReadRaw(command_fd_), {"out", "err"});
+}
+
+// Tests an inprocess command with the shell protocol.
+TEST_F(ShellServiceTest, RawShellProtocolInprocess) {
+ ASSERT_NO_FATAL_FAILURE(
+ StartTestCommandInProcess("321",
+ [](auto args, auto in, auto out, auto err) -> int {
+ EXPECT_EQ("321", args);
+ char input[10];
+ EXPECT_TRUE(ReadFdExactly(in, input, 2));
+ input[2] = 0;
+ EXPECT_STREQ("in", input);
+ WriteFdExactly(out, "out\n");
+ WriteFdExactly(err, "err\n");
+ return 0;
+ },
+ SubprocessProtocol::kShell));
+
+ {
+ auto write_protocol = std::make_unique<ShellProtocol>(command_fd_);
+ memcpy(write_protocol->data(), "in", 2);
+ write_protocol->Write(ShellProtocol::kIdStdin, 2);
+ }
+
+ std::string stdout, stderr;
+ // For in-process commands the exit code is always the default (1).
+ EXPECT_EQ(1, ReadShellProtocol(command_fd_, &stdout, &stderr));
+ ExpectLinesEqual(stdout, {"out"});
+ ExpectLinesEqual(stderr, {"err"});
+}
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index b42236e..8c33ca5 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -168,7 +168,8 @@
struct UsbFfsConnection : public Connection {
UsbFfsConnection(unique_fd control, unique_fd read, unique_fd write,
std::promise<void> destruction_notifier)
- : stopped_(false),
+ : worker_started_(false),
+ stopped_(false),
destruction_notifier_(std::move(destruction_notifier)),
control_fd_(std::move(control)),
read_fd_(std::move(read)),
@@ -194,6 +195,7 @@
// We need to explicitly close our file descriptors before we notify our destruction,
// because the thread listening on the future will immediately try to reopen the endpoint.
+ aio_context_.reset();
control_fd_.reset();
read_fd_.reset();
write_fd_.reset();
@@ -267,18 +269,23 @@
adb_thread_setname("UsbFfs-monitor");
bool bound = false;
- bool started = false;
+ bool enabled = false;
bool running = true;
while (running) {
adb_pollfd pfd[2] = {
{ .fd = control_fd_.get(), .events = POLLIN, .revents = 0 },
{ .fd = monitor_event_fd_.get(), .events = POLLIN, .revents = 0 },
};
- int rc = TEMP_FAILURE_RETRY(adb_poll(pfd, 2, -1));
+
+ // If we don't see our first bind within a second, try again.
+ int timeout_ms = bound ? -1 : 1000;
+
+ int rc = TEMP_FAILURE_RETRY(adb_poll(pfd, 2, timeout_ms));
if (rc == -1) {
PLOG(FATAL) << "poll on USB control fd failed";
} else if (rc == 0) {
- LOG(FATAL) << "poll on USB control fd returned 0";
+ LOG(WARNING) << "timed out while waiting for FUNCTIONFS_BIND, trying again";
+ break;
}
if (pfd[1].revents) {
@@ -297,30 +304,70 @@
switch (event.type) {
case FUNCTIONFS_BIND:
- CHECK(!bound) << "received FUNCTIONFS_BIND while already bound?";
+ if (bound) {
+ LOG(WARNING) << "received FUNCTIONFS_BIND while already bound?";
+ running = false;
+ }
+
+ if (enabled) {
+ LOG(WARNING) << "received FUNCTIONFS_BIND while already enabled?";
+ running = false;
+ }
+
bound = true;
break;
case FUNCTIONFS_ENABLE:
- CHECK(!started) << "received FUNCTIONFS_ENABLE while already running?";
- started = true;
+ if (!bound) {
+ LOG(WARNING) << "received FUNCTIONFS_ENABLE while not bound?";
+ running = false;
+ }
+
+ if (enabled) {
+ LOG(WARNING) << "received FUNCTIONFS_ENABLE while already enabled?";
+ running = false;
+ }
+
+ enabled = true;
StartWorker();
break;
case FUNCTIONFS_DISABLE:
+ if (!bound) {
+ LOG(WARNING) << "received FUNCTIONFS_DISABLE while not bound?";
+ }
+
+ if (!enabled) {
+ LOG(WARNING) << "received FUNCTIONFS_DISABLE while not enabled?";
+ }
+
+ enabled = false;
+ running = false;
+ break;
+
+ case FUNCTIONFS_UNBIND:
+ if (enabled) {
+ LOG(WARNING) << "received FUNCTIONFS_UNBIND while still enabled?";
+ }
+
+ if (!bound) {
+ LOG(WARNING) << "received FUNCTIONFS_UNBIND when not bound?";
+ }
+
+ bound = false;
running = false;
break;
}
}
StopWorker();
- aio_context_.reset();
- read_fd_.reset();
- write_fd_.reset();
+ HandleError("monitor thread finished");
});
}
void StartWorker() {
+ CHECK(!worker_started_);
+ worker_started_ = true;
worker_thread_ = std::thread([this]() {
adb_thread_setname("UsbFfs-worker");
for (size_t i = 0; i < kUsbReadQueueDepth; ++i) {
@@ -339,12 +386,16 @@
LOG(FATAL) << "hit EOF on eventfd";
}
- WaitForEvents();
+ ReadEvents();
}
});
}
void StopWorker() {
+ if (!worker_started_) {
+ return;
+ }
+
pthread_t worker_thread_handle = worker_thread_.native_handle();
while (true) {
int rc = pthread_kill(worker_thread_handle, kInterruptionSignal);
@@ -389,7 +440,7 @@
return block;
}
- void WaitForEvents() {
+ void ReadEvents() {
static constexpr size_t kMaxEvents = kUsbReadQueueDepth + kUsbWriteQueueDepth;
struct io_event events[kMaxEvents];
struct timespec timeout = {.tv_sec = 0, .tv_nsec = 0};
@@ -552,6 +603,8 @@
LOG(VERBOSE) << "submitting write_request " << static_cast<void*>(iocbs[i]);
}
+ writes_submitted_ += writes_to_submit;
+
int rc = io_submit(aio_context_.get(), writes_to_submit, iocbs);
if (rc == -1) {
HandleError(StringPrintf("failed to submit write requests: %s", strerror(errno)));
@@ -560,8 +613,6 @@
LOG(FATAL) << "failed to submit all writes: wanted to submit " << writes_to_submit
<< ", actually submitted " << rc;
}
-
- writes_submitted_ += rc;
}
void HandleError(const std::string& error) {
@@ -574,6 +625,8 @@
}
std::thread monitor_thread_;
+
+ bool worker_started_;
std::thread worker_thread_;
std::atomic<bool> stopped_;
diff --git a/adb/daemon/usb_dummy.cpp b/adb/daemon/usb_dummy.cpp
index 984bc25..c9bf797 100644
--- a/adb/daemon/usb_dummy.cpp
+++ b/adb/daemon/usb_dummy.cpp
@@ -33,6 +33,10 @@
return -1;
}
+void usb_reset(usb_handle*) {
+ LOG(FATAL) << "unimplemented";
+}
+
void usb_kick(usb_handle*) {
LOG(FATAL) << "unimplemented";
}
diff --git a/adb/daemon/usb_legacy.cpp b/adb/daemon/usb_legacy.cpp
index 7ace59d..b65727a 100644
--- a/adb/daemon/usb_legacy.cpp
+++ b/adb/daemon/usb_legacy.cpp
@@ -307,6 +307,10 @@
return 0;
}
+void usb_reset(usb_handle* h) {
+ usb_close(h);
+}
+
void usb_kick(usb_handle* h) {
h->kick(h);
}
diff --git a/adb/services.cpp b/adb/services.cpp
index 80f9f79..cf346ba 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -188,7 +188,7 @@
if (!strncmp(host.c_str(), "emu:", 4)) {
connect_emulator(host.c_str() + 4, &response);
} else {
- connect_device(host.c_str(), &response);
+ connect_device(host, &response);
}
// Send response for emulator and device
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 0b4e084..15c3a9a 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -257,6 +257,11 @@
return next++;
}
+void Connection::Reset() {
+ LOG(INFO) << "Connection::Reset(): stopping";
+ Stop();
+}
+
BlockingConnectionAdapter::BlockingConnectionAdapter(std::unique_ptr<BlockingConnection> connection)
: underlying_(std::move(connection)) {}
@@ -312,6 +317,26 @@
started_ = true;
}
+void BlockingConnectionAdapter::Reset() {
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ if (!started_) {
+ LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): not started";
+ return;
+ }
+
+ if (stopped_) {
+ LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_
+ << "): already stopped";
+ return;
+ }
+ }
+
+ LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): resetting";
+ this->underlying_->Reset();
+ Stop();
+}
+
void BlockingConnectionAdapter::Stop() {
{
std::lock_guard<std::mutex> lock(mutex_);
@@ -424,14 +449,18 @@
}
}
-void kick_transport(atransport* t) {
+void kick_transport(atransport* t, bool reset) {
std::lock_guard<std::recursive_mutex> lock(transport_lock);
// As kick_transport() can be called from threads without guarantee that t is valid,
// check if the transport is in transport_list first.
//
// TODO(jmgao): WTF? Is this actually true?
if (std::find(transport_list.begin(), transport_list.end(), t) != transport_list.end()) {
- t->Kick();
+ if (reset) {
+ t->Reset();
+ } else {
+ t->Kick();
+ }
}
#if ADB_HOST
@@ -942,9 +971,16 @@
return this->connection()->Write(std::unique_ptr<apacket>(p)) ? 0 : -1;
}
+void atransport::Reset() {
+ if (!kicked_.exchange(true)) {
+ LOG(INFO) << "resetting transport " << this << " " << this->serial;
+ this->connection()->Reset();
+ }
+}
+
void atransport::Kick() {
if (!kicked_.exchange(true)) {
- D("kicking transport %p %s", this, this->serial.c_str());
+ LOG(INFO) << "kicking transport " << this << " " << this->serial;
this->connection()->Stop();
}
}
@@ -1173,18 +1209,22 @@
return result;
}
-void close_usb_devices(std::function<bool(const atransport*)> predicate) {
+void close_usb_devices(std::function<bool(const atransport*)> predicate, bool reset) {
std::lock_guard<std::recursive_mutex> lock(transport_lock);
for (auto& t : transport_list) {
if (predicate(t)) {
- t->Kick();
+ if (reset) {
+ t->Reset();
+ } else {
+ t->Kick();
+ }
}
}
}
/* hack for osx */
-void close_usb_devices() {
- close_usb_devices([](const atransport*) { return true; });
+void close_usb_devices(bool reset) {
+ close_usb_devices([](const atransport*) { return true; }, reset);
}
#endif // ADB_HOST
diff --git a/adb/transport.h b/adb/transport.h
index a0174b8..f4490ed 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -99,6 +99,9 @@
virtual void Start() = 0;
virtual void Stop() = 0;
+ // Stop, and reset the device if it's a USB connection.
+ virtual void Reset();
+
std::string transport_name_;
ReadCallback read_callback_;
ErrorCallback error_callback_;
@@ -124,6 +127,9 @@
// This method must be thread-safe, and must cause concurrent Reads/Writes to terminate.
// Formerly known as 'Kick' in atransport.
virtual void Close() = 0;
+
+ // Terminate a connection, and reset it.
+ virtual void Reset() = 0;
};
struct BlockingConnectionAdapter : public Connection {
@@ -136,6 +142,8 @@
virtual void Start() override final;
virtual void Stop() override final;
+ virtual void Reset() override final;
+
bool started_ GUARDED_BY(mutex_) = false;
bool stopped_ GUARDED_BY(mutex_) = false;
@@ -157,6 +165,7 @@
bool Write(apacket* packet) override final;
void Close() override;
+ virtual void Reset() override final { Close(); }
private:
unique_fd fd_;
@@ -170,6 +179,7 @@
bool Write(apacket* packet) override final;
void Close() override final;
+ virtual void Reset() override final;
usb_handle* handle_;
};
@@ -235,6 +245,7 @@
virtual ~atransport();
int Write(apacket* p);
+ void Reset();
void Kick();
bool kicked() const { return kicked_; }
@@ -364,7 +375,7 @@
atransport* acquire_one_transport(TransportType type, const char* serial, TransportId transport_id,
bool* is_ambiguous, std::string* error_out,
bool accept_any_state = false);
-void kick_transport(atransport* t);
+void kick_transport(atransport* t, bool reset = false);
void update_transports(void);
// Iterates across all of the current and pending transports.
@@ -395,8 +406,8 @@
bool check_header(apacket* p, atransport* t);
-void close_usb_devices();
-void close_usb_devices(std::function<bool(const atransport*)> predicate);
+void close_usb_devices(bool reset = false);
+void close_usb_devices(std::function<bool(const atransport*)> predicate, bool reset = false);
void send_packet(apacket* p, atransport* t);
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index 2e5918a..3e87522 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -171,6 +171,11 @@
return true;
}
+void UsbConnection::Reset() {
+ usb_reset(handle_);
+ usb_kick(handle_);
+}
+
void UsbConnection::Close() {
usb_kick(handle_);
}
diff --git a/adb/types.h b/adb/types.h
index 0090c98..cd1366d 100644
--- a/adb/types.h
+++ b/adb/types.h
@@ -216,7 +216,10 @@
// Add a nonempty block to the chain.
// The end of the chain must be a complete block (i.e. end_offset_ == 0).
void append(std::unique_ptr<const block_type> block) {
- CHECK_NE(0ULL, block->size());
+ if (block->size() == 0) {
+ return;
+ }
+
CHECK_EQ(0ULL, end_offset_);
chain_length_ += block->size();
chain_.emplace_back(std::move(block));
diff --git a/adb/usb.h b/adb/usb.h
index cd83c42..eb8ca6c 100644
--- a/adb/usb.h
+++ b/adb/usb.h
@@ -26,6 +26,7 @@
int usb_write(handle_ref_type h, const void* data, int len); \
int usb_read(handle_ref_type h, void* data, int len); \
int usb_close(handle_ref_type h); \
+ void usb_reset(handle_ref_type h); \
void usb_kick(handle_ref_type h); \
size_t usb_get_max_packet_size(handle_ref_type)
diff --git a/base/file.cpp b/base/file.cpp
index 2f4a517..adc8984 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -385,7 +385,12 @@
bool Realpath(const std::string& path, std::string* result) {
result->clear();
- char* realpath_buf = realpath(path.c_str(), nullptr);
+ // realpath may exit with EINTR. Retry if so.
+ char* realpath_buf = nullptr;
+ do {
+ realpath_buf = realpath(path.c_str(), nullptr);
+ } while (realpath_buf == nullptr && errno == EINTR);
+
if (realpath_buf == nullptr) {
return false;
}
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index 83213e9..3fa3bea 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -105,6 +105,9 @@
int get() const { return fd_; }
operator int() const { return get(); } // NOLINT
+ // Catch bogus error checks (i.e.: "!fd" instead of "fd != -1").
+ bool operator!() const = delete;
+
int release() __attribute__((warn_unused_result)) {
tag(fd_, this, nullptr);
int ret = fd_;
diff --git a/debuggerd/libdebuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp
index 753ebcb..94fcfb2 100644
--- a/debuggerd/libdebuggerd/backtrace.cpp
+++ b/debuggerd/libdebuggerd/backtrace.cpp
@@ -74,6 +74,7 @@
return;
}
+ unwinder->SetDisplayBuildID(true);
for (size_t i = 0; i < unwinder->NumFrames(); i++) {
_LOG(&log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(i).c_str());
}
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
index 7c5304e..238c00c 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
@@ -18,6 +18,7 @@
#ifndef _DEBUGGERD_UTILITY_H
#define _DEBUGGERD_UTILITY_H
+#include <inttypes.h>
#include <signal.h>
#include <stdbool.h>
#include <sys/types.h>
@@ -25,7 +26,6 @@
#include <string>
#include <android-base/macros.h>
-#include <backtrace/Backtrace.h>
struct log_t {
// Tombstone file descriptor.
@@ -61,6 +61,14 @@
OPEN_FILES
};
+#if defined(__LP64__)
+#define PRIPTR "016" PRIx64
+typedef uint64_t word_t;
+#else
+#define PRIPTR "08" PRIx64
+typedef uint32_t word_t;
+#endif
+
// Log information onto the tombstone.
void _LOG(log_t* log, logtype ltype, const char* fmt, ...) __attribute__((format(printf, 3, 4)));
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index eed5bd3..3196ce8 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -15,6 +15,7 @@
*/
#include <stdlib.h>
+#include <sys/mman.h>
#include <time.h>
#include <memory>
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index c08afda..cc337ed 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -27,6 +27,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/mman.h>
#include <sys/ptrace.h>
#include <sys/stat.h>
#include <time.h>
@@ -371,6 +372,7 @@
}
void dump_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix) {
+ unwinder->SetDisplayBuildID(true);
for (size_t i = 0; i < unwinder->NumFrames(); i++) {
_LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str());
}
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index d0c5234..7aebea8 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -35,7 +35,6 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
-#include <backtrace/Backtrace.h>
#include <debuggerd/handler.h>
#include <log/log.h>
#include <unwindstack/Memory.h>
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 4cdd8bc..f8f7eb3 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -1407,7 +1407,7 @@
int LocalImageSource::OpenFile(const std::string& name) const {
auto path = find_item_given_name(name);
- return open(path.c_str(), O_RDONLY);
+ return open(path.c_str(), O_RDONLY | O_BINARY);
}
static void do_flashall(const std::string& slot_override, bool skip_secondary, bool wipe) {
@@ -1805,7 +1805,7 @@
auto format = [&](const std::string& partition) {
fb_perform_format(partition, 0, type_override, size_override, "");
};
- do_for_partitions(partition.c_str(), slot_override, format, true);
+ do_for_partitions(partition, slot_override, format, true);
} else if (command == "signature") {
std::string filename = next_arg(&args);
std::vector<char> data;
@@ -1876,7 +1876,7 @@
}
do_flash(partition.c_str(), fname.c_str());
};
- do_for_partitions(pname.c_str(), slot_override, flash, true);
+ do_for_partitions(pname, slot_override, flash, true);
} else if (command == "flash:raw") {
std::string partition = next_arg(&args);
std::string kernel = next_arg(&args);
diff --git a/fastboot/fuzzy_fastboot/fixtures.cpp b/fastboot/fuzzy_fastboot/fixtures.cpp
index eb043ce..c23da01 100644
--- a/fastboot/fuzzy_fastboot/fixtures.cpp
+++ b/fastboot/fuzzy_fastboot/fixtures.cpp
@@ -130,10 +130,14 @@
ASSERT_EQ(device_path, cb_scratch); // The path can not change
}
fb = std::unique_ptr<FastBootDriver>(new FastBootDriver(transport.get(), {}, true));
+ // No error checking since non-A/B devices may not support the command
+ fb->GetVar("current-slot", &initial_slot);
}
void FastBootTest::TearDown() {
EXPECT_TRUE(UsbStillAvailible()) << USB_PORT_GONE;
+ // No error checking since non-A/B devices may not support the command
+ fb->SetActive(initial_slot);
TearDownSerial();
@@ -232,6 +236,7 @@
std::string FastBootTest::device_path = "";
std::string FastBootTest::cb_scratch = "";
+std::string FastBootTest::initial_slot = "";
int FastBootTest::serial_port = 0;
template <bool UNLOCKED>
diff --git a/fastboot/fuzzy_fastboot/fixtures.h b/fastboot/fuzzy_fastboot/fixtures.h
index 9c955ea..7c8d54d 100644
--- a/fastboot/fuzzy_fastboot/fixtures.h
+++ b/fastboot/fuzzy_fastboot/fixtures.h
@@ -70,6 +70,7 @@
// This is an annoying hack
static std::string cb_scratch;
static std::string device_path;
+ static std::string initial_slot;
};
template <bool UNLOCKED>
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index 7ffc7d5..a40bc27 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -201,18 +201,28 @@
ASSERT_TRUE(UserSpaceFastboot());
std::string has_slot;
EXPECT_EQ(fb->GetVar("has-slot:system", &has_slot), SUCCESS) << "getvar has-slot:system failed";
- std::string is_logical_cmd;
+ std::string is_logical_cmd_system = "is-logical:system";
+ std::string is_logical_cmd_vendor = "is-logical:vendor";
+ std::string is_logical_cmd_boot = "is-logical:boot";
if (has_slot == "yes") {
std::string current_slot;
- EXPECT_EQ(fb->GetVar("current-slot", ¤t_slot), SUCCESS)
+ ASSERT_EQ(fb->GetVar("current-slot", ¤t_slot), SUCCESS)
<< "getvar current-slot failed";
- is_logical_cmd = "is-logical:system_" + current_slot;
- } else {
- is_logical_cmd = "is-logical:system";
+ std::string slot_suffix = "_" + current_slot;
+ is_logical_cmd_system += slot_suffix;
+ is_logical_cmd_vendor += slot_suffix;
+ is_logical_cmd_boot += slot_suffix;
}
std::string is_logical;
- EXPECT_EQ(fb->GetVar(is_logical_cmd, &is_logical), SUCCESS) << "getvar is-logical failed";
- ASSERT_EQ(is_logical, "yes");
+ EXPECT_EQ(fb->GetVar(is_logical_cmd_system, &is_logical), SUCCESS)
+ << "system must be a logical partition";
+ EXPECT_EQ(is_logical, "yes");
+ EXPECT_EQ(fb->GetVar(is_logical_cmd_vendor, &is_logical), SUCCESS)
+ << "vendor must be a logical partition";
+ EXPECT_EQ(is_logical, "yes");
+ EXPECT_EQ(fb->GetVar(is_logical_cmd_boot, &is_logical), SUCCESS)
+ << "boot must not be logical partition";
+ EXPECT_EQ(is_logical, "no");
}
TEST_F(LogicalPartitionCompliance, FastbootRebootTest) {
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index d26f2d5..045bb48 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -1609,14 +1609,7 @@
DeviceMapper& dm = DeviceMapper::Instance();
- std::string mount_point;
- if (entry.mount_point == "/") {
- // In AVB, the dm device name is vroot instead of system.
- mount_point = entry.fs_mgr_flags.avb ? "vroot" : "system";
- } else {
- mount_point = Basename(entry.mount_point);
- }
-
+ std::string mount_point = GetVerityDeviceName(entry);
if (dm.GetState(mount_point) == DmDeviceState::INVALID) {
return false;
}
@@ -1639,6 +1632,27 @@
return false;
}
+bool fs_mgr_verity_is_check_at_most_once(const android::fs_mgr::FstabEntry& entry) {
+ if (!entry.fs_mgr_flags.verify && !entry.fs_mgr_flags.avb) {
+ return false;
+ }
+
+ DeviceMapper& dm = DeviceMapper::Instance();
+ std::string device = GetVerityDeviceName(entry);
+
+ std::vector<DeviceMapper::TargetInfo> table;
+ if (dm.GetState(device) == DmDeviceState::INVALID || !dm.GetTableInfo(device, &table)) {
+ return false;
+ }
+ for (const auto& target : table) {
+ if (strcmp(target.spec.target_type, "verity") == 0 &&
+ target.data.find("check_at_most_once") != std::string::npos) {
+ return true;
+ }
+ }
+ return false;
+}
+
std::string fs_mgr_get_super_partition_name(int slot) {
// Devices upgrading to dynamic partitions are allowed to specify a super
// partition name, assumed to be A/B (non-A/B retrofit is not supported).
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 2f1e41f..4043fc6 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -754,20 +754,32 @@
FstabEntry BuildGsiSystemFstabEntry() {
// .logical_partition_name is required to look up AVB Hashtree descriptors.
- FstabEntry system = {.blk_device = "system_gsi",
- .mount_point = "/system",
- .fs_type = "ext4",
- .flags = MS_RDONLY,
- .fs_options = "barrier=1",
- // could add more keys separated by ':'.
- .avb_keys = "/avb/gsi.avbpubkey:",
- .logical_partition_name = "system"};
+ FstabEntry system = {
+ .blk_device = "system_gsi",
+ .mount_point = "/system",
+ .fs_type = "ext4",
+ .flags = MS_RDONLY,
+ .fs_options = "barrier=1",
+ // could add more keys separated by ':'.
+ .avb_keys = "/avb/q-gsi.avbpubkey:/avb/r-gsi.avbpubkey:/avb/s-gsi.avbpubkey",
+ .logical_partition_name = "system"};
system.fs_mgr_flags.wait = true;
system.fs_mgr_flags.logical = true;
system.fs_mgr_flags.first_stage_mount = true;
return system;
}
+std::string GetVerityDeviceName(const FstabEntry& entry) {
+ std::string base_device;
+ if (entry.mount_point == "/") {
+ // In AVB, the dm device name is vroot instead of system.
+ base_device = entry.fs_mgr_flags.avb ? "vroot" : "system";
+ } else {
+ base_device = android::base::Basename(entry.mount_point);
+ }
+ return base_device + "-verity";
+}
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index 24044d8..093d44d 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -340,6 +340,7 @@
blk_device = rentry.blk_device;
break;
}
+ // Find overlayfs mount point?
if ((mount_point == "/") && (rentry.mount_point == "/system")) {
blk_device = rentry.blk_device;
mount_point = "/system";
@@ -352,6 +353,12 @@
}
fs_mgr_set_blk_ro(blk_device, false);
+ // Find system-as-root mount point?
+ if ((mount_point == "/system") && !GetEntryForMountPoint(&mounts, mount_point) &&
+ GetEntryForMountPoint(&mounts, "/")) {
+ mount_point = "/";
+ }
+
// Now remount!
if (::mount(blk_device.c_str(), mount_point.c_str(), entry.fs_type.c_str(), MS_REMOUNT,
nullptr) == 0) {
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index a3bb852..8abe609 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -77,6 +77,10 @@
bool fs_mgr_swapon_all(const android::fs_mgr::Fstab& fstab);
bool fs_mgr_update_logical_partition(android::fs_mgr::FstabEntry* entry);
+// Returns true if the given fstab entry has verity enabled, *and* the verity
+// device is in "check_at_most_once" mode.
+bool fs_mgr_verity_is_check_at_most_once(const android::fs_mgr::FstabEntry& entry);
+
int fs_mgr_do_format(const android::fs_mgr::FstabEntry& entry, bool reserve_footer);
#define FS_MGR_SETUP_VERITY_SKIPPED (-3)
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index e811447..88da41d 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -107,5 +107,10 @@
std::set<std::string> GetBootDevices();
+// Return the name of the dm-verity device for the given fstab entry. This does
+// not check whether the device is valid or exists; it merely returns the
+// expected name.
+std::string GetVerityDeviceName(const FstabEntry& entry);
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/libdm/Android.mk b/fs_mgr/libdm/Android.mk
new file mode 100644
index 0000000..6aedc25
--- /dev/null
+++ b/fs_mgr/libdm/Android.mk
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := VtsKernelLibdmTest
+-include test/vts/tools/build/Android.host_config.mk
diff --git a/fs_mgr/libdm/AndroidTest.xml b/fs_mgr/libdm/AndroidTest.xml
new file mode 100644
index 0000000..b4e0c23
--- /dev/null
+++ b/fs_mgr/libdm/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<configuration description="Config for VTS VtsKernelLibdmTest">
+ <option name="config-descriptor:metadata" key="plan" value="vts-kernel" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="abort-on-push-failure" value="false"/>
+ <option name="push-group" value="HostDrivenTest.push"/>
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="VtsKernelLibdmTest"/>
+ <option name="binary-test-source" value="_32bit::DATA/nativetest/libdm_test/libdm_test" />
+ <option name="binary-test-source" value="_64bit::DATA/nativetest64/libdm_test/libdm_test" />
+ <option name="binary-test-type" value="gtest"/>
+ <option name="test-timeout" value="1m"/>
+ <option name="precondition-first-api-level" value="29" />
+ </test>
+</configuration>
+
diff --git a/fs_mgr/libfiemap_writer/fiemap_writer.cpp b/fs_mgr/libfiemap_writer/fiemap_writer.cpp
index 85589cc..e3803d5 100644
--- a/fs_mgr/libfiemap_writer/fiemap_writer.cpp
+++ b/fs_mgr/libfiemap_writer/fiemap_writer.cpp
@@ -407,9 +407,25 @@
#define F2FS_IOC_GET_PIN_FILE _IOR(F2FS_IOCTL_MAGIC, 14, __u32)
#endif
+ // f2fs: export FS_NOCOW_FL flag to user
+ uint32_t flags;
+ int error = ioctl(file_fd, FS_IOC_GETFLAGS, &flags);
+ if (error < 0) {
+ if ((errno == ENOTTY) || (errno == ENOTSUP)) {
+ PLOG(ERROR) << "Failed to get flags, not supported by kernel: " << file_path;
+ } else {
+ PLOG(ERROR) << "Failed to get flags: " << file_path;
+ }
+ return false;
+ }
+ if (!(flags & FS_NOCOW_FL)) {
+ LOG(ERROR) << "It is not pinned: " << file_path;
+ return false;
+ }
+
// F2FS_IOC_GET_PIN_FILE returns the number of blocks moved.
uint32_t moved_blocks_nr;
- int error = ioctl(file_fd, F2FS_IOC_GET_PIN_FILE, &moved_blocks_nr);
+ error = ioctl(file_fd, F2FS_IOC_GET_PIN_FILE, &moved_blocks_nr);
if (error < 0) {
if ((errno == ENOTTY) || (errno == ENOTSUP)) {
PLOG(ERROR) << "Failed to get file pin status, not supported by kernel: " << file_path;
diff --git a/fs_mgr/libfs_avb/avb_util.cpp b/fs_mgr/libfs_avb/avb_util.cpp
index f4e4d4e..d9650f3 100644
--- a/fs_mgr/libfs_avb/avb_util.cpp
+++ b/fs_mgr/libfs_avb/avb_util.cpp
@@ -105,14 +105,15 @@
table.set_readonly(true);
const std::string mount_point(Basename(fstab_entry->mount_point));
+ const std::string device_name(GetVerityDeviceName(*fstab_entry));
android::dm::DeviceMapper& dm = android::dm::DeviceMapper::Instance();
- if (!dm.CreateDevice(mount_point, table)) {
+ if (!dm.CreateDevice(device_name, table)) {
LERROR << "Couldn't create verity device!";
return false;
}
std::string dev_path;
- if (!dm.GetDmDevicePathByName(mount_point, &dev_path)) {
+ if (!dm.GetDmDevicePathByName(device_name, &dev_path)) {
LERROR << "Couldn't get verity device path!";
return false;
}
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index 355b7a1..7039994 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -43,6 +43,11 @@
windows: {
enabled: true,
},
+ android: {
+ shared_libs: [
+ "libcutils",
+ ],
+ },
},
export_include_dirs: ["include"],
}
diff --git a/fs_mgr/liblp/Android.mk b/fs_mgr/liblp/Android.mk
new file mode 100644
index 0000000..7f7f891
--- /dev/null
+++ b/fs_mgr/liblp/Android.mk
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := VtsKernelLiblpTest
+-include test/vts/tools/build/Android.host_config.mk
diff --git a/fs_mgr/liblp/AndroidTest.xml b/fs_mgr/liblp/AndroidTest.xml
new file mode 100644
index 0000000..007a302
--- /dev/null
+++ b/fs_mgr/liblp/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<configuration description="Config for VTS VtsKernelLiblpTest">
+ <option name="config-descriptor:metadata" key="plan" value="vts-kernel" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="abort-on-push-failure" value="false"/>
+ <option name="push-group" value="HostDrivenTest.push"/>
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="VtsKernelLiblpTest"/>
+ <option name="binary-test-source" value="_32bit::DATA/nativetest/liblp_test/liblp_test" />
+ <option name="binary-test-source" value="_64bit::DATA/nativetest64/liblp_test/liblp_test" />
+ <option name="binary-test-type" value="gtest"/>
+ <option name="test-timeout" value="1m"/>
+ <option name="precondition-first-api-level" value="29" />
+ </test>
+</configuration>
+
diff --git a/fs_mgr/liblp/images.cpp b/fs_mgr/liblp/images.cpp
index 5a498f9..db27022 100644
--- a/fs_mgr/liblp/images.cpp
+++ b/fs_mgr/liblp/images.cpp
@@ -68,7 +68,7 @@
}
std::unique_ptr<LpMetadata> ReadFromImageFile(const std::string& image_file) {
- unique_fd fd(open(image_file.c_str(), O_RDONLY | O_CLOEXEC));
+ unique_fd fd = GetControlFileOrOpen(image_file.c_str(), O_RDONLY | O_CLOEXEC);
if (fd < 0) {
PERROR << __PRETTY_FUNCTION__ << " open failed: " << image_file;
return nullptr;
@@ -98,11 +98,12 @@
return WriteToImageFile(fd, input);
}
-SparseBuilder::SparseBuilder(const LpMetadata& metadata, uint32_t block_size,
- const std::map<std::string, std::string>& images)
+ImageBuilder::ImageBuilder(const LpMetadata& metadata, uint32_t block_size,
+ const std::map<std::string, std::string>& images, bool sparsify)
: metadata_(metadata),
geometry_(metadata.geometry),
block_size_(block_size),
+ sparsify_(sparsify),
images_(images) {
uint64_t total_size = GetTotalSuperPartitionSize(metadata);
if (block_size % LP_SECTOR_SIZE != 0) {
@@ -144,11 +145,11 @@
}
}
-bool SparseBuilder::IsValid() const {
+bool ImageBuilder::IsValid() const {
return device_images_.size() == metadata_.block_devices.size();
}
-bool SparseBuilder::Export(const char* file) {
+bool ImageBuilder::Export(const char* file) {
unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC, 0644));
if (fd < 0) {
PERROR << "open failed: " << file;
@@ -158,8 +159,8 @@
LERROR << "Cannot export to a single image on retrofit builds.";
return false;
}
- // No gzip compression; sparseify; no checksum.
- int ret = sparse_file_write(device_images_[0].get(), fd, false, true, false);
+ // No gzip compression; no checksum.
+ int ret = sparse_file_write(device_images_[0].get(), fd, false, sparsify_, false);
if (ret != 0) {
LERROR << "sparse_file_write failed (error code " << ret << ")";
return false;
@@ -167,7 +168,7 @@
return true;
}
-bool SparseBuilder::ExportFiles(const std::string& output_dir) {
+bool ImageBuilder::ExportFiles(const std::string& output_dir) {
for (size_t i = 0; i < device_images_.size(); i++) {
std::string name = GetBlockDevicePartitionName(metadata_.block_devices[i]);
std::string file_name = "super_" + name + ".img";
@@ -179,8 +180,8 @@
PERROR << "open failed: " << file_path;
return false;
}
- // No gzip compression; sparseify; no checksum.
- int ret = sparse_file_write(device_images_[i].get(), fd, false, true, false);
+ // No gzip compression; no checksum.
+ int ret = sparse_file_write(device_images_[i].get(), fd, false, sparsify_, false);
if (ret != 0) {
LERROR << "sparse_file_write failed (error code " << ret << ")";
return false;
@@ -189,7 +190,7 @@
return true;
}
-bool SparseBuilder::AddData(sparse_file* file, const std::string& blob, uint64_t sector) {
+bool ImageBuilder::AddData(sparse_file* file, const std::string& blob, uint64_t sector) {
uint32_t block;
if (!SectorToBlock(sector, &block)) {
return false;
@@ -203,7 +204,7 @@
return true;
}
-bool SparseBuilder::SectorToBlock(uint64_t sector, uint32_t* block) {
+bool ImageBuilder::SectorToBlock(uint64_t sector, uint32_t* block) {
// The caller must ensure that the metadata has an alignment that is a
// multiple of the block size. liblp will take care of the rest, ensuring
// that all partitions are on an aligned boundary. Therefore all writes
@@ -218,11 +219,11 @@
return true;
}
-uint64_t SparseBuilder::BlockToSector(uint64_t block) const {
+uint64_t ImageBuilder::BlockToSector(uint64_t block) const {
return (block * block_size_) / LP_SECTOR_SIZE;
}
-bool SparseBuilder::Build() {
+bool ImageBuilder::Build() {
if (sparse_file_add_fill(device_images_[0].get(), 0, LP_PARTITION_RESERVED_BYTES, 0) < 0) {
LERROR << "Could not add initial sparse block for reserved zeroes";
return false;
@@ -275,8 +276,8 @@
return true;
}
-bool SparseBuilder::AddPartitionImage(const LpMetadataPartition& partition,
- const std::string& file) {
+bool ImageBuilder::AddPartitionImage(const LpMetadataPartition& partition,
+ const std::string& file) {
// Track which extent we're processing.
uint32_t extent_index = partition.first_extent_index;
@@ -371,7 +372,7 @@
return true;
}
-uint64_t SparseBuilder::ComputePartitionSize(const LpMetadataPartition& partition) const {
+uint64_t ImageBuilder::ComputePartitionSize(const LpMetadataPartition& partition) const {
uint64_t sectors = 0;
for (size_t i = 0; i < partition.num_extents; i++) {
sectors += metadata_.extents[partition.first_extent_index + i].num_sectors;
@@ -386,7 +387,7 @@
//
// Without this, it would be more difficult to find the appropriate extent for
// an output block. With this guarantee it is a linear walk.
-bool SparseBuilder::CheckExtentOrdering() {
+bool ImageBuilder::CheckExtentOrdering() {
std::vector<uint64_t> last_sectors(metadata_.block_devices.size());
for (const auto& extent : metadata_.extents) {
@@ -407,8 +408,8 @@
return true;
}
-int SparseBuilder::OpenImageFile(const std::string& file) {
- android::base::unique_fd source_fd(open(file.c_str(), O_RDONLY | O_CLOEXEC));
+int ImageBuilder::OpenImageFile(const std::string& file) {
+ android::base::unique_fd source_fd = GetControlFileOrOpen(file.c_str(), O_RDONLY | O_CLOEXEC);
if (source_fd < 0) {
PERROR << "open image file failed: " << file;
return -1;
@@ -437,15 +438,16 @@
return temp_fds_.back().get();
}
-bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t block_size,
- const std::map<std::string, std::string>& images) {
- SparseBuilder builder(metadata, block_size, images);
+bool WriteToImageFile(const char* file, const LpMetadata& metadata, uint32_t block_size,
+ const std::map<std::string, std::string>& images, bool sparsify) {
+ ImageBuilder builder(metadata, block_size, images, sparsify);
return builder.IsValid() && builder.Build() && builder.Export(file);
}
-bool WriteSplitSparseFiles(const std::string& output_dir, const LpMetadata& metadata,
- uint32_t block_size, const std::map<std::string, std::string>& images) {
- SparseBuilder builder(metadata, block_size, images);
+bool WriteSplitImageFiles(const std::string& output_dir, const LpMetadata& metadata,
+ uint32_t block_size, const std::map<std::string, std::string>& images,
+ bool sparsify) {
+ ImageBuilder builder(metadata, block_size, images, sparsify);
return builder.IsValid() && builder.Build() && builder.ExportFiles(output_dir);
}
diff --git a/fs_mgr/liblp/images.h b/fs_mgr/liblp/images.h
index 44217a0..75060f9 100644
--- a/fs_mgr/liblp/images.h
+++ b/fs_mgr/liblp/images.h
@@ -32,13 +32,13 @@
bool WriteToImageFile(const char* file, const LpMetadata& metadata);
bool WriteToImageFile(int fd, const LpMetadata& metadata);
-// We use an object to build the sparse file since it requires that data
+// We use an object to build the image file since it requires that data
// pointers be held alive until the sparse file is destroyed. It's easier
// to do this when the data pointers are all in one place.
-class SparseBuilder {
+class ImageBuilder {
public:
- SparseBuilder(const LpMetadata& metadata, uint32_t block_size,
- const std::map<std::string, std::string>& images);
+ ImageBuilder(const LpMetadata& metadata, uint32_t block_size,
+ const std::map<std::string, std::string>& images, bool sparsify);
bool Build();
bool Export(const char* file);
@@ -60,6 +60,7 @@
const LpMetadata& metadata_;
const LpMetadataGeometry& geometry_;
uint32_t block_size_;
+ bool sparsify_;
std::vector<SparsePtr> device_images_;
std::string all_metadata_;
diff --git a/fs_mgr/liblp/include/liblp/liblp.h b/fs_mgr/liblp/include/liblp/liblp.h
index 6348f55..5f782b0 100644
--- a/fs_mgr/liblp/include/liblp/liblp.h
+++ b/fs_mgr/liblp/include/liblp/liblp.h
@@ -72,8 +72,8 @@
// Read/Write logical partition metadata to an image file, for diagnostics or
// flashing.
-bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t block_size,
- const std::map<std::string, std::string>& images);
+bool WriteToImageFile(const char* file, const LpMetadata& metadata, uint32_t block_size,
+ const std::map<std::string, std::string>& images, bool sparsify);
bool WriteToImageFile(const char* file, const LpMetadata& metadata);
std::unique_ptr<LpMetadata> ReadFromImageFile(const std::string& image_file);
std::unique_ptr<LpMetadata> ReadFromImageBlob(const void* data, size_t bytes);
@@ -83,8 +83,9 @@
// is intended for retrofit devices, and will generate one sparse file per
// block device (each named super_<name>.img) and placed in the specified
// output folder.
-bool WriteSplitSparseFiles(const std::string& output_dir, const LpMetadata& metadata,
- uint32_t block_size, const std::map<std::string, std::string>& images);
+bool WriteSplitImageFiles(const std::string& output_dir, const LpMetadata& metadata,
+ uint32_t block_size, const std::map<std::string, std::string>& images,
+ bool sparsify);
// Helper to extract safe C++ strings from partition info.
std::string GetPartitionName(const LpMetadataPartition& partition);
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index 9f3314d..8fc02cb 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -598,7 +598,7 @@
ASSERT_NE(exported, nullptr);
// Build the sparse file.
- SparseBuilder sparse(*exported.get(), 512, {});
+ ImageBuilder sparse(*exported.get(), 512, {}, true /* sparsify */);
ASSERT_TRUE(sparse.IsValid());
ASSERT_TRUE(sparse.Build());
diff --git a/fs_mgr/liblp/partition_opener.cpp b/fs_mgr/liblp/partition_opener.cpp
index 898f241..bb8ec9c 100644
--- a/fs_mgr/liblp/partition_opener.cpp
+++ b/fs_mgr/liblp/partition_opener.cpp
@@ -45,7 +45,7 @@
bool GetBlockDeviceInfo(const std::string& block_device, BlockDeviceInfo* device_info) {
#if defined(__linux__)
- unique_fd fd(open(block_device.c_str(), O_RDONLY));
+ unique_fd fd = GetControlFileOrOpen(block_device.c_str(), O_RDONLY);
if (fd < 0) {
PERROR << __PRETTY_FUNCTION__ << "open '" << block_device << "' failed";
return false;
@@ -85,7 +85,7 @@
unique_fd PartitionOpener::Open(const std::string& partition_name, int flags) const {
std::string path = GetPartitionAbsolutePath(partition_name);
- return unique_fd{open(path.c_str(), flags | O_CLOEXEC)};
+ return GetControlFileOrOpen(path.c_str(), flags | O_CLOEXEC);
}
bool PartitionOpener::GetInfo(const std::string& partition_name, BlockDeviceInfo* info) const {
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index ecf94a4..72a3c57 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -28,6 +28,10 @@
#include <ext4_utils/ext4_utils.h>
#include <openssl/sha.h>
+#ifdef __ANDROID__
+#include <cutils/android_get_control_file.h>
+#endif
+
#include "utility.h"
namespace android {
@@ -171,5 +175,19 @@
#endif
}
+base::unique_fd GetControlFileOrOpen(const char* path, int flags) {
+#if defined(__ANDROID__)
+ int fd = android_get_control_file(path);
+ if (fd >= 0) {
+ int newfd = TEMP_FAILURE_RETRY(dup(fd));
+ if (newfd >= 0) {
+ return base::unique_fd(newfd);
+ }
+ PERROR << "Cannot dup fd for already controlled file: " << path << ", reopening...";
+ }
+#endif
+ return base::unique_fd(open(path, flags));
+}
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/liblp/utility.h b/fs_mgr/liblp/utility.h
index e8b2ca9..96f1717 100644
--- a/fs_mgr/liblp/utility.h
+++ b/fs_mgr/liblp/utility.h
@@ -22,6 +22,7 @@
#include <sys/types.h>
#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
#include "liblp/liblp.h"
@@ -92,6 +93,8 @@
// Call BLKROSET ioctl on fd so that fd is readonly / read-writable.
bool SetBlockReadonly(int fd, bool readonly);
+::android::base::unique_fd GetControlFileOrOpen(const char* path, int flags);
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/tests/Android.bp b/fs_mgr/tests/Android.bp
index 19737fe..eb9f525 100644
--- a/fs_mgr/tests/Android.bp
+++ b/fs_mgr/tests/Android.bp
@@ -52,6 +52,14 @@
host_supported: true,
}
+sh_test {
+ name: "adb-remount-sh",
+ src: "adb-remount-test.sh",
+ filename: "adb-remount-test.sh",
+ test_suites: ["general-tests"],
+ test_config: "adb-remount-sh.xml",
+}
+
java_test_host {
name: "fs_mgr_vendor_overlay_test",
diff --git a/fs_mgr/tests/adb-remount-sh.xml b/fs_mgr/tests/adb-remount-sh.xml
new file mode 100644
index 0000000..fa0d63f
--- /dev/null
+++ b/fs_mgr/tests/adb-remount-sh.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<configuration description="Config for adb remount test cases">
+ <option name="test-suite-tag" value="adb-remount" />
+ <!-- This test requires a device, so it's not annotated with a null-device -->
+ <test class="com.android.tradefed.testtype.binary.ExecutableHostTest" >
+ <option name="binary" value="adb-remount-test.sh" />
+ <!-- Increase default timeout as script is quite long -->
+ <option name="per-binary-timeout" value="1h" />
+ </test>
+</configuration>
+
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index c09dc3d..c22176b 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -1026,7 +1026,7 @@
elif [ -z "${ANDROID_HOST_OUT}" ]; then
echo "${ORANGE}[ WARNING ]${NORMAL} please run lunch, skipping"
else
- adb reboot-fastboot ||
+ adb reboot fastboot ||
die "fastbootd not supported (wrong adb in path?)"
any_wait 2m &&
inFastboot ||
@@ -1136,7 +1136,7 @@
echo "${GREEN}[ RUN ]${NORMAL} test fastboot flash to ${scratch_partition} recovery" >&2
- adb reboot-fastboot ||
+ adb reboot fastboot ||
die "Reboot into fastbootd"
img=${TMPDIR}/adb-remount-test-${$}.img
cleanup() {
diff --git a/fs_mgr/tools/dmctl.cpp b/fs_mgr/tools/dmctl.cpp
index 63661f0..9309aad 100644
--- a/fs_mgr/tools/dmctl.cpp
+++ b/fs_mgr/tools/dmctl.cpp
@@ -316,7 +316,7 @@
DeviceMapper& dm = DeviceMapper::Instance();
std::vector<DeviceMapper::TargetInfo> table;
- if (!dm.GetTableStatus(argv[0], &table)) {
+ if (!dm.GetTableInfo(argv[0], &table)) {
std::cerr << "Could not query table status of device \"" << argv[0] << "\"." << std::endl;
return -EINVAL;
}
diff --git a/healthd/healthd_draw.cpp b/healthd/healthd_draw.cpp
index 706dc80..3da8bda 100644
--- a/healthd/healthd_draw.cpp
+++ b/healthd/healthd_draw.cpp
@@ -64,7 +64,8 @@
clear_screen();
/* try to display *something* */
- if (batt_anim->cur_level < 0 || batt_anim->num_frames == 0)
+ if (batt_anim->cur_status == BATTERY_STATUS_UNKNOWN || batt_anim->cur_level < 0 ||
+ batt_anim->num_frames == 0)
draw_unknown(surf_unknown);
else
draw_battery(batt_anim);
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 5fe58ac..edf34f7 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -36,6 +36,7 @@
#include <linux/netlink.h>
#include <sys/socket.h>
+#include <cutils/android_get_control_file.h>
#include <cutils/klog.h>
#include <cutils/misc.h>
#include <cutils/properties.h>
@@ -76,6 +77,8 @@
#define POWER_ON_KEY_TIME (2 * MSEC_PER_SEC)
#define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC)
#define UNPLUGGED_DISPLAY_TIME (3 * MSEC_PER_SEC)
+#define MAX_BATT_LEVEL_WAIT_TIME (3 * MSEC_PER_SEC)
+#define UNPLUGGED_SHUTDOWN_TIME_PROP "ro.product.charger.unplugged_shutdown_time"
#define LAST_KMSG_MAX_SZ (32 * 1024)
@@ -104,6 +107,7 @@
int64_t next_screen_transition;
int64_t next_key_check;
int64_t next_pwr_check;
+ int64_t wait_batt_level_timestamp;
key_state keys[KEY_MAX + 1];
@@ -206,10 +210,9 @@
#define MAX_KLOG_WRITE_BUF_SZ 256
static void dump_last_kmsg(void) {
- char* buf;
+ std::string buf;
char* ptr;
- unsigned sz = 0;
- int len;
+ size_t len;
LOGW("\n");
LOGW("*************** LAST KMSG ***************\n");
@@ -221,21 +224,25 @@
"/proc/last_kmsg",
// clang-format on
};
- for (size_t i = 0; i < arraysize(kmsg); ++i) {
- buf = (char*)load_file(kmsg[i], &sz);
- if (buf && sz) break;
+ for (size_t i = 0; i < arraysize(kmsg) && buf.empty(); ++i) {
+ auto fd = android_get_control_file(kmsg[i]);
+ if (fd >= 0) {
+ android::base::ReadFdToString(fd, &buf);
+ } else {
+ android::base::ReadFileToString(kmsg[i], &buf);
+ }
}
- if (!buf || !sz) {
+ if (buf.empty()) {
LOGW("last_kmsg not found. Cold reset?\n");
goto out;
}
- len = min(sz, LAST_KMSG_MAX_SZ);
- ptr = buf + (sz - len);
+ len = min(buf.size(), LAST_KMSG_MAX_SZ);
+ ptr = &buf[buf.size() - len];
while (len > 0) {
- int cnt = min(len, MAX_KLOG_WRITE_BUF_SZ);
+ size_t cnt = min(len, MAX_KLOG_WRITE_BUF_SZ);
char yoink;
char* nl;
@@ -251,8 +258,6 @@
ptr += cnt;
}
- free(buf);
-
out:
LOGW("\n");
LOGW("************* END LAST KMSG *************\n");
@@ -288,6 +293,21 @@
if (!batt_anim->run || now < charger->next_screen_transition) return;
+ // If battery level is not ready, keep checking in the defined time
+ if (batt_prop == nullptr ||
+ (batt_prop->batteryLevel == 0 && batt_prop->batteryStatus == BATTERY_STATUS_UNKNOWN)) {
+ if (charger->wait_batt_level_timestamp == 0) {
+ // Set max delay time and skip drawing screen
+ charger->wait_batt_level_timestamp = now + MAX_BATT_LEVEL_WAIT_TIME;
+ LOGV("[%" PRId64 "] wait for battery capacity ready\n", now);
+ return;
+ } else if (now <= charger->wait_batt_level_timestamp) {
+ // Do nothing, keep waiting
+ return;
+ }
+ // If timeout and battery level is still not ready, draw unknown battery
+ }
+
if (healthd_draw == nullptr) {
if (healthd_config && healthd_config->screen_on) {
if (!healthd_config->screen_on(batt_prop)) {
@@ -494,6 +514,7 @@
}
static void handle_power_supply_state(charger* charger, int64_t now) {
+ int timer_shutdown = UNPLUGGED_SHUTDOWN_TIME;
if (!charger->have_battery_state) return;
if (!charger->charger_connected) {
@@ -506,12 +527,14 @@
* Reset & kick animation to show complete animation cycles
* when charger disconnected.
*/
+ timer_shutdown =
+ property_get_int32(UNPLUGGED_SHUTDOWN_TIME_PROP, UNPLUGGED_SHUTDOWN_TIME);
charger->next_screen_transition = now - 1;
reset_animation(charger->batt_anim);
kick_animation(charger->batt_anim);
- charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;
+ charger->next_pwr_check = now + timer_shutdown;
LOGW("[%" PRId64 "] device unplugged: shutting down in %" PRId64 " (@ %" PRId64 ")\n",
- now, (int64_t)UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
+ now, (int64_t)timer_shutdown, charger->next_pwr_check);
} else if (now >= charger->next_pwr_check) {
LOGW("[%" PRId64 "] shutting down\n", now);
reboot(RB_POWER_OFF);
@@ -707,6 +730,7 @@
charger->next_screen_transition = -1;
charger->next_key_check = -1;
charger->next_pwr_check = -1;
+ charger->wait_batt_level_timestamp = 0;
// Initialize Health implementation (which initializes the internal BatteryMonitor).
Health::initInstance(config);
diff --git a/init/Android.bp b/init/Android.bp
index 8292aa0..69ee34f 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -61,6 +61,7 @@
static_libs: [
"libseccomp_policy",
"libavb",
+ "libcgrouprc_format",
"libprotobuf-cpp-lite",
"libpropertyinfoserializer",
"libpropertyinfoparser",
@@ -82,6 +83,7 @@
"liblogwrap",
"liblp",
"libprocessgroup",
+ "libprocessgroup_setup",
"libselinux",
"libutils",
],
diff --git a/init/README.md b/init/README.md
index b2039b4..aadf11d 100644
--- a/init/README.md
+++ b/init/README.md
@@ -57,7 +57,7 @@
The intention of these directories is:
1. /system/etc/init/ is for core system items such as
- SurfaceFlinger, MediaService, and logcatd.
+ SurfaceFlinger, MediaService, and logd.
2. /vendor/etc/init/ is for SoC vendor items such as actions or
daemons needed for core SoC functionality.
3. /odm/etc/init/ is for device manufacturer items such as
@@ -72,7 +72,7 @@
init .rc file should additionally contain any actions associated with
its service.
-An example is the logcatd.rc and Android.mk files located in the
+An example is the userdebug logcatd.rc and Android.mk files located in the
system/core/logcat directory. The LOCAL\_INIT\_RC macro in the
Android.mk file places logcatd.rc in /system/etc/init/ during the
build process. Init loads logcatd.rc during the mount\_all command and
@@ -277,10 +277,6 @@
since it has some peculiarities for backwards compatibility reasons. The 'imports' section of
this file has more details on the order.
-`parse_apex_configs`
- Parses config file(s) from the mounted APEXes. Intented to be used only once
- when apexd notifies the mount event by setting apexd.status to ready.
-
`priority <priority>`
> Scheduling priority of the service process. This value has to be in range
-20 to 19. Default priority is 0. Priority is set via setpriority().
@@ -321,7 +317,7 @@
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
+> Create a UNIX domain socket named /dev/socket/_name_ and pass its fd to the
launched process. _type_ must be "dgram", "stream" or "seqpacket". User and
group default to 0. 'seclabel' is the SELinux security context for the
socket. It defaults to the service security context, as specified by
@@ -510,7 +506,11 @@
> Attempt to mount the named device at the directory _dir_
_flag_s include "ro", "rw", "remount", "noatime", ...
_options_ include "barrier=1", "noauto\_da\_alloc", "discard", ... as
- a comma separated string, eg: barrier=1,noauto\_da\_alloc
+ a comma separated string, e.g. barrier=1,noauto\_da\_alloc
+
+`parse_apex_configs`
+> Parses config file(s) from the mounted APEXes. Intended to be used only once
+ when apexd notifies the mount event by setting apexd.status to ready.
`restart <service>`
> Stops and restarts a running service, does nothing if the service is currently
@@ -572,7 +572,7 @@
`symlink <target> <path>`
> Create a symbolic link at _path_ with the value _target_
-`sysclktz <mins_west_of_gmt>`
+`sysclktz <minutes_west_of_gmt>`
> Set the system clock base (0 if system clock ticks in GMT)
`trigger <event>`
@@ -635,7 +635,7 @@
earlier executed trigger, or 2) place it in an Action with the same
trigger within the same file at an earlier line.
-Nonetheless, the defacto order for first stage mount devices is:
+Nonetheless, the de facto order for first stage mount devices is:
1. /init.rc is parsed then recursively each of its imports are
parsed.
2. The contents of /system/etc/init/ are alphabetized and parsed
@@ -725,7 +725,7 @@
A handy script named compare-bootcharts.py can be used to compare the
start/end time of selected processes. The aforementioned grab-bootchart.sh
will leave a bootchart tarball named bootchart.tgz at /tmp/android-bootchart.
-If two such barballs are preserved on the host machine under different
+If two such tarballs are preserved on the host machine under different
directories, the script can list the timestamps differences. For example:
Usage: system/core/init/compare-bootcharts.py _base-bootchart-dir_ _exp-bootchart-dir_
@@ -773,7 +773,7 @@
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.
-This flag can also be dynamically controled via the ctl.sigstop_on and ctl.sigstop_off properties.
+This flag can also be dynamically controlled via the ctl.sigstop_on and ctl.sigstop_off properties.
Below is an example of dynamically debugging logd via the above:
diff --git a/init/devices.cpp b/init/devices.cpp
index 1a77ba1..159c75e 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -21,8 +21,14 @@
#include <sys/sysmacros.h>
#include <unistd.h>
+#include <chrono>
+#include <map>
#include <memory>
+#include <string>
+#include <thread>
+#include <android-base/chrono_utils.h>
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
@@ -37,12 +43,16 @@
#error "Do not include init.h in files used by ueventd; it will expose init's globals"
#endif
+using namespace std::chrono_literals;
+
using android::base::Basename;
using android::base::Dirname;
+using android::base::ReadFileToString;
using android::base::Readlink;
using android::base::Realpath;
using android::base::StartsWith;
using android::base::StringPrintf;
+using android::base::Trim;
namespace android {
namespace init {
@@ -101,6 +111,31 @@
return true;
}
+// Given a path that may start with a virtual dm block device, populate
+// the supplied buffer with the dm module's instantiated name.
+// If it doesn't start with a virtual block device, or there is some
+// error, return false.
+static bool FindDmDevicePartition(const std::string& path, std::string* result) {
+ result->clear();
+ if (!StartsWith(path, "/devices/virtual/block/dm-")) return false;
+ if (getpid() == 1) return false; // first_stage_init has no sepolicy needs
+
+ static std::map<std::string, std::string> cache;
+ // wait_for_file will not work, the content is also delayed ...
+ for (android::base::Timer t; t.duration() < 200ms; std::this_thread::sleep_for(10ms)) {
+ if (ReadFileToString("/sys" + path + "/dm/name", result) && !result->empty()) {
+ // Got it, set cache with result, when node arrives
+ cache[path] = *result = Trim(*result);
+ return true;
+ }
+ }
+ auto it = cache.find(path);
+ if ((it == cache.end()) || (it->second.empty())) return false;
+ // Return cached results, when node goes away
+ *result = it->second;
+ return true;
+}
+
Permissions::Permissions(const std::string& name, mode_t perm, uid_t uid, gid_t gid)
: name_(name), perm_(perm), uid_(uid), gid_(gid), prefix_(false), wildcard_(false) {
// Set 'prefix_' or 'wildcard_' based on the below cases:
@@ -293,6 +328,7 @@
std::vector<std::string> DeviceHandler::GetBlockDeviceSymlinks(const Uevent& uevent) const {
std::string device;
std::string type;
+ std::string partition;
if (FindPlatformDevice(uevent.path, &device)) {
// Skip /devices/platform or /devices/ if present
@@ -310,6 +346,8 @@
type = "pci";
} else if (FindVbdDevicePrefix(uevent.path, &device)) {
type = "vbd";
+ } else if (FindDmDevicePartition(uevent.path, &partition)) {
+ return {"/dev/block/mapper/" + partition};
} else {
return {};
}
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 4b0f05d..d458924 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -78,6 +78,7 @@
ListenerAction HandleBlockDevice(const std::string& name, const Uevent&);
bool InitRequiredDevices();
bool InitMappedDevice(const std::string& verity_device);
+ bool InitDeviceMapper();
bool CreateLogicalPartitions();
bool MountPartition(const Fstab::iterator& begin, bool erase_used_fstab_entry,
Fstab::iterator* end = nullptr);
@@ -97,6 +98,7 @@
virtual bool SetUpDmVerity(FstabEntry* fstab_entry) = 0;
bool need_dm_verity_;
+ bool gsi_not_on_userdata_ = false;
Fstab fstab_;
std::string lp_metadata_partition_;
@@ -267,8 +269,6 @@
}
required_devices_partition_names_.emplace(super_partition_name_);
- // When booting from live GSI images, userdata is the super device.
- required_devices_partition_names_.emplace("userdata");
return true;
}
@@ -281,25 +281,7 @@
}
if (IsDmLinearEnabled() || need_dm_verity_) {
- const std::string dm_path = "/devices/virtual/misc/device-mapper";
- bool found = false;
- auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) {
- if (uevent.path == dm_path) {
- device_handler_->HandleUevent(uevent);
- found = true;
- return ListenerAction::kStop;
- }
- return ListenerAction::kContinue;
- };
- uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path, dm_callback);
- if (!found) {
- LOG(INFO) << "device-mapper device not found in /sys, waiting for its uevent";
- Timer t;
- uevent_listener_.Poll(dm_callback, 10s);
- LOG(INFO) << "Wait for device-mapper returned after " << t;
- }
- if (!found) {
- LOG(ERROR) << "device-mapper device not found after polling timeout";
+ if (!InitDeviceMapper()) {
return false;
}
}
@@ -327,11 +309,36 @@
return true;
}
+bool FirstStageMount::InitDeviceMapper() {
+ const std::string dm_path = "/devices/virtual/misc/device-mapper";
+ bool found = false;
+ auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) {
+ if (uevent.path == dm_path) {
+ device_handler_->HandleUevent(uevent);
+ found = true;
+ return ListenerAction::kStop;
+ }
+ return ListenerAction::kContinue;
+ };
+ uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path, dm_callback);
+ if (!found) {
+ LOG(INFO) << "device-mapper device not found in /sys, waiting for its uevent";
+ Timer t;
+ uevent_listener_.Poll(dm_callback, 10s);
+ LOG(INFO) << "Wait for device-mapper returned after " << t;
+ }
+ if (!found) {
+ LOG(ERROR) << "device-mapper device not found after polling timeout";
+ return false;
+ }
+ return true;
+}
+
bool FirstStageMount::InitDmLinearBackingDevices(const android::fs_mgr::LpMetadata& metadata) {
auto partition_names = android::fs_mgr::GetBlockDevicePartitionNames(metadata);
for (const auto& partition_name : partition_names) {
- const auto super_device = android::fs_mgr::GetMetadataSuperBlockDevice(metadata);
- if (partition_name == android::fs_mgr::GetBlockDevicePartitionName(*super_device)) {
+ // The super partition was found in the earlier pass.
+ if (partition_name == super_partition_name_) {
continue;
}
required_devices_partition_names_.emplace(partition_name);
@@ -499,6 +506,10 @@
if (system_partition == fstab_.end()) return true;
if (MountPartition(system_partition, false)) {
+ if (gsi_not_on_userdata_ && fs_mgr_verity_is_check_at_most_once(*system_partition)) {
+ LOG(ERROR) << "check_most_at_once forbidden on external media";
+ return false;
+ }
SwitchRoot("/system");
} else {
PLOG(ERROR) << "Failed to mount /system";
@@ -612,7 +623,29 @@
return;
}
- if (!android::fs_mgr::CreateLogicalPartitions(*metadata.get(), "/dev/block/by-name/userdata")) {
+ if (!InitDmLinearBackingDevices(*metadata.get())) {
+ return;
+ }
+
+ // Device-mapper might not be ready if the device doesn't use DAP or verity
+ // (for example, hikey).
+ if (access("/dev/device-mapper", F_OK) && !InitDeviceMapper()) {
+ return;
+ }
+
+ // Find the name of the super partition for the GSI. It will either be
+ // "userdata", or a block device such as an sdcard. There are no by-name
+ // partitions other than userdata that we support installing GSIs to.
+ auto super = GetMetadataSuperBlockDevice(*metadata.get());
+ std::string super_name = android::fs_mgr::GetBlockDevicePartitionName(*super);
+ std::string super_path;
+ if (super_name == "userdata") {
+ super_path = "/dev/block/by-name/" + super_name;
+ } else {
+ super_path = "/dev/block/" + super_name;
+ }
+
+ if (!android::fs_mgr::CreateLogicalPartitions(*metadata.get(), super_path)) {
LOG(ERROR) << "GSI partition layout could not be instantiated";
return;
}
@@ -630,6 +663,7 @@
fstab_.erase(system_partition);
}
fstab_.emplace_back(BuildGsiSystemFstabEntry());
+ gsi_not_on_userdata_ = (super_name != "userdata");
}
bool FirstStageMountVBootV1::GetDmVerityDevices() {
diff --git a/init/init.cpp b/init/init.cpp
index a5f4549..0f44efd 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -45,6 +45,7 @@
#include <libavb/libavb.h>
#include <libgsi/libgsi.h>
#include <processgroup/processgroup.h>
+#include <processgroup/setup.h>
#include <selinux/android.h>
#ifndef RECOVERY
@@ -357,8 +358,8 @@
static Result<Success> SetupCgroupsAction(const BuiltinArguments&) {
// Have to create <CGROUPS_RC_DIR> using make_dir function
// for appropriate sepolicy to be set for it
- make_dir(CGROUPS_RC_DIR, 0711);
- if (!CgroupSetupCgroups()) {
+ make_dir(android::base::Dirname(CGROUPS_RC_PATH), 0711);
+ if (!CgroupSetup()) {
return ErrnoError() << "Failed to setup cgroups";
}
diff --git a/init/mount_handler.cpp b/init/mount_handler.cpp
index 12dfc6d..c8f0e76 100644
--- a/init/mount_handler.cpp
+++ b/init/mount_handler.cpp
@@ -27,6 +27,7 @@
#include <algorithm>
#include <string>
#include <utility>
+#include <vector>
#include <android-base/file.h>
#include <android-base/logging.h>
@@ -34,6 +35,7 @@
#include <android-base/strings.h>
#include <fs_mgr.h>
#include <fstab/fstab.h>
+#include <libdm/dm.h>
#include "epoll.h"
#include "property_service.h"
@@ -47,8 +49,13 @@
auto fields = android::base::Split(line, " ");
while (fields.size() < 3) fields.emplace_back("");
if (fields[0] == "/dev/root") {
- if (android::fs_mgr::Fstab fstab; android::fs_mgr::ReadDefaultFstab(&fstab)) {
- if (auto entry = GetEntryForMountPoint(&fstab, "/")) {
+ auto& dm = dm::DeviceMapper::Instance();
+ std::string path;
+ if (dm.GetDmDevicePathByName("system", &path) || dm.GetDmDevicePathByName("vroot", &path)) {
+ fields[0] = path;
+ } else if (android::fs_mgr::Fstab fstab; android::fs_mgr::ReadDefaultFstab(&fstab)) {
+ auto entry = GetEntryForMountPoint(&fstab, "/");
+ if (entry || (entry = GetEntryForMountPoint(&fstab, "/system"))) {
fields[0] = entry->blk_device;
}
}
@@ -77,14 +84,19 @@
struct stat sb;
if (stat(queue.c_str(), &sb) || !S_ISDIR(sb.st_mode)) value = "";
if (stat(entry.mount_point.c_str(), &sb) || !S_ISDIR(sb.st_mode)) value = "";
- // Skip the noise associated with APEX until there is a need
+ // Clear the noise associated with loopback and APEX.
if (android::base::StartsWith(value, "loop")) value = "";
+ if (android::base::StartsWith(entry.mount_point, "/apex/")) value = "";
}
- std::string property =
- "dev.mnt.blk" + ((entry.mount_point == "/") ? "/root" : entry.mount_point);
- std::replace(property.begin(), property.end(), '/', '.');
- if (value.empty() && android::base::GetProperty(property, "").empty()) return;
- property_set(property, value);
+ auto mount_prop = entry.mount_point;
+ if (mount_prop == "/") mount_prop = "/root";
+ std::replace(mount_prop.begin(), mount_prop.end(), '/', '.');
+ mount_prop = "dev.mnt.blk" + mount_prop;
+ // Set property even if its value does not change to trigger 'on property:'
+ // handling, except for clearing non-existent or already clear property.
+ // Goal is reduction of empty properties and associated triggers.
+ if (value.empty() && android::base::GetProperty(mount_prop, "").empty()) return;
+ property_set(mount_prop, value);
}
} // namespace
@@ -114,25 +126,27 @@
void MountHandler::MountHandlerFunction() {
rewind(fp_.get());
+ std::vector<MountHandlerEntry> touched;
+ auto untouched = mounts_;
char* buf = nullptr;
size_t len = 0;
- auto untouched = mounts_;
while (getline(&buf, &len, fp_.get()) != -1) {
- auto entry = ParseMount(std::string(buf, len));
+ auto entry = ParseMount(std::string(buf));
auto match = untouched.find(entry);
if (match == untouched.end()) {
- SetMountProperty(entry, true);
- mounts_.emplace(std::move(entry));
+ touched.emplace_back(std::move(entry));
} else {
untouched.erase(match);
}
}
free(buf);
for (auto entry : untouched) {
- auto match = mounts_.find(entry);
- if (match == mounts_.end()) continue;
- mounts_.erase(match);
SetMountProperty(entry, false);
+ mounts_.erase(entry);
+ }
+ for (auto entry : touched) {
+ SetMountProperty(entry, true);
+ mounts_.emplace(std::move(entry));
}
}
diff --git a/init/property_service.cpp b/init/property_service.cpp
index fc5538c..467568c 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -557,9 +557,8 @@
uint32_t result =
HandlePropertySet(prop_name, prop_value, socket.source_context(), cr, &error);
if (result != PROP_SUCCESS) {
- LOG(ERROR) << "Unable to set property '" << prop_name << "' to '" << prop_value
- << "' from uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid << ": "
- << error;
+ LOG(ERROR) << "Unable to set property '" << prop_name << "' from uid:" << cr.uid
+ << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
}
break;
@@ -579,9 +578,8 @@
std::string error;
uint32_t result = HandlePropertySet(name, value, socket.source_context(), cr, &error);
if (result != PROP_SUCCESS) {
- LOG(ERROR) << "Unable to set property '" << name << "' to '" << value
- << "' from uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid << ": "
- << error;
+ LOG(ERROR) << "Unable to set property '" << name << "' from uid:" << cr.uid
+ << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
}
socket.SendUint32(result);
break;
diff --git a/init/service.cpp b/init/service.cpp
index cba42c4..f5c13b9 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -177,7 +177,7 @@
Result<Success> Service::EnterNamespaces() const {
for (const auto& [nstype, path] : namespaces_to_enter_) {
auto fd = unique_fd{open(path.c_str(), O_RDONLY | O_CLOEXEC)};
- if (!fd) {
+ if (fd == -1) {
return ErrnoError() << "Could not open namespace at " << path;
}
if (setns(fd, nstype) == -1) {
@@ -756,6 +756,11 @@
if (args[2] != "r" && args[2] != "w" && args[2] != "rw") {
return Error() << "file type must be 'r', 'w' or 'rw'";
}
+ std::string expanded;
+ if (!expand_props(args[1], &expanded)) {
+ return Error() << "Could not expand property in file path '" << args[1] << "'";
+ }
+ args[1] = std::move(expanded);
if ((args[1][0] != '/') || (args[1].find("../") != std::string::npos)) {
return Error() << "file name must not be relative";
}
diff --git a/janitors/OWNERS b/janitors/OWNERS
index 0610b41..3e32c26 100644
--- a/janitors/OWNERS
+++ b/janitors/OWNERS
@@ -1,4 +1,6 @@
# OWNERS file for projects that don't really have owners so much as volunteer janitors.
+ccross@google.com
+dwillemsen@google.com
enh@google.com
hhb@google.com
narayan@google.com
diff --git a/libbacktrace/UnwindStack.h b/libbacktrace/UnwindStack.h
index 33c4282..4ec591d 100644
--- a/libbacktrace/UnwindStack.h
+++ b/libbacktrace/UnwindStack.h
@@ -58,7 +58,7 @@
bool Unwind(size_t num_ignore_frames, void* context) override;
- std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset);
+ std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset) override;
size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) override;
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index b4b8cd1..619bc56 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -18,7 +18,6 @@
// they correspond to features not used by our host development tools
// which are also hard or even impossible to port to native Win32
libcutils_nonwindows_sources = [
- "android_get_control_file.cpp",
"fs.cpp",
"hashmap.cpp",
"multiuser.cpp",
@@ -84,6 +83,8 @@
],
},
windows: {
+ host_ldlibs: ["-lws2_32"],
+
srcs: [
"socket_inaddr_any_server_windows.cpp",
"socket_network_client_windows.cpp",
@@ -92,9 +93,6 @@
],
enabled: true,
- shared: {
- enabled: false,
- },
cflags: [
"-D_GNU_SOURCE",
],
@@ -102,6 +100,7 @@
android: {
srcs: libcutils_nonwindows_sources + [
+ "android_get_control_file.cpp",
"android_reboot.cpp",
"ashmem-dev.cpp",
"fs_config.cpp",
@@ -236,6 +235,7 @@
"libbase",
"libjsoncpp",
"libprocessgroup",
+ "libcgrouprc",
]
cc_test {
@@ -250,7 +250,10 @@
name: "libcutils_test_static",
test_suites: ["device-tests"],
defaults: ["libcutils_test_default"],
- static_libs: ["libc"] + test_libraries,
+ static_libs: [
+ "libc",
+ "libcgrouprc_format",
+ ] + test_libraries,
stl: "libc++_static",
target: {
diff --git a/libcutils/android_get_control_env.h b/libcutils/android_get_control_env.h
index 638c831..a830269 100644
--- a/libcutils/android_get_control_env.h
+++ b/libcutils/android_get_control_env.h
@@ -14,20 +14,13 @@
* limitations under the License.
*/
-#ifndef __CUTILS_ANDROID_GET_CONTROL_ENV_H
-#define __CUTILS_ANDROID_GET_CONTROL_ENV_H
+#pragma once
-/* To declare library function hidden and internal */
-#define LIBCUTILS_HIDDEN __attribute__((visibility("hidden")))
+#include <sys/cdefs.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
+__BEGIN_DECLS
-LIBCUTILS_HIDDEN int __android_get_control_from_env(const char* prefix,
- const char* name);
-#ifdef __cplusplus
-}
-#endif
+int __android_get_control_from_env(const char* prefix, const char* name)
+ __attribute__((visibility("hidden")));
-#endif /* __CUTILS_ANDROID_GET_CONTROL_ENV_H */
+__END_DECLS
diff --git a/libcutils/android_get_control_file.cpp b/libcutils/android_get_control_file.cpp
index d8121f5..d5b0894 100644
--- a/libcutils/android_get_control_file.cpp
+++ b/libcutils/android_get_control_file.cpp
@@ -39,14 +39,14 @@
#include <sys/types.h>
#include <unistd.h>
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+
#include "android_get_control_env.h"
-#ifndef TEMP_FAILURE_RETRY
-#define TEMP_FAILURE_RETRY(exp) (exp) // KISS implementation
-#endif
-
-LIBCUTILS_HIDDEN int __android_get_control_from_env(const char* prefix,
- const char* name) {
+int __android_get_control_from_env(const char* prefix, const char* name) {
if (!prefix || !name) return -1;
char *key = NULL;
@@ -67,48 +67,33 @@
long fd = strtol(val, NULL, 10);
if (errno) return -1;
- // validity checking
+ // Since we are inheriting an fd, it could legitimately exceed _SC_OPEN_MAX
if ((fd < 0) || (fd > INT_MAX)) return -1;
- // Since we are inheriting an fd, it could legitimately exceed _SC_OPEN_MAX
-
// Still open?
-#if defined(F_GETFD) // Lowest overhead
if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD)) < 0) return -1;
-#elif defined(F_GETFL) // Alternate lowest overhead
- if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL)) < 0) return -1;
-#else // Hail Mary pass
- struct stat s;
- if (TEMP_FAILURE_RETRY(fstat(fd, &s)) < 0) return -1;
-#endif
return static_cast<int>(fd);
}
int android_get_control_file(const char* path) {
- int fd = __android_get_control_from_env(ANDROID_FILE_ENV_PREFIX, path);
+ std::string given_path;
+ if (!android::base::Realpath(path, &given_path)) return -1;
-#if defined(__linux__)
- // Find file path from /proc and make sure it is correct
- char *proc = NULL;
- if (asprintf(&proc, "/proc/self/fd/%d", fd) < 0) return -1;
- if (!proc) return -1;
-
- size_t len = strlen(path);
- // readlink() does not guarantee a nul byte, len+2 so we catch truncation.
- char *buf = static_cast<char *>(calloc(1, len + 2));
- if (!buf) {
- free(proc);
- return -1;
+ // Try path, then realpath(path), as keys to get the fd from env.
+ auto fd = __android_get_control_from_env(ANDROID_FILE_ENV_PREFIX, path);
+ if (fd < 0) {
+ fd = __android_get_control_from_env(ANDROID_FILE_ENV_PREFIX, given_path.c_str());
+ if (fd < 0) return fd;
}
- ssize_t ret = TEMP_FAILURE_RETRY(readlink(proc, buf, len + 1));
- free(proc);
- int cmp = (len != static_cast<size_t>(ret)) || strcmp(buf, path);
- free(buf);
- if (ret < 0) return -1;
- if (cmp != 0) return -1;
+
+ // Find file path from /proc and make sure it is correct
+ auto proc = android::base::StringPrintf("/proc/self/fd/%d", fd);
+ std::string fd_path;
+ if (!android::base::Realpath(proc, &fd_path)) return -1;
+
+ if (given_path != fd_path) return -1;
// It is what we think it is
-#endif
return fd;
}
diff --git a/libcutils/android_reboot.cpp b/libcutils/android_reboot.cpp
index ce41cd3..e0def71 100644
--- a/libcutils/android_reboot.cpp
+++ b/libcutils/android_reboot.cpp
@@ -23,12 +23,12 @@
#define TAG "android_reboot"
-int android_reboot(int cmd, int /*flags*/, const char* arg) {
+int android_reboot(unsigned cmd, int /*flags*/, const char* arg) {
int ret;
const char* restart_cmd = NULL;
char* prop_value;
- switch (static_cast<unsigned>(cmd)) {
+ switch (cmd) {
case ANDROID_RB_RESTART: // deprecated
case ANDROID_RB_RESTART2:
restart_cmd = "reboot";
diff --git a/libcutils/ashmem-dev.cpp b/libcutils/ashmem-dev.cpp
index e35b91a..e67b458 100644
--- a/libcutils/ashmem-dev.cpp
+++ b/libcutils/ashmem-dev.cpp
@@ -73,6 +73,8 @@
#ifndef __ANDROID_VNDK__
using openFdType = int (*)();
+static openFdType openFd;
+
openFdType initOpenAshmemFd() {
openFdType openFd = nullptr;
void* handle = dlopen("libashmemd_client.so", RTLD_NOW);
@@ -221,7 +223,10 @@
int fd = -1;
#ifndef __ANDROID_VNDK__
- static auto openFd = initOpenAshmemFd();
+ if (!openFd) {
+ openFd = initOpenAshmemFd();
+ }
+
if (openFd) {
fd = openFd();
}
@@ -480,3 +485,11 @@
return __ashmem_check_failure(fd, TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_GET_SIZE, NULL)));
}
+
+void ashmem_init() {
+#ifndef __ANDROID_VNDK__
+ pthread_mutex_lock(&__ashmem_lock);
+ openFd = initOpenAshmemFd();
+ pthread_mutex_unlock(&__ashmem_lock);
+#endif //__ANDROID_VNDK__
+}
diff --git a/libcutils/ashmem-host.cpp b/libcutils/ashmem-host.cpp
index bb990d5..32446d4 100644
--- a/libcutils/ashmem-host.cpp
+++ b/libcutils/ashmem-host.cpp
@@ -82,3 +82,5 @@
return buf.st_size;
}
+
+void ashmem_init() {}
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index a3df380..6217bc8 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -91,7 +91,7 @@
{ 00750, AID_ROOT, AID_SHELL, 0, "sbin" },
{ 00777, AID_ROOT, AID_ROOT, 0, "sdcard" },
{ 00751, AID_ROOT, AID_SDCARD_R, 0, "storage" },
- { 00755, AID_ROOT, AID_SHELL, 0, "system/bin" },
+ { 00751, AID_ROOT, AID_SHELL, 0, "system/bin" },
{ 00755, AID_ROOT, AID_ROOT, 0, "system/etc/ppp" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/vendor" },
{ 00751, AID_ROOT, AID_SHELL, 0, "system/xbin" },
diff --git a/libcutils/include/cutils/android_reboot.h b/libcutils/include/cutils/android_reboot.h
index 99030ed..cd27eef 100644
--- a/libcutils/include/cutils/android_reboot.h
+++ b/libcutils/include/cutils/android_reboot.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef __CUTILS_ANDROID_REBOOT_H__
-#define __CUTILS_ANDROID_REBOOT_H__
+#pragma once
#include <sys/cdefs.h>
@@ -36,10 +35,8 @@
/* Reboot or shutdown the system.
* This call uses ANDROID_RB_PROPERTY to request reboot to init process.
* Due to that, process calling this should have proper selinux permission
- * to write to the property. Otherwise, the call will fail.
+ * to write to the property or the call will fail.
*/
-int android_reboot(int cmd, int flags, const char *arg);
+int android_reboot(unsigned cmd, int flags, const char* arg);
__END_DECLS
-
-#endif /* __CUTILS_ANDROID_REBOOT_H__ */
diff --git a/libcutils/include/cutils/ashmem.h b/libcutils/include/cutils/ashmem.h
index d80caa6..abc5068 100644
--- a/libcutils/include/cutils/ashmem.h
+++ b/libcutils/include/cutils/ashmem.h
@@ -26,6 +26,7 @@
int ashmem_pin_region(int fd, size_t offset, size_t len);
int ashmem_unpin_region(int fd, size_t offset, size_t len);
int ashmem_get_size_region(int fd);
+void ashmem_init();
#ifdef __cplusplus
}
diff --git a/libcutils/sockets_unix.cpp b/libcutils/sockets_unix.cpp
index 2248817..6acdcd8 100644
--- a/libcutils/sockets_unix.cpp
+++ b/libcutils/sockets_unix.cpp
@@ -16,8 +16,6 @@
#include <cutils/sockets.h>
-#define LOG_TAG "socket-unix"
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -27,9 +25,6 @@
#include <time.h>
#include <unistd.h>
-#include <cutils/android_get_control_file.h>
-#include <log/log.h>
-
#include "android_get_control_env.h"
int socket_close(int sock) {
@@ -62,6 +57,7 @@
return writev(sock, iovec_buffers, num_buffers);
}
+#if defined(__ANDROID__)
int android_get_control_socket(const char* name) {
int fd = __android_get_control_from_env(ANDROID_SOCKET_ENV_PREFIX, name);
@@ -82,3 +78,8 @@
}
return -1;
}
+#else
+int android_get_control_socket(const char*) {
+ return -1;
+}
+#endif
diff --git a/libkeyutils/mini_keyctl.cpp b/libkeyutils/mini_keyctl.cpp
index e09c864..fe89e62 100644
--- a/libkeyutils/mini_keyctl.cpp
+++ b/libkeyutils/mini_keyctl.cpp
@@ -30,7 +30,6 @@
fprintf(stderr, "usage: mini-keyctl <action> [args,]\n");
fprintf(stderr, " mini-keyctl add <type> <desc> <data> <keyring>\n");
fprintf(stderr, " mini-keyctl padd <type> <desc> <keyring>\n");
- fprintf(stderr, " mini-keyctl dadd <type> <desc_prefix> <cert_dir> <keyring>\n");
fprintf(stderr, " mini-keyctl unlink <key> <keyring>\n");
fprintf(stderr, " mini-keyctl restrict_keyring <keyring>\n");
fprintf(stderr, " mini-keyctl security <key>\n");
@@ -56,14 +55,6 @@
std::string data = argv[4];
std::string keyring = argv[5];
return Add(type, desc, data, keyring);
- } else if (action == "dadd") {
- if (argc != 6) Usage(1);
- std::string type = argv[2];
- // The key description contains desc_prefix and an index.
- std::string desc_prefix = argv[3];
- std::string cert_dir = argv[4];
- std::string keyring = argv[5];
- return AddCertsFromDir(type, desc_prefix, cert_dir, keyring);
} else if (action == "padd") {
if (argc != 5) Usage(1);
std::string type = argv[2];
diff --git a/libkeyutils/mini_keyctl_utils.cpp b/libkeyutils/mini_keyctl_utils.cpp
index 9fe2dfe..b012a33 100644
--- a/libkeyutils/mini_keyctl_utils.cpp
+++ b/libkeyutils/mini_keyctl_utils.cpp
@@ -18,6 +18,7 @@
#include <dirent.h>
#include <errno.h>
+#include <error.h>
#include <sys/types.h>
#include <unistd.h>
@@ -29,7 +30,6 @@
#include <vector>
#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>
@@ -47,22 +47,18 @@
// kernel keyring, the id is looked up from /proc/keys. The keyring description may contain other
// information in the descritption section depending on the key type, only the first word in the
// keyring description is used for searching.
-static bool GetKeyringId(const std::string& keyring_desc, key_serial_t* keyring_id) {
- if (!keyring_id) {
- LOG(ERROR) << "keyring_id is null";
- return false;
- }
-
+static key_serial_t GetKeyringIdOrDie(const std::string& keyring_desc) {
// If the keyring id is already a hex number, directly convert it to keyring id
- if (android::base::ParseInt(keyring_desc.c_str(), keyring_id)) {
- return true;
+ key_serial_t keyring_id;
+ if (android::base::ParseInt(keyring_desc.c_str(), &keyring_id)) {
+ return keyring_id;
}
// Only keys allowed by SELinux rules will be shown here.
std::ifstream proc_keys_file("/proc/keys");
if (!proc_keys_file.is_open()) {
- PLOG(ERROR) << "Failed to open /proc/keys";
- return false;
+ error(1, errno, "Failed to open /proc/keys");
+ return -1;
}
std::string line;
@@ -80,68 +76,19 @@
if (key_type != "keyring" || key_desc_prefix != key_desc_pattern) {
continue;
}
- *keyring_id = std::stoi(key_id, nullptr, 16);
- return true;
- }
- return false;
-}
-
-int AddCertsFromDir(const std::string& type, const std::string& desc_prefix,
- const std::string& cert_dir, const std::string& keyring) {
- key_serial_t keyring_id;
- if (!GetKeyringId(keyring, &keyring_id)) {
- LOG(ERROR) << "Can not find keyring id";
- return 1;
- }
-
- std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(cert_dir.c_str()), closedir);
- if (!dir) {
- PLOG(WARNING) << "Failed to open directory " << cert_dir;
- return 1;
- }
- int keys_added = 0;
- struct dirent* dp;
- while ((dp = readdir(dir.get())) != NULL) {
- if (dp->d_type != DT_REG) {
- continue;
+ if (!android::base::ParseInt(key_id.c_str(), &keyring_id)) {
+ error(1, 0, "Unexpected key format in /proc/keys");
+ return -1;
}
- std::string cert_path = cert_dir + "/" + dp->d_name;
- std::string cert_buf;
- if (!android::base::ReadFileToString(cert_path, &cert_buf, false /* follow_symlinks */)) {
- LOG(ERROR) << "Failed to read " << cert_path;
- continue;
- }
-
- if (cert_buf.size() > kMaxCertSize) {
- LOG(ERROR) << "Certficate size too large: " << cert_path;
- continue;
- }
-
- // Add key to keyring.
- int key_desc_index = keys_added;
- std::string key_desc = desc_prefix + std::to_string(key_desc_index);
- key_serial_t key =
- add_key(type.c_str(), key_desc.c_str(), &cert_buf[0], cert_buf.size(), keyring_id);
- if (key < 0) {
- PLOG(ERROR) << "Failed to add key to keyring: " << cert_path;
- continue;
- }
- LOG(INFO) << "Key " << cert_path << " added to " << keyring << " with key id 0x" << std::hex
- << key;
- keys_added++;
+ return keyring_id;
}
- return 0;
+ return -1;
}
int Unlink(key_serial_t key, const std::string& keyring) {
- key_serial_t keyring_id;
- if (!GetKeyringId(keyring, &keyring_id)) {
- LOG(ERROR) << "Can't find keyring " << keyring;
- return 1;
- }
-
+ key_serial_t keyring_id = GetKeyringIdOrDie(keyring);
if (keyctl_unlink(key, keyring_id) < 0) {
- PLOG(ERROR) << "Failed to unlink key 0x" << std::hex << key << " from keyring " << keyring_id;
+ error(1, errno, "Failed to unlink key %x from keyring %s", key, keyring.c_str());
return 1;
}
return 0;
@@ -150,63 +97,49 @@
int Add(const std::string& type, const std::string& desc, const std::string& data,
const std::string& keyring) {
if (data.size() > kMaxCertSize) {
- LOG(ERROR) << "Certificate too large";
+ error(1, 0, "Certificate too large");
return 1;
}
- key_serial_t keyring_id;
- if (!GetKeyringId(keyring, &keyring_id)) {
- LOG(ERROR) << "Can not find keyring id";
- return 1;
- }
-
+ key_serial_t keyring_id = GetKeyringIdOrDie(keyring);
key_serial_t key = add_key(type.c_str(), desc.c_str(), data.c_str(), data.size(), keyring_id);
if (key < 0) {
- PLOG(ERROR) << "Failed to add key";
+ error(1, errno, "Failed to add key");
return 1;
}
- LOG(INFO) << "Key " << desc << " added to " << keyring << " with key id: 0x" << std::hex << key;
+ std::cout << key << std::endl;
return 0;
}
int Padd(const std::string& type, const std::string& desc, const std::string& keyring) {
- key_serial_t keyring_id;
- if (!GetKeyringId(keyring, &keyring_id)) {
- LOG(ERROR) << "Can not find keyring id";
- return 1;
- }
+ key_serial_t keyring_id = GetKeyringIdOrDie(keyring);
// read from stdin to get the certificates
std::istreambuf_iterator<char> begin(std::cin), end;
std::string data(begin, end);
if (data.size() > kMaxCertSize) {
- LOG(ERROR) << "Certificate too large";
+ error(1, 0, "Certificate too large");
return 1;
}
key_serial_t key = add_key(type.c_str(), desc.c_str(), data.c_str(), data.size(), keyring_id);
if (key < 0) {
- PLOG(ERROR) << "Failed to add key";
+ error(1, errno, "Failed to add key");
return 1;
}
- LOG(INFO) << "Key " << desc << " added to " << keyring << " with key id: 0x" << std::hex << key;
+ std::cout << key << std::endl;
return 0;
}
int RestrictKeyring(const std::string& keyring) {
- key_serial_t keyring_id;
- if (!GetKeyringId(keyring, &keyring_id)) {
- LOG(ERROR) << "Cannot find keyring id";
- return 1;
- }
-
+ key_serial_t keyring_id = GetKeyringIdOrDie(keyring);
if (keyctl_restrict_keyring(keyring_id, nullptr, nullptr) < 0) {
- PLOG(ERROR) << "Cannot restrict keyring " << keyring;
+ error(1, errno, "Cannot restrict keyring '%s'", keyring.c_str());
return 1;
}
return 0;
@@ -219,11 +152,11 @@
context.resize(kMaxSupportedSize);
long retval = keyctl_get_security(key, context.data(), kMaxSupportedSize);
if (retval < 0) {
- PLOG(ERROR) << "Cannot get security context of key 0x" << std::hex << key;
+ error(1, errno, "Cannot get security context of key %x", key);
return std::string();
}
if (retval > kMaxSupportedSize) {
- LOG(ERROR) << "The key has unexpectedly long security context than " << kMaxSupportedSize;
+ error(1, 0, "The key has unexpectedly long security context than %d", kMaxSupportedSize);
return std::string();
}
context.resize(retval);
diff --git a/libkeyutils/mini_keyctl_utils.h b/libkeyutils/mini_keyctl_utils.h
index 804a357..3616831 100644
--- a/libkeyutils/mini_keyctl_utils.h
+++ b/libkeyutils/mini_keyctl_utils.h
@@ -18,11 +18,6 @@
#include <string>
-// Add all files in a directory as certificates to a keyring. |keyring| could be the keyring
-// description or keyring id in hex.
-int AddCertsFromDir(const std::string& type, const std::string& desc_prefix,
- const std::string& cert_dir, const std::string& keyring);
-
// Add key to a keyring. Returns non-zero if error happens.
int Add(const std::string& type, const std::string& desc, const std::string& data,
const std::string& keyring);
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 9b41ebe..da475cb 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -139,6 +139,5 @@
llndk_library {
name: "liblog",
symbol_file: "liblog.map.txt",
- unversioned: true,
export_include_dirs: ["include_vndk"],
}
diff --git a/liblog/logger_name.cpp b/liblog/logger_name.cpp
index 3aa6841..ece0550 100644
--- a/liblog/logger_name.cpp
+++ b/liblog/logger_name.cpp
@@ -50,8 +50,9 @@
unsigned int ret;
if (!logName) {
- return static_cast<log_id_t>(0xFFFFFFFF);
+ return static_cast<log_id_t>(LOG_ID_MAX);
}
+
b = strrchr(logName, '/');
if (!b) {
b = logName;
@@ -65,5 +66,6 @@
return static_cast<log_id_t>(ret);
}
}
- return static_cast<log_id_t>(0xFFFFFFFF); /* should never happen */
+
+ return static_cast<log_id_t>(LOG_ID_MAX);
}
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp
index b9f0dbf..66cb49f 100644
--- a/libnativeloader/Android.bp
+++ b/libnativeloader/Android.bp
@@ -24,6 +24,13 @@
"libnativebridge",
"libbase",
],
+ target: {
+ android: {
+ shared_libs: [
+ "libdl_android",
+ ],
+ },
+ },
required: [
"llndk.libraries.txt",
"vndksp.libraries.txt",
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 1c2581f..5cc0857 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -288,8 +288,9 @@
// Give access to VNDK-SP libraries from the 'vndk' namespace.
vndk_ns = android_get_exported_namespace(kVndkNamespaceName);
- LOG_ALWAYS_FATAL_IF(vndk_ns == nullptr, "Cannot find \"%s\" namespace for %s apks",
- kVndkNamespaceName, origin_partition);
+ if (vndk_ns == nullptr) {
+ ALOGW("Cannot find \"%s\" namespace for %s apks", kVndkNamespaceName, origin_partition);
+ }
// Different name is useful for debugging
namespace_name = kVendorClassloaderNamespaceName;
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index d97f09f..78a02e5 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -31,6 +31,7 @@
},
shared_libs: [
"libbase",
+ "libcgrouprc",
"libjsoncpp",
],
// for cutils/android_filesystem_config.h
@@ -45,5 +46,6 @@
cflags: [
"-Wall",
"-Werror",
+ "-Wexit-time-destructors",
],
}
diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp
index b3b497f..6cd6b6e 100644
--- a/libprocessgroup/cgroup_map.cpp
+++ b/libprocessgroup/cgroup_map.cpp
@@ -44,241 +44,42 @@
using android::base::StringPrintf;
using android::base::unique_fd;
-static constexpr const char* CGROUPS_DESC_FILE = "/etc/cgroups.json";
-static constexpr const char* CGROUPS_DESC_VENDOR_FILE = "/vendor/etc/cgroups.json";
-
static constexpr const char* CGROUP_PROCS_FILE = "/cgroup.procs";
static constexpr const char* CGROUP_TASKS_FILE = "/tasks";
static constexpr const char* CGROUP_TASKS_FILE_V2 = "/cgroup.tasks";
-static bool Mkdir(const std::string& path, mode_t mode, const std::string& uid,
- const std::string& gid) {
- if (mode == 0) {
- mode = 0755;
- }
-
- if (mkdir(path.c_str(), mode) != 0) {
- /* chmod in case the directory already exists */
- if (errno == EEXIST) {
- if (fchmodat(AT_FDCWD, path.c_str(), mode, AT_SYMLINK_NOFOLLOW) != 0) {
- // /acct is a special case when the directory already exists
- // TODO: check if file mode is already what we want instead of using EROFS
- if (errno != EROFS) {
- PLOG(ERROR) << "fchmodat() failed for " << path;
- return false;
- }
- }
- } else {
- PLOG(ERROR) << "mkdir() failed for " << path;
- return false;
- }
- }
-
- if (uid.empty()) {
- return true;
- }
-
- passwd* uid_pwd = getpwnam(uid.c_str());
- if (!uid_pwd) {
- PLOG(ERROR) << "Unable to decode UID for '" << uid << "'";
- return false;
- }
-
- uid_t pw_uid = uid_pwd->pw_uid;
- gid_t gr_gid = -1;
- if (!gid.empty()) {
- group* gid_pwd = getgrnam(gid.c_str());
- if (!gid_pwd) {
- PLOG(ERROR) << "Unable to decode GID for '" << gid << "'";
- return false;
- }
- gr_gid = gid_pwd->gr_gid;
- }
-
- if (lchown(path.c_str(), pw_uid, gr_gid) < 0) {
- PLOG(ERROR) << "lchown() failed for " << path;
- return false;
- }
-
- /* chown may have cleared S_ISUID and S_ISGID, chmod again */
- if (mode & (S_ISUID | S_ISGID)) {
- if (fchmodat(AT_FDCWD, path.c_str(), mode, AT_SYMLINK_NOFOLLOW) != 0) {
- PLOG(ERROR) << "fchmodat() failed for " << path;
- return false;
- }
- }
-
- return true;
+uint32_t CgroupController::version() const {
+ CHECK(HasValue());
+ return ACgroupController_getVersion(controller_);
}
-static bool ReadDescriptorsFromFile(const std::string& file_name,
- std::map<std::string, CgroupDescriptor>* descriptors) {
- std::vector<CgroupDescriptor> result;
- std::string json_doc;
-
- if (!android::base::ReadFileToString(file_name, &json_doc)) {
- PLOG(ERROR) << "Failed to read task profiles from " << file_name;
- return false;
- }
-
- Json::Reader reader;
- Json::Value root;
- if (!reader.parse(json_doc, root)) {
- LOG(ERROR) << "Failed to parse cgroups description: " << reader.getFormattedErrorMessages();
- return false;
- }
-
- if (root.isMember("Cgroups")) {
- const Json::Value& cgroups = root["Cgroups"];
- for (Json::Value::ArrayIndex i = 0; i < cgroups.size(); ++i) {
- std::string name = cgroups[i]["Controller"].asString();
- auto iter = descriptors->find(name);
- if (iter == descriptors->end()) {
- descriptors->emplace(name, CgroupDescriptor(1, name, cgroups[i]["Path"].asString(),
- std::strtoul(cgroups[i]["Mode"].asString().c_str(), 0, 8),
- cgroups[i]["UID"].asString(), cgroups[i]["GID"].asString()));
- } else {
- iter->second = CgroupDescriptor(1, name, cgroups[i]["Path"].asString(),
- std::strtoul(cgroups[i]["Mode"].asString().c_str(), 0, 8),
- cgroups[i]["UID"].asString(), cgroups[i]["GID"].asString());
- }
- }
- }
-
- if (root.isMember("Cgroups2")) {
- const Json::Value& cgroups2 = root["Cgroups2"];
- auto iter = descriptors->find(CGROUPV2_CONTROLLER_NAME);
- if (iter == descriptors->end()) {
- descriptors->emplace(CGROUPV2_CONTROLLER_NAME, CgroupDescriptor(2, CGROUPV2_CONTROLLER_NAME, cgroups2["Path"].asString(),
- std::strtoul(cgroups2["Mode"].asString().c_str(), 0, 8),
- cgroups2["UID"].asString(), cgroups2["GID"].asString()));
- } else {
- iter->second = CgroupDescriptor(2, CGROUPV2_CONTROLLER_NAME, cgroups2["Path"].asString(),
- std::strtoul(cgroups2["Mode"].asString().c_str(), 0, 8),
- cgroups2["UID"].asString(), cgroups2["GID"].asString());
- }
- }
-
- return true;
+const char* CgroupController::name() const {
+ CHECK(HasValue());
+ return ACgroupController_getName(controller_);
}
-static bool ReadDescriptors(std::map<std::string, CgroupDescriptor>* descriptors) {
- // load system cgroup descriptors
- if (!ReadDescriptorsFromFile(CGROUPS_DESC_FILE, descriptors)) {
- return false;
- }
-
- // load vendor cgroup descriptors if the file exists
- if (!access(CGROUPS_DESC_VENDOR_FILE, F_OK) &&
- !ReadDescriptorsFromFile(CGROUPS_DESC_VENDOR_FILE, descriptors)) {
- return false;
- }
-
- return true;
+const char* CgroupController::path() const {
+ CHECK(HasValue());
+ return ACgroupController_getPath(controller_);
}
-// To avoid issues in sdk_mac build
-#if defined(__ANDROID__)
-
-static bool SetupCgroup(const CgroupDescriptor& descriptor) {
- const CgroupController* controller = descriptor.controller();
-
- // mkdir <path> [mode] [owner] [group]
- if (!Mkdir(controller->path(), descriptor.mode(), descriptor.uid(), descriptor.gid())) {
- LOG(ERROR) << "Failed to create directory for " << controller->name() << " cgroup";
- return false;
- }
-
- int result;
- if (controller->version() == 2) {
- result = mount("none", controller->path(), "cgroup2", MS_NODEV | MS_NOEXEC | MS_NOSUID,
- nullptr);
- } else {
- // Unfortunately historically cpuset controller was mounted using a mount command
- // different from all other controllers. This results in controller attributes not
- // to be prepended with controller name. For example this way instead of
- // /dev/cpuset/cpuset.cpus the attribute becomes /dev/cpuset/cpus which is what
- // the system currently expects.
- if (!strcmp(controller->name(), "cpuset")) {
- // mount cpuset none /dev/cpuset nodev noexec nosuid
- result = mount("none", controller->path(), controller->name(),
- MS_NODEV | MS_NOEXEC | MS_NOSUID, nullptr);
- } else {
- // mount cgroup none <path> nodev noexec nosuid <controller>
- result = mount("none", controller->path(), "cgroup", MS_NODEV | MS_NOEXEC | MS_NOSUID,
- controller->name());
- }
- }
-
- if (result < 0) {
- PLOG(ERROR) << "Failed to mount " << controller->name() << " cgroup";
- return false;
- }
-
- return true;
+bool CgroupController::HasValue() const {
+ return controller_ != nullptr;
}
-#else
+std::string CgroupController::GetTasksFilePath(const std::string& rel_path) const {
+ std::string tasks_path = path();
-// Stubs for non-Android targets.
-static bool SetupCgroup(const CgroupDescriptor&) {
- return false;
+ if (!rel_path.empty()) {
+ tasks_path += "/" + rel_path;
+ }
+ return (version() == 1) ? tasks_path + CGROUP_TASKS_FILE : tasks_path + CGROUP_TASKS_FILE_V2;
}
-#endif
-
-static bool WriteRcFile(const std::map<std::string, CgroupDescriptor>& descriptors) {
- std::string cgroup_rc_path = StringPrintf("%s/%s", CGROUPS_RC_DIR, CgroupMap::CGROUPS_RC_FILE);
- unique_fd fd(TEMP_FAILURE_RETRY(open(cgroup_rc_path.c_str(),
- O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC,
- S_IRUSR | S_IRGRP | S_IROTH)));
- if (fd < 0) {
- PLOG(ERROR) << "open() failed for " << cgroup_rc_path;
- return false;
- }
-
- CgroupFile fl;
- fl.version_ = CgroupFile::FILE_CURR_VERSION;
- fl.controller_count_ = descriptors.size();
- int ret = TEMP_FAILURE_RETRY(write(fd, &fl, sizeof(fl)));
- if (ret < 0) {
- PLOG(ERROR) << "write() failed for " << cgroup_rc_path;
- return false;
- }
-
- for (const auto& [name, descriptor] : descriptors) {
- ret = TEMP_FAILURE_RETRY(write(fd, descriptor.controller(), sizeof(CgroupController)));
- if (ret < 0) {
- PLOG(ERROR) << "write() failed for " << cgroup_rc_path;
- return false;
- }
- }
-
- return true;
-}
-
-CgroupController::CgroupController(uint32_t version, const std::string& name,
- const std::string& path) {
- version_ = version;
- strncpy(name_, name.c_str(), sizeof(name_) - 1);
- name_[sizeof(name_) - 1] = '\0';
- strncpy(path_, path.c_str(), sizeof(path_) - 1);
- path_[sizeof(path_) - 1] = '\0';
-}
-
-std::string CgroupController::GetTasksFilePath(const std::string& path) const {
- std::string tasks_path = path_;
-
- if (!path.empty()) {
- tasks_path += "/" + path;
- }
- return (version_ == 1) ? tasks_path + CGROUP_TASKS_FILE : tasks_path + CGROUP_TASKS_FILE_V2;
-}
-
-std::string CgroupController::GetProcsFilePath(const std::string& path, uid_t uid,
+std::string CgroupController::GetProcsFilePath(const std::string& rel_path, uid_t uid,
pid_t pid) const {
- std::string proc_path(path_);
- proc_path.append("/").append(path);
+ std::string proc_path(path());
+ proc_path.append("/").append(rel_path);
proc_path = regex_replace(proc_path, std::regex("<uid>"), std::to_string(uid));
proc_path = regex_replace(proc_path, std::regex("<pid>"), std::to_string(pid));
@@ -299,7 +100,7 @@
return true;
}
- std::string cg_tag = StringPrintf(":%s:", name_);
+ std::string cg_tag = StringPrintf(":%s:", name());
size_t start_pos = content.find(cg_tag);
if (start_pos == std::string::npos) {
return false;
@@ -316,25 +117,12 @@
return true;
}
-CgroupDescriptor::CgroupDescriptor(uint32_t version, const std::string& name,
- const std::string& path, mode_t mode, const std::string& uid,
- const std::string& gid)
- : controller_(version, name, path), mode_(mode), uid_(uid), gid_(gid) {}
-
-CgroupMap::CgroupMap() : cg_file_data_(nullptr), cg_file_size_(0) {
+CgroupMap::CgroupMap() {
if (!LoadRcFile()) {
LOG(ERROR) << "CgroupMap::LoadRcFile called for [" << getpid() << "] failed";
}
}
-CgroupMap::~CgroupMap() {
- if (cg_file_data_) {
- munmap(cg_file_data_, cg_file_size_);
- cg_file_data_ = nullptr;
- cg_file_size_ = 0;
- }
-}
-
CgroupMap& CgroupMap::GetInstance() {
// Deliberately leak this object to avoid a race between destruction on
// process exit and concurrent access from another thread.
@@ -343,129 +131,46 @@
}
bool CgroupMap::LoadRcFile() {
- struct stat sb;
-
- if (cg_file_data_) {
- // Data already initialized
- return true;
+ if (!loaded_) {
+ loaded_ = (ACgroupFile_getVersion() != 0);
}
-
- std::string cgroup_rc_path = StringPrintf("%s/%s", CGROUPS_RC_DIR, CGROUPS_RC_FILE);
- unique_fd fd(TEMP_FAILURE_RETRY(open(cgroup_rc_path.c_str(), O_RDONLY | O_CLOEXEC)));
- if (fd < 0) {
- PLOG(ERROR) << "open() failed for " << cgroup_rc_path;
- return false;
- }
-
- if (fstat(fd, &sb) < 0) {
- PLOG(ERROR) << "fstat() failed for " << cgroup_rc_path;
- return false;
- }
-
- size_t file_size = sb.st_size;
- if (file_size < sizeof(CgroupFile)) {
- LOG(ERROR) << "Invalid file format " << cgroup_rc_path;
- return false;
- }
-
- CgroupFile* file_data = (CgroupFile*)mmap(nullptr, file_size, PROT_READ, MAP_SHARED, fd, 0);
- if (file_data == MAP_FAILED) {
- PLOG(ERROR) << "Failed to mmap " << cgroup_rc_path;
- return false;
- }
-
- if (file_data->version_ != CgroupFile::FILE_CURR_VERSION) {
- LOG(ERROR) << cgroup_rc_path << " file version mismatch";
- munmap(file_data, file_size);
- return false;
- }
-
- if (file_size != sizeof(CgroupFile) + file_data->controller_count_ * sizeof(CgroupController)) {
- LOG(ERROR) << cgroup_rc_path << " file has invalid size";
- munmap(file_data, file_size);
- return false;
- }
-
- cg_file_data_ = file_data;
- cg_file_size_ = file_size;
-
- return true;
+ return loaded_;
}
void CgroupMap::Print() const {
- if (!cg_file_data_) {
+ if (!loaded_) {
LOG(ERROR) << "CgroupMap::Print called for [" << getpid()
<< "] failed, RC file was not initialized properly";
return;
}
- LOG(INFO) << "File version = " << cg_file_data_->version_;
- LOG(INFO) << "File controller count = " << cg_file_data_->controller_count_;
+ LOG(INFO) << "File version = " << ACgroupFile_getVersion();
+ LOG(INFO) << "File controller count = " << ACgroupFile_getControllerCount();
LOG(INFO) << "Mounted cgroups:";
- CgroupController* controller = (CgroupController*)(cg_file_data_ + 1);
- for (int i = 0; i < cg_file_data_->controller_count_; i++, controller++) {
- LOG(INFO) << "\t" << controller->name() << " ver " << controller->version() << " path "
- << controller->path();
+
+ auto controller_count = ACgroupFile_getControllerCount();
+ for (uint32_t i = 0; i < controller_count; ++i) {
+ const ACgroupController* controller = ACgroupFile_getController(i);
+ LOG(INFO) << "\t" << ACgroupController_getName(controller) << " ver "
+ << ACgroupController_getVersion(controller) << " path "
+ << ACgroupController_getPath(controller);
}
}
-bool CgroupMap::SetupCgroups() {
- std::map<std::string, CgroupDescriptor> descriptors;
-
- // load cgroups.json file
- if (!ReadDescriptors(&descriptors)) {
- LOG(ERROR) << "Failed to load cgroup description file";
- return false;
- }
-
- // setup cgroups
- for (const auto& [name, descriptor] : descriptors) {
- if (!SetupCgroup(descriptor)) {
- // issue a warning and proceed with the next cgroup
- // TODO: mark the descriptor as invalid and skip it in WriteRcFile()
- LOG(WARNING) << "Failed to setup " << name << " cgroup";
- }
- }
-
- // mkdir <CGROUPS_RC_DIR> 0711 system system
- if (!Mkdir(CGROUPS_RC_DIR, 0711, "system", "system")) {
- LOG(ERROR) << "Failed to create directory for <CGROUPS_RC_FILE> file";
- return false;
- }
-
- // Generate <CGROUPS_RC_FILE> file which can be directly mmapped into
- // process memory. This optimizes performance, memory usage
- // and limits infrormation shared with unprivileged processes
- // to the minimum subset of information from cgroups.json
- if (!WriteRcFile(descriptors)) {
- LOG(ERROR) << "Failed to write " << CGROUPS_RC_FILE << " file";
- return false;
- }
-
- std::string cgroup_rc_path = StringPrintf("%s/%s", CGROUPS_RC_DIR, CGROUPS_RC_FILE);
- // chmod 0644 <cgroup_rc_path>
- if (fchmodat(AT_FDCWD, cgroup_rc_path.c_str(), 0644, AT_SYMLINK_NOFOLLOW) < 0) {
- PLOG(ERROR) << "fchmodat() failed";
- return false;
- }
-
- return true;
-}
-
-const CgroupController* CgroupMap::FindController(const std::string& name) const {
- if (!cg_file_data_) {
+CgroupController CgroupMap::FindController(const std::string& name) const {
+ if (!loaded_) {
LOG(ERROR) << "CgroupMap::FindController called for [" << getpid()
<< "] failed, RC file was not initialized properly";
- return nullptr;
+ return CgroupController(nullptr);
}
- // skip the file header to get to the first controller
- CgroupController* controller = (CgroupController*)(cg_file_data_ + 1);
- for (int i = 0; i < cg_file_data_->controller_count_; i++, controller++) {
- if (name == controller->name()) {
- return controller;
+ auto controller_count = ACgroupFile_getControllerCount();
+ for (uint32_t i = 0; i < controller_count; ++i) {
+ const ACgroupController* controller = ACgroupFile_getController(i);
+ if (name == ACgroupController_getName(controller)) {
+ return CgroupController(controller);
}
}
- return nullptr;
+ return CgroupController(nullptr);
}
diff --git a/libprocessgroup/cgroup_map.h b/libprocessgroup/cgroup_map.h
index 1c355cd..d765e60 100644
--- a/libprocessgroup/cgroup_map.h
+++ b/libprocessgroup/cgroup_map.h
@@ -20,77 +20,43 @@
#include <sys/types.h>
#include <map>
+#include <memory>
#include <mutex>
#include <string>
+#include <vector>
-// Minimal controller description to be mmapped into process address space
+#include <android/cgrouprc.h>
+
+// Convenient wrapper of an ACgroupController pointer.
class CgroupController {
public:
- CgroupController() {}
- CgroupController(uint32_t version, const std::string& name, const std::string& path);
+ // Does not own controller
+ explicit CgroupController(const ACgroupController* controller) : controller_(controller) {}
- uint32_t version() const { return version_; }
- const char* name() const { return name_; }
- const char* path() const { return path_; }
+ uint32_t version() const;
+ const char* name() const;
+ const char* path() const;
+
+ bool HasValue() const;
std::string GetTasksFilePath(const std::string& path) const;
std::string GetProcsFilePath(const std::string& path, uid_t uid, pid_t pid) const;
bool GetTaskGroup(int tid, std::string* group) const;
-
private:
- static constexpr size_t CGROUP_NAME_BUF_SZ = 16;
- static constexpr size_t CGROUP_PATH_BUF_SZ = 32;
-
- uint32_t version_;
- char name_[CGROUP_NAME_BUF_SZ];
- char path_[CGROUP_PATH_BUF_SZ];
-};
-
-// Complete controller description for mounting cgroups
-class CgroupDescriptor {
- public:
- CgroupDescriptor(uint32_t version, const std::string& name, const std::string& path,
- mode_t mode, const std::string& uid, const std::string& gid);
-
- const CgroupController* controller() const { return &controller_; }
- mode_t mode() const { return mode_; }
- std::string uid() const { return uid_; }
- std::string gid() const { return gid_; }
-
- private:
- CgroupController controller_;
- mode_t mode_;
- std::string uid_;
- std::string gid_;
-};
-
-struct CgroupFile {
- static constexpr uint32_t FILE_VERSION_1 = 1;
- static constexpr uint32_t FILE_CURR_VERSION = FILE_VERSION_1;
-
- uint32_t version_;
- uint32_t controller_count_;
- CgroupController controllers_[];
+ const ACgroupController* controller_ = nullptr;
};
class CgroupMap {
public:
- static constexpr const char* CGROUPS_RC_FILE = "cgroup.rc";
-
// Selinux policy ensures only init process can successfully use this function
static bool SetupCgroups();
static CgroupMap& GetInstance();
-
- const CgroupController* FindController(const std::string& name) const;
+ CgroupController FindController(const std::string& name) const;
private:
- struct CgroupFile* cg_file_data_;
- size_t cg_file_size_;
-
+ bool loaded_ = false;
CgroupMap();
- ~CgroupMap();
-
bool LoadRcFile();
void Print() const;
};
diff --git a/libprocessgroup/cgrouprc/Android.bp b/libprocessgroup/cgrouprc/Android.bp
new file mode 100644
index 0000000..6848620
--- /dev/null
+++ b/libprocessgroup/cgrouprc/Android.bp
@@ -0,0 +1,61 @@
+// Copyright (C) 2019 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.
+
+cc_library {
+ name: "libcgrouprc",
+ host_supported: true,
+ recovery_available: true,
+ // Do not ever mark this as vendor_available; otherwise, vendor modules
+ // that links to the static library will behave unexpectedly. All on-device
+ // modules should use libprocessgroup which links to the LL-NDK library
+ // defined below. The static library is built for tests.
+ vendor_available: false,
+ srcs: [
+ "cgroup_controller.cpp",
+ "cgroup_file.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ export_include_dirs: [
+ "include",
+ ],
+ header_libs: [
+ "libprocessgroup_headers",
+ ],
+ shared_libs: [
+ "libbase",
+ ],
+ static_libs: [
+ "libcgrouprc_format",
+ ],
+ stubs: {
+ symbol_file: "libcgrouprc.map.txt",
+ versions: ["29"],
+ },
+ target: {
+ linux: {
+ version_script: "libcgrouprc.map.txt",
+ },
+ },
+}
+
+llndk_library {
+ name: "libcgrouprc",
+ symbol_file: "libcgrouprc.map.txt",
+ export_include_dirs: [
+ "include",
+ ],
+}
diff --git a/libprocessgroup/cgrouprc/cgroup_controller.cpp b/libprocessgroup/cgrouprc/cgroup_controller.cpp
new file mode 100644
index 0000000..d064d31
--- /dev/null
+++ b/libprocessgroup/cgrouprc/cgroup_controller.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/cgrouprc.h>
+
+#include "cgrouprc_internal.h"
+
+// All ACgroupController_* functions implicitly convert the pointer back
+// to the original CgroupController pointer before invoking the member functions.
+
+uint32_t ACgroupController_getVersion(const ACgroupController* controller) {
+ CHECK(controller != nullptr);
+ return controller->version();
+}
+
+const char* ACgroupController_getName(const ACgroupController* controller) {
+ CHECK(controller != nullptr);
+ return controller->name();
+}
+
+const char* ACgroupController_getPath(const ACgroupController* controller) {
+ CHECK(controller != nullptr);
+ return controller->path();
+}
diff --git a/libprocessgroup/cgrouprc/cgroup_file.cpp b/libprocessgroup/cgrouprc/cgroup_file.cpp
new file mode 100644
index 0000000..e26d841
--- /dev/null
+++ b/libprocessgroup/cgrouprc/cgroup_file.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <memory>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
+#include <android/cgrouprc.h>
+#include <processgroup/processgroup.h>
+
+#include "cgrouprc_internal.h"
+
+using android::base::StringPrintf;
+using android::base::unique_fd;
+
+using android::cgrouprc::format::CgroupController;
+using android::cgrouprc::format::CgroupFile;
+
+static CgroupFile* LoadRcFile() {
+ struct stat sb;
+
+ unique_fd fd(TEMP_FAILURE_RETRY(open(CGROUPS_RC_PATH, O_RDONLY | O_CLOEXEC)));
+ if (fd < 0) {
+ PLOG(ERROR) << "open() failed for " << CGROUPS_RC_PATH;
+ return nullptr;
+ }
+
+ if (fstat(fd, &sb) < 0) {
+ PLOG(ERROR) << "fstat() failed for " << CGROUPS_RC_PATH;
+ return nullptr;
+ }
+
+ size_t file_size = sb.st_size;
+ if (file_size < sizeof(CgroupFile)) {
+ LOG(ERROR) << "Invalid file format " << CGROUPS_RC_PATH;
+ return nullptr;
+ }
+
+ CgroupFile* file_data = (CgroupFile*)mmap(nullptr, file_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (file_data == MAP_FAILED) {
+ PLOG(ERROR) << "Failed to mmap " << CGROUPS_RC_PATH;
+ return nullptr;
+ }
+
+ if (file_data->version_ != CgroupFile::FILE_CURR_VERSION) {
+ LOG(ERROR) << CGROUPS_RC_PATH << " file version mismatch";
+ munmap(file_data, file_size);
+ return nullptr;
+ }
+
+ auto expected = sizeof(CgroupFile) + file_data->controller_count_ * sizeof(CgroupController);
+ if (file_size != expected) {
+ LOG(ERROR) << CGROUPS_RC_PATH << " file has invalid size, expected " << expected
+ << ", actual " << file_size;
+ munmap(file_data, file_size);
+ return nullptr;
+ }
+
+ return file_data;
+}
+
+static CgroupFile* GetInstance() {
+ // Deliberately leak this object (not munmap) to avoid a race between destruction on
+ // process exit and concurrent access from another thread.
+ static auto* file = LoadRcFile();
+ return file;
+}
+
+uint32_t ACgroupFile_getVersion() {
+ auto file = GetInstance();
+ if (file == nullptr) return 0;
+ return file->version_;
+}
+
+uint32_t ACgroupFile_getControllerCount() {
+ auto file = GetInstance();
+ if (file == nullptr) return 0;
+ return file->controller_count_;
+}
+
+const ACgroupController* ACgroupFile_getController(uint32_t index) {
+ auto file = GetInstance();
+ if (file == nullptr) return nullptr;
+ CHECK(index < file->controller_count_);
+ // Although the object is not actually an ACgroupController object, all ACgroupController_*
+ // functions implicitly convert ACgroupController* back to CgroupController* before invoking
+ // member functions.
+ return static_cast<ACgroupController*>(&file->controllers_[index]);
+}
diff --git a/libprocessgroup/cgrouprc/cgrouprc_internal.h b/libprocessgroup/cgrouprc/cgrouprc_internal.h
new file mode 100644
index 0000000..cd02f03
--- /dev/null
+++ b/libprocessgroup/cgrouprc/cgrouprc_internal.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2019 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 <android/cgrouprc.h>
+
+#include <processgroup/format/cgroup_controller.h>
+#include <processgroup/format/cgroup_file.h>
+
+struct ACgroupController : android::cgrouprc::format::CgroupController {};
diff --git a/libprocessgroup/cgrouprc/include/android/cgrouprc.h b/libprocessgroup/cgrouprc/include/android/cgrouprc.h
new file mode 100644
index 0000000..4edd239
--- /dev/null
+++ b/libprocessgroup/cgrouprc/include/android/cgrouprc.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2019 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 <stdint.h>
+
+__BEGIN_DECLS
+
+// For host builds, __INTRODUCED_IN is not defined.
+#ifndef __INTRODUCED_IN
+#define __INTRODUCED_IN(x)
+#endif
+
+struct ACgroupController;
+typedef struct ACgroupController ACgroupController;
+
+#if __ANDROID_API__ >= __ANDROID_API_Q__
+
+// ACgroupFile
+
+/**
+ * Returns file version. See android::cgrouprc::format::CgroupFile for a list of valid versions
+ * for the file.
+ * If ACgroupFile_init() isn't called, initialization will be done first.
+ * If initialization failed, return 0.
+ */
+__attribute__((warn_unused_result)) uint32_t ACgroupFile_getVersion() __INTRODUCED_IN(29);
+
+/**
+ * Returns the number of controllers.
+ * If ACgroupFile_init() isn't called, initialization will be done first.
+ * If initialization failed, return 0.
+ */
+__attribute__((warn_unused_result)) uint32_t ACgroupFile_getControllerCount() __INTRODUCED_IN(29);
+
+/**
+ * Returns the controller at the given index.
+ * Returnss nullptr if the given index exceeds getControllerCount().
+ * If ACgroupFile_init() isn't called, initialization will be done first.
+ * If initialization failed, return 0.
+ */
+__attribute__((warn_unused_result)) const ACgroupController* ACgroupFile_getController(
+ uint32_t index) __INTRODUCED_IN(29);
+
+// ACgroupController
+
+/**
+ * Returns the version of the given controller.
+ * If the given controller is null, return 0.
+ */
+__attribute__((warn_unused_result)) uint32_t ACgroupController_getVersion(const ACgroupController*)
+ __INTRODUCED_IN(29);
+
+/**
+ * Returns the name of the given controller.
+ * If the given controller is null, return nullptr.
+ */
+__attribute__((warn_unused_result)) const char* ACgroupController_getName(const ACgroupController*)
+ __INTRODUCED_IN(29);
+
+/**
+ * Returns the path of the given controller.
+ * If the given controller is null, return nullptr.
+ */
+__attribute__((warn_unused_result)) const char* ACgroupController_getPath(const ACgroupController*)
+ __INTRODUCED_IN(29);
+
+__END_DECLS
+
+#endif
diff --git a/libprocessgroup/cgrouprc/libcgrouprc.map.txt b/libprocessgroup/cgrouprc/libcgrouprc.map.txt
new file mode 100644
index 0000000..91df392
--- /dev/null
+++ b/libprocessgroup/cgrouprc/libcgrouprc.map.txt
@@ -0,0 +1,11 @@
+LIBCGROUPRC { # introduced=29
+ global:
+ ACgroupFile_getVersion;
+ ACgroupFile_getControllerCount;
+ ACgroupFile_getController;
+ ACgroupController_getVersion;
+ ACgroupController_getName;
+ ACgroupController_getPath;
+ local:
+ *;
+};
diff --git a/libprocessgroup/cgrouprc_format/Android.bp b/libprocessgroup/cgrouprc_format/Android.bp
new file mode 100644
index 0000000..dfbeed7
--- /dev/null
+++ b/libprocessgroup/cgrouprc_format/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2019 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.
+
+cc_library_static {
+ name: "libcgrouprc_format",
+ host_supported: true,
+ recovery_available: true,
+ srcs: [
+ "cgroup_controller.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ export_include_dirs: [
+ "include",
+ ],
+ shared_libs: [
+ "libbase",
+ ],
+}
diff --git a/libprocessgroup/cgrouprc_format/cgroup_controller.cpp b/libprocessgroup/cgrouprc_format/cgroup_controller.cpp
new file mode 100644
index 0000000..877eed8
--- /dev/null
+++ b/libprocessgroup/cgrouprc_format/cgroup_controller.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 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 <processgroup/format/cgroup_controller.h>
+
+namespace android {
+namespace cgrouprc {
+namespace format {
+
+CgroupController::CgroupController(uint32_t version, const std::string& name,
+ const std::string& path) {
+ // strlcpy isn't available on host. Although there is an implementation
+ // in licutils, libcutils itself depends on libcgrouprc_format, causing
+ // a circular dependency.
+ version_ = version;
+ strncpy(name_, name.c_str(), sizeof(name_) - 1);
+ name_[sizeof(name_) - 1] = '\0';
+ strncpy(path_, path.c_str(), sizeof(path_) - 1);
+ path_[sizeof(path_) - 1] = '\0';
+}
+
+uint32_t CgroupController::version() const {
+ return version_;
+}
+
+const char* CgroupController::name() const {
+ return name_;
+}
+
+const char* CgroupController::path() const {
+ return path_;
+}
+
+} // namespace format
+} // namespace cgrouprc
+} // namespace android
diff --git a/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h b/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h
new file mode 100644
index 0000000..64c7532
--- /dev/null
+++ b/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2019 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 <stdint.h>
+#include <string>
+
+namespace android {
+namespace cgrouprc {
+namespace format {
+
+// Minimal controller description to be mmapped into process address space
+struct CgroupController {
+ public:
+ CgroupController() {}
+ CgroupController(uint32_t version, const std::string& name, const std::string& path);
+
+ uint32_t version() const;
+ const char* name() const;
+ const char* path() const;
+
+ private:
+ static constexpr size_t CGROUP_NAME_BUF_SZ = 16;
+ static constexpr size_t CGROUP_PATH_BUF_SZ = 32;
+
+ uint32_t version_;
+ char name_[CGROUP_NAME_BUF_SZ];
+ char path_[CGROUP_PATH_BUF_SZ];
+};
+
+} // namespace format
+} // namespace cgrouprc
+} // namespace android
diff --git a/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_file.h b/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_file.h
new file mode 100644
index 0000000..f1678a1
--- /dev/null
+++ b/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_file.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 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 <processgroup/format/cgroup_controller.h>
+
+namespace android {
+namespace cgrouprc {
+namespace format {
+
+struct CgroupFile {
+ uint32_t version_;
+ uint32_t controller_count_;
+ CgroupController controllers_[];
+
+ static constexpr uint32_t FILE_VERSION_1 = 1;
+ static constexpr uint32_t FILE_CURR_VERSION = FILE_VERSION_1;
+};
+
+} // namespace format
+} // namespace cgrouprc
+} // namespace android
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index 6f973b8..86e6035 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -24,9 +24,8 @@
__BEGIN_DECLS
static constexpr const char* CGROUPV2_CONTROLLER_NAME = "cgroup2";
-static constexpr const char* CGROUPS_RC_DIR = "/dev/cgroup_info";
+static constexpr const char* CGROUPS_RC_PATH = "/dev/cgroup_info/cgroup.rc";
-bool CgroupSetupCgroups();
bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path);
bool CgroupGetAttributePath(const std::string& attr_name, std::string* path);
bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path);
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 8884650..abe63dd 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -55,19 +55,15 @@
#define PROCESSGROUP_CGROUP_PROCS_FILE "/cgroup.procs"
-bool CgroupSetupCgroups() {
- return CgroupMap::SetupCgroups();
-}
-
bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path) {
- const CgroupController* controller = CgroupMap::GetInstance().FindController(cgroup_name);
+ auto controller = CgroupMap::GetInstance().FindController(cgroup_name);
- if (controller == nullptr) {
+ if (!controller.HasValue()) {
return false;
}
if (path) {
- *path = controller->path();
+ *path = controller.path();
}
return true;
@@ -111,7 +107,7 @@
static bool isMemoryCgroupSupported() {
std::string cgroup_name;
- static bool memcg_supported = (CgroupMap::GetInstance().FindController("memory") != nullptr);
+ static bool memcg_supported = CgroupMap::GetInstance().FindController("memory").HasValue();
return memcg_supported;
}
diff --git a/libprocessgroup/sched_policy.cpp b/libprocessgroup/sched_policy.cpp
index 1eefada..c7d0cca 100644
--- a/libprocessgroup/sched_policy.cpp
+++ b/libprocessgroup/sched_policy.cpp
@@ -152,21 +152,21 @@
}
bool cpusets_enabled() {
- static bool enabled = (CgroupMap::GetInstance().FindController("cpuset") != nullptr);
+ static bool enabled = (CgroupMap::GetInstance().FindController("cpuset").HasValue());
return enabled;
}
bool schedboost_enabled() {
- static bool enabled = (CgroupMap::GetInstance().FindController("schedtune") != nullptr);
+ static bool enabled = (CgroupMap::GetInstance().FindController("schedtune").HasValue());
return enabled;
}
static int getCGroupSubsys(int tid, const char* subsys, std::string& subgroup) {
- const CgroupController* controller = CgroupMap::GetInstance().FindController(subsys);
+ auto controller = CgroupMap::GetInstance().FindController(subsys);
- if (!controller) return -1;
+ if (!controller.HasValue()) return -1;
- if (!controller->GetTaskGroup(tid, &subgroup)) {
+ if (!controller.GetTaskGroup(tid, &subgroup)) {
LOG(ERROR) << "Failed to find cgroup for tid " << tid;
return -1;
}
diff --git a/libprocessgroup/setup/Android.bp b/libprocessgroup/setup/Android.bp
new file mode 100644
index 0000000..f6fc066
--- /dev/null
+++ b/libprocessgroup/setup/Android.bp
@@ -0,0 +1,44 @@
+//
+// Copyright (C) 2019 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.
+//
+
+cc_library_shared {
+ name: "libprocessgroup_setup",
+ recovery_available: true,
+ srcs: [
+ "cgroup_map_write.cpp",
+ ],
+ export_include_dirs: [
+ "include",
+ ],
+ shared_libs: [
+ "libbase",
+ "libcgrouprc",
+ "libjsoncpp",
+ ],
+ static_libs: [
+ "libcgrouprc_format",
+ ],
+ header_libs: [
+ "libprocessgroup_headers",
+ ],
+ export_header_lib_headers: [
+ "libprocessgroup_headers",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
diff --git a/libprocessgroup/setup/cgroup_descriptor.h b/libprocessgroup/setup/cgroup_descriptor.h
new file mode 100644
index 0000000..597060e
--- /dev/null
+++ b/libprocessgroup/setup/cgroup_descriptor.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 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 <processgroup/format/cgroup_controller.h>
+
+namespace android {
+namespace cgrouprc {
+
+// Complete controller description for mounting cgroups
+class CgroupDescriptor {
+ public:
+ CgroupDescriptor(uint32_t version, const std::string& name, const std::string& path,
+ mode_t mode, const std::string& uid, const std::string& gid);
+
+ const format::CgroupController* controller() const { return &controller_; }
+ mode_t mode() const { return mode_; }
+ std::string uid() const { return uid_; }
+ std::string gid() const { return gid_; }
+
+ private:
+ format::CgroupController controller_;
+ mode_t mode_ = 0;
+ std::string uid_;
+ std::string gid_;
+};
+
+} // namespace cgrouprc
+} // namespace android
diff --git a/libprocessgroup/setup/cgroup_map_write.cpp b/libprocessgroup/setup/cgroup_map_write.cpp
new file mode 100644
index 0000000..da60948
--- /dev/null
+++ b/libprocessgroup/setup/cgroup_map_write.cpp
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "libprocessgroup"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <pwd.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <regex>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
+#include <json/reader.h>
+#include <json/value.h>
+#include <processgroup/format/cgroup_file.h>
+#include <processgroup/processgroup.h>
+#include <processgroup/setup.h>
+
+#include "cgroup_descriptor.h"
+
+using android::base::GetBoolProperty;
+using android::base::StringPrintf;
+using android::base::unique_fd;
+
+namespace android {
+namespace cgrouprc {
+
+static constexpr const char* CGROUPS_DESC_FILE = "/etc/cgroups.json";
+static constexpr const char* CGROUPS_DESC_VENDOR_FILE = "/vendor/etc/cgroups.json";
+
+static bool Mkdir(const std::string& path, mode_t mode, const std::string& uid,
+ const std::string& gid) {
+ if (mode == 0) {
+ mode = 0755;
+ }
+
+ if (mkdir(path.c_str(), mode) != 0) {
+ /* chmod in case the directory already exists */
+ if (errno == EEXIST) {
+ if (fchmodat(AT_FDCWD, path.c_str(), mode, AT_SYMLINK_NOFOLLOW) != 0) {
+ // /acct is a special case when the directory already exists
+ // TODO: check if file mode is already what we want instead of using EROFS
+ if (errno != EROFS) {
+ PLOG(ERROR) << "fchmodat() failed for " << path;
+ return false;
+ }
+ }
+ } else {
+ PLOG(ERROR) << "mkdir() failed for " << path;
+ return false;
+ }
+ }
+
+ if (uid.empty()) {
+ return true;
+ }
+
+ passwd* uid_pwd = getpwnam(uid.c_str());
+ if (!uid_pwd) {
+ PLOG(ERROR) << "Unable to decode UID for '" << uid << "'";
+ return false;
+ }
+
+ uid_t pw_uid = uid_pwd->pw_uid;
+ gid_t gr_gid = -1;
+ if (!gid.empty()) {
+ group* gid_pwd = getgrnam(gid.c_str());
+ if (!gid_pwd) {
+ PLOG(ERROR) << "Unable to decode GID for '" << gid << "'";
+ return false;
+ }
+ gr_gid = gid_pwd->gr_gid;
+ }
+
+ if (lchown(path.c_str(), pw_uid, gr_gid) < 0) {
+ PLOG(ERROR) << "lchown() failed for " << path;
+ return false;
+ }
+
+ /* chown may have cleared S_ISUID and S_ISGID, chmod again */
+ if (mode & (S_ISUID | S_ISGID)) {
+ if (fchmodat(AT_FDCWD, path.c_str(), mode, AT_SYMLINK_NOFOLLOW) != 0) {
+ PLOG(ERROR) << "fchmodat() failed for " << path;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool ReadDescriptorsFromFile(const std::string& file_name,
+ std::map<std::string, CgroupDescriptor>* descriptors) {
+ std::vector<CgroupDescriptor> result;
+ std::string json_doc;
+
+ if (!android::base::ReadFileToString(file_name, &json_doc)) {
+ PLOG(ERROR) << "Failed to read task profiles from " << file_name;
+ return false;
+ }
+
+ Json::Reader reader;
+ Json::Value root;
+ if (!reader.parse(json_doc, root)) {
+ LOG(ERROR) << "Failed to parse cgroups description: " << reader.getFormattedErrorMessages();
+ return false;
+ }
+
+ if (root.isMember("Cgroups")) {
+ const Json::Value& cgroups = root["Cgroups"];
+ for (Json::Value::ArrayIndex i = 0; i < cgroups.size(); ++i) {
+ std::string name = cgroups[i]["Controller"].asString();
+ auto iter = descriptors->find(name);
+ if (iter == descriptors->end()) {
+ descriptors->emplace(
+ name, CgroupDescriptor(
+ 1, name, cgroups[i]["Path"].asString(),
+ std::strtoul(cgroups[i]["Mode"].asString().c_str(), 0, 8),
+ cgroups[i]["UID"].asString(), cgroups[i]["GID"].asString()));
+ } else {
+ iter->second = CgroupDescriptor(
+ 1, name, cgroups[i]["Path"].asString(),
+ std::strtoul(cgroups[i]["Mode"].asString().c_str(), 0, 8),
+ cgroups[i]["UID"].asString(), cgroups[i]["GID"].asString());
+ }
+ }
+ }
+
+ if (root.isMember("Cgroups2")) {
+ const Json::Value& cgroups2 = root["Cgroups2"];
+ auto iter = descriptors->find(CGROUPV2_CONTROLLER_NAME);
+ if (iter == descriptors->end()) {
+ descriptors->emplace(
+ CGROUPV2_CONTROLLER_NAME,
+ CgroupDescriptor(2, CGROUPV2_CONTROLLER_NAME, cgroups2["Path"].asString(),
+ std::strtoul(cgroups2["Mode"].asString().c_str(), 0, 8),
+ cgroups2["UID"].asString(), cgroups2["GID"].asString()));
+ } else {
+ iter->second =
+ CgroupDescriptor(2, CGROUPV2_CONTROLLER_NAME, cgroups2["Path"].asString(),
+ std::strtoul(cgroups2["Mode"].asString().c_str(), 0, 8),
+ cgroups2["UID"].asString(), cgroups2["GID"].asString());
+ }
+ }
+
+ return true;
+}
+
+static bool ReadDescriptors(std::map<std::string, CgroupDescriptor>* descriptors) {
+ // load system cgroup descriptors
+ if (!ReadDescriptorsFromFile(CGROUPS_DESC_FILE, descriptors)) {
+ return false;
+ }
+
+ // load vendor cgroup descriptors if the file exists
+ if (!access(CGROUPS_DESC_VENDOR_FILE, F_OK) &&
+ !ReadDescriptorsFromFile(CGROUPS_DESC_VENDOR_FILE, descriptors)) {
+ return false;
+ }
+
+ return true;
+}
+
+// To avoid issues in sdk_mac build
+#if defined(__ANDROID__)
+
+static bool SetupCgroup(const CgroupDescriptor& descriptor) {
+ const format::CgroupController* controller = descriptor.controller();
+
+ // mkdir <path> [mode] [owner] [group]
+ if (!Mkdir(controller->path(), descriptor.mode(), descriptor.uid(), descriptor.gid())) {
+ LOG(ERROR) << "Failed to create directory for " << controller->name() << " cgroup";
+ return false;
+ }
+
+ int result;
+ if (controller->version() == 2) {
+ result = mount("none", controller->path(), "cgroup2", MS_NODEV | MS_NOEXEC | MS_NOSUID,
+ nullptr);
+ } else {
+ // Unfortunately historically cpuset controller was mounted using a mount command
+ // different from all other controllers. This results in controller attributes not
+ // to be prepended with controller name. For example this way instead of
+ // /dev/cpuset/cpuset.cpus the attribute becomes /dev/cpuset/cpus which is what
+ // the system currently expects.
+ if (!strcmp(controller->name(), "cpuset")) {
+ // mount cpuset none /dev/cpuset nodev noexec nosuid
+ result = mount("none", controller->path(), controller->name(),
+ MS_NODEV | MS_NOEXEC | MS_NOSUID, nullptr);
+ } else {
+ // mount cgroup none <path> nodev noexec nosuid <controller>
+ result = mount("none", controller->path(), "cgroup", MS_NODEV | MS_NOEXEC | MS_NOSUID,
+ controller->name());
+ }
+ }
+
+ if (result < 0) {
+ PLOG(ERROR) << "Failed to mount " << controller->name() << " cgroup";
+ return false;
+ }
+
+ return true;
+}
+
+#else
+
+// Stubs for non-Android targets.
+static bool SetupCgroup(const CgroupDescriptor&) {
+ return false;
+}
+
+#endif
+
+static bool WriteRcFile(const std::map<std::string, CgroupDescriptor>& descriptors) {
+ unique_fd fd(TEMP_FAILURE_RETRY(open(CGROUPS_RC_PATH, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC,
+ S_IRUSR | S_IRGRP | S_IROTH)));
+ if (fd < 0) {
+ PLOG(ERROR) << "open() failed for " << CGROUPS_RC_PATH;
+ return false;
+ }
+
+ format::CgroupFile fl;
+ fl.version_ = format::CgroupFile::FILE_CURR_VERSION;
+ fl.controller_count_ = descriptors.size();
+ int ret = TEMP_FAILURE_RETRY(write(fd, &fl, sizeof(fl)));
+ if (ret < 0) {
+ PLOG(ERROR) << "write() failed for " << CGROUPS_RC_PATH;
+ return false;
+ }
+
+ for (const auto& [name, descriptor] : descriptors) {
+ ret = TEMP_FAILURE_RETRY(
+ write(fd, descriptor.controller(), sizeof(format::CgroupController)));
+ if (ret < 0) {
+ PLOG(ERROR) << "write() failed for " << CGROUPS_RC_PATH;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+CgroupDescriptor::CgroupDescriptor(uint32_t version, const std::string& name,
+ const std::string& path, mode_t mode, const std::string& uid,
+ const std::string& gid)
+ : controller_(version, name, path), mode_(mode), uid_(uid), gid_(gid) {}
+
+} // namespace cgrouprc
+} // namespace android
+
+bool CgroupSetup() {
+ using namespace android::cgrouprc;
+
+ std::map<std::string, CgroupDescriptor> descriptors;
+
+ if (getpid() != 1) {
+ LOG(ERROR) << "Cgroup setup can be done only by init process";
+ return false;
+ }
+
+ // Make sure we do this only one time. No need for std::call_once because
+ // init is a single-threaded process
+ if (access(CGROUPS_RC_PATH, F_OK) == 0) {
+ LOG(WARNING) << "Attempt to call SetupCgroups more than once";
+ return true;
+ }
+
+ // load cgroups.json file
+ if (!ReadDescriptors(&descriptors)) {
+ LOG(ERROR) << "Failed to load cgroup description file";
+ return false;
+ }
+
+ // setup cgroups
+ for (const auto& [name, descriptor] : descriptors) {
+ if (!SetupCgroup(descriptor)) {
+ // issue a warning and proceed with the next cgroup
+ // TODO: mark the descriptor as invalid and skip it in WriteRcFile()
+ LOG(WARNING) << "Failed to setup " << name << " cgroup";
+ }
+ }
+
+ // mkdir <CGROUPS_RC_DIR> 0711 system system
+ if (!Mkdir(android::base::Dirname(CGROUPS_RC_PATH), 0711, "system", "system")) {
+ LOG(ERROR) << "Failed to create directory for " << CGROUPS_RC_PATH << " file";
+ return false;
+ }
+
+ // Generate <CGROUPS_RC_FILE> file which can be directly mmapped into
+ // process memory. This optimizes performance, memory usage
+ // and limits infrormation shared with unprivileged processes
+ // to the minimum subset of information from cgroups.json
+ if (!WriteRcFile(descriptors)) {
+ LOG(ERROR) << "Failed to write " << CGROUPS_RC_PATH << " file";
+ return false;
+ }
+
+ // chmod 0644 <CGROUPS_RC_PATH>
+ if (fchmodat(AT_FDCWD, CGROUPS_RC_PATH, 0644, AT_SYMLINK_NOFOLLOW) < 0) {
+ PLOG(ERROR) << "fchmodat() failed";
+ return false;
+ }
+
+ return true;
+}
diff --git a/libprocessgroup/setup/include/processgroup/setup.h b/libprocessgroup/setup/include/processgroup/setup.h
new file mode 100644
index 0000000..6ea1979
--- /dev/null
+++ b/libprocessgroup/setup/include/processgroup/setup.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 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
+
+bool CgroupSetup();
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index 9362c03..4b45c87 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -46,7 +46,7 @@
bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const {
std::string subgroup;
- if (!controller_->GetTaskGroup(tid, &subgroup)) {
+ if (!controller()->GetTaskGroup(tid, &subgroup)) {
return false;
}
@@ -55,9 +55,10 @@
}
if (subgroup.empty()) {
- *path = StringPrintf("%s/%s", controller_->path(), file_name_.c_str());
+ *path = StringPrintf("%s/%s", controller()->path(), file_name_.c_str());
} else {
- *path = StringPrintf("%s/%s/%s", controller_->path(), subgroup.c_str(), file_name_.c_str());
+ *path = StringPrintf("%s/%s/%s", controller()->path(), subgroup.c_str(),
+ file_name_.c_str());
}
return true;
}
@@ -135,7 +136,7 @@
return path.find("<uid>", 0) != std::string::npos || path.find("<pid>", 0) != std::string::npos;
}
-SetCgroupAction::SetCgroupAction(const CgroupController* c, const std::string& p)
+SetCgroupAction::SetCgroupAction(const CgroupController& c, const std::string& p)
: controller_(c), path_(p) {
#ifdef CACHE_FILE_DESCRIPTORS
// cache file descriptor only if path is app independent
@@ -145,7 +146,7 @@
return;
}
- std::string tasks_path = c->GetTasksFilePath(p.c_str());
+ std::string tasks_path = c.GetTasksFilePath(p);
if (access(tasks_path.c_str(), W_OK) != 0) {
// file is not accessible
@@ -199,7 +200,7 @@
}
// this is app-dependent path, file descriptor is not cached
- std::string procs_path = controller_->GetProcsFilePath(path_, uid, pid);
+ std::string procs_path = controller()->GetProcsFilePath(path_, uid, pid);
unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(procs_path.c_str(), O_WRONLY | O_CLOEXEC)));
if (tmp_fd < 0) {
PLOG(WARNING) << "Failed to open " << procs_path;
@@ -212,7 +213,7 @@
return true;
#else
- std::string procs_path = controller_->GetProcsFilePath(path_, uid, pid);
+ std::string procs_path = controller()->GetProcsFilePath(path_, uid, pid);
unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(procs_path.c_str(), O_WRONLY | O_CLOEXEC)));
if (tmp_fd < 0) {
// no permissions to access the file, ignore
@@ -247,7 +248,7 @@
LOG(ERROR) << "Application profile can't be applied to a thread";
return false;
#else
- std::string tasks_path = controller_->GetTasksFilePath(path_);
+ std::string tasks_path = controller()->GetTasksFilePath(path_);
unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(tasks_path.c_str(), O_WRONLY | O_CLOEXEC)));
if (tmp_fd < 0) {
// no permissions to access the file, ignore
@@ -326,8 +327,8 @@
std::string file_attr = attr[i]["File"].asString();
if (attributes_.find(name) == attributes_.end()) {
- const CgroupController* controller = cg_map.FindController(controller_name);
- if (controller) {
+ auto controller = cg_map.FindController(controller_name);
+ if (controller.HasValue()) {
attributes_[name] = std::make_unique<ProfileAttribute>(controller, file_attr);
} else {
LOG(WARNING) << "Controller " << controller_name << " is not found";
@@ -355,8 +356,8 @@
std::string controller_name = params_val["Controller"].asString();
std::string path = params_val["Path"].asString();
- const CgroupController* controller = cg_map.FindController(controller_name);
- if (controller) {
+ auto controller = cg_map.FindController(controller_name);
+ if (controller.HasValue()) {
profile->Add(std::make_unique<SetCgroupAction>(controller, path));
} else {
LOG(WARNING) << "JoinCgroup: controller " << controller_name << " is not found";
diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h
index 9ee81c1..37cc305 100644
--- a/libprocessgroup/task_profiles.h
+++ b/libprocessgroup/task_profiles.h
@@ -27,16 +27,16 @@
class ProfileAttribute {
public:
- ProfileAttribute(const CgroupController* controller, const std::string& file_name)
+ ProfileAttribute(const CgroupController& controller, const std::string& file_name)
: controller_(controller), file_name_(file_name) {}
- const CgroupController* controller() const { return controller_; }
+ const CgroupController* controller() const { return &controller_; }
const std::string& file_name() const { return file_name_; }
bool GetPathForTask(int tid, std::string* path) const;
private:
- const CgroupController* controller_;
+ CgroupController controller_;
std::string file_name_;
};
@@ -106,16 +106,16 @@
// Set cgroup profile element
class SetCgroupAction : public ProfileAction {
public:
- SetCgroupAction(const CgroupController* c, const std::string& p);
+ SetCgroupAction(const CgroupController& c, const std::string& p);
virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
virtual bool ExecuteForTask(int tid) const;
- const CgroupController* controller() const { return controller_; }
+ const CgroupController* controller() const { return &controller_; }
std::string path() const { return path_; }
private:
- const CgroupController* controller_;
+ CgroupController controller_;
std::string path_;
#ifdef CACHE_FILE_DESCRIPTORS
android::base::unique_fd fd_;
diff --git a/libstats/include/stats_event_list.h b/libstats/include/stats_event_list.h
index b5bc5af..845a197 100644
--- a/libstats/include/stats_event_list.h
+++ b/libstats/include/stats_event_list.h
@@ -18,15 +18,18 @@
#define ANDROID_STATS_LOG_STATS_EVENT_LIST_H
#include <log/log_event_list.h>
+#include <sys/uio.h>
#ifdef __cplusplus
extern "C" {
#endif
void reset_log_context(android_log_context ctx);
int write_to_logger(android_log_context context, log_id_t id);
-void note_log_drop(int error);
+void note_log_drop(int error, int atom_tag);
void stats_log_close();
int android_log_write_char_array(android_log_context ctx, const char* value, size_t len);
+extern int (*write_to_statsd)(struct iovec* vec, size_t nr);
+
#ifdef __cplusplus
}
#endif
diff --git a/libstats/stats_event_list.c b/libstats/stats_event_list.c
index 5b90361..ae12cbe 100644
--- a/libstats/stats_event_list.c
+++ b/libstats/stats_event_list.c
@@ -41,7 +41,7 @@
extern struct android_log_transport_write statsdLoggerWrite;
static int __write_to_statsd_init(struct iovec* vec, size_t nr);
-static int (*write_to_statsd)(struct iovec* vec, size_t nr) = __write_to_statsd_init;
+int (*write_to_statsd)(struct iovec* vec, size_t nr) = __write_to_statsd_init;
// Similar to create_android_logger(), but instead of allocation a new buffer,
// this function resets the buffer for resuse.
@@ -120,8 +120,8 @@
return retValue;
}
-void note_log_drop(int error) {
- statsdLoggerWrite.noteDrop(error);
+void note_log_drop(int error, int tag) {
+ statsdLoggerWrite.noteDrop(error, tag);
}
void stats_log_close() {
diff --git a/libstats/statsd_writer.c b/libstats/statsd_writer.c
index f5be95c..b778f92 100644
--- a/libstats/statsd_writer.c
+++ b/libstats/statsd_writer.c
@@ -47,9 +47,18 @@
#endif
#endif
+#ifndef htole64
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define htole64(x) (x)
+#else
+#define htole64(x) __bswap_64(x)
+#endif
+#endif
+
static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
static atomic_int dropped = 0;
static atomic_int log_error = 0;
+static atomic_int atom_tag = 0;
void statsd_writer_init_lock() {
/*
@@ -152,9 +161,10 @@
return 1;
}
-static void statsdNoteDrop(int error) {
+static void statsdNoteDrop(int error, int tag) {
atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
atomic_exchange_explicit(&log_error, error, memory_order_relaxed);
+ atomic_exchange_explicit(&atom_tag, tag, memory_order_relaxed);
}
static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr) {
@@ -203,12 +213,17 @@
if (sock >= 0) {
int32_t snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
if (snapshot) {
- android_log_event_int_t buffer;
+ android_log_event_long_t buffer;
header.id = LOG_ID_STATS;
// store the last log error in the tag field. This tag field is not used by statsd.
buffer.header.tag = htole32(atomic_load(&log_error));
- buffer.payload.type = EVENT_TYPE_INT;
- buffer.payload.data = htole32(snapshot);
+ buffer.payload.type = EVENT_TYPE_LONG;
+ // format:
+ // |atom_tag|dropped_count|
+ int64_t composed_long = atomic_load(&atom_tag);
+ // Send 2 int32's via an int64.
+ composed_long = ((composed_long << 32) | ((int64_t)snapshot));
+ buffer.payload.data = htole64(composed_long);
newVec[headerLength].iov_base = &buffer;
newVec[headerLength].iov_len = sizeof(buffer);
diff --git a/libstats/statsd_writer.h b/libstats/statsd_writer.h
index 4fc3f8b..fe2d37c 100644
--- a/libstats/statsd_writer.h
+++ b/libstats/statsd_writer.h
@@ -39,7 +39,7 @@
/* write log to transport, returns number of bytes propagated, or -errno */
int (*write)(struct timespec* ts, struct iovec* vec, size_t nr);
/* note one log drop */
- void (*noteDrop)(int error);
+ void (*noteDrop)(int error, int tag);
};
#endif // ANDROID_STATS_LOG_STATS_WRITER_H
diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp
index b07853a..523584a 100644
--- a/libsysutils/src/FrameworkListener.cpp
+++ b/libsysutils/src/FrameworkListener.cpp
@@ -26,7 +26,7 @@
#include <sysutils/FrameworkListener.h>
#include <sysutils/SocketClient.h>
-static const int CMD_BUF_SIZE = 1024;
+static const int CMD_BUF_SIZE = 4096;
FrameworkListener::FrameworkListener(const char *socketName, bool withSeq) :
SocketListener(socketName, true, withSeq) {
diff --git a/libunwindstack/DwarfEhFrameWithHdr.cpp b/libunwindstack/DwarfEhFrameWithHdr.cpp
index 668527a..802beca 100644
--- a/libunwindstack/DwarfEhFrameWithHdr.cpp
+++ b/libunwindstack/DwarfEhFrameWithHdr.cpp
@@ -61,6 +61,14 @@
table_encoding_ = data[3];
table_entry_size_ = memory_.template GetEncodedSize<AddressType>(table_encoding_);
+ // If we can't perform a binary search on the entries, it's not worth
+ // using this object. The calling code will fall back to the DwarfEhFrame
+ // object in this case.
+ if (table_entry_size_ == 0) {
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
+ return false;
+ }
+
memory_.set_pc_offset(memory_.cur_offset());
if (!memory_.template ReadEncodedValue<AddressType>(ptr_encoding_, &ptr_offset_)) {
last_error_.code = DWARF_ERROR_MEMORY_INVALID;
@@ -137,13 +145,13 @@
}
template <typename AddressType>
-bool DwarfEhFrameWithHdr<AddressType>::GetFdeOffsetBinary(uint64_t pc, uint64_t* fde_offset,
- uint64_t total_entries) {
- CHECK(fde_count_ > 0);
- CHECK(total_entries <= fde_count_);
+bool DwarfEhFrameWithHdr<AddressType>::GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) {
+ if (fde_count_ == 0) {
+ return false;
+ }
size_t first = 0;
- size_t last = total_entries;
+ size_t last = fde_count_;
while (first < last) {
size_t current = (first + last) / 2;
const FdeInfo* info = GetFdeInfoFromIndex(current);
@@ -172,87 +180,6 @@
}
template <typename AddressType>
-bool DwarfEhFrameWithHdr<AddressType>::GetFdeOffsetSequential(uint64_t pc, uint64_t* fde_offset) {
- CHECK(fde_count_ != 0);
- last_error_.code = DWARF_ERROR_NONE;
- last_error_.address = 0;
-
- // We can do a binary search if the pc is in the range of the elements
- // that have already been cached.
- if (!fde_info_.empty()) {
- const FdeInfo* info = &fde_info_[fde_info_.size() - 1];
- if (pc >= info->pc) {
- *fde_offset = info->offset;
- return true;
- }
- if (pc < info->pc) {
- return GetFdeOffsetBinary(pc, fde_offset, fde_info_.size());
- }
- }
-
- if (cur_entries_offset_ == 0) {
- // All entries read, or error encountered.
- return false;
- }
-
- memory_.set_data_offset(entries_data_offset_);
- memory_.set_cur_offset(cur_entries_offset_);
- memory_.set_pc_offset(0);
- cur_entries_offset_ = 0;
-
- FdeInfo* prev_info = nullptr;
- for (size_t current = fde_info_.size();
- current < fde_count_ && memory_.cur_offset() < entries_end_; current++) {
- FdeInfo* info = &fde_info_[current];
- uint64_t value;
- if (!memory_.template ReadEncodedValue<AddressType>(table_encoding_, &value) ||
- !memory_.template ReadEncodedValue<AddressType>(table_encoding_, &info->offset)) {
- fde_info_.erase(current);
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- // Relative encodings require adding in the load bias.
- if (IsEncodingRelative(table_encoding_)) {
- value += load_bias_;
- }
- info->pc = value;
-
- if (pc < info->pc) {
- if (prev_info == nullptr) {
- return false;
- }
- cur_entries_offset_ = memory_.cur_offset();
- *fde_offset = prev_info->offset;
- return true;
- }
- prev_info = info;
- }
-
- if (fde_count_ == fde_info_.size() && pc >= prev_info->pc) {
- *fde_offset = prev_info->offset;
- return true;
- }
- return false;
-}
-
-template <typename AddressType>
-bool DwarfEhFrameWithHdr<AddressType>::GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) {
- if (fde_count_ == 0) {
- return false;
- }
-
- if (table_entry_size_ > 0) {
- // Do a binary search since the size of each table entry is fixed.
- return GetFdeOffsetBinary(pc, fde_offset, fde_count_);
- } else {
- // Do a sequential search since each table entry size is variable.
- return GetFdeOffsetSequential(pc, fde_offset);
- }
-}
-
-template <typename AddressType>
void DwarfEhFrameWithHdr<AddressType>::GetFdes(std::vector<const DwarfFde*>* fdes) {
for (size_t i = 0; i < fde_count_; i++) {
const FdeInfo* info = GetFdeInfoFromIndex(i);
diff --git a/libunwindstack/DwarfEhFrameWithHdr.h b/libunwindstack/DwarfEhFrameWithHdr.h
index e3e9ca8..0e5eef7 100644
--- a/libunwindstack/DwarfEhFrameWithHdr.h
+++ b/libunwindstack/DwarfEhFrameWithHdr.h
@@ -69,10 +69,6 @@
const FdeInfo* GetFdeInfoFromIndex(size_t index);
- bool GetFdeOffsetSequential(uint64_t pc, uint64_t* fde_offset);
-
- bool GetFdeOffsetBinary(uint64_t pc, uint64_t* fde_offset, uint64_t total_entries);
-
void GetFdes(std::vector<const DwarfFde*>* fdes) override;
protected:
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp
index 57a780e..849a31a 100644
--- a/libunwindstack/DwarfSection.cpp
+++ b/libunwindstack/DwarfSection.cpp
@@ -138,7 +138,7 @@
return false;
}
- if (cie->version != 1 && cie->version != 3 && cie->version != 4) {
+ if (cie->version != 1 && cie->version != 3 && cie->version != 4 && cie->version != 5) {
// Unrecognized version.
last_error_.code = DWARF_ERROR_UNSUPPORTED_VERSION;
return false;
@@ -155,7 +155,7 @@
cie->augmentation_string.push_back(aug_value);
} while (aug_value != '\0');
- if (cie->version == 4) {
+ if (cie->version == 4 || cie->version == 5) {
// Skip the Address Size field since we only use it for validation.
memory_.set_cur_offset(memory_.cur_offset() + 1);
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 12efb94..dee8eb3 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -276,7 +276,7 @@
if (gnu_build_id_size_ - offset < hdr.n_descsz || hdr.n_descsz == 0) {
return "";
}
- std::string build_id(hdr.n_descsz - 1, '\0');
+ std::string build_id(hdr.n_descsz, '\0');
if (memory_->ReadFully(gnu_build_id_offset_ + offset, &build_id[0], hdr.n_descsz)) {
return build_id;
}
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index a1c58dd..3f2e1c1 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -284,17 +284,9 @@
}
}
-std::string Unwinder::FormatFrame(size_t frame_num) {
- if (frame_num >= frames_.size()) {
- return "";
- }
- return FormatFrame(frames_[frame_num], regs_->Is32Bit());
-}
-
-std::string Unwinder::FormatFrame(const FrameData& frame, bool is32bit) {
+std::string Unwinder::FormatFrame(const FrameData& frame) {
std::string data;
-
- if (is32bit) {
+ if (regs_->Is32Bit()) {
data += android::base::StringPrintf(" #%02zu pc %08" PRIx64, frame.num, frame.rel_pc);
} else {
data += android::base::StringPrintf(" #%02zu pc %016" PRIx64, frame.num, frame.rel_pc);
@@ -320,9 +312,24 @@
}
data += ')';
}
+
+ MapInfo* map_info = maps_->Find(frame.map_start);
+ if (map_info != nullptr && display_build_id_) {
+ std::string build_id = map_info->GetPrintableBuildID();
+ if (!build_id.empty()) {
+ data += " (BuildId: " + build_id + ')';
+ }
+ }
return data;
}
+std::string Unwinder::FormatFrame(size_t frame_num) {
+ if (frame_num >= frames_.size()) {
+ return "";
+ }
+ return FormatFrame(frames_[frame_num]);
+}
+
void Unwinder::SetJitDebug(JitDebug* jit_debug, ArchEnum arch) {
jit_debug->SetArch(arch);
jit_debug_ = jit_debug;
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index a0554e2..8b01654 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -88,7 +88,7 @@
}
std::string FormatFrame(size_t frame_num);
- static std::string FormatFrame(const FrameData& frame, bool is32bit);
+ std::string FormatFrame(const FrameData& frame);
void SetJitDebug(JitDebug* jit_debug, ArchEnum arch);
@@ -105,6 +105,8 @@
// NOTE: This does nothing unless resolving names is enabled.
void SetEmbeddedSoname(bool embedded_soname) { embedded_soname_ = embedded_soname; }
+ void SetDisplayBuildID(bool display_build_id) { display_build_id_ = display_build_id; }
+
#if !defined(NO_LIBDEXFILE_SUPPORT)
void SetDexFiles(DexFiles* dex_files, ArchEnum arch);
#endif
@@ -130,6 +132,7 @@
#endif
bool resolve_names_ = true;
bool embedded_soname_ = true;
+ bool display_build_id_ = false;
ErrorData last_error_;
};
diff --git a/libunwindstack/tests/DwarfDebugFrameTest.cpp b/libunwindstack/tests/DwarfDebugFrameTest.cpp
index d620934..120bd73 100644
--- a/libunwindstack/tests/DwarfDebugFrameTest.cpp
+++ b/libunwindstack/tests/DwarfDebugFrameTest.cpp
@@ -550,6 +550,22 @@
VerifyCieVersion(cie, 4, 10, DW_EH_PE_sdata8, 0x181, 0x1c, 0x10c);
}
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_version5) {
+ SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{5, '\0', 0, 10, 4, 8, 0x81, 3});
+ const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieVersion(cie, 5, 10, DW_EH_PE_sdata4, 0x181, 0x10, 0x104);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_version5) {
+ SetCie64(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{5, '\0', 0, 10, 4, 8, 0x81, 3});
+ const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieVersion(cie, 5, 10, DW_EH_PE_sdata8, 0x181, 0x1c, 0x10c);
+}
+
TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset_version_invalid) {
SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{0, '\0', 1, 2, 3, 4, 5, 6, 7});
ASSERT_TRUE(this->debug_frame_->GetCieFromOffset(0x5000) == nullptr);
@@ -558,10 +574,10 @@
ASSERT_TRUE(this->debug_frame_->GetCieFromOffset(0x6000) == nullptr);
EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->debug_frame_->LastErrorCode());
- SetCie32(&this->memory_, 0x7000, 0x100, std::vector<uint8_t>{5, '\0', 1, 2, 3, 4, 5, 6, 7});
+ SetCie32(&this->memory_, 0x7000, 0x100, std::vector<uint8_t>{6, '\0', 1, 2, 3, 4, 5, 6, 7});
ASSERT_TRUE(this->debug_frame_->GetCieFromOffset(0x7000) == nullptr);
EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->debug_frame_->LastErrorCode());
- SetCie64(&this->memory_, 0x8000, 0x100, std::vector<uint8_t>{5, '\0', 1, 2, 3, 4, 5, 6, 7});
+ SetCie64(&this->memory_, 0x8000, 0x100, std::vector<uint8_t>{6, '\0', 1, 2, 3, 4, 5, 6, 7});
ASSERT_TRUE(this->debug_frame_->GetCieFromOffset(0x8000) == nullptr);
EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->debug_frame_->LastErrorCode());
}
@@ -803,9 +819,10 @@
GetFdeFromPc64_not_in_section, GetCieFde32, GetCieFde64, GetCieFromOffset32_cie_cached,
GetCieFromOffset64_cie_cached, GetCieFromOffset32_version1, GetCieFromOffset64_version1,
GetCieFromOffset32_version3, GetCieFromOffset64_version3, GetCieFromOffset32_version4,
- GetCieFromOffset64_version4, GetCieFromOffset_version_invalid, GetCieFromOffset32_augment,
- GetCieFromOffset64_augment, GetFdeFromOffset32_augment, GetFdeFromOffset64_augment,
- GetFdeFromOffset32_lsda_address, GetFdeFromOffset64_lsda_address, GetFdeFromPc_interleaved);
+ GetCieFromOffset64_version4, GetCieFromOffset32_version5, GetCieFromOffset64_version5,
+ GetCieFromOffset_version_invalid, GetCieFromOffset32_augment, GetCieFromOffset64_augment,
+ GetFdeFromOffset32_augment, GetFdeFromOffset64_augment, GetFdeFromOffset32_lsda_address,
+ GetFdeFromOffset64_lsda_address, GetFdeFromPc_interleaved);
typedef ::testing::Types<uint32_t, uint64_t> DwarfDebugFrameTestTypes;
INSTANTIATE_TYPED_TEST_CASE_P(, DwarfDebugFrameTest, DwarfDebugFrameTestTypes);
diff --git a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
index 910ae36..be9e721 100644
--- a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
@@ -95,6 +95,13 @@
EXPECT_EQ(0x1000U, this->eh_frame_->TestGetEntriesDataOffset());
EXPECT_EQ(0x100aU, this->eh_frame_->TestGetCurEntriesOffset());
+ // Verify a zero table entry size fails to init.
+ this->memory_.SetData8(0x1003, 0x1);
+ ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100, 0));
+ ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->LastErrorCode());
+ // Reset the value back to the original.
+ this->memory_.SetData8(0x1003, DW_EH_PE_sdata4);
+
// Verify a zero fde count fails to init.
this->memory_.SetData32(0x1006, 0);
ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100, 0));
@@ -276,9 +283,8 @@
EXPECT_EQ(0x500U, info->offset);
}
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetBinary_verify) {
+TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_verify) {
this->eh_frame_->TestSetTableEntrySize(0x10);
- this->eh_frame_->TestSetFdeCount(10);
typename DwarfEhFrameWithHdr<TypeParam>::FdeInfo info;
for (size_t i = 0; i < 10; i++) {
@@ -288,105 +294,42 @@
}
uint64_t fde_offset;
- EXPECT_FALSE(this->eh_frame_->GetFdeOffsetBinary(0x100, &fde_offset, 10));
+ this->eh_frame_->TestSetFdeCount(10);
+ EXPECT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x100, &fde_offset));
// Not an error, just not found.
ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
// Even number of elements.
for (size_t i = 0; i < 10; i++) {
+ SCOPED_TRACE(testing::Message() << "Failed at index " << i);
TypeParam pc = 0x1000 * (i + 1);
- EXPECT_TRUE(this->eh_frame_->GetFdeOffsetBinary(pc, &fde_offset, 10)) << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- EXPECT_TRUE(this->eh_frame_->GetFdeOffsetBinary(pc + 1, &fde_offset, 10))
- << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- EXPECT_TRUE(this->eh_frame_->GetFdeOffsetBinary(pc + 0xfff, &fde_offset, 10))
- << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
+ EXPECT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc, &fde_offset));
+ EXPECT_EQ(0x5000 + i * 0x20, fde_offset);
+ EXPECT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 1, &fde_offset));
+ EXPECT_EQ(0x5000 + i * 0x20, fde_offset);
+ EXPECT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset));
+ EXPECT_EQ(0x5000 + i * 0x20, fde_offset);
}
+
// Odd number of elements.
+ this->eh_frame_->TestSetFdeCount(9);
for (size_t i = 0; i < 9; i++) {
+ SCOPED_TRACE(testing::Message() << "Failed at index " << i);
TypeParam pc = 0x1000 * (i + 1);
- EXPECT_TRUE(this->eh_frame_->GetFdeOffsetBinary(pc, &fde_offset, 9)) << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- EXPECT_TRUE(this->eh_frame_->GetFdeOffsetBinary(pc + 1, &fde_offset, 9))
- << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- EXPECT_TRUE(this->eh_frame_->GetFdeOffsetBinary(pc + 0xfff, &fde_offset, 9))
- << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
+ EXPECT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc, &fde_offset));
+ EXPECT_EQ(0x5000 + i * 0x20, fde_offset);
+ EXPECT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 1, &fde_offset));
+ EXPECT_EQ(0x5000 + i * 0x20, fde_offset);
+ EXPECT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset));
+ EXPECT_EQ(0x5000 + i * 0x20, fde_offset);
}
}
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetBinary_index_fail) {
+TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_index_fail) {
this->eh_frame_->TestSetTableEntrySize(0x10);
this->eh_frame_->TestSetFdeCount(10);
uint64_t fde_offset;
- EXPECT_FALSE(this->eh_frame_->GetFdeOffsetBinary(0x1000, &fde_offset, 10));
-}
-
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetSequential) {
- this->eh_frame_->TestSetFdeCount(10);
- this->eh_frame_->TestSetEntriesDataOffset(0x100);
- this->eh_frame_->TestSetEntriesEnd(0x2000);
- this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
-
- this->memory_.SetData32(0x1040, 0x340);
- this->memory_.SetData32(0x1044, 0x500);
-
- this->memory_.SetData32(0x1048, 0x440);
- this->memory_.SetData32(0x104c, 0x600);
-
- // Verify that if entries is zero, that it fails.
- uint64_t fde_offset;
- ASSERT_FALSE(this->eh_frame_->GetFdeOffsetSequential(0x344, &fde_offset));
- this->eh_frame_->TestSetCurEntriesOffset(0x1040);
-
- ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x344, &fde_offset));
- EXPECT_EQ(0x500U, fde_offset);
-
- ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x444, &fde_offset));
- EXPECT_EQ(0x600U, fde_offset);
-
- // Expect that the data is cached so no more memory reads will occur.
- this->memory_.Clear();
- ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x444, &fde_offset));
- EXPECT_EQ(0x600U, fde_offset);
-}
-
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetSequential_last_element) {
- this->eh_frame_->TestSetFdeCount(2);
- this->eh_frame_->TestSetEntriesDataOffset(0x100);
- this->eh_frame_->TestSetEntriesEnd(0x2000);
- this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
- this->eh_frame_->TestSetCurEntriesOffset(0x1040);
-
- this->memory_.SetData32(0x1040, 0x340);
- this->memory_.SetData32(0x1044, 0x500);
-
- this->memory_.SetData32(0x1048, 0x440);
- this->memory_.SetData32(0x104c, 0x600);
-
- uint64_t fde_offset;
- ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x540, &fde_offset));
- EXPECT_EQ(0x600U, fde_offset);
-}
-
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetSequential_end_check) {
- this->eh_frame_->TestSetFdeCount(2);
- this->eh_frame_->TestSetEntriesDataOffset(0x100);
- this->eh_frame_->TestSetEntriesEnd(0x1048);
- this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
-
- this->memory_.SetData32(0x1040, 0x340);
- this->memory_.SetData32(0x1044, 0x500);
-
- this->memory_.SetData32(0x1048, 0x440);
- this->memory_.SetData32(0x104c, 0x600);
-
- uint64_t fde_offset;
- ASSERT_FALSE(this->eh_frame_->GetFdeOffsetSequential(0x540, &fde_offset));
- ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
+ EXPECT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x1000, &fde_offset));
}
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_fail_fde_count) {
@@ -397,7 +340,7 @@
ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
}
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_binary_search) {
+TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_search) {
this->eh_frame_->TestSetTableEntrySize(16);
this->eh_frame_->TestSetFdeCount(10);
@@ -417,26 +360,6 @@
EXPECT_EQ(0x10700U, fde_offset);
}
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_sequential_search) {
- this->eh_frame_->TestSetFdeCount(10);
- this->eh_frame_->TestSetTableEntrySize(0);
-
- typename DwarfEhFrameWithHdr<TypeParam>::FdeInfo info;
- info.pc = 0x50;
- info.offset = 0x10000;
- this->eh_frame_->TestSetFdeInfo(0, info);
- info.pc = 0x150;
- info.offset = 0x10100;
- this->eh_frame_->TestSetFdeInfo(1, info);
- info.pc = 0x250;
- info.offset = 0x10200;
- this->eh_frame_->TestSetFdeInfo(2, info);
-
- uint64_t fde_offset;
- ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(0x200, &fde_offset));
- EXPECT_EQ(0x10100U, fde_offset);
-}
-
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetCieFde32) {
// CIE 32 information.
this->memory_.SetData32(0xf000, 0x100);
@@ -526,10 +449,8 @@
REGISTER_TYPED_TEST_CASE_P(DwarfEhFrameWithHdrTest, Init, Init_non_zero_load_bias, GetFdes,
GetFdeInfoFromIndex_expect_cache_fail, GetFdeInfoFromIndex_read_pcrel,
GetFdeInfoFromIndex_read_datarel, GetFdeInfoFromIndex_cached,
- GetFdeOffsetBinary_verify, GetFdeOffsetBinary_index_fail,
- GetFdeOffsetSequential, GetFdeOffsetSequential_last_element,
- GetFdeOffsetSequential_end_check, GetFdeOffsetFromPc_fail_fde_count,
- GetFdeOffsetFromPc_binary_search, GetFdeOffsetFromPc_sequential_search,
+ GetFdeOffsetFromPc_verify, GetFdeOffsetFromPc_index_fail,
+ GetFdeOffsetFromPc_fail_fde_count, GetFdeOffsetFromPc_search,
GetCieFde32, GetCieFde64, GetFdeFromPc_fde_not_found);
typedef ::testing::Types<uint32_t, uint64_t> DwarfEhFrameWithHdrTestTypes;
diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp
index d895863..cdc927a 100644
--- a/libunwindstack/tests/ElfInterfaceTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceTest.cpp
@@ -1192,14 +1192,16 @@
char note_section[128];
Nhdr note_header = {};
note_header.n_namesz = 4; // "GNU"
- note_header.n_descsz = 8; // "BUILDID"
+ note_header.n_descsz = 7; // "BUILDID"
note_header.n_type = NT_GNU_BUILD_ID;
memcpy(¬e_section, ¬e_header, sizeof(note_header));
size_t note_offset = sizeof(note_header);
+ // The note information contains the GNU and trailing '\0'.
memcpy(¬e_section[note_offset], "GNU", sizeof("GNU"));
note_offset += sizeof("GNU");
- memcpy(¬e_section[note_offset], "BUILDID", sizeof("BUILDID"));
- note_offset += sizeof("BUILDID");
+ // This part of the note does not contain any trailing '\0'.
+ memcpy(¬e_section[note_offset], "BUILDID", 7);
+ note_offset += 8;
Shdr shdr = {};
shdr.sh_type = SHT_NOTE;
@@ -1244,24 +1246,27 @@
char note_section[128];
Nhdr note_header = {};
note_header.n_namesz = 8; // "WRONG" aligned to 4
- note_header.n_descsz = 8; // "BUILDID"
+ note_header.n_descsz = 7; // "BUILDID"
note_header.n_type = NT_GNU_BUILD_ID;
memcpy(¬e_section, ¬e_header, sizeof(note_header));
size_t note_offset = sizeof(note_header);
memcpy(¬e_section[note_offset], "WRONG", sizeof("WRONG"));
note_offset += 8;
- memcpy(¬e_section[note_offset], "BUILDID", sizeof("BUILDID"));
- note_offset += sizeof("BUILDID");
+ // This part of the note does not contain any trailing '\0'.
+ memcpy(¬e_section[note_offset], "BUILDID", 7);
+ note_offset += 8;
note_header.n_namesz = 4; // "GNU"
- note_header.n_descsz = 8; // "BUILDID"
+ note_header.n_descsz = 7; // "BUILDID"
note_header.n_type = NT_GNU_BUILD_ID;
memcpy(¬e_section[note_offset], ¬e_header, sizeof(note_header));
note_offset += sizeof(note_header);
+ // The note information contains the GNU and trailing '\0'.
memcpy(¬e_section[note_offset], "GNU", sizeof("GNU"));
note_offset += sizeof("GNU");
- memcpy(¬e_section[note_offset], "BUILDID", sizeof("BUILDID"));
- note_offset += sizeof("BUILDID");
+ // This part of the note does not contain any trailing '\0'.
+ memcpy(¬e_section[note_offset], "BUILDID", 7);
+ note_offset += 8;
Shdr shdr = {};
shdr.sh_type = SHT_NOTE;
@@ -1306,14 +1311,16 @@
char note_section[128];
Nhdr note_header = {};
note_header.n_namesz = 4; // "GNU"
- note_header.n_descsz = 8; // "BUILDID"
+ note_header.n_descsz = 7; // "BUILDID"
note_header.n_type = NT_GNU_BUILD_ID;
memcpy(¬e_section, ¬e_header, sizeof(note_header));
size_t note_offset = sizeof(note_header);
+ // The note information contains the GNU and trailing '\0'.
memcpy(¬e_section[note_offset], "GNU", sizeof("GNU"));
note_offset += sizeof("GNU");
- memcpy(¬e_section[note_offset], "BUILDID", sizeof("BUILDID"));
- note_offset += sizeof("BUILDID");
+ // This part of the note does not contain any trailing '\0'.
+ memcpy(¬e_section[note_offset], "BUILDID", 7);
+ note_offset += 8;
Shdr shdr = {};
shdr.sh_type = SHT_NOTE;
@@ -1358,14 +1365,16 @@
char note_section[128];
Nhdr note_header = {};
note_header.n_namesz = 4; // "GNU"
- note_header.n_descsz = 8; // "BUILDID"
+ note_header.n_descsz = 7; // "BUILDID"
note_header.n_type = NT_GNU_BUILD_ID;
memcpy(¬e_section, ¬e_header, sizeof(note_header));
size_t note_offset = sizeof(note_header);
+ // The note information contains the GNU and trailing '\0'.
memcpy(¬e_section[note_offset], "GNU", sizeof("GNU"));
note_offset += sizeof("GNU");
- memcpy(¬e_section[note_offset], "BUILDID", sizeof("BUILDID"));
- note_offset += sizeof("BUILDID");
+ // This part of the note does not contain any trailing '\0'.
+ memcpy(¬e_section[note_offset], "BUILDID", 7);
+ note_offset += 8;
Shdr shdr = {};
shdr.sh_type = SHT_NOTE;
@@ -1410,14 +1419,16 @@
char note_section[128];
Nhdr note_header = {};
note_header.n_namesz = 4; // "GNU"
- note_header.n_descsz = 8; // "BUILDID"
+ note_header.n_descsz = 7; // "BUILDID"
note_header.n_type = NT_GNU_BUILD_ID;
memcpy(¬e_section, ¬e_header, sizeof(note_header));
size_t note_offset = sizeof(note_header);
+ // The note information contains the GNU and trailing '\0'.
memcpy(¬e_section[note_offset], "GNU", sizeof("GNU"));
note_offset += sizeof("GNU");
- memcpy(¬e_section[note_offset], "BUILDID", sizeof("BUILDID"));
- note_offset += sizeof("BUILDID");
+ // This part of the note does not contain any trailing '\0'.
+ memcpy(¬e_section[note_offset], "BUILDID", 7);
+ note_offset += 8;
Shdr shdr = {};
shdr.sh_type = SHT_NOTE;
diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h
index d6ca9b7..207d46e 100644
--- a/libunwindstack/tests/RegsFake.h
+++ b/libunwindstack/tests/RegsFake.h
@@ -23,6 +23,8 @@
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
+#include "Check.h"
+
namespace unwindstack {
class RegsFake : public Regs {
@@ -47,7 +49,10 @@
void IterateRegisters(std::function<void(const char*, uint64_t)>) override {}
- bool Is32Bit() { return false; }
+ bool Is32Bit() {
+ CHECK(fake_arch_ != ARCH_UNKNOWN);
+ return fake_arch_ == ARCH_ARM || fake_arch_ == ARCH_X86 || fake_arch_ == ARCH_MIPS;
+ }
uint64_t GetPcAdjustment(uint64_t, Elf*) override { return 2; }
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index 655579e..02ba9c8 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -204,6 +204,7 @@
TEST_F(UnwindOfflineTest, pc_straddle_arm) {
ASSERT_NO_FATAL_FAILURE(Init("straddle_arm/", ARCH_ARM));
+ std::unique_ptr<Regs> regs_copy(regs_->Clone());
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
@@ -223,6 +224,22 @@
EXPECT_EQ(0xe9c86730U, unwinder.frames()[2].sp);
EXPECT_EQ(0xf3367147U, unwinder.frames()[3].pc);
EXPECT_EQ(0xe9c86778U, unwinder.frames()[3].sp);
+
+ // Display build ids now.
+ unwinder.SetRegs(regs_copy.get());
+ unwinder.SetDisplayBuildID(true);
+ unwinder.Unwind();
+
+ frame_info = DumpFrames(unwinder);
+ ASSERT_EQ(4U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 0001a9f8 libc.so (abort+64) (BuildId: 2dd0d4ba881322a0edabeed94808048c)\n"
+ " #01 pc 00006a1b libbase.so (android::base::DefaultAborter(char const*)+6) (BuildId: "
+ "ed43842c239cac1a618e600ea91c4cbd)\n"
+ " #02 pc 00007441 libbase.so (android::base::LogMessage::~LogMessage()+748) (BuildId: "
+ "ed43842c239cac1a618e600ea91c4cbd)\n"
+ " #03 pc 00015147 /does/not/exist/libhidlbase.so\n",
+ frame_info);
}
TEST_F(UnwindOfflineTest, pc_in_gnu_debugdata_arm) {
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 504b57a..48e038e 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -58,7 +58,9 @@
maps_.reset(new Maps);
ElfFake* elf = new ElfFake(new MemoryFake);
- elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+ ElfInterfaceFake* interface_fake = new ElfInterfaceFake(nullptr);
+ interface_fake->FakeSetBuildID("FAKE");
+ elf->FakeSetInterface(interface_fake);
AddMapInfo(0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so", elf);
AddMapInfo(0x10000, 0x12000, 0, PROT_READ | PROT_WRITE, "[stack]");
@@ -1102,7 +1104,15 @@
}
// Verify format frame code.
-TEST_F(UnwinderTest, format_frame_static) {
+TEST_F(UnwinderTest, format_frame) {
+ RegsFake regs_arm(10);
+ regs_arm.FakeSetArch(ARCH_ARM);
+ Unwinder unwinder32(10, maps_.get(), ®s_arm, process_memory_);
+
+ RegsFake regs_arm64(10);
+ regs_arm64.FakeSetArch(ARCH_ARM64);
+ Unwinder unwinder64(10, maps_.get(), ®s_arm64, process_memory_);
+
FrameData frame;
frame.num = 1;
frame.rel_pc = 0x1000;
@@ -1117,39 +1127,61 @@
frame.map_flags = PROT_READ;
EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (offset 0x2000) (function+100)",
- Unwinder::FormatFrame(frame, false));
+ unwinder64.FormatFrame(frame));
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (offset 0x2000) (function+100)",
- Unwinder::FormatFrame(frame, true));
+ unwinder32.FormatFrame(frame));
frame.map_elf_start_offset = 0;
EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (function+100)",
- Unwinder::FormatFrame(frame, false));
- EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function+100)",
- Unwinder::FormatFrame(frame, true));
+ unwinder64.FormatFrame(frame));
+ EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function+100)", unwinder32.FormatFrame(frame));
frame.function_offset = 0;
EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (function)",
- Unwinder::FormatFrame(frame, false));
- EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function)", Unwinder::FormatFrame(frame, true));
+ unwinder64.FormatFrame(frame));
+ EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function)", unwinder32.FormatFrame(frame));
// Verify the function name is demangled.
frame.function_name = "_ZN4funcEv";
- EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (func())",
- Unwinder::FormatFrame(frame, false));
- EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (func())", Unwinder::FormatFrame(frame, true));
+ EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (func())", unwinder64.FormatFrame(frame));
+ EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (func())", unwinder32.FormatFrame(frame));
frame.function_name = "";
- EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so", Unwinder::FormatFrame(frame, false));
- EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so", Unwinder::FormatFrame(frame, true));
+ EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so", unwinder64.FormatFrame(frame));
+ EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so", unwinder32.FormatFrame(frame));
frame.map_name = "";
- EXPECT_EQ(" #01 pc 0000000000001000 <anonymous:3000>", Unwinder::FormatFrame(frame, false));
- EXPECT_EQ(" #01 pc 00001000 <anonymous:3000>", Unwinder::FormatFrame(frame, true));
+ EXPECT_EQ(" #01 pc 0000000000001000 <anonymous:3000>", unwinder64.FormatFrame(frame));
+ EXPECT_EQ(" #01 pc 00001000 <anonymous:3000>", unwinder32.FormatFrame(frame));
frame.map_start = 0;
frame.map_end = 0;
- EXPECT_EQ(" #01 pc 0000000000001000 <unknown>", Unwinder::FormatFrame(frame, false));
- EXPECT_EQ(" #01 pc 00001000 <unknown>", Unwinder::FormatFrame(frame, true));
+ EXPECT_EQ(" #01 pc 0000000000001000 <unknown>", unwinder64.FormatFrame(frame));
+ EXPECT_EQ(" #01 pc 00001000 <unknown>", unwinder32.FormatFrame(frame));
+}
+
+TEST_F(UnwinderTest, format_frame_build_id) {
+ RegsFake regs(10);
+ regs.FakeSetArch(ARCH_ARM);
+ Unwinder unwinder(10, maps_.get(), ®s, process_memory_);
+
+ FrameData frame;
+ frame.num = 1;
+ frame.rel_pc = 0x1000;
+ frame.pc = 0x4000;
+ frame.sp = 0x1000;
+ frame.function_name = "function";
+ frame.function_offset = 100;
+ frame.map_name = "/fake/libfake.so";
+ frame.map_elf_start_offset = 0;
+ frame.map_start = 0x3000;
+ frame.map_end = 0x6000;
+ frame.map_flags = PROT_READ;
+
+ EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function+100)", unwinder.FormatFrame(frame));
+ unwinder.SetDisplayBuildID(true);
+ EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function+100) (BuildId: 46414b45)",
+ unwinder.FormatFrame(frame));
}
static std::string ArchToString(ArchEnum arch) {
@@ -1167,7 +1199,7 @@
}
// Verify format frame code.
-TEST_F(UnwinderTest, format_frame) {
+TEST_F(UnwinderTest, format_frame_by_arch) {
std::vector<Regs*> reg_list;
RegsArm* arm = new RegsArm;
arm->set_pc(0x2300);
diff --git a/libutils/Android.bp b/libutils/Android.bp
index c67ff8f..4f194c7 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -69,6 +69,7 @@
],
shared_libs: [
+ "libcutils",
"liblog",
],
@@ -83,7 +84,6 @@
cflags: ["-fvisibility=protected"],
shared_libs: [
- "libcutils",
"libprocessgroup",
"libdl",
"libvndksupport",
@@ -98,14 +98,6 @@
exclude_shared_libs: ["libvndksupport"],
},
- host: {
- cflags: ["-DLIBUTILS_NATIVE=1"],
-
- shared: {
- enabled: false,
- },
- },
-
linux_bionic: {
enabled: true,
},
@@ -180,18 +172,23 @@
},
},
+ shared_libs: [
+ "libutils",
+ "libbacktrace",
+ ],
+
target: {
- android: {
- shared_libs: [
- "libutils",
- "libbacktrace",
- ],
- },
linux: {
srcs: [
"ProcessCallStack.cpp",
],
},
+ darwin: {
+ enabled: false,
+ },
+ windows: {
+ enabled: false,
+ },
},
}
diff --git a/libutils/Looper.cpp b/libutils/Looper.cpp
index b3f943d..2d696eb 100644
--- a/libutils/Looper.cpp
+++ b/libutils/Looper.cpp
@@ -76,8 +76,8 @@
}
void Looper::initTLSKey() {
- int result = pthread_key_create(& gTLSKey, threadDestructor);
- LOG_ALWAYS_FATAL_IF(result != 0, "Could not allocate TLS key.");
+ int error = pthread_key_create(&gTLSKey, threadDestructor);
+ LOG_ALWAYS_FATAL_IF(error != 0, "Could not allocate TLS key: %s", strerror(error));
}
void Looper::threadDestructor(void *st) {
@@ -399,8 +399,8 @@
ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd.get(), &inc, sizeof(uint64_t)));
if (nWrite != sizeof(uint64_t)) {
if (errno != EAGAIN) {
- LOG_ALWAYS_FATAL("Could not write wake signal to fd %d: %s", mWakeEventFd.get(),
- strerror(errno));
+ LOG_ALWAYS_FATAL("Could not write wake signal to fd %d (returned %zd): %s",
+ mWakeEventFd.get(), nWrite, strerror(errno));
}
}
}
diff --git a/libutils/Mutex_test.cpp b/libutils/Mutex_test.cpp
index 8a1805f..79f4302 100644
--- a/libutils/Mutex_test.cpp
+++ b/libutils/Mutex_test.cpp
@@ -29,4 +29,20 @@
android::Mutex::Autolock _l(mLock);
i = 0;
modifyLockedVariable();
-}
\ No newline at end of file
+}
+
+TEST(Mutex, tryLock) {
+ if (mLock.tryLock() != 0) {
+ return;
+ }
+ mLock.unlock();
+}
+
+#if defined(__ANDROID__)
+TEST(Mutex, timedLock) {
+ if (mLock.timedLock(1) != 0) {
+ return;
+ }
+ mLock.unlock();
+}
+#endif
diff --git a/libutils/include/utils/Mutex.h b/libutils/include/utils/Mutex.h
index 29c2e8c..1325bf3 100644
--- a/libutils/include/utils/Mutex.h
+++ b/libutils/include/utils/Mutex.h
@@ -108,7 +108,7 @@
void unlock() RELEASE();
// lock if possible; returns 0 on success, error otherwise
- status_t tryLock() TRY_ACQUIRE(true);
+ status_t tryLock() TRY_ACQUIRE(0);
#if defined(__ANDROID__)
// Lock the mutex, but don't wait longer than timeoutNs (relative time).
@@ -122,7 +122,7 @@
// which is subject to NTP adjustments, and includes time during suspend,
// so a timeout may occur even though no processes could run.
// Not holding a partial wakelock may lead to a system suspend.
- status_t timedLock(nsecs_t timeoutNs) TRY_ACQUIRE(true);
+ status_t timedLock(nsecs_t timeoutNs) TRY_ACQUIRE(0);
#endif
// Manages the mutex automatically. It'll be locked when Autolock is
diff --git a/libvndksupport/Android.bp b/libvndksupport/Android.bp
index bfa2508..546c15c 100644
--- a/libvndksupport/Android.bp
+++ b/libvndksupport/Android.bp
@@ -9,7 +9,10 @@
],
local_include_dirs: ["include/vndksupport"],
export_include_dirs: ["include"],
- shared_libs: ["liblog"],
+ shared_libs: [
+ "libdl_android",
+ "liblog",
+ ],
version_script: "libvndksupport.map.txt",
stubs: {
symbol_file: "libvndksupport.map.txt",
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 9538bba..bc1543b 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -38,6 +38,19 @@
],
},
},
+ sanitize: {
+ misc_undefined: [
+ "signed-integer-overflow",
+ "unsigned-integer-overflow",
+ "shift",
+ "integer-divide-by-zero",
+ "implicit-signed-integer-truncation",
+ // TODO: Fix crash when we enable this option
+ // "implicit-unsigned-integer-truncation",
+ // TODO: not tested yet.
+ // "implicit-integer-sign-change",
+ ],
+ },
}
cc_defaults {
diff --git a/libziparchive/entry_name_utils-inl.h b/libziparchive/entry_name_utils-inl.h
index 5fc2fb4..1714586 100644
--- a/libziparchive/entry_name_utils-inl.h
+++ b/libziparchive/entry_name_utils-inl.h
@@ -35,7 +35,7 @@
return false;
} else {
// 2-5 byte sequences.
- for (uint8_t first = byte << 1; first & 0x80; first <<= 1) {
+ for (uint8_t first = (byte & 0x7f) << 1; first & 0x80; first = (first & 0x7f) << 1) {
++i;
// Missing continuation byte..
diff --git a/libziparchive/unzip.cpp b/libziparchive/unzip.cpp
index 6756007..cc059d8 100644
--- a/libziparchive/unzip.cpp
+++ b/libziparchive/unzip.cpp
@@ -17,6 +17,7 @@
#include <errno.h>
#include <error.h>
#include <fcntl.h>
+#include <fnmatch.h>
#include <getopt.h>
#include <inttypes.h>
#include <stdio.h>
@@ -52,9 +53,21 @@
static uint64_t total_compressed_length = 0;
static size_t file_count = 0;
-static bool Filter(const std::string& name) {
- if (!excludes.empty() && excludes.find(name) != excludes.end()) return true;
- if (!includes.empty() && includes.find(name) == includes.end()) return true;
+static bool ShouldInclude(const std::string& name) {
+ // Explicitly excluded?
+ if (!excludes.empty()) {
+ for (const auto& exclude : excludes) {
+ if (!fnmatch(exclude.c_str(), name.c_str(), 0)) return false;
+ }
+ }
+
+ // Implicitly included?
+ if (includes.empty()) return true;
+
+ // Explicitly included?
+ for (const auto& include : includes) {
+ if (!fnmatch(include.c_str(), name.c_str(), 0)) return true;
+ }
return false;
}
@@ -245,7 +258,7 @@
ZipString string;
while ((err = Next(cookie, &entry, &string)) >= 0) {
std::string name(string.name, string.name + string.name_length);
- if (!Filter(name)) ProcessOne(zah, entry, name);
+ if (ShouldInclude(name)) ProcessOne(zah, entry, name);
}
if (err < -1) error(1, 0, "failed iterating %s: %s", archive_name, ErrorCodeString(err));
@@ -260,7 +273,8 @@
printf(
"\n"
- "Extract FILEs from ZIP archive. Default is all files.\n"
+ "Extract FILEs from ZIP archive. Default is all files. Both the include and\n"
+ "exclude (-x) lists use shell glob patterns.\n"
"\n"
"-d DIR Extract into DIR\n"
"-l List contents (-lq excludes archive name, -lv is verbose)\n"
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 6b9f6e1..e1ec47a 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -102,21 +102,8 @@
}
static uint32_t ComputeHash(const ZipString& name) {
-#if !defined(_WIN32)
- return std::hash<std::string_view>{}(
- std::string_view(reinterpret_cast<const char*>(name.name), name.name_length));
-#else
- // Remove this code path once the windows compiler knows how to compile the above statement.
- uint32_t hash = 0;
- uint16_t len = name.name_length;
- const uint8_t* str = name.name;
-
- while (len--) {
- hash = hash * 31 + *str++;
- }
-
- return hash;
-#endif
+ return static_cast<uint32_t>(std::hash<std::string_view>{}(
+ std::string_view(reinterpret_cast<const char*>(name.name), name.name_length)));
}
static bool isZipStringEqual(const uint8_t* start, const ZipString& zip_string,
@@ -278,11 +265,6 @@
if (static_cast<off64_t>(eocd->cd_start_offset) + eocd->cd_size > eocd_offset) {
ALOGW("Zip: bad offsets (dir %" PRIu32 ", size %" PRIu32 ", eocd %" PRId64 ")",
eocd->cd_start_offset, eocd->cd_size, static_cast<int64_t>(eocd_offset));
-#if defined(__ANDROID__)
- if (eocd->cd_start_offset + eocd->cd_size <= eocd_offset) {
- android_errorWriteLog(0x534e4554, "31251826");
- }
-#endif
return kInvalidOffset;
}
if (eocd->num_records == 0) {
diff --git a/libziparchive/zip_writer.cc b/libziparchive/zip_writer.cc
index 981df3a..0df0fa5 100644
--- a/libziparchive/zip_writer.cc
+++ b/libziparchive/zip_writer.cc
@@ -30,9 +30,13 @@
#include "entry_name_utils-inl.h"
#include "zip_archive_common.h"
-#if !defined(powerof2)
-#define powerof2(x) ((((x)-1) & (x)) == 0)
-#endif
+#undef powerof2
+#define powerof2(x) \
+ ({ \
+ __typeof__(x) _x = (x); \
+ __typeof__(x) _x2; \
+ __builtin_add_overflow(_x, -1, &_x2) ? 1 : ((_x2 & _x) == 0); \
+ })
/* Zip compression methods we support */
enum {
diff --git a/libziparchive/zip_writer_test.cc b/libziparchive/zip_writer_test.cc
index c284273..7322afb 100644
--- a/libziparchive/zip_writer_test.cc
+++ b/libziparchive/zip_writer_test.cc
@@ -257,7 +257,7 @@
std::vector<uint8_t> buffer(kBufSize);
size_t prev = 1;
for (size_t i = 0; i < kBufSize; i++) {
- buffer[i] = i + prev;
+ buffer[i] = static_cast<uint8_t>(i + prev);
prev = i;
}
diff --git a/lmkd/event.logtags b/lmkd/event.logtags
index 7c2cd18..065c6db 100644
--- a/lmkd/event.logtags
+++ b/lmkd/event.logtags
@@ -35,4 +35,4 @@
# TODO: generate ".java" and ".h" files with integer constants from this file.
# for meminfo logs
-10195355 meminfo (MemFree|1),(Cached|1),(SwapCached|1),(Buffers|1),(Shmem|1),(Unevictable|1),(SwapFree|1),(ActiveAnon|1),(InactiveAnon|1),(ActiveFile|1),(InactiveFile|1),(SReclaimable|1),(SUnreclaim|1),(KernelStack|1),(PageTables|1),(ION_heap|1),(ION_heap_pool|1),(CmaFree|1)
+10195355 meminfo (MemFree|1),(Cached|1),(SwapCached|1),(Buffers|1),(Shmem|1),(Unevictable|1),(SwapTotal|1),(SwapFree|1),(ActiveAnon|1),(InactiveAnon|1),(ActiveFile|1),(InactiveFile|1),(SReclaimable|1),(SUnreclaim|1),(KernelStack|1),(PageTables|1),(ION_heap|1),(ION_heap_pool|1),(CmaFree|1)
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 2d3fbfc..2de7378 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -110,7 +110,7 @@
*/
#define PSI_WINDOW_SIZE_MS 1000
/* Polling period after initial PSI signal */
-#define PSI_POLL_PERIOD_MS 40
+#define PSI_POLL_PERIOD_MS 10
/* Poll for the duration of one window after initial PSI signal */
#define PSI_POLL_COUNT (PSI_WINDOW_SIZE_MS / PSI_POLL_PERIOD_MS)
diff --git a/logcat/event.logtags b/logcat/event.logtags
index da8d2d4..3a1d36f 100644
--- a/logcat/event.logtags
+++ b/logcat/event.logtags
@@ -116,8 +116,8 @@
# audio
# 61000 - 61199 reserved for audioserver
-# 0 for screen off, 1 for screen on, 2 for key-guard done
-70000 screen_toggled (screen_state|1|5)
+# com.android.server.policy
+# 70000 - 70199 reserved for PhoneWindowManager and other policies
# aggregation service
70200 aggregation (aggregation time|2|3)
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index d5c40be..b32b437 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -33,6 +33,7 @@
#include <android-base/file.h>
#include <android-base/macros.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <gtest/gtest.h>
#include <log/event_tag_map.h>
#include <log/log.h>
@@ -1747,3 +1748,13 @@
EXPECT_EQ(logcatHelpTextSize * 2, logcatLastHelpTextSize);
#endif
}
+
+TEST(logcat, invalid_buffer) {
+ FILE* fp = popen("logcat -b foo 2>&1", "r");
+ ASSERT_NE(nullptr, fp);
+ std::string output;
+ ASSERT_TRUE(android::base::ReadFdToString(fileno(fp), &output));
+ pclose(fp);
+
+ ASSERT_TRUE(android::base::StartsWith(output, "unknown buffer foo\n"));
+}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 54b019e..462ae8b 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -8,6 +8,7 @@
LOCAL_SRC_FILES := $(LOCAL_MODULE)
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
+LOCAL_REQUIRED_MODULES := fsverity_init
# The init symlink must be a post install command of a file that is to TARGET_ROOT_OUT.
# Since init.rc is required for init and satisfies that requirement, we hijack it to create the symlink.
@@ -57,6 +58,15 @@
endif
#######################################
+# fsverity_init
+
+include $(CLEAR_VARS)
+LOCAL_MODULE:= fsverity_init
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_SRC_FILES := fsverity_init.sh
+include $(BUILD_PREBUILT)
+
+#######################################
# init.environ.rc
include $(CLEAR_VARS)
@@ -79,7 +89,7 @@
EXPORT_GLOBAL_GCOV_OPTIONS :=
ifeq ($(NATIVE_COVERAGE),true)
- EXPORT_GLOBAL_GCOV_OPTIONS := export GCOV_PREFIX /data/misc/gcov
+ EXPORT_GLOBAL_GCOV_OPTIONS := export GCOV_PREFIX /data/misc/trace
endif
# Put it here instead of in init.rc module definition,
@@ -366,3 +376,5 @@
$(hide) echo -n > $@
$(hide) $(foreach lib,$(PRIVATE_VNDK_SAMEPROCESS_LIBRARIES), \
echo $(lib).so >> $@;)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/rootdir/avb/Android.mk b/rootdir/avb/Android.mk
new file mode 100644
index 0000000..5dc019c
--- /dev/null
+++ b/rootdir/avb/Android.mk
@@ -0,0 +1,46 @@
+LOCAL_PATH:= $(call my-dir)
+
+#######################################
+# q-gsi.avbpubkey
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := q-gsi.avbpubkey
+LOCAL_MODULE_CLASS := ETC
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/first_stage_ramdisk/avb
+else
+LOCAL_MODULE_PATH := $(TARGET_RAMDISK_OUT)/avb
+endif
+
+include $(BUILD_PREBUILT)
+
+#######################################
+# r-gsi.avbpubkey
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := r-gsi.avbpubkey
+LOCAL_MODULE_CLASS := ETC
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/first_stage_ramdisk/avb
+else
+LOCAL_MODULE_PATH := $(TARGET_RAMDISK_OUT)/avb
+endif
+
+include $(BUILD_PREBUILT)
+
+#######################################
+# s-gsi.avbpubkey
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := s-gsi.avbpubkey
+LOCAL_MODULE_CLASS := ETC
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/first_stage_ramdisk/avb
+else
+LOCAL_MODULE_PATH := $(TARGET_RAMDISK_OUT)/avb
+endif
+
+include $(BUILD_PREBUILT)
diff --git a/rootdir/avb/q-gsi.avbpubkey b/rootdir/avb/q-gsi.avbpubkey
new file mode 100644
index 0000000..5ed7543
--- /dev/null
+++ b/rootdir/avb/q-gsi.avbpubkey
Binary files differ
diff --git a/rootdir/avb/r-gsi.avbpubkey b/rootdir/avb/r-gsi.avbpubkey
new file mode 100644
index 0000000..2609b30
--- /dev/null
+++ b/rootdir/avb/r-gsi.avbpubkey
Binary files differ
diff --git a/rootdir/avb/s-gsi.avbpubkey b/rootdir/avb/s-gsi.avbpubkey
new file mode 100644
index 0000000..9065fb8
--- /dev/null
+++ b/rootdir/avb/s-gsi.avbpubkey
Binary files differ
diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt
index fa46334..7324ba9 100644
--- a/rootdir/etc/ld.config.legacy.txt
+++ b/rootdir/etc/ld.config.legacy.txt
@@ -11,14 +11,13 @@
dir.legacy = /odm
dir.legacy = /sbin
-dir.legacy = /data/nativetest
-dir.legacy = /data/nativetest64
-dir.legacy = /data/benchmarktest
-dir.legacy = /data/benchmarktest64
-
# Except for /postinstall, where only /system and /product are searched
dir.postinstall = /postinstall
+# Fallback entry to provide APEX namespace lookups for binaries anywhere else.
+# This must be last.
+dir.legacy = /data
+
[legacy]
namespace.default.isolated = false
@@ -54,8 +53,7 @@
# Visible because some libraries are dlopen'ed, e.g. libopenjdk is dlopen'ed by
# libart.
namespace.default.visible = true
-namespace.default.link.runtime.shared_libs = libart.so:libartd.so
-namespace.default.link.runtime.shared_libs += libdexfile_external.so
+namespace.default.link.runtime.shared_libs = libdexfile_external.so
namespace.default.link.runtime.shared_libs += libnativebridge.so
namespace.default.link.runtime.shared_libs += libnativehelper.so
namespace.default.link.runtime.shared_libs += libnativeloader.so
@@ -102,6 +100,7 @@
namespace.media.link.default.shared_libs = libandroid.so
namespace.media.link.default.shared_libs += libbinder_ndk.so
namespace.media.link.default.shared_libs += libc.so
+namespace.media.link.default.shared_libs += libcgrouprc.so
namespace.media.link.default.shared_libs += libdl.so
namespace.media.link.default.shared_libs += liblog.so
namespace.media.link.default.shared_libs += libmediametrics.so
@@ -127,7 +126,7 @@
namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
namespace.conscrypt.links = runtime,default
-namespace.conscrypt.link.runtime.shared_libs = libjavacore.so
+namespace.conscrypt.link.runtime.shared_libs = libandroidio.so
namespace.conscrypt.link.default.shared_libs = libc.so
namespace.conscrypt.link.default.shared_libs += libm.so
namespace.conscrypt.link.default.shared_libs += libdl.so
@@ -145,6 +144,7 @@
namespace.resolv.asan.search.paths = /apex/com.android.resolv/${LIB}
namespace.resolv.links = default
namespace.resolv.link.default.shared_libs = libc.so
+namespace.resolv.link.default.shared_libs += libcgrouprc.so
namespace.resolv.link.default.shared_libs += libm.so
namespace.resolv.link.default.shared_libs += libdl.so
namespace.resolv.link.default.shared_libs += libbinder_ndk.so
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 927587b..45e80e1 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -27,13 +27,12 @@
# necessary) the unrestricted subdirs above. Then clean this up.
dir.unrestricted = /data/local/tmp
-dir.system = /data/nativetest
-dir.system = /data/nativetest64
-dir.system = /data/benchmarktest
-dir.system = /data/benchmarktest64
-
dir.postinstall = /postinstall
+# Fallback entry to provide APEX namespace lookups for binaries anywhere else.
+# This must be last.
+dir.system = /data
+
[system]
additional.namespaces = runtime,conscrypt,media,resolv,sphal,vndk,rs
@@ -133,8 +132,7 @@
# Visible because some libraries are dlopen'ed, e.g. libopenjdk is dlopen'ed by
# libart.
namespace.default.visible = true
-namespace.default.link.runtime.shared_libs = libart.so:libartd.so
-namespace.default.link.runtime.shared_libs += libdexfile_external.so
+namespace.default.link.runtime.shared_libs = libdexfile_external.so
namespace.default.link.runtime.shared_libs += libnativebridge.so
namespace.default.link.runtime.shared_libs += libnativehelper.so
namespace.default.link.runtime.shared_libs += libnativeloader.so
@@ -196,7 +194,7 @@
namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
namespace.conscrypt.links = runtime,default
-namespace.conscrypt.link.runtime.shared_libs = libjavacore.so
+namespace.conscrypt.link.runtime.shared_libs = libandroidio.so
namespace.conscrypt.link.default.shared_libs = libc.so
namespace.conscrypt.link.default.shared_libs += libm.so
namespace.conscrypt.link.default.shared_libs += libdl.so
@@ -214,6 +212,7 @@
namespace.resolv.asan.search.paths = /apex/com.android.resolv/${LIB}
namespace.resolv.links = default
namespace.resolv.link.default.shared_libs = libc.so
+namespace.resolv.link.default.shared_libs += libcgrouprc.so
namespace.resolv.link.default.shared_libs += libm.so
namespace.resolv.link.default.shared_libs += libdl.so
namespace.resolv.link.default.shared_libs += libbinder_ndk.so
@@ -255,17 +254,19 @@
namespace.sphal.asan.permitted.paths += /vendor/${LIB}
# Once in this namespace, access to libraries in /system/lib is restricted. Only
-# libs listed here can be used.
-namespace.sphal.links = default,vndk,rs
+# libs listed here can be used. Order is important here as the namespaces are
+# tried in this order. rs should be before vndk because both are capable
+# of loading libRS_internal.so
+namespace.sphal.links = rs,default,vndk
+
+# Renderscript gets separate namespace
+namespace.sphal.link.rs.shared_libs = libRS_internal.so
namespace.sphal.link.default.shared_libs = %LLNDK_LIBRARIES%
namespace.sphal.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
namespace.sphal.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
-# Renderscript gets separate namespace
-namespace.sphal.link.rs.shared_libs = libRS_internal.so
-
###############################################################################
# "rs" namespace
#
@@ -577,8 +578,7 @@
namespace.default.links = runtime,resolv
namespace.default.visible = true
-namespace.default.link.runtime.shared_libs = libart.so:libartd.so
-namespace.default.link.runtime.shared_libs += libdexfile_external.so
+namespace.default.link.runtime.shared_libs = libdexfile_external.so
namespace.default.link.runtime.shared_libs += libnativebridge.so
namespace.default.link.runtime.shared_libs += libnativehelper.so
namespace.default.link.runtime.shared_libs += libnativeloader.so
@@ -637,7 +637,7 @@
namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
namespace.conscrypt.links = runtime,default
-namespace.conscrypt.link.runtime.shared_libs = libjavacore.so
+namespace.conscrypt.link.runtime.shared_libs = libandroidio.so
namespace.conscrypt.link.default.shared_libs = libc.so
namespace.conscrypt.link.default.shared_libs += libm.so
namespace.conscrypt.link.default.shared_libs += libdl.so
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index beb6125..a762ba8 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -27,13 +27,12 @@
# necessary) the unrestricted subdirs above. Then clean this up.
dir.unrestricted = /data/local/tmp
-dir.system = /data/nativetest
-dir.system = /data/nativetest64
-dir.system = /data/benchmarktest
-dir.system = /data/benchmarktest64
-
dir.postinstall = /postinstall
+# Fallback entry to provide APEX namespace lookups for binaries anywhere else.
+# This must be last.
+dir.system = /data
+
[system]
additional.namespaces = runtime,conscrypt,media,resolv,sphal,vndk,rs
@@ -74,8 +73,7 @@
# Visible because some libraries are dlopen'ed, e.g. libopenjdk is dlopen'ed by
# libart.
namespace.default.visible = true
-namespace.default.link.runtime.shared_libs = libart.so:libartd.so
-namespace.default.link.runtime.shared_libs += libdexfile_external.so
+namespace.default.link.runtime.shared_libs = libdexfile_external.so
namespace.default.link.runtime.shared_libs += libnativebridge.so
namespace.default.link.runtime.shared_libs += libnativehelper.so
namespace.default.link.runtime.shared_libs += libnativeloader.so
@@ -138,7 +136,7 @@
namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
namespace.conscrypt.links = runtime,default
-namespace.conscrypt.link.runtime.shared_libs = libjavacore.so
+namespace.conscrypt.link.runtime.shared_libs = libandroidio.so
namespace.conscrypt.link.default.shared_libs = libc.so
namespace.conscrypt.link.default.shared_libs += libm.so
namespace.conscrypt.link.default.shared_libs += libdl.so
@@ -156,6 +154,7 @@
namespace.resolv.asan.search.paths = /apex/com.android.resolv/${LIB}
namespace.resolv.links = default
namespace.resolv.link.default.shared_libs = libc.so
+namespace.resolv.link.default.shared_libs += libcgrouprc.so
namespace.resolv.link.default.shared_libs += libm.so
namespace.resolv.link.default.shared_libs += libdl.so
namespace.resolv.link.default.shared_libs += libbinder_ndk.so
@@ -197,17 +196,19 @@
namespace.sphal.asan.permitted.paths += /vendor/${LIB}
# Once in this namespace, access to libraries in /system/lib is restricted. Only
-# libs listed here can be used.
-namespace.sphal.links = default,vndk,rs
+# libs listed here can be used. Order is important here as the namespaces are
+# tried in this order. rs should be before vndk because both are capable
+# of loading libRS_internal.so
+namespace.sphal.links = rs,default,vndk
+
+# Renderscript gets separate namespace
+namespace.sphal.link.rs.shared_libs = libRS_internal.so
namespace.sphal.link.default.shared_libs = %LLNDK_LIBRARIES%
namespace.sphal.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
namespace.sphal.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
-# Renderscript gets separate namespace
-namespace.sphal.link.rs.shared_libs = libRS_internal.so
-
###############################################################################
# "rs" namespace
#
@@ -400,8 +401,7 @@
namespace.default.links = runtime,resolv
namespace.default.visible = true
-namespace.default.link.runtime.shared_libs = libart.so:libartd.so
-namespace.default.link.runtime.shared_libs += libdexfile_external.so
+namespace.default.link.runtime.shared_libs = libdexfile_external.so
namespace.default.link.runtime.shared_libs += libnativebridge.so
namespace.default.link.runtime.shared_libs += libnativehelper.so
namespace.default.link.runtime.shared_libs += libnativeloader.so
@@ -460,7 +460,7 @@
namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
namespace.conscrypt.links = runtime,default
-namespace.conscrypt.link.runtime.shared_libs = libjavacore.so
+namespace.conscrypt.link.runtime.shared_libs = libandroidio.so
namespace.conscrypt.link.default.shared_libs = libc.so
namespace.conscrypt.link.default.shared_libs += libm.so
namespace.conscrypt.link.default.shared_libs += libdl.so
@@ -477,6 +477,7 @@
namespace.resolv.asan.search.paths = /apex/com.android.resolv/${LIB}
namespace.resolv.links = default
namespace.resolv.link.default.shared_libs = libc.so
+namespace.resolv.link.default.shared_libs += libcgrouprc.so
namespace.resolv.link.default.shared_libs += libm.so
namespace.resolv.link.default.shared_libs += libdl.so
namespace.resolv.link.default.shared_libs += libbinder_ndk.so
diff --git a/rootdir/fsverity_init.sh b/rootdir/fsverity_init.sh
new file mode 100644
index 0000000..4fee15f
--- /dev/null
+++ b/rootdir/fsverity_init.sh
@@ -0,0 +1,32 @@
+#!/system/bin/sh
+#
+# Copyright (C) 2019 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.
+#
+
+# Enforce fsverity signature checking
+echo 1 > /proc/sys/fs/verity/require_signatures
+
+# Load all keys
+for cert in /product/etc/security/fsverity/*.der; do
+ /system/bin/mini-keyctl padd asymmetric fsv_product .fs-verity < "$cert" ||
+ log -p e -t fsverity_init "Failed to load $cert"
+done
+
+DEBUGGABLE=$(getprop ro.debuggable)
+if [ $DEBUGGABLE != "1" ]; then
+ # Prevent future key links to .fs-verity keyring
+ /system/bin/mini-keyctl restrict_keyring .fs-verity ||
+ log -p e -t fsverity_init "Failed to restrict .fs-verity keyring"
+fi
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 8e63a81..473cd8d 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -222,6 +222,9 @@
chmod 0664 /dev/cpuset/restricted/tasks
chmod 0664 /dev/cpuset/tasks
+ # make the PSI monitor accessible to others
+ chown system system /proc/pressure/memory
+ chmod 0664 /proc/pressure/memory
# qtaguid will limit access to specific data based on group memberships.
# net_bw_acct grants impersonation of socket owners.
@@ -420,12 +423,7 @@
# Load fsverity keys. This needs to happen before apexd, as post-install of
# APEXes may rely on keys.
- exec -- /system/bin/mini-keyctl dadd asymmetric product_cert /product/etc/security/cacerts_fsverity .fs-verity
- exec -- /system/bin/mini-keyctl dadd asymmetric vendor_cert /vendor/etc/security/cacerts_fsverity .fs-verity
- # Prevent future key links to fsverity keyring
- exec -- /system/bin/mini-keyctl restrict_keyring .fs-verity
- # Enforce fsverity signature checking
- write /proc/sys/fs/verity/require_signatures 1
+ exec -- /system/bin/fsverity_init
# Make sure that apexd is started in the default namespace
enter_default_mount_ns
@@ -654,6 +652,12 @@
write /proc/sys/vm/dirty_expire_centisecs 200
write /proc/sys/vm/dirty_background_ratio 5
+ # F2FS tuning. Set cp_interval larger than dirty_expire_centisecs
+ # to avoid power consumption when system becomes mostly idle. Be careful
+ # to make it too large, since it may bring userdata loss, if they
+ # are not aware of using fsync()/sync() to prepare sudden power-cut.
+ write /sys/fs/f2fs/${dev.mnt.blk.data}/cp_interval 200
+
# Permissions for System Server and daemons.
chown radio system /sys/android_power/state
chown radio system /sys/android_power/request_state
diff --git a/rootdir/update_and_install_ld_config.mk b/rootdir/update_and_install_ld_config.mk
index 912a73e..f62c3df 100644
--- a/rootdir/update_and_install_ld_config.mk
+++ b/rootdir/update_and_install_ld_config.mk
@@ -134,8 +134,8 @@
# if TARGET_VNDK_USE_CORE_VARIANT is not set. In this case, we need to remove
# the entire line in the linker config so that we are not left with a line
# like:
- # namespace.sphal.link.default.shared_libs +=
- $(hide) sed -i.bak -e "s?^.*\+= %VNDK_USING_CORE_VARIANT_LIBRARIES%\$$??" $@
+ # namespace.vndk.link.vndk_in_system.shared_libs =
+ $(hide) sed -i.bak -e 's?^.*= %VNDK_USING_CORE_VARIANT_LIBRARIES%$$??' $@
endif
$(hide) echo -n > $(PRIVATE_INTERMEDIATES_DIR)/private_llndk && \
diff --git a/toolbox/Android.bp b/toolbox/Android.bp
index 7ad6f1c..5289976 100644
--- a/toolbox/Android.bp
+++ b/toolbox/Android.bp
@@ -7,6 +7,8 @@
"-Wno-unused-const-variable",
"-D_FILE_OFFSET_BITS=64",
"-DWITHOUT_NLS",
+ "-DWITHOUT_BZ2",
+ "-DWITHOUT_GZIP",
],
}
@@ -54,14 +56,6 @@
defaults: ["toolbox_binary_defaults"],
}
-// We only want 'r' on userdebug and eng builds.
-cc_binary {
- name: "r",
- defaults: ["toolbox_defaults"],
- srcs: ["r.c"],
- vendor_available: true,
-}
-
// We build BSD grep separately (but see http://b/111849261).
cc_defaults {
name: "grep_common",
diff --git a/toolbox/r.c b/toolbox/r.c
deleted file mode 100644
index b96cdb2..0000000
--- a/toolbox/r.c
+++ /dev/null
@@ -1,102 +0,0 @@
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-#if __LP64__
-#define strtoptr strtoull
-#else
-#define strtoptr strtoul
-#endif
-
-static int usage()
-{
- fprintf(stderr,"r [-b|-s] <address> [<value>]\n");
- return -1;
-}
-
-int main(int argc, char *argv[])
-{
- if(argc < 2) return usage();
-
- int width = 4;
- if(!strcmp(argv[1], "-b")) {
- width = 1;
- argc--;
- argv++;
- } else if(!strcmp(argv[1], "-s")) {
- width = 2;
- argc--;
- argv++;
- }
-
- if(argc < 2) return usage();
- uintptr_t addr = strtoptr(argv[1], 0, 16);
-
- uintptr_t endaddr = 0;
- char* end = strchr(argv[1], '-');
- if (end)
- endaddr = strtoptr(end + 1, 0, 16);
-
- if (!endaddr)
- endaddr = addr + width - 1;
-
- if (endaddr <= addr) {
- fprintf(stderr, "end address <= start address\n");
- return -1;
- }
-
- bool set = false;
- uint32_t value = 0;
- if(argc > 2) {
- set = true;
- value = strtoul(argv[2], 0, 16);
- }
-
- int fd = open("/dev/mem", O_RDWR | O_SYNC);
- if(fd < 0) {
- fprintf(stderr,"cannot open /dev/mem\n");
- return -1;
- }
-
- off64_t mmap_start = addr & ~(PAGE_SIZE - 1);
- size_t mmap_size = endaddr - mmap_start + 1;
- mmap_size = (mmap_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
-
- void* page = mmap64(0, mmap_size, PROT_READ | PROT_WRITE,
- MAP_SHARED, fd, mmap_start);
-
- if(page == MAP_FAILED){
- fprintf(stderr,"cannot mmap region\n");
- return -1;
- }
-
- while (addr <= endaddr) {
- switch(width){
- case 4: {
- uint32_t* x = (uint32_t*) (((uintptr_t) page) + (addr & 4095));
- if(set) *x = value;
- fprintf(stderr,"%08"PRIxPTR": %08x\n", addr, *x);
- break;
- }
- case 2: {
- uint16_t* x = (uint16_t*) (((uintptr_t) page) + (addr & 4095));
- if(set) *x = value;
- fprintf(stderr,"%08"PRIxPTR": %04x\n", addr, *x);
- break;
- }
- case 1: {
- uint8_t* x = (uint8_t*) (((uintptr_t) page) + (addr & 4095));
- if(set) *x = value;
- fprintf(stderr,"%08"PRIxPTR": %02x\n", addr, *x);
- break;
- }
- }
- addr += width;
- }
- return 0;
-}
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/file.c b/toolbox/upstream-netbsd/usr.bin/grep/file.c
index cf4a0fa..428bf58 100644
--- a/toolbox/upstream-netbsd/usr.bin/grep/file.c
+++ b/toolbox/upstream-netbsd/usr.bin/grep/file.c
@@ -1,4 +1,4 @@
-/* $NetBSD: file.c,v 1.7 2011/04/18 22:46:48 joerg Exp $ */
+/* $NetBSD: file.c,v 1.10 2018/08/12 09:03:21 christos Exp $ */
/* $FreeBSD: head/usr.bin/grep/file.c 211496 2010-08-19 09:28:59Z des $ */
/* $OpenBSD: file.c,v 1.11 2010/07/02 20:48:48 nicm Exp $ */
@@ -35,15 +35,12 @@
#endif
#include <sys/cdefs.h>
-__RCSID("$NetBSD: file.c,v 1.7 2011/04/18 22:46:48 joerg Exp $");
+__RCSID("$NetBSD: file.c,v 1.10 2018/08/12 09:03:21 christos Exp $");
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
-#ifndef __ANDROID__
-#include <bzlib.h>
-#endif
#include <err.h>
#include <errno.h>
#include <fcntl.h>
@@ -53,21 +50,20 @@
#include <unistd.h>
#include <wchar.h>
#include <wctype.h>
-#ifndef __ANDROID__
-#include <zlib.h>
-#endif
#include "grep.h"
#define MAXBUFSIZ (32 * 1024)
#define LNBUFBUMP 80
-#ifndef __ANDROID__
+#ifndef WITHOUT_GZIP
static gzFile gzbufdesc;
+#endif
+#ifndef WITHOUT_BZ2
static BZFILE* bzbufdesc;
#endif
-static unsigned char buffer[MAXBUFSIZ];
+static unsigned char buffer[MAXBUFSIZ + 1];
static unsigned char *bufpos;
static size_t bufrem;
@@ -77,18 +73,21 @@
static inline int
grep_refill(struct file *f)
{
- ssize_t nr;
-#ifndef __ANDROID__
+ ssize_t nr = -1;
int bzerr;
-#endif
bufpos = buffer;
bufrem = 0;
-#ifndef __ANDROID__
- if (filebehave == FILE_GZIP)
+#ifndef WITHOUT_GZIP
+ if (filebehave == FILE_GZIP) {
nr = gzread(gzbufdesc, buffer, MAXBUFSIZ);
- else if (filebehave == FILE_BZIP && bzbufdesc != NULL) {
+ if (nr == -1)
+ return -1;
+ }
+#endif
+#ifndef WITHOUT_BZ2
+ if (filebehave == FILE_BZIP && bzbufdesc != NULL) {
nr = BZ2_bzRead(&bzerr, bzbufdesc, buffer, MAXBUFSIZ);
switch (bzerr) {
case BZ_OK:
@@ -114,9 +113,13 @@
/* Make sure we exit with an error */
nr = -1;
}
- } else
+ if (nr == -1)
+ return -1;
+ }
#endif
+ if (nr == -1) {
nr = read(f->fd, buffer, MAXBUFSIZ);
+ }
if (nr < 0)
return (-1);
@@ -125,7 +128,7 @@
return (0);
}
-static inline int
+static inline void
grep_lnbufgrow(size_t newlen)
{
@@ -133,8 +136,6 @@
lnbuf = grep_realloc(lnbuf, newlen);
lnbuflen = newlen;
}
-
- return (0);
}
char *
@@ -159,20 +160,22 @@
/* Look for a newline in the remaining part of the buffer */
if ((p = memchr(bufpos, line_sep, bufrem)) != NULL) {
++p; /* advance over newline */
- ret = (char *)bufpos;
len = p - bufpos;
+ grep_lnbufgrow(len + 1);
+ memcpy(lnbuf, bufpos, len);
+ lnbuf[len] = '\0';
+ *lenp = len;
bufrem -= len;
bufpos = p;
- *lenp = len;
- return (ret);
+ return ((char *)lnbuf);
}
/* We have to copy the current buffered data to the line buffer */
for (len = bufrem, off = 0; ; len += bufrem) {
/* Make sure there is room for more data */
- if (grep_lnbufgrow(len + LNBUFBUMP))
- goto error;
+ grep_lnbufgrow(len + LNBUFBUMP);
memcpy(lnbuf + off, bufpos, len - off);
+ lnbuf[len] = '\0';
off = len;
if (grep_refill(f) != 0)
goto error;
@@ -185,9 +188,9 @@
++p;
diff = p - bufpos;
len += diff;
- if (grep_lnbufgrow(len))
- goto error;
+ grep_lnbufgrow(len + 1);
memcpy(lnbuf + off, bufpos, diff);
+ lnbuf[off + diff] = '\0';
bufrem -= diff;
bufpos = p;
break;
@@ -204,11 +207,13 @@
grep_file_init(struct file *f)
{
-#ifndef __ANDROID__
+#ifndef WITHOUT_GZIP
if (filebehave == FILE_GZIP &&
(gzbufdesc = gzdopen(f->fd, "r")) == NULL)
goto error;
+#endif
+#ifndef WITHOUT_BZ2
if (filebehave == FILE_BZIP &&
(bzbufdesc = BZ2_bzdopen(f->fd, "r")) == NULL)
goto error;
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/grep.c b/toolbox/upstream-netbsd/usr.bin/grep/grep.c
index 1ea6ed3..bad2a73 100644
--- a/toolbox/upstream-netbsd/usr.bin/grep/grep.c
+++ b/toolbox/upstream-netbsd/usr.bin/grep/grep.c
@@ -1,4 +1,4 @@
-/* $NetBSD: grep.c,v 1.12 2014/07/11 16:30:45 christos Exp $ */
+/* $NetBSD: grep.c,v 1.15 2018/08/12 09:03:21 christos Exp $ */
/* $FreeBSD: head/usr.bin/grep/grep.c 211519 2010-08-19 22:55:17Z delphij $ */
/* $OpenBSD: grep.c,v 1.42 2010/07/02 22:18:03 tedu Exp $ */
@@ -34,7 +34,7 @@
#endif
#include <sys/cdefs.h>
-__RCSID("$NetBSD: grep.c,v 1.12 2014/07/11 16:30:45 christos Exp $");
+__RCSID("$NetBSD: grep.c,v 1.15 2018/08/12 09:03:21 christos Exp $");
#include <sys/stat.h>
#include <sys/types.h>
@@ -170,7 +170,9 @@
struct option long_options[] =
{
{"binary-files", required_argument, NULL, BIN_OPT},
+#ifndef WITHOUT_GZIP
{"decompress", no_argument, NULL, DECOMPRESS_OPT},
+#endif
{"help", no_argument, NULL, HELP_OPT},
{"mmap", no_argument, NULL, MMAP_OPT},
{"line-buffered", no_argument, NULL, LINEBUF_OPT},
@@ -197,7 +199,9 @@
{"no-filename", no_argument, NULL, 'h'},
{"with-filename", no_argument, NULL, 'H'},
{"ignore-case", no_argument, NULL, 'i'},
+#ifndef WITHOUT_BZ2
{"bz2decompress", no_argument, NULL, 'J'},
+#endif
{"files-with-matches", no_argument, NULL, 'l'},
{"files-without-match", no_argument, NULL, 'L'},
{"max-count", required_argument, NULL, 'm'},
@@ -338,6 +342,7 @@
case 'g':
grepbehave = GREP_BASIC;
break;
+#ifndef WITHOUT_GZIP
case 'z':
filebehave = FILE_GZIP;
switch(__progname[1]) {
@@ -352,6 +357,7 @@
break;
}
break;
+#endif
}
lastc = '\0';
@@ -491,9 +497,11 @@
iflag = true;
cflags |= REG_ICASE;
break;
+#ifndef WITHOUT_BZ2
case 'J':
filebehave = FILE_BZIP;
break;
+#endif
case 'L':
lflag = false;
Lflag = true;
@@ -596,9 +604,11 @@
strcasecmp("no", optarg) != 0)
errx(2, getstr(3), "--color");
break;
+#ifndef WITHOUT_GZIP
case DECOMPRESS_OPT:
filebehave = FILE_GZIP;
break;
+#endif
case LABEL_OPT:
label = optarg;
break;
@@ -679,8 +689,13 @@
}
}
- if (lbflag)
+ if (lbflag) {
+#ifdef _IOLBF
+ setvbuf(stdout, NULL, _IOLBF, 0);
+#else
setlinebuf(stdout);
+#endif
+ }
if ((aargc == 0 || aargc == 1) && !Hflag)
hflag = true;
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/grep.h b/toolbox/upstream-netbsd/usr.bin/grep/grep.h
index fa2a3e3..b7ef7fa 100644
--- a/toolbox/upstream-netbsd/usr.bin/grep/grep.h
+++ b/toolbox/upstream-netbsd/usr.bin/grep/grep.h
@@ -1,4 +1,4 @@
-/* $NetBSD: grep.h,v 1.8 2012/05/06 22:27:00 joerg Exp $ */
+/* $NetBSD: grep.h,v 1.10 2018/08/12 09:03:21 christos Exp $ */
/* $OpenBSD: grep.h,v 1.15 2010/04/05 03:03:55 tedu Exp $ */
/* $FreeBSD: head/usr.bin/grep/grep.h 211496 2010-08-19 09:28:59Z des $ */
@@ -29,14 +29,14 @@
* SUCH DAMAGE.
*/
-#ifndef __ANDROID__
+#ifndef WITHOUT_BZ2
#include <bzlib.h>
#endif
#include <limits.h>
#include <regex.h>
#include <stdbool.h>
#include <stdio.h>
-#ifndef __ANDROID__
+#ifndef WITHOUT_GZIP
#include <zlib.h>
#endif
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/util.c b/toolbox/upstream-netbsd/usr.bin/grep/util.c
index ecd948d..a3c9e4c 100644
--- a/toolbox/upstream-netbsd/usr.bin/grep/util.c
+++ b/toolbox/upstream-netbsd/usr.bin/grep/util.c
@@ -1,4 +1,4 @@
-/* $NetBSD: util.c,v 1.17 2013/01/21 03:24:43 msaitoh Exp $ */
+/* $NetBSD: util.c,v 1.19 2018/02/05 22:14:26 mrg Exp $ */
/* $FreeBSD: head/usr.bin/grep/util.c 211496 2010-08-19 09:28:59Z des $ */
/* $OpenBSD: util.c,v 1.39 2010/07/02 22:18:03 tedu Exp $ */
@@ -34,7 +34,7 @@
#endif
#include <sys/cdefs.h>
-__RCSID("$NetBSD: util.c,v 1.17 2013/01/21 03:24:43 msaitoh Exp $");
+__RCSID("$NetBSD: util.c,v 1.19 2018/02/05 22:14:26 mrg Exp $");
#include <sys/stat.h>
#include <sys/types.h>
@@ -478,9 +478,10 @@
if (color)
fprintf(stdout, "\33[%sm\33[K", color);
- fwrite(line->dat + matches[i].rm_so,
- matches[i].rm_eo - matches[i].rm_so, 1,
- stdout);
+ fwrite(line->dat + matches[i].rm_so,
+ matches[i].rm_eo - matches[i].rm_so, 1,
+ stdout);
+
if (color)
fprintf(stdout, "\33[m\33[K");
a = matches[i].rm_eo;
diff --git a/trusty/trusty-base.mk b/trusty/trusty-base.mk
index 0a0ecec..00e3dbc 100644
--- a/trusty/trusty-base.mk
+++ b/trusty/trusty-base.mk
@@ -19,8 +19,13 @@
# to pull in the baseline set of Trusty specific modules.
#
+# For gatekeeper, we include the generic -service and -impl to use legacy
+# HAL loading of gatekeeper.trusty.
+
PRODUCT_PACKAGES += \
android.hardware.keymaster@3.0-service.trusty \
+ android.hardware.gatekeeper@1.0-service \
+ android.hardware.gatekeeper@1.0-impl \
gatekeeper.trusty
PRODUCT_PROPERTY_OVERRIDES += \