Merge "Allow properties to be derived from partition-specific properties during init"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index bc5685b..cc85408 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -19,6 +19,9 @@
"name": "libprocinfo_test"
},
{
+ "name": "libutils_test"
+ },
+ {
"name": "memunreachable_test"
},
{
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index fa3738d..32f9086 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -32,6 +32,7 @@
#include <functional>
#include <list>
#include <mutex>
+#include <optional>
#include <unordered_map>
#include <utility>
#include <variant>
@@ -225,14 +226,22 @@
void fdevent_add(fdevent* fde, unsigned events) {
check_main_thread();
+ CHECK(!(events & FDE_TIMEOUT));
fdevent_set(fde, (fde->state & FDE_EVENTMASK) | events);
}
void fdevent_del(fdevent* fde, unsigned events) {
check_main_thread();
+ CHECK(!(events & FDE_TIMEOUT));
fdevent_set(fde, (fde->state & FDE_EVENTMASK) & ~events);
}
+void fdevent_set_timeout(fdevent* fde, std::optional<std::chrono::milliseconds> timeout) {
+ check_main_thread();
+ fde->timeout = timeout;
+ fde->last_active = std::chrono::steady_clock::now();
+}
+
static std::string dump_pollfds(const std::vector<adb_pollfd>& pollfds) {
std::string result;
for (const auto& pollfd : pollfds) {
@@ -248,6 +257,32 @@
return result;
}
+static std::optional<std::chrono::milliseconds> calculate_timeout() {
+ std::optional<std::chrono::milliseconds> result = std::nullopt;
+ auto now = std::chrono::steady_clock::now();
+ check_main_thread();
+
+ for (const auto& [fd, pollnode] : g_poll_node_map) {
+ UNUSED(fd);
+ auto timeout_opt = pollnode.fde->timeout;
+ if (timeout_opt) {
+ auto deadline = pollnode.fde->last_active + *timeout_opt;
+ auto time_left = std::chrono::duration_cast<std::chrono::milliseconds>(deadline - now);
+ if (time_left < std::chrono::milliseconds::zero()) {
+ time_left = std::chrono::milliseconds::zero();
+ }
+
+ if (!result) {
+ result = time_left;
+ } else {
+ result = std::min(*result, time_left);
+ }
+ }
+ }
+
+ return result;
+}
+
static void fdevent_process() {
std::vector<adb_pollfd> pollfds;
for (const auto& pair : g_poll_node_map) {
@@ -256,11 +291,22 @@
CHECK_GT(pollfds.size(), 0u);
D("poll(), pollfds = %s", dump_pollfds(pollfds).c_str());
- int ret = adb_poll(&pollfds[0], pollfds.size(), -1);
+ auto timeout = calculate_timeout();
+ int timeout_ms;
+ if (!timeout) {
+ timeout_ms = -1;
+ } else {
+ timeout_ms = timeout->count();
+ }
+
+ int ret = adb_poll(&pollfds[0], pollfds.size(), timeout_ms);
if (ret == -1) {
PLOG(ERROR) << "poll(), ret = " << ret;
return;
}
+
+ auto post_poll = std::chrono::steady_clock::now();
+
for (const auto& pollfd : pollfds) {
if (pollfd.revents != 0) {
D("for fd %d, revents = %x", pollfd.fd, pollfd.revents);
@@ -282,12 +328,24 @@
events |= FDE_READ | FDE_ERROR;
}
#endif
+ auto it = g_poll_node_map.find(pollfd.fd);
+ CHECK(it != g_poll_node_map.end());
+ fdevent* fde = it->second.fde;
+
+ if (events == 0) {
+ // Check for timeout.
+ if (fde->timeout) {
+ auto deadline = fde->last_active + *fde->timeout;
+ if (deadline < post_poll) {
+ events |= FDE_TIMEOUT;
+ }
+ }
+ }
+
if (events != 0) {
- auto it = g_poll_node_map.find(pollfd.fd);
- CHECK(it != g_poll_node_map.end());
- fdevent* fde = it->second.fde;
CHECK_EQ(fde->fd.get(), pollfd.fd);
fde->events |= events;
+ fde->last_active = post_poll;
D("%s got events %x", dump_fde(fde).c_str(), events);
fde->state |= FDE_PENDING;
g_pending_list.push_back(fde);
diff --git a/adb/fdevent.h b/adb/fdevent.h
index 70e0a96..42dbb9e 100644
--- a/adb/fdevent.h
+++ b/adb/fdevent.h
@@ -18,17 +18,20 @@
#define __FDEVENT_H
#include <stddef.h>
-#include <stdint.h> /* for int64_t */
+#include <stdint.h>
+#include <chrono>
#include <functional>
+#include <optional>
#include <variant>
#include "adb_unique_fd.h"
-/* events that may be observed */
-#define FDE_READ 0x0001
-#define FDE_WRITE 0x0002
-#define FDE_ERROR 0x0004
+// Events that may be observed
+#define FDE_READ 0x0001
+#define FDE_WRITE 0x0002
+#define FDE_ERROR 0x0004
+#define FDE_TIMEOUT 0x0008
typedef void (*fd_func)(int fd, unsigned events, void *userdata);
typedef void (*fd_func2)(struct fdevent* fde, unsigned events, void* userdata);
@@ -41,6 +44,8 @@
uint16_t state = 0;
uint16_t events = 0;
+ std::optional<std::chrono::milliseconds> timeout;
+ std::chrono::steady_clock::time_point last_active;
std::variant<fd_func, fd_func2> func;
void* arg = nullptr;
@@ -62,7 +67,11 @@
void fdevent_add(fdevent *fde, unsigned events);
void fdevent_del(fdevent *fde, unsigned events);
-void fdevent_set_timeout(fdevent *fde, int64_t timeout_ms);
+// Set a timeout on an fdevent.
+// If no events are triggered by the timeout, an FDE_TIMEOUT will be generated.
+// Note timeouts are not defused automatically; if a timeout is set on an fdevent, it will
+// trigger repeatedly every |timeout| ms.
+void fdevent_set_timeout(fdevent* fde, std::optional<std::chrono::milliseconds> timeout);
// Loop forever, handling events.
void fdevent_loop();
diff --git a/adb/fdevent_test.cpp b/adb/fdevent_test.cpp
index a9746bb..682f061 100644
--- a/adb/fdevent_test.cpp
+++ b/adb/fdevent_test.cpp
@@ -18,6 +18,7 @@
#include <gtest/gtest.h>
+#include <chrono>
#include <limits>
#include <memory>
#include <queue>
@@ -28,6 +29,8 @@
#include "adb_io.h"
#include "fdevent_test.h"
+using namespace std::chrono_literals;
+
class FdHandler {
public:
FdHandler(int read_fd, int write_fd, bool use_new_callback)
@@ -257,3 +260,100 @@
ASSERT_EQ(i, vec[i]);
}
}
+
+TEST_F(FdeventTest, timeout) {
+ fdevent_reset();
+ PrepareThread();
+
+ enum class TimeoutEvent {
+ read,
+ timeout,
+ done,
+ };
+
+ struct TimeoutTest {
+ std::vector<std::pair<TimeoutEvent, std::chrono::steady_clock::time_point>> events;
+ fdevent* fde;
+ };
+ TimeoutTest test;
+
+ int fds[2];
+ ASSERT_EQ(0, adb_socketpair(fds));
+ static constexpr auto delta = 100ms;
+ fdevent_run_on_main_thread([&]() {
+ test.fde = fdevent_create(fds[0], [](fdevent* fde, unsigned events, void* arg) {
+ auto test = static_cast<TimeoutTest*>(arg);
+ auto now = std::chrono::steady_clock::now();
+ CHECK((events & FDE_READ) ^ (events & FDE_TIMEOUT));
+ TimeoutEvent event;
+ if ((events & FDE_READ)) {
+ char buf[2];
+ ssize_t rc = adb_read(fde->fd.get(), buf, sizeof(buf));
+ if (rc == 0) {
+ event = TimeoutEvent::done;
+ } else if (rc == 1) {
+ event = TimeoutEvent::read;
+ } else {
+ abort();
+ }
+ } else if ((events & FDE_TIMEOUT)) {
+ event = TimeoutEvent::timeout;
+ } else {
+ abort();
+ }
+
+ CHECK_EQ(fde, test->fde);
+ test->events.emplace_back(event, now);
+
+ if (event == TimeoutEvent::done) {
+ fdevent_destroy(fde);
+ }
+ }, &test);
+ fdevent_add(test.fde, FDE_READ);
+ fdevent_set_timeout(test.fde, delta);
+ });
+
+ ASSERT_EQ(1, adb_write(fds[1], "", 1));
+
+ // Timeout should happen here
+ std::this_thread::sleep_for(delta);
+
+ // and another.
+ std::this_thread::sleep_for(delta);
+
+ // No timeout should happen here.
+ std::this_thread::sleep_for(delta / 2);
+ adb_close(fds[1]);
+
+ TerminateThread();
+
+ ASSERT_EQ(4ULL, test.events.size());
+ ASSERT_EQ(TimeoutEvent::read, test.events[0].first);
+ ASSERT_EQ(TimeoutEvent::timeout, test.events[1].first);
+ ASSERT_EQ(TimeoutEvent::timeout, test.events[2].first);
+ ASSERT_EQ(TimeoutEvent::done, test.events[3].first);
+
+ std::vector<int> time_deltas;
+ for (size_t i = 0; i < test.events.size() - 1; ++i) {
+ auto before = test.events[i].second;
+ auto after = test.events[i + 1].second;
+ auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(after - before);
+ time_deltas.push_back(diff.count());
+ }
+
+ std::vector<int> expected = {
+ delta.count(),
+ delta.count(),
+ delta.count() / 2,
+ };
+
+ std::vector<int> diff;
+ ASSERT_EQ(time_deltas.size(), expected.size());
+ for (size_t i = 0; i < time_deltas.size(); ++i) {
+ diff.push_back(std::abs(time_deltas[i] - expected[i]));
+ }
+
+ ASSERT_LT(diff[0], delta.count() * 0.5);
+ ASSERT_LT(diff[1], delta.count() * 0.5);
+ ASSERT_LT(diff[2], delta.count() * 0.5);
+}
diff --git a/adb/socket_test.cpp b/adb/socket_test.cpp
index 7908f82..5e28f76 100644
--- a/adb/socket_test.cpp
+++ b/adb/socket_test.cpp
@@ -221,6 +221,8 @@
EXPECT_EQ(2u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
ASSERT_EQ(0, adb_close(socket_fd[0]));
+ std::this_thread::sleep_for(2s);
+
WaitForFdeventLoop();
ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
TerminateThread();
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index f7c39f0..420a6d5 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -26,6 +26,7 @@
#include <unistd.h>
#include <algorithm>
+#include <chrono>
#include <mutex>
#include <string>
#include <vector>
@@ -41,6 +42,8 @@
#include "transport.h"
#include "types.h"
+using namespace std::chrono_literals;
+
static std::recursive_mutex& local_socket_list_lock = *new std::recursive_mutex();
static unsigned local_socket_next_id = 1;
@@ -238,16 +241,64 @@
fdevent_add(s->fde, FDE_READ);
}
+struct ClosingSocket {
+ std::chrono::steady_clock::time_point begin;
+};
+
+// The standard (RFC 1122 - 4.2.2.13) says that if we call close on a
+// socket while we have pending data, a TCP RST should be sent to the
+// other end to notify it that we didn't read all of its data. However,
+// this can result in data that we've successfully written out to be dropped
+// on the other end. To avoid this, instead of immediately closing a
+// socket, call shutdown on it instead, and then read from the file
+// descriptor until we hit EOF or an error before closing.
+static void deferred_close(unique_fd fd) {
+ // Shutdown the socket in the outgoing direction only, so that
+ // we don't have the same problem on the opposite end.
+ adb_shutdown(fd.get(), SHUT_WR);
+ auto callback = [](fdevent* fde, unsigned event, void* arg) {
+ auto socket_info = static_cast<ClosingSocket*>(arg);
+ if (event & FDE_READ) {
+ ssize_t rc;
+ char buf[BUFSIZ];
+ while ((rc = adb_read(fde->fd.get(), buf, sizeof(buf))) > 0) {
+ continue;
+ }
+
+ if (rc == -1 && errno == EAGAIN) {
+ // There's potentially more data to read.
+ auto duration = std::chrono::steady_clock::now() - socket_info->begin;
+ if (duration > 1s) {
+ LOG(WARNING) << "timeout expired while flushing socket, closing";
+ } else {
+ return;
+ }
+ }
+ } else if (event & FDE_TIMEOUT) {
+ LOG(WARNING) << "timeout expired while flushing socket, closing";
+ }
+
+ // Either there was an error, we hit the end of the socket, or our timeout expired.
+ fdevent_destroy(fde);
+ delete socket_info;
+ };
+
+ ClosingSocket* socket_info = new ClosingSocket{
+ .begin = std::chrono::steady_clock::now(),
+ };
+
+ fdevent* fde = fdevent_create(fd.release(), callback, socket_info);
+ fdevent_add(fde, FDE_READ);
+ fdevent_set_timeout(fde, 1s);
+}
+
// be sure to hold the socket list lock when calling this
static void local_socket_destroy(asocket* s) {
int exit_on_close = s->exit_on_close;
D("LS(%d): destroying fde.fd=%d", s->id, s->fd);
- /* IMPORTANT: the remove closes the fd
- ** that belongs to this socket
- */
- fdevent_destroy(s->fde);
+ deferred_close(fdevent_release(s->fde));
remove_socket(s);
delete s;
diff --git a/adb/sysdeps/chrono.h b/adb/sysdeps/chrono.h
index c73a638..5c5af7c 100644
--- a/adb/sysdeps/chrono.h
+++ b/adb/sysdeps/chrono.h
@@ -18,29 +18,4 @@
#include <chrono>
-#if defined(_WIN32)
-// We don't have C++14 on Windows yet.
-// Reimplement std::chrono_literals ourselves until we do.
-
-// Silence the following warning (which gets promoted to an error):
-// error: literal operator suffixes not preceded by ‘_’ are reserved for future standardization
-#pragma GCC system_header
-
-constexpr std::chrono::seconds operator"" s(unsigned long long s) {
- return std::chrono::seconds(s);
-}
-
-constexpr std::chrono::duration<long double> operator"" s(long double s) {
- return std::chrono::duration<long double>(s);
-}
-
-constexpr std::chrono::milliseconds operator"" ms(unsigned long long ms) {
- return std::chrono::milliseconds(ms);
-}
-
-constexpr std::chrono::duration<long double, std::milli> operator"" ms(long double ms) {
- return std::chrono::duration<long double, std::milli>(ms);
-}
-#else
using namespace std::chrono_literals;
-#endif
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index d587589..4c5d8cb 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -356,6 +356,9 @@
DWORD desiredAccess = 0;
DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ // CreateFileW is inherently O_CLOEXEC by default.
+ options &= ~O_CLOEXEC;
+
switch (options) {
case O_RDONLY:
desiredAccess = GENERIC_READ;
diff --git a/adb/test_adb.py b/adb/test_adb.py
index 430fc3d..14e5071 100755
--- a/adb/test_adb.py
+++ b/adb/test_adb.py
@@ -422,6 +422,9 @@
with fake_adbd() as (port, _):
serial = "localhost:{}".format(port)
with adb_connect(self, serial):
+ # Wait a bit to give adb some time to connect.
+ time.sleep(0.25)
+
output = subprocess.check_output(["adb", "-s", serial,
"get-state"])
self.assertEqual(output.strip(), b"device")
diff --git a/adb/test_device.py b/adb/test_device.py
index 34f8fd9..f95a5b3 100755
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -35,6 +35,8 @@
import time
import unittest
+from datetime import datetime
+
import adb
def requires_root(func):
@@ -1335,6 +1337,63 @@
self.device.forward_remove("tcp:{}".format(local_port))
+class SocketTest(DeviceTest):
+ def test_socket_flush(self):
+ """Test that we handle socket closure properly.
+
+ If we're done writing to a socket, closing before the other end has
+ closed will send a TCP_RST if we have incoming data queued up, which
+ may result in data that we've written being discarded.
+
+ Bug: http://b/74616284
+ """
+ s = socket.create_connection(("localhost", 5037))
+
+ def adb_length_prefixed(string):
+ encoded = string.encode("utf8")
+ result = b"%04x%s" % (len(encoded), encoded)
+ return result
+
+ if "ANDROID_SERIAL" in os.environ:
+ transport_string = "host:transport:" + os.environ["ANDROID_SERIAL"]
+ else:
+ transport_string = "host:transport-any"
+
+ s.sendall(adb_length_prefixed(transport_string))
+ response = s.recv(4)
+ self.assertEquals(b"OKAY", response)
+
+ shell_string = "shell:sleep 0.5; dd if=/dev/zero bs=1m count=1 status=none; echo foo"
+ s.sendall(adb_length_prefixed(shell_string))
+
+ response = s.recv(4)
+ self.assertEquals(b"OKAY", response)
+
+ # Spawn a thread that dumps garbage into the socket until failure.
+ def spam():
+ buf = b"\0" * 16384
+ try:
+ while True:
+ s.sendall(buf)
+ except Exception as ex:
+ print(ex)
+
+ thread = threading.Thread(target=spam)
+ thread.start()
+
+ time.sleep(1)
+
+ received = b""
+ while True:
+ read = s.recv(512)
+ if len(read) == 0:
+ break
+ received += read
+
+ self.assertEquals(1024 * 1024 + len("foo\n"), len(received))
+ thread.join()
+
+
if sys.platform == "win32":
# From https://stackoverflow.com/a/38749458
import os
diff --git a/base/mapped_file.cpp b/base/mapped_file.cpp
index f7901af..faa845d 100644
--- a/base/mapped_file.cpp
+++ b/base/mapped_file.cpp
@@ -16,6 +16,8 @@
#include "android-base/mapped_file.h"
+#include <errno.h>
+
namespace android {
namespace base {
@@ -50,7 +52,14 @@
new MappedFile{static_cast<char*>(base), length, slop, handle});
#else
void* base = mmap(nullptr, file_length, prot, MAP_SHARED, fd, file_offset);
- if (base == MAP_FAILED) return nullptr;
+ if (base == MAP_FAILED) {
+ // http://b/119818070 "app crashes when reading asset of zero length".
+ // mmap fails with EINVAL for a zero length region.
+ if (errno == EINVAL && length == 0) {
+ return std::unique_ptr<MappedFile>(new MappedFile{nullptr, 0, 0});
+ }
+ return nullptr;
+ }
return std::unique_ptr<MappedFile>(new MappedFile{static_cast<char*>(base), length, slop});
#endif
}
diff --git a/base/mapped_file_test.cpp b/base/mapped_file_test.cpp
index 7e89723..cfde73c 100644
--- a/base/mapped_file_test.cpp
+++ b/base/mapped_file_test.cpp
@@ -25,7 +25,6 @@
#include <string>
#include "android-base/file.h"
-#include "android-base/unique_fd.h"
TEST(mapped_file, smoke) {
TemporaryFile tf;
@@ -37,3 +36,13 @@
ASSERT_EQ('l', m->data()[0]);
ASSERT_EQ('o', m->data()[1]);
}
+
+TEST(mapped_file, zero_length_mapping) {
+ // http://b/119818070 "app crashes when reading asset of zero length".
+ // mmap fails with EINVAL for a zero length region.
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ auto m = android::base::MappedFile::FromFd(tf.fd, 4096, 0, PROT_READ);
+ ASSERT_EQ(0u, m->size());
+}
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 6700b6c..ed955ea 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -114,25 +114,6 @@
return cmd;
}
-// Convenience wrapper over the property API that returns an
-// std::string.
-std::string GetProperty(const char* key) {
- std::vector<char> temp(PROPERTY_VALUE_MAX);
- const int len = property_get(key, &temp[0], nullptr);
- if (len < 0) {
- return "";
- }
- return std::string(&temp[0], len);
-}
-
-bool SetProperty(const char* key, const std::string& val) {
- return property_set(key, val.c_str()) == 0;
-}
-
-bool SetProperty(const char* key, const char* val) {
- return property_set(key, val) == 0;
-}
-
constexpr int32_t kEmptyBootReason = 0;
constexpr int32_t kUnknownBootReason = 1;
@@ -746,11 +727,13 @@
void BootReasonAddToHistory(const std::string& system_boot_reason) {
if (system_boot_reason.empty()) return;
LOG(INFO) << "Canonical boot reason: " << system_boot_reason;
- auto old_system_boot_reason = GetProperty(system_reboot_reason_property);
- if (!SetProperty(system_reboot_reason_property, system_boot_reason)) {
- SetProperty(system_reboot_reason_property, system_boot_reason.substr(0, PROPERTY_VALUE_MAX - 1));
+ auto old_system_boot_reason = android::base::GetProperty(system_reboot_reason_property, "");
+ if (!android::base::SetProperty(system_reboot_reason_property, system_boot_reason)) {
+ android::base::SetProperty(system_reboot_reason_property,
+ system_boot_reason.substr(0, PROPERTY_VALUE_MAX - 1));
}
- auto reason_history = android::base::Split(GetProperty(history_reboot_reason_property), "\n");
+ auto reason_history =
+ android::base::Split(android::base::GetProperty(history_reboot_reason_property, ""), "\n");
static auto mark = time(nullptr);
auto mark_str = std::string(",") + std::to_string(mark);
auto marked_system_boot_reason = system_boot_reason + mark_str;
@@ -773,7 +756,8 @@
reason_history.insert(reason_history.begin(), marked_system_boot_reason);
// If the property string is too long ( > PROPERTY_VALUE_MAX)
// we get an error, so trim out last entry and try again.
- while (!(SetProperty(history_reboot_reason_property, android::base::Join(reason_history, '\n')))) {
+ while (!android::base::SetProperty(history_reboot_reason_property,
+ android::base::Join(reason_history, '\n'))) {
auto it = std::prev(reason_history.end());
if (it == reason_history.end()) break;
reason_history.erase(it);
@@ -782,7 +766,7 @@
// Scrub, Sanitize, Standardize and Enhance the boot reason string supplied.
std::string BootReasonStrToReason(const std::string& boot_reason) {
- std::string ret(GetProperty(system_reboot_reason_property));
+ auto ret = android::base::GetProperty(system_reboot_reason_property, "");
std::string reason(boot_reason);
// If sys.boot.reason == ro.boot.bootreason, let's re-evaluate
if (reason == ret) ret = "";
@@ -922,7 +906,7 @@
if (isBluntRebootReason(ret)) {
// Content buffer no longer will have console data. Beware if more
// checks added below, that depend on parsing console content.
- content = GetProperty(last_reboot_reason_property);
+ content = android::base::GetProperty(last_reboot_reason_property, "");
transformReason(content);
// Anything in last is better than 'super-blunt' reboot or shutdown.
@@ -966,7 +950,7 @@
static const std::string kBuildDateKey = "build_date";
std::string boot_complete_prefix = "boot_complete";
- std::string build_date_str = GetProperty("ro.build.date.utc");
+ auto build_date_str = android::base::GetProperty("ro.build.date.utc", "");
int32_t build_date;
if (!android::base::ParseInt(build_date_str, &build_date)) {
return std::string();
@@ -989,7 +973,7 @@
// Records the value of a given ro.boottime.init property in milliseconds.
void RecordInitBootTimeProp(BootEventRecordStore* boot_event_store, const char* property) {
- std::string value = GetProperty(property);
+ auto value = android::base::GetProperty(property, "");
int32_t time_in_ms;
if (android::base::ParseInt(value, &time_in_ms)) {
@@ -1007,7 +991,7 @@
// |ro.boot.boottime| is of the form 'stage1:time1,...,stageN:timeN',
// where timeN is in milliseconds.
- std::string value = GetProperty("ro.boot.boottime");
+ auto value = android::base::GetProperty("ro.boot.boottime", "");
if (value.empty()) {
// ro.boot.boottime is not reported on all devices.
return BootloaderTimingMap();
@@ -1019,6 +1003,7 @@
auto stageTimingValues = android::base::Split(stageTiming, ":");
DCHECK_EQ(2U, stageTimingValues.size());
+ if (stageTimingValues.size() < 2) continue;
std::string stageName = stageTimingValues[0];
int32_t time_ms;
if (android::base::ParseInt(stageTimingValues[1], &time_ms)) {
@@ -1080,7 +1065,7 @@
void LogBootInfoToStatsd(std::chrono::milliseconds end_time,
std::chrono::milliseconds total_duration, int32_t bootloader_duration_ms,
double time_since_last_boot_sec) {
- const std::string reason(GetProperty(bootloader_reboot_reason_property));
+ const auto reason = android::base::GetProperty(bootloader_reboot_reason_property, "");
if (reason.empty()) {
android::util::stats_write(android::util::BOOT_SEQUENCE_REPORTED, "<EMPTY>", "<EMPTY>",
@@ -1090,7 +1075,7 @@
return;
}
- const std::string system_reason(GetProperty(system_reboot_reason_property));
+ const auto system_reason = android::base::GetProperty(system_reboot_reason_property, "");
android::util::stats_write(android::util::BOOT_SEQUENCE_REPORTED, reason.c_str(),
system_reason.c_str(), end_time.count(), total_duration.count(),
(int64_t)bootloader_duration_ms,
@@ -1098,19 +1083,20 @@
}
void SetSystemBootReason() {
- const std::string bootloader_boot_reason(GetProperty(bootloader_reboot_reason_property));
+ const auto bootloader_boot_reason =
+ android::base::GetProperty(bootloader_reboot_reason_property, "");
const std::string system_boot_reason(BootReasonStrToReason(bootloader_boot_reason));
// Record the scrubbed system_boot_reason to the property
BootReasonAddToHistory(system_boot_reason);
// Shift last_reboot_reason_property to last_last_reboot_reason_property
- std::string last_boot_reason(GetProperty(last_reboot_reason_property));
+ auto last_boot_reason = android::base::GetProperty(last_reboot_reason_property, "");
if (last_boot_reason.empty() || isKernelRebootReason(system_boot_reason)) {
last_boot_reason = system_boot_reason;
} else {
transformReason(last_boot_reason);
}
- SetProperty(last_last_reboot_reason_property, last_boot_reason);
- SetProperty(last_reboot_reason_property, "");
+ android::base::SetProperty(last_last_reboot_reason_property, last_boot_reason);
+ android::base::SetProperty(last_reboot_reason_property, "");
}
// Gets the boot time offset. This is useful when Android is running in a
@@ -1197,7 +1183,7 @@
// Records the boot_reason metric by querying the ro.boot.bootreason system
// property.
void RecordBootReason() {
- const std::string reason(GetProperty(bootloader_reboot_reason_property));
+ const auto reason = android::base::GetProperty(bootloader_reboot_reason_property, "");
if (reason.empty()) {
// Log an empty boot reason value as '<EMPTY>' to ensure the value is intentional
@@ -1215,12 +1201,12 @@
boot_event_store.AddBootEventWithValue("boot_reason", boot_reason);
// Log the scrubbed system_boot_reason.
- const std::string system_reason(GetProperty(system_reboot_reason_property));
+ const auto system_reason = android::base::GetProperty(system_reboot_reason_property, "");
int32_t system_boot_reason = BootReasonStrToEnum(system_reason);
boot_event_store.AddBootEventWithValue("system_boot_reason", system_boot_reason);
if (reason == "") {
- SetProperty(bootloader_reboot_reason_property, system_reason);
+ android::base::SetProperty(bootloader_reboot_reason_property, system_reason);
}
}
diff --git a/bootstat/bootstat.rc b/bootstat/bootstat.rc
index 1300a27..85caf25 100644
--- a/bootstat/bootstat.rc
+++ b/bootstat/bootstat.rc
@@ -1,7 +1,9 @@
# This file is the LOCAL_INIT_RC file for the bootstat command.
-# mirror bootloader boot reason to system boot reason
-on property:ro.boot.bootreason=*
+# Mirror bootloader boot reason to system boot reason
+# ro.boot.bootreason should be set by init already
+# before post-fs trigger
+on post-fs && property:ro.boot.bootreason=*
setprop sys.boot.reason ${ro.boot.bootreason}
on post-fs-data
@@ -66,11 +68,16 @@
on property:init.svc.zygote=stopping
setprop sys.logbootcomplete 0
+# Set boot reason
+on zygote-start
+ # Converts bootloader boot reason and persist.sys.boot.reason to system boot reason
+ # Need go after persist peroperties are loaded which is right before zygote-start trigger
+ exec_background - system log -- /system/bin/bootstat --set_system_boot_reason
+
# Record boot complete metrics.
on property:sys.boot_completed=1 && property:sys.logbootcomplete=1
- # Converts bootloader boot reason to system boot reason
# Record boot_complete and related stats (decryption, etc).
# Record the boot reason.
# Record time since factory reset.
# Log all boot events.
- exec_background - system log -- /system/bin/bootstat --set_system_boot_reason --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l
+ exec_background - system log -- /system/bin/bootstat --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l
diff --git a/fs_mgr/README.overlayfs.md b/fs_mgr/README.overlayfs.md
index 8784c94..2aac260 100644
--- a/fs_mgr/README.overlayfs.md
+++ b/fs_mgr/README.overlayfs.md
@@ -74,7 +74,7 @@
When *overlayfs* logic is feasible, it will use either the
**/cache/overlay/** directory for non-A/B devices, or the
**/mnt/scratch/overlay** directory for A/B devices that have
-access to *Logical Resizeable Android Partitions*.
+access to *Logical Resizable Android Partitions*.
The backing store is used as soon as possible in the boot
process and can occur at first stage init, or at the
mount_all init rc commands.
@@ -94,12 +94,17 @@
and thus free dynamic partition space.
- Kernel must have CONFIG_OVERLAY_FS=y and will need to be patched
with "*overlayfs: override_creds=off option bypass creator_cred*"
- if higher than 4.6.
+ if kernel is higher than 4.6.
+ The patch is available on the upstream mailing list and the latest as of
+ Feb 8 2019 is https://lore.kernel.org/patchwork/patch/1009299/.
+ This patch adds an override_creds _mount_ option to overlayfs that
+ permits legacy behavior for systems that do not have overlapping
+ sepolicy rules, principals of least privilege, which is how Android behaves.
- *adb enable-verity* will free up overlayfs and as a bonus the
device will be reverted pristine to before any content was updated.
Update engine does not take advantage of this, will perform a full OTA.
- Update engine may not run if *fs_mgr_overlayfs_is_setup*() reports
- true as adb remount overrides are incompatable with an OTA resources.
+ true as adb remount overrides are incompatible with an OTA resources.
- For implementation simplicity on retrofit dynamic partition devices,
take the whole alternate super (eg: if "*a*" slot, then the whole of
"*system_b*").
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index e5caf3a..e684293 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -378,7 +378,7 @@
// Set the number of reserved filesystem blocks if needed.
static void tune_reserved_size(const std::string& blk_device, const FstabEntry& entry,
const struct ext4_super_block* sb, int* fs_stat) {
- if (!entry.fs_mgr_flags.reserved_size) {
+ if (entry.reserved_size != 0) {
return;
}
@@ -551,7 +551,7 @@
}
if (is_extfs(entry.fs_type) &&
- (entry.fs_mgr_flags.reserved_size || entry.fs_mgr_flags.file_encryption ||
+ (entry.reserved_size != 0 || entry.fs_mgr_flags.file_encryption ||
entry.fs_mgr_flags.fs_verity)) {
struct ext4_super_block sb;
@@ -806,7 +806,7 @@
}
static bool should_use_metadata_encryption(const FstabEntry& entry) {
- return entry.fs_mgr_flags.key_directory &&
+ return !entry.key_dir.empty() &&
(entry.fs_mgr_flags.file_encryption || entry.fs_mgr_flags.force_fde_or_fbe);
}
@@ -1374,18 +1374,6 @@
return FS_MGR_DOMNT_FAILED;
}
-int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point) {
- auto new_fstab = LegacyFstabToFstab(fstab);
- return fs_mgr_do_mount_helper(&new_fstab, n_name, n_blk_device, tmp_mount_point, -1);
-}
-
-int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point,
- bool needs_checkpoint) {
- auto new_fstab = LegacyFstabToFstab(fstab);
- return fs_mgr_do_mount_helper(&new_fstab, n_name, n_blk_device, tmp_mount_point,
- needs_checkpoint);
-}
-
int fs_mgr_do_mount(Fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point) {
return fs_mgr_do_mount_helper(fstab, n_name, n_blk_device, tmp_mount_point, -1);
}
@@ -1444,7 +1432,7 @@
}
// Prepare target path
- unique_fd target_fd(TEMP_FAILURE_RETRY(open(loop.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0664)));
+ unique_fd target_fd(TEMP_FAILURE_RETRY(open(loop.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0600)));
if (target_fd.get() == -1) {
PERROR << "Cannot open target path: " << loop;
return false;
@@ -1556,48 +1544,6 @@
return ret;
}
-struct fstab_rec const* fs_mgr_get_crypt_entry(fstab const* fstab) {
- int i;
-
- if (!fstab) {
- return NULL;
- }
-
- /* Look for the encryptable partition to find the data */
- for (i = 0; i < fstab->num_entries; i++) {
- /* Don't deal with vold managed enryptable partitions here */
- if (!(fstab->recs[i].fs_mgr_flags & MF_VOLDMANAGED) &&
- (fstab->recs[i].fs_mgr_flags &
- (MF_CRYPT | MF_FORCECRYPT | MF_FORCEFDEORFBE | MF_FILEENCRYPTION))) {
- return &fstab->recs[i];
- }
- }
- return NULL;
-}
-
-/*
- * key_loc must be at least PROPERTY_VALUE_MAX bytes long
- *
- * real_blk_device must be at least PROPERTY_VALUE_MAX bytes long
- */
-void fs_mgr_get_crypt_info(fstab* fstab, char* key_loc, char* real_blk_device, size_t size) {
- struct fstab_rec const* rec = fs_mgr_get_crypt_entry(fstab);
- if (key_loc) {
- if (rec) {
- strlcpy(key_loc, rec->key_loc, size);
- } else {
- *key_loc = '\0';
- }
- }
- if (real_blk_device) {
- if (rec) {
- strlcpy(real_blk_device, rec->blk_device, size);
- } else {
- *real_blk_device = '\0';
- }
- }
-}
-
bool fs_mgr_load_verity_state(int* mode) {
/* return the default mode, unless any of the verified partitions are in
* logging mode, in which case return that */
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index ee88e0d..4d44fcf 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -175,8 +175,8 @@
}
void ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) {
- entry->fs_mgr_flags.val = 0U;
for (const auto& flag : Split(flags, ",")) {
+ if (flag.empty() || flag == "defaults") continue;
std::string arg;
if (auto equal_sign = flag.find('='); equal_sign != std::string::npos) {
arg = flag.substr(equal_sign + 1);
@@ -239,18 +239,14 @@
}
} else if (StartsWith(flag, "length=")) {
// The length flag is followed by an = and the size of the partition.
- entry->fs_mgr_flags.length = true;
if (!ParseInt(arg, &entry->length)) {
LWARNING << "Warning: length= flag malformed: " << arg;
}
} else if (StartsWith(flag, "swapprio=")) {
- entry->fs_mgr_flags.swap_prio = true;
if (!ParseInt(arg, &entry->swap_prio)) {
LWARNING << "Warning: length= flag malformed: " << arg;
}
} else if (StartsWith(flag, "zramsize=")) {
- entry->fs_mgr_flags.zram_size = true;
-
if (!arg.empty() && arg.back() == '%') {
arg.pop_back();
int val;
@@ -282,13 +278,11 @@
entry->file_contents_mode = "aes-256-xts";
entry->file_names_mode = "aes-256-cts";
} else if (StartsWith(flag, "max_comp_streams=")) {
- entry->fs_mgr_flags.max_comp_streams = true;
if (!ParseInt(arg, &entry->max_comp_streams)) {
LWARNING << "Warning: max_comp_streams= flag malformed: " << arg;
}
} else if (StartsWith(flag, "reservedsize=")) {
// The reserved flag is followed by an = and the reserved size of the partition.
- entry->fs_mgr_flags.reserved_size = true;
uint64_t size;
if (!ParseByteCount(arg, &size)) {
LWARNING << "Warning: reservedsize= flag malformed: " << arg;
@@ -298,7 +292,6 @@
} else if (StartsWith(flag, "eraseblk=")) {
// The erase block size flag is followed by an = and the flash erase block size. Get it,
// check that it is a power of 2 and at least 4096, and return it.
- entry->fs_mgr_flags.erase_blk_size = true;
off64_t val;
if (!ParseInt(arg, &val) || val < 4096 || (val & (val - 1)) != 0) {
LWARNING << "Warning: eraseblk= flag malformed: " << arg;
@@ -308,7 +301,6 @@
} else if (StartsWith(flag, "logicalblk=")) {
// The logical block size flag is followed by an = and the flash logical block size. Get
// it, check that it is a power of 2 and at least 4096, and return it.
- entry->fs_mgr_flags.logical_blk_size = true;
off64_t val;
if (!ParseInt(arg, &val) || val < 4096 || (val & (val - 1)) != 0) {
LWARNING << "Warning: logicalblk= flag malformed: " << arg;
@@ -320,23 +312,18 @@
entry->vbmeta_partition = arg;
} else if (StartsWith(flag, "keydirectory=")) {
// The metadata flag is followed by an = and the directory for the keys.
- entry->fs_mgr_flags.key_directory = true;
entry->key_dir = arg;
} else if (StartsWith(flag, "sysfs_path=")) {
// The path to trigger device gc by idle-maint of vold.
- entry->fs_mgr_flags.sysfs = true;
entry->sysfs_path = arg;
} else if (StartsWith(flag, "zram_loopback_path=")) {
// The path to use loopback for zram.
- entry->fs_mgr_flags.zram_loopback_path = true;
entry->zram_loopback_path = arg;
} else if (StartsWith(flag, "zram_loopback_size=")) {
- entry->fs_mgr_flags.zram_loopback_size = true;
if (!ParseByteCount(arg, &entry->zram_loopback_size)) {
LWARNING << "Warning: zram_loopback_size= flag malformed: " << arg;
}
} else if (StartsWith(flag, "zram_backing_dev_path=")) {
- entry->fs_mgr_flags.zram_backing_dev_path = true;
entry->zram_backing_dev_path = arg;
} else if (StartsWith(flag, "avb_key=")) {
entry->avb_key = arg;
@@ -778,214 +765,3 @@
return false;
}
-
-// Everything from here down is deprecated and will be removed shortly.
-
-using android::fs_mgr::Fstab;
-using android::fs_mgr::FstabEntry;
-using android::fs_mgr::ReadDefaultFstab;
-using android::fs_mgr::ReadFstabFromFile;
-
-struct fstab* fs_mgr_read_fstab(const char* fstab_path) {
- Fstab fstab;
- if (!ReadFstabFromFile(fstab_path, &fstab)) {
- return nullptr;
- }
-
- return FstabToLegacyFstab(fstab);
-}
-
-struct fstab* fs_mgr_read_fstab_default() {
- Fstab fstab;
- if (!ReadDefaultFstab(&fstab)) {
- return nullptr;
- }
-
- return FstabToLegacyFstab(fstab);
-}
-
-void fs_mgr_free_fstab(struct fstab *fstab)
-{
- int i;
-
- if (!fstab) {
- return;
- }
-
- for (i = 0; i < fstab->num_entries; i++) {
- /* Free the pointers return by strdup(3) */
- free(fstab->recs[i].blk_device);
- free(fstab->recs[i].logical_partition_name);
- free(fstab->recs[i].mount_point);
- free(fstab->recs[i].fs_type);
- free(fstab->recs[i].fs_options);
- free(fstab->recs[i].key_loc);
- free(fstab->recs[i].key_dir);
- free(fstab->recs[i].label);
- free(fstab->recs[i].file_contents_mode);
- free(fstab->recs[i].file_names_mode);
- free(fstab->recs[i].sysfs_path);
- free(fstab->recs[i].zram_loopback_path);
- free(fstab->recs[i].zram_backing_dev_path);
- }
-
- /* Free the fstab_recs array created by calloc(3) */
- free(fstab->recs);
-
- /* Free fstab */
- free(fstab);
-}
-
-struct fstab_rec* fs_mgr_get_entry_for_mount_point(struct fstab* fstab, const std::string& path) {
- if (!fstab) {
- return nullptr;
- }
- for (int i = 0; i < fstab->num_entries; i++) {
- if (fstab->recs[i].mount_point && path == fstab->recs[i].mount_point) {
- return &fstab->recs[i];
- }
- }
- return nullptr;
-}
-
-FstabEntry FstabRecToFstabEntry(const fstab_rec* fstab_rec) {
- FstabEntry entry;
- entry.blk_device = fstab_rec->blk_device;
- entry.logical_partition_name = fstab_rec->logical_partition_name;
- entry.mount_point = fstab_rec->mount_point;
- entry.fs_type = fstab_rec->fs_type;
- entry.flags = fstab_rec->flags;
- entry.fs_options = fstab_rec->fs_options;
- entry.fs_mgr_flags.val = fstab_rec->fs_mgr_flags;
- entry.key_loc = fstab_rec->key_loc;
- entry.key_dir = fstab_rec->key_dir;
- entry.verity_loc = fstab_rec->verity_loc;
- entry.length = fstab_rec->length;
- entry.label = fstab_rec->label;
- entry.partnum = fstab_rec->partnum;
- entry.swap_prio = fstab_rec->swap_prio;
- entry.max_comp_streams = fstab_rec->max_comp_streams;
- entry.zram_size = fstab_rec->zram_size;
- entry.reserved_size = fstab_rec->reserved_size;
- entry.file_contents_mode = fstab_rec->file_contents_mode;
- entry.file_names_mode = fstab_rec->file_names_mode;
- entry.erase_blk_size = fstab_rec->erase_blk_size;
- entry.logical_blk_size = fstab_rec->logical_blk_size;
- entry.sysfs_path = fstab_rec->sysfs_path;
- entry.zram_loopback_path = fstab_rec->zram_loopback_path;
- entry.zram_loopback_size = fstab_rec->zram_loopback_size;
- entry.zram_backing_dev_path = fstab_rec->zram_backing_dev_path;
-
- return entry;
-}
-
-Fstab LegacyFstabToFstab(const struct fstab* legacy_fstab) {
- Fstab fstab;
- for (int i = 0; i < legacy_fstab->num_entries; i++) {
- fstab.emplace_back(FstabRecToFstabEntry(&legacy_fstab->recs[i]));
- }
-
- return fstab;
-}
-
-fstab* FstabToLegacyFstab(const Fstab& fstab) {
- struct fstab* legacy_fstab = static_cast<struct fstab*>(calloc(1, sizeof(struct fstab)));
- legacy_fstab->num_entries = fstab.size();
- legacy_fstab->recs =
- static_cast<fstab_rec*>(calloc(legacy_fstab->num_entries, sizeof(fstab_rec)));
-
- for (int i = 0; i < legacy_fstab->num_entries; i++) {
- legacy_fstab->recs[i].blk_device = strdup(fstab[i].blk_device.c_str());
- legacy_fstab->recs[i].logical_partition_name =
- strdup(fstab[i].logical_partition_name.c_str());
- legacy_fstab->recs[i].mount_point = strdup(fstab[i].mount_point.c_str());
- legacy_fstab->recs[i].fs_type = strdup(fstab[i].fs_type.c_str());
- legacy_fstab->recs[i].flags = fstab[i].flags;
- legacy_fstab->recs[i].fs_options = strdup(fstab[i].fs_options.c_str());
- legacy_fstab->recs[i].fs_mgr_flags = fstab[i].fs_mgr_flags.val;
- legacy_fstab->recs[i].key_loc = strdup(fstab[i].key_loc.c_str());
- legacy_fstab->recs[i].key_dir = strdup(fstab[i].key_dir.c_str());
- legacy_fstab->recs[i].verity_loc = strdup(fstab[i].verity_loc.c_str());
- legacy_fstab->recs[i].length = fstab[i].length;
- legacy_fstab->recs[i].label = strdup(fstab[i].label.c_str());
- legacy_fstab->recs[i].partnum = fstab[i].partnum;
- legacy_fstab->recs[i].swap_prio = fstab[i].swap_prio;
- legacy_fstab->recs[i].max_comp_streams = fstab[i].max_comp_streams;
- legacy_fstab->recs[i].zram_size = fstab[i].zram_size;
- legacy_fstab->recs[i].reserved_size = fstab[i].reserved_size;
- legacy_fstab->recs[i].file_contents_mode = strdup(fstab[i].file_contents_mode.c_str());
- legacy_fstab->recs[i].file_names_mode = strdup(fstab[i].file_names_mode.c_str());
- legacy_fstab->recs[i].erase_blk_size = fstab[i].erase_blk_size;
- legacy_fstab->recs[i].logical_blk_size = fstab[i].logical_blk_size;
- legacy_fstab->recs[i].sysfs_path = strdup(fstab[i].sysfs_path.c_str());
- legacy_fstab->recs[i].zram_loopback_path = strdup(fstab[i].zram_loopback_path.c_str());
- legacy_fstab->recs[i].zram_loopback_size = fstab[i].zram_loopback_size;
- legacy_fstab->recs[i].zram_backing_dev_path = strdup(fstab[i].zram_backing_dev_path.c_str());
- }
- return legacy_fstab;
-}
-
-int fs_mgr_is_voldmanaged(const struct fstab_rec *fstab)
-{
- return fstab->fs_mgr_flags & MF_VOLDMANAGED;
-}
-
-int fs_mgr_is_nonremovable(const struct fstab_rec *fstab)
-{
- return fstab->fs_mgr_flags & MF_NONREMOVABLE;
-}
-
-int fs_mgr_is_verified(const struct fstab_rec *fstab)
-{
- return fstab->fs_mgr_flags & MF_VERIFY;
-}
-
-int fs_mgr_is_encryptable(const struct fstab_rec *fstab)
-{
- return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT | MF_FORCEFDEORFBE);
-}
-
-void fs_mgr_get_file_encryption_modes(const struct fstab_rec* fstab, const char** contents_mode_ret,
- const char** filenames_mode_ret) {
- *contents_mode_ret = fstab->file_contents_mode;
- *filenames_mode_ret = fstab->file_names_mode;
-}
-
-int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab)
-{
- return fstab->fs_mgr_flags & MF_FORCEFDEORFBE;
-}
-
-int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab)
-{
- return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
-}
-
-int fs_mgr_is_notrim(const struct fstab_rec* fstab) {
- return fstab->fs_mgr_flags & MF_NOTRIM;
-}
-
-int fs_mgr_is_quota(const struct fstab_rec* fstab) {
- return fstab->fs_mgr_flags & MF_QUOTA;
-}
-
-int fs_mgr_has_sysfs_path(const struct fstab_rec *fstab)
-{
- return fstab->fs_mgr_flags & MF_SYSFS;
-}
-
-int fs_mgr_is_logical(const struct fstab_rec* fstab) {
- return fstab->fs_mgr_flags & MF_LOGICAL;
-}
-
-int fs_mgr_is_checkpoint(const struct fstab_rec* fstab) {
- return fstab->fs_mgr_flags & (MF_CHECKPOINT_FS | MF_CHECKPOINT_BLK);
-}
-
-int fs_mgr_is_checkpoint_fs(const struct fstab_rec* fstab) {
- return fstab->fs_mgr_flags & MF_CHECKPOINT_FS;
-}
-
-int fs_mgr_is_checkpoint_blk(const struct fstab_rec* fstab) {
- return fstab->fs_mgr_flags & MF_CHECKPOINT_BLK;
-}
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index c7d2cb9..df1e326 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -67,6 +67,13 @@
return ret;
}
+// determine if a filesystem is available
+bool fs_mgr_overlayfs_filesystem_available(const std::string& filesystem) {
+ std::string filesystems;
+ if (!android::base::ReadFileToString("/proc/filesystems", &filesystems)) return false;
+ return filesystems.find("\t" + filesystem + "\n") != std::string::npos;
+}
+
} // namespace
#if ALLOW_ADBD_DISABLE_VERITY == 0 // If we are a user build, provide stubs
@@ -321,6 +328,7 @@
bool fs_mgr_overlayfs_setup_one(const std::string& overlay, const std::string& mount_point,
bool* change) {
auto ret = true;
+ if (fs_mgr_overlayfs_already_mounted(mount_point)) return ret;
auto fsrec_mount_point = overlay + "/" + android::base::Basename(mount_point) + "/";
if (setfscreatecon(kOverlayfsFileContext)) {
@@ -531,7 +539,10 @@
std::vector<std::string> mounts;
auto verity = fs_mgr_overlayfs_verity_enabled_list();
for (auto& entry : *fstab) {
- if (!fs_mgr_wants_overlayfs(&entry)) continue;
+ if (!fs_mgr_overlayfs_already_mounted(entry.mount_point) &&
+ !fs_mgr_wants_overlayfs(&entry)) {
+ continue;
+ }
std::string new_mount_point(fs_mgr_mount_point(entry.mount_point.c_str()));
if (mount_point && (new_mount_point != mount_point)) continue;
if (std::find(verity.begin(), verity.end(), android::base::Basename(new_mount_point)) !=
@@ -554,26 +565,6 @@
if (!duplicate_or_more_specific) mounts.emplace_back(new_mount_point);
}
- // if not itemized /system or /, system as root, fake one up?
-
- // do we want or need to?
- if (mount_point && ("/system"s != mount_point)) return mounts;
- if (std::find(mounts.begin(), mounts.end(), "/system") != mounts.end()) return mounts;
-
- // fs_mgr_overlayfs_verity_enabled_list says not to?
- if (std::find(verity.begin(), verity.end(), "system") != verity.end()) return mounts;
-
- // confirm that fstab is missing system
- if (GetEntryForMountPoint(fstab, "/") != nullptr ||
- GetEntryForMountPoint(fstab, "/system") != nullptr) {
- return mounts;
- }
-
- // We have a stunted fstab (w/o system or / ) passed in by the caller,
- // verity claims are assumed accurate because they are collected internally
- // from fs_mgr_fstab_default() from within fs_mgr_update_verity_state(),
- // Can (re)evaluate /system with impunity since we know it is ever-present.
- mounts.emplace_back("/system");
return mounts;
}
@@ -625,8 +616,12 @@
// Only a suggestion for _first_ try during mounting
std::string fs_mgr_overlayfs_scratch_mount_type() {
- if (!access(kMkF2fs.c_str(), X_OK) && fs_mgr_access("/sys/fs/f2fs")) return "f2fs";
- if (!access(kMkExt4.c_str(), X_OK) && fs_mgr_access("/sys/fs/ext4")) return "ext4";
+ if (!access(kMkF2fs.c_str(), X_OK) && fs_mgr_overlayfs_filesystem_available("f2fs")) {
+ return "f2fs";
+ }
+ if (!access(kMkExt4.c_str(), X_OK) && fs_mgr_overlayfs_filesystem_available("ext4")) {
+ return "ext4";
+ }
return "auto";
}
@@ -657,7 +652,7 @@
if (mnt_type == "f2fs") {
command = kMkF2fs + " -w 4096 -f -d1 -l" + android::base::Basename(kScratchMountPoint);
} else if (mnt_type == "ext4") {
- command = kMkExt4 + " -b 4096 -t ext4 -m 0 -O has_journal -M " + kScratchMountPoint;
+ command = kMkExt4 + " -F -b 4096 -t ext4 -m 0 -O has_journal -M " + kScratchMountPoint;
} else {
errno = ESRCH;
LERROR << mnt_type << " has no mkfs cookbook";
@@ -821,7 +816,10 @@
auto scratch_can_be_mounted = true;
for (const auto& mount_point : fs_mgr_candidate_list(fstab)) {
- if (fs_mgr_overlayfs_already_mounted(mount_point)) continue;
+ if (fs_mgr_overlayfs_already_mounted(mount_point)) {
+ ret = true;
+ continue;
+ }
if (scratch_can_be_mounted) {
scratch_can_be_mounted = false;
auto scratch_device = fs_mgr_overlayfs_scratch_device();
@@ -1002,7 +1000,7 @@
if (fs_mgr_access("/sys/module/overlay/parameters/override_creds")) {
return OverlayfsValidResult::kOverrideCredsRequired;
}
- if (!fs_mgr_access("/sys/module/overlay")) {
+ if (!fs_mgr_overlayfs_filesystem_available("overlay")) {
return OverlayfsValidResult::kNotSupported;
}
struct utsname uts;
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 83e5d7b..166c32b 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef __CORE_FS_MGR_PRIV_H
-#define __CORE_FS_MGR_PRIV_H
+#pragma once
#include <chrono>
#include <string>
@@ -85,53 +84,6 @@
*
*/
-// clang-format off
-#define MF_WAIT 0x1
-#define MF_CHECK 0x2
-#define MF_CRYPT 0x4
-#define MF_NONREMOVABLE 0x8
-#define MF_VOLDMANAGED 0x10
-#define MF_LENGTH 0x20
-#define MF_RECOVERYONLY 0x40
-#define MF_SWAPPRIO 0x80
-#define MF_ZRAMSIZE 0x100
-#define MF_VERIFY 0x200
-#define MF_FORCECRYPT 0x400
-#define MF_NOEMULATEDSD 0x800 /* no emulated sdcard daemon, sd card is the only
- external storage */
-#define MF_NOTRIM 0x1000
-#define MF_FILEENCRYPTION 0x2000
-#define MF_FORMATTABLE 0x4000
-#define MF_SLOTSELECT 0x8000
-#define MF_FORCEFDEORFBE 0x10000
-#define MF_LATEMOUNT 0x20000
-#define MF_NOFAIL 0x40000
-#define MF_VERIFYATBOOT 0x80000
-#define MF_MAX_COMP_STREAMS 0x100000
-#define MF_RESERVEDSIZE 0x200000
-#define MF_QUOTA 0x400000
-#define MF_ERASEBLKSIZE 0x800000
-#define MF_LOGICALBLKSIZE 0X1000000
-#define MF_AVB 0X2000000
-#define MF_KEYDIRECTORY 0X4000000
-#define MF_SYSFS 0X8000000
-#define MF_LOGICAL 0x10000000
-#define MF_CHECKPOINT_BLK 0x20000000
-#define MF_CHECKPOINT_FS 0x40000000
-#define MF_FIRST_STAGE_MOUNT \
- 0x80000000
-#define MF_SLOTSELECT_OTHER \
- 0x100000000
-#define MF_ZRAM_LOOPBACK_PATH \
- 0x200000000
-#define MF_ZRAM_LOOPBACK_SIZE \
- 0x400000000
-#define MF_ZRAM_BACKING_DEV_PATH \
- 0x800000000
-#define MF_FS_VERITY \
- 0x1000000000
-// clang-format on
-
#define DM_BUF_SIZE 4096
using namespace std::chrono_literals;
@@ -148,5 +100,3 @@
const std::string& get_android_dt_dir();
bool is_dt_compatible();
int load_verity_state(const android::fs_mgr::FstabEntry& entry, int* mode);
-
-#endif /* __CORE_FS_MGR_PRIV_H */
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 6e9f1b0..8af80a7 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -65,9 +65,6 @@
#define FS_MGR_DOMNT_FAILED (-1)
#define FS_MGR_DOMNT_BUSY (-2)
#define FS_MGR_DOMNT_SUCCESS 0
-int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point);
-int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point,
- bool needs_checkpoint);
int fs_mgr_do_mount(android::fs_mgr::Fstab* fstab, const char* n_name, char* n_blk_device,
char* tmp_mount_point);
int fs_mgr_do_mount(android::fs_mgr::Fstab* fstab, const char* n_name, char* n_blk_device,
@@ -75,8 +72,6 @@
int fs_mgr_do_mount_one(const android::fs_mgr::FstabEntry& entry,
const std::string& mount_point = "");
int fs_mgr_do_tmpfs_mount(const char *n_name);
-fstab_rec const* fs_mgr_get_crypt_entry(fstab const* fstab);
-void fs_mgr_get_crypt_info(fstab* fstab, char* key_loc, char* real_blk_device, size_t size);
bool fs_mgr_load_verity_state(int* mode);
bool fs_mgr_update_verity_state(
std::function<void(const std::string& mount_point, int mode)> callback);
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index a942d43..a3d9fdd 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -16,75 +16,13 @@
#pragma once
-#include <linux/dm-ioctl.h>
-#include <stdbool.h>
#include <stdint.h>
-#include <stdio.h>
#include <sys/types.h>
#include <set>
#include <string>
#include <vector>
-/*
- * The entries must be kept in the same order as they were seen in the fstab.
- * Unless explicitly requested, a lookup on mount point should always
- * return the 1st one.
- */
-struct fstab {
- int num_entries;
- struct fstab_rec* recs;
-};
-
-struct fstab_rec {
- char* blk_device;
- char* logical_partition_name;
- char* mount_point;
- char* fs_type;
- unsigned long flags;
- char* fs_options;
- uint64_t fs_mgr_flags;
- char* key_loc;
- char* key_dir;
- char* verity_loc;
- off64_t length;
- char* label;
- int partnum;
- int swap_prio;
- int max_comp_streams;
- off64_t zram_size;
- off64_t reserved_size;
- char* file_contents_mode;
- char* file_names_mode;
- off64_t erase_blk_size;
- off64_t logical_blk_size;
- char* sysfs_path;
- char* zram_loopback_path;
- uint64_t zram_loopback_size;
- char* zram_backing_dev_path;
-};
-
-struct fstab* fs_mgr_read_fstab_default();
-struct fstab* fs_mgr_read_fstab(const char* fstab_path);
-void fs_mgr_free_fstab(struct fstab* fstab);
-
-struct fstab_rec* fs_mgr_get_entry_for_mount_point(struct fstab* fstab, const std::string& path);
-int fs_mgr_is_voldmanaged(const struct fstab_rec* fstab);
-int fs_mgr_is_nonremovable(const struct fstab_rec* fstab);
-int fs_mgr_is_verified(const struct fstab_rec* fstab);
-int fs_mgr_is_encryptable(const struct fstab_rec* fstab);
-void fs_mgr_get_file_encryption_modes(const struct fstab_rec* fstab, const char** contents_mode_ret,
- const char** filenames_mode_ret);
-int fs_mgr_is_convertible_to_fbe(const struct fstab_rec* fstab);
-int fs_mgr_is_noemulatedsd(const struct fstab_rec* fstab);
-int fs_mgr_is_notrim(const struct fstab_rec* fstab);
-int fs_mgr_is_quota(const struct fstab_rec* fstab);
-int fs_mgr_is_logical(const struct fstab_rec* fstab);
-int fs_mgr_is_checkpoint(const struct fstab_rec* fstab);
-int fs_mgr_is_checkpoint_fs(const struct fstab_rec* fstab);
-int fs_mgr_is_checkpoint_blk(const struct fstab_rec* fstab);
-int fs_mgr_has_sysfs_path(const struct fstab_rec* fstab);
-
std::string fs_mgr_get_slot_suffix();
std::string fs_mgr_get_other_slot_suffix();
@@ -119,60 +57,34 @@
std::string zram_backing_dev_path;
std::string avb_key;
- // TODO: Remove this union once fstab_rec is deprecated. It only serves as a
- // convenient way to convert between fstab_rec::fs_mgr_flags and these bools.
- union FsMgrFlags {
- uint64_t val;
- struct {
- // bit 0
- bool wait : 1;
- bool check : 1;
- bool crypt : 1;
- bool nonremovable : 1;
- bool vold_managed : 1;
- bool length : 1;
- bool recovery_only : 1;
- bool swap_prio : 1;
-
- // bit 8
- bool zram_size : 1;
- bool verify : 1;
- bool force_crypt : 1;
- bool no_emulated_sd : 1; // No emulated sdcard daemon; sd card is the only external
- // storage.
- bool no_trim : 1;
- bool file_encryption : 1;
- bool formattable : 1;
- bool slot_select : 1;
-
- // bit 16
- bool force_fde_or_fbe : 1;
- bool late_mount : 1;
- bool no_fail : 1;
- bool verify_at_boot : 1;
- bool max_comp_streams : 1;
- bool reserved_size : 1;
- bool quota : 1;
- bool erase_blk_size : 1;
-
- // bit 24
- bool logical_blk_size : 1;
- bool avb : 1;
- bool key_directory : 1;
- bool sysfs : 1;
- bool logical : 1;
- bool checkpoint_blk : 1;
- bool checkpoint_fs : 1;
- bool first_stage_mount : 1;
-
- // bit 32
- bool slot_select_other : 1;
- bool zram_loopback_path : 1;
- bool zram_loopback_size : 1;
- bool zram_backing_dev_path : 1;
- bool fs_verity : 1;
- };
- } fs_mgr_flags;
+ struct FsMgrFlags {
+ bool wait : 1;
+ bool check : 1;
+ bool crypt : 1;
+ bool nonremovable : 1;
+ bool vold_managed : 1;
+ bool recovery_only : 1;
+ bool verify : 1;
+ bool force_crypt : 1;
+ bool no_emulated_sd : 1; // No emulated sdcard daemon; sd card is the only external
+ // storage.
+ bool no_trim : 1;
+ bool file_encryption : 1;
+ bool formattable : 1;
+ bool slot_select : 1;
+ bool force_fde_or_fbe : 1;
+ bool late_mount : 1;
+ bool no_fail : 1;
+ bool verify_at_boot : 1;
+ bool quota : 1;
+ bool avb : 1;
+ bool logical : 1;
+ bool checkpoint_blk : 1;
+ bool checkpoint_fs : 1;
+ bool first_stage_mount : 1;
+ bool slot_select_other : 1;
+ bool fs_verity : 1;
+ } fs_mgr_flags = {};
bool is_encryptable() const {
return fs_mgr_flags.crypt || fs_mgr_flags.force_crypt || fs_mgr_flags.force_fde_or_fbe;
@@ -180,6 +92,8 @@
};
// An Fstab is a collection of FstabEntry structs.
+// The entries must be kept in the same order as they were seen in the fstab.
+// Unless explicitly requested, a lookup on mount point should always return the 1st one.
using Fstab = std::vector<FstabEntry>;
bool ReadFstabFromFile(const std::string& path, Fstab* fstab);
@@ -195,8 +109,3 @@
} // namespace fs_mgr
} // namespace android
-
-// Temporary conversion functions.
-android::fs_mgr::FstabEntry FstabRecToFstabEntry(const fstab_rec* fstab_rec);
-android::fs_mgr::Fstab LegacyFstabToFstab(const struct fstab* legacy_fstab);
-fstab* FstabToLegacyFstab(const android::fs_mgr::Fstab& fstab);
diff --git a/fs_mgr/libfs_avb/TEST_MAPPING b/fs_mgr/libfs_avb/TEST_MAPPING
index dc23827..b0f36d4 100644
--- a/fs_mgr/libfs_avb/TEST_MAPPING
+++ b/fs_mgr/libfs_avb/TEST_MAPPING
@@ -1,5 +1,5 @@
{
- "presubmit": [
+ "postsubmit": [
{
"name": "libfs_avb_test",
"host": true
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index 4d9bc61..8298bf2 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -1,4 +1,15 @@
#! /bin/bash
+#
+# Divided into four section:
+#
+## USAGE
+## Helper Variables
+## Helper Functions
+## MAINLINE
+
+##
+## USAGE
+##
USAGE="USAGE: `basename ${0}` [-s <SerialNumber>]
@@ -17,20 +28,26 @@
exit 0
fi
-# Helper Variables
+##
+## Helper Variables
+##
SPACE=" "
# A _real_ embedded tab character
TAB="`echo | tr '\n' '\t'`"
# A _real_ embedded escape character
ESCAPE="`echo | tr '\n' '\033'`"
+# A _real_ embedded carriage return character
+CR="`echo | tr '\n' '\r'`"
GREEN="${ESCAPE}[38;5;40m"
RED="${ESCAPE}[38;5;196m"
ORANGE="${ESCAPE}[38;5;255:165:0m"
BLUE="${ESCAPE}[35m"
NORMAL="${ESCAPE}[0m"
-# Helper functions
+##
+## Helper Functions
+##
[ "USAGE: inFastboot
@@ -68,6 +85,8 @@
args="${args}${i}"
elif [ X"${i}" != X"${i#* }" ]; then
args="${args}'${i}'"
+ elif [ X"${i}" != X"${i#*${TAB}}" ]; then
+ args="${args}'${i}'"
else
args="${args}${i}"
fi
@@ -130,16 +149,62 @@
Returns: true if the reboot command succeeded" ]
adb_reboot() {
- adb reboot remount-test &&
+ adb reboot remount-test || true
sleep 2
}
+[ "USAGE: format_duration [<seconds>|<seconds>s|<minutes>m|<hours>h|<days>d]
+
+human readable output whole seconds, whole minutes or mm:ss" ]
+format_duration() {
+ if [ -z "${1}" ]; then
+ echo unknown
+ return
+ fi
+ duration="${1}"
+ if [ X"${duration}" != X"${duration%s}" ]; then
+ duration=${duration%s}
+ elif [ X"${duration}" != X"${duration%m}" ]; then
+ duration=`expr ${duration%m} \* 60`
+ elif [ X"${duration}" != X"${duration%h}" ]; then
+ duration=`expr ${duration%h} \* 3600`
+ elif [ X"${duration}" != X"${duration%d}" ]; then
+ duration=`expr ${duration%d} \* 86400`
+ fi
+ seconds=`expr ${duration} % 60`
+ minutes=`expr \( ${duration} / 60 \) % 60`
+ hours=`expr ${duration} / 3600`
+ if [ 0 -eq ${minutes} -a 0 -eq ${hours} ]; then
+ if [ 1 -eq ${duration} ]; then
+ echo 1 second
+ return
+ fi
+ echo ${duration} seconds
+ return
+ elif [ 60 -eq ${duration} ]; then
+ echo 1 minute
+ return
+ elif [ 0 -eq ${seconds} -a 0 -eq ${hours} ]; then
+ echo ${minutes} minutes
+ return
+ fi
+ if [ 0 -eq ${hours} ]; then
+ echo ${minutes}:`expr ${seconds} / 10``expr ${seconds} % 10`
+ return
+ fi
+ echo ${hours}:`expr ${minutes} / 10``expr ${minutes} % 10`:`expr ${seconds} / 10``expr ${seconds} % 10`
+}
+
[ "USAGE: adb_wait [timeout]
Returns: waits until the device has returned for adb or optional timeout" ]
adb_wait() {
if [ -n "${1}" ]; then
+ echo -n ". . . waiting `format_duration ${1}`" ${ANDROID_SERIAL} ${USB_ADDRESS} "${CR}"
timeout --preserve-status --signal=KILL ${1} adb wait-for-device
+ retval=${?}
+ echo -n " ${CR}"
+ return ${retval}
else
adb wait-for-device
fi
@@ -152,10 +217,14 @@
# fastboot has no wait-for-device, but it does an automatic
# wait and requires (even a nonsensical) command to do so.
if [ -n "${1}" ]; then
- timeout --preserve-status --signal=KILL ${1} fastboot wait-for-device
+ echo -n ". . . waiting `format_duration ${1}`" ${ANDROID_SERIAL} ${USB_ADDRESS} "${CR}"
+ timeout --preserve-status --signal=KILL ${1} fastboot wait-for-device >/dev/null 2>/dev/null
+ retval=${?}
+ echo -n " ${CR}"
+ ( exit ${retval} )
else
- fastboot wait-for-device >/dev/null
- fi >/dev/null 2>/dev/null ||
+ fastboot wait-for-device >/dev/null 2>/dev/null
+ fi ||
inFastboot
}
@@ -310,9 +379,14 @@
-e "^\(overlay\|tmpfs\|none\|sysfs\|proc\|selinuxfs\|debugfs\) " \
-e "^\(bpf\|cg2_bpf\|pstore\|tracefs\|adb\|mtp\|ptp\|devpts\) " \
-e "^\(/data/media\|/dev/block/loop[0-9]*\) " \
+ -e "^rootfs / rootfs rw," \
-e " /\(cache\|mnt/scratch\|mnt/vendor/persist\|persist\|metadata\) "
}
+##
+## MAINLINE
+##
+
if [ X"-s" = X"${1}" -a -n "${2}" ]; then
export ANDROID_SERIAL="${2}"
shift 2
@@ -320,7 +394,7 @@
inFastboot && die "device in fastboot mode"
if ! inAdb; then
- echo "${ORANGE}[ WARNING ]${NORMAL} device not in adb mode ... waiting 2 minutes"
+ echo "${ORANGE}[ WARNING ]${NORMAL} device not in adb mode"
adb_wait 2m
fi
inAdb || die "specified device not in adb mode"
@@ -331,19 +405,38 @@
enforcing=false
fi
-# Do something
+# Do something.
D=`get_property ro.serialno`
[ -n "${D}" ] || D=`get_property ro.boot.serialno`
[ -z "${D}" ] || ANDROID_SERIAL=${D}
+USB_SERIAL=
+[ -z "${ANDROID_SERIAL}" ] || USB_SERIAL=`find /sys/devices -name serial |
+ grep usb |
+ xargs grep -l ${ANDROID_SERIAL}`
+USB_ADDRESS=
+if [ -n "${USB_SERIAL}" ]; then
+ USB_ADDRESS=${USB_SERIAL%/serial}
+ USB_ADDRESS=usb${USB_ADDRESS##*/}
+fi
+[ -z "${ANDROID_SERIAL}${USB_ADDRESS}" ] ||
+ echo "${BLUE}[ INFO ]${NORMAL}" ${ANDROID_SERIAL} ${USB_ADDRESS} >&2
BUILD_DESCRIPTION=`get_property ro.build.description`
-echo "${BLUE}[ INFO ]${NORMAL} ${ANDROID_SERIAL} ${BUILD_DESCRIPTION}" >&2
+[ -z "${BUILD_DESCRIPTION}" ] ||
+ echo "${BLUE}[ INFO ]${NORMAL} ${BUILD_DESCRIPTION}" >&2
+
+VERITY_WAS_ENABLED=false
+if [ "orange" = "`get_property ro.boot.verifiedbootstate`" -a \
+ "2" = "`get_property partition.system.verified`" ]; then
+ VERITY_WAS_ENABLED=true
+fi
echo "${GREEN}[ RUN ]${NORMAL} Testing kernel support for overlayfs" >&2
overlayfs_supported=true;
adb_wait || die "wait for device failed"
-adb_sh ls -d /sys/module/overlay </dev/null >/dev/null &&
+adb_sh ls -d /sys/module/overlay </dev/null >/dev/null 2>/dev/null ||
+ adb_sh grep "nodev${TAB}overlay" /proc/filesystems </dev/null >/dev/null 2>/dev/null &&
echo "${GREEN}[ OK ]${NORMAL} overlay module present" >&2 ||
(
echo "${ORANGE}[ WARNING ]${NORMAL} overlay module not present" >&2 &&
@@ -391,9 +484,9 @@
echo "${ORANGE}[ WARNING ]${NORMAL} rebooting before test" >&2
adb_reboot &&
adb_wait 2m ||
- die "lost device after reboot after wipe"
+ die "lost device after reboot after wipe (USB stack broken?)"
adb_root ||
- die "lost device after elevation to root after wipe"
+ die "lost device after elevation to root after wipe (USB stack broken?)"
fi
D=`adb_sh df -k </dev/null` &&
H=`echo "${D}" | head -1` &&
@@ -455,9 +548,9 @@
L=`adb_logcat -b all -v nsec -t ${T} 2>&1`
adb_reboot &&
adb_wait 2m ||
- die "lost device after reboot requested"
+ die "lost device after reboot requested (USB stack broken?)"
adb_root ||
- die "lost device after elevation to root"
+ die "lost device after elevation to root (USB stack broken?)"
rebooted=true
# re-disable verity to see the setup remarks expected
T=`adb_date`
@@ -544,7 +637,7 @@
echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
die "overlay takeover after remount"
!(adb_sh grep "^overlay " /proc/mounts </dev/null |
- grep -v "^overlay /\(vendor\|system\)/..* overlay ro," |
+ grep -v "^overlay /\(vendor\|system\|bionic\)/..* overlay ro," |
grep " overlay ro,") &&
!(adb_sh grep " rw," /proc/mounts </dev/null |
skip_administrative_mounts data) ||
@@ -555,7 +648,7 @@
fi
fi
-# Check something
+# Check something.
echo "${GREEN}[ RUN ]${NORMAL} push content to /system and /vendor" >&2
@@ -569,17 +662,22 @@
die "vendor hello"
check_eq "${A}" "${B}" /vendor before reboot
-# download libc.so, append some gargage, push back, and check if the file is updated.
+# Download libc.so, append some gargage, push back, and check if the file
+# is updated.
tempdir="`mktemp -d`"
cleanup() {
rm -rf ${tempdir}
}
-adb pull /system/lib/bootstrap/libc.so ${tempdir} || die "pull libc.so from device"
+adb pull /system/lib/bootstrap/libc.so ${tempdir} >/dev/null ||
+ die "pull libc.so from device"
garbage="`hexdump -n 16 -e '4/4 "%08X" 1 "\n"' /dev/random`"
echo ${garbage} >> ${tempdir}/libc.so
-adb push ${tempdir}/libc.so /system/lib/bootstrap/libc.so || die "push libc.so to device"
-adb pull /system/lib/bootstrap/libc.so ${tempdir}/libc.so.fromdevice || die "pull libc.so from device"
-diff ${tempdir}/libc.so ${tempdir}/libc.so.fromdevice > /dev/null || die "libc.so differ"
+adb push ${tempdir}/libc.so /system/lib/bootstrap/libc.so >/dev/null ||
+ die "push libc.so to device"
+adb pull /system/lib/bootstrap/libc.so ${tempdir}/libc.so.fromdevice >/dev/null ||
+ die "pull libc.so from device"
+diff ${tempdir}/libc.so ${tempdir}/libc.so.fromdevice > /dev/null ||
+ die "libc.so differ"
echo "${GREEN}[ RUN ]${NORMAL} reboot to confirm content persistent" >&2
@@ -605,7 +703,7 @@
die "re-read /system/hello after reboot"
check_eq "${A}" "${B}" /system after reboot
echo "${GREEN}[ OK ]${NORMAL} /system content remains after reboot" >&2
-# Only root can read vendor if sepolicy permissions are as expected
+# Only root can read vendor if sepolicy permissions are as expected.
if ${enforcing}; then
adb_unroot
B="`adb_cat /vendor/hello`" &&
@@ -619,9 +717,9 @@
check_eq "${A}" "${B}" vendor after reboot
echo "${GREEN}[ OK ]${NORMAL} /vendor content remains after reboot" >&2
-# check if the updated libc.so is persistent after reboot
+# Check if the updated libc.so is persistent after reboot.
adb_root &&
- adb pull /system/lib/bootstrap/libc.so ${tempdir}/libc.so.fromdevice ||
+ adb pull /system/lib/bootstrap/libc.so ${tempdir}/libc.so.fromdevice >/dev/null ||
die "pull libc.so from device"
diff ${tempdir}/libc.so ${tempdir}/libc.so.fromdevice > /dev/null || die "libc.so differ"
rm -r ${tempdir}
@@ -677,7 +775,7 @@
fi
fastboot reboot ||
die "can not reboot out of fastboot"
- echo "${ORANGE}[ WARNING ]${NORMAL} adb after fastboot ... waiting 2 minutes"
+ echo "${ORANGE}[ WARNING ]${NORMAL} adb after fastboot"
adb_wait 2m ||
die "did not reboot after flash"
if ${overlayfs_needed}; then
@@ -719,9 +817,26 @@
echo "${GREEN}[ RUN ]${NORMAL} remove test content (cleanup)" >&2
T=`adb_date`
-adb remount &&
+H=`adb remount 2>&1`
+err=${?}
+L=
+D="${H%?Now reboot your device for settings to take effect}"
+if [ X"${H}" != X"${D}" ]; then
+ echo "${ORANGE}[ WARNING ]${NORMAL} adb remount requires a reboot after partial flash (legacy avb)"
+ L=`adb_logcat -b all -v nsec -t ${T} 2>&1`
+ adb_reboot &&
+ adb_wait 2m &&
+ adb_root ||
+ die "failed to reboot"
+ T=`adb_date`
+ H=`adb remount 2>&1`
+ err=${?}
+fi
+echo "${H}"
+[ ${err} = 0 ] &&
( adb_sh rm /vendor/hello </dev/null 2>/dev/null || true ) &&
adb_sh rm /system/hello </dev/null ||
+ ( [ -n "${L}" ] && echo "${L}" && false ) ||
die -t ${T} "cleanup hello"
B="`adb_cat /system/hello`" &&
die "re-read /system/hello after rm"
@@ -768,12 +883,12 @@
die -t ${T} "setup for overlayfs"
fi
-echo "${GREEN}[ RUN ]${NORMAL} test raw remount command" >&2
+echo "${GREEN}[ RUN ]${NORMAL} test raw remount commands" >&2
-# prerequisite is a prepped device from above
+# Prerequisite is a prepped device from above.
adb_reboot &&
adb_wait 2m ||
- die "lost device after reboot to ro state"
+ die "lost device after reboot to ro state (USB stack broken?)"
adb_sh grep " /vendor .* rw," /proc/mounts >/dev/null &&
die "/vendor is not read-only"
adb_su mount -o rw,remount /vendor ||
@@ -782,4 +897,12 @@
die "/vendor is not read-write"
echo "${GREEN}[ OK ]${NORMAL} mount -o rw,remount command works" >&2
+if $VERITY_WAS_ENABLED && $overlayfs_supported; then
+ adb_root &&
+ adb enable-verity &&
+ adb_reboot &&
+ adb_wait 2m ||
+ die "failed to restore verity" >&2
+fi
+
echo "${GREEN}[ PASSED ]${NORMAL} adb remount" >&2
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 870c98c..1815a38 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -256,6 +256,36 @@
EXPECT_EQ("", fstab[10].fs_options);
}
+static bool CompareFlags(FstabEntry::FsMgrFlags& lhs, FstabEntry::FsMgrFlags& rhs) {
+ // clang-format off
+ return lhs.wait == rhs.wait &&
+ lhs.check == rhs.check &&
+ lhs.crypt == rhs.crypt &&
+ lhs.nonremovable == rhs.nonremovable &&
+ lhs.vold_managed == rhs.vold_managed &&
+ lhs.recovery_only == rhs.recovery_only &&
+ lhs.verify == rhs.verify &&
+ lhs.force_crypt == rhs.force_crypt &&
+ lhs.no_emulated_sd == rhs.no_emulated_sd &&
+ lhs.no_trim == rhs.no_trim &&
+ lhs.file_encryption == rhs.file_encryption &&
+ lhs.formattable == rhs.formattable &&
+ lhs.slot_select == rhs.slot_select &&
+ lhs.force_fde_or_fbe == rhs.force_fde_or_fbe &&
+ lhs.late_mount == rhs.late_mount &&
+ lhs.no_fail == rhs.no_fail &&
+ lhs.verify_at_boot == rhs.verify_at_boot &&
+ lhs.quota == rhs.quota &&
+ lhs.avb == rhs.avb &&
+ lhs.logical == rhs.logical &&
+ lhs.checkpoint_blk == rhs.checkpoint_blk &&
+ lhs.checkpoint_fs == rhs.checkpoint_fs &&
+ lhs.first_stage_mount == rhs.first_stage_mount &&
+ lhs.slot_select_other == rhs.slot_select_other &&
+ lhs.fs_verity == rhs.fs_verity;
+ // clang-format on
+}
+
TEST(fs_mgr, ReadFstabFromFile_FsMgrFlags) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
@@ -276,62 +306,62 @@
auto entry = fstab.begin();
EXPECT_EQ("none0", entry->mount_point);
{
- FstabEntry::FsMgrFlags flags = {0};
+ FstabEntry::FsMgrFlags flags = {};
flags.wait = true;
flags.check = true;
flags.nonremovable = true;
flags.recovery_only = true;
flags.verify_at_boot = true;
flags.verify = true;
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
}
entry++;
EXPECT_EQ("none1", entry->mount_point);
{
- FstabEntry::FsMgrFlags flags = {0};
+ FstabEntry::FsMgrFlags flags = {};
flags.avb = true;
flags.no_emulated_sd = true;
flags.no_trim = true;
flags.formattable = true;
flags.slot_select = true;
flags.no_fail = true;
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
}
entry++;
EXPECT_EQ("none2", entry->mount_point);
{
- FstabEntry::FsMgrFlags flags = {0};
+ FstabEntry::FsMgrFlags flags = {};
flags.first_stage_mount = true;
flags.late_mount = true;
flags.quota = true;
flags.logical = true;
flags.slot_select_other = true;
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
}
entry++;
EXPECT_EQ("none3", entry->mount_point);
{
- FstabEntry::FsMgrFlags flags = {0};
+ FstabEntry::FsMgrFlags flags = {};
flags.checkpoint_blk = true;
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
}
entry++;
EXPECT_EQ("none4", entry->mount_point);
{
- FstabEntry::FsMgrFlags flags = {0};
+ FstabEntry::FsMgrFlags flags = {};
flags.checkpoint_fs = true;
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
}
entry++;
EXPECT_EQ("none5", entry->mount_point);
{
- FstabEntry::FsMgrFlags flags = {0};
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ FstabEntry::FsMgrFlags flags = {};
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
}
}
@@ -355,8 +385,8 @@
auto entry = fstab.begin();
EXPECT_EQ("none0", entry->mount_point);
{
- FstabEntry::FsMgrFlags flags = {0};
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ FstabEntry::FsMgrFlags flags = {};
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
}
EXPECT_EQ("", entry->key_loc);
EXPECT_EQ("", entry->key_dir);
@@ -380,25 +410,13 @@
EXPECT_EQ("none1", entry->mount_point);
{
- FstabEntry::FsMgrFlags flags = {0};
+ FstabEntry::FsMgrFlags flags = {};
flags.crypt = true;
flags.force_crypt = true;
flags.file_encryption = true;
- flags.key_directory = true;
- flags.length = true;
- flags.swap_prio = true;
- flags.zram_size = true;
- flags.max_comp_streams = true;
flags.verify = true;
flags.avb = true;
- flags.reserved_size = true;
- flags.erase_blk_size = true;
- flags.logical_blk_size = true;
- flags.sysfs = true;
- flags.zram_loopback_path = true;
- flags.zram_loopback_size = true;
- flags.zram_backing_dev_path = true;
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
}
EXPECT_EQ("", entry->key_loc);
EXPECT_EQ("", entry->key_dir);
@@ -423,9 +441,9 @@
// forcefdeorfbe sets file_contents_mode and file_names_mode by default, so test it separately.
EXPECT_EQ("none2", entry->mount_point);
{
- FstabEntry::FsMgrFlags flags = {0};
+ FstabEntry::FsMgrFlags flags = {};
flags.force_fde_or_fbe = true;
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
}
EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
EXPECT_EQ("aes-256-cts", entry->file_names_mode);
@@ -444,12 +462,12 @@
EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
ASSERT_EQ(1U, fstab.size());
- FstabEntry::FsMgrFlags flags = {0};
+ FstabEntry::FsMgrFlags flags = {};
flags.crypt = true;
auto entry = fstab.begin();
EXPECT_EQ("none0", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("/dir/key", entry->key_loc);
}
@@ -468,30 +486,30 @@
EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
ASSERT_EQ(4U, fstab.size());
- FstabEntry::FsMgrFlags flags = {0};
+ FstabEntry::FsMgrFlags flags = {};
flags.vold_managed = true;
auto entry = fstab.begin();
EXPECT_EQ("none0", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_TRUE(entry->label.empty());
EXPECT_EQ(-1, entry->partnum);
entry++;
EXPECT_EQ("none1", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_TRUE(entry->label.empty());
EXPECT_EQ(-1, entry->partnum);
entry++;
EXPECT_EQ("none2", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("sdcard", entry->label);
EXPECT_EQ(3, entry->partnum);
entry++;
EXPECT_EQ("none3", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("sdcard", entry->label);
EXPECT_EQ(-1, entry->partnum);
}
@@ -509,17 +527,16 @@
EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
ASSERT_EQ(2U, fstab.size());
- FstabEntry::FsMgrFlags flags = {0};
- flags.length = true;
+ FstabEntry::FsMgrFlags flags = {};
auto entry = fstab.begin();
EXPECT_EQ("none0", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(0, entry->length);
entry++;
EXPECT_EQ("none1", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(123456, entry->length);
}
@@ -536,17 +553,16 @@
EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
ASSERT_EQ(2U, fstab.size());
- FstabEntry::FsMgrFlags flags = {0};
- flags.swap_prio = true;
+ FstabEntry::FsMgrFlags flags = {};
auto entry = fstab.begin();
EXPECT_EQ("none0", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(-1, entry->swap_prio);
entry++;
EXPECT_EQ("none1", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(123456, entry->swap_prio);
}
@@ -567,37 +583,36 @@
EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
ASSERT_EQ(6U, fstab.size());
- FstabEntry::FsMgrFlags flags = {0};
- flags.zram_size = true;
+ FstabEntry::FsMgrFlags flags = {};
auto entry = fstab.begin();
EXPECT_EQ("none0", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(0, entry->zram_size);
entry++;
EXPECT_EQ("none1", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(123456, entry->zram_size);
entry++;
EXPECT_EQ("none2", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(0, entry->zram_size);
entry++;
EXPECT_EQ("none3", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_NE(0, entry->zram_size);
entry++;
EXPECT_EQ("none4", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(0, entry->zram_size);
entry++;
EXPECT_EQ("none5", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(0, entry->zram_size);
}
@@ -617,9 +632,9 @@
auto entry = fstab.begin();
EXPECT_EQ("none0", entry->mount_point);
- FstabEntry::FsMgrFlags flags = {0};
+ FstabEntry::FsMgrFlags flags = {};
flags.verify = true;
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("/dir/key", entry->verity_loc);
}
@@ -640,9 +655,9 @@
auto entry = fstab.begin();
EXPECT_EQ("none0", entry->mount_point);
- FstabEntry::FsMgrFlags flags = {0};
+ FstabEntry::FsMgrFlags flags = {};
flags.force_crypt = true;
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("/dir/key", entry->key_loc);
}
@@ -663,9 +678,9 @@
auto entry = fstab.begin();
EXPECT_EQ("none0", entry->mount_point);
- FstabEntry::FsMgrFlags flags = {0};
+ FstabEntry::FsMgrFlags flags = {};
flags.force_fde_or_fbe = true;
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("/dir/key", entry->key_loc);
EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
@@ -695,72 +710,72 @@
EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
ASSERT_EQ(11U, fstab.size());
- FstabEntry::FsMgrFlags flags = {0};
+ FstabEntry::FsMgrFlags flags = {};
flags.file_encryption = true;
auto entry = fstab.begin();
EXPECT_EQ("none0", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("", entry->file_contents_mode);
EXPECT_EQ("", entry->file_names_mode);
entry++;
EXPECT_EQ("none1", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
EXPECT_EQ("aes-256-cts", entry->file_names_mode);
entry++;
EXPECT_EQ("none2", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
EXPECT_EQ("aes-256-cts", entry->file_names_mode);
entry++;
EXPECT_EQ("none3", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("adiantum", entry->file_contents_mode);
EXPECT_EQ("adiantum", entry->file_names_mode);
entry++;
EXPECT_EQ("none4", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("adiantum", entry->file_contents_mode);
EXPECT_EQ("aes-256-heh", entry->file_names_mode);
entry++;
EXPECT_EQ("none5", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("ice", entry->file_contents_mode);
EXPECT_EQ("aes-256-cts", entry->file_names_mode);
entry++;
EXPECT_EQ("none6", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("ice", entry->file_contents_mode);
EXPECT_EQ("", entry->file_names_mode);
entry++;
EXPECT_EQ("none7", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("ice", entry->file_contents_mode);
EXPECT_EQ("aes-256-cts", entry->file_names_mode);
entry++;
EXPECT_EQ("none8", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("ice", entry->file_contents_mode);
EXPECT_EQ("aes-256-heh", entry->file_names_mode);
entry++;
EXPECT_EQ("none9", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("ice", entry->file_contents_mode);
EXPECT_EQ("adiantum", entry->file_names_mode);
entry++;
EXPECT_EQ("none10", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("", entry->file_contents_mode);
EXPECT_EQ("", entry->file_names_mode);
}
@@ -778,17 +793,16 @@
EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
ASSERT_EQ(2U, fstab.size());
- FstabEntry::FsMgrFlags flags = {0};
- flags.max_comp_streams = true;
+ FstabEntry::FsMgrFlags flags = {};
auto entry = fstab.begin();
EXPECT_EQ("none0", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(0, entry->max_comp_streams);
entry++;
EXPECT_EQ("none1", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(123456, entry->max_comp_streams);
}
@@ -807,27 +821,26 @@
EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
ASSERT_EQ(4U, fstab.size());
- FstabEntry::FsMgrFlags flags = {0};
- flags.reserved_size = true;
+ FstabEntry::FsMgrFlags flags = {};
auto entry = fstab.begin();
EXPECT_EQ("none0", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(0, entry->reserved_size);
entry++;
EXPECT_EQ("none1", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(2, entry->reserved_size);
entry++;
EXPECT_EQ("none2", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(1024, entry->reserved_size);
entry++;
EXPECT_EQ("none3", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(2 * 1024 * 1024, entry->reserved_size);
}
@@ -846,27 +859,26 @@
EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
ASSERT_EQ(4U, fstab.size());
- FstabEntry::FsMgrFlags flags = {0};
- flags.erase_blk_size = true;
+ FstabEntry::FsMgrFlags flags = {};
auto entry = fstab.begin();
EXPECT_EQ("none0", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(0, entry->erase_blk_size);
entry++;
EXPECT_EQ("none1", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(0, entry->erase_blk_size);
entry++;
EXPECT_EQ("none2", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(0, entry->erase_blk_size);
entry++;
EXPECT_EQ("none3", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(8192, entry->erase_blk_size);
}
@@ -885,27 +897,26 @@
EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
ASSERT_EQ(4U, fstab.size());
- FstabEntry::FsMgrFlags flags = {0};
- flags.logical_blk_size = true;
+ FstabEntry::FsMgrFlags flags = {};
auto entry = fstab.begin();
EXPECT_EQ("none0", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(0, entry->logical_blk_size);
entry++;
EXPECT_EQ("none1", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(0, entry->logical_blk_size);
entry++;
EXPECT_EQ("none2", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(0, entry->logical_blk_size);
entry++;
EXPECT_EQ("none3", entry->mount_point);
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(8192, entry->logical_blk_size);
}
@@ -925,9 +936,9 @@
auto entry = fstab.begin();
EXPECT_EQ("none0", entry->mount_point);
- FstabEntry::FsMgrFlags flags = {0};
+ FstabEntry::FsMgrFlags flags = {};
flags.avb = true;
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("vbmeta_partition", entry->vbmeta_partition);
}
@@ -948,9 +959,8 @@
auto entry = fstab.begin();
EXPECT_EQ("none0", entry->mount_point);
- FstabEntry::FsMgrFlags flags = {0};
- flags.key_directory = true;
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ FstabEntry::FsMgrFlags flags = {};
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("/dir/key", entry->key_dir);
}
@@ -971,9 +981,8 @@
auto entry = fstab.begin();
EXPECT_EQ("none0", entry->mount_point);
- FstabEntry::FsMgrFlags flags = {0};
- flags.sysfs = true;
- EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+ FstabEntry::FsMgrFlags flags = {};
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("/sys/device", entry->sysfs_path);
}
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 2127b96..823ed06 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -109,6 +109,7 @@
libbase \
libutils \
libcutils \
+ libjsoncpp \
libprocessgroup \
liblog \
libm \
diff --git a/init/Android.bp b/init/Android.bp
index 67688f2..639d8d1 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -60,7 +60,6 @@
},
static_libs: [
"libseccomp_policy",
- "libprocessgroup",
"libavb",
"libprotobuf-cpp-lite",
"libpropertyinfoserializer",
@@ -82,6 +81,7 @@
"liblog",
"liblogwrap",
"liblp",
+ "libprocessgroup",
"libselinux",
"libutils",
],
diff --git a/init/README.md b/init/README.md
index 3a7c71c..f0e5d55 100644
--- a/init/README.md
+++ b/init/README.md
@@ -161,11 +161,13 @@
Options are modifiers to services. They affect how and when init
runs the service.
-`capabilities <capability> [ <capability>\* ]`
+`capabilities [ <capability>\* ]`
> Set capabilities when exec'ing this service. 'capability' should be a Linux
capability without the "CAP\_" prefix, like "NET\_ADMIN" or "SETPCAP". See
http://man7.org/linux/man-pages/man7/capabilities.7.html for a list of Linux
capabilities.
+ If no capabilities are provided, then all capabilities are removed from this service, even if it
+ runs as root.
`class <name> [ <name>\* ]`
> Specify class names for the service. All services in a
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 7d5bf57..1b077bc 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -157,6 +157,37 @@
return fstab;
}
+static bool GetRootEntry(FstabEntry* root_entry) {
+ Fstab proc_mounts;
+ if (!ReadFstabFromFile("/proc/mounts", &proc_mounts)) {
+ LOG(ERROR) << "Could not read /proc/mounts and /system not in fstab, /system will not be "
+ "available for overlayfs";
+ return false;
+ }
+
+ auto entry = std::find_if(proc_mounts.begin(), proc_mounts.end(), [](const auto& entry) {
+ return entry.mount_point == "/" && entry.fs_type != "rootfs";
+ });
+
+ if (entry == proc_mounts.end()) {
+ LOG(ERROR) << "Could not get mount point for '/' in /proc/mounts, /system will not be "
+ "available for overlayfs";
+ return false;
+ }
+
+ *root_entry = std::move(*entry);
+
+ // We don't know if we're avb or not, so we query device mapper as if we are avb. If we get a
+ // success, then mark as avb, otherwise default to verify.
+ auto& dm = android::dm::DeviceMapper::Instance();
+ if (dm.GetState("vroot") != android::dm::DmDeviceState::INVALID) {
+ root_entry->fs_mgr_flags.avb = true;
+ } else {
+ root_entry->fs_mgr_flags.verify = true;
+ }
+ return true;
+}
+
// Class Definitions
// -----------------
FirstStageMount::FirstStageMount(Fstab fstab)
@@ -443,7 +474,7 @@
if (system_partition == fstab_.end()) return true;
- if (MountPartition(system_partition, true /* erase_used_fstab_entry */)) {
+ if (MountPartition(system_partition, false)) {
SwitchRoot("/system");
} else {
PLOG(ERROR) << "Failed to mount /system";
@@ -487,6 +518,12 @@
if (!TrySkipMountingPartitions()) return false;
for (auto current = fstab_.begin(); current != fstab_.end();) {
+ // We've already mounted /system above.
+ if (current->mount_point == "/system") {
+ ++current;
+ continue;
+ }
+
Fstab::iterator end;
if (!MountPartition(current, false, &end)) {
if (current->fs_mgr_flags.no_fail) {
@@ -503,6 +540,15 @@
current = end;
}
+ // If we don't see /system or / in the fstab, then we need to create an root entry for
+ // overlayfs.
+ if (!GetEntryForMountPoint(&fstab_, "/system") && !GetEntryForMountPoint(&fstab_, "/")) {
+ FstabEntry root_entry;
+ if (GetRootEntry(&root_entry)) {
+ fstab_.emplace_back(std::move(root_entry));
+ }
+ }
+
// heads up for instantiating required device(s) for overlayfs logic
const auto devices = fs_mgr_overlayfs_required_devices(&fstab_);
for (auto const& device : devices) {
diff --git a/init/init.cpp b/init/init.cpp
index 4f4a15f..a8924f2 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -42,6 +42,7 @@
#include <fs_mgr_vendor_overlay.h>
#include <keyutils.h>
#include <libavb/libavb.h>
+#include <processgroup/processgroup.h>
#include <selinux/android.h>
#ifndef RECOVERY
@@ -191,7 +192,8 @@
if (waiting_for_prop) {
if (wait_prop_name == name && wait_prop_value == value) {
- LOG(INFO) << "Wait for property took " << *waiting_for_prop;
+ LOG(INFO) << "Wait for property '" << wait_prop_name << "=" << wait_prop_value
+ << "' took " << *waiting_for_prop;
ResetWaitForProp();
}
}
@@ -347,6 +349,17 @@
return Success();
}
+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()) {
+ return ErrnoError() << "Failed to setup cgroups";
+ }
+
+ return Success();
+}
+
static void import_kernel_nv(const std::string& key, const std::string& value, bool for_emulator) {
if (key.empty()) return;
@@ -682,6 +695,8 @@
// Nexus 9 boot time, so it's disabled by default.
if (false) DumpState();
+ am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups");
+
am.QueueEventTrigger("early-init");
// Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
diff --git a/init/service.cpp b/init/service.cpp
index a6eb7f7..2186a85 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -218,12 +218,12 @@
Service::Service(const std::string& name, Subcontext* subcontext_for_restart_commands,
const std::vector<std::string>& args)
- : Service(name, 0, 0, 0, {}, 0, 0, "", subcontext_for_restart_commands, args) {}
+ : Service(name, 0, 0, 0, {}, 0, "", subcontext_for_restart_commands, args) {}
Service::Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid,
- const std::vector<gid_t>& supp_gids, const CapSet& capabilities,
- unsigned namespace_flags, const std::string& seclabel,
- Subcontext* subcontext_for_restart_commands, const std::vector<std::string>& args)
+ const std::vector<gid_t>& supp_gids, unsigned namespace_flags,
+ const std::string& seclabel, Subcontext* subcontext_for_restart_commands,
+ const std::vector<std::string>& args)
: name_(name),
classnames_({"default"}),
flags_(flags),
@@ -232,7 +232,6 @@
uid_(uid),
gid_(gid),
supp_gids_(supp_gids),
- capabilities_(capabilities),
namespace_flags_(namespace_flags),
seclabel_(seclabel),
onrestart_(false, subcontext_for_restart_commands, "<Service '" + name + "' onrestart>", 0,
@@ -289,7 +288,7 @@
}
}
// Keep capabilites on uid change.
- if (capabilities_.any() && uid_) {
+ if (capabilities_ && uid_) {
// If Android is running in a container, some securebits might already
// be locked, so don't change those.
unsigned long securebits = prctl(PR_GET_SECUREBITS);
@@ -328,8 +327,8 @@
PLOG(FATAL) << "setpriority failed for " << name_;
}
}
- if (capabilities_.any()) {
- if (!SetCapsForExec(capabilities_)) {
+ if (capabilities_) {
+ if (!SetCapsForExec(*capabilities_)) {
LOG(FATAL) << "cannot set capabilities for " << name_;
}
} else if (uid_) {
@@ -375,7 +374,7 @@
// If we crash > 4 times in 4 minutes, reboot into bootloader or set crashing property
boot_clock::time_point now = boot_clock::now();
- if (((flags_ & SVC_CRITICAL) || classnames_.count("updatable")) && !(flags_ & SVC_RESTART)) {
+ if (((flags_ & SVC_CRITICAL) || !pre_apexd_) && !(flags_ & SVC_RESTART)) {
if (now < time_crashed_ + 4min) {
if (++crash_count_ > 4) {
if (flags_ & SVC_CRITICAL) {
@@ -420,7 +419,7 @@
}
unsigned int last_valid_cap = GetLastValidCap();
- if (last_valid_cap >= capabilities_.size()) {
+ if (last_valid_cap >= capabilities_->size()) {
LOG(WARNING) << "last valid run-time capability is larger than CAP_LAST_CAP";
}
@@ -435,7 +434,7 @@
return Error() << StringPrintf("capability '%s' not supported by the kernel",
arg.c_str());
}
- capabilities_[cap] = true;
+ (*capabilities_)[cap] = true;
}
return Success();
}
@@ -796,7 +795,7 @@
// clang-format off
static const Map option_parsers = {
{"capabilities",
- {1, kMax, &Service::ParseCapabilities}},
+ {0, kMax, &Service::ParseCapabilities}},
{"class", {1, kMax, &Service::ParseClass}},
{"console", {0, 1, &Service::ParseConsole}},
{"critical", {0, 0, &Service::ParseCritical}},
@@ -991,27 +990,33 @@
std::for_each(descriptors_.begin(), descriptors_.end(),
std::bind(&DescriptorInfo::CreateAndPublish, std::placeholders::_1, scon));
- // See if there were "writepid" instructions to write to files under /dev/cpuset/.
- auto cpuset_predicate = [](const std::string& path) {
- return StartsWith(path, "/dev/cpuset/");
- };
- auto iter = std::find_if(writepid_files_.begin(), writepid_files_.end(), cpuset_predicate);
- if (iter == writepid_files_.end()) {
- // There were no "writepid" instructions for cpusets, check if the system default
- // cpuset is specified to be used for the process.
- std::string default_cpuset = GetProperty("ro.cpuset.default", "");
- if (!default_cpuset.empty()) {
- // Make sure the cpuset name starts and ends with '/'.
- // A single '/' means the 'root' cpuset.
- if (default_cpuset.front() != '/') {
- default_cpuset.insert(0, 1, '/');
+ // See if there were "writepid" instructions to write to files under cpuset path.
+ std::string cpuset_path;
+ if (CgroupGetControllerPath("cpuset", &cpuset_path)) {
+ auto cpuset_predicate = [&cpuset_path](const std::string& path) {
+ return StartsWith(path, cpuset_path + "/");
+ };
+ auto iter =
+ std::find_if(writepid_files_.begin(), writepid_files_.end(), cpuset_predicate);
+ if (iter == writepid_files_.end()) {
+ // There were no "writepid" instructions for cpusets, check if the system default
+ // cpuset is specified to be used for the process.
+ std::string default_cpuset = GetProperty("ro.cpuset.default", "");
+ if (!default_cpuset.empty()) {
+ // Make sure the cpuset name starts and ends with '/'.
+ // A single '/' means the 'root' cpuset.
+ if (default_cpuset.front() != '/') {
+ default_cpuset.insert(0, 1, '/');
+ }
+ if (default_cpuset.back() != '/') {
+ default_cpuset.push_back('/');
+ }
+ writepid_files_.push_back(
+ StringPrintf("%s%stasks", cpuset_path.c_str(), default_cpuset.c_str()));
}
- if (default_cpuset.back() != '/') {
- default_cpuset.push_back('/');
- }
- writepid_files_.push_back(
- StringPrintf("/dev/cpuset%stasks", default_cpuset.c_str()));
}
+ } else {
+ LOG(ERROR) << "cpuset cgroup controller is not mounted!";
}
std::string pid_str = std::to_string(getpid());
for (const auto& file : writepid_files_) {
@@ -1262,7 +1267,6 @@
std::string name = "exec " + std::to_string(exec_count) + " (" + Join(str_args, " ") + ")";
unsigned flags = SVC_ONESHOT | SVC_TEMPORARY;
- CapSet no_capabilities;
unsigned namespace_flags = 0;
std::string seclabel = "";
@@ -1297,8 +1301,8 @@
}
}
- return std::make_unique<Service>(name, flags, *uid, *gid, supp_gids, no_capabilities,
- namespace_flags, seclabel, nullptr, str_args);
+ return std::make_unique<Service>(name, flags, *uid, *gid, supp_gids, namespace_flags, seclabel,
+ nullptr, str_args);
}
// Shutdown services in the opposite order that they were started.
diff --git a/init/service.h b/init/service.h
index c29723a..c42a5a3 100644
--- a/init/service.h
+++ b/init/service.h
@@ -68,9 +68,9 @@
const std::vector<std::string>& args);
Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid,
- const std::vector<gid_t>& supp_gids, const CapSet& capabilities,
- unsigned namespace_flags, const std::string& seclabel,
- Subcontext* subcontext_for_restart_commands, const std::vector<std::string>& args);
+ const std::vector<gid_t>& supp_gids, unsigned namespace_flags,
+ const std::string& seclabel, Subcontext* subcontext_for_restart_commands,
+ const std::vector<std::string>& args);
static std::unique_ptr<Service> MakeTemporaryOneshotService(const std::vector<std::string>& args);
@@ -192,7 +192,7 @@
uid_t uid_;
gid_t gid_;
std::vector<gid_t> supp_gids_;
- CapSet capabilities_;
+ std::optional<CapSet> capabilities_;
unsigned namespace_flags_;
// Pair of namespace type, path to namespace.
std::vector<std::pair<int, std::string>> namespaces_to_enter_;
diff --git a/init/service_test.cpp b/init/service_test.cpp
index 194aa2b..4bfaa6b 100644
--- a/init/service_test.cpp
+++ b/init/service_test.cpp
@@ -57,7 +57,7 @@
}
Service* service_in_old_memory2 = new (old_memory) Service(
- "test_old_memory", 0U, 0U, 0U, std::vector<gid_t>(), CapSet(), 0U, "", nullptr, dummy_args);
+ "test_old_memory", 0U, 0U, 0U, std::vector<gid_t>(), 0U, "", nullptr, dummy_args);
EXPECT_EQ(0U, service_in_old_memory2->flags());
EXPECT_EQ(0, service_in_old_memory2->pid());
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 0dbbc3f..b4b8cd1 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -60,7 +60,6 @@
host_supported: true,
srcs: [
"config_utils.cpp",
- "fs_config.cpp",
"canned_fs_config.cpp",
"iosched_policy.cpp",
"load_file.cpp",
@@ -80,6 +79,7 @@
not_windows: {
srcs: libcutils_nonwindows_sources + [
"ashmem-host.cpp",
+ "fs_config.cpp",
"trace-host.cpp",
],
},
@@ -104,6 +104,7 @@
srcs: libcutils_nonwindows_sources + [
"android_reboot.cpp",
"ashmem-dev.cpp",
+ "fs_config.cpp",
"klog.cpp",
"partition_utils.cpp",
"properties.cpp",
@@ -172,7 +173,10 @@
}
},
- shared_libs: ["liblog"],
+ shared_libs: [
+ "liblog",
+ "libbase",
+ ],
header_libs: [
"libbase_headers",
"libcutils_headers",
@@ -192,4 +196,71 @@
],
}
-subdirs = ["tests"]
+cc_defaults {
+ name: "libcutils_test_default",
+ srcs: ["sockets_test.cpp"],
+
+ target: {
+ android: {
+ srcs: [
+ "android_get_control_file_test.cpp",
+ "android_get_control_socket_test.cpp",
+ "ashmem_test.cpp",
+ "fs_config_test.cpp",
+ "memset_test.cpp",
+ "multiuser_test.cpp",
+ "properties_test.cpp",
+ "sched_policy_test.cpp",
+ "str_parms_test.cpp",
+ "trace-dev_test.cpp",
+ ],
+ },
+
+ not_windows: {
+ srcs: [
+ "str_parms_test.cpp",
+ ],
+ },
+ },
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+}
+
+test_libraries = [
+ "libcutils",
+ "liblog",
+ "libbase",
+ "libjsoncpp",
+ "libprocessgroup",
+]
+
+cc_test {
+ name: "libcutils_test",
+ test_suites: ["device-tests"],
+ defaults: ["libcutils_test_default"],
+ host_supported: true,
+ shared_libs: test_libraries,
+}
+
+cc_test {
+ name: "libcutils_test_static",
+ test_suites: ["device-tests"],
+ defaults: ["libcutils_test_default"],
+ static_libs: ["libc"] + test_libraries,
+ stl: "libc++_static",
+
+ target: {
+ android: {
+ static_executable: true,
+ },
+ windows: {
+ host_ldlibs: ["-lws2_32"],
+
+ enabled: true,
+ },
+ },
+}
diff --git a/libcutils/tests/android_get_control_file_test.cpp b/libcutils/android_get_control_file_test.cpp
similarity index 100%
rename from libcutils/tests/android_get_control_file_test.cpp
rename to libcutils/android_get_control_file_test.cpp
diff --git a/libcutils/tests/android_get_control_socket_test.cpp b/libcutils/android_get_control_socket_test.cpp
similarity index 100%
rename from libcutils/tests/android_get_control_socket_test.cpp
rename to libcutils/android_get_control_socket_test.cpp
diff --git a/libcutils/ashmem-dev.cpp b/libcutils/ashmem-dev.cpp
index 0cc4fc0..e35b91a 100644
--- a/libcutils/ashmem-dev.cpp
+++ b/libcutils/ashmem-dev.cpp
@@ -23,20 +23,40 @@
*/
#define LOG_TAG "ashmem"
+#ifndef __ANDROID_VNDK__
+#include <dlfcn.h>
+#endif
#include <errno.h>
#include <fcntl.h>
#include <linux/ashmem.h>
+#include <linux/memfd.h>
+#include <log/log.h>
#include <pthread.h>
+#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
+#include <sys/mman.h>
#include <sys/stat.h>
+#include <sys/syscall.h>
#include <sys/sysmacros.h>
#include <sys/types.h>
#include <unistd.h>
-#include <log/log.h>
+
+#include <android-base/properties.h>
+#include <android-base/unique_fd.h>
#define ASHMEM_DEVICE "/dev/ashmem"
+/* Will be added to UAPI once upstream change is merged */
+#define F_SEAL_FUTURE_WRITE 0x0010
+
+/*
+ * The minimum vendor API level at and after which it is safe to use memfd.
+ * This is to facilitate deprecation of ashmem.
+ */
+#define MIN_MEMFD_VENDOR_API_LEVEL 29
+#define MIN_MEMFD_VENDOR_API_LEVEL_CHAR 'Q'
+
/* ashmem identity */
static dev_t __ashmem_rdev;
/*
@@ -45,13 +65,170 @@
*/
static pthread_mutex_t __ashmem_lock = PTHREAD_MUTEX_INITIALIZER;
+/*
+ * We use ashmemd to enforce that apps don't open /dev/ashmem directly. Vendor
+ * code can't access system aidl services per Treble requirements. So we limit
+ * ashmemd access to the system variant of libcutils.
+ */
+#ifndef __ANDROID_VNDK__
+using openFdType = int (*)();
+
+openFdType initOpenAshmemFd() {
+ openFdType openFd = nullptr;
+ void* handle = dlopen("libashmemd_client.so", RTLD_NOW);
+ if (!handle) {
+ ALOGE("Failed to dlopen() libashmemd_client.so: %s", dlerror());
+ return openFd;
+ }
+
+ openFd = reinterpret_cast<openFdType>(dlsym(handle, "openAshmemdFd"));
+ if (!openFd) {
+ ALOGE("Failed to dlsym() openAshmemdFd() function: %s", dlerror());
+ }
+ return openFd;
+}
+#endif
+
+/*
+ * has_memfd_support() determines if the device can use memfd. memfd support
+ * has been there for long time, but certain things in it may be missing. We
+ * check for needed support in it. Also we check if the VNDK version of
+ * libcutils being used is new enough, if its not, then we cannot use memfd
+ * since the older copies may be using ashmem so we just use ashmem. Once all
+ * Android devices that are getting updates are new enough (ex, they were
+ * originally shipped with Android release > P), then we can just use memfd and
+ * delete all ashmem code from libcutils (while preserving the interface).
+ *
+ * NOTE:
+ * The sys.use_memfd property is set by default to false in Android
+ * to temporarily disable memfd, till vendor and apps are ready for it.
+ * The main issue: either apps or vendor processes can directly make ashmem
+ * IOCTLs on FDs they receive by assuming they are ashmem, without going
+ * through libcutils. Such fds could have very well be originally created with
+ * libcutils hence they could be memfd. Thus the IOCTLs will break.
+ *
+ * Set default value of sys.use_memfd property to true once the issue is
+ * resolved, so that the code can then self-detect if kernel support is present
+ * on the device. The property can also set to true from adb shell, for
+ * debugging.
+ */
+
+static bool debug_log = false; /* set to true for verbose logging and other debug */
+static bool pin_deprecation_warn = true; /* Log the pin deprecation warning only once */
+
+/* Determine if vendor processes would be ok with memfd in the system:
+ *
+ * If VNDK is using older libcutils, don't use memfd. This is so that the
+ * same shared memory mechanism is used across binder transactions between
+ * vendor partition processes and system partition processes.
+ */
+static bool check_vendor_memfd_allowed() {
+ std::string vndk_version = android::base::GetProperty("ro.vndk.version", "");
+
+ if (vndk_version == "") {
+ ALOGE("memfd: ro.vndk.version not defined or invalid (%s), this is mandated since P.\n",
+ vndk_version.c_str());
+ return false;
+ }
+
+ /* No issues if vendor is targetting current Dessert */
+ if (vndk_version == "current") {
+ return false;
+ }
+
+ /* Check if VNDK version is a number and act on it */
+ char* p;
+ long int vers = strtol(vndk_version.c_str(), &p, 10);
+ if (*p == 0) {
+ if (vers < MIN_MEMFD_VENDOR_API_LEVEL) {
+ ALOGI("memfd: device VNDK version (%s) is < Q so using ashmem.\n",
+ vndk_version.c_str());
+ return false;
+ }
+
+ return true;
+ }
+
+ /* If its not a number, assume string, but check if its a sane string */
+ if (tolower(vndk_version[0]) < 'a' || tolower(vndk_version[0]) > 'z') {
+ ALOGE("memfd: ro.vndk.version not defined or invalid (%s), this is mandated since P.\n",
+ vndk_version.c_str());
+ return false;
+ }
+
+ if (tolower(vndk_version[0]) < tolower(MIN_MEMFD_VENDOR_API_LEVEL_CHAR)) {
+ ALOGI("memfd: device is using VNDK version (%s) which is less than Q. Use ashmem only.\n",
+ vndk_version.c_str());
+ return false;
+ }
+
+ return true;
+}
+
+
+/* Determine if memfd can be supported. This is just one-time hardwork
+ * which will be cached by the caller.
+ */
+static bool __has_memfd_support() {
+ if (check_vendor_memfd_allowed() == false) {
+ return false;
+ }
+
+ /* Used to turn on/off the detection at runtime, in the future this
+ * property will be removed once we switch everything over to ashmem.
+ * Currently it is used only for debugging to switch the system over.
+ */
+ if (!android::base::GetBoolProperty("sys.use_memfd", false)) {
+ if (debug_log) {
+ ALOGD("sys.use_memfd=false so memfd disabled\n");
+ }
+ return false;
+ }
+
+ /* Check if kernel support exists, otherwise fall back to ashmem */
+ android::base::unique_fd fd(
+ syscall(__NR_memfd_create, "test_android_memfd", MFD_ALLOW_SEALING));
+ if (fd == -1) {
+ ALOGE("memfd_create failed: %s, no memfd support.\n", strerror(errno));
+ return false;
+ }
+
+ if (fcntl(fd, F_ADD_SEALS, F_SEAL_FUTURE_WRITE) == -1) {
+ ALOGE("fcntl(F_ADD_SEALS) failed: %s, no memfd support.\n", strerror(errno));
+ return false;
+ }
+
+ if (debug_log) {
+ ALOGD("memfd: device has memfd support, using it\n");
+ }
+ return true;
+}
+
+static bool has_memfd_support() {
+ /* memfd_supported is the initial global per-process state of what is known
+ * about memfd.
+ */
+ static bool memfd_supported = __has_memfd_support();
+
+ return memfd_supported;
+}
+
/* logistics of getting file descriptor for ashmem */
static int __ashmem_open_locked()
{
int ret;
struct stat st;
- int fd = TEMP_FAILURE_RETRY(open(ASHMEM_DEVICE, O_RDWR | O_CLOEXEC));
+ int fd = -1;
+#ifndef __ANDROID_VNDK__
+ static auto openFd = initOpenAshmemFd();
+ if (openFd) {
+ fd = openFd();
+ }
+#endif
+ if (fd < 0) {
+ fd = TEMP_FAILURE_RETRY(open(ASHMEM_DEVICE, O_RDWR | O_CLOEXEC));
+ }
if (fd < 0) {
return fd;
}
@@ -141,11 +318,49 @@
return result;
}
+static bool memfd_is_ashmem(int fd) {
+ static bool fd_check_error_once = false;
+
+ if (__ashmem_is_ashmem(fd, 0) == 0) {
+ if (!fd_check_error_once) {
+ ALOGE("memfd: memfd expected but ashmem fd used - please use libcutils.\n");
+ fd_check_error_once = true;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
int ashmem_valid(int fd)
{
+ if (has_memfd_support() && !memfd_is_ashmem(fd)) {
+ return 1;
+ }
+
return __ashmem_is_ashmem(fd, 0) >= 0;
}
+static int memfd_create_region(const char* name, size_t size) {
+ android::base::unique_fd fd(syscall(__NR_memfd_create, name, MFD_ALLOW_SEALING));
+
+ if (fd == -1) {
+ ALOGE("memfd_create(%s, %zd) failed: %s\n", name, size, strerror(errno));
+ return -1;
+ }
+
+ if (ftruncate(fd, size) == -1) {
+ ALOGE("ftruncate(%s, %zd) failed for memfd creation: %s\n", name, size, strerror(errno));
+ return -1;
+ }
+
+ if (debug_log) {
+ ALOGE("memfd_create(%s, %zd) success. fd=%d\n", name, size, fd.get());
+ }
+ return fd.release();
+}
+
/*
* ashmem_create_region - creates a new ashmem region and returns the file
* descriptor, or <0 on error
@@ -157,6 +372,10 @@
{
int ret, save_errno;
+ if (has_memfd_support()) {
+ return memfd_create_region(name ? name : "none", size);
+ }
+
int fd = __ashmem_open();
if (fd < 0) {
return fd;
@@ -186,28 +405,78 @@
return ret;
}
+static int memfd_set_prot_region(int fd, int prot) {
+ /* Only proceed if an fd needs to be write-protected */
+ if (prot & PROT_WRITE) {
+ return 0;
+ }
+
+ if (fcntl(fd, F_ADD_SEALS, F_SEAL_FUTURE_WRITE) == -1) {
+ ALOGE("memfd_set_prot_region(%d, %d): F_SEAL_FUTURE_WRITE seal failed: %s\n", fd, prot,
+ strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
int ashmem_set_prot_region(int fd, int prot)
{
+ if (has_memfd_support() && !memfd_is_ashmem(fd)) {
+ return memfd_set_prot_region(fd, prot);
+ }
+
return __ashmem_check_failure(fd, TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_PROT_MASK, prot)));
}
int ashmem_pin_region(int fd, size_t offset, size_t len)
{
+ if (!pin_deprecation_warn || debug_log) {
+ ALOGE("Pinning is deprecated since Android Q. Please use trim or other methods.\n");
+ pin_deprecation_warn = true;
+ }
+
+ if (has_memfd_support() && !memfd_is_ashmem(fd)) {
+ return 0;
+ }
+
// TODO: should LP64 reject too-large offset/len?
ashmem_pin pin = { static_cast<uint32_t>(offset), static_cast<uint32_t>(len) };
-
return __ashmem_check_failure(fd, TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_PIN, &pin)));
}
int ashmem_unpin_region(int fd, size_t offset, size_t len)
{
+ if (!pin_deprecation_warn || debug_log) {
+ ALOGE("Pinning is deprecated since Android Q. Please use trim or other methods.\n");
+ pin_deprecation_warn = true;
+ }
+
+ if (has_memfd_support() && !memfd_is_ashmem(fd)) {
+ return 0;
+ }
+
// TODO: should LP64 reject too-large offset/len?
ashmem_pin pin = { static_cast<uint32_t>(offset), static_cast<uint32_t>(len) };
-
return __ashmem_check_failure(fd, TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_UNPIN, &pin)));
}
int ashmem_get_size_region(int fd)
{
+ if (has_memfd_support() && !memfd_is_ashmem(fd)) {
+ struct stat sb;
+
+ if (fstat(fd, &sb) == -1) {
+ ALOGE("ashmem_get_size_region(%d): fstat failed: %s\n", fd, strerror(errno));
+ return -1;
+ }
+
+ if (debug_log) {
+ ALOGD("ashmem_get_size_region(%d): %d\n", fd, static_cast<int>(sb.st_size));
+ }
+
+ return sb.st_size;
+ }
+
return __ashmem_check_failure(fd, TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_GET_SIZE, NULL)));
}
diff --git a/libcutils/tests/AshmemTest.cpp b/libcutils/ashmem_test.cpp
similarity index 100%
rename from libcutils/tests/AshmemTest.cpp
rename to libcutils/ashmem_test.cpp
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index 59cbbc5..f1dcd50 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -24,6 +24,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <fnmatch.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -31,6 +32,9 @@
#include <sys/stat.h>
#include <sys/types.h>
+#include <string>
+
+#include <android-base/strings.h>
#include <log/log.h>
#include <private/android_filesystem_config.h>
#include <utils/Compat.h>
@@ -39,6 +43,9 @@
#define O_BINARY 0
#endif
+using android::base::EndsWith;
+using android::base::StartsWith;
+
// My kingdom for <endian.h>
static inline uint16_t get2LE(const uint8_t* src) {
return src[0] | (src[1] << 8);
@@ -88,6 +95,7 @@
{ 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" },
+ { 00755, AID_ROOT, AID_SHELL, 0, "system/apex/*/bin" },
{ 00751, AID_ROOT, AID_SHELL, 0, "vendor/bin" },
{ 00755, AID_ROOT, AID_SHELL, 0, "vendor" },
{ 00755, AID_ROOT, AID_ROOT, 0, 0 },
@@ -214,6 +222,7 @@
{ 00755, AID_ROOT, AID_ROOT, 0, "system/lib/valgrind/*" },
{ 00755, AID_ROOT, AID_ROOT, 0, "system/lib64/valgrind/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/xbin/*" },
+ { 00755, AID_ROOT, AID_SHELL, 0, "system/apex/*/bin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "vendor/bin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "vendor/xbin/*" },
{ 00644, AID_ROOT, AID_ROOT, 0, 0 },
@@ -253,46 +262,55 @@
// if path is "odm/<stuff>", "oem/<stuff>", "product/<stuff>",
// "product_services/<stuff>" or "vendor/<stuff>"
-static bool is_partition(const char* path, size_t len) {
+static bool is_partition(const std::string& path) {
static const char* partitions[] = {"odm/", "oem/", "product/", "product_services/", "vendor/"};
for (size_t i = 0; i < (sizeof(partitions) / sizeof(partitions[0])); ++i) {
- size_t plen = strlen(partitions[i]);
- if (len <= plen) continue;
- if (!strncmp(path, partitions[i], plen)) return true;
+ if (StartsWith(path, partitions[i])) return true;
}
return false;
}
-static inline bool prefix_cmp(bool partial, const char* prefix, size_t len, const char* path,
- size_t plen) {
- return ((partial && plen >= len) || (plen == len)) && !strncmp(prefix, path, len);
-}
-
// alias prefixes of "<partition>/<stuff>" to "system/<partition>/<stuff>" or
// "system/<partition>/<stuff>" to "<partition>/<stuff>"
-static bool fs_config_cmp(bool partial, const char* prefix, size_t len, const char* path,
- size_t plen) {
- // If name ends in * then allow partial matches.
- if (!partial && prefix[len - 1] == '*') {
- len--;
- partial = true;
+static bool fs_config_cmp(bool dir, const char* prefix, size_t len, const char* path, size_t plen) {
+ std::string pattern(prefix, len);
+ std::string input(path, plen);
+
+ // Massage pattern and input so that they can be used by fnmatch where
+ // directories have to end with /.
+ if (dir) {
+ if (!EndsWith(input, "/")) {
+ input.append("/");
+ }
+
+ if (!EndsWith(pattern, "/*")) {
+ if (EndsWith(pattern, "/")) {
+ pattern.append("*");
+ } else {
+ pattern.append("/*");
+ }
+ }
}
- if (prefix_cmp(partial, prefix, len, path, plen)) return true;
+ // no FNM_PATHNAME is set in order to match a/b/c/d with a/*
+ // FNM_ESCAPE is set in order to prevent using \\? and \\* and maintenance issues.
+ const int fnm_flags = FNM_NOESCAPE;
+ if (fnmatch(pattern.c_str(), input.c_str(), fnm_flags) == 0) return true;
- static const char system[] = "system/";
- if (!strncmp(path, system, strlen(system))) {
- path += strlen(system);
- plen -= strlen(system);
- } else if (len <= strlen(system)) {
+ static constexpr const char* kSystem = "system/";
+ if (StartsWith(input, kSystem)) {
+ input.erase(0, strlen(kSystem));
+ } else if (input.size() <= strlen(kSystem)) {
return false;
- } else if (strncmp(prefix, system, strlen(system))) {
- return false;
+ } else if (StartsWith(pattern, kSystem)) {
+ pattern.erase(0, strlen(kSystem));
} else {
- prefix += strlen(system);
- len -= strlen(system);
+ return false;
}
- return is_partition(prefix, len) && prefix_cmp(partial, prefix, len, path, plen);
+
+ if (!is_partition(pattern)) return false;
+ if (!is_partition(input)) return false;
+ return fnmatch(pattern.c_str(), input.c_str(), fnm_flags) == 0;
}
#ifndef __ANDROID_VNDK__
auto __for_testing_only__fs_config_cmp = fs_config_cmp;
diff --git a/libcutils/tests/fs_config.cpp b/libcutils/fs_config_test.cpp
similarity index 91%
rename from libcutils/tests/fs_config.cpp
rename to libcutils/fs_config_test.cpp
index d5dc66a..c26315f 100644
--- a/libcutils/tests/fs_config.cpp
+++ b/libcutils/fs_config_test.cpp
@@ -42,11 +42,15 @@
const char* path;
bool match;
} fs_config_cmp_tests[] = {
- // clang-format off
+ // clang-format off
{ true, "system/lib", "system/lib/hw", true },
{ true, "vendor/lib", "system/vendor/lib/hw", true },
{ true, "system/vendor/lib", "vendor/lib/hw", true },
{ true, "system/vendor/lib", "system/vendor/lib/hw", true },
+ { true, "foo/*/bar/*", "foo/1/bar/2", true },
+ { true, "foo/*/bar/*", "foo/1/bar", true },
+ { true, "foo/*/bar/*", "foo/1/bar/2/3", true },
+ { true, "foo/*/bar/*", "foo/1/bar/2/3/", true },
{ false, "vendor/bin/wifi", "system/vendor/bin/w", false },
{ false, "vendor/bin/wifi", "system/vendor/bin/wifi", true },
{ false, "vendor/bin/wifi", "system/vendor/bin/wifi2", false },
@@ -58,8 +62,14 @@
{ false, "vendor/bin/*", "system/vendor/bin/wifi", true },
{ false, "system/bin/*", "system/bin", false },
{ false, "system/vendor/bin/*", "vendor/bin/wifi", true },
+ { false, "foo/*/bar/*", "foo/1/bar/2", true },
+ { false, "foo/*/bar/*", "foo/1/bar", false },
+ { false, "foo/*/bar/*", "foo/1/bar/2/3", true },
+ { false, "foo/*/bar/*.so", "foo/1/bar/2/3", false },
+ { false, "foo/*/bar/*.so", "foo/1/bar/2.so", true },
+ { false, "foo/*/bar/*.so", "foo/1/bar/2/3.so", true },
{ false, NULL, NULL, false },
- // clang-format on
+ // clang-format on
};
static bool check_unique(std::vector<const char*>& paths, const std::string& config_name,
diff --git a/libcutils/tests/MemsetTest.cpp b/libcutils/memset_test.cpp
similarity index 100%
rename from libcutils/tests/MemsetTest.cpp
rename to libcutils/memset_test.cpp
diff --git a/libcutils/tests/multiuser_test.cpp b/libcutils/multiuser_test.cpp
similarity index 100%
rename from libcutils/tests/multiuser_test.cpp
rename to libcutils/multiuser_test.cpp
diff --git a/libcutils/tests/PropertiesTest.cpp b/libcutils/properties_test.cpp
similarity index 100%
rename from libcutils/tests/PropertiesTest.cpp
rename to libcutils/properties_test.cpp
diff --git a/libcutils/tests/sched_policy_test.cpp b/libcutils/sched_policy_test.cpp
similarity index 96%
rename from libcutils/tests/sched_policy_test.cpp
rename to libcutils/sched_policy_test.cpp
index 1f657e2..a321c90 100644
--- a/libcutils/tests/sched_policy_test.cpp
+++ b/libcutils/sched_policy_test.cpp
@@ -90,17 +90,18 @@
// A measureable effect of scheduling policy is that the kernel has 800x
// greater slack time in waking up a sleeping background thread.
//
- // Look for 100x difference in how long FB and BG threads actually sleep
+ // Look for 10x difference in how long FB and BG threads actually sleep
// when trying to sleep for 1 ns. This difference is large enough not
// to happen by chance, but small enough (compared to 800x) to keep inherent
// fuzziness in scheduler behavior from causing false negatives.
- const unsigned int BG_FG_SLACK_FACTOR = 100;
+ const unsigned int BG_FG_SLACK_FACTOR = 10;
ASSERT_EQ(0, set_sched_policy(0, SP_BACKGROUND));
auto bgSleepTime = medianSleepTime();
ASSERT_EQ(0, set_sched_policy(0, SP_FOREGROUND));
auto fgSleepTime = medianSleepTime();
+
ASSERT_GT(bgSleepTime, fgSleepTime * BG_FG_SLACK_FACTOR);
}
diff --git a/libcutils/tests/sockets_test.cpp b/libcutils/sockets_test.cpp
similarity index 100%
rename from libcutils/tests/sockets_test.cpp
rename to libcutils/sockets_test.cpp
diff --git a/libcutils/tests/test_str_parms.cpp b/libcutils/str_parms_test.cpp
similarity index 100%
rename from libcutils/tests/test_str_parms.cpp
rename to libcutils/str_parms_test.cpp
diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp
deleted file mode 100644
index 72ae559..0000000
--- a/libcutils/tests/Android.bp
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright (C) 2014 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-cc_defaults {
- name: "libcutils_test_default",
- srcs: ["sockets_test.cpp"],
-
- target: {
- android: {
- srcs: [
- "AshmemTest.cpp",
- "MemsetTest.cpp",
- "PropertiesTest.cpp",
- "sched_policy_test.cpp",
- "trace-dev_test.cpp",
- "test_str_parms.cpp",
- "android_get_control_socket_test.cpp",
- "android_get_control_file_test.cpp",
- "multiuser_test.cpp",
- "fs_config.cpp",
- ],
- },
-
- not_windows: {
- srcs: [
- "test_str_parms.cpp",
- ],
- },
- },
-
- multilib: {
- lib32: {
- suffix: "32",
- },
- lib64: {
- suffix: "64",
- },
- },
-
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- ],
-}
-
-test_libraries = [
- "libcutils",
- "liblog",
- "libbase",
- "libprocessgroup",
-]
-
-cc_test {
- name: "libcutils_test",
- test_suites: ["device-tests"],
- defaults: ["libcutils_test_default"],
- host_supported: true,
- shared_libs: test_libraries,
-}
-
-cc_test {
- name: "libcutils_test_static",
- test_suites: ["device-tests"],
- defaults: ["libcutils_test_default"],
- static_libs: ["libc"] + test_libraries,
- stl: "libc++_static",
-
- target: {
- android: {
- static_executable: true,
- },
- windows: {
- host_ldlibs: ["-lws2_32"],
-
- enabled: true,
- },
- },
-}
diff --git a/libcutils/tests/AndroidTest.xml b/libcutils/tests/AndroidTest.xml
deleted file mode 100644
index dd7aca2..0000000
--- a/libcutils/tests/AndroidTest.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<configuration description="Config for libcutils_test">
- <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
- <option name="cleanup" value="true" />
- <option name="push" value="libcutils_test->/data/local/tmp/libcutils_test" />
- </target_preparer>
- <option name="test-suite-tag" value="apct" />
- <test class="com.android.tradefed.testtype.GTest" >
- <option name="native-test-device-path" value="/data/local/tmp" />
- <option name="module-name" value="libcutils_test" />
- </test>
-</configuration>
\ No newline at end of file
diff --git a/libcutils/tests/trace-dev_test.cpp b/libcutils/trace-dev_test.cpp
similarity index 100%
rename from libcutils/tests/trace-dev_test.cpp
rename to libcutils/trace-dev_test.cpp
diff --git a/liblog/Android.bp b/liblog/Android.bp
index bd7a551..1d4a0a0 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -101,7 +101,6 @@
cflags: [
"-Werror",
- "-fvisibility=hidden",
// This is what we want to do:
// liblog_cflags := $(shell \
// sed -n \
diff --git a/liblog/config_read.cpp b/liblog/config_read.cpp
index 80177a4..3139f78 100644
--- a/liblog/config_read.cpp
+++ b/liblog/config_read.cpp
@@ -19,10 +19,10 @@
#include "config_read.h"
#include "logger.h"
-LIBLOG_HIDDEN struct listnode __android_log_transport_read = {&__android_log_transport_read,
- &__android_log_transport_read};
-LIBLOG_HIDDEN struct listnode __android_log_persist_read = {&__android_log_persist_read,
- &__android_log_persist_read};
+struct listnode __android_log_transport_read = {&__android_log_transport_read,
+ &__android_log_transport_read};
+struct listnode __android_log_persist_read = {&__android_log_persist_read,
+ &__android_log_persist_read};
static void __android_log_add_transport(struct listnode* list,
struct android_log_transport_read* transport) {
@@ -52,7 +52,7 @@
}
}
-LIBLOG_HIDDEN void __android_log_config_read() {
+void __android_log_config_read() {
#if (FAKE_LOG_DEVICE == 0)
if ((__android_log_transport == LOGGER_DEFAULT) || (__android_log_transport & LOGGER_LOGD)) {
extern struct android_log_transport_read logdLoggerRead;
@@ -64,7 +64,7 @@
#endif
}
-LIBLOG_HIDDEN void __android_log_config_read_close() {
+void __android_log_config_read_close() {
struct android_log_transport_read* transport;
struct listnode* n;
diff --git a/liblog/config_read.h b/liblog/config_read.h
index 00ea453..212b8a0 100644
--- a/liblog/config_read.h
+++ b/liblog/config_read.h
@@ -22,8 +22,8 @@
__BEGIN_DECLS
-extern LIBLOG_HIDDEN struct listnode __android_log_transport_read;
-extern LIBLOG_HIDDEN struct listnode __android_log_persist_read;
+extern struct listnode __android_log_transport_read;
+extern struct listnode __android_log_persist_read;
#define read_transport_for_each(transp, transports) \
for ((transp) = node_to_item((transports)->next, \
@@ -46,7 +46,7 @@
(transp) = node_to_item((n), struct android_log_transport_read, node), \
(n) = (transp)->node.next)
-LIBLOG_HIDDEN void __android_log_config_read();
-LIBLOG_HIDDEN void __android_log_config_read_close();
+void __android_log_config_read();
+void __android_log_config_read_close();
__END_DECLS
diff --git a/liblog/config_write.cpp b/liblog/config_write.cpp
index e65c238..d454379 100644
--- a/liblog/config_write.cpp
+++ b/liblog/config_write.cpp
@@ -19,10 +19,10 @@
#include "config_write.h"
#include "logger.h"
-LIBLOG_HIDDEN struct listnode __android_log_transport_write = {&__android_log_transport_write,
- &__android_log_transport_write};
-LIBLOG_HIDDEN struct listnode __android_log_persist_write = {&__android_log_persist_write,
- &__android_log_persist_write};
+struct listnode __android_log_transport_write = {&__android_log_transport_write,
+ &__android_log_transport_write};
+struct listnode __android_log_persist_write = {&__android_log_persist_write,
+ &__android_log_persist_write};
static void __android_log_add_transport(struct listnode* list,
struct android_log_transport_write* transport) {
@@ -52,7 +52,7 @@
}
}
-LIBLOG_HIDDEN void __android_log_config_write() {
+void __android_log_config_write() {
if ((__android_log_transport == LOGGER_DEFAULT) || (__android_log_transport & LOGGER_LOGD)) {
#if (FAKE_LOG_DEVICE == 0)
extern struct android_log_transport_write logdLoggerWrite;
@@ -89,7 +89,7 @@
}
}
-LIBLOG_HIDDEN void __android_log_config_write_close() {
+void __android_log_config_write_close() {
struct android_log_transport_write* transport;
struct listnode* n;
diff --git a/liblog/config_write.h b/liblog/config_write.h
index e3be445..a901f13 100644
--- a/liblog/config_write.h
+++ b/liblog/config_write.h
@@ -22,8 +22,8 @@
__BEGIN_DECLS
-extern LIBLOG_HIDDEN struct listnode __android_log_transport_write;
-extern LIBLOG_HIDDEN struct listnode __android_log_persist_write;
+extern struct listnode __android_log_transport_write;
+extern struct listnode __android_log_persist_write;
#define write_transport_for_each(transp, transports) \
for ((transp) = node_to_item((transports)->next, \
@@ -46,7 +46,7 @@
(transp) = node_to_item((n), struct android_log_transport_write, node), \
(n) = (transp)->node.next)
-LIBLOG_HIDDEN void __android_log_config_write();
-LIBLOG_HIDDEN void __android_log_config_write_close();
+void __android_log_config_write();
+void __android_log_config_write_close();
__END_DECLS
diff --git a/liblog/event_tag_map.cpp b/liblog/event_tag_map.cpp
index 574a386..22cf43b 100644
--- a/liblog/event_tag_map.cpp
+++ b/liblog/event_tag_map.cpp
@@ -407,7 +407,7 @@
//
// We create a private mapping because we want to terminate the log tag
// strings with '\0'.
-LIBLOG_ABI_PUBLIC EventTagMap* android_openEventTagMap(const char* fileName) {
+EventTagMap* android_openEventTagMap(const char* fileName) {
EventTagMap* newTagMap;
off_t end[NUM_MAPS];
int save_errno, fd[NUM_MAPS];
@@ -488,7 +488,7 @@
}
// Close the map.
-LIBLOG_ABI_PUBLIC void android_closeEventTagMap(EventTagMap* map) {
+void android_closeEventTagMap(EventTagMap* map) {
if (map) delete map;
}
@@ -535,9 +535,7 @@
}
// Look up an entry in the map.
-LIBLOG_ABI_PUBLIC const char* android_lookupEventTag_len(const EventTagMap* map,
- size_t* len,
- unsigned int tag) {
+const char* android_lookupEventTag_len(const EventTagMap* map, size_t* len, unsigned int tag) {
if (len) *len = 0;
const TagFmt* str = map->find(tag);
if (!str) {
@@ -549,8 +547,7 @@
}
// Look up an entry in the map.
-LIBLOG_ABI_PUBLIC const char* android_lookupEventFormat_len(
- const EventTagMap* map, size_t* len, unsigned int tag) {
+const char* android_lookupEventFormat_len(const EventTagMap* map, size_t* len, unsigned int tag) {
if (len) *len = 0;
const TagFmt* str = map->find(tag);
if (!str) {
@@ -565,8 +562,7 @@
// since it will cause the map to change from Shared and backed by a file,
// to Private Dirty and backed up by swap, albeit highly compressible. By
// deprecating this function everywhere, we save 100s of MB of memory space.
-LIBLOG_ABI_PUBLIC const char* android_lookupEventTag(const EventTagMap* map,
- unsigned int tag) {
+const char* android_lookupEventTag(const EventTagMap* map, unsigned int tag) {
size_t len;
const char* tagStr = android_lookupEventTag_len(map, &len, tag);
@@ -578,9 +574,7 @@
}
// Look up tagname, generate one if necessary, and return a tag
-LIBLOG_ABI_PUBLIC int android_lookupEventTagNum(EventTagMap* map,
- const char* tagname,
- const char* format, int prio) {
+int android_lookupEventTagNum(EventTagMap* map, const char* tagname, const char* format, int prio) {
const char* ep = endOfTag(tagname);
size_t len = ep - tagname;
if (!len || *ep) {
diff --git a/liblog/fake_log_device.cpp b/liblog/fake_log_device.cpp
index 5daae41..428a482 100644
--- a/liblog/fake_log_device.cpp
+++ b/liblog/fake_log_device.cpp
@@ -548,7 +548,7 @@
* tag (N bytes -- null-terminated ASCII string)
* message (N bytes -- null-terminated ASCII string)
*/
-LIBLOG_HIDDEN ssize_t fakeLogWritev(int fd, const struct iovec* vector, int count) {
+ssize_t fakeLogWritev(int fd, const struct iovec* vector, int count) {
LogState* state;
/* Make sure that no-one frees the LogState while we're using it.
@@ -623,7 +623,7 @@
* call is in the exit handler. Logging can continue in the exit handler to
* help debug HOST tools ...
*/
-LIBLOG_HIDDEN int fakeLogClose(int fd) {
+int fakeLogClose(int fd) {
deleteFakeFd(fd);
return 0;
}
@@ -631,7 +631,7 @@
/*
* Open a log output device and return a fake fd.
*/
-LIBLOG_HIDDEN int fakeLogOpen(const char* pathName) {
+int fakeLogOpen(const char* pathName) {
LogState* logState;
int fd = -1;
@@ -650,20 +650,20 @@
return fd;
}
-LIBLOG_HIDDEN ssize_t __send_log_msg(char*, size_t) {
+ssize_t __send_log_msg(char*, size_t) {
return -ENODEV;
}
-LIBLOG_ABI_PUBLIC int __android_log_is_loggable(int prio, const char*, int def) {
+int __android_log_is_loggable(int prio, const char*, int def) {
int logLevel = def;
return logLevel >= 0 && prio >= logLevel;
}
-LIBLOG_ABI_PUBLIC int __android_log_is_loggable_len(int prio, const char*, size_t, int def) {
+int __android_log_is_loggable_len(int prio, const char*, size_t, int def) {
int logLevel = def;
return logLevel >= 0 && prio >= logLevel;
}
-LIBLOG_ABI_PRIVATE int __android_log_is_debuggable() {
+int __android_log_is_debuggable() {
return 1;
}
diff --git a/liblog/fake_log_device.h b/liblog/fake_log_device.h
index ef0beb6..ce54db2 100644
--- a/liblog/fake_log_device.h
+++ b/liblog/fake_log_device.h
@@ -25,14 +25,13 @@
__BEGIN_DECLS
-LIBLOG_HIDDEN int fakeLogOpen(const char* pathName);
-LIBLOG_HIDDEN int fakeLogClose(int fd);
-LIBLOG_HIDDEN ssize_t fakeLogWritev(int fd, const struct iovec* vector,
- int count);
+int fakeLogOpen(const char* pathName);
+int fakeLogClose(int fd);
+ssize_t fakeLogWritev(int fd, const struct iovec* vector, int count);
-LIBLOG_HIDDEN ssize_t __send_log_msg(char*, size_t);
-LIBLOG_ABI_PUBLIC int __android_log_is_loggable(int prio, const char*, int def);
-LIBLOG_ABI_PUBLIC int __android_log_is_loggable_len(int prio, const char*, size_t, int def);
-LIBLOG_ABI_PRIVATE int __android_log_is_debuggable();
+ssize_t __send_log_msg(char*, size_t);
+int __android_log_is_loggable(int prio, const char*, int def);
+int __android_log_is_loggable_len(int prio, const char*, size_t, int def);
+int __android_log_is_debuggable();
__END_DECLS
diff --git a/liblog/fake_writer.cpp b/liblog/fake_writer.cpp
index 46d171b..c0b0e69 100644
--- a/liblog/fake_writer.cpp
+++ b/liblog/fake_writer.cpp
@@ -31,7 +31,7 @@
static int logFds[(int)LOG_ID_MAX] = {-1, -1, -1, -1, -1, -1};
-LIBLOG_HIDDEN struct android_log_transport_write fakeLoggerWrite = {
+struct android_log_transport_write fakeLoggerWrite = {
.node = {&fakeLoggerWrite.node, &fakeLoggerWrite.node},
.context.priv = &logFds,
.name = "fake",
diff --git a/liblog/log_event_list.cpp b/liblog/log_event_list.cpp
index 088ea94..b1b527c 100644
--- a/liblog/log_event_list.cpp
+++ b/liblog/log_event_list.cpp
@@ -73,7 +73,7 @@
context->read_write_flag = kAndroidLoggerRead;
}
-LIBLOG_ABI_PUBLIC android_log_context create_android_logger(uint32_t tag) {
+android_log_context create_android_logger(uint32_t tag) {
android_log_context_internal* context;
context =
@@ -86,7 +86,7 @@
return (android_log_context)context;
}
-LIBLOG_ABI_PUBLIC android_log_context create_android_log_parser(const char* msg, size_t len) {
+android_log_context create_android_log_parser(const char* msg, size_t len) {
android_log_context_internal* context;
size_t i;
@@ -100,7 +100,7 @@
return (android_log_context)context;
}
-LIBLOG_ABI_PUBLIC int android_log_destroy(android_log_context* ctx) {
+int android_log_destroy(android_log_context* ctx) {
android_log_context_internal* context;
context = (android_log_context_internal*)*ctx;
@@ -113,7 +113,7 @@
return 0;
}
-LIBLOG_ABI_PUBLIC int android_log_reset(android_log_context ctx) {
+int android_log_reset(android_log_context ctx) {
android_log_context_internal* context;
uint32_t tag;
@@ -129,8 +129,7 @@
return 0;
}
-LIBLOG_ABI_PUBLIC int android_log_parser_reset(android_log_context ctx, const char* msg,
- size_t len) {
+int android_log_parser_reset(android_log_context ctx, const char* msg, size_t len) {
android_log_context_internal* context;
context = (android_log_context_internal*)ctx;
@@ -144,7 +143,7 @@
return 0;
}
-LIBLOG_ABI_PUBLIC int android_log_write_list_begin(android_log_context ctx) {
+int android_log_write_list_begin(android_log_context ctx) {
size_t needed;
android_log_context_internal* context;
@@ -185,7 +184,7 @@
buf[3] = (val >> 24) & 0xFF;
}
-LIBLOG_ABI_PUBLIC int android_log_write_int32(android_log_context ctx, int32_t value) {
+int android_log_write_int32(android_log_context ctx, int32_t value) {
size_t needed;
android_log_context_internal* context;
@@ -219,7 +218,7 @@
buf[7] = (val >> 56) & 0xFF;
}
-LIBLOG_ABI_PUBLIC int android_log_write_int64(android_log_context ctx, int64_t value) {
+int android_log_write_int64(android_log_context ctx, int64_t value) {
size_t needed;
android_log_context_internal* context;
@@ -242,8 +241,7 @@
return 0;
}
-LIBLOG_ABI_PUBLIC int android_log_write_string8_len(android_log_context ctx, const char* value,
- size_t maxlen) {
+int android_log_write_string8_len(android_log_context ctx, const char* value, size_t maxlen) {
size_t needed;
ssize_t len;
android_log_context_internal* context;
@@ -278,11 +276,11 @@
return len;
}
-LIBLOG_ABI_PUBLIC int android_log_write_string8(android_log_context ctx, const char* value) {
+int android_log_write_string8(android_log_context ctx, const char* value) {
return android_log_write_string8_len(ctx, value, MAX_EVENT_PAYLOAD);
}
-LIBLOG_ABI_PUBLIC int android_log_write_float32(android_log_context ctx, float value) {
+int android_log_write_float32(android_log_context ctx, float value) {
size_t needed;
uint32_t ivalue;
android_log_context_internal* context;
@@ -307,7 +305,7 @@
return 0;
}
-LIBLOG_ABI_PUBLIC int android_log_write_list_end(android_log_context ctx) {
+int android_log_write_list_end(android_log_context ctx) {
android_log_context_internal* context;
context = (android_log_context_internal*)ctx;
@@ -337,7 +335,7 @@
/*
* Logs the list of elements to the event log.
*/
-LIBLOG_ABI_PUBLIC int android_log_write_list(android_log_context ctx, log_id_t id) {
+int android_log_write_list(android_log_context ctx, log_id_t id) {
android_log_context_internal* context;
const char* msg;
ssize_t len;
@@ -371,7 +369,7 @@
: __android_log_security_bwrite(context->tag, msg, len));
}
-LIBLOG_ABI_PRIVATE int android_log_write_list_buffer(android_log_context ctx, const char** buffer) {
+int android_log_write_list_buffer(android_log_context ctx, const char** buffer) {
android_log_context_internal* context;
const char* msg;
ssize_t len;
@@ -593,10 +591,10 @@
}
}
-LIBLOG_ABI_PUBLIC android_log_list_element android_log_read_next(android_log_context ctx) {
+android_log_list_element android_log_read_next(android_log_context ctx) {
return android_log_read_next_internal(ctx, 0);
}
-LIBLOG_ABI_PUBLIC android_log_list_element android_log_peek_next(android_log_context ctx) {
+android_log_list_element android_log_peek_next(android_log_context ctx) {
return android_log_read_next_internal(ctx, 1);
}
diff --git a/liblog/log_event_write.cpp b/liblog/log_event_write.cpp
index e644a3b..d04ba90 100644
--- a/liblog/log_event_write.cpp
+++ b/liblog/log_event_write.cpp
@@ -24,8 +24,8 @@
#define MAX_SUBTAG_LEN 32
-LIBLOG_ABI_PUBLIC int __android_log_error_write(int tag, const char* subTag, int32_t uid,
- const char* data, uint32_t dataLen) {
+int __android_log_error_write(int tag, const char* subTag, int32_t uid, const char* data,
+ uint32_t dataLen) {
int ret = -EINVAL;
if (subTag && (data || !dataLen)) {
diff --git a/liblog/log_portability.h b/liblog/log_portability.h
index b9fb1d2..468a498 100644
--- a/liblog/log_portability.h
+++ b/liblog/log_portability.h
@@ -19,25 +19,6 @@
#include <sys/cdefs.h>
#include <unistd.h>
-/* Helpful private sys/cdefs.h like definitions */
-
-/* Declare this library function hidden and internal */
-#if defined(_WIN32)
-#define LIBLOG_HIDDEN
-#else
-#define LIBLOG_HIDDEN __attribute__((visibility("hidden")))
-#endif
-
-/* Declare this library function visible and external */
-#if defined(_WIN32)
-#define LIBLOG_ABI_PUBLIC
-#else
-#define LIBLOG_ABI_PUBLIC __attribute__((visibility("default")))
-#endif
-
-/* Declare this library function visible but private */
-#define LIBLOG_ABI_PRIVATE LIBLOG_ABI_PUBLIC
-
/*
* Declare this library function as reimplementation.
* Prevent circular dependencies, but allow _real_ library to hijack
diff --git a/liblog/log_time.cpp b/liblog/log_time.cpp
index 77bb94f..3ae250f 100644
--- a/liblog/log_time.cpp
+++ b/liblog/log_time.cpp
@@ -23,12 +23,12 @@
#include "log_portability.h"
-LIBLOG_ABI_PRIVATE const char log_time::default_format[] = "%m-%d %H:%M:%S.%q";
-LIBLOG_ABI_PRIVATE const timespec log_time::EPOCH = { 0, 0 };
+const char log_time::default_format[] = "%m-%d %H:%M:%S.%q";
+const timespec log_time::EPOCH = {0, 0};
// Add %#q for fractional seconds to standard strptime function
-LIBLOG_ABI_PRIVATE char* log_time::strptime(const char* s, const char* format) {
+char* log_time::strptime(const char* s, const char* format) {
time_t now;
#ifdef __linux__
*this = log_time(CLOCK_REALTIME);
@@ -134,7 +134,7 @@
return ret;
}
-LIBLOG_ABI_PRIVATE log_time log_time::operator-=(const timespec& T) {
+log_time log_time::operator-=(const timespec& T) {
// No concept of negative time, clamp to EPOCH
if (*this <= T) {
return *this = log_time(EPOCH);
@@ -151,7 +151,7 @@
return *this;
}
-LIBLOG_ABI_PRIVATE log_time log_time::operator+=(const timespec& T) {
+log_time log_time::operator+=(const timespec& T) {
this->tv_nsec += (unsigned long int)T.tv_nsec;
if (this->tv_nsec >= NS_PER_SEC) {
this->tv_nsec -= NS_PER_SEC;
@@ -162,7 +162,7 @@
return *this;
}
-LIBLOG_ABI_PRIVATE log_time log_time::operator-=(const log_time& T) {
+log_time log_time::operator-=(const log_time& T) {
// No concept of negative time, clamp to EPOCH
if (*this <= T) {
return *this = log_time(EPOCH);
@@ -179,7 +179,7 @@
return *this;
}
-LIBLOG_ABI_PRIVATE log_time log_time::operator+=(const log_time& T) {
+log_time log_time::operator+=(const log_time& T) {
this->tv_nsec += T.tv_nsec;
if (this->tv_nsec >= NS_PER_SEC) {
this->tv_nsec -= NS_PER_SEC;
diff --git a/liblog/logd_reader.cpp b/liblog/logd_reader.cpp
index 05bbcbc..2f0af4a 100644
--- a/liblog/logd_reader.cpp
+++ b/liblog/logd_reader.cpp
@@ -67,7 +67,7 @@
static ssize_t logdGetStats(struct android_log_logger_list* logger,
struct android_log_transport_context* transp, char* buf, size_t len);
-LIBLOG_HIDDEN struct android_log_transport_read logdLoggerRead = {
+struct android_log_transport_read logdLoggerRead = {
.node = {&logdLoggerRead.node, &logdLoggerRead.node},
.name = "logd",
.available = logdAvailable,
@@ -309,7 +309,7 @@
return ret;
}
-LIBLOG_HIDDEN ssize_t __send_log_msg(char* buf, size_t buf_size) {
+ssize_t __send_log_msg(char* buf, size_t buf_size) {
return send_log_msg(NULL, NULL, buf, buf_size);
}
diff --git a/liblog/logd_reader.h b/liblog/logd_reader.h
index 0bba7cf..7c53cbb 100644
--- a/liblog/logd_reader.h
+++ b/liblog/logd_reader.h
@@ -22,6 +22,6 @@
__BEGIN_DECLS
-LIBLOG_HIDDEN ssize_t __send_log_msg(char* buf, size_t buf_size);
+ssize_t __send_log_msg(char* buf, size_t buf_size);
__END_DECLS
diff --git a/liblog/logd_writer.cpp b/liblog/logd_writer.cpp
index ed906b3..c3f72f4 100644
--- a/liblog/logd_writer.cpp
+++ b/liblog/logd_writer.cpp
@@ -48,7 +48,7 @@
static void logdClose();
static int logdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr);
-LIBLOG_HIDDEN struct android_log_transport_write logdLoggerWrite = {
+struct android_log_transport_write logdLoggerWrite = {
.node = {&logdLoggerWrite.node, &logdLoggerWrite.node},
.context.sock = -EBADF,
.name = "logd",
diff --git a/liblog/logger.h b/liblog/logger.h
index b2479d2..1f632c0 100644
--- a/liblog/logger.h
+++ b/liblog/logger.h
@@ -156,10 +156,10 @@
}
#endif
-LIBLOG_HIDDEN void __android_log_lock();
-LIBLOG_HIDDEN int __android_log_trylock();
-LIBLOG_HIDDEN void __android_log_unlock();
+void __android_log_lock();
+int __android_log_trylock();
+void __android_log_unlock();
-extern LIBLOG_HIDDEN int __android_log_transport;
+extern int __android_log_transport;
__END_DECLS
diff --git a/liblog/logger_lock.cpp b/liblog/logger_lock.cpp
index d4e3a75..4636b00 100644
--- a/liblog/logger_lock.cpp
+++ b/liblog/logger_lock.cpp
@@ -28,7 +28,7 @@
static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
#endif
-LIBLOG_HIDDEN void __android_log_lock() {
+void __android_log_lock() {
#if !defined(_WIN32)
/*
* If we trigger a signal handler in the middle of locked activity and the
@@ -38,7 +38,7 @@
#endif
}
-LIBLOG_HIDDEN int __android_log_trylock() {
+int __android_log_trylock() {
#if !defined(_WIN32)
return pthread_mutex_trylock(&log_init_lock);
#else
@@ -46,7 +46,7 @@
#endif
}
-LIBLOG_HIDDEN void __android_log_unlock() {
+void __android_log_unlock() {
#if !defined(_WIN32)
pthread_mutex_unlock(&log_init_lock);
#endif
diff --git a/liblog/logger_name.cpp b/liblog/logger_name.cpp
index c6f3cb7..3aa6841 100644
--- a/liblog/logger_name.cpp
+++ b/liblog/logger_name.cpp
@@ -35,7 +35,7 @@
/* clang-format on */
};
-LIBLOG_ABI_PUBLIC const char* android_log_id_to_name(log_id_t log_id) {
+const char* android_log_id_to_name(log_id_t log_id) {
if (log_id >= LOG_ID_MAX) {
log_id = LOG_ID_MAIN;
}
@@ -45,7 +45,7 @@
static_assert(std::is_same<std::underlying_type<log_id_t>::type, uint32_t>::value,
"log_id_t must be an unsigned int");
-LIBLOG_ABI_PUBLIC log_id_t android_name_to_log_id(const char* logName) {
+log_id_t android_name_to_log_id(const char* logName) {
const char* b;
unsigned int ret;
diff --git a/liblog/logger_read.cpp b/liblog/logger_read.cpp
index e429c36..4cf0846 100644
--- a/liblog/logger_read.cpp
+++ b/liblog/logger_read.cpp
@@ -50,7 +50,7 @@
/* android_logger_alloc unimplemented, no use case */
/* method for getting the associated sublog id */
-LIBLOG_ABI_PUBLIC log_id_t android_logger_get_id(struct logger* logger) {
+log_id_t android_logger_get_id(struct logger* logger) {
return ((struct android_log_logger*)logger)->logId;
}
@@ -139,16 +139,16 @@
} \
return ret
-LIBLOG_ABI_PUBLIC int android_logger_clear(struct logger* logger) {
+int android_logger_clear(struct logger* logger) {
LOGGER_FUNCTION(logger, -ENODEV, clear);
}
/* returns the total size of the log's ring buffer */
-LIBLOG_ABI_PUBLIC long android_logger_get_log_size(struct logger* logger) {
+long android_logger_get_log_size(struct logger* logger) {
LOGGER_FUNCTION(logger, -ENODEV, getSize);
}
-LIBLOG_ABI_PUBLIC int android_logger_set_log_size(struct logger* logger, unsigned long size) {
+int android_logger_set_log_size(struct logger* logger, unsigned long size) {
LOGGER_FUNCTION(logger, -ENODEV, setSize, size);
}
@@ -156,14 +156,14 @@
* returns the readable size of the log's ring buffer (that is, amount of the
* log consumed)
*/
-LIBLOG_ABI_PUBLIC long android_logger_get_log_readable_size(struct logger* logger) {
+long android_logger_get_log_readable_size(struct logger* logger) {
LOGGER_FUNCTION(logger, -ENODEV, getReadableSize);
}
/*
* returns the logger version
*/
-LIBLOG_ABI_PUBLIC int android_logger_get_log_version(struct logger* logger) {
+int android_logger_get_log_version(struct logger* logger) {
LOGGER_FUNCTION(logger, 4, version);
}
@@ -191,23 +191,19 @@
/*
* returns statistics
*/
-LIBLOG_ABI_PUBLIC ssize_t android_logger_get_statistics(struct logger_list* logger_list, char* buf,
- size_t len) {
+ssize_t android_logger_get_statistics(struct logger_list* logger_list, char* buf, size_t len) {
LOGGER_LIST_FUNCTION(logger_list, -ENODEV, getStats, buf, len);
}
-LIBLOG_ABI_PUBLIC ssize_t android_logger_get_prune_list(struct logger_list* logger_list, char* buf,
- size_t len) {
+ssize_t android_logger_get_prune_list(struct logger_list* logger_list, char* buf, size_t len) {
LOGGER_LIST_FUNCTION(logger_list, -ENODEV, getPrune, buf, len);
}
-LIBLOG_ABI_PUBLIC int android_logger_set_prune_list(struct logger_list* logger_list, char* buf,
- size_t len) {
+int android_logger_set_prune_list(struct logger_list* logger_list, char* buf, size_t len) {
LOGGER_LIST_FUNCTION(logger_list, -ENODEV, setPrune, buf, len);
}
-LIBLOG_ABI_PUBLIC struct logger_list* android_logger_list_alloc(int mode, unsigned int tail,
- pid_t pid) {
+struct logger_list* android_logger_list_alloc(int mode, unsigned int tail, pid_t pid) {
struct android_log_logger_list* logger_list;
logger_list = static_cast<android_log_logger_list*>(calloc(1, sizeof(*logger_list)));
@@ -224,8 +220,7 @@
return (struct logger_list*)logger_list;
}
-LIBLOG_ABI_PUBLIC struct logger_list* android_logger_list_alloc_time(int mode, log_time start,
- pid_t pid) {
+struct logger_list* android_logger_list_alloc_time(int mode, log_time start, pid_t pid) {
struct android_log_logger_list* logger_list;
logger_list = static_cast<android_log_logger_list*>(calloc(1, sizeof(*logger_list)));
@@ -246,8 +241,7 @@
/* android_logger_list_unregister unimplemented, no use case */
/* Open the named log and add it to the logger list */
-LIBLOG_ABI_PUBLIC struct logger* android_logger_open(struct logger_list* logger_list,
- log_id_t logId) {
+struct logger* android_logger_open(struct logger_list* logger_list, log_id_t logId) {
struct android_log_logger_list* logger_list_internal =
(struct android_log_logger_list*)logger_list;
struct android_log_logger* logger;
@@ -289,8 +283,8 @@
}
/* Open the single named log and make it part of a new logger list */
-LIBLOG_ABI_PUBLIC struct logger_list* android_logger_list_open(log_id_t logId, int mode,
- unsigned int tail, pid_t pid) {
+struct logger_list* android_logger_list_open(log_id_t logId, int mode, unsigned int tail,
+ pid_t pid) {
struct logger_list* logger_list = android_logger_list_alloc(mode, tail, pid);
if (!logger_list) {
@@ -345,8 +339,7 @@
}
/* Read from the selected logs */
-LIBLOG_ABI_PUBLIC int android_logger_list_read(struct logger_list* logger_list,
- struct log_msg* log_msg) {
+int android_logger_list_read(struct logger_list* logger_list, struct log_msg* log_msg) {
struct android_log_transport_context* transp;
struct android_log_logger_list* logger_list_internal =
(struct android_log_logger_list*)logger_list;
@@ -437,7 +430,7 @@
}
/* Close all the logs */
-LIBLOG_ABI_PUBLIC void android_logger_list_free(struct logger_list* logger_list) {
+void android_logger_list_free(struct logger_list* logger_list) {
struct android_log_logger_list* logger_list_internal =
(struct android_log_logger_list*)logger_list;
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
index af8cb2d..908fe7f 100644
--- a/liblog/logger_write.cpp
+++ b/liblog/logger_write.cpp
@@ -105,7 +105,7 @@
}
}
-LIBLOG_ABI_PUBLIC extern "C" int __android_log_dev_available() {
+extern "C" int __android_log_dev_available() {
struct android_log_transport_write* node;
if (list_empty(&__android_log_transport_write)) {
@@ -128,7 +128,7 @@
/*
* Release any logger resources. A new log write will immediately re-acquire.
*/
-LIBLOG_ABI_PUBLIC void __android_log_close() {
+void __android_log_close() {
struct android_log_transport_write* transport;
#if defined(__ANDROID__)
EventTagMap* m;
@@ -402,12 +402,11 @@
return ret;
}
-LIBLOG_ABI_PUBLIC int __android_log_write(int prio, const char* tag, const char* msg) {
+int __android_log_write(int prio, const char* tag, const char* msg) {
return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
}
-LIBLOG_ABI_PUBLIC int __android_log_buf_write(int bufID, int prio, const char* tag,
- const char* msg) {
+int __android_log_buf_write(int bufID, int prio, const char* tag, const char* msg) {
struct iovec vec[3];
char tmp_tag[32];
@@ -472,7 +471,7 @@
return write_to_log(static_cast<log_id_t>(bufID), vec, 3);
}
-LIBLOG_ABI_PUBLIC int __android_log_vprint(int prio, const char* tag, const char* fmt, va_list ap) {
+int __android_log_vprint(int prio, const char* tag, const char* fmt, va_list ap) {
char buf[LOG_BUF_SIZE];
vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
@@ -480,7 +479,7 @@
return __android_log_write(prio, tag, buf);
}
-LIBLOG_ABI_PUBLIC int __android_log_print(int prio, const char* tag, const char* fmt, ...) {
+int __android_log_print(int prio, const char* tag, const char* fmt, ...) {
va_list ap;
char buf[LOG_BUF_SIZE];
@@ -491,8 +490,7 @@
return __android_log_write(prio, tag, buf);
}
-LIBLOG_ABI_PUBLIC int __android_log_buf_print(int bufID, int prio, const char* tag, const char* fmt,
- ...) {
+int __android_log_buf_print(int bufID, int prio, const char* tag, const char* fmt, ...) {
va_list ap;
char buf[LOG_BUF_SIZE];
@@ -503,8 +501,7 @@
return __android_log_buf_write(bufID, prio, tag, buf);
}
-LIBLOG_ABI_PUBLIC void __android_log_assert(const char* cond, const char* tag, const char* fmt,
- ...) {
+void __android_log_assert(const char* cond, const char* tag, const char* fmt, ...) {
char buf[LOG_BUF_SIZE];
if (fmt) {
@@ -533,7 +530,7 @@
/* NOTREACHED */
}
-LIBLOG_ABI_PUBLIC int __android_log_bwrite(int32_t tag, const void* payload, size_t len) {
+int __android_log_bwrite(int32_t tag, const void* payload, size_t len) {
struct iovec vec[2];
vec[0].iov_base = &tag;
@@ -544,7 +541,7 @@
return write_to_log(LOG_ID_EVENTS, vec, 2);
}
-LIBLOG_ABI_PUBLIC int __android_log_stats_bwrite(int32_t tag, const void* payload, size_t len) {
+int __android_log_stats_bwrite(int32_t tag, const void* payload, size_t len) {
struct iovec vec[2];
vec[0].iov_base = &tag;
@@ -555,7 +552,7 @@
return write_to_log(LOG_ID_STATS, vec, 2);
}
-LIBLOG_ABI_PUBLIC int __android_log_security_bwrite(int32_t tag, const void* payload, size_t len) {
+int __android_log_security_bwrite(int32_t tag, const void* payload, size_t len) {
struct iovec vec[2];
vec[0].iov_base = &tag;
@@ -571,8 +568,7 @@
* for the general case where we're generating lists of stuff, but very
* handy if we just want to dump an integer into the log.
*/
-LIBLOG_ABI_PUBLIC int __android_log_btwrite(int32_t tag, char type, const void* payload,
- size_t len) {
+int __android_log_btwrite(int32_t tag, char type, const void* payload, size_t len) {
struct iovec vec[3];
vec[0].iov_base = &tag;
@@ -589,7 +585,7 @@
* Like __android_log_bwrite, but used for writing strings to the
* event log.
*/
-LIBLOG_ABI_PUBLIC int __android_log_bswrite(int32_t tag, const char* payload) {
+int __android_log_bswrite(int32_t tag, const char* payload) {
struct iovec vec[4];
char type = EVENT_TYPE_STRING;
uint32_t len = strlen(payload);
@@ -610,7 +606,7 @@
* Like __android_log_security_bwrite, but used for writing strings to the
* security log.
*/
-LIBLOG_ABI_PUBLIC int __android_log_security_bswrite(int32_t tag, const char* payload) {
+int __android_log_security_bswrite(int32_t tag, const char* payload) {
struct iovec vec[4];
char type = EVENT_TYPE_STRING;
uint32_t len = strlen(payload);
@@ -645,9 +641,9 @@
/* Following functions need access to our internal write_to_log status */
-LIBLOG_HIDDEN int __android_log_transport;
+int __android_log_transport;
-LIBLOG_ABI_PUBLIC int android_set_log_transport(int transport_flag) {
+int android_set_log_transport(int transport_flag) {
int retval;
if (transport_flag < 0) {
@@ -688,7 +684,7 @@
return retval;
}
-LIBLOG_ABI_PUBLIC int android_get_log_transport() {
+int android_get_log_transport() {
int ret = LOGGER_DEFAULT;
__android_log_lock();
diff --git a/liblog/logprint.cpp b/liblog/logprint.cpp
index 798b089..bc056cb 100644
--- a/liblog/logprint.cpp
+++ b/liblog/logprint.cpp
@@ -195,12 +195,12 @@
* returns 1 if this log line should be printed based on its priority
* and tag, and 0 if it should not
*/
-LIBLOG_ABI_PUBLIC int android_log_shouldPrintLine(AndroidLogFormat* p_format, const char* tag,
- android_LogPriority pri) {
+int android_log_shouldPrintLine(AndroidLogFormat* p_format, const char* tag,
+ android_LogPriority pri) {
return pri >= filterPriForTag(p_format, tag);
}
-LIBLOG_ABI_PUBLIC AndroidLogFormat* android_log_format_new() {
+AndroidLogFormat* android_log_format_new() {
AndroidLogFormat* p_ret;
p_ret = static_cast<AndroidLogFormat*>(calloc(1, sizeof(AndroidLogFormat)));
@@ -228,7 +228,7 @@
static list_declare(convertHead);
-LIBLOG_ABI_PUBLIC void android_log_format_free(AndroidLogFormat* p_format) {
+void android_log_format_free(AndroidLogFormat* p_format) {
FilterInfo *p_info, *p_info_old;
p_info = p_format->filters;
@@ -251,8 +251,7 @@
}
}
-LIBLOG_ABI_PUBLIC int android_log_setPrintFormat(AndroidLogFormat* p_format,
- AndroidLogPrintFormat format) {
+int android_log_setPrintFormat(AndroidLogFormat* p_format, AndroidLogPrintFormat format) {
switch (format) {
case FORMAT_MODIFIER_COLOR:
p_format->colored_output = true;
@@ -298,7 +297,7 @@
/**
* Returns FORMAT_OFF on invalid string
*/
-LIBLOG_ABI_PUBLIC AndroidLogPrintFormat android_log_formatFromString(const char* formatString) {
+AndroidLogPrintFormat android_log_formatFromString(const char* formatString) {
static AndroidLogPrintFormat format;
/* clang-format off */
@@ -367,8 +366,7 @@
* Assumes single threaded execution
*/
-LIBLOG_ABI_PUBLIC int android_log_addFilterRule(AndroidLogFormat* p_format,
- const char* filterExpression) {
+int android_log_addFilterRule(AndroidLogFormat* p_format, const char* filterExpression) {
size_t tagNameLength;
android_LogPriority pri = ANDROID_LOG_DEFAULT;
@@ -463,8 +461,7 @@
* Assumes single threaded execution
*
*/
-LIBLOG_ABI_PUBLIC int android_log_addFilterString(AndroidLogFormat* p_format,
- const char* filterString) {
+int android_log_addFilterString(AndroidLogFormat* p_format, const char* filterString) {
char* filterStringCopy = strdup(filterString);
char* p_cur = filterStringCopy;
char* p_ret;
@@ -496,8 +493,7 @@
* Returns 0 on success and -1 on invalid wire format (entry will be
* in unspecified state)
*/
-LIBLOG_ABI_PUBLIC int android_log_processLogBuffer(struct logger_entry* buf,
- AndroidLogEntry* entry) {
+int android_log_processLogBuffer(struct logger_entry* buf, AndroidLogEntry* entry) {
entry->message = NULL;
entry->messageLen = 0;
@@ -997,7 +993,7 @@
* it however we choose, which means we can't really use a fixed-size buffer
* here.
*/
-LIBLOG_ABI_PUBLIC int android_log_processBinaryLogBuffer(
+int android_log_processBinaryLogBuffer(
struct logger_entry* buf, AndroidLogEntry* entry,
[[maybe_unused]] const EventTagMap* map, /* only on !__ANDROID__ */
char* messageBuf, int messageBufLen) {
@@ -1525,10 +1521,9 @@
* Returns NULL on malloc error
*/
-LIBLOG_ABI_PUBLIC char* android_log_formatLogLine(AndroidLogFormat* p_format, char* defaultBuffer,
- size_t defaultBufferSize,
- const AndroidLogEntry* entry,
- size_t* p_outLength) {
+char* android_log_formatLogLine(AndroidLogFormat* p_format, char* defaultBuffer,
+ size_t defaultBufferSize, const AndroidLogEntry* entry,
+ size_t* p_outLength) {
#if !defined(_WIN32)
struct tm tmBuf;
#endif
@@ -1819,8 +1814,7 @@
* Returns count bytes written
*/
-LIBLOG_ABI_PUBLIC int android_log_printLogLine(AndroidLogFormat* p_format, int fd,
- const AndroidLogEntry* entry) {
+int android_log_printLogLine(AndroidLogFormat* p_format, int fd, const AndroidLogEntry* entry) {
int ret;
char defaultBuffer[512];
char* outBuffer = NULL;
diff --git a/liblog/pmsg_reader.cpp b/liblog/pmsg_reader.cpp
index 7bc6e4a..ba27fd7 100644
--- a/liblog/pmsg_reader.cpp
+++ b/liblog/pmsg_reader.cpp
@@ -38,7 +38,7 @@
static int pmsgClear(struct android_log_logger* logger,
struct android_log_transport_context* transp);
-LIBLOG_HIDDEN struct android_log_transport_read pmsgLoggerRead = {
+struct android_log_transport_read pmsgLoggerRead = {
.node = {&pmsgLoggerRead.node, &pmsgLoggerRead.node},
.name = "pmsg",
.available = pmsgAvailable,
@@ -270,10 +270,8 @@
return result;
}
-LIBLOG_ABI_PRIVATE ssize_t __android_log_pmsg_file_read(log_id_t logId, char prio,
- const char* prefix,
- __android_log_pmsg_file_read_fn fn,
- void* arg) {
+ssize_t __android_log_pmsg_file_read(log_id_t logId, char prio, const char* prefix,
+ __android_log_pmsg_file_read_fn fn, void* arg) {
ssize_t ret;
struct android_log_logger_list logger_list;
struct android_log_transport_context transp;
diff --git a/liblog/pmsg_writer.cpp b/liblog/pmsg_writer.cpp
index b2fc6d0..e851100 100644
--- a/liblog/pmsg_writer.cpp
+++ b/liblog/pmsg_writer.cpp
@@ -40,7 +40,7 @@
static int pmsgAvailable(log_id_t logId);
static int pmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr);
-LIBLOG_HIDDEN struct android_log_transport_write pmsgLoggerWrite = {
+struct android_log_transport_write pmsgLoggerWrite = {
.node = {&pmsgLoggerWrite.node, &pmsgLoggerWrite.node},
.context.fd = -1,
.name = "pmsg",
@@ -200,9 +200,8 @@
}
/* Write a buffer as filename references (tag = <basedir>:<basename>) */
-LIBLOG_ABI_PRIVATE ssize_t __android_log_pmsg_file_write(log_id_t logId, char prio,
- const char* filename, const char* buf,
- size_t len) {
+ssize_t __android_log_pmsg_file_write(log_id_t logId, char prio, const char* filename,
+ const char* buf, size_t len) {
bool weOpened;
size_t length, packet_len;
const char* tag;
diff --git a/liblog/properties.cpp b/liblog/properties.cpp
index 764877e..2e0a8c9 100644
--- a/liblog/properties.cpp
+++ b/liblog/properties.cpp
@@ -264,18 +264,17 @@
return default_prio;
}
-LIBLOG_ABI_PUBLIC int __android_log_is_loggable_len(int prio, const char* tag, size_t len,
- int default_prio) {
+int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio) {
int logLevel = __android_log_level(tag, len, default_prio);
return logLevel >= 0 && prio >= logLevel;
}
-LIBLOG_ABI_PUBLIC int __android_log_is_loggable(int prio, const char* tag, int default_prio) {
+int __android_log_is_loggable(int prio, const char* tag, int default_prio) {
int logLevel = __android_log_level(tag, (tag && *tag) ? strlen(tag) : 0, default_prio);
return logLevel >= 0 && prio >= logLevel;
}
-LIBLOG_ABI_PUBLIC int __android_log_is_debuggable() {
+int __android_log_is_debuggable() {
static uint32_t serial;
static struct cache_char tag_cache;
static const char key[] = "ro.debuggable";
@@ -361,7 +360,7 @@
* Timestamp state generally remains constant, but can change at any time
* to handle developer requirements.
*/
-LIBLOG_ABI_PUBLIC clockid_t android_log_clockid() {
+clockid_t android_log_clockid() {
static struct cache2_char clockid = {PTHREAD_MUTEX_INITIALIZER, 0,
"persist.logd.timestamp", {{NULL, 0xFFFFFFFF}, '\0'},
"ro.logd.timestamp", {{NULL, 0xFFFFFFFF}, '\0'},
@@ -380,7 +379,7 @@
return (c != BOOLEAN_FALSE) && c && (self->cache_persist.c == BOOLEAN_TRUE);
}
-LIBLOG_ABI_PUBLIC int __android_log_security() {
+int __android_log_security() {
static struct cache2_char security = {
PTHREAD_MUTEX_INITIALIZER, 0,
"persist.logd.security", {{NULL, 0xFFFFFFFF}, BOOLEAN_FALSE},
@@ -428,7 +427,7 @@
}
/* get boolean with the logger twist that supports eng adjustments */
-LIBLOG_ABI_PRIVATE bool __android_logger_property_get_bool(const char* key, int flag) {
+bool __android_logger_property_get_bool(const char* key, int flag) {
struct cache_property property = {{NULL, 0xFFFFFFFF}, {0}};
if (flag & BOOL_DEFAULT_FLAG_PERSIST) {
char newkey[strlen("persist.") + strlen(key) + 1];
@@ -478,7 +477,7 @@
return (flag & BOOL_DEFAULT_FLAG_TRUE_FALSE) != BOOL_DEFAULT_FALSE;
}
-LIBLOG_ABI_PRIVATE bool __android_logger_valid_buffer_size(unsigned long value) {
+bool __android_logger_valid_buffer_size(unsigned long value) {
static long pages, pagesize;
unsigned long maximum;
@@ -583,7 +582,7 @@
return property_get_size_from_cache(&self->cache_ro);
}
-LIBLOG_ABI_PRIVATE unsigned long __android_logger_get_buffer_size(log_id_t logId) {
+unsigned long __android_logger_get_buffer_size(log_id_t logId) {
static const char global_tunable[] = "persist.logd.size"; /* Settings App */
static const char global_default[] = "ro.logd.size"; /* BoardConfig.mk */
static struct cache2_property_size global = {
diff --git a/liblog/stderr_write.cpp b/liblog/stderr_write.cpp
index 28195aa..e324a7c 100644
--- a/liblog/stderr_write.cpp
+++ b/liblog/stderr_write.cpp
@@ -54,7 +54,7 @@
#endif
};
-LIBLOG_HIDDEN struct android_log_transport_write stderrLoggerWrite = {
+struct android_log_transport_write stderrLoggerWrite = {
.node = {&stderrLoggerWrite.node, &stderrLoggerWrite.node},
.context.priv = NULL,
.name = "stderr",
diff --git a/libmeminfo/libdmabufinfo/Android.bp b/libmeminfo/libdmabufinfo/Android.bp
index 3d5f2e7..4aed45c 100644
--- a/libmeminfo/libdmabufinfo/Android.bp
+++ b/libmeminfo/libdmabufinfo/Android.bp
@@ -17,9 +17,11 @@
name: "dmabufinfo_defaults",
static_libs: [
"libbase",
- "liblog",
"libprocinfo",
],
+ shared_libs: [
+ "liblog",
+ ],
cflags: [
"-Wall",
@@ -30,10 +32,9 @@
cc_library_static {
name: "libdmabufinfo",
+ vendor_available: true,
defaults: ["dmabufinfo_defaults"],
export_include_dirs: ["include"],
- static_libs: ["libc++fs"],
-
srcs: [
"dmabufinfo.cpp",
],
diff --git a/libmeminfo/libdmabufinfo/dmabufinfo.cpp b/libmeminfo/libdmabufinfo/dmabufinfo.cpp
index b4ad667..439cf68 100644
--- a/libmeminfo/libdmabufinfo/dmabufinfo.cpp
+++ b/libmeminfo/libdmabufinfo/dmabufinfo.cpp
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#include <dmabufinfo/dmabufinfo.h>
-
+#include <dirent.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
@@ -35,6 +34,8 @@
#include <android-base/strings.h>
#include <procinfo/process_map.h>
+#include <dmabufinfo/dmabufinfo.h>
+
namespace android {
namespace dmabufinfo {
@@ -80,16 +81,42 @@
return true;
}
+// TODO: std::filesystem::is_symlink fails to link on vendor code,
+// forcing this workaround.
+// Move back to libc++fs once it is vendor-available. See b/124012728
+static bool is_symlink(const char *filename)
+{
+ struct stat p_statbuf;
+ if (lstat(filename, &p_statbuf) < 0) {
+ return false;
+ }
+ if (S_ISLNK(p_statbuf.st_mode) == 1) {
+ return true;
+ }
+ return false;
+}
+
static bool ReadDmaBufFdRefs(pid_t pid, std::vector<DmaBuffer>* dmabufs) {
std::string fdpath = ::android::base::StringPrintf("/proc/%d/fd", pid);
- for (auto& de : std::filesystem::directory_iterator(fdpath)) {
- if (!std::filesystem::is_symlink(de.path())) {
+
+ std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(fdpath.c_str()), closedir);
+ if (!dir) {
+ LOG(ERROR) << "Failed to open " << fdpath << " directory" << std::endl;
+ return false;
+ }
+ struct dirent* dent;
+ while ((dent = readdir(dir.get()))) {
+ std::string path =
+ ::android::base::StringPrintf("%s/%s", fdpath.c_str(), dent->d_name);
+
+ if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..") ||
+ !is_symlink(path.c_str())) {
continue;
}
std::string target;
- if (!::android::base::Readlink(de.path().string(), &target)) {
- LOG(ERROR) << "Failed to find target for symlink: " << de.path().string();
+ if (!::android::base::Readlink(path, &target)) {
+ LOG(ERROR) << "Failed to find target for symlink: " << path;
return false;
}
@@ -98,8 +125,8 @@
}
int fd;
- if (!::android::base::ParseInt(de.path().filename().string(), &fd)) {
- LOG(ERROR) << "Dmabuf fd: " << de.path().string() << " is invalid";
+ if (!::android::base::ParseInt(dent->d_name, &fd)) {
+ LOG(ERROR) << "Dmabuf fd: " << path << " is invalid";
return false;
}
@@ -109,13 +136,13 @@
std::string exporter = "<unknown>";
uint64_t count = 0;
if (!ReadDmaBufFdInfo(pid, fd, &name, &exporter, &count)) {
- LOG(ERROR) << "Failed to read fdinfo for: " << de.path().string();
+ LOG(ERROR) << "Failed to read fdinfo for: " << path;
return false;
}
struct stat sb;
- if (stat(de.path().c_str(), &sb) < 0) {
- PLOG(ERROR) << "Failed to stat: " << de.path().string();
+ if (stat(path.c_str(), &sb) < 0) {
+ PLOG(ERROR) << "Failed to stat: " << path;
return false;
}
@@ -130,7 +157,7 @@
if (buf->count() == 0)
buf->SetCount(count);
buf->AddFdRef(pid);
- return true;
+ continue;
}
DmaBuffer& db =
diff --git a/libmeminfo/libdmabufinfo/dmabufinfo_test.cpp b/libmeminfo/libdmabufinfo/dmabufinfo_test.cpp
index 95aa2c7..eb53e57 100644
--- a/libmeminfo/libdmabufinfo/dmabufinfo_test.cpp
+++ b/libmeminfo/libdmabufinfo/dmabufinfo_test.cpp
@@ -14,14 +14,17 @@
*/
#include <gtest/gtest.h>
+#include <inttypes.h>
#include <linux/dma-buf.h>
+#include <poll.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
+#include <fstream>
#include <string>
-#include <vector>
#include <unordered_map>
+#include <vector>
#include <android-base/file.h>
#include <android-base/logging.h>
@@ -50,6 +53,115 @@
#define DMA_BUF_SET_NAME _IOW(DMA_BUF_BASE, 5, const char*)
#endif
+class fd_sharer {
+ public:
+ fd_sharer();
+ ~fd_sharer() { kill(); }
+
+ bool ok() const { return child_pid > 0; }
+ bool sendfd(int fd);
+ bool kill();
+ pid_t pid() const { return child_pid; }
+
+ private:
+ unique_fd parent_fd, child_fd;
+ pid_t child_pid;
+
+ void run();
+};
+
+fd_sharer::fd_sharer() : parent_fd{}, child_fd{}, child_pid{-1} {
+ bool sp_ok = android::base::Socketpair(SOCK_STREAM, &parent_fd, &child_fd);
+ if (!sp_ok) return;
+
+ child_pid = fork();
+ if (child_pid < 0) return;
+
+ if (child_pid == 0) run();
+}
+
+bool fd_sharer::kill() {
+ int err = ::kill(child_pid, SIGKILL);
+ if (err < 0) return false;
+
+ return ::waitpid(child_pid, nullptr, 0) == child_pid;
+}
+
+void fd_sharer::run() {
+ while (true) {
+ int fd;
+ char unused = 0;
+
+ iovec iov{};
+ iov.iov_base = &unused;
+ iov.iov_len = sizeof(unused);
+
+ msghdr msg{};
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ char cmsg_buf[CMSG_SPACE(sizeof(fd))];
+ msg.msg_control = cmsg_buf;
+ msg.msg_controllen = sizeof(cmsg_buf);
+
+ cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+
+ ssize_t s = TEMP_FAILURE_RETRY(recvmsg(child_fd, &msg, 0));
+ if (s == -1) break;
+
+ s = TEMP_FAILURE_RETRY(write(child_fd, &unused, sizeof(unused)));
+ if (s == -1) break;
+ }
+}
+
+bool fd_sharer::sendfd(int fd) {
+ char unused = 0;
+
+ iovec iov{};
+ iov.iov_base = &unused;
+ iov.iov_len = sizeof(unused);
+
+ msghdr msg{};
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ char cmsg_buf[CMSG_SPACE(sizeof(fd))];
+ msg.msg_control = cmsg_buf;
+ msg.msg_controllen = sizeof(cmsg_buf);
+
+ cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+
+ int* fd_buf = reinterpret_cast<int*>(CMSG_DATA(cmsg));
+ *fd_buf = fd;
+
+ ssize_t s = TEMP_FAILURE_RETRY(sendmsg(parent_fd, &msg, 0));
+ if (s == -1) return false;
+
+ // The target process installs the fd into its fd table during recvmsg().
+ // So if we return now, there's a brief window between sendfd() finishing
+ // and libmemoryinfo actually seeing that the buffer has been shared. This
+ // window is just large enough to break tests.
+ //
+ // To work around this, wait for the target process to respond with a dummy
+ // byte, with a timeout of 1 s.
+ pollfd p{};
+ p.fd = parent_fd;
+ p.events = POLL_IN;
+ int ready = poll(&p, 1, 1000);
+ if (ready != 1) return false;
+
+ s = TEMP_FAILURE_RETRY(read(parent_fd, &unused, sizeof(unused)));
+ if (s == -1) return false;
+
+ return true;
+}
+
#define EXPECT_ONE_BUF_EQ(_bufptr, _name, _fdrefs, _maprefs, _expname, _count, _size) \
do { \
EXPECT_EQ(_bufptr->name(), _name); \
@@ -140,6 +252,24 @@
return unique_fd{fd};
}
+ void readAndCheckDmaBuffer(std::vector<DmaBuffer>* dmabufs, pid_t pid, const std::string name,
+ size_t fdrefs_size, size_t maprefs_size, const std::string exporter,
+ size_t refcount, uint64_t buf_size, bool expectFdrefs,
+ bool expectMapRefs) {
+ EXPECT_TRUE(ReadDmaBufInfo(pid, dmabufs));
+ EXPECT_EQ(dmabufs->size(), 1UL);
+ EXPECT_ONE_BUF_EQ(dmabufs->begin(), name, fdrefs_size, maprefs_size, exporter, refcount,
+ buf_size);
+ // Make sure the buffer has the right pid too.
+ EXPECT_PID_IN_FDREFS(dmabufs->begin(), pid, expectFdrefs);
+ EXPECT_PID_IN_MAPREFS(dmabufs->begin(), pid, expectMapRefs);
+ }
+
+ bool checkPidRef(DmaBuffer& dmabuf, pid_t pid, int expectFdrefs) {
+ int fdrefs = dmabuf.fdrefs().find(pid)->second;
+ return fdrefs == expectFdrefs;
+ }
+
private:
int get_ion_heap_mask() {
if (ion_fd < 0) {
@@ -196,7 +326,7 @@
EXPECT_ONE_BUF_EQ(dmabufs.begin(), "dmabuftester-4k", 1UL, 0UL, "ion", 1UL, 4096ULL);
// Make sure the buffer has the right pid too.
- EXPECT_PID_IN_FDREFS(dmabufs.begin(), pid, false);
+ EXPECT_PID_IN_FDREFS(dmabufs.begin(), pid, true);
}
// Now make sure the buffer has disappeared
@@ -222,8 +352,8 @@
EXPECT_ONE_BUF_EQ(dmabufs.begin(), "dmabuftester-4k", 1UL, 1UL, "ion", 2UL, 4096ULL);
// Make sure the buffer has the right pid too.
- EXPECT_PID_IN_FDREFS(dmabufs.begin(), pid, false);
- EXPECT_PID_IN_MAPREFS(dmabufs.begin(), pid, false);
+ EXPECT_PID_IN_FDREFS(dmabufs.begin(), pid, true);
+ EXPECT_PID_IN_MAPREFS(dmabufs.begin(), pid, true);
// close the file descriptor and re-read the stats
buf.reset(-1);
@@ -232,8 +362,8 @@
EXPECT_EQ(dmabufs.size(), 1UL);
EXPECT_ONE_BUF_EQ(dmabufs.begin(), "<unknown>", 0UL, 1UL, "<unknown>", 0UL, 4096ULL);
- EXPECT_PID_IN_FDREFS(dmabufs.begin(), pid, true);
- EXPECT_PID_IN_MAPREFS(dmabufs.begin(), pid, false);
+ EXPECT_PID_IN_FDREFS(dmabufs.begin(), pid, false);
+ EXPECT_PID_IN_MAPREFS(dmabufs.begin(), pid, true);
// unmap the bufer and lose all references
munmap(ptr, 4096);
@@ -244,6 +374,109 @@
EXPECT_TRUE(dmabufs.empty());
}
+TEST_F(DmaBufTester, TestSharedfd) {
+ // Each time a shared buffer is received over a socket, the remote process
+ // will take an extra reference on it.
+
+ ASSERT_TRUE(is_valid());
+
+ pid_t pid = getpid();
+ std::vector<DmaBuffer> dmabufs;
+ {
+ fd_sharer sharer{};
+ ASSERT_TRUE(sharer.ok());
+ // Allocate one buffer and make sure the library can see it
+ unique_fd buf = allocate(4096, "dmabuftester-4k");
+ ASSERT_GT(buf, 0) << "Allocated buffer is invalid";
+ readAndCheckDmaBuffer(&dmabufs, pid, "dmabuftester-4k", 1UL, 0UL, "ion", 1UL, 4096ULL, true,
+ false);
+
+ ASSERT_TRUE(sharer.sendfd(buf));
+ readAndCheckDmaBuffer(&dmabufs, pid, "dmabuftester-4k", 1UL, 0UL, "ion", 2UL, 4096ULL, true,
+ false);
+ EXPECT_TRUE(checkPidRef(dmabufs[0], pid, 1));
+ readAndCheckDmaBuffer(&dmabufs, sharer.pid(), "dmabuftester-4k", 1UL, 0UL, "ion", 2UL,
+ 4096ULL, true, false);
+ EXPECT_TRUE(checkPidRef(dmabufs[0], sharer.pid(), 1));
+
+ ASSERT_TRUE(sharer.sendfd(buf));
+ readAndCheckDmaBuffer(&dmabufs, pid, "dmabuftester-4k", 1UL, 0UL, "ion", 3UL, 4096ULL, true,
+ false);
+ EXPECT_TRUE(checkPidRef(dmabufs[0], pid, 1));
+ readAndCheckDmaBuffer(&dmabufs, sharer.pid(), "dmabuftester-4k", 1UL, 0UL, "ion", 3UL,
+ 4096ULL, true, false);
+ EXPECT_TRUE(checkPidRef(dmabufs[0], sharer.pid(), 2));
+
+ ASSERT_TRUE(sharer.kill());
+ readAndCheckDmaBuffer(&dmabufs, pid, "dmabuftester-4k", 1UL, 0UL, "ion", 1UL, 4096ULL, true,
+ false);
+ }
+
+ // Now make sure the buffer has disappeared
+ ASSERT_TRUE(ReadDmaBufInfo(pid, &dmabufs));
+ EXPECT_TRUE(dmabufs.empty());
+}
+
+TEST_F(DmaBufTester, DupFdTest) {
+ // dup()ing an fd will make this process take an extra reference on the
+ // shared buffer.
+
+ ASSERT_TRUE(is_valid());
+
+ pid_t pid = getpid();
+ std::vector<DmaBuffer> dmabufs;
+ {
+ // Allocate one buffer and make sure the library can see it
+ unique_fd buf = allocate(4096, "dmabuftester-4k");
+ ASSERT_GT(buf, 0) << "Allocated buffer is invalid";
+ readAndCheckDmaBuffer(&dmabufs, pid, "dmabuftester-4k", 1UL, 0UL, "ion", 1UL, 4096ULL, true,
+ false);
+
+ unique_fd buf2{dup(buf)};
+ readAndCheckDmaBuffer(&dmabufs, pid, "dmabuftester-4k", 1UL, 0UL, "ion", 2UL, 4096ULL, true,
+ false);
+ EXPECT_TRUE(checkPidRef(dmabufs[0], pid, 2));
+
+ close(buf2.release());
+ readAndCheckDmaBuffer(&dmabufs, pid, "dmabuftester-4k", 1UL, 0UL, "ion", 1UL, 4096ULL, true,
+ false);
+ EXPECT_TRUE(checkPidRef(dmabufs[0], pid, 1));
+ }
+
+ // Now make sure the buffer has disappeared
+ ASSERT_TRUE(ReadDmaBufInfo(pid, &dmabufs));
+ EXPECT_TRUE(dmabufs.empty());
+}
+
+TEST_F(DmaBufTester, ForkTest) {
+ // fork()ing a child will cause the child to automatically take a reference
+ // on any existing shared buffers.
+ ASSERT_TRUE(is_valid());
+
+ pid_t pid = getpid();
+ std::vector<DmaBuffer> dmabufs;
+ {
+ // Allocate one buffer and make sure the library can see it
+ unique_fd buf = allocate(4096, "dmabuftester-4k");
+ ASSERT_GT(buf, 0) << "Allocated buffer is invalid";
+ readAndCheckDmaBuffer(&dmabufs, pid, "dmabuftester-4k", 1UL, 0UL, "ion", 1UL, 4096ULL, true,
+ false);
+ fd_sharer sharer{};
+ ASSERT_TRUE(sharer.ok());
+ readAndCheckDmaBuffer(&dmabufs, pid, "dmabuftester-4k", 1UL, 0UL, "ion", 2UL, 4096ULL, true,
+ false);
+ readAndCheckDmaBuffer(&dmabufs, sharer.pid(), "dmabuftester-4k", 1UL, 0UL, "ion", 2UL,
+ 4096ULL, true, false);
+ ASSERT_TRUE(sharer.kill());
+ readAndCheckDmaBuffer(&dmabufs, pid, "dmabuftester-4k", 1UL, 0UL, "ion", 1UL, 4096ULL, true,
+ false);
+ }
+
+ // Now make sure the buffer has disappeared
+ ASSERT_TRUE(ReadDmaBufInfo(pid, &dmabufs));
+ EXPECT_TRUE(dmabufs.empty());
+}
+
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
::android::base::InitLogging(argv, android::base::StderrLogger);
diff --git a/libmeminfo/libdmabufinfo/include/dmabufinfo/dmabufinfo.h b/libmeminfo/libdmabufinfo/include/dmabufinfo/dmabufinfo.h
index 74eff3c..a16c3fd 100644
--- a/libmeminfo/libdmabufinfo/include/dmabufinfo/dmabufinfo.h
+++ b/libmeminfo/libdmabufinfo/include/dmabufinfo/dmabufinfo.h
@@ -30,25 +30,29 @@
public:
DmaBuffer(ino_t inode, uint64_t size, uint64_t count, const std::string& exporter,
const std::string& name)
- : inode_(inode), size_(size), count_(count), exporter_(exporter), name_(name) {}
+ : inode_(inode), size_(size), count_(count), exporter_(exporter), name_(name) {
+ total_refs_ = 0;
+ }
~DmaBuffer() = default;
// Adds one file descriptor reference for the given pid
void AddFdRef(pid_t pid) {
AddRefToPidMap(pid, &fdrefs_);
+ total_refs_++;
}
// Adds one map reference for the given pid
void AddMapRef(pid_t pid) {
AddRefToPidMap(pid, &maprefs_);
+ total_refs_++;
}
// Getters for each property
- uint64_t size() { return size_; }
+ uint64_t size() const { return size_; }
const std::unordered_map<pid_t, int>& fdrefs() const { return fdrefs_; }
const std::unordered_map<pid_t, int>& maprefs() const { return maprefs_; }
ino_t inode() const { return inode_; }
- uint64_t total_refs() const { return fdrefs_.size() + maprefs_.size(); }
+ uint64_t total_refs() const { return total_refs_; }
uint64_t count() const { return count_; };
const std::string& name() const { return name_; }
const std::string& exporter() const { return exporter_; }
@@ -56,10 +60,16 @@
void SetExporter(const std::string& exporter) { exporter_ = exporter; }
void SetCount(uint64_t count) { count_ = count; }
+ bool operator==(const DmaBuffer& rhs) {
+ return (inode_ == rhs.inode()) && (size_ == rhs.size()) && (name_ == rhs.name()) &&
+ (exporter_ == rhs.exporter());
+ }
+
private:
ino_t inode_;
uint64_t size_;
uint64_t count_;
+ uint64_t total_refs_;
std::string exporter_;
std::string name_;
std::unordered_map<pid_t, int> fdrefs_;
@@ -76,7 +86,6 @@
// Read and return current dma buf objects from
// DEBUGFS/dma_buf/bufinfo. The references to each dma buffer are not
// populated here and will return an empty vector.
-//
// Returns false if something went wrong with the function, true otherwise.
bool ReadDmaBufInfo(std::vector<DmaBuffer>* dmabufs,
const std::string& path = "/sys/kernel/debug/dma_buf/bufinfo");
@@ -84,13 +93,13 @@
// Read and return dmabuf objects for a given process without the help
// of DEBUGFS
-//
// Returns false if something went wrong with the function, true otherwise.
bool ReadDmaBufInfo(pid_t pid, std::vector<DmaBuffer>* dmabufs);
-// Append dmabuf objects for a given process without the help
-// of DEBUGFS to an existing vector
-//
+// Append new dmabuf objects from a given process to an existing vector.
+// When the vector contains an existing element with a matching inode,
+// the reference counts will be updated.
+// Does not depend on DEBUGFS.
// Returns false if something went wrong with the function, true otherwise.
bool AppendDmaBufInfo(pid_t pid, std::vector<DmaBuffer>* dmabufs);
diff --git a/libmeminfo/libdmabufinfo/tools/Android.bp b/libmeminfo/libdmabufinfo/tools/Android.bp
new file mode 100644
index 0000000..0af3c48
--- /dev/null
+++ b/libmeminfo/libdmabufinfo/tools/Android.bp
@@ -0,0 +1,30 @@
+// 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_binary {
+ name: "dmabuf_dump",
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ srcs: ["dmabuf_dump.cpp"],
+ shared_libs: [
+ "libbase",
+ ],
+ static_libs: [
+ "libdmabufinfo",
+ ],
+ soc_specific: true,
+}
\ No newline at end of file
diff --git a/libmeminfo/libdmabufinfo/tools/dmabuf_dump.cpp b/libmeminfo/libdmabufinfo/tools/dmabuf_dump.cpp
new file mode 100644
index 0000000..0851fb3
--- /dev/null
+++ b/libmeminfo/libdmabufinfo/tools/dmabuf_dump.cpp
@@ -0,0 +1,185 @@
+/*
+ * 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 <dirent.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <string>
+#include <vector>
+#include <map>
+#include <set>
+
+#include <android-base/stringprintf.h>
+#include <dmabufinfo/dmabufinfo.h>
+
+using DmaBuffer = ::android::dmabufinfo::DmaBuffer;
+
+[[noreturn]] static void usage(int exit_status) {
+ fprintf(stderr,
+ "Usage: %s [PID] \n"
+ "\t If PID is supplied, the dmabuf information for this process is shown.\n"
+ "\t Otherwise, shows the information for all processes.\n",
+ getprogname());
+
+ exit(exit_status);
+}
+
+static std::string GetProcessBaseName(pid_t pid) {
+ std::string pid_path = android::base::StringPrintf("/proc/%d/comm", pid);
+ std::ifstream in{pid_path};
+ if (!in) return std::string("N/A");
+ std::string line;
+ std::getline(in, line);
+ if (!in) return std::string("N/A");
+ return line;
+}
+
+static void AddPidsToSet(const std::unordered_map<pid_t, int>& map, std::set<pid_t>* set)
+{
+ for (auto it = map.begin(); it != map.end(); ++it)
+ set->insert(it->first);
+}
+
+static void PrintDmaBufInfo(const std::vector<DmaBuffer>& bufs) {
+ std::set<pid_t> pid_set;
+ std::map<pid_t, int> pid_column;
+
+ if (bufs.empty()) {
+ std::cout << "dmabuf info not found ¯\\_(ツ)_/¯" << std::endl;
+ return;
+ }
+
+ // Find all unique pids in the input vector, create a set
+ for (int i = 0; i < bufs.size(); i++) {
+ AddPidsToSet(bufs[i].fdrefs(), &pid_set);
+ AddPidsToSet(bufs[i].maprefs(), &pid_set);
+ }
+
+ int pid_count = 0;
+
+ std::cout << "\t\t\t\t\t\t";
+
+ // Create a map to convert each unique pid into a column number
+ for (auto it = pid_set.begin(); it != pid_set.end(); ++it, ++pid_count) {
+ pid_column.insert(std::make_pair(*it, pid_count));
+ std::cout << ::android::base::StringPrintf("[pid: % 4d]\t", *it);
+ }
+
+ std::cout << std::endl << "\t\t\t\t\t\t";
+
+ for (auto it = pid_set.begin(); it != pid_set.end(); ++it) {
+ std::cout << ::android::base::StringPrintf("%16s",
+ GetProcessBaseName(*it).c_str());
+ }
+
+ std::cout << std::endl << "\tinode\t\tsize\t\tcount\t";
+ for (int i = 0; i < pid_count; i++) {
+ std::cout << "fd\tmap\t";
+ }
+ std::cout << std::endl;
+
+ auto fds = std::make_unique<int[]>(pid_count);
+ auto maps = std::make_unique<int[]>(pid_count);
+ auto pss = std::make_unique<long[]>(pid_count);
+
+ memset(pss.get(), 0, sizeof(long) * pid_count);
+
+ for (auto buf = bufs.begin(); buf != bufs.end(); ++buf) {
+
+ std::cout << ::android::base::StringPrintf("%16lu\t%10" PRIu64 "\t%" PRIu64 "\t",
+ buf->inode(),buf->size(), buf->count());
+
+ memset(fds.get(), 0, sizeof(int) * pid_count);
+ memset(maps.get(), 0, sizeof(int) * pid_count);
+
+ for (auto it = buf->fdrefs().begin(); it != buf->fdrefs().end(); ++it) {
+ fds[pid_column[it->first]] = it->second;
+ pss[pid_column[it->first]] += buf->size() * it->second / buf->count();
+ }
+
+ for (auto it = buf->maprefs().begin(); it != buf->maprefs().end(); ++it) {
+ maps[pid_column[it->first]] = it->second;
+ pss[pid_column[it->first]] += buf->size() * it->second / buf->count();
+ }
+
+ for (int i = 0; i < pid_count; i++) {
+ std::cout << ::android::base::StringPrintf("%d\t%d\t", fds[i], maps[i]);
+ }
+ std::cout << std::endl;
+ }
+ std::cout << "-----------------------------------------" << std::endl;
+ std::cout << "PSS ";
+ for (int i = 0; i < pid_count; i++) {
+ std::cout << ::android::base::StringPrintf("%15ldK", pss[i] / 1024);
+ }
+ std::cout << std::endl;
+}
+
+int main(int argc, char* argv[]) {
+ pid_t pid = -1;
+ std::vector<DmaBuffer> bufs;
+ bool show_all = true;
+
+ if (argc > 1) {
+ if (sscanf(argv[1], "%d", &pid) == 1) {
+ show_all = false;
+ }
+ else {
+ usage(EXIT_FAILURE);
+ }
+ }
+
+ if (show_all) {
+ if (!ReadDmaBufInfo(&bufs)) {
+ std::cerr << "debugfs entry for dmabuf not available, skipping" << std::endl;
+ bufs.clear();
+ }
+ std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir("/proc"), closedir);
+ if (!dir) {
+ std::cerr << "Failed to open /proc directory" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ struct dirent* dent;
+ while ((dent = readdir(dir.get()))) {
+ if (dent->d_type != DT_DIR) continue;
+
+ int matched = sscanf(dent->d_name, "%d", &pid);
+ if (matched != 1) {
+ continue;
+ }
+
+ if (!AppendDmaBufInfo(pid, &bufs)) {
+ std::cerr << "Unable to read dmabuf info for pid " << pid << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ }
+ } else {
+ if (!ReadDmaBufInfo(pid, &bufs)) {
+ std::cerr << "Unable to read dmabuf info" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ }
+ PrintDmaBufInfo(bufs);
+ return 0;
+}
+
+
diff --git a/libmeminfo/vts/Android.bp b/libmeminfo/vts/Android.bp
new file mode 100644
index 0000000..5a3a23b
--- /dev/null
+++ b/libmeminfo/vts/Android.bp
@@ -0,0 +1,20 @@
+// 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_test {
+ name: "vts_meminfo_test",
+ defaults: ["libmeminfo_defaults"],
+ srcs: ["vts_meminfo_test.cpp"],
+ static_libs: ["libmeminfo"],
+}
diff --git a/libmeminfo/vts/Android.mk b/libmeminfo/vts/Android.mk
new file mode 100644
index 0000000..62d68d9
--- /dev/null
+++ b/libmeminfo/vts/Android.mk
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := VtsKernelMemInfoTest
+-include test/vts/tools/build/Android.host_config.mk
diff --git a/libmeminfo/vts/AndroidTest.xml b/libmeminfo/vts/AndroidTest.xml
new file mode 100644
index 0000000..530d16e
--- /dev/null
+++ b/libmeminfo/vts/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?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 VtsKernelMemInfoTest.">
+ <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="VtsKernelMemInfoTest"/>
+ <option name="binary-test-source" value="_32bit::DATA/nativetest/vts_meminfo_test/vts_meminfo_test" />
+ <option name="binary-test-source" value="_64bit::DATA/nativetest64/vts_meminfo_test/vts_meminfo_test" />
+ <option name="binary-test-type" value="gtest"/>
+ <option name="test-timeout" value="10m"/>
+ </test>
+</configuration>
diff --git a/libmeminfo/vts/vts_meminfo_test.cpp b/libmeminfo/vts/vts_meminfo_test.cpp
new file mode 100644
index 0000000..3193c31
--- /dev/null
+++ b/libmeminfo/vts/vts_meminfo_test.cpp
@@ -0,0 +1,31 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include <meminfo/procmeminfo.h>
+
+namespace android {
+namespace meminfo {
+
+// /proc/<pid>/smaps_rollup support is required.
+TEST(SmapsRollup, IsSupported) {
+ // Use init's pid for this test since it's the only known pid.
+ ASSERT_TRUE(IsSmapsRollupSupported(1));
+}
+
+} // namespace meminfo
+} // namespace android
diff --git a/libnativebridge/include/nativebridge/native_bridge.h b/libnativebridge/include/nativebridge/native_bridge.h
index 5aea967..e9c9500 100644
--- a/libnativebridge/include/nativebridge/native_bridge.h
+++ b/libnativebridge/include/nativebridge/native_bridge.h
@@ -164,8 +164,9 @@
void* NativeBridgeLoadLibraryExt(const char* libpath, int flag,
struct native_bridge_namespace_t* ns);
-// Returns vendor namespace if it is enabled for the device and null otherwise
-struct native_bridge_namespace_t* NativeBridgeGetVendorNamespace();
+// Returns exported namespace by the name. This is a reflection of
+// android_get_exported_namespace function. Introduced in v5.
+struct native_bridge_namespace_t* NativeBridgeGetExportedNamespace(const char* name);
// Native bridge interfaces to runtime.
struct NativeBridgeCallbacks {
@@ -362,7 +363,17 @@
//
// Returns:
// vendor namespace or null if it was not set up for the device
+ //
+ // Starting with v5 (Android Q) this function is no longer used.
+ // Use getExportedNamespace() below.
struct native_bridge_namespace_t* (*getVendorNamespace)();
+
+ // Get native bridge version of exported namespace. Peer of
+ // android_get_exported_namespace(const char*) function.
+ //
+ // Returns:
+ // exported namespace or null if it was not set up for the device
+ struct native_bridge_namespace_t* (*getExportedNamespace)(const char* name);
};
// Runtime interfaces to native bridge.
diff --git a/libnativebridge/libnativebridge.map.txt b/libnativebridge/libnativebridge.map.txt
index a616b85..a6841a3 100644
--- a/libnativebridge/libnativebridge.map.txt
+++ b/libnativebridge/libnativebridge.map.txt
@@ -24,7 +24,7 @@
NativeBridgeGetError;
NativeBridgeIsPathSupported;
NativeBridgeCreateNamespace;
- NativeBridgeGetVendorNamespace;
+ NativeBridgeGetExportedNamespace;
NativeBridgeLinkNamespaces;
NativeBridgeLoadLibraryExt;
NativeBridgeInitAnonymousNamespace;
diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc
index a2d8d81..9adba9a 100644
--- a/libnativebridge/native_bridge.cc
+++ b/libnativebridge/native_bridge.cc
@@ -101,6 +101,8 @@
NAMESPACE_VERSION = 3,
// The version with vendor namespaces
VENDOR_NAMESPACE_VERSION = 4,
+ // The version with runtime namespaces
+ RUNTIME_NAMESPACE_VERSION = 5,
};
// Whether we had an error at some point.
@@ -610,12 +612,22 @@
return false;
}
-native_bridge_namespace_t* NativeBridgeGetVendorNamespace() {
- if (!NativeBridgeInitialized() || !isCompatibleWith(VENDOR_NAMESPACE_VERSION)) {
+native_bridge_namespace_t* NativeBridgeGetExportedNamespace(const char* name) {
+ if (!NativeBridgeInitialized()) {
return nullptr;
}
- return callbacks->getVendorNamespace();
+ if (isCompatibleWith(RUNTIME_NAMESPACE_VERSION)) {
+ return callbacks->getExportedNamespace(name);
+ }
+
+ // sphal is vendor namespace name -> use v4 callback in the case NB callbacks
+ // are not compatible with v5
+ if (isCompatibleWith(VENDOR_NAMESPACE_VERSION) && name != nullptr && strcmp("sphal", name) == 0) {
+ return callbacks->getVendorNamespace();
+ }
+
+ return nullptr;
}
void* NativeBridgeLoadLibraryExt(const char* libpath, int flag, native_bridge_namespace_t* ns) {
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index ad967db..5394d7e 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -103,6 +103,11 @@
static constexpr const char kVndkspNativeLibrariesSystemConfigPathFromRoot[] =
"/etc/vndksp.libraries.txt";
+static const std::vector<const std::string> kRuntimePublicLibraries = {
+ "libicuuc.so",
+ "libicui18n.so",
+};
+
// The device may be configured to have the vendor libraries loaded to a separate namespace.
// For historical reasons this namespace was named sphal but effectively it is intended
// to use to load vendor libraries to separate namespace with controlled interface between
@@ -111,7 +116,18 @@
static constexpr const char* kVndkNamespaceName = "vndk";
+static constexpr const char* kRuntimeNamespaceName = "runtime";
+
+// classloader-namespace is a linker namespace that is created for the loaded
+// app. To be specific, it is created for the app classloader. When
+// System.load() is called from a Java class that is loaded from the
+// classloader, the classloader-namespace namespace associated with that
+// classloader is selected for dlopen. The namespace is configured so that its
+// search path is set to the app-local JNI directory and it is linked to the
+// default namespace with the names of libs listed in the public.libraries.txt.
+// This way an app can only load its own JNI libraries along with the public libs.
static constexpr const char* kClassloaderNamespaceName = "classloader-namespace";
+// Same thing for vendor APKs.
static constexpr const char* kVendorClassloaderNamespaceName = "vendor-classloader-namespace";
// (http://b/27588281) This is a workaround for apps using custom classloaders and calling
@@ -245,6 +261,8 @@
}
}
+ std::string runtime_exposed_libraries = base::Join(kRuntimePublicLibraries, ":");
+
NativeLoaderNamespace native_loader_ns;
if (!is_native_bridge) {
android_namespace_t* android_parent_ns =
@@ -265,11 +283,21 @@
// which is expected behavior in this case.
android_namespace_t* vendor_ns = android_get_exported_namespace(kVendorNamespaceName);
+ android_namespace_t* runtime_ns = android_get_exported_namespace(kRuntimeNamespaceName);
+
if (!android_link_namespaces(ns, nullptr, system_exposed_libraries.c_str())) {
*error_msg = dlerror();
return nullptr;
}
+ // Runtime apex does not exist in host, and under certain build conditions.
+ if (runtime_ns != nullptr) {
+ if (!android_link_namespaces(ns, runtime_ns, runtime_exposed_libraries.c_str())) {
+ *error_msg = dlerror();
+ return nullptr;
+ }
+ }
+
if (vndk_ns != nullptr && !system_vndksp_libraries_.empty()) {
// vendor apks are allowed to use VNDK-SP libraries.
if (!android_link_namespaces(ns, vndk_ns, system_vndksp_libraries_.c_str())) {
@@ -300,13 +328,22 @@
return nullptr;
}
- native_bridge_namespace_t* vendor_ns = NativeBridgeGetVendorNamespace();
+ native_bridge_namespace_t* vendor_ns = NativeBridgeGetExportedNamespace(kVendorNamespaceName);
+ native_bridge_namespace_t* runtime_ns =
+ NativeBridgeGetExportedNamespace(kRuntimeNamespaceName);
if (!NativeBridgeLinkNamespaces(ns, nullptr, system_exposed_libraries.c_str())) {
*error_msg = NativeBridgeGetError();
return nullptr;
}
+ // Runtime apex does not exist in host, and under certain build conditions.
+ if (runtime_ns != nullptr) {
+ if (!NativeBridgeLinkNamespaces(ns, runtime_ns, runtime_exposed_libraries.c_str())) {
+ *error_msg = NativeBridgeGetError();
+ return nullptr;
+ }
+ }
if (!vendor_public_libraries_.empty()) {
if (!NativeBridgeLinkNamespaces(ns, vendor_ns, vendor_public_libraries_.c_str())) {
*error_msg = NativeBridgeGetError();
diff --git a/libnetutils/OWNERS b/libnetutils/OWNERS
index e3ec950..8321de6 100644
--- a/libnetutils/OWNERS
+++ b/libnetutils/OWNERS
@@ -1,3 +1,2 @@
-# TODO: should this be in system/netd?
-ek@google.com
-lorenzo@google.com
+include platform/system/netd:/OWNERS
+
diff --git a/libpixelflinger/tests/Android.bp b/libpixelflinger/tests/Android.bp
index 820a84d..e20dd93 100644
--- a/libpixelflinger/tests/Android.bp
+++ b/libpixelflinger/tests/Android.bp
@@ -8,6 +8,7 @@
header_libs: ["libpixelflinger_internal"],
static_libs: [
+ "libbase",
"libcutils",
"liblog",
"libpixelflinger",
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index d04a79a..d97f09f 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -16,8 +16,10 @@
cc_library {
srcs: [
+ "cgroup_map.cpp",
"processgroup.cpp",
"sched_policy.cpp",
+ "task_profiles.cpp",
],
name: "libprocessgroup",
host_supported: true,
@@ -29,7 +31,7 @@
},
shared_libs: [
"libbase",
- "liblog",
+ "libjsoncpp",
],
// for cutils/android_filesystem_config.h
header_libs: [
diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp
new file mode 100644
index 0000000..cd8ef94
--- /dev/null
+++ b/libprocessgroup/cgroup_map.cpp
@@ -0,0 +1,421 @@
+/*
+ * 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 <cgroup_map.h>
+#include <json/reader.h>
+#include <json/value.h>
+#include <processgroup/processgroup.h>
+
+using android::base::GetBoolProperty;
+using android::base::StringPrintf;
+using android::base::unique_fd;
+
+static constexpr const char* CGROUPS_DESC_FILE = "/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;
+}
+
+static bool ReadDescriptors(std::map<std::string, CgroupDescriptor>* descriptors) {
+ std::vector<CgroupDescriptor> result;
+ std::string json_doc;
+
+ if (!android::base::ReadFileToString(CGROUPS_DESC_FILE, &json_doc)) {
+ LOG(ERROR) << "Failed to read task profiles from " << CGROUPS_DESC_FILE;
+ 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;
+ }
+
+ Json::Value cgroups = root["Cgroups"];
+ for (Json::Value::ArrayIndex i = 0; i < cgroups.size(); ++i) {
+ std::string name = cgroups[i]["Controller"].asString();
+ descriptors->emplace(std::make_pair(
+ 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())));
+ }
+
+ Json::Value cgroups2 = root["Cgroups2"];
+ descriptors->emplace(std::make_pair(
+ 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())));
+
+ return true;
+}
+
+// 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())) {
+ PLOG(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) {
+ 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,
+ pid_t pid) const {
+ std::string proc_path(path_);
+ proc_path.append("/").append(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));
+
+ return proc_path.append(CGROUP_PROCS_FILE);
+}
+
+bool CgroupController::GetTaskGroup(int tid, std::string* group) const {
+ std::string file_name = StringPrintf("/proc/%d/cgroup", tid);
+ std::string content;
+ if (!android::base::ReadFileToString(file_name, &content)) {
+ LOG(ERROR) << "Failed to read " << file_name;
+ return false;
+ }
+
+ // if group is null and tid exists return early because
+ // user is not interested in cgroup membership
+ if (group == nullptr) {
+ return true;
+ }
+
+ std::string cg_tag = StringPrintf(":%s:", name_);
+ size_t start_pos = content.find(cg_tag);
+ if (start_pos == std::string::npos) {
+ return false;
+ }
+
+ start_pos += cg_tag.length() + 1; // skip '/'
+ size_t end_pos = content.find('\n', start_pos);
+ if (end_pos == std::string::npos) {
+ *group = content.substr(start_pos, std::string::npos);
+ } else {
+ *group = content.substr(start_pos, end_pos - start_pos);
+ }
+
+ 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) {
+ if (!LoadRcFile()) {
+ PLOG(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() {
+ static CgroupMap instance;
+ return instance;
+}
+
+bool CgroupMap::LoadRcFile() {
+ struct stat sb;
+
+ if (cg_file_data_) {
+ // Data already initialized
+ return true;
+ }
+
+ 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;
+ }
+
+ cg_file_size_ = sb.st_size;
+ if (cg_file_size_ < sizeof(CgroupFile)) {
+ PLOG(ERROR) << "Invalid file format " << cgroup_rc_path;
+ return false;
+ }
+
+ cg_file_data_ = (CgroupFile*)mmap(nullptr, cg_file_size_, PROT_READ, MAP_SHARED, fd, 0);
+ if (cg_file_data_ == MAP_FAILED) {
+ PLOG(ERROR) << "Failed to mmap " << cgroup_rc_path;
+ return false;
+ }
+
+ if (cg_file_data_->version_ != CgroupFile::FILE_CURR_VERSION) {
+ PLOG(ERROR) << cgroup_rc_path << " file version mismatch";
+ return false;
+ }
+
+ return true;
+}
+
+void CgroupMap::Print() {
+ LOG(INFO) << "File version = " << cg_file_data_->version_;
+ LOG(INFO) << "File controller count = " << cg_file_data_->controller_count_;
+
+ 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();
+ }
+}
+
+bool CgroupMap::SetupCgroups() {
+ std::map<std::string, CgroupDescriptor> descriptors;
+
+ // load cgroups.json file
+ if (!ReadDescriptors(&descriptors)) {
+ PLOG(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")) {
+ PLOG(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) {
+ LOG(ERROR) << "fchmodat() failed";
+ return false;
+ }
+
+ return true;
+}
+
+const CgroupController* CgroupMap::FindController(const std::string& name) const {
+ if (!cg_file_data_) {
+ return 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;
+ }
+ }
+
+ return nullptr;
+}
diff --git a/libprocessgroup/cgroup_map.h b/libprocessgroup/cgroup_map.h
new file mode 100644
index 0000000..ba2caf7
--- /dev/null
+++ b/libprocessgroup/cgroup_map.h
@@ -0,0 +1,96 @@
+/*
+ * 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 <sys/cdefs.h>
+#include <sys/types.h>
+
+#include <map>
+#include <mutex>
+#include <string>
+
+// Minimal controller description to be mmapped into process address space
+class CgroupController {
+ public:
+ CgroupController() {}
+ CgroupController(uint32_t version, const std::string& name, const std::string& path);
+
+ uint32_t version() const { return version_; }
+ const char* name() const { return name_; }
+ const char* path() const { return path_; }
+
+ 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_[];
+};
+
+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;
+
+ private:
+ struct CgroupFile* cg_file_data_;
+ size_t cg_file_size_;
+
+ CgroupMap();
+ ~CgroupMap();
+
+ bool LoadRcFile();
+ void Print();
+};
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index 2412f3c..6f973b8 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -14,14 +14,28 @@
* limitations under the License.
*/
-#ifndef _PROCESSGROUP_H_
-#define _PROCESSGROUP_H_
+#pragma once
#include <sys/cdefs.h>
#include <sys/types.h>
+#include <string>
+#include <vector>
__BEGIN_DECLS
+static constexpr const char* CGROUPV2_CONTROLLER_NAME = "cgroup2";
+static constexpr const char* CGROUPS_RC_DIR = "/dev/cgroup_info";
+
+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);
+
+bool UsePerAppMemcg();
+
+bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles);
+bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles);
+
// Return 0 and removes the cgroup if there are no longer any processes in it.
// Returns -1 in the case of an error occurring or if there are processes still running
// even after retrying for up to 200ms.
@@ -42,5 +56,3 @@
void removeAllProcessGroups(void);
__END_DECLS
-
-#endif
diff --git a/libprocessgroup/include/processgroup/sched_policy.h b/libprocessgroup/include/processgroup/sched_policy.h
index 79a32fd..3c498da 100644
--- a/libprocessgroup/include/processgroup/sched_policy.h
+++ b/libprocessgroup/include/processgroup/sched_policy.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -67,13 +67,13 @@
* On platforms which support gettid(), zero tid means current thread.
* Return value: 0 for success, or -1 for error and set errno.
*/
-extern int get_sched_policy(int tid, SchedPolicy *policy);
+extern int get_sched_policy(int tid, SchedPolicy* policy);
/* Return a displayable string corresponding to policy.
* Return value: non-NULL NUL-terminated name of unspecified length;
* the caller is responsible for displaying the useful part of the string.
*/
-extern const char *get_sched_policy_name(SchedPolicy policy);
+extern const char* get_sched_policy_name(SchedPolicy policy);
#ifdef __cplusplus
}
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 8d2ac3d..e9dec12 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -25,12 +25,12 @@
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <chrono>
+#include <map>
#include <memory>
#include <mutex>
#include <set>
@@ -43,8 +43,8 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <cutils/android_filesystem_config.h>
-
#include <processgroup/processgroup.h>
+#include <task_profiles.h>
using android::base::GetBoolProperty;
using android::base::StartsWith;
@@ -53,16 +53,103 @@
using namespace std::chrono_literals;
-static const char kCpuacctCgroup[] = "/acct";
-static const char kMemoryCgroup[] = "/dev/memcg/apps";
-
#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);
+
+ if (controller == nullptr) {
+ return false;
+ }
+
+ if (path) {
+ *path = controller->path();
+ }
+
+ return true;
+}
+
+bool CgroupGetAttributePath(const std::string& attr_name, std::string* path) {
+ const TaskProfiles& tp = TaskProfiles::GetInstance();
+ const ProfileAttribute* attr = tp.GetAttribute(attr_name);
+
+ if (attr == nullptr) {
+ return false;
+ }
+
+ if (path) {
+ *path = StringPrintf("%s/%s", attr->controller()->path(), attr->file_name().c_str());
+ }
+
+ return true;
+}
+
+bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path) {
+ const TaskProfiles& tp = TaskProfiles::GetInstance();
+ const ProfileAttribute* attr = tp.GetAttribute(attr_name);
+
+ if (attr == nullptr) {
+ return false;
+ }
+
+ if (!attr->GetPathForTask(tid, path)) {
+ PLOG(ERROR) << "Failed to find cgroup for tid " << tid;
+ return false;
+ }
+
+ return true;
+}
+
+bool UsePerAppMemcg() {
+ bool low_ram_device = GetBoolProperty("ro.config.low_ram", false);
+ return GetBoolProperty("ro.config.per_app_memcg", low_ram_device);
+}
+
static bool isMemoryCgroupSupported() {
- static bool memcg_supported = !access("/dev/memcg/memory.limit_in_bytes", F_OK);
+ std::string cgroup_name;
+ static bool memcg_supported = (CgroupMap::GetInstance().FindController("memory") != nullptr);
+
return memcg_supported;
}
+bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles) {
+ const TaskProfiles& tp = TaskProfiles::GetInstance();
+
+ for (const auto& name : profiles) {
+ const TaskProfile* profile = tp.GetProfile(name);
+ if (profile != nullptr) {
+ if (!profile->ExecuteForProcess(uid, pid)) {
+ PLOG(WARNING) << "Failed to apply " << name << " process profile";
+ }
+ } else {
+ PLOG(WARNING) << "Failed to find " << name << "process profile";
+ }
+ }
+
+ return true;
+}
+
+bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles) {
+ const TaskProfiles& tp = TaskProfiles::GetInstance();
+
+ for (const auto& name : profiles) {
+ const TaskProfile* profile = tp.GetProfile(name);
+ if (profile != nullptr) {
+ if (!profile->ExecuteForTask(tid)) {
+ PLOG(WARNING) << "Failed to apply " << name << " task profile";
+ }
+ } else {
+ PLOG(WARNING) << "Failed to find " << name << "task profile";
+ }
+ }
+
+ return true;
+}
+
static std::string ConvertUidToPath(const char* cgroup, uid_t uid) {
return StringPrintf("%s/uid_%d", cgroup, uid);
}
@@ -103,11 +190,21 @@
}
}
-void removeAllProcessGroups()
-{
+void removeAllProcessGroups() {
LOG(VERBOSE) << "removeAllProcessGroups()";
- for (const char* cgroup_root_path : {kCpuacctCgroup, kMemoryCgroup}) {
- std::unique_ptr<DIR, decltype(&closedir)> root(opendir(cgroup_root_path), closedir);
+
+ std::vector<std::string> cgroups;
+ std::string path;
+
+ if (CgroupGetControllerPath("cpuacct", &path)) {
+ cgroups.push_back(path);
+ }
+ if (CgroupGetControllerPath("memory", &path)) {
+ cgroups.push_back(path);
+ }
+
+ for (std::string cgroup_root_path : cgroups) {
+ std::unique_ptr<DIR, decltype(&closedir)> root(opendir(cgroup_root_path.c_str()), closedir);
if (root == NULL) {
PLOG(ERROR) << "Failed to open " << cgroup_root_path;
} else {
@@ -121,7 +218,7 @@
continue;
}
- auto path = StringPrintf("%s/%s", cgroup_root_path, dir->d_name);
+ auto path = StringPrintf("%s/%s", cgroup_root_path.c_str(), dir->d_name);
RemoveUidProcessGroups(path);
LOG(VERBOSE) << "Removing " << path;
if (rmdir(path.c_str()) == -1) PLOG(WARNING) << "Failed to remove " << path;
@@ -130,6 +227,21 @@
}
}
+static bool MkdirAndChown(const std::string& path, mode_t mode, uid_t uid, gid_t gid) {
+ if (mkdir(path.c_str(), mode) == -1 && errno != EEXIST) {
+ return false;
+ }
+
+ if (chown(path.c_str(), uid, gid) == -1) {
+ int saved_errno = errno;
+ rmdir(path.c_str());
+ errno = saved_errno;
+ return false;
+ }
+
+ return true;
+}
+
// Returns number of processes killed on success
// Returns 0 if there are no processes in the process cgroup left to kill
// Returns -1 on error
@@ -200,10 +312,16 @@
}
static int KillProcessGroup(uid_t uid, int initialPid, int signal, int retries) {
+ std::string cpuacct_path;
+ std::string memory_path;
+
+ CgroupGetControllerPath("cpuacct", &cpuacct_path);
+ CgroupGetControllerPath("memory", &memory_path);
+
const char* cgroup =
- (!access(ConvertUidPidToPath(kCpuacctCgroup, uid, initialPid).c_str(), F_OK))
- ? kCpuacctCgroup
- : kMemoryCgroup;
+ (!access(ConvertUidPidToPath(cpuacct_path.c_str(), uid, initialPid).c_str(), F_OK))
+ ? cpuacct_path.c_str()
+ : memory_path.c_str();
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
@@ -258,44 +376,22 @@
return KillProcessGroup(uid, initialPid, signal, 0 /*retries*/);
}
-static bool MkdirAndChown(const std::string& path, mode_t mode, uid_t uid, gid_t gid) {
- if (mkdir(path.c_str(), mode) == -1 && errno != EEXIST) {
- return false;
- }
-
- if (chown(path.c_str(), uid, gid) == -1) {
- int saved_errno = errno;
- rmdir(path.c_str());
- errno = saved_errno;
- return false;
- }
-
- return true;
-}
-
-static bool isPerAppMemcgEnabled() {
- static bool per_app_memcg =
- GetBoolProperty("ro.config.per_app_memcg", GetBoolProperty("ro.config.low_ram", false));
- return per_app_memcg;
-}
-
-int createProcessGroup(uid_t uid, int initialPid, bool memControl)
-{
- const char* cgroup;
- if (isMemoryCgroupSupported() && (memControl || isPerAppMemcgEnabled())) {
- cgroup = kMemoryCgroup;
+int createProcessGroup(uid_t uid, int initialPid, bool memControl) {
+ std::string cgroup;
+ if (isMemoryCgroupSupported() && (memControl || UsePerAppMemcg())) {
+ CgroupGetControllerPath("memory", &cgroup);
} else {
- cgroup = kCpuacctCgroup;
+ CgroupGetControllerPath("cpuacct", &cgroup);
}
- auto uid_path = ConvertUidToPath(cgroup, uid);
+ auto uid_path = ConvertUidToPath(cgroup.c_str(), uid);
if (!MkdirAndChown(uid_path, 0750, AID_SYSTEM, AID_SYSTEM)) {
PLOG(ERROR) << "Failed to make and chown " << uid_path;
return -errno;
}
- auto uid_pid_path = ConvertUidPidToPath(cgroup, uid, initialPid);
+ auto uid_pid_path = ConvertUidPidToPath(cgroup.c_str(), uid, initialPid);
if (!MkdirAndChown(uid_pid_path, 0750, AID_SYSTEM, AID_SYSTEM)) {
PLOG(ERROR) << "Failed to make and chown " << uid_pid_path;
@@ -313,13 +409,17 @@
return ret;
}
-static bool SetProcessGroupValue(uid_t uid, int pid, const std::string& file_name, int64_t value) {
+static bool SetProcessGroupValue(int tid, const std::string& attr_name, int64_t value) {
if (!isMemoryCgroupSupported()) {
PLOG(ERROR) << "Memcg is not mounted.";
return false;
}
- auto path = ConvertUidPidToPath(kMemoryCgroup, uid, pid) + file_name;
+ std::string path;
+ if (!CgroupGetAttributePathForTask(attr_name, tid, &path)) {
+ PLOG(ERROR) << "Failed to find attribute '" << attr_name << "'";
+ return false;
+ }
if (!WriteStringToFile(std::to_string(value), path)) {
PLOG(ERROR) << "Failed to write '" << value << "' to " << path;
@@ -328,14 +428,14 @@
return true;
}
-bool setProcessGroupSwappiness(uid_t uid, int pid, int swappiness) {
- return SetProcessGroupValue(uid, pid, "/memory.swappiness", swappiness);
+bool setProcessGroupSwappiness(uid_t, int pid, int swappiness) {
+ return SetProcessGroupValue(pid, "MemSwappiness", swappiness);
}
-bool setProcessGroupSoftLimit(uid_t uid, int pid, int64_t soft_limit_in_bytes) {
- return SetProcessGroupValue(uid, pid, "/memory.soft_limit_in_bytes", soft_limit_in_bytes);
+bool setProcessGroupSoftLimit(uid_t, int pid, int64_t soft_limit_in_bytes) {
+ return SetProcessGroupValue(pid, "MemSoftLimit", soft_limit_in_bytes);
}
-bool setProcessGroupLimit(uid_t uid, int pid, int64_t limit_in_bytes) {
- return SetProcessGroupValue(uid, pid, "/memory.limit_in_bytes", limit_in_bytes);
+bool setProcessGroupLimit(uid_t, int pid, int64_t limit_in_bytes) {
+ return SetProcessGroupValue(pid, "MemLimit", limit_in_bytes);
}
diff --git a/libprocessgroup/sched_policy.cpp b/libprocessgroup/sched_policy.cpp
index f95d7e4..337b032 100644
--- a/libprocessgroup/sched_policy.cpp
+++ b/libprocessgroup/sched_policy.cpp
@@ -1,372 +1,83 @@
/*
-** Copyright 2007, 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.
-*/
+ * 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/sched_policy.h>
#define LOG_TAG "SchedPolicy"
#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
#include <unistd.h>
-#include <android-base/macros.h>
-#include <log/log.h>
+#include <android-base/logging.h>
+#include <android-base/threads.h>
+#include <cgroup_map.h>
+#include <processgroup/processgroup.h>
+
+using android::base::GetThreadId;
/* Re-map SP_DEFAULT to the system default policy, and leave other values unchanged.
* Call this any place a SchedPolicy is used as an input parameter.
* Returns the possibly re-mapped policy.
*/
-static inline SchedPolicy _policy(SchedPolicy p)
-{
- return p == SP_DEFAULT ? SP_SYSTEM_DEFAULT : p;
+static inline SchedPolicy _policy(SchedPolicy p) {
+ return p == SP_DEFAULT ? SP_SYSTEM_DEFAULT : p;
}
#if defined(__ANDROID__)
-#include <pthread.h>
-#include <sched.h>
-#include <sys/prctl.h>
-
-#define POLICY_DEBUG 0
-
-// timer slack value in nS enforced when the thread moves to background
-#define TIMER_SLACK_BG 40000000
-#define TIMER_SLACK_FG 50000
-
-static pthread_once_t the_once = PTHREAD_ONCE_INIT;
-
-static int __sys_supports_timerslack = -1;
-
-// File descriptors open to /dev/cpuset/../tasks, setup by initialize, or -1 on error
-static int system_bg_cpuset_fd = -1;
-static int bg_cpuset_fd = -1;
-static int fg_cpuset_fd = -1;
-static int ta_cpuset_fd = -1; // special cpuset for top app
-static int rs_cpuset_fd = -1; // special cpuset for screen off restrictions
-
-// File descriptors open to /dev/stune/../tasks, setup by initialize, or -1 on error
-static int bg_schedboost_fd = -1;
-static int fg_schedboost_fd = -1;
-static int ta_schedboost_fd = -1;
-static int rt_schedboost_fd = -1;
-
-/* Add tid to the scheduling group defined by the policy */
-static int add_tid_to_cgroup(int tid, int fd)
-{
- if (fd < 0) {
- SLOGE("add_tid_to_cgroup failed; fd=%d\n", fd);
- errno = EINVAL;
- return -1;
- }
-
- // specialized itoa -- works for tid > 0
- char text[22];
- char *end = text + sizeof(text) - 1;
- char *ptr = end;
- *ptr = '\0';
- while (tid > 0) {
- *--ptr = '0' + (tid % 10);
- tid = tid / 10;
- }
-
- if (write(fd, ptr, end - ptr) < 0) {
- /*
- * If the thread is in the process of exiting,
- * don't flag an error
- */
- if (errno == ESRCH)
- return 0;
- SLOGW("add_tid_to_cgroup failed to write '%s' (%s); fd=%d\n",
- ptr, strerror(errno), fd);
- errno = EINVAL;
- return -1;
- }
-
- return 0;
-}
-
-/*
- If CONFIG_CPUSETS for Linux kernel is set, "tasks" can be found under
- /dev/cpuset mounted in init.rc; otherwise, that file does not exist
- even though the directory, /dev/cpuset, is still created (by init.rc).
-
- A couple of other candidates (under cpuset mount directory):
- notify_on_release
- release_agent
-
- Yet another way to decide if cpuset is enabled is to parse
- /proc/self/status and search for lines begin with "Mems_allowed".
-
- If CONFIG_PROC_PID_CPUSET is set, the existence "/proc/self/cpuset" can
- be used to decide if CONFIG_CPUSETS is set, so we don't have a dependency
- on where init.rc mounts cpuset. That's why we'd better require this
- configuration be set if CONFIG_CPUSETS is set.
-
- In older releases, this was controlled by build-time configuration.
- */
-bool cpusets_enabled() {
- static bool enabled = (access("/dev/cpuset/tasks", F_OK) == 0);
-
- return enabled;
-}
-
-/*
- Similar to CONFIG_CPUSETS above, but with a different configuration
- CONFIG_CGROUP_SCHEDTUNE that's in Android common Linux kernel and Linaro
- Stable Kernel (LSK), but not in mainline Linux as of v4.9.
-
- In older releases, this was controlled by build-time configuration.
- */
-bool schedboost_enabled() {
- static bool enabled = (access("/dev/stune/tasks", F_OK) == 0);
-
- return enabled;
-}
-
-static void __initialize() {
- const char* filename;
-
- if (cpusets_enabled()) {
- if (!access("/dev/cpuset/tasks", W_OK)) {
-
- filename = "/dev/cpuset/foreground/tasks";
- fg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
- filename = "/dev/cpuset/background/tasks";
- bg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
- filename = "/dev/cpuset/system-background/tasks";
- system_bg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
- filename = "/dev/cpuset/top-app/tasks";
- ta_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
- filename = "/dev/cpuset/restricted/tasks";
- rs_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
-
- if (schedboost_enabled()) {
- filename = "/dev/stune/top-app/tasks";
- ta_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
- filename = "/dev/stune/foreground/tasks";
- fg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
- filename = "/dev/stune/background/tasks";
- bg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
- filename = "/dev/stune/rt/tasks";
- rt_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
- }
- }
- }
-
- char buf[64];
- snprintf(buf, sizeof(buf), "/proc/%d/timerslack_ns", getpid());
- __sys_supports_timerslack = !access(buf, W_OK);
-}
-
-/*
- * Returns the path under the requested cgroup subsystem (if it exists)
- *
- * The data from /proc/<pid>/cgroup looks (something) like:
- * 2:cpu:/bg_non_interactive
- * 1:cpuacct:/
- *
- * We return the part after the "/", which will be an empty string for
- * the default cgroup. If the string is longer than "bufLen", the string
- * will be truncated.
- */
-static int getCGroupSubsys(int tid, const char* subsys, char* buf, size_t bufLen)
-{
-#if defined(__ANDROID__)
- char pathBuf[32];
- char lineBuf[256];
- FILE *fp;
-
- snprintf(pathBuf, sizeof(pathBuf), "/proc/%d/cgroup", tid);
- if (!(fp = fopen(pathBuf, "re"))) {
- return -1;
- }
-
- while(fgets(lineBuf, sizeof(lineBuf) -1, fp)) {
- char *next = lineBuf;
- char *found_subsys;
- char *grp;
- size_t len;
-
- /* Junk the first field */
- if (!strsep(&next, ":")) {
- goto out_bad_data;
- }
-
- if (!(found_subsys = strsep(&next, ":"))) {
- goto out_bad_data;
- }
-
- if (strcmp(found_subsys, subsys)) {
- /* Not the subsys we're looking for */
- continue;
- }
-
- if (!(grp = strsep(&next, ":"))) {
- goto out_bad_data;
- }
- grp++; /* Drop the leading '/' */
- len = strlen(grp);
- grp[len-1] = '\0'; /* Drop the trailing '\n' */
-
- if (bufLen <= len) {
- len = bufLen - 1;
- }
- strncpy(buf, grp, len);
- buf[len] = '\0';
- fclose(fp);
- return 0;
- }
-
- SLOGE("Failed to find subsys %s", subsys);
- fclose(fp);
- return -1;
- out_bad_data:
- SLOGE("Bad cgroup data {%s}", lineBuf);
- fclose(fp);
- return -1;
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-
-int get_sched_policy(int tid, SchedPolicy *policy)
-{
+int set_cpuset_policy(int tid, SchedPolicy policy) {
if (tid == 0) {
- tid = gettid();
- }
- pthread_once(&the_once, __initialize);
-
- char grpBuf[32];
-
- grpBuf[0] = '\0';
- if (schedboost_enabled()) {
- if (getCGroupSubsys(tid, "schedtune", grpBuf, sizeof(grpBuf)) < 0) return -1;
- }
- if ((grpBuf[0] == '\0') && cpusets_enabled()) {
- if (getCGroupSubsys(tid, "cpuset", grpBuf, sizeof(grpBuf)) < 0) return -1;
- }
- if (grpBuf[0] == '\0') {
- *policy = SP_FOREGROUND;
- } else if (!strcmp(grpBuf, "foreground")) {
- *policy = SP_FOREGROUND;
- } else if (!strcmp(grpBuf, "system-background")) {
- *policy = SP_SYSTEM;
- } else if (!strcmp(grpBuf, "background")) {
- *policy = SP_BACKGROUND;
- } else if (!strcmp(grpBuf, "top-app")) {
- *policy = SP_TOP_APP;
- } else {
- errno = ERANGE;
- return -1;
- }
- return 0;
-}
-
-int set_cpuset_policy(int tid, SchedPolicy policy)
-{
- // in the absence of cpusets, use the old sched policy
- if (!cpusets_enabled()) {
- return set_sched_policy(tid, policy);
- }
-
- if (tid == 0) {
- tid = gettid();
+ tid = GetThreadId();
}
policy = _policy(policy);
- pthread_once(&the_once, __initialize);
- int fd = -1;
- int boost_fd = -1;
switch (policy) {
- case SP_BACKGROUND:
- fd = bg_cpuset_fd;
- boost_fd = bg_schedboost_fd;
- break;
- case SP_FOREGROUND:
- case SP_AUDIO_APP:
- case SP_AUDIO_SYS:
- fd = fg_cpuset_fd;
- boost_fd = fg_schedboost_fd;
- break;
- case SP_TOP_APP :
- fd = ta_cpuset_fd;
- boost_fd = ta_schedboost_fd;
- break;
- case SP_SYSTEM:
- fd = system_bg_cpuset_fd;
- break;
- case SP_RESTRICTED:
- fd = rs_cpuset_fd;
- break;
- default:
- boost_fd = fd = -1;
- break;
- }
-
- if (add_tid_to_cgroup(tid, fd) != 0) {
- if (errno != ESRCH && errno != ENOENT)
- return -errno;
- }
-
- if (schedboost_enabled()) {
- if (boost_fd > 0 && add_tid_to_cgroup(tid, boost_fd) != 0) {
- if (errno != ESRCH && errno != ENOENT)
- return -errno;
- }
+ case SP_BACKGROUND:
+ return SetTaskProfiles(tid,
+ {"HighEnergySaving", "ProcessCapacityLow", "TimerSlackHigh"})
+ ? 0
+ : -1;
+ case SP_FOREGROUND:
+ case SP_AUDIO_APP:
+ case SP_AUDIO_SYS:
+ return SetTaskProfiles(tid,
+ {"HighPerformance", "ProcessCapacityHigh", "TimerSlackNormal"})
+ ? 0
+ : -1;
+ case SP_TOP_APP:
+ return SetTaskProfiles(tid,
+ {"MaxPerformance", "ProcessCapacityMax", "TimerSlackNormal"})
+ ? 0
+ : -1;
+ case SP_SYSTEM:
+ return SetTaskProfiles(tid, {"ServiceCapacityLow", "TimerSlackNormal"}) ? 0 : -1;
+ case SP_RESTRICTED:
+ return SetTaskProfiles(tid, {"ServiceCapacityRestricted", "TimerSlackNormal"}) ? 0 : -1;
+ default:
+ break;
}
return 0;
}
-static void set_timerslack_ns(int tid, unsigned long slack) {
- // v4.6+ kernels support the /proc/<tid>/timerslack_ns interface.
- // TODO: once we've backported this, log if the open(2) fails.
- if (__sys_supports_timerslack) {
- char buf[64];
- snprintf(buf, sizeof(buf), "/proc/%d/timerslack_ns", tid);
- int fd = open(buf, O_WRONLY | O_CLOEXEC);
- if (fd != -1) {
- int len = snprintf(buf, sizeof(buf), "%lu", slack);
- if (write(fd, buf, len) != len) {
- SLOGE("set_timerslack_ns write failed: %s\n", strerror(errno));
- }
- close(fd);
- return;
- }
- }
-
- // TODO: Remove when /proc/<tid>/timerslack_ns interface is backported.
- if ((tid == 0) || (tid == gettid())) {
- if (prctl(PR_SET_TIMERSLACK, slack) == -1) {
- SLOGE("set_timerslack_ns prctl failed: %s\n", strerror(errno));
- }
- }
-}
-
-int set_sched_policy(int tid, SchedPolicy policy)
-{
+int set_sched_policy(int tid, SchedPolicy policy) {
if (tid == 0) {
- tid = gettid();
+ tid = GetThreadId();
}
policy = _policy(policy);
- pthread_once(&the_once, __initialize);
#if POLICY_DEBUG
char statfile[64];
@@ -376,73 +87,113 @@
snprintf(statfile, sizeof(statfile), "/proc/%d/stat", tid);
memset(thread_name, 0, sizeof(thread_name));
- int fd = open(statfile, O_RDONLY | O_CLOEXEC);
+ unique_fd fd(TEMP_FAILURE_RETRY(open(statfile, O_RDONLY | O_CLOEXEC)));
if (fd >= 0) {
int rc = read(fd, statline, 1023);
- close(fd);
statline[rc] = 0;
- char *p = statline;
- char *q;
+ char* p = statline;
+ char* q;
- for (p = statline; *p != '('; p++);
+ for (p = statline; *p != '('; p++)
+ ;
p++;
- for (q = p; *q != ')'; q++);
+ for (q = p; *q != ')'; q++)
+ ;
- strncpy(thread_name, p, (q-p));
+ strncpy(thread_name, p, (q - p));
}
switch (policy) {
- case SP_BACKGROUND:
- SLOGD("vvv tid %d (%s)", tid, thread_name);
- break;
- case SP_FOREGROUND:
- case SP_AUDIO_APP:
- case SP_AUDIO_SYS:
- case SP_TOP_APP:
- SLOGD("^^^ tid %d (%s)", tid, thread_name);
- break;
- case SP_SYSTEM:
- SLOGD("/// tid %d (%s)", tid, thread_name);
- break;
- case SP_RT_APP:
- SLOGD("RT tid %d (%s)", tid, thread_name);
- break;
- default:
- SLOGD("??? tid %d (%s)", tid, thread_name);
- break;
- }
-#endif
-
- if (schedboost_enabled()) {
- int boost_fd = -1;
- switch (policy) {
case SP_BACKGROUND:
- boost_fd = bg_schedboost_fd;
+ SLOGD("vvv tid %d (%s)", tid, thread_name);
break;
case SP_FOREGROUND:
case SP_AUDIO_APP:
case SP_AUDIO_SYS:
- boost_fd = fg_schedboost_fd;
- break;
case SP_TOP_APP:
- boost_fd = ta_schedboost_fd;
+ SLOGD("^^^ tid %d (%s)", tid, thread_name);
+ break;
+ case SP_SYSTEM:
+ SLOGD("/// tid %d (%s)", tid, thread_name);
break;
case SP_RT_APP:
- boost_fd = rt_schedboost_fd;
- break;
- default:
- boost_fd = -1;
+ SLOGD("RT tid %d (%s)", tid, thread_name);
break;
- }
+ default:
+ SLOGD("??? tid %d (%s)", tid, thread_name);
+ break;
+ }
+#endif
- if (boost_fd > 0 && add_tid_to_cgroup(tid, boost_fd) != 0) {
- if (errno != ESRCH && errno != ENOENT)
- return -errno;
- }
-
+ switch (policy) {
+ case SP_BACKGROUND:
+ return SetTaskProfiles(tid, {"HighEnergySaving", "TimerSlackHigh"}) ? 0 : -1;
+ case SP_FOREGROUND:
+ case SP_AUDIO_APP:
+ case SP_AUDIO_SYS:
+ return SetTaskProfiles(tid, {"HighPerformance", "TimerSlackNormal"}) ? 0 : -1;
+ case SP_TOP_APP:
+ return SetTaskProfiles(tid, {"MaxPerformance", "TimerSlackNormal"}) ? 0 : -1;
+ case SP_RT_APP:
+ return SetTaskProfiles(tid, {"RealtimePerformance", "TimerSlackNormal"}) ? 0 : -1;
+ default:
+ return SetTaskProfiles(tid, {"TimerSlackNormal"}) ? 0 : -1;
}
- set_timerslack_ns(tid, policy == SP_BACKGROUND ? TIMER_SLACK_BG : TIMER_SLACK_FG);
+ return 0;
+}
+bool cpusets_enabled() {
+ static bool enabled = (CgroupMap::GetInstance().FindController("cpuset") != nullptr);
+ return enabled;
+}
+
+bool schedboost_enabled() {
+ static bool enabled = (CgroupMap::GetInstance().FindController("schedtune") != nullptr);
+ return enabled;
+}
+
+static int getCGroupSubsys(int tid, const char* subsys, std::string& subgroup) {
+ const CgroupController* controller = CgroupMap::GetInstance().FindController(subsys);
+
+ if (!controller) return -1;
+
+ if (!controller->GetTaskGroup(tid, &subgroup)) {
+ PLOG(ERROR) << "Failed to find cgroup for tid " << tid;
+ return -1;
+ }
+ return 0;
+}
+
+int get_sched_policy(int tid, SchedPolicy* policy) {
+ if (tid == 0) {
+ tid = GetThreadId();
+ }
+
+ std::string group;
+ if (schedboost_enabled()) {
+ if (getCGroupSubsys(tid, "schedtune", group) < 0) return -1;
+ }
+ if (group.empty() && cpusets_enabled()) {
+ if (getCGroupSubsys(tid, "cpuset", group) < 0) return -1;
+ }
+
+ // TODO: replace hardcoded directories
+ if (group.empty()) {
+ *policy = SP_FOREGROUND;
+ } else if (group == "foreground") {
+ *policy = SP_FOREGROUND;
+ } else if (group == "system-background") {
+ *policy = SP_SYSTEM;
+ } else if (group == "background") {
+ *policy = SP_BACKGROUND;
+ } else if (group == "top-app") {
+ *policy = SP_TOP_APP;
+ } else if (group == "restricted") {
+ *policy = SP_RESTRICTED;
+ } else {
+ errno = ERANGE;
+ return -1;
+ }
return 0;
}
@@ -450,11 +201,11 @@
/* Stubs for non-Android targets. */
-int set_sched_policy(int /*tid*/, SchedPolicy /*policy*/) {
+int set_sched_policy(int, SchedPolicy) {
return 0;
}
-int get_sched_policy(int /*tid*/, SchedPolicy* policy) {
+int get_sched_policy(int, SchedPolicy* policy) {
*policy = SP_SYSTEM_DEFAULT;
return 0;
}
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
new file mode 100644
index 0000000..447852d
--- /dev/null
+++ b/libprocessgroup/task_profiles.cpp
@@ -0,0 +1,414 @@
+/*
+ * 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 <fcntl.h>
+#include <task_profiles.h>
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/threads.h>
+
+#include <cutils/android_filesystem_config.h>
+
+#include <json/reader.h>
+#include <json/value.h>
+
+// To avoid issues in sdk_mac build
+#if defined(__ANDROID__)
+#include <sys/prctl.h>
+#endif
+
+using android::base::GetThreadId;
+using android::base::StringPrintf;
+using android::base::unique_fd;
+using android::base::WriteStringToFile;
+
+#define TASK_PROFILE_DB_FILE "/etc/task_profiles.json"
+
+bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const {
+ std::string subgroup;
+ if (!controller_->GetTaskGroup(tid, &subgroup)) {
+ return false;
+ }
+
+ if (path == nullptr) {
+ return true;
+ }
+
+ if (subgroup.empty()) {
+ *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());
+ }
+ return true;
+}
+
+bool SetClampsAction::ExecuteForProcess(uid_t, pid_t) const {
+ // TODO: add support when kernel supports util_clamp
+ LOG(WARNING) << "SetClampsAction::ExecuteForProcess is not supported";
+ return false;
+}
+
+bool SetClampsAction::ExecuteForTask(int) const {
+ // TODO: add support when kernel supports util_clamp
+ LOG(WARNING) << "SetClampsAction::ExecuteForTask is not supported";
+ return false;
+}
+
+// To avoid issues in sdk_mac build
+#if defined(__ANDROID__)
+
+bool SetTimerSlackAction::IsTimerSlackSupported(int tid) {
+ auto file = StringPrintf("/proc/%d/timerslack_ns", tid);
+
+ return (access(file.c_str(), W_OK) == 0);
+}
+
+bool SetTimerSlackAction::ExecuteForTask(int tid) const {
+ static bool sys_supports_timerslack = IsTimerSlackSupported(tid);
+
+ // v4.6+ kernels support the /proc/<tid>/timerslack_ns interface.
+ // TODO: once we've backported this, log if the open(2) fails.
+ if (sys_supports_timerslack) {
+ auto file = StringPrintf("/proc/%d/timerslack_ns", tid);
+ if (!WriteStringToFile(std::to_string(slack_), file)) {
+ PLOG(ERROR) << "set_timerslack_ns write failed";
+ }
+ }
+
+ // TODO: Remove when /proc/<tid>/timerslack_ns interface is backported.
+ if (tid == 0 || tid == GetThreadId()) {
+ if (prctl(PR_SET_TIMERSLACK, slack_) == -1) {
+ PLOG(ERROR) << "set_timerslack_ns prctl failed";
+ }
+ }
+
+ return true;
+}
+
+#endif
+
+bool SetAttributeAction::ExecuteForProcess(uid_t, pid_t pid) const {
+ return ExecuteForTask(pid);
+}
+
+bool SetAttributeAction::ExecuteForTask(int tid) const {
+ std::string path;
+
+ if (!attribute_->GetPathForTask(tid, &path)) {
+ PLOG(ERROR) << "Failed to find cgroup for tid " << tid;
+ return false;
+ }
+
+ if (!WriteStringToFile(value_, path)) {
+ PLOG(ERROR) << "Failed to write '" << value_ << "' to " << path;
+ return false;
+ }
+
+ return true;
+}
+
+bool SetCgroupAction::IsAppDependentPath(const std::string& path) {
+ return path.find("<uid>", 0) != std::string::npos || path.find("<pid>", 0) != std::string::npos;
+}
+
+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
+ if (IsAppDependentPath(path_)) {
+ // file descriptor is not cached
+ fd_.reset(-2);
+ return;
+ }
+
+ std::string tasks_path = c->GetTasksFilePath(p.c_str());
+
+ if (access(tasks_path.c_str(), W_OK) != 0) {
+ // file is not accessible
+ fd_.reset(-1);
+ return;
+ }
+
+ unique_fd fd(TEMP_FAILURE_RETRY(open(tasks_path.c_str(), O_WRONLY | O_CLOEXEC)));
+ if (fd < 0) {
+ PLOG(ERROR) << "Failed to cache fd '" << tasks_path << "'";
+ fd_.reset(-1);
+ return;
+ }
+
+ fd_ = std::move(fd);
+#endif
+}
+
+bool SetCgroupAction::AddTidToCgroup(int tid, int fd) {
+ if (tid <= 0) {
+ return true;
+ }
+
+ std::string value = std::to_string(tid);
+
+ if (TEMP_FAILURE_RETRY(write(fd, value.c_str(), value.length())) < 0) {
+ // If the thread is in the process of exiting, don't flag an error
+ if (errno != ESRCH) {
+ PLOG(ERROR) << "JoinGroup failed to write '" << value << "'; fd=" << fd;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool SetCgroupAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
+#ifdef CACHE_FILE_DESCRIPTORS
+ if (fd_ >= 0) {
+ // fd is cached, reuse it
+ if (!AddTidToCgroup(pid, fd_)) {
+ PLOG(ERROR) << "Failed to add task into cgroup";
+ return false;
+ }
+ return true;
+ }
+
+ if (fd_ == -1) {
+ // no permissions to access the file, ignore
+ return true;
+ }
+
+ // this is app-dependent path, file descriptor is not cached
+ std::string procs_path = controller_->GetProcsFilePath(path_.c_str(), 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 << ": " << strerror(errno);
+ return false;
+ }
+ if (!AddTidToCgroup(pid, tmp_fd)) {
+ PLOG(ERROR) << "Failed to add task into cgroup";
+ return false;
+ }
+
+ return true;
+#else
+ std::string procs_path = controller_->GetProcsFilePath(path_.c_str(), 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
+ return true;
+ }
+ if (!AddTidToCgroup(pid, tmp_fd)) {
+ PLOG(ERROR) << "Failed to add task into cgroup";
+ return false;
+ }
+
+ return true;
+#endif
+}
+
+bool SetCgroupAction::ExecuteForTask(int tid) const {
+#ifdef CACHE_FILE_DESCRIPTORS
+ if (fd_ >= 0) {
+ // fd is cached, reuse it
+ if (!AddTidToCgroup(tid, fd_)) {
+ PLOG(ERROR) << "Failed to add task into cgroup";
+ return false;
+ }
+ return true;
+ }
+
+ if (fd_ == -1) {
+ // no permissions to access the file, ignore
+ return true;
+ }
+
+ // application-dependent path can't be used with tid
+ PLOG(ERROR) << "Application profile can't be applied to a thread";
+ return false;
+#else
+ std::string tasks_path = controller_->GetTasksFilePath(path_.c_str());
+ 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
+ return true;
+ }
+ if (!AddTidToCgroup(tid, tmp_fd)) {
+ PLOG(ERROR) << "Failed to add task into cgroup";
+ return false;
+ }
+
+ return true;
+#endif
+}
+
+bool TaskProfile::ExecuteForProcess(uid_t uid, pid_t pid) const {
+ for (const auto& element : elements_) {
+ if (!element->ExecuteForProcess(uid, pid)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool TaskProfile::ExecuteForTask(int tid) const {
+ if (tid == 0) {
+ tid = GetThreadId();
+ }
+ for (const auto& element : elements_) {
+ if (!element->ExecuteForTask(tid)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+TaskProfiles& TaskProfiles::GetInstance() {
+ static TaskProfiles instance;
+ return instance;
+}
+
+TaskProfiles::TaskProfiles() {
+ if (!Load(CgroupMap::GetInstance())) {
+ LOG(ERROR) << "TaskProfiles::Load for [" << getpid() << "] failed";
+ }
+}
+
+bool TaskProfiles::Load(const CgroupMap& cg_map) {
+ std::string json_doc;
+
+ if (!android::base::ReadFileToString(TASK_PROFILE_DB_FILE, &json_doc)) {
+ LOG(ERROR) << "Failed to read task profiles from " << TASK_PROFILE_DB_FILE;
+ return false;
+ }
+
+ Json::Reader reader;
+ Json::Value root;
+ if (!reader.parse(json_doc, root)) {
+ LOG(ERROR) << "Failed to parse task profiles: " << reader.getFormattedErrorMessages();
+ return false;
+ }
+
+ Json::Value attr = root["Attributes"];
+ for (Json::Value::ArrayIndex i = 0; i < attr.size(); ++i) {
+ std::string name = attr[i]["Name"].asString();
+ std::string ctrlName = attr[i]["Controller"].asString();
+ std::string file_name = attr[i]["File"].asString();
+
+ if (attributes_.find(name) == attributes_.end()) {
+ const CgroupController* controller = cg_map.FindController(ctrlName.c_str());
+ if (controller) {
+ attributes_[name] = std::make_unique<ProfileAttribute>(controller, file_name);
+ } else {
+ LOG(WARNING) << "Controller " << ctrlName << " is not found";
+ }
+ } else {
+ LOG(WARNING) << "Attribute " << name << " is already defined";
+ }
+ }
+
+ std::map<std::string, std::string> params;
+
+ Json::Value profilesVal = root["Profiles"];
+ for (Json::Value::ArrayIndex i = 0; i < profilesVal.size(); ++i) {
+ Json::Value profileVal = profilesVal[i];
+
+ std::string profileName = profileVal["Name"].asString();
+ Json::Value actions = profileVal["Actions"];
+ auto profile = std::make_unique<TaskProfile>();
+
+ for (Json::Value::ArrayIndex actIdx = 0; actIdx < actions.size(); ++actIdx) {
+ Json::Value actionVal = actions[actIdx];
+ std::string actionName = actionVal["Name"].asString();
+ Json::Value paramsVal = actionVal["Params"];
+ if (actionName == "JoinCgroup") {
+ std::string ctrlName = paramsVal["Controller"].asString();
+ std::string path = paramsVal["Path"].asString();
+
+ const CgroupController* controller = cg_map.FindController(ctrlName.c_str());
+ if (controller) {
+ profile->Add(std::make_unique<SetCgroupAction>(controller, path));
+ } else {
+ LOG(WARNING) << "JoinCgroup: controller " << ctrlName << " is not found";
+ }
+ } else if (actionName == "SetTimerSlack") {
+ std::string slackValue = paramsVal["Slack"].asString();
+ char* end;
+ unsigned long slack;
+
+ slack = strtoul(slackValue.c_str(), &end, 10);
+ if (end > slackValue.c_str()) {
+ profile->Add(std::make_unique<SetTimerSlackAction>(slack));
+ } else {
+ LOG(WARNING) << "SetTimerSlack: invalid parameter: " << slackValue;
+ }
+ } else if (actionName == "SetAttribute") {
+ std::string attrName = paramsVal["Name"].asString();
+ std::string attrValue = paramsVal["Value"].asString();
+
+ auto iter = attributes_.find(attrName);
+ if (iter != attributes_.end()) {
+ profile->Add(
+ std::make_unique<SetAttributeAction>(iter->second.get(), attrValue));
+ } else {
+ LOG(WARNING) << "SetAttribute: unknown attribute: " << attrName;
+ }
+ } else if (actionName == "SetClamps") {
+ std::string boostValue = paramsVal["Boost"].asString();
+ std::string clampValue = paramsVal["Clamp"].asString();
+ char* end;
+ unsigned long boost;
+
+ boost = strtoul(boostValue.c_str(), &end, 10);
+ if (end > boostValue.c_str()) {
+ unsigned long clamp = strtoul(clampValue.c_str(), &end, 10);
+ if (end > clampValue.c_str()) {
+ profile->Add(std::make_unique<SetClampsAction>(boost, clamp));
+ } else {
+ LOG(WARNING) << "SetClamps: invalid parameter " << clampValue;
+ }
+ } else {
+ LOG(WARNING) << "SetClamps: invalid parameter: " << boostValue;
+ }
+ } else {
+ LOG(WARNING) << "Unknown profile action: " << actionName;
+ }
+ }
+ profiles_[profileName] = std::move(profile);
+ }
+
+ return true;
+}
+
+const TaskProfile* TaskProfiles::GetProfile(const std::string& name) const {
+ auto iter = profiles_.find(name);
+
+ if (iter != profiles_.end()) {
+ return iter->second.get();
+ }
+ return nullptr;
+}
+
+const ProfileAttribute* TaskProfiles::GetAttribute(const std::string& name) const {
+ auto iter = attributes_.find(name);
+
+ if (iter != attributes_.end()) {
+ return iter->second.get();
+ }
+ return nullptr;
+}
diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h
new file mode 100644
index 0000000..b2e39f9
--- /dev/null
+++ b/libprocessgroup/task_profiles.h
@@ -0,0 +1,156 @@
+/*
+ * 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 <sys/cdefs.h>
+#include <sys/types.h>
+#include <map>
+#include <string>
+#include <vector>
+
+#include <android-base/unique_fd.h>
+#include <cgroup_map.h>
+
+class ProfileAttribute {
+ public:
+ ProfileAttribute(const CgroupController* controller, const std::string& file_name)
+ : controller_(controller), file_name_(file_name) {}
+
+ 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_;
+ std::string file_name_;
+};
+
+// Abstract profile element
+class ProfileAction {
+ public:
+ virtual ~ProfileAction() {}
+
+ // Default implementations will fail
+ virtual bool ExecuteForProcess(uid_t, pid_t) const { return false; };
+ virtual bool ExecuteForTask(int) const { return false; };
+};
+
+// Profile actions
+class SetClampsAction : public ProfileAction {
+ public:
+ SetClampsAction(int boost, int clamp) noexcept : boost_(boost), clamp_(clamp) {}
+
+ virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
+ virtual bool ExecuteForTask(int tid) const;
+
+ protected:
+ int boost_;
+ int clamp_;
+};
+
+// To avoid issues in sdk_mac build
+#if defined(__ANDROID__)
+
+class SetTimerSlackAction : public ProfileAction {
+ public:
+ SetTimerSlackAction(unsigned long slack) noexcept : slack_(slack) {}
+
+ virtual bool ExecuteForTask(int tid) const;
+
+ private:
+ unsigned long slack_;
+
+ static bool IsTimerSlackSupported(int tid);
+};
+
+#else
+
+class SetTimerSlackAction : public ProfileAction {
+ public:
+ SetTimerSlackAction(unsigned long) noexcept {}
+
+ virtual bool ExecuteForTask(int) const { return true; }
+};
+
+#endif
+
+// Set attribute profile element
+class SetAttributeAction : public ProfileAction {
+ public:
+ SetAttributeAction(const ProfileAttribute* attribute, const std::string& value)
+ : attribute_(attribute), value_(value) {}
+
+ virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
+ virtual bool ExecuteForTask(int tid) const;
+
+ private:
+ const ProfileAttribute* attribute_;
+ std::string value_;
+};
+
+// Set cgroup profile element
+class SetCgroupAction : public ProfileAction {
+ public:
+ 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_; }
+ std::string path() const { return path_; }
+
+ private:
+ const CgroupController* controller_;
+ std::string path_;
+#ifdef CACHE_FILE_DESCRIPTORS
+ android::base::unique_fd fd_;
+#endif
+
+ static bool IsAppDependentPath(const std::string& path);
+ static bool AddTidToCgroup(int tid, int fd);
+};
+
+class TaskProfile {
+ public:
+ TaskProfile() {}
+
+ void Add(std::unique_ptr<ProfileAction> e) { elements_.push_back(std::move(e)); }
+
+ bool ExecuteForProcess(uid_t uid, pid_t pid) const;
+ bool ExecuteForTask(int tid) const;
+
+ private:
+ std::vector<std::unique_ptr<ProfileAction>> elements_;
+};
+
+class TaskProfiles {
+ public:
+ // Should be used by all users
+ static TaskProfiles& GetInstance();
+
+ const TaskProfile* GetProfile(const std::string& name) const;
+ const ProfileAttribute* GetAttribute(const std::string& name) const;
+
+ private:
+ std::map<std::string, std::unique_ptr<TaskProfile>> profiles_;
+ std::map<std::string, std::unique_ptr<ProfileAttribute>> attributes_;
+
+ TaskProfiles();
+
+ bool Load(const CgroupMap& cg_map);
+};
diff --git a/libsystem/OWNERS b/libsystem/OWNERS
index aeb160c..fdea804 100644
--- a/libsystem/OWNERS
+++ b/libsystem/OWNERS
@@ -1,2 +1,9 @@
-jessehall@google.com
-olv@google.com
+# graphics/composer
+adyabr@google.com
+lpy@google.com
+marissaw@google.com
+stoza@google.com
+vhau@google.com
+
+# camera
+etalvala@google.com
diff --git a/libutils/Android.bp b/libutils/Android.bp
index fb7ca32..93aa1e6 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -195,17 +195,83 @@
},
}
-// Include subdirectory makefiles
-// ============================================================
-
cc_test {
- name: "SharedBufferTest",
+ name: "libutils_test",
host_supported: true,
- static_libs: ["libutils"],
- shared_libs: ["liblog"],
- srcs: ["SharedBufferTest.cpp"],
+
+ srcs: [
+ "BitSet_test.cpp",
+ "FileMap_test.cpp",
+ "LruCache_test.cpp",
+ "Mutex_test.cpp",
+ "SharedBuffer_test.cpp",
+ "Singleton_test.cpp",
+ "String8_test.cpp",
+ "StrongPointer_test.cpp",
+ "Unicode_test.cpp",
+ "Vector_test.cpp",
+ ],
+
+ target: {
+ android: {
+ srcs: [
+ "SystemClock_test.cpp",
+ ],
+ shared_libs: [
+ "libz",
+ "liblog",
+ "libcutils",
+ "libutils",
+ "libbase",
+ ],
+ },
+ linux: {
+ srcs: [
+ "Looper_test.cpp",
+ "RefBase_test.cpp",
+ ],
+ },
+ host: {
+ static_libs: [
+ "libutils",
+ "liblog",
+ "libbase",
+ ],
+ },
+ },
+
+ required: [
+ "libutils_test_singleton1",
+ "libutils_test_singleton2",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wthread-safety",
+ ],
+}
+
+cc_test_library {
+ name: "libutils_test_singleton1",
+ host_supported: true,
+ relative_install_path: "libutils_test",
+ srcs: ["Singleton_test1.cpp"],
cflags: [
"-Wall",
"-Werror",
],
}
+
+cc_test_library {
+ name: "libutils_test_singleton2",
+ host_supported: true,
+ relative_install_path: "libutils_test",
+ srcs: ["Singleton_test2.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: ["libutils_test_singleton1"],
+}
diff --git a/libutils/tests/BitSet_test.cpp b/libutils/BitSet_test.cpp
similarity index 100%
rename from libutils/tests/BitSet_test.cpp
rename to libutils/BitSet_test.cpp
diff --git a/libutils/FileMap.cpp b/libutils/FileMap.cpp
index 5feb2aa..1202c15 100644
--- a/libutils/FileMap.cpp
+++ b/libutils/FileMap.cpp
@@ -174,12 +174,6 @@
return false;
}
#else // !defined(__MINGW32__)
- int prot, flags, adjust;
- off64_t adjOffset;
- size_t adjLength;
-
- void* ptr;
-
assert(fd >= 0);
assert(offset >= 0);
assert(length > 0);
@@ -193,20 +187,23 @@
}
}
- adjust = offset % mPageSize;
- adjOffset = offset - adjust;
- adjLength = length + adjust;
+ int adjust = offset % mPageSize;
+ off64_t adjOffset = offset - adjust;
+ size_t adjLength = length + adjust;
- flags = MAP_SHARED;
- prot = PROT_READ;
- if (!readOnly)
- prot |= PROT_WRITE;
+ int flags = MAP_SHARED;
+ int prot = PROT_READ;
+ if (!readOnly) prot |= PROT_WRITE;
- ptr = mmap(nullptr, adjLength, prot, flags, fd, adjOffset);
+ void* ptr = mmap(nullptr, adjLength, prot, flags, fd, adjOffset);
if (ptr == MAP_FAILED) {
- ALOGE("mmap(%lld,%zu) failed: %s\n",
- (long long)adjOffset, adjLength, strerror(errno));
- return false;
+ if (errno == EINVAL && length == 0) {
+ ptr = nullptr;
+ adjust = 0;
+ } else {
+ ALOGE("mmap(%lld,%zu) failed: %s\n", (long long)adjOffset, adjLength, strerror(errno));
+ return false;
+ }
}
mBasePtr = ptr;
#endif // !defined(__MINGW32__)
@@ -217,8 +214,6 @@
mDataPtr = (char*) mBasePtr + adjust;
mDataLength = length;
- assert(mBasePtr != NULL);
-
ALOGV("MAP: base %p/%zu data %p/%zu\n",
mBasePtr, mBaseLength, mDataPtr, mDataLength);
diff --git a/libutils/FileMap_test.cpp b/libutils/FileMap_test.cpp
new file mode 100644
index 0000000..576d89b
--- /dev/null
+++ b/libutils/FileMap_test.cpp
@@ -0,0 +1,34 @@
+/*
+ * 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 "utils/FileMap.h"
+
+#include <gtest/gtest.h>
+
+#include "android-base/file.h"
+
+TEST(FileMap, zero_length_mapping) {
+ // http://b/119818070 "app crashes when reading asset of zero length".
+ // mmap fails with EINVAL for a zero length region.
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ android::FileMap m;
+ ASSERT_TRUE(m.create("test", tf.fd, 4096, 0, true));
+ ASSERT_STREQ("test", m.getFileName());
+ ASSERT_EQ(0u, m.getDataLength());
+ ASSERT_EQ(4096, m.getDataOffset());
+}
diff --git a/libutils/tests/Looper_test.cpp b/libutils/Looper_test.cpp
similarity index 96%
rename from libutils/tests/Looper_test.cpp
rename to libutils/Looper_test.cpp
index 2282ced..6fdc0ed 100644
--- a/libutils/tests/Looper_test.cpp
+++ b/libutils/Looper_test.cpp
@@ -9,7 +9,7 @@
#include <unistd.h>
#include <time.h>
-#include "TestHelpers.h"
+#include <utils/threads.h>
// # of milliseconds to fudge stopwatch measurements
#define TIMING_TOLERANCE_MS 25
@@ -23,6 +23,59 @@
MSG_TEST4 = 4,
};
+class Pipe {
+public:
+ int sendFd;
+ int receiveFd;
+
+ Pipe() {
+ int fds[2];
+ ::pipe(fds);
+
+ receiveFd = fds[0];
+ sendFd = fds[1];
+ }
+
+ ~Pipe() {
+ if (sendFd != -1) {
+ ::close(sendFd);
+ }
+
+ if (receiveFd != -1) {
+ ::close(receiveFd);
+ }
+ }
+
+ status_t writeSignal() {
+ ssize_t nWritten = ::write(sendFd, "*", 1);
+ return nWritten == 1 ? 0 : -errno;
+ }
+
+ status_t readSignal() {
+ char buf[1];
+ ssize_t nRead = ::read(receiveFd, buf, 1);
+ return nRead == 1 ? 0 : nRead == 0 ? -EPIPE : -errno;
+ }
+};
+
+class DelayedTask : public Thread {
+ int mDelayMillis;
+
+public:
+ explicit DelayedTask(int delayMillis) : mDelayMillis(delayMillis) { }
+
+protected:
+ virtual ~DelayedTask() { }
+
+ virtual void doTask() = 0;
+
+ virtual bool threadLoop() {
+ usleep(mDelayMillis * 1000);
+ doTask();
+ return false;
+ }
+};
+
class DelayedWake : public DelayedTask {
sp<Looper> mLooper;
diff --git a/libutils/tests/LruCache_test.cpp b/libutils/LruCache_test.cpp
similarity index 100%
rename from libutils/tests/LruCache_test.cpp
rename to libutils/LruCache_test.cpp
diff --git a/libutils/tests/Mutex_test.cpp b/libutils/Mutex_test.cpp
similarity index 100%
rename from libutils/tests/Mutex_test.cpp
rename to libutils/Mutex_test.cpp
diff --git a/libutils/tests/RefBase_test.cpp b/libutils/RefBase_test.cpp
similarity index 100%
rename from libutils/tests/RefBase_test.cpp
rename to libutils/RefBase_test.cpp
diff --git a/libutils/SharedBufferTest.cpp b/libutils/SharedBuffer_test.cpp
similarity index 100%
rename from libutils/SharedBufferTest.cpp
rename to libutils/SharedBuffer_test.cpp
diff --git a/libutils/tests/Singleton_test.cpp b/libutils/Singleton_test.cpp
similarity index 88%
rename from libutils/tests/Singleton_test.cpp
rename to libutils/Singleton_test.cpp
index 9acd3c3..61084b0 100644
--- a/libutils/tests/Singleton_test.cpp
+++ b/libutils/Singleton_test.cpp
@@ -30,15 +30,15 @@
TEST(SingletonTest, bug35674422) {
std::string path = android::base::GetExecutableDirectory();
- // libutils_tests_singleton1.so contains the ANDROID_SINGLETON_STATIC_INSTANCE
+ // libutils_test_singleton1.so contains the ANDROID_SINGLETON_STATIC_INSTANCE
// definition of SingletonTestData, load it first.
- std::string lib = android::base::StringPrintf("%s/libutils_tests_singleton1.so", path.c_str());
+ std::string lib = android::base::StringPrintf("%s/libutils_test_singleton1.so", path.c_str());
void* handle1 = dlopen(lib.c_str(), RTLD_NOW);
ASSERT_TRUE(handle1 != nullptr) << dlerror();
- // libutils_tests_singleton2.so references SingletonTestData but should not
+ // libutils_test_singleton2.so references SingletonTestData but should not
// have a definition
- lib = android::base::StringPrintf("%s/libutils_tests_singleton2.so", path.c_str());
+ lib = android::base::StringPrintf("%s/libutils_test_singleton2.so", path.c_str());
void* handle2 = dlopen(lib.c_str(), RTLD_NOW);
ASSERT_TRUE(handle2 != nullptr) << dlerror();
diff --git a/libutils/tests/Singleton_test.h b/libutils/Singleton_test.h
similarity index 100%
rename from libutils/tests/Singleton_test.h
rename to libutils/Singleton_test.h
diff --git a/libutils/tests/Singleton_test1.cpp b/libutils/Singleton_test1.cpp
similarity index 100%
rename from libutils/tests/Singleton_test1.cpp
rename to libutils/Singleton_test1.cpp
diff --git a/libutils/tests/Singleton_test2.cpp b/libutils/Singleton_test2.cpp
similarity index 100%
rename from libutils/tests/Singleton_test2.cpp
rename to libutils/Singleton_test2.cpp
diff --git a/libutils/tests/String8_test.cpp b/libutils/String8_test.cpp
similarity index 100%
rename from libutils/tests/String8_test.cpp
rename to libutils/String8_test.cpp
diff --git a/libutils/tests/StrongPointer_test.cpp b/libutils/StrongPointer_test.cpp
similarity index 100%
rename from libutils/tests/StrongPointer_test.cpp
rename to libutils/StrongPointer_test.cpp
diff --git a/libutils/tests/SystemClock_test.cpp b/libutils/SystemClock_test.cpp
similarity index 100%
rename from libutils/tests/SystemClock_test.cpp
rename to libutils/SystemClock_test.cpp
diff --git a/libutils/tests/Unicode_test.cpp b/libutils/Unicode_test.cpp
similarity index 100%
rename from libutils/tests/Unicode_test.cpp
rename to libutils/Unicode_test.cpp
diff --git a/libutils/tests/Vector_test.cpp b/libutils/Vector_test.cpp
similarity index 100%
rename from libutils/tests/Vector_test.cpp
rename to libutils/Vector_test.cpp
diff --git a/libutils/tests/Android.bp b/libutils/tests/Android.bp
deleted file mode 100644
index 1390552..0000000
--- a/libutils/tests/Android.bp
+++ /dev/null
@@ -1,96 +0,0 @@
-//
-// Copyright (C) 2014 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-// Build the unit tests.
-
-cc_test {
- name: "libutils_tests",
- host_supported: true,
-
- srcs: [
- "BitSet_test.cpp",
- "LruCache_test.cpp",
- "Mutex_test.cpp",
- "Singleton_test.cpp",
- "String8_test.cpp",
- "StrongPointer_test.cpp",
- "Unicode_test.cpp",
- "Vector_test.cpp",
- ],
-
- target: {
- android: {
- srcs: [
- "SystemClock_test.cpp",
- ],
- shared_libs: [
- "libz",
- "liblog",
- "libcutils",
- "libutils",
- "libbase",
- ],
- },
- linux: {
- srcs: [
- "Looper_test.cpp",
- "RefBase_test.cpp",
- ],
- },
- host: {
- static_libs: [
- "libutils",
- "liblog",
- "libbase",
- ],
- },
- },
-
- required: [
- "libutils_tests_singleton1",
- "libutils_tests_singleton2",
- ],
-
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- "-Wthread-safety",
- ],
-}
-
-cc_test_library {
- name: "libutils_tests_singleton1",
- host_supported: true,
- relative_install_path: "libutils_tests",
- srcs: ["Singleton_test1.cpp"],
- cflags: [
- "-Wall",
- "-Werror",
- ],
-}
-
-cc_test_library {
- name: "libutils_tests_singleton2",
- host_supported: true,
- relative_install_path: "libutils_tests",
- srcs: ["Singleton_test2.cpp"],
- cflags: [
- "-Wall",
- "-Werror",
- ],
- shared_libs: ["libutils_tests_singleton1"],
-}
diff --git a/libutils/tests/README.txt b/libutils/tests/README.txt
deleted file mode 100644
index ad54e57..0000000
--- a/libutils/tests/README.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-Run device tests:
-
-mma -j<whatever>
-(after adb root; adb disable-verity; adb reboot)
-adb root
-adb remount
-adb sync
-adb shell /data/nativetest/libutils_tests/libutils_tests
diff --git a/libutils/tests/TestHelpers.h b/libutils/tests/TestHelpers.h
deleted file mode 100644
index 6801cd7..0000000
--- a/libutils/tests/TestHelpers.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef TESTHELPERS_H
-#define TESTHELPERS_H
-
-#include <utils/threads.h>
-
-namespace android {
-
-class Pipe {
-public:
- int sendFd;
- int receiveFd;
-
- Pipe() {
- int fds[2];
- ::pipe(fds);
-
- receiveFd = fds[0];
- sendFd = fds[1];
- }
-
- ~Pipe() {
- if (sendFd != -1) {
- ::close(sendFd);
- }
-
- if (receiveFd != -1) {
- ::close(receiveFd);
- }
- }
-
- status_t writeSignal() {
- ssize_t nWritten = ::write(sendFd, "*", 1);
- return nWritten == 1 ? 0 : -errno;
- }
-
- status_t readSignal() {
- char buf[1];
- ssize_t nRead = ::read(receiveFd, buf, 1);
- return nRead == 1 ? 0 : nRead == 0 ? -EPIPE : -errno;
- }
-};
-
-class DelayedTask : public Thread {
- int mDelayMillis;
-
-public:
- explicit DelayedTask(int delayMillis) : mDelayMillis(delayMillis) { }
-
-protected:
- virtual ~DelayedTask() { }
-
- virtual void doTask() = 0;
-
- virtual bool threadLoop() {
- usleep(mDelayMillis * 1000);
- doTask();
- return false;
- }
-};
-
-} // namespace android
-
-#endif // TESTHELPERS_H
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 6cb059e..562e578 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -1969,11 +1969,9 @@
clock_gettime(CLOCK_MONOTONIC_COARSE, &curr_tm);
if (get_time_diff_ms(&last_report_tm, &curr_tm) >= PSI_POLL_PERIOD_MS) {
- if (polling) {
- polling--;
- poll_handler->handler(poll_handler->data, 0);
- last_report_tm = curr_tm;
- }
+ polling--;
+ poll_handler->handler(poll_handler->data, 0);
+ last_report_tm = curr_tm;
}
} else {
/* Wait for events with no timeout */
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 5a6f41b..cbbc710 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -47,6 +47,28 @@
include $(BUILD_PREBUILT)
#######################################
+# cgroups.json
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := cgroups.json
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
+
+include $(BUILD_PREBUILT)
+
+#######################################
+# task_profiles.json
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := task_profiles.json
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
+
+include $(BUILD_PREBUILT)
+
+#######################################
# asan.options
ifneq ($(filter address,$(SANITIZE_TARGET)),)
diff --git a/rootdir/cgroups.json b/rootdir/cgroups.json
new file mode 100644
index 0000000..aa71956
--- /dev/null
+++ b/rootdir/cgroups.json
@@ -0,0 +1,43 @@
+{
+ "Cgroups": [
+ {
+ "Controller": "cpu",
+ "Path": "/dev/cpuctl",
+ "Mode": "0755",
+ "UID": "system",
+ "GID": "system"
+ },
+ {
+ "Controller": "cpuacct",
+ "Path": "/acct",
+ "Mode": "0555"
+ },
+ {
+ "Controller": "cpuset",
+ "Path": "/dev/cpuset",
+ "Mode": "0755",
+ "UID": "system",
+ "GID": "system"
+ },
+ {
+ "Controller": "memory",
+ "Path": "/dev/memcg",
+ "Mode": "0700",
+ "UID": "root",
+ "GID": "system"
+ },
+ {
+ "Controller": "schedtune",
+ "Path": "/dev/stune",
+ "Mode": "0755",
+ "UID": "system",
+ "GID": "system"
+ }
+ ],
+ "Cgroups2": {
+ "Path": "/dev/cg2_bpf",
+ "Mode": "0600",
+ "UID": "root",
+ "GID": "root"
+ }
+}
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 9bf9058..7aa097d 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -24,6 +24,9 @@
dir.system = /data/nativetest64
dir.system = /data/benchmarktest
dir.system = /data/benchmarktest64
+# TODO(b/123864775): Ensure tests are run from one of the directories above and
+# remove this.
+dir.system = /data/local/tmp
dir.postinstall = /postinstall
@@ -78,9 +81,9 @@
namespace.default.asan.search.paths = /data/asan/system/${LIB}
namespace.default.asan.search.paths += /system/${LIB}
-namespace.default.asan.search.paths += /data/asan/product/${LIB}
+namespace.default.asan.search.paths += /data/asan/%PRODUCT%/${LIB}
namespace.default.asan.search.paths += /%PRODUCT%/${LIB}
-namespace.default.asan.search.paths += /data/asan/product_services/${LIB}
+namespace.default.asan.search.paths += /data/asan/%PRODUCT_SERVICES%/${LIB}
namespace.default.asan.search.paths += /%PRODUCT_SERVICES%/${LIB}
namespace.default.asan.permitted.paths = /data
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index ca180c0..1904445 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -50,9 +50,9 @@
namespace.default.asan.search.paths += /odm/${LIB}
namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
namespace.default.asan.search.paths += /vendor/${LIB}
-namespace.default.asan.search.paths += /data/asan/product/${LIB}
+namespace.default.asan.search.paths += /data/asan/%PRODUCT%/${LIB}
namespace.default.asan.search.paths += /%PRODUCT%/${LIB}
-namespace.default.asan.search.paths += /data/asan/product_services/${LIB}
+namespace.default.asan.search.paths += /data/asan/%PRODUCT_SERVICES%/${LIB}
namespace.default.asan.search.paths += /%PRODUCT_SERVICES%/${LIB}
# Keep in sync with the platform namespace in the com.android.runtime APEX
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 7aba3dc..57032bc 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -11,6 +11,7 @@
import /init.usb.configfs.rc
import /init.${ro.zygote}.rc
+# Cgroups are mounted right before early-init using list from /etc/cgroups.json
on early-init
# Mount shared so changes propagate into child namespaces
# Do this before other processes are started from init. Otherwise,
@@ -30,14 +31,8 @@
# Set the security context of /postinstall if present.
restorecon /postinstall
- # Mount cgroup mount point for cpu accounting
- mount cgroup none /acct nodev noexec nosuid cpuacct
- chmod 0555 /acct
mkdir /acct/uid
- # root memory control cgroup, used by lmkd
- mkdir /dev/memcg 0700 root system
- mount cgroup none /dev/memcg nodev noexec nosuid memory
# memory.pressure_level used by lmkd
chown root system /dev/memcg/memory.pressure_level
chmod 0040 /dev/memcg/memory.pressure_level
@@ -69,8 +64,6 @@
symlink /system/vendor /vendor
# Create energy-aware scheduler tuning nodes
- mkdir /dev/stune
- mount cgroup none /dev/stune nodev noexec nosuid schedtune
mkdir /dev/stune/foreground
mkdir /dev/stune/background
mkdir /dev/stune/top-app
@@ -164,8 +157,6 @@
chmod 0400 /proc/net/fib_trie
# Create cgroup mount points for process groups
- mkdir /dev/cpuctl
- mount cgroup none /dev/cpuctl nodev noexec nosuid cpu
chown system system /dev/cpuctl
chown system system /dev/cpuctl/tasks
chmod 0666 /dev/cpuctl/tasks
@@ -173,9 +164,6 @@
write /dev/cpuctl/cpu.rt_runtime_us 950000
# sets up initial cpusets for ActivityManager
- mkdir /dev/cpuset
- mount cpuset none /dev/cpuset nodev noexec nosuid
-
# this ensures that the cpusets are present and usable, but the device's
# init.rc must actually set the correct cpus
mkdir /dev/cpuset/foreground
@@ -237,8 +225,6 @@
# This is needed by any process that uses socket tagging.
chmod 0644 /dev/xt_qtaguid
- mkdir /dev/cg2_bpf
- mount cgroup2 cg2_bpf /dev/cg2_bpf nodev noexec nosuid
chown root root /dev/cg2_bpf
chmod 0600 /dev/cg2_bpf
mount bpf bpf /sys/fs/bpf nodev noexec nosuid
@@ -291,6 +277,10 @@
# Start logd before any other services run to ensure we capture all of their logs.
start logd
+
+ # Start apexd as soon as we can
+ start apexd
+
# Start essential services.
start servicemanager
start hwservicemanager
@@ -426,8 +416,8 @@
mkdir /data/bootchart 0755 shell shell
bootchart start
- # Start apexd as soon as we can
- start apexd
+ # /data/apex is now available. Let apexd to scan and activate APEXes.
+ setprop apexd.data.status ready
# Avoid predictable entropy pool. Carry over entropy from previous boot.
copy /data/system/entropy.dat /dev/urandom
@@ -545,6 +535,9 @@
mkdir /data/anr 0775 system system
mkdir /data/apex 0750 root system
+ mkdir /data/apex/active 0750 root system
+ mkdir /data/apex/backup 0700 root system
+ mkdir /data/apex/sessions 0700 root system
mkdir /data/staging 0750 system system
# NFC: create data/nfc for nv storage
@@ -604,6 +597,11 @@
# Set indication (checked by vold) that we have finished this action
#setprop vold.post_fs_data_done 1
+ # sys.memfd_use set to false by default, which keeps it disabled
+ # until it is confirmed that apps and vendor processes don't make
+ # IOCTLs on ashmem fds any more.
+ setprop sys.use_memfd false
+
# It is recommended to put unnecessary data/ initialization from post-fs-data
# to start-zygote in device's init.rc to unblock zygote start.
on zygote-start && property:ro.crypto.state=unencrypted
diff --git a/rootdir/task_profiles.json b/rootdir/task_profiles.json
new file mode 100644
index 0000000..5a090c5
--- /dev/null
+++ b/rootdir/task_profiles.json
@@ -0,0 +1,445 @@
+{
+ "Attributes": [
+ {
+ "Name": "LowCapacityCPUs",
+ "Controller": "cpuset",
+ "File": "background/cpus"
+ },
+ {
+ "Name": "HighCapacityCPUs",
+ "Controller": "cpuset",
+ "File": "foreground/cpus"
+ },
+ {
+ "Name": "MaxCapacityCPUs",
+ "Controller": "cpuset",
+ "File": "top-app/cpus"
+ },
+
+ {
+ "Name": "MemLimit",
+ "Controller": "memory",
+ "File": "memory.limit_in_bytes"
+ },
+ {
+ "Name": "MemSoftLimit",
+ "Controller": "memory",
+ "File": "memory.soft_limit_in_bytes"
+ },
+ {
+ "Name": "MemSwappiness",
+ "Controller": "memory",
+ "File": "memory.swappiness"
+ },
+ {
+ "Name": "STuneBoost",
+ "Controller": "schedtune",
+ "File": "schedtune.boost"
+ },
+ {
+ "Name": "STunePreferIdle",
+ "Controller": "schedtune",
+ "File": "schedtune.prefer_idle"
+ },
+ {
+ "Name": "UClampMin",
+ "Controller": "cpu",
+ "File": "cpu.util.min"
+ },
+ {
+ "Name": "UClampMax",
+ "Controller": "cpu",
+ "File": "cpu.util.max"
+ }
+ ],
+
+ "Profiles": [
+ {
+ "Name": "HighEnergySaving",
+ "Actions" : [
+ {
+ "Name" : "JoinCgroup",
+ "Params" :
+ {
+ "Controller": "schedtune",
+ "Path": "background"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "NormalPerformance",
+ "Actions" : [
+ {
+ "Name" : "JoinCgroup",
+ "Params" :
+ {
+ "Controller": "schedtune",
+ "Path": ""
+ }
+ }
+ ]
+ },
+ {
+ "Name": "HighPerformance",
+ "Actions" : [
+ {
+ "Name" : "JoinCgroup",
+ "Params" :
+ {
+ "Controller": "schedtune",
+ "Path": "foreground"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "MaxPerformance",
+ "Actions" : [
+ {
+ "Name" : "JoinCgroup",
+ "Params" :
+ {
+ "Controller": "schedtune",
+ "Path": "top-app"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "RealtimePerformance",
+ "Actions" : [
+ {
+ "Name" : "JoinCgroup",
+ "Params" :
+ {
+ "Controller": "schedtune",
+ "Path": "rt"
+ }
+ }
+ ]
+ },
+
+ {
+ "Name": "CpuPolicySpread",
+ "Actions" : [
+ {
+ "Name" : "SetAttribute",
+ "Params" :
+ {
+ "Name" : "STunePreferIdle",
+ "Value" : "1"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "CpuPolicyPack",
+ "Actions" : [
+ {
+ "Name" : "SetAttribute",
+ "Params" :
+ {
+ "Name" : "STunePreferIdle",
+ "Value" : "0"
+ }
+ }
+ ]
+ },
+
+ {
+ "Name": "VrKernelCapacity",
+ "Actions" : [
+ {
+ "Name" : "JoinCgroup",
+ "Params" :
+ {
+ "Controller": "cpuset",
+ "Path": ""
+ }
+ }
+ ]
+ },
+ {
+ "Name": "VrServiceCapacityLow",
+ "Actions" : [
+ {
+ "Name" : "JoinCgroup",
+ "Params" :
+ {
+ "Controller": "cpuset",
+ "Path": "system/background"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "VrServiceCapacityNormal",
+ "Actions" : [
+ {
+ "Name" : "JoinCgroup",
+ "Params" :
+ {
+ "Controller": "cpuset",
+ "Path": "system"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "VrServiceCapacityHigh",
+ "Actions" : [
+ {
+ "Name" : "JoinCgroup",
+ "Params" :
+ {
+ "Controller": "cpuset",
+ "Path": "system/performance"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "VrProcessCapacityLow",
+ "Actions" : [
+ {
+ "Name" : "JoinCgroup",
+ "Params" :
+ {
+ "Controller": "cpuset",
+ "Path": "application/background"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "VrProcessCapacityNormal",
+ "Actions" : [
+ {
+ "Name" : "JoinCgroup",
+ "Params" :
+ {
+ "Controller": "cpuset",
+ "Path": "application"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "VrProcessCapacityHigh",
+ "Actions" : [
+ {
+ "Name" : "JoinCgroup",
+ "Params" :
+ {
+ "Controller": "cpuset",
+ "Path": "application/performance"
+ }
+ }
+ ]
+ },
+
+ {
+ "Name": "ProcessCapacityLow",
+ "Actions" : [
+ {
+ "Name" : "JoinCgroup",
+ "Params" :
+ {
+ "Controller": "cpuset",
+ "Path": "background"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "ProcessCapacityNormal",
+ "Actions" : [
+ {
+ "Name" : "JoinCgroup",
+ "Params" :
+ {
+ "Controller": "cpuset",
+ "Path": ""
+ }
+ }
+ ]
+ },
+ {
+ "Name": "ProcessCapacityHigh",
+ "Actions" : [
+ {
+ "Name" : "JoinCgroup",
+ "Params" :
+ {
+ "Controller": "cpuset",
+ "Path": "foreground"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "ProcessCapacityMax",
+ "Actions" : [
+ {
+ "Name" : "JoinCgroup",
+ "Params" :
+ {
+ "Controller": "cpuset",
+ "Path": "top-app"
+ }
+ }
+ ]
+ },
+
+ {
+ "Name": "ServiceCapacityLow",
+ "Actions" : [
+ {
+ "Name" : "JoinCgroup",
+ "Params" :
+ {
+ "Controller": "cpuset",
+ "Path": "system-background"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "ServiceCapacityRestricted",
+ "Actions" : [
+ {
+ "Name" : "JoinCgroup",
+ "Params" :
+ {
+ "Controller": "cpuset",
+ "Path": "restricted"
+ }
+ }
+ ]
+ },
+
+ {
+ "Name": "CameraServiceCapacity",
+ "Actions" : [
+ {
+ "Name" : "JoinCgroup",
+ "Params" :
+ {
+ "Controller": "cpuset",
+ "Path": "camera-daemon"
+ }
+ }
+ ]
+ },
+
+ {
+ "Name": "TimerSlackHigh",
+ "Actions" : [
+ {
+ "Name" : "SetTimerSlack",
+ "Params" :
+ {
+ "Slack": "40000000"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "TimerSlackNormal",
+ "Actions" : [
+ {
+ "Name" : "SetTimerSlack",
+ "Params" :
+ {
+ "Slack": "50000"
+ }
+ }
+ ]
+ },
+
+ {
+ "Name": "PerfBoost",
+ "Actions" : [
+ {
+ "Name" : "SetClamps",
+ "Params" :
+ {
+ "Boost" : "50%",
+ "Clamp" : "0"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "PerfClamp",
+ "Actions" : [
+ {
+ "Name" : "SetClamps",
+ "Params" :
+ {
+ "Boost" : "0",
+ "Clamp" : "30%"
+ }
+ }
+ ]
+ },
+
+ {
+ "Name": "LowMemoryUsage",
+ "Actions" : [
+ {
+ "Name" : "SetAttribute",
+ "Params" :
+ {
+ "Name" : "MemSoftLimit",
+ "Value" : "16MB"
+ }
+ },
+ {
+ "Name" : "SetAttribute",
+ "Params" :
+ {
+ "Name" : "MemSwappiness",
+ "Value" : "150"
+
+ }
+ }
+ ]
+ },
+ {
+ "Name": "HighMemoryUsage",
+ "Actions" : [
+ {
+ "Name" : "SetAttribute",
+ "Params" :
+ {
+ "Name" : "MemSoftLimit",
+ "Value" : "512MB"
+ }
+ },
+ {
+ "Name" : "SetAttribute",
+ "Params" :
+ {
+ "Name" : "MemSwappiness",
+ "Value" : "100"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "SystemMemoryProcess",
+ "Actions" : [
+ {
+ "Name" : "JoinCgroup",
+ "Params" :
+ {
+ "Controller": "memory",
+ "Path": "system"
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/rootdir/update_and_install_ld_config.mk b/rootdir/update_and_install_ld_config.mk
index 450be66..852e234 100644
--- a/rootdir/update_and_install_ld_config.mk
+++ b/rootdir/update_and_install_ld_config.mk
@@ -118,7 +118,12 @@
$(hide) sed -i.bak -e "s?%SANITIZER_RUNTIME_LIBRARIES%?$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g" $@
$(hide) sed -i.bak -e "s?%VNDK_VER%?$(PRIVATE_VNDK_VERSION_SUFFIX)?g" $@
$(hide) sed -i.bak -e "s?%PRODUCT%?$(TARGET_COPY_OUT_PRODUCT)?g" $@
+ifeq ($(TARGET_COPY_OUT_PRODUCT),$(TARGET_COPY_OUT_PRODUCT_SERVICES))
+ # Remove lines containing %PRODUCT_SERVICES% (identical to the %PRODUCT% ones)
+ $(hide) sed -i.bak -e "\?%PRODUCT_SERVICES%?d" $@
+else
$(hide) sed -i.bak -e "s?%PRODUCT_SERVICES%?$(TARGET_COPY_OUT_PRODUCT_SERVICES)?g" $@
+endif
$(hide) sed -i.bak -e "s?^$(PRIVATE_VNDK_VERSION_TAG)??g" $@
$(hide) sed -i.bak "/^\#VNDK[0-9]\{2\}\#.*$$/d" $@
$(hide) rm -f $@.bak