Merge "init: init_kill_services_test"
diff --git a/adb/Android.bp b/adb/Android.bp
index 97bc4da..d8fa713 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -387,17 +387,17 @@
generated_headers: ["platform_tools_version"],
static_libs: [
- "libadbconnection_server",
- "libapp_processes_protos_lite",
"libdiagnose_usb",
],
shared_libs: [
+ "libadbconnection_server",
"libadb_crypto",
"libadb_pairing_connection",
"libadb_protos",
"libadb_tls_connection",
"libadbd_auth",
+ "libapp_processes_protos_lite",
"libasyncio",
"libbase",
"libcrypto",
@@ -432,12 +432,13 @@
exclude_shared_libs: [
"libadb_pairing_auth",
"libadb_pairing_connection",
+ "libapp_processes_protos_lite",
],
}
},
}
-cc_library_static {
+cc_library {
name: "libadbd_services",
defaults: ["adbd_defaults", "host_adbd_supported"],
recovery_available: true,
@@ -458,9 +459,7 @@
static_libs: [
"libadbconnection_server",
"libadbd_core",
- "libapp_processes_protos_lite",
"libdiagnose_usb",
- "libprotobuf-cpp-lite",
],
shared_libs: [
@@ -470,11 +469,14 @@
"libadb_tls_connection",
"libadbd_auth",
"libadbd_fs",
+ "libapp_processes_protos_lite",
"libasyncio",
"libbase",
"libcrypto",
"libcrypto_utils",
+ "libcutils_sockets",
"liblog",
+ "libprotobuf-cpp-lite",
],
target: {
@@ -513,20 +515,20 @@
// libminadbd wants both, as it's used to build native tests.
compile_multilib: "both",
- // libadbd doesn't build any additional source, but to expose libadbd_core as a shared library.
whole_static_libs: [
- "libadbconnection_server",
"libadbd_core",
- "libapp_processes_protos_lite",
- "libprotobuf-cpp-lite",
],
shared_libs: [
+ "libadbconnection_server",
+ "libapp_processes_protos_lite",
+ "libprotobuf-cpp-lite",
"libadb_crypto",
"libadb_pairing_connection",
"libadb_tls_connection",
"libadbd_auth",
"libadbd_fs",
+ "libadbd_services",
"libasyncio",
"libbase",
"libcrypto",
@@ -545,7 +547,6 @@
},
static_libs: [
- "libadbd_services",
"libcutils_sockets",
"libdiagnose_usb",
"libmdnssd",
@@ -588,11 +589,9 @@
"libcrypto_utils",
"libcutils_sockets",
"libdiagnose_usb",
- "liblog",
"libmdnssd",
"libminijail",
"libprotobuf-cpp-lite",
- "libselinux",
"libssl",
],
@@ -602,6 +601,8 @@
"libadbd_auth",
"libadbd_fs",
"libcrypto",
+ "liblog",
+ "libselinux",
],
target: {
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 1186060..7c7da08 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -194,8 +194,8 @@
" generate adb public/private key; private key stored in FILE,\n"
"\n"
"scripting:\n"
- " wait-for[-TRANSPORT]-STATE\n"
- " wait for device to be in the given state\n"
+ " wait-for[-TRANSPORT]-STATE...\n"
+ " wait for device to be in a given state\n"
" STATE: device, recovery, rescue, sideload, bootloader, or disconnect\n"
" TRANSPORT: usb, local, or any [default=any]\n"
" get-state print offline | bootloader | device\n"
@@ -1057,17 +1057,16 @@
static bool wait_for_device(const char* service,
std::optional<std::chrono::milliseconds> timeout = std::nullopt) {
std::vector<std::string> components = android::base::Split(service, "-");
- if (components.size() < 3 || components.size() > 4) {
+ if (components.size() < 3) {
fprintf(stderr, "adb: couldn't parse 'wait-for' command: %s\n", service);
return false;
}
- TransportType t;
- adb_get_transport(&t, nullptr, nullptr);
-
- // Was the caller vague about what they'd like us to wait for?
- // If so, check they weren't more specific in their choice of transport type.
- if (components.size() == 3) {
+ // If the first thing after "wait-for-" wasn't a TRANSPORT, insert whatever
+ // the current transport implies.
+ if (components[2] != "usb" && components[2] != "local" && components[2] != "any") {
+ TransportType t;
+ adb_get_transport(&t, nullptr, nullptr);
auto it = components.begin() + 2;
if (t == kTransportUsb) {
components.insert(it, "usb");
@@ -1076,23 +1075,9 @@
} else {
components.insert(it, "any");
}
- } else if (components[2] != "any" && components[2] != "local" && components[2] != "usb") {
- fprintf(stderr, "adb: unknown type %s; expected 'any', 'local', or 'usb'\n",
- components[2].c_str());
- return false;
}
- if (components[3] != "any" && components[3] != "bootloader" && components[3] != "device" &&
- components[3] != "recovery" && components[3] != "rescue" && components[3] != "sideload" &&
- components[3] != "disconnect") {
- fprintf(stderr,
- "adb: unknown state %s; "
- "expected 'any', 'bootloader', 'device', 'recovery', 'rescue', 'sideload', or "
- "'disconnect'\n",
- components[3].c_str());
- return false;
- }
-
+ // Stitch it back together and send it over...
std::string cmd = format_host_command(android::base::Join(components, "-").c_str());
if (timeout) {
std::thread([timeout]() {
diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp
index 922f2ba..04ad536 100644
--- a/adb/client/file_sync_client.cpp
+++ b/adb/client/file_sync_client.cpp
@@ -29,6 +29,7 @@
#include <utime.h>
#include <chrono>
+#include <deque>
#include <functional>
#include <memory>
#include <sstream>
@@ -203,7 +204,7 @@
class SyncConnection {
public:
- SyncConnection() : expect_done_(false) {
+ SyncConnection() {
max = SYNC_DATA_MAX; // TODO: decide at runtime.
std::string error;
@@ -239,16 +240,6 @@
bool IsValid() { return fd >= 0; }
- bool ReceivedError(const char* from, const char* to) {
- adb_pollfd pfd = {.fd = fd.get(), .events = POLLIN};
- int rc = adb_poll(&pfd, 1, 0);
- if (rc < 0) {
- Error("failed to poll: %s", strerror(errno));
- return true;
- }
- return rc != 0;
- }
-
void NewTransfer() {
current_ledger_.Reset();
}
@@ -258,6 +249,11 @@
global_ledger_.bytes_transferred += bytes;
}
+ void RecordFileSent(std::string from, std::string to) {
+ RecordFilesTransferred(1);
+ deferred_acknowledgements_.emplace_back(std::move(from), std::move(to));
+ }
+
void RecordFilesTransferred(size_t files) {
current_ledger_.files_transferred += files;
global_ledger_.files_transferred += files;
@@ -283,39 +279,38 @@
}
}
- bool SendRequest(int id, const char* path_and_mode) {
- size_t path_length = strlen(path_and_mode);
- if (path_length > 1024) {
- Error("SendRequest failed: path too long: %zu", path_length);
+ bool SendRequest(int id, const std::string& path) {
+ if (path.length() > 1024) {
+ Error("SendRequest failed: path too long: %zu", path.length());
errno = ENAMETOOLONG;
return false;
}
// Sending header and payload in a single write makes a noticeable
// difference to "adb sync" performance.
- std::vector<char> buf(sizeof(SyncRequest) + path_length);
+ std::vector<char> buf(sizeof(SyncRequest) + path.length());
SyncRequest* req = reinterpret_cast<SyncRequest*>(&buf[0]);
req->id = id;
- req->path_length = path_length;
+ req->path_length = path.length();
char* data = reinterpret_cast<char*>(req + 1);
- memcpy(data, path_and_mode, path_length);
+ memcpy(data, path.data(), path.length());
- return WriteFdExactly(fd, &buf[0], buf.size());
+ return WriteFdExactly(fd, buf.data(), buf.size());
}
- bool SendStat(const char* path_and_mode) {
+ bool SendStat(const std::string& path) {
if (!have_stat_v2_) {
errno = ENOTSUP;
return false;
}
- return SendRequest(ID_STAT_V2, path_and_mode);
+ return SendRequest(ID_STAT_V2, path);
}
- bool SendLstat(const char* path_and_mode) {
+ bool SendLstat(const std::string& path) {
if (have_stat_v2_) {
- return SendRequest(ID_LSTAT_V2, path_and_mode);
+ return SendRequest(ID_LSTAT_V2, path);
} else {
- return SendRequest(ID_LSTAT_V1, path_and_mode);
+ return SendRequest(ID_LSTAT_V1, path);
}
}
@@ -374,7 +369,7 @@
return true;
}
- bool SendLs(const char* path) {
+ bool SendLs(const std::string& path) {
return SendRequest(have_ls_v2_ ? ID_LIST_V2 : ID_LIST_V1, path);
}
@@ -415,28 +410,26 @@
// Sending header, payload, and footer in a single write makes a huge
// difference to "adb sync" performance.
- bool SendSmallFile(const char* path_and_mode,
- const char* lpath, const char* rpath,
- unsigned mtime,
- const char* data, size_t data_length) {
- size_t path_length = strlen(path_and_mode);
- if (path_length > 1024) {
- Error("SendSmallFile failed: path too long: %zu", path_length);
+ bool SendSmallFile(const std::string& path, mode_t mode, const std::string& lpath,
+ const std::string& rpath, unsigned mtime, const char* data,
+ size_t data_length) {
+ std::string path_and_mode = android::base::StringPrintf("%s,%d", path.c_str(), mode);
+ if (path_and_mode.length() > 1024) {
+ Error("SendSmallFile failed: path too long: %zu", path_and_mode.length());
errno = ENAMETOOLONG;
return false;
}
- std::vector<char> buf(sizeof(SyncRequest) + path_length +
- sizeof(SyncRequest) + data_length +
- sizeof(SyncRequest));
+ std::vector<char> buf(sizeof(SyncRequest) + path_and_mode.length() + sizeof(SyncRequest) +
+ data_length + sizeof(SyncRequest));
char* p = &buf[0];
SyncRequest* req_send = reinterpret_cast<SyncRequest*>(p);
req_send->id = ID_SEND;
- req_send->path_length = path_length;
+ req_send->path_length = path_and_mode.length();
p += sizeof(SyncRequest);
- memcpy(p, path_and_mode, path_length);
- p += path_length;
+ memcpy(p, path_and_mode.data(), path_and_mode.size());
+ p += path_and_mode.length();
SyncRequest* req_data = reinterpret_cast<SyncRequest*>(p);
req_data->id = ID_DATA;
@@ -451,34 +444,34 @@
p += sizeof(SyncRequest);
WriteOrDie(lpath, rpath, &buf[0], (p - &buf[0]));
- expect_done_ = true;
- // RecordFilesTransferred gets called in CopyDone.
+ RecordFileSent(lpath, rpath);
RecordBytesTransferred(data_length);
ReportProgress(rpath, data_length, data_length);
return true;
}
- bool SendLargeFile(const char* path_and_mode,
- const char* lpath, const char* rpath,
- unsigned mtime) {
+ bool SendLargeFile(const std::string& path, mode_t mode, const std::string& lpath,
+ const std::string& rpath, unsigned mtime) {
+ std::string path_and_mode = android::base::StringPrintf("%s,%d", path.c_str(), mode);
if (!SendRequest(ID_SEND, path_and_mode)) {
- Error("failed to send ID_SEND message '%s': %s", path_and_mode, strerror(errno));
+ Error("failed to send ID_SEND message '%s': %s", path_and_mode.c_str(),
+ strerror(errno));
return false;
}
struct stat st;
- if (stat(lpath, &st) == -1) {
- Error("cannot stat '%s': %s", lpath, strerror(errno));
+ if (stat(lpath.c_str(), &st) == -1) {
+ Error("cannot stat '%s': %s", lpath.c_str(), strerror(errno));
return false;
}
uint64_t total_size = st.st_size;
uint64_t bytes_copied = 0;
- unique_fd lfd(adb_open(lpath, O_RDONLY));
+ unique_fd lfd(adb_open(lpath.c_str(), O_RDONLY));
if (lfd < 0) {
- Error("opening '%s' locally failed: %s", lpath, strerror(errno));
+ Error("opening '%s' locally failed: %s", lpath.c_str(), strerror(errno));
return false;
}
@@ -487,7 +480,7 @@
while (true) {
int bytes_read = adb_read(lfd, sbuf.data, max - sizeof(SyncRequest));
if (bytes_read == -1) {
- Error("reading '%s' locally failed: %s", lpath, strerror(errno));
+ Error("reading '%s' locally failed: %s", lpath.c_str(), strerror(errno));
return false;
} else if (bytes_read == 0) {
break;
@@ -499,55 +492,53 @@
RecordBytesTransferred(bytes_read);
bytes_copied += bytes_read;
- // Check to see if we've received an error from the other side.
- if (ReceivedError(lpath, rpath)) {
- break;
- }
-
ReportProgress(rpath, bytes_copied, total_size);
}
syncmsg msg;
msg.data.id = ID_DONE;
msg.data.size = mtime;
- expect_done_ = true;
-
- // RecordFilesTransferred gets called in CopyDone.
+ RecordFileSent(lpath, rpath);
return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data));
}
- bool CopyDone(const char* from, const char* to) {
+ bool ReadAcknowledgments() {
+ bool result = true;
+ while (!deferred_acknowledgements_.empty()) {
+ auto [from, to] = std::move(deferred_acknowledgements_.front());
+ deferred_acknowledgements_.pop_front();
+ result &= CopyDone(from, to);
+ }
+ return result;
+ }
+
+ bool CopyDone(const std::string& from, const std::string& to) {
syncmsg msg;
if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
- Error("failed to copy '%s' to '%s': couldn't read from device", from, to);
+ Error("failed to copy '%s' to '%s': couldn't read from device", from.c_str(),
+ to.c_str());
return false;
}
if (msg.status.id == ID_OKAY) {
- if (expect_done_) {
- expect_done_ = false;
- RecordFilesTransferred(1);
- return true;
- } else {
- Error("failed to copy '%s' to '%s': received premature success", from, to);
- return true;
- }
+ return true;
}
if (msg.status.id != ID_FAIL) {
- Error("failed to copy '%s' to '%s': unknown reason %d", from, to, msg.status.id);
+ Error("failed to copy '%s' to '%s': unknown reason %d", from.c_str(), to.c_str(),
+ msg.status.id);
return false;
}
return ReportCopyFailure(from, to, msg);
}
- bool ReportCopyFailure(const char* from, const char* to, const syncmsg& msg) {
+ bool ReportCopyFailure(const std::string& from, const std::string& to, const syncmsg& msg) {
std::vector<char> buf(msg.status.msglen + 1);
if (!ReadFdExactly(fd, &buf[0], msg.status.msglen)) {
- Error("failed to copy '%s' to '%s'; failed to read reason (!): %s",
- from, to, strerror(errno));
+ Error("failed to copy '%s' to '%s'; failed to read reason (!): %s", from.c_str(),
+ to.c_str(), strerror(errno));
return false;
}
buf[msg.status.msglen] = 0;
- Error("failed to copy '%s' to '%s': remote %s", from, to, &buf[0]);
+ Error("failed to copy '%s' to '%s': remote %s", from.c_str(), to.c_str(), &buf[0]);
return false;
}
@@ -616,7 +607,7 @@
size_t max;
private:
- bool expect_done_;
+ std::deque<std::pair<std::string, std::string>> deferred_acknowledgements_;
FeatureSet features_;
bool have_stat_v2_;
bool have_ls_v2_;
@@ -629,16 +620,19 @@
return SendRequest(ID_QUIT, ""); // TODO: add a SendResponse?
}
- bool WriteOrDie(const char* from, const char* to, const void* data, size_t data_length) {
+ bool WriteOrDie(const std::string& from, const std::string& to, const void* data,
+ size_t data_length) {
if (!WriteFdExactly(fd, data, data_length)) {
if (errno == ECONNRESET) {
// Assume adbd told us why it was closing the connection, and
// try to read failure reason from adbd.
syncmsg msg;
if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
- Error("failed to copy '%s' to '%s': no response: %s", from, to, strerror(errno));
+ Error("failed to copy '%s' to '%s': no response: %s", from.c_str(), to.c_str(),
+ strerror(errno));
} else if (msg.status.id != ID_FAIL) {
- Error("failed to copy '%s' to '%s': not ID_FAIL: %d", from, to, msg.status.id);
+ Error("failed to copy '%s' to '%s': not ID_FAIL: %d", from.c_str(), to.c_str(),
+ msg.status.id);
} else {
ReportCopyFailure(from, to, msg);
}
@@ -651,20 +645,20 @@
}
};
-static bool sync_ls(SyncConnection& sc, const char* path,
+static bool sync_ls(SyncConnection& sc, const std::string& path,
const std::function<sync_ls_cb>& func) {
return sc.SendLs(path) && sc.FinishLs(func);
}
-static bool sync_stat(SyncConnection& sc, const char* path, struct stat* st) {
+static bool sync_stat(SyncConnection& sc, const std::string& path, struct stat* st) {
return sc.SendStat(path) && sc.FinishStat(st);
}
-static bool sync_lstat(SyncConnection& sc, const char* path, struct stat* st) {
+static bool sync_lstat(SyncConnection& sc, const std::string& path, struct stat* st) {
return sc.SendLstat(path) && sc.FinishStat(st);
}
-static bool sync_stat_fallback(SyncConnection& sc, const char* path, struct stat* st) {
+static bool sync_stat_fallback(SyncConnection& sc, const std::string& path, struct stat* st) {
if (sync_stat(sc, path, st)) {
return true;
}
@@ -688,7 +682,7 @@
struct stat tmp_st;
st->st_mode &= ~S_IFMT;
- if (sync_lstat(sc, dir_path.c_str(), &tmp_st)) {
+ if (sync_lstat(sc, dir_path, &tmp_st)) {
st->st_mode |= S_IFDIR;
} else {
st->st_mode |= S_IFREG;
@@ -697,10 +691,8 @@
return true;
}
-static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath, unsigned mtime,
- mode_t mode, bool sync) {
- std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode);
-
+static bool sync_send(SyncConnection& sc, const std::string& lpath, const std::string& rpath,
+ unsigned mtime, mode_t mode, bool sync) {
if (sync) {
struct stat st;
if (sync_lstat(sc, rpath, &st)) {
@@ -714,41 +706,40 @@
if (S_ISLNK(mode)) {
#if !defined(_WIN32)
char buf[PATH_MAX];
- ssize_t data_length = readlink(lpath, buf, PATH_MAX - 1);
+ ssize_t data_length = readlink(lpath.c_str(), buf, PATH_MAX - 1);
if (data_length == -1) {
- sc.Error("readlink '%s' failed: %s", lpath, strerror(errno));
+ sc.Error("readlink '%s' failed: %s", lpath.c_str(), strerror(errno));
return false;
}
buf[data_length++] = '\0';
- if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime, buf, data_length)) {
+ if (!sc.SendSmallFile(rpath, mode, lpath, rpath, mtime, buf, data_length)) {
return false;
}
- return sc.CopyDone(lpath, rpath);
+ return true;
#endif
}
struct stat st;
- if (stat(lpath, &st) == -1) {
- sc.Error("failed to stat local file '%s': %s", lpath, strerror(errno));
+ if (stat(lpath.c_str(), &st) == -1) {
+ sc.Error("failed to stat local file '%s': %s", lpath.c_str(), strerror(errno));
return false;
}
if (st.st_size < SYNC_DATA_MAX) {
std::string data;
if (!android::base::ReadFileToString(lpath, &data, true)) {
- sc.Error("failed to read all of '%s': %s", lpath, strerror(errno));
+ sc.Error("failed to read all of '%s': %s", lpath.c_str(), strerror(errno));
return false;
}
- if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime,
- data.data(), data.size())) {
+ if (!sc.SendSmallFile(rpath, mode, lpath, rpath, mtime, data.data(), data.size())) {
return false;
}
} else {
- if (!sc.SendLargeFile(path_and_mode.c_str(), lpath, rpath, mtime)) {
+ if (!sc.SendLargeFile(rpath, mode, lpath, rpath, mtime)) {
return false;
}
}
- return sc.CopyDone(lpath, rpath);
+ return true;
}
static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath,
@@ -943,7 +934,7 @@
if (check_timestamps) {
for (const copyinfo& ci : file_list) {
- if (!sc.SendLstat(ci.rpath.c_str())) {
+ if (!sc.SendLstat(ci.rpath)) {
sc.Error("failed to send lstat");
return false;
}
@@ -965,7 +956,7 @@
if (list_only) {
sc.Println("would push: %s -> %s", ci.lpath.c_str(), ci.rpath.c_str());
} else {
- if (!sync_send(sc, ci.lpath.c_str(), ci.rpath.c_str(), ci.time, ci.mode, false)) {
+ if (!sync_send(sc, ci.lpath, ci.rpath, ci.time, ci.mode, false)) {
return false;
}
}
@@ -1069,6 +1060,7 @@
sc.ReportTransferRate(src_path, TransferDirection::push);
}
+ success &= sc.ReadAcknowledgments();
sc.ReportOverallTransferRate(TransferDirection::push);
return success;
}
@@ -1105,14 +1097,14 @@
}
};
- if (!sync_ls(sc, rpath.c_str(), callback)) {
+ if (!sync_ls(sc, rpath, callback)) {
return false;
}
// Check each symlink we found to see whether it's a file or directory.
for (copyinfo& link_ci : linklist) {
struct stat st;
- if (!sync_stat_fallback(sc, link_ci.rpath.c_str(), &st)) {
+ if (!sync_stat_fallback(sc, link_ci.rpath, &st)) {
sc.Warning("stat failed for path %s: %s", link_ci.rpath.c_str(), strerror(errno));
continue;
}
diff --git a/adb/daemon/jdwp_service.cpp b/adb/daemon/jdwp_service.cpp
index c99aead..adae9f7 100644
--- a/adb/daemon/jdwp_service.cpp
+++ b/adb/daemon/jdwp_service.cpp
@@ -16,6 +16,7 @@
#if !ADB_HOST
+#if !defined(__ANDROID_RECOVERY__)
#define TRACE_TAG JDWP
#include "sysdeps.h"
@@ -459,7 +460,7 @@
return -1;
}
-asocket* create_process_tracker_service_socket(TrackerKind kind) {
+static asocket* create_process_tracker_service_socket(TrackerKind kind) {
auto t = std::make_unique<JdwpTracker>(kind, true);
if (!t) {
LOG(FATAL) << "failed to allocate JdwpTracker";
@@ -509,4 +510,28 @@
return 0;
}
+#else // !defined(__ANDROID_RECOVERY)
+#include "adb.h"
+
+asocket* create_jdwp_service_socket(void) {
+ return nullptr;
+}
+
+unique_fd create_jdwp_connection_fd(int pid) {
+ return {};
+}
+
+asocket* create_app_tracker_service_socket() {
+ return nullptr;
+}
+
+asocket* create_jdwp_tracker_service_socket() {
+ return nullptr;
+}
+
+int init_jdwp() {
+ return 0;
+}
+
+#endif /* defined(__ANDROID_RECOVERY__) */
#endif /* !ADB_HOST */
diff --git a/adb/services.cpp b/adb/services.cpp
index 853d658..d87948c 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -95,56 +95,6 @@
}
#if ADB_HOST
-struct state_info {
- TransportType transport_type;
- std::string serial;
- TransportId transport_id;
- ConnectionState state;
-};
-
-static void wait_for_state(unique_fd fd, state_info* sinfo) {
- D("wait_for_state %d", sinfo->state);
-
- while (true) {
- bool is_ambiguous = false;
- std::string error = "unknown error";
- const char* serial = sinfo->serial.length() ? sinfo->serial.c_str() : nullptr;
- atransport* t = acquire_one_transport(sinfo->transport_type, serial, sinfo->transport_id,
- &is_ambiguous, &error);
- if (sinfo->state == kCsOffline) {
- // wait-for-disconnect uses kCsOffline, we don't actually want to wait for 'offline'.
- if (t == nullptr) {
- SendOkay(fd);
- break;
- }
- } else if (t != nullptr &&
- (sinfo->state == kCsAny || sinfo->state == t->GetConnectionState())) {
- SendOkay(fd);
- break;
- }
-
- if (!is_ambiguous) {
- adb_pollfd pfd = {.fd = fd.get(), .events = POLLIN};
- int rc = adb_poll(&pfd, 1, 100);
- if (rc < 0) {
- SendFail(fd, error);
- break;
- } else if (rc > 0 && (pfd.revents & POLLHUP) != 0) {
- // The other end of the socket is closed, probably because the other side was
- // terminated, bail out.
- break;
- }
-
- // Try again...
- } else {
- SendFail(fd, error);
- break;
- }
- }
-
- D("wait_for_state is done");
-}
-
void connect_emulator(const std::string& port_spec, std::string* response) {
std::vector<std::string> pieces = android::base::Split(port_spec, ",");
if (pieces.size() != 2) {
@@ -201,6 +151,80 @@
adb_wifi_pair_device(host, password, response);
SendProtocolString(fd.get(), response);
}
+
+static void wait_service(unique_fd fd, std::string serial, TransportId transport_id,
+ std::string spec) {
+ std::vector<std::string> components = android::base::Split(spec, "-");
+ if (components.size() < 2) {
+ SendFail(fd, "short wait-for-: " + spec);
+ return;
+ }
+
+ TransportType transport_type;
+ if (components[0] == "local") {
+ transport_type = kTransportLocal;
+ } else if (components[0] == "usb") {
+ transport_type = kTransportUsb;
+ } else if (components[0] == "any") {
+ transport_type = kTransportAny;
+ } else {
+ SendFail(fd, "bad wait-for- transport: " + spec);
+ return;
+ }
+
+ std::vector<ConnectionState> states;
+ for (size_t i = 1; i < components.size(); ++i) {
+ if (components[i] == "device") {
+ states.push_back(kCsDevice);
+ } else if (components[i] == "recovery") {
+ states.push_back(kCsRecovery);
+ } else if (components[i] == "rescue") {
+ states.push_back(kCsRescue);
+ } else if (components[i] == "sideload") {
+ states.push_back(kCsSideload);
+ } else if (components[i] == "bootloader") {
+ states.push_back(kCsBootloader);
+ } else if (components[i] == "any") {
+ states.push_back(kCsAny);
+ } else if (components[i] == "disconnect") {
+ states.push_back(kCsOffline);
+ } else {
+ SendFail(fd, "bad wait-for- state: " + spec);
+ return;
+ }
+ }
+
+ while (true) {
+ bool is_ambiguous = false;
+ std::string error = "unknown error";
+ atransport* t =
+ acquire_one_transport(transport_type, !serial.empty() ? serial.c_str() : nullptr,
+ transport_id, &is_ambiguous, &error);
+
+ for (const auto& state : states) {
+ // wait-for-disconnect uses kCsOffline, we don't actually want to wait for 'offline'.
+ if ((t == nullptr && state == kCsOffline) || (t != nullptr && state == kCsAny) ||
+ (t != nullptr && state == t->GetConnectionState())) {
+ SendOkay(fd);
+ return;
+ }
+ }
+
+ if (is_ambiguous) {
+ SendFail(fd, error);
+ return;
+ }
+
+ // Sleep before retrying.
+ adb_pollfd pfd = {.fd = fd.get(), .events = POLLIN};
+ if (adb_poll(&pfd, 1, 100) != 0) {
+ // The other end of the socket is closed, probably because the
+ // client terminated. Bail out.
+ SendFail(fd, error);
+ return;
+ }
+ }
+}
#endif
#if ADB_HOST
@@ -211,45 +235,10 @@
} else if (name == "track-devices-l") {
return create_device_tracker(true);
} else if (android::base::ConsumePrefix(&name, "wait-for-")) {
- std::shared_ptr<state_info> sinfo = std::make_shared<state_info>();
- if (sinfo == nullptr) {
- fprintf(stderr, "couldn't allocate state_info: %s", strerror(errno));
- return nullptr;
- }
-
- sinfo->serial = serial;
- sinfo->transport_id = transport_id;
-
- if (android::base::ConsumePrefix(&name, "local")) {
- sinfo->transport_type = kTransportLocal;
- } else if (android::base::ConsumePrefix(&name, "usb")) {
- sinfo->transport_type = kTransportUsb;
- } else if (android::base::ConsumePrefix(&name, "any")) {
- sinfo->transport_type = kTransportAny;
- } else {
- return nullptr;
- }
-
- if (name == "-device") {
- sinfo->state = kCsDevice;
- } else if (name == "-recovery") {
- sinfo->state = kCsRecovery;
- } else if (name == "-rescue") {
- sinfo->state = kCsRescue;
- } else if (name == "-sideload") {
- sinfo->state = kCsSideload;
- } else if (name == "-bootloader") {
- sinfo->state = kCsBootloader;
- } else if (name == "-any") {
- sinfo->state = kCsAny;
- } else if (name == "-disconnect") {
- sinfo->state = kCsOffline;
- } else {
- return nullptr;
- }
-
- unique_fd fd = create_service_thread(
- "wait", [sinfo](unique_fd fd) { wait_for_state(std::move(fd), sinfo.get()); });
+ std::string spec(name);
+ unique_fd fd =
+ create_service_thread("wait", std::bind(wait_service, std::placeholders::_1,
+ std::string(serial), transport_id, spec));
return create_local_socket(std::move(fd));
} else if (android::base::ConsumePrefix(&name, "connect:")) {
std::string host(name);
diff --git a/base/Android.bp b/base/Android.bp
index 25c74f2..12de3b2 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -47,6 +47,10 @@
enabled: true,
},
},
+ apex_available: [
+ "//apex_available:anyapex",
+ "//apex_available:platform",
+ ],
}
cc_defaults {
@@ -203,6 +207,23 @@
test_suites: ["device-tests"],
}
+cc_test {
+ name: "libbase_tidy_test",
+ defaults: ["libbase_cflags_defaults"],
+ host_supported: true,
+
+ tidy: true,
+ tidy_checks_as_errors: ["bugprone-use-after-move"],
+
+ srcs: [
+ "tidy/unique_fd_test.cpp",
+ "tidy/unique_fd_test2.cpp",
+ ],
+
+ shared_libs: ["libbase"],
+ test_suites: ["device_tests"],
+}
+
cc_benchmark {
name: "libbase_benchmark",
defaults: ["libbase_cflags_defaults"],
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index c4a0aad..9ceb5db 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -102,7 +102,7 @@
return *this;
}
- void reset(int new_value = -1) { reset(new_value, nullptr); }
+ [[clang::reinitializes]] void reset(int new_value = -1) { reset(new_value, nullptr); }
int get() const { return fd_; }
diff --git a/base/liblog_symbols.cpp b/base/liblog_symbols.cpp
index d5dfcd2..8d59179 100644
--- a/base/liblog_symbols.cpp
+++ b/base/liblog_symbols.cpp
@@ -16,14 +16,20 @@
#include "liblog_symbols.h"
-#if defined(__ANDROID__) && !defined(NO_LIBLOG_DLSYM)
+#if defined(__ANDROID__)
+#if !defined(NO_LIBLOG_DLSYM) || defined(__ANDROID_APEX__)
+#define USE_DLSYM
+#endif
+#endif
+
+#ifdef USE_DLSYM
#include <dlfcn.h>
#endif
namespace android {
namespace base {
-#if defined(__ANDROID__) && !defined(NO_LIBLOG_DLSYM)
+#ifdef USE_DLSYM
const std::optional<LibLogFunctions>& GetLibLogFunctions() {
static std::optional<LibLogFunctions> liblog_functions = []() -> std::optional<LibLogFunctions> {
diff --git a/base/liblog_symbols.h b/base/liblog_symbols.h
index d3134e9..b4ab06a 100644
--- a/base/liblog_symbols.h
+++ b/base/liblog_symbols.h
@@ -36,8 +36,8 @@
void (*__android_log_set_aborter)(__android_aborter_function aborter);
void (*__android_log_call_aborter)(const char* abort_message);
void (*__android_log_default_aborter)(const char* abort_message);
- int (*__android_log_set_minimum_priority)(int priority);
- int (*__android_log_get_minimum_priority)();
+ int32_t (*__android_log_set_minimum_priority)(int32_t priority);
+ int32_t (*__android_log_get_minimum_priority)();
void (*__android_log_set_default_tag)(const char* tag);
};
diff --git a/base/logging.cpp b/base/logging.cpp
index 9360a56..9a6e0fb 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -118,7 +118,7 @@
}
#endif
-static LogId log_id_tToLogId(int buffer_id) {
+static LogId log_id_tToLogId(int32_t buffer_id) {
switch (buffer_id) {
case LOG_ID_MAIN:
return MAIN;
@@ -134,7 +134,7 @@
}
}
-static int LogIdTolog_id_t(LogId log_id) {
+static int32_t LogIdTolog_id_t(LogId log_id) {
switch (log_id) {
case MAIN:
return LOG_ID_MAIN;
@@ -171,7 +171,7 @@
}
}
-static android_LogPriority LogSeverityToPriority(LogSeverity severity) {
+static int32_t LogSeverityToPriority(LogSeverity severity) {
switch (severity) {
case VERBOSE:
return ANDROID_LOG_VERBOSE;
@@ -333,12 +333,12 @@
void LogdLogger::operator()(LogId id, LogSeverity severity, const char* tag,
const char* file, unsigned int line,
const char* message) {
- android_LogPriority priority = LogSeverityToPriority(severity);
+ int32_t priority = LogSeverityToPriority(severity);
if (id == DEFAULT) {
id = default_log_id_;
}
- int lg_id = LogIdTolog_id_t(id);
+ int32_t lg_id = LogIdTolog_id_t(id);
char log_message_with_file[4068]; // LOGGER_ENTRY_MAX_PAYLOAD, not available in the NDK.
if (priority == ANDROID_LOG_FATAL && file != nullptr) {
@@ -574,7 +574,7 @@
void LogMessage::LogLine(const char* file, unsigned int line, LogSeverity severity, const char* tag,
const char* message) {
static auto& liblog_functions = GetLibLogFunctions();
- auto priority = LogSeverityToPriority(severity);
+ int32_t priority = LogSeverityToPriority(severity);
if (liblog_functions) {
__android_logger_data logger_data = {
sizeof(__android_logger_data), LOG_ID_DEFAULT, priority, tag, file, line};
@@ -608,7 +608,7 @@
// we need to fall back to using gMinimumLogSeverity, since __android_log_is_loggable() will not
// take into consideration the value from SetMinimumLogSeverity().
if (liblog_functions) {
- int priority = LogSeverityToPriority(severity);
+ int32_t priority = LogSeverityToPriority(severity);
return __android_log_is_loggable(priority, tag, ANDROID_LOG_INFO);
} else {
return severity >= gMinimumLogSeverity;
@@ -618,7 +618,7 @@
LogSeverity SetMinimumLogSeverity(LogSeverity new_severity) {
static auto& liblog_functions = GetLibLogFunctions();
if (liblog_functions) {
- auto priority = LogSeverityToPriority(new_severity);
+ int32_t priority = LogSeverityToPriority(new_severity);
return PriorityToLogSeverity(liblog_functions->__android_log_set_minimum_priority(priority));
} else {
LogSeverity old_severity = gMinimumLogSeverity;
diff --git a/base/tidy/unique_fd_test.cpp b/base/tidy/unique_fd_test.cpp
new file mode 100644
index 0000000..b3a99fc
--- /dev/null
+++ b/base/tidy/unique_fd_test.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "android-base/unique_fd.h"
+
+#include <utility>
+
+#include <gtest/gtest.h>
+
+extern void consume_unique_fd(android::base::unique_fd fd);
+
+TEST(unique_fd, bugprone_use_after_move) {
+ // Compile time test for clang-tidy's bugprone-use-after-move check.
+ android::base::unique_fd ufd(open("/dev/null", O_RDONLY | O_CLOEXEC));
+ consume_unique_fd(std::move(ufd));
+ ufd.reset(open("/dev/null", O_RDONLY | O_CLOEXEC));
+ ufd.get();
+ consume_unique_fd(std::move(ufd));
+}
diff --git a/init/service_lock.cpp b/base/tidy/unique_fd_test2.cpp
similarity index 81%
rename from init/service_lock.cpp
rename to base/tidy/unique_fd_test2.cpp
index 404d439..b0c71e2 100644
--- a/init/service_lock.cpp
+++ b/base/tidy/unique_fd_test2.cpp
@@ -14,12 +14,6 @@
* limitations under the License.
*/
-#include "service_lock.h"
+#include "android-base/unique_fd.h"
-namespace android {
-namespace init {
-
-RecursiveMutex service_lock;
-
-} // namespace init
-} // namespace android
+void consume_unique_fd(android::base::unique_fd) {}
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index d9167e7..e7f785b 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -261,6 +261,10 @@
GTEST_LOG_(INFO) << "Flashing a logical partition..";
EXPECT_EQ(fb->FlashPartition(test_partition_name, buf), SUCCESS)
<< "flash logical -partition failed";
+
+ GTEST_LOG_(INFO) << "Testing 'fastboot delete-logical-partition' command";
+ EXPECT_EQ(fb->DeletePartition(test_partition_name), SUCCESS)
+ << "delete logical-partition failed";
}
// Conformance tests
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 0089989..c0c0e99 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -1588,76 +1588,58 @@
}
}
-static std::string ResolveBlockDevice(const std::string& block_device) {
+static bool UnwindDmDeviceStack(const std::string& block_device,
+ std::vector<std::string>* dm_stack) {
if (!StartsWith(block_device, "/dev/block/")) {
LWARNING << block_device << " is not a block device";
- return block_device;
+ return false;
}
- std::string name = block_device.substr(5);
- if (!StartsWith(name, "block/dm-")) {
- // Not a dm-device, but might be a symlink. Optimistically try to readlink.
- std::string result;
- if (Readlink(block_device, &result)) {
- return result;
- } else if (errno == EINVAL) {
- // After all, it wasn't a symlink.
- return block_device;
- } else {
- LERROR << "Failed to readlink " << block_device;
- return "";
- }
- }
- // It's a dm-device, let's find what's inside!
- std::string sys_dir = "/sys/" + name;
+ std::string current = block_device;
+ DeviceMapper& dm = DeviceMapper::Instance();
while (true) {
- std::string slaves_dir = sys_dir + "/slaves";
- std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(slaves_dir.c_str()), closedir);
- if (!dir) {
- LERROR << "Failed to open " << slaves_dir;
- return "";
+ dm_stack->push_back(current);
+ if (!dm.IsDmBlockDevice(current)) {
+ break;
}
- std::string sub_device_name = "";
- for (auto entry = readdir(dir.get()); entry; entry = readdir(dir.get())) {
- if (entry->d_type != DT_LNK) continue;
- if (!sub_device_name.empty()) {
- LERROR << "Too many slaves in " << slaves_dir;
- return "";
- }
- sub_device_name = entry->d_name;
+ auto parent = dm.GetParentBlockDeviceByPath(current);
+ if (!parent) {
+ return false;
}
- if (sub_device_name.empty()) {
- LERROR << "No slaves in " << slaves_dir;
- return "";
- }
- if (!StartsWith(sub_device_name, "dm-")) {
- // Not a dm-device! We can stop now.
- return "/dev/block/" + sub_device_name;
- }
- // Still a dm-device, keep digging.
- sys_dir = "/sys/block/" + sub_device_name;
+ current = *parent;
}
+ return true;
}
FstabEntry* fs_mgr_get_mounted_entry_for_userdata(Fstab* fstab, const FstabEntry& mounted_entry) {
- std::string resolved_block_device = ResolveBlockDevice(mounted_entry.blk_device);
- if (resolved_block_device.empty()) {
+ if (mounted_entry.mount_point != "/data") {
+ LERROR << mounted_entry.mount_point << " is not /data";
return nullptr;
}
- LINFO << "/data is mounted on " << resolved_block_device;
+ std::vector<std::string> dm_stack;
+ if (!UnwindDmDeviceStack(mounted_entry.blk_device, &dm_stack)) {
+ LERROR << "Failed to unwind dm-device stack for " << mounted_entry.blk_device;
+ return nullptr;
+ }
for (auto& entry : *fstab) {
if (entry.mount_point != "/data") {
continue;
}
std::string block_device;
- if (!Readlink(entry.blk_device, &block_device)) {
- LWARNING << "Failed to readlink " << entry.blk_device;
+ if (entry.fs_mgr_flags.logical) {
+ if (!fs_mgr_update_logical_partition(&entry)) {
+ LERROR << "Failed to update logic partition " << entry.blk_device;
+ continue;
+ }
+ block_device = entry.blk_device;
+ } else if (!Readlink(entry.blk_device, &block_device)) {
+ PWARNING << "Failed to read link " << entry.blk_device;
block_device = entry.blk_device;
}
- if (block_device == resolved_block_device) {
+ if (std::find(dm_stack.begin(), dm_stack.end(), block_device) != dm_stack.end()) {
return &entry;
}
}
- LERROR << "Didn't find entry that was used to mount /data";
+ LERROR << "Didn't find entry that was used to mount /data onto " << mounted_entry.blk_device;
return nullptr;
}
diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp
index 1c3427f..c2c2cc4 100644
--- a/fs_mgr/libdm/Android.bp
+++ b/fs_mgr/libdm/Android.bp
@@ -84,17 +84,21 @@
}
cc_fuzz {
- name: "dm_linear_table_fuzzer",
- defaults: ["fs_mgr_defaults"],
- srcs: [
- "dm_linear_fuzzer.cpp",
- "test_util.cpp",
- ],
- static_libs: [
+ name: "dm_linear_table_fuzzer",
+ defaults: ["fs_mgr_defaults"],
+ srcs: [
+ "dm_linear_fuzzer.cpp",
+ "test_util.cpp",
+ ],
+ static_libs: [
"libdm",
"libbase",
"libext2_uuid",
"libfs_mgr",
"liblog",
- ],
+ ],
+}
+
+vts_config {
+ name: "VtsKernelLibdmTest",
}
diff --git a/fs_mgr/libdm/Android.mk b/fs_mgr/libdm/Android.mk
deleted file mode 100644
index 6aedc25..0000000
--- a/fs_mgr/libdm/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := VtsKernelLibdmTest
--include test/vts/tools/build/Android.host_config.mk
diff --git a/fs_mgr/libfiemap/Android.bp b/fs_mgr/libfiemap/Android.bp
index 2fd463c..ac589c7 100644
--- a/fs_mgr/libfiemap/Android.bp
+++ b/fs_mgr/libfiemap/Android.bp
@@ -45,6 +45,7 @@
whole_static_libs: [
"gsi_aidl_interface-cpp",
"libgsi",
+ "libgsid",
],
shared_libs: [
"libbinder",
diff --git a/fs_mgr/libfiemap/binder.cpp b/fs_mgr/libfiemap/binder.cpp
index 96c36ed..c8516ab 100644
--- a/fs_mgr/libfiemap/binder.cpp
+++ b/fs_mgr/libfiemap/binder.cpp
@@ -19,10 +19,9 @@
#include <android-base/properties.h>
#include <android/gsi/BnProgressCallback.h>
#include <android/gsi/IGsiService.h>
-#include <android/gsi/IGsid.h>
-#include <binder/IServiceManager.h>
#include <libfiemap/image_manager.h>
#include <libgsi/libgsi.h>
+#include <libgsi/libgsid.h>
namespace android {
namespace fiemap {
@@ -225,54 +224,12 @@
return false;
}
-static android::sp<IGsid> AcquireIGsid(const std::chrono::milliseconds& timeout_ms) {
- if (android::base::GetProperty("init.svc.gsid", "") != "running") {
- if (!android::base::SetProperty("ctl.start", "gsid") ||
- !android::base::WaitForProperty("init.svc.gsid", "running", timeout_ms)) {
- LOG(ERROR) << "Could not start the gsid service";
- return nullptr;
- }
- // Sleep for 250ms to give the service time to register.
- usleep(250 * 1000);
- }
- auto sm = android::defaultServiceManager();
- auto name = android::String16(kGsiServiceName);
- auto service = sm->checkService(name);
- return android::interface_cast<IGsid>(service);
-}
-
-static android::sp<IGsid> GetGsiService(const std::chrono::milliseconds& timeout_ms) {
- auto start_time = std::chrono::steady_clock::now();
-
- std::chrono::milliseconds elapsed = std::chrono::milliseconds::zero();
- do {
- if (auto gsid = AcquireIGsid(timeout_ms - elapsed); gsid != nullptr) {
- return gsid;
- }
- auto now = std::chrono::steady_clock::now();
- elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
- } while (elapsed <= timeout_ms);
-
- LOG(ERROR) << "Timed out trying to acquire IGsid interface";
- return nullptr;
-}
-
-std::unique_ptr<IImageManager> IImageManager::Open(const std::string& dir,
- const std::chrono::milliseconds& timeout_ms) {
- auto gsid = GetGsiService(timeout_ms);
- if (!gsid) {
- return nullptr;
- }
-
- android::sp<IGsiService> service;
- auto status = gsid->getClient(&service);
- if (!status.isOk() || !service) {
- LOG(ERROR) << "Could not acquire IGsiService";
- return nullptr;
- }
-
+std::unique_ptr<IImageManager> IImageManager::Open(
+ const std::string& dir, const std::chrono::milliseconds& /*timeout_ms*/) {
+ android::sp<IGsiService> service = android::gsi::GetGsiService();
android::sp<IImageService> manager;
- status = service->openImageService(dir, &manager);
+
+ auto status = service->openImageService(dir, &manager);
if (!status.isOk() || !manager) {
LOG(ERROR) << "Could not acquire IImageManager: " << status.exceptionMessage().string();
return nullptr;
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index ea0fca8..ad19f38 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -108,3 +108,6 @@
defaults: ["liblp_test_defaults"],
}
+vts_config {
+ name: "VtsKernelLiblpTest",
+}
diff --git a/fs_mgr/liblp/Android.mk b/fs_mgr/liblp/Android.mk
deleted file mode 100644
index 7f7f891..0000000
--- a/fs_mgr/liblp/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := VtsKernelLiblpTest
--include test/vts/tools/build/Android.host_config.mk
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 0a0a21d..d670ca0 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -96,16 +96,6 @@
static_libs: [
"libfs_mgr_binder"
],
-
- shared_libs: [
- // TODO(b/148818798): remove when parent bug is fixed
- "libutilscallstack",
- ],
- cflags: [
- "-g",
- "-O0",
- "-DLIBSNAPSHOT_USE_CALLSTACK",
- ],
}
cc_library_static {
@@ -179,9 +169,6 @@
"libsparse",
"libutils",
"libz",
-
- // TODO(b/148818798): remove when parent bug is fixed
- "libutilscallstack",
],
static_libs: [
"libfs_mgr",
@@ -231,8 +218,5 @@
"libprotobuf-cpp-lite",
"libstatslog",
"libutils",
-
- // TODO(b/148818798): remove when parent bug is fixed.
- "libutilscallstack",
],
}
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 81f616c..957c26c 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -74,7 +74,8 @@
static constexpr const std::string_view kCowGroupName = "cow";
-bool SourceCopyOperationIsClone(const chromeos_update_engine::InstallOperation& operation);
+bool OptimizeSourceCopyOperation(const chromeos_update_engine::InstallOperation& operation,
+ chromeos_update_engine::InstallOperation* optimized);
enum class CreateResult : unsigned int {
ERROR,
@@ -178,16 +179,6 @@
UpdateState ProcessUpdateState(const std::function<bool()>& callback = {},
const std::function<bool()>& before_cancel = {});
- // Initiate the merge if necessary, then wait for the merge to finish.
- // See InitiateMerge() and ProcessUpdateState() for details.
- // Returns:
- // - None if no merge to initiate
- // - Unverified if called on the source slot
- // - MergeCompleted if merge is completed
- // - other states indicating an error has occurred
- UpdateState InitiateMergeAndWait(SnapshotMergeReport* report = nullptr,
- const std::function<bool()>& before_cancel = {});
-
// Find the status of the current update, if any.
//
// |progress| depends on the returned status:
diff --git a/fs_mgr/libsnapshot/partition_cow_creator.cpp b/fs_mgr/libsnapshot/partition_cow_creator.cpp
index 61f5c0c..efdb59f 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator.cpp
+++ b/fs_mgr/libsnapshot/partition_cow_creator.cpp
@@ -62,17 +62,68 @@
return false;
}
-bool SourceCopyOperationIsClone(const InstallOperation& operation) {
- using ChromeOSExtent = chromeos_update_engine::Extent;
- if (operation.src_extents().size() != operation.dst_extents().size()) {
+bool OptimizeSourceCopyOperation(const InstallOperation& operation, InstallOperation* optimized) {
+ if (operation.type() != InstallOperation::SOURCE_COPY) {
return false;
}
- return std::equal(operation.src_extents().begin(), operation.src_extents().end(),
- operation.dst_extents().begin(),
- [](const ChromeOSExtent& src, const ChromeOSExtent& dst) {
- return src.start_block() == dst.start_block() &&
- src.num_blocks() == dst.num_blocks();
- });
+
+ optimized->Clear();
+ optimized->set_type(InstallOperation::SOURCE_COPY);
+
+ const auto& src_extents = operation.src_extents();
+ const auto& dst_extents = operation.dst_extents();
+
+ // If input is empty, skip by returning an empty result.
+ if (src_extents.empty() && dst_extents.empty()) {
+ return true;
+ }
+
+ auto s_it = src_extents.begin();
+ auto d_it = dst_extents.begin();
+ uint64_t s_offset = 0; // offset within *s_it
+ uint64_t d_offset = 0; // offset within *d_it
+ bool is_optimized = false;
+
+ while (s_it != src_extents.end() || d_it != dst_extents.end()) {
+ if (s_it == src_extents.end() || d_it == dst_extents.end()) {
+ LOG(ERROR) << "number of blocks do not equal in src_extents and dst_extents";
+ return false;
+ }
+ if (s_it->num_blocks() <= s_offset || d_it->num_blocks() <= d_offset) {
+ LOG(ERROR) << "Offset goes out of bounds.";
+ return false;
+ }
+
+ // Check the next |step| blocks, where |step| is the min of remaining blocks in the current
+ // source extent and current destination extent.
+ auto s_step = s_it->num_blocks() - s_offset;
+ auto d_step = d_it->num_blocks() - d_offset;
+ auto step = std::min(s_step, d_step);
+
+ bool moved = s_it->start_block() + s_offset != d_it->start_block() + d_offset;
+ if (moved) {
+ // If the next |step| blocks are not copied to the same location, add them to result.
+ AppendExtent(optimized->mutable_src_extents(), s_it->start_block() + s_offset, step);
+ AppendExtent(optimized->mutable_dst_extents(), d_it->start_block() + d_offset, step);
+ } else {
+ // The next |step| blocks are optimized out.
+ is_optimized = true;
+ }
+
+ // Advance offsets by |step|, and go to the next non-empty extent if the current extent is
+ // depleted.
+ s_offset += step;
+ d_offset += step;
+ while (s_it != src_extents.end() && s_offset >= s_it->num_blocks()) {
+ ++s_it;
+ s_offset = 0;
+ }
+ while (d_it != dst_extents.end() && d_offset >= d_it->num_blocks()) {
+ ++d_it;
+ d_offset = 0;
+ }
+ }
+ return is_optimized;
}
void WriteExtent(DmSnapCowSizeCalculator* sc, const chromeos_update_engine::Extent& de,
@@ -101,12 +152,15 @@
if (operations == nullptr) return sc.cow_size_bytes();
for (const auto& iop : *operations) {
- // Do not allocate space for operations that are going to be skipped
+ const InstallOperation* written_op = &iop;
+ InstallOperation buf;
+ // Do not allocate space for extents that are going to be skipped
// during OTA application.
- if (iop.type() == InstallOperation::SOURCE_COPY && SourceCopyOperationIsClone(iop))
- continue;
+ if (iop.type() == InstallOperation::SOURCE_COPY && OptimizeSourceCopyOperation(iop, &buf)) {
+ written_op = &buf;
+ }
- for (const auto& de : iop.dst_extents()) {
+ for (const auto& de : written_op->dst_extents()) {
WriteExtent(&sc, de, sectors_per_block);
}
}
diff --git a/fs_mgr/libsnapshot/partition_cow_creator_test.cpp b/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
index 9da3f05..526f874 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
+++ b/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
@@ -12,6 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include <optional>
+#include <tuple>
+
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <libdm/dm.h>
@@ -26,6 +29,13 @@
using namespace android::fs_mgr;
+using chromeos_update_engine::InstallOperation;
+using UeExtent = chromeos_update_engine::Extent;
+using google::protobuf::RepeatedPtrField;
+using ::testing::Matches;
+using ::testing::Pointwise;
+using ::testing::Truly;
+
namespace android {
namespace snapshot {
@@ -213,5 +223,76 @@
}
}
+void BlocksToExtents(const std::vector<uint64_t>& blocks,
+ google::protobuf::RepeatedPtrField<UeExtent>* extents) {
+ for (uint64_t block : blocks) {
+ AppendExtent(extents, block, 1);
+ }
+}
+
+template <typename T>
+std::vector<uint64_t> ExtentsToBlocks(const T& extents) {
+ std::vector<uint64_t> blocks;
+ for (const auto& extent : extents) {
+ for (uint64_t offset = 0; offset < extent.num_blocks(); ++offset) {
+ blocks.push_back(extent.start_block() + offset);
+ }
+ }
+ return blocks;
+}
+
+InstallOperation CreateCopyOp(const std::vector<uint64_t>& src_blocks,
+ const std::vector<uint64_t>& dst_blocks) {
+ InstallOperation op;
+ op.set_type(InstallOperation::SOURCE_COPY);
+ BlocksToExtents(src_blocks, op.mutable_src_extents());
+ BlocksToExtents(dst_blocks, op.mutable_dst_extents());
+ return op;
+}
+
+// ExtentEqual(tuple<UeExtent, UeExtent>)
+MATCHER(ExtentEqual, "") {
+ auto&& [a, b] = arg;
+ return a.start_block() == b.start_block() && a.num_blocks() == b.num_blocks();
+}
+
+struct OptimizeOperationTestParam {
+ InstallOperation input;
+ std::optional<InstallOperation> expected_output;
+};
+
+class OptimizeOperationTest : public ::testing::TestWithParam<OptimizeOperationTestParam> {};
+TEST_P(OptimizeOperationTest, Test) {
+ InstallOperation actual_output;
+ EXPECT_EQ(GetParam().expected_output.has_value(),
+ OptimizeSourceCopyOperation(GetParam().input, &actual_output))
+ << "OptimizeSourceCopyOperation should "
+ << (GetParam().expected_output.has_value() ? "succeed" : "fail");
+ if (!GetParam().expected_output.has_value()) return;
+ EXPECT_THAT(actual_output.src_extents(),
+ Pointwise(ExtentEqual(), GetParam().expected_output->src_extents()));
+ EXPECT_THAT(actual_output.dst_extents(),
+ Pointwise(ExtentEqual(), GetParam().expected_output->dst_extents()));
+}
+
+std::vector<OptimizeOperationTestParam> GetOptimizeOperationTestParams() {
+ return {
+ {CreateCopyOp({}, {}), CreateCopyOp({}, {})},
+ {CreateCopyOp({1, 2, 4}, {1, 2, 4}), CreateCopyOp({}, {})},
+ {CreateCopyOp({1, 2, 3}, {4, 5, 6}), std::nullopt},
+ {CreateCopyOp({3, 2}, {1, 2}), CreateCopyOp({3}, {1})},
+ {CreateCopyOp({5, 6, 3, 4, 1, 2}, {1, 2, 3, 4, 5, 6}),
+ CreateCopyOp({5, 6, 1, 2}, {1, 2, 5, 6})},
+ {CreateCopyOp({1, 2, 3, 5, 5, 6}, {5, 6, 3, 4, 1, 2}),
+ CreateCopyOp({1, 2, 5, 5, 6}, {5, 6, 4, 1, 2})},
+ {CreateCopyOp({1, 2, 5, 6, 9, 10}, {1, 4, 5, 6, 7, 8}),
+ CreateCopyOp({2, 9, 10}, {4, 7, 8})},
+ {CreateCopyOp({2, 3, 3, 4, 4}, {1, 2, 3, 4, 5}), CreateCopyOp({2, 3, 4}, {1, 2, 5})},
+ };
+}
+
+INSTANTIATE_TEST_CASE_P(Snapshot, OptimizeOperationTest,
+ ::testing::ValuesIn(GetOptimizeOperationTestParams()));
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 0573c59..ed052b1 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -21,7 +21,6 @@
#include <sys/unistd.h>
#include <optional>
-#include <sstream>
#include <thread>
#include <unordered_set>
@@ -38,10 +37,6 @@
#include <libfiemap/image_manager.h>
#include <liblp/liblp.h>
-#ifdef LIBSNAPSHOT_USE_CALLSTACK
-#include <utils/CallStack.h>
-#endif
-
#include <android/snapshot/snapshot.pb.h>
#include <libsnapshot/snapshot_stats.h>
#include "device_info.h"
@@ -228,25 +223,6 @@
LOG(INFO) << "Removing all update state.";
-#ifdef LIBSNAPSHOT_USE_CALLSTACK
- LOG(WARNING) << "Logging stack; see b/148818798.";
- // Do not use CallStack's log functions because snapshotctl relies on
- // android-base/logging to save log to files.
- // TODO(b/148818798): remove this before we ship.
- CallStack callstack;
- callstack.update();
- auto callstack_str = callstack.toString();
- LOG(WARNING) << callstack_str.c_str();
- std::stringstream path;
- path << "/data/misc/snapshotctl_log/libsnapshot." << Now() << ".log";
- std::string path_str = path.str();
- android::base::WriteStringToFile(callstack_str.c_str(), path_str);
- if (chmod(path_str.c_str(), 0644) == -1) {
- PLOG(WARNING) << "Unable to chmod 0644 "
- << ", file maybe dropped from bugreport:" << path_str;
- }
-#endif
-
if (!RemoveAllSnapshots(lock)) {
LOG(ERROR) << "Could not remove all snapshots";
return false;
@@ -2498,68 +2474,6 @@
return AutoUnmountDevice::New(device_->GetMetadataDir());
}
-UpdateState SnapshotManager::InitiateMergeAndWait(SnapshotMergeReport* stats_report,
- const std::function<bool()>& before_cancel) {
- {
- auto lock = LockExclusive();
- // Sync update state from file with bootloader.
- if (!WriteUpdateState(lock.get(), ReadUpdateState(lock.get()))) {
- LOG(WARNING) << "Unable to sync write update state, fastboot may "
- << "reject / accept wipes incorrectly!";
- }
- }
-
- auto merge_stats = SnapshotMergeStats::GetInstance(*this);
-
- unsigned int last_progress = 0;
- auto callback = [&]() -> bool {
- double progress;
- GetUpdateState(&progress);
- if (last_progress < static_cast<unsigned int>(progress)) {
- last_progress = progress;
- LOG(INFO) << "Waiting for merge to complete: " << last_progress << "%.";
- }
- return true; // continue
- };
-
- LOG(INFO) << "Waiting for any previous merge request to complete. "
- << "This can take up to several minutes.";
- merge_stats->Start();
- auto state = ProcessUpdateState(callback, before_cancel);
- merge_stats->set_state(state);
- if (state == UpdateState::None) {
- LOG(INFO) << "Can't find any snapshot to merge.";
- return state;
- }
- if (state == UpdateState::Unverified) {
- if (GetCurrentSlot() != Slot::Target) {
- LOG(INFO) << "Cannot merge until device reboots.";
- return state;
- }
-
- if (!InitiateMerge()) {
- LOG(ERROR) << "Failed to initiate merge.";
- return state;
- }
- // All other states can be handled by ProcessUpdateState.
- LOG(INFO) << "Waiting for merge to complete. This can take up to several minutes.";
- last_progress = 0;
- state = ProcessUpdateState(callback, before_cancel);
- merge_stats->set_state(state);
- }
-
- LOG(INFO) << "Merge finished with state \"" << state << "\".";
- if (stats_report) {
- auto result = merge_stats->Finish();
- if (result) {
- *stats_report = result->report();
- } else {
- LOG(WARNING) << "SnapshotMergeStatus::Finish failed.";
- }
- }
- return state;
-}
-
bool SnapshotManager::HandleImminentDataWipe(const std::function<void()>& callback) {
if (!device_->IsRecovery()) {
LOG(ERROR) << "Data wipes are only allowed in recovery.";
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 7d16ec2..855451d 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -1027,7 +1027,8 @@
}
// Initiate the merge and wait for it to be completed.
- ASSERT_EQ(UpdateState::MergeCompleted, init->InitiateMergeAndWait());
+ ASSERT_TRUE(init->InitiateMerge());
+ ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
// Check that the target partitions have the same content after the merge.
for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
@@ -1201,7 +1202,8 @@
// Initiate the merge and wait for it to be completed.
auto new_sm = SnapshotManager::New(new TestDeviceInfo(fake_super, "_b"));
- ASSERT_EQ(UpdateState::MergeCompleted, new_sm->InitiateMergeAndWait());
+ ASSERT_TRUE(new_sm->InitiateMerge());
+ ASSERT_EQ(UpdateState::MergeCompleted, new_sm->ProcessUpdateState());
// Execute the second update.
ASSERT_TRUE(new_sm->BeginUpdate());
@@ -1341,7 +1343,8 @@
ASSERT_GE(fd, 0);
// COW cannot be removed due to open fd, so expect a soft failure.
- ASSERT_EQ(UpdateState::MergeNeedsReboot, init->InitiateMergeAndWait());
+ ASSERT_TRUE(init->InitiateMerge());
+ ASSERT_EQ(UpdateState::MergeNeedsReboot, init->ProcessUpdateState());
// Simulate shutting down the device.
fd.reset();
@@ -1354,7 +1357,7 @@
ASSERT_FALSE(sm->IsSnapshotDevice("sys_b", nullptr));
// Merge should be able to complete now.
- ASSERT_EQ(UpdateState::MergeCompleted, init->InitiateMergeAndWait());
+ ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
}
class MetadataMountedTest : public SnapshotUpdateTest {
@@ -1691,7 +1694,8 @@
// There should be no snapshot to merge.
auto new_sm = SnapshotManager::New(new TestDeviceInfo(fake_super, flashed_slot_suffix));
- ASSERT_EQ(UpdateState::Cancelled, new_sm->InitiateMergeAndWait());
+ // update_enigne calls ProcessUpdateState first -- should see Cancelled.
+ ASSERT_EQ(UpdateState::Cancelled, new_sm->ProcessUpdateState());
// Next OTA calls CancelUpdate no matter what.
ASSERT_TRUE(new_sm->CancelUpdate());
diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp
index aa5e9c1..a44de84 100644
--- a/fs_mgr/libsnapshot/snapshotctl.cpp
+++ b/fs_mgr/libsnapshot/snapshotctl.cpp
@@ -24,12 +24,8 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
-#include <android/snapshot/snapshot.pb.h>
-#include <libsnapshot/snapshot.h>
-#include <libsnapshot/snapshot_stats.h>
-#include <statslog.h>
-#include "utility.h"
+#include <libsnapshot/snapshot.h>
using namespace std::string_literals;
@@ -39,146 +35,22 @@
"Actions:\n"
" dump\n"
" Print snapshot states.\n"
- " merge [--logcat] [--log-to-file] [--report] [--dry-run]\n"
- " Initialize merge and wait for it to be completed.\n"
- " If --logcat is specified, log to logcat.\n"
- " If --log-to-file is specified, log to /data/misc/snapshotctl_log/.\n"
- " If both specified, log to both. If none specified, log to stdout.\n"
- " If --report is specified, send merge statistics to statsd.\n"
- " If --dry-run flag, no real merge operation is is triggered, and\n"
- " sample statistics are sent to statsd for testing purpose.\n";
+ " merge\n"
+ " Deprecated.\n";
return EX_USAGE;
}
namespace android {
namespace snapshot {
-static SnapshotMergeReport GetDummySnapshotMergeReport() {
- SnapshotMergeReport fake_report;
-
- fake_report.set_state(UpdateState::MergeCompleted);
- fake_report.set_resume_count(56);
-
- return fake_report;
-}
-
bool DumpCmdHandler(int /*argc*/, char** argv) {
android::base::InitLogging(argv, &android::base::StderrLogger);
return SnapshotManager::New()->Dump(std::cout);
}
-class FileLogger {
- public:
- FileLogger() {
- static constexpr const char* kLogFilePath = "/data/misc/snapshotctl_log/";
- std::stringstream ss;
- ss << kLogFilePath << "snapshotctl." << Now() << ".log";
- fd_.reset(TEMP_FAILURE_RETRY(
- open(ss.str().c_str(),
- O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_SYNC, 0644)));
- if (fd_ == -1) {
- PLOG(ERROR) << "Cannot open persistent log " << ss.str();
- return;
- }
- // Explicitly chmod again because mode in open() may be masked by umask.
- if (fchmod(fd_.get(), 0644) == -1) {
- PLOG(ERROR) << "Cannot chmod 0644 persistent log " << ss.str();
- return;
- }
- }
- // Copy-contuctor needed to be converted to std::function.
- FileLogger(const FileLogger& other) { fd_.reset(dup(other.fd_)); }
- void operator()(android::base::LogId, android::base::LogSeverity, const char* /*tag*/,
- const char* /*file*/, unsigned int /*line*/, const char* message) {
- if (fd_ == -1) return;
- std::stringstream ss;
- ss << Now() << ":" << message << "\n";
- (void)android::base::WriteStringToFd(ss.str(), fd_);
- }
-
- private:
- android::base::unique_fd fd_;
-};
-
-class MergeCmdLogger {
- public:
- MergeCmdLogger(int argc, char** argv) {
- for (int i = 0; i < argc; ++i) {
- if (argv[i] == "--logcat"s) {
- loggers_.push_back(android::base::LogdLogger());
- }
- if (argv[i] == "--log-to-file"s) {
- loggers_.push_back(std::move(FileLogger()));
- }
- }
- if (loggers_.empty()) {
- loggers_.push_back(&android::base::StdioLogger);
- }
- }
- void operator()(android::base::LogId id, android::base::LogSeverity severity, const char* tag,
- const char* file, unsigned int line, const char* message) {
- for (auto&& logger : loggers_) {
- logger(id, severity, tag, file, line, message);
- }
- }
-
- private:
- std::vector<android::base::LogFunction> loggers_;
-};
-
-bool MergeCmdHandler(int argc, char** argv) {
- std::chrono::milliseconds passed_ms;
-
- bool report_to_statsd = false;
- bool dry_run = false;
- for (int i = 2; i < argc; ++i) {
- if (argv[i] == "--report"s) {
- report_to_statsd = true;
- } else if (argv[i] == "--dry-run"s) {
- dry_run = true;
- }
- }
-
- // 'snapshotctl merge' is stripped away from arguments to
- // Logger.
- android::base::InitLogging(argv);
- android::base::SetLogger(MergeCmdLogger(argc - 2, argv + 2));
-
- UpdateState state;
- SnapshotMergeReport merge_report;
- if (dry_run) {
- merge_report = GetDummySnapshotMergeReport();
- state = merge_report.state();
- passed_ms = std::chrono::milliseconds(1234);
- } else {
- auto begin = std::chrono::steady_clock::now();
-
- state = SnapshotManager::New()->InitiateMergeAndWait(&merge_report);
-
- // We could wind up in the Unverified state if the device rolled back or
- // hasn't fully rebooted. Ignore this.
- if (state == UpdateState::None || state == UpdateState::Unverified) {
- return true;
- }
-
- auto end = std::chrono::steady_clock::now();
- passed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin);
- }
-
- if (report_to_statsd) {
- android::util::stats_write(android::util::SNAPSHOT_MERGE_REPORTED,
- static_cast<int32_t>(merge_report.state()),
- static_cast<int64_t>(passed_ms.count()),
- static_cast<int32_t>(merge_report.resume_count()));
- }
-
- if (state == UpdateState::MergeCompleted) {
- LOG(INFO) << "Snapshot merged in " << passed_ms.count() << " ms.";
- return true;
- }
-
- LOG(ERROR) << "Snapshot failed to merge with state \"" << state << "\".";
-
+bool MergeCmdHandler(int /*argc*/, char** argv) {
+ android::base::InitLogging(argv, &android::base::StderrLogger);
+ LOG(WARNING) << "Deprecated. Call update_engine_client --merge instead.";
return false;
}
diff --git a/fs_mgr/libsnapshot/utility.cpp b/fs_mgr/libsnapshot/utility.cpp
index 3318b33..d32b61e 100644
--- a/fs_mgr/libsnapshot/utility.cpp
+++ b/fs_mgr/libsnapshot/utility.cpp
@@ -34,6 +34,7 @@
using android::fs_mgr::MetadataBuilder;
using android::fs_mgr::Partition;
using android::fs_mgr::ReadDefaultFstab;
+using google::protobuf::RepeatedPtrField;
namespace android {
namespace snapshot {
@@ -166,5 +167,20 @@
return os << std::put_time(&now, "%Y%m%d-%H%M%S");
}
+void AppendExtent(RepeatedPtrField<chromeos_update_engine::Extent>* extents, uint64_t start_block,
+ uint64_t num_blocks) {
+ if (extents->size() > 0) {
+ auto last_extent = extents->rbegin();
+ auto next_block = last_extent->start_block() + last_extent->num_blocks();
+ if (start_block == next_block) {
+ last_extent->set_num_blocks(last_extent->num_blocks() + num_blocks);
+ return;
+ }
+ }
+ auto* new_extent = extents->Add();
+ new_extent->set_start_block(start_block);
+ new_extent->set_num_blocks(num_blocks);
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/utility.h b/fs_mgr/libsnapshot/utility.h
index 90ad0fe..e69bdad 100644
--- a/fs_mgr/libsnapshot/utility.h
+++ b/fs_mgr/libsnapshot/utility.h
@@ -125,5 +125,9 @@
struct Now {};
std::ostream& operator<<(std::ostream& os, const Now&);
+// Append to |extents|. Merged into the last element if possible.
+void AppendExtent(google::protobuf::RepeatedPtrField<chromeos_update_engine::Extent>* extents,
+ uint64_t start_block, uint64_t num_blocks);
+
} // namespace snapshot
} // namespace android
diff --git a/init/Android.bp b/init/Android.bp
index 52628f3..72a7bfe 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -28,7 +28,6 @@
"rlimit_parser.cpp",
"service.cpp",
"service_list.cpp",
- "service_lock.cpp",
"service_parser.cpp",
"service_utils.cpp",
"subcontext.cpp",
diff --git a/init/builtins.cpp b/init/builtins.cpp
index dd5af72..200bfff 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -151,7 +151,6 @@
template <typename F>
static void ForEachServiceInClass(const std::string& classname, F function) {
- auto lock = std::lock_guard{service_lock};
for (const auto& service : ServiceList::GetInstance()) {
if (service->classnames().count(classname)) std::invoke(function, service);
}
@@ -163,7 +162,6 @@
return {};
// Starting a class does not start services which are explicitly disabled.
// They must be started individually.
- auto lock = std::lock_guard{service_lock};
for (const auto& service : ServiceList::GetInstance()) {
if (service->classnames().count(args[1])) {
if (auto result = service->StartIfNotDisabled(); !result.ok()) {
@@ -186,7 +184,6 @@
// stopped either.
return {};
}
- auto lock = std::lock_guard{service_lock};
for (const auto& service : ServiceList::GetInstance()) {
if (service->classnames().count(args[1])) {
if (auto result = service->StartIfPostData(); !result.ok()) {
@@ -237,7 +234,6 @@
}
static Result<void> do_enable(const BuiltinArguments& args) {
- auto lock = std::lock_guard{service_lock};
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) return Error() << "Could not find service";
@@ -249,7 +245,6 @@
}
static Result<void> do_exec(const BuiltinArguments& args) {
- auto lock = std::lock_guard{service_lock};
auto service = Service::MakeTemporaryOneshotService(args.args);
if (!service.ok()) {
return Error() << "Could not create exec service: " << service.error();
@@ -263,7 +258,6 @@
}
static Result<void> do_exec_background(const BuiltinArguments& args) {
- auto lock = std::lock_guard{service_lock};
auto service = Service::MakeTemporaryOneshotService(args.args);
if (!service.ok()) {
return Error() << "Could not create exec background service: " << service.error();
@@ -277,7 +271,6 @@
}
static Result<void> do_exec_start(const BuiltinArguments& args) {
- auto lock = std::lock_guard{service_lock};
Service* service = ServiceList::GetInstance().FindService(args[1]);
if (!service) {
return Error() << "Service not found";
@@ -347,7 +340,6 @@
}
static Result<void> do_interface_restart(const BuiltinArguments& args) {
- auto lock = std::lock_guard{service_lock};
Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
if (!svc) return Error() << "interface " << args[1] << " not found";
svc->Restart();
@@ -355,7 +347,6 @@
}
static Result<void> do_interface_start(const BuiltinArguments& args) {
- auto lock = std::lock_guard{service_lock};
Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
if (!svc) return Error() << "interface " << args[1] << " not found";
if (auto result = svc->Start(); !result.ok()) {
@@ -365,7 +356,6 @@
}
static Result<void> do_interface_stop(const BuiltinArguments& args) {
- auto lock = std::lock_guard{service_lock};
Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
if (!svc) return Error() << "interface " << args[1] << " not found";
svc->Stop();
@@ -750,7 +740,6 @@
}
static Result<void> do_start(const BuiltinArguments& args) {
- auto lock = std::lock_guard{service_lock};
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) return Error() << "service " << args[1] << " not found";
if (auto result = svc->Start(); !result.ok()) {
@@ -760,7 +749,6 @@
}
static Result<void> do_stop(const BuiltinArguments& args) {
- auto lock = std::lock_guard{service_lock};
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) return Error() << "service " << args[1] << " not found";
svc->Stop();
@@ -768,7 +756,6 @@
}
static Result<void> do_restart(const BuiltinArguments& args) {
- auto lock = std::lock_guard{service_lock};
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) return Error() << "service " << args[1] << " not found";
svc->Restart();
@@ -1124,7 +1111,6 @@
function(StringPrintf("Exec service failed, status %d", siginfo.si_status));
}
});
- auto lock = std::lock_guard{service_lock};
if (auto result = (*service)->ExecStart(); !result.ok()) {
function("ExecStart failed: " + result.error().message());
}
@@ -1264,7 +1250,6 @@
}
success &= parser.ParseConfigFile(c);
}
- auto lock = std::lock_guard{service_lock};
ServiceList::GetInstance().MarkServicesUpdate();
if (success) {
return {};
diff --git a/init/init.cpp b/init/init.cpp
index 63aefc1..4289dcf 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -99,6 +99,15 @@
static std::unique_ptr<Subcontext> subcontext;
+struct PendingControlMessage {
+ std::string message;
+ std::string name;
+ pid_t pid;
+ int fd;
+};
+static std::mutex pending_control_messages_lock;
+static std::queue<PendingControlMessage> pending_control_messages;
+
// Init epolls various FDs to wait for various inputs. It previously waited on property changes
// with a blocking socket that contained the information related to the change, however, it was easy
// to fill that socket and deadlock the system. Now we use locks to handle the property changes
@@ -238,7 +247,6 @@
} shutdown_state;
void DumpState() {
- auto lock = std::lock_guard{service_lock};
ServiceList::GetInstance().DumpState();
ActionManager::GetInstance().DumpState();
}
@@ -312,7 +320,6 @@
static std::optional<boot_clock::time_point> HandleProcessActions() {
std::optional<boot_clock::time_point> next_process_action_time;
- auto lock = std::lock_guard{service_lock};
for (const auto& s : ServiceList::GetInstance()) {
if ((s->flags() & SVC_RUNNING) && s->timeout_period()) {
auto timeout_time = s->time_started() + *s->timeout_period();
@@ -341,7 +348,7 @@
return next_process_action_time;
}
-static Result<void> DoControlStart(Service* service) REQUIRES(service_lock) {
+static Result<void> DoControlStart(Service* service) {
return service->Start();
}
@@ -350,7 +357,7 @@
return {};
}
-static Result<void> DoControlRestart(Service* service) REQUIRES(service_lock) {
+static Result<void> DoControlRestart(Service* service) {
service->Restart();
return {};
}
@@ -384,7 +391,7 @@
return control_message_functions;
}
-bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t from_pid) {
+bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t pid) {
const auto& map = get_control_message_map();
const auto it = map.find(msg);
@@ -393,7 +400,7 @@
return false;
}
- std::string cmdline_path = StringPrintf("proc/%d/cmdline", from_pid);
+ std::string cmdline_path = StringPrintf("proc/%d/cmdline", pid);
std::string process_cmdline;
if (ReadFileToString(cmdline_path, &process_cmdline)) {
std::replace(process_cmdline.begin(), process_cmdline.end(), '\0', ' ');
@@ -404,8 +411,6 @@
const ControlMessageFunction& function = it->second;
- auto lock = std::lock_guard{service_lock};
-
Service* svc = nullptr;
switch (function.target) {
@@ -423,22 +428,59 @@
if (svc == nullptr) {
LOG(ERROR) << "Control message: Could not find '" << name << "' for ctl." << msg
- << " from pid: " << from_pid << " (" << process_cmdline << ")";
+ << " from pid: " << pid << " (" << process_cmdline << ")";
return false;
}
if (auto result = function.action(svc); !result.ok()) {
LOG(ERROR) << "Control message: Could not ctl." << msg << " for '" << name
- << "' from pid: " << from_pid << " (" << process_cmdline
- << "): " << result.error();
+ << "' from pid: " << pid << " (" << process_cmdline << "): " << result.error();
return false;
}
LOG(INFO) << "Control message: Processed ctl." << msg << " for '" << name
- << "' from pid: " << from_pid << " (" << process_cmdline << ")";
+ << "' from pid: " << pid << " (" << process_cmdline << ")";
return true;
}
+bool QueueControlMessage(const std::string& message, const std::string& name, pid_t pid, int fd) {
+ auto lock = std::lock_guard{pending_control_messages_lock};
+ if (pending_control_messages.size() > 100) {
+ LOG(ERROR) << "Too many pending control messages, dropped '" << message << "' for '" << name
+ << "' from pid: " << pid;
+ return false;
+ }
+ pending_control_messages.push({message, name, pid, fd});
+ WakeEpoll();
+ return true;
+}
+
+static void HandleControlMessages() {
+ auto lock = std::unique_lock{pending_control_messages_lock};
+ // Init historically would only execute handle one property message, including control messages
+ // in each iteration of its main loop. We retain this behavior here to prevent starvation of
+ // other actions in the main loop.
+ if (!pending_control_messages.empty()) {
+ auto control_message = pending_control_messages.front();
+ pending_control_messages.pop();
+ lock.unlock();
+
+ bool success = HandleControlMessage(control_message.message, control_message.name,
+ control_message.pid);
+
+ uint32_t response = success ? PROP_SUCCESS : PROP_ERROR_HANDLE_CONTROL_MESSAGE;
+ if (control_message.fd != -1) {
+ TEMP_FAILURE_RETRY(send(control_message.fd, &response, sizeof(response), 0));
+ close(control_message.fd);
+ }
+ lock.lock();
+ }
+ // If we still have items to process, make sure we wake back up to do so.
+ if (!pending_control_messages.empty()) {
+ WakeEpoll();
+ }
+}
+
static Result<void> wait_for_coldboot_done_action(const BuiltinArguments& args) {
if (!prop_waiter_state.StartWaiting(kColdBootDoneProp, "true")) {
LOG(FATAL) << "Could not wait for '" << kColdBootDoneProp << "'";
@@ -588,7 +630,6 @@
}
auto found = false;
- auto lock = std::lock_guard{service_lock};
for (const auto& service : ServiceList::GetInstance()) {
auto svc = service.get();
if (svc->keycodes() == keycodes) {
@@ -659,22 +700,6 @@
}
}
-void SendStopSendingMessagesMessage() {
- auto init_message = InitMessage{};
- init_message.set_stop_sending_messages(true);
- if (auto result = SendMessage(property_fd, init_message); !result.ok()) {
- LOG(ERROR) << "Failed to send 'stop sending messages' message: " << result.error();
- }
-}
-
-void SendStartSendingMessagesMessage() {
- auto init_message = InitMessage{};
- init_message.set_start_sending_messages(true);
- if (auto result = SendMessage(property_fd, init_message); !result.ok()) {
- LOG(ERROR) << "Failed to send 'start sending messages' message: " << result.error();
- }
-}
-
int SecondStageMain(int argc, char** argv) {
if (REBOOT_BOOTLOADER_ON_PANIC) {
InstallRebootSignalHandlers();
@@ -688,8 +713,15 @@
InitKernelLogging(argv);
LOG(INFO) << "init second stage started!";
- // Will handle EPIPE at the time of write by checking the errno
- signal(SIGPIPE, SIG_IGN);
+ // Init should not crash because of a dependence on any other process, therefore we ignore
+ // SIGPIPE and handle EPIPE at the call site directly. Note that setting a signal to SIG_IGN
+ // is inherited across exec, but custom signal handlers are not. Since we do not want to
+ // ignore SIGPIPE for child processes, we set a no-op function for the signal handler instead.
+ {
+ struct sigaction action = {.sa_flags = SA_RESTART};
+ action.sa_handler = [](int) {};
+ sigaction(SIGPIPE, &action, nullptr);
+ }
// Set init and its forked children's oom_adj.
if (auto result =
@@ -796,7 +828,6 @@
Keychords keychords;
am.QueueBuiltinAction(
[&epoll, &keychords](const BuiltinArguments& args) -> Result<void> {
- auto lock = std::lock_guard{service_lock};
for (const auto& svc : ServiceList::GetInstance()) {
keychords.Register(svc->keycodes());
}
@@ -863,6 +894,7 @@
(*function)();
}
}
+ HandleControlMessages();
}
return 0;
diff --git a/init/init.h b/init/init.h
index bcf24e7..27f64e2 100644
--- a/init/init.h
+++ b/init/init.h
@@ -38,11 +38,9 @@
void ResetWaitForProp();
void SendLoadPersistentPropertiesMessage();
-void SendStopSendingMessagesMessage();
-void SendStartSendingMessagesMessage();
void PropertyChanged(const std::string& name, const std::string& value);
-bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t from_pid);
+bool QueueControlMessage(const std::string& message, const std::string& name, pid_t pid, int fd);
int SecondStageMain(int argc, char** argv);
diff --git a/init/init_test.cpp b/init/init_test.cpp
index 3053bd8..caf3e03 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -167,7 +167,6 @@
ServiceList service_list;
TestInitText(init_script, BuiltinFunctionMap(), {}, &service_list);
- auto lock = std::lock_guard{service_lock};
ASSERT_EQ(1, std::distance(service_list.begin(), service_list.end()));
auto service = service_list.begin()->get();
diff --git a/init/lmkd_service.cpp b/init/lmkd_service.cpp
index a531d0a..dd1ab4d 100644
--- a/init/lmkd_service.cpp
+++ b/init/lmkd_service.cpp
@@ -79,8 +79,7 @@
}
static void RegisterServices(pid_t exclude_pid) {
- auto lock = std::lock_guard{service_lock};
- for (const auto& service : ServiceList::GetInstance()) {
+ for (const auto& service : ServiceList::GetInstance().services()) {
auto svc = service.get();
if (svc->oom_score_adjust() != DEFAULT_OOM_SCORE_ADJUST) {
// skip if process is excluded or not yet forked (pid==0)
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
index 2175075..0749fe3 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -29,7 +29,6 @@
#include <android-base/unique_fd.h>
#include <apex_manifest.pb.h>
-#include "property_service.h"
#include "util.h"
namespace android {
@@ -291,14 +290,6 @@
return true;
}
if (default_ns_id != GetMountNamespaceId()) {
- // The property service thread and its descendent threads must be in the correct mount
- // namespace to call Service::Start(), however setns() only operates on a single thread and
- // fails when secondary threads attempt to join the same mount namespace. Therefore, we
- // must join the property service thread and its descendents before the setns() call. Those
- // threads are then started again after the setns() call, and they'll be in the proper
- // namespace.
- PausePropertyService();
-
if (setns(default_ns_fd.get(), CLONE_NEWNS) == -1) {
PLOG(ERROR) << "Failed to switch back to the default mount namespace.";
return false;
@@ -308,8 +299,6 @@
LOG(ERROR) << result.error();
return false;
}
-
- ResumePropertyService();
}
LOG(INFO) << "Switched to default mount namespace";
@@ -323,20 +312,10 @@
}
if (bootstrap_ns_id != GetMountNamespaceId() && bootstrap_ns_fd.get() != -1 &&
IsApexUpdatable()) {
- // The property service thread and its descendent threads must be in the correct mount
- // namespace to call Service::Start(), however setns() only operates on a single thread and
- // fails when secondary threads attempt to join the same mount namespace. Therefore, we
- // must join the property service thread and its descendents before the setns() call. Those
- // threads are then started again after the setns() call, and they'll be in the proper
- // namespace.
- PausePropertyService();
-
if (setns(bootstrap_ns_fd.get(), CLONE_NEWNS) == -1) {
PLOG(ERROR) << "Failed to switch to bootstrap mount namespace.";
return false;
}
-
- ResumePropertyService();
}
return true;
}
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 319a241..8206522 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -95,6 +95,7 @@
static int from_init_socket = -1;
static int init_socket = -1;
static bool accept_messages = false;
+static std::mutex accept_messages_lock;
static std::thread property_service_thread;
static PropertyInfoAreaFile property_info_area;
@@ -117,6 +118,16 @@
return 0;
}
+void StartSendingMessages() {
+ auto lock = std::lock_guard{accept_messages_lock};
+ accept_messages = true;
+}
+
+void StopSendingMessages() {
+ auto lock = std::lock_guard{accept_messages_lock};
+ accept_messages = true;
+}
+
bool CanReadProperty(const std::string& source_context, const std::string& name) {
const char* target_context = nullptr;
property_info_area->GetPropertyInfo(name.c_str(), &target_context, nullptr);
@@ -186,138 +197,49 @@
}
// If init hasn't started its main loop, then it won't be handling property changed messages
// anyway, so there's no need to try to send them.
+ auto lock = std::lock_guard{accept_messages_lock};
if (accept_messages) {
PropertyChanged(name, value);
}
return PROP_SUCCESS;
}
-template <typename T>
-class SingleThreadExecutor {
+class AsyncRestorecon {
public:
- virtual ~SingleThreadExecutor() {}
-
- template <typename F = T>
- void Run(F&& item) {
+ void TriggerRestorecon(const std::string& path) {
auto guard = std::lock_guard{mutex_};
- items_.emplace(std::forward<F>(item));
+ paths_.emplace(path);
- if (thread_state_ == ThreadState::kRunning || thread_state_ == ThreadState::kStopped) {
- return;
- }
-
- if (thread_state_ == ThreadState::kPendingJoin) {
- thread_.join();
- }
-
- StartThread();
- }
-
- void StopAndJoin() {
- auto lock = std::unique_lock{mutex_};
- if (thread_state_ == ThreadState::kPendingJoin) {
- thread_.join();
- } else if (thread_state_ == ThreadState::kRunning) {
- thread_state_ = ThreadState::kStopped;
- lock.unlock();
- thread_.join();
- lock.lock();
- }
-
- thread_state_ = ThreadState::kStopped;
- }
-
- void Restart() {
- auto guard = std::lock_guard{mutex_};
- if (items_.empty()) {
- thread_state_ = ThreadState::kNotStarted;
- } else {
- StartThread();
- }
- }
-
- void MaybeJoin() {
- auto guard = std::lock_guard{mutex_};
- if (thread_state_ == ThreadState::kPendingJoin) {
- thread_.join();
- thread_state_ = ThreadState::kNotStarted;
+ if (!thread_started_) {
+ thread_started_ = true;
+ std::thread{&AsyncRestorecon::ThreadFunction, this}.detach();
}
}
private:
- virtual void Execute(T&& item) = 0;
-
- void StartThread() {
- thread_state_ = ThreadState::kRunning;
- auto thread = std::thread{&SingleThreadExecutor::ThreadFunction, this};
- std::swap(thread_, thread);
- }
-
void ThreadFunction() {
auto lock = std::unique_lock{mutex_};
- while (!items_.empty()) {
- auto item = items_.front();
- items_.pop();
+ while (!paths_.empty()) {
+ auto path = paths_.front();
+ paths_.pop();
lock.unlock();
- Execute(std::move(item));
+ if (selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
+ LOG(ERROR) << "Asynchronous restorecon of '" << path << "' failed'";
+ }
+ android::base::SetProperty(kRestoreconProperty, path);
lock.lock();
}
- if (thread_state_ != ThreadState::kStopped) {
- thread_state_ = ThreadState::kPendingJoin;
- }
+ thread_started_ = false;
}
std::mutex mutex_;
- std::queue<T> items_;
- enum class ThreadState {
- kNotStarted, // Initial state when starting the program or when restarting with no items to
- // process.
- kRunning, // The thread is running and is in a state that it will process new items if
- // are run.
- kPendingJoin, // The thread has run to completion and is pending join(). A new thread must
- // be launched for new items to be processed.
- kStopped, // This executor has stopped and will not process more items until Restart() is
- // called. Currently pending items will be processed and the thread will be
- // joined.
- };
- ThreadState thread_state_ = ThreadState::kNotStarted;
- std::thread thread_;
+ std::queue<std::string> paths_;
+ bool thread_started_ = false;
};
-class RestoreconThread : public SingleThreadExecutor<std::string> {
- virtual void Execute(std::string&& path) override {
- if (selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
- LOG(ERROR) << "Asynchronous restorecon of '" << path << "' failed'";
- }
- android::base::SetProperty(kRestoreconProperty, path);
- }
-};
-
-struct ControlMessageInfo {
- std::string message;
- std::string name;
- pid_t pid;
- int fd;
-};
-
-class ControlMessageThread : public SingleThreadExecutor<ControlMessageInfo> {
- virtual void Execute(ControlMessageInfo&& info) override {
- bool success = HandleControlMessage(info.message, info.name, info.pid);
-
- uint32_t response = success ? PROP_SUCCESS : PROP_ERROR_HANDLE_CONTROL_MESSAGE;
- if (info.fd != -1) {
- TEMP_FAILURE_RETRY(send(info.fd, &response, sizeof(response), 0));
- close(info.fd);
- }
- }
-};
-
-static RestoreconThread restorecon_thread;
-static ControlMessageThread control_message_thread;
-
class SocketConnection {
public:
SocketConnection(int socket, const ucred& cred) : socket_(socket), cred_(cred) {}
@@ -454,22 +376,25 @@
static uint32_t SendControlMessage(const std::string& msg, const std::string& name, pid_t pid,
SocketConnection* socket, std::string* error) {
+ auto lock = std::lock_guard{accept_messages_lock};
if (!accept_messages) {
*error = "Received control message after shutdown, ignoring";
return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
}
- // We must release the fd before spawning the thread, otherwise there will be a race with the
- // thread. If the thread calls close() before this function calls Release(), then fdsan will see
- // the wrong tag and abort().
+ // We must release the fd before sending it to init, otherwise there will be a race with init.
+ // If init calls close() before Release(), then fdsan will see the wrong tag and abort().
int fd = -1;
if (socket != nullptr && SelinuxGetVendorAndroidVersion() > __ANDROID_API_Q__) {
fd = socket->Release();
}
- // Handling a control message likely calls SetProperty, which we must synchronously handle,
- // therefore we must fork a thread to handle it.
- control_message_thread.Run({msg, name, pid, fd});
+ bool queue_success = QueueControlMessage(msg, name, pid, fd);
+ if (!queue_success && fd != -1) {
+ uint32_t response = PROP_ERROR_HANDLE_CONTROL_MESSAGE;
+ TEMP_FAILURE_RETRY(send(fd, &response, sizeof(response), 0));
+ close(fd);
+ }
return PROP_SUCCESS;
}
@@ -571,7 +496,8 @@
// We use a thread to do this restorecon operation to prevent holding up init, as it may take
// a long time to complete.
if (name == kRestoreconProperty && cr.pid != 1 && !value.empty()) {
- restorecon_thread.Run(value);
+ static AsyncRestorecon async_restorecon;
+ async_restorecon.TriggerRestorecon(value);
return PROP_SUCCESS;
}
@@ -1152,8 +1078,6 @@
PropertyLoadBootDefaults();
}
-static bool pause_property_service = false;
-
static void HandleInitSocket() {
auto message = ReadMessage(init_socket);
if (!message.ok()) {
@@ -1180,18 +1104,6 @@
persistent_properties_loaded = true;
break;
}
- case InitMessage::kStopSendingMessages: {
- accept_messages = false;
- break;
- }
- case InitMessage::kStartSendingMessages: {
- accept_messages = true;
- break;
- }
- case InitMessage::kPausePropertyService: {
- pause_property_service = true;
- break;
- }
default:
LOG(ERROR) << "Unknown message type from init: " << init_message.msg_case();
}
@@ -1212,7 +1124,7 @@
LOG(FATAL) << result.error();
}
- while (!pause_property_service) {
+ while (true) {
auto pending_functions = epoll.Wait(std::nullopt);
if (!pending_functions.ok()) {
LOG(ERROR) << pending_functions.error();
@@ -1221,34 +1133,9 @@
(*function)();
}
}
- control_message_thread.MaybeJoin();
- restorecon_thread.MaybeJoin();
}
}
-void SendStopPropertyServiceMessage() {
- auto init_message = InitMessage{};
- init_message.set_pause_property_service(true);
- if (auto result = SendMessage(from_init_socket, init_message); !result.ok()) {
- LOG(ERROR) << "Failed to send stop property service message: " << result.error();
- }
-}
-
-void PausePropertyService() {
- control_message_thread.StopAndJoin();
- restorecon_thread.StopAndJoin();
- SendStopPropertyServiceMessage();
- property_service_thread.join();
-}
-
-void ResumePropertyService() {
- pause_property_service = false;
- auto new_thread = std::thread{PropertyServiceThread};
- property_service_thread.swap(new_thread);
- restorecon_thread.Restart();
- control_message_thread.Restart();
-}
-
void StartPropertyService(int* epoll_socket) {
InitPropertySet("ro.property_service.version", "2");
@@ -1258,7 +1145,7 @@
}
*epoll_socket = from_init_socket = sockets[0];
init_socket = sockets[1];
- accept_messages = true;
+ StartSendingMessages();
if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
false, 0666, 0, 0, {});
diff --git a/init/property_service.h b/init/property_service.h
index e921326..2d49a36 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -31,8 +31,9 @@
void PropertyInit();
void StartPropertyService(int* epoll_socket);
-void ResumePropertyService();
-void PausePropertyService();
+
+void StartSendingMessages();
+void StopSendingMessages();
} // namespace init
} // namespace android
diff --git a/init/property_service.proto b/init/property_service.proto
index 36245b2..08268d9 100644
--- a/init/property_service.proto
+++ b/init/property_service.proto
@@ -41,6 +41,5 @@
bool load_persistent_properties = 1;
bool stop_sending_messages = 2;
bool start_sending_messages = 3;
- bool pause_property_service = 4;
};
}
diff --git a/init/reboot.cpp b/init/reboot.cpp
index cad192d..f006df3 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -59,6 +59,7 @@
#include "builtin_arguments.h"
#include "init.h"
#include "mount_namespace.h"
+#include "property_service.h"
#include "reboot_utils.h"
#include "service.h"
#include "service_list.h"
@@ -85,7 +86,7 @@
static const std::set<std::string> kDebuggingServices{"tombstoned", "logd", "adbd", "console"};
-static std::vector<Service*> GetDebuggingServices(bool only_post_data) REQUIRES(service_lock) {
+static std::vector<Service*> GetDebuggingServices(bool only_post_data) {
std::vector<Service*> ret;
ret.reserve(kDebuggingServices.size());
for (const auto& s : ServiceList::GetInstance()) {
@@ -181,7 +182,7 @@
};
// Turn off backlight while we are performing power down cleanup activities.
-static void TurnOffBacklight() REQUIRES(service_lock) {
+static void TurnOffBacklight() {
Service* service = ServiceList::GetInstance().FindService("blank_screen");
if (service == nullptr) {
LOG(WARNING) << "cannot find blank_screen in TurnOffBacklight";
@@ -589,7 +590,6 @@
// Start reboot monitor thread
sem_post(&reboot_semaphore);
- auto lock = std::lock_guard{service_lock};
// watchdogd is a vendor specific component but should be alive to complete shutdown safely.
const std::set<std::string> to_starts{"watchdogd"};
std::vector<Service*> stop_first;
@@ -709,21 +709,15 @@
// Skip wait for prop if it is in progress
ResetWaitForProp();
// Clear EXEC flag if there is one pending
- auto lock = std::lock_guard{service_lock};
for (const auto& s : ServiceList::GetInstance()) {
s->UnSetExec();
}
- // We no longer process messages about properties changing coming from property service, so we
- // need to tell property service to stop sending us these messages, otherwise it'll fill the
- // buffers and block indefinitely, causing future property sets, including those that init makes
- // during shutdown in Service::NotifyStateChange() to also block indefinitely.
- SendStopSendingMessagesMessage();
}
static void LeaveShutdown() {
LOG(INFO) << "Leaving shutdown mode";
shutting_down = false;
- SendStartSendingMessagesMessage();
+ StartSendingMessages();
}
static Result<void> UnmountAllApexes() {
@@ -753,7 +747,6 @@
return Error() << "Failed to set sys.init.userspace_reboot.in_progress property";
}
EnterShutdown();
- auto lock = std::lock_guard{service_lock};
if (!SetProperty("sys.powerctl", "")) {
return Error() << "Failed to reset sys.powerctl property";
}
@@ -914,7 +907,6 @@
run_fsck = true;
} else if (cmd_params[1] == "thermal") {
// Turn off sources of heat immediately.
- auto lock = std::lock_guard{service_lock};
TurnOffBacklight();
// run_fsck is false to avoid delay
cmd = ANDROID_RB_THERMOFF;
@@ -985,6 +977,10 @@
return;
}
+ // We do not want to process any messages (queue'ing triggers, shutdown messages, control
+ // messages, etc) from properties during reboot.
+ StopSendingMessages();
+
if (userspace_reboot) {
HandleUserspaceReboot();
return;
diff --git a/init/selinux.cpp b/init/selinux.cpp
index acbcbd6..808cb7f 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -539,9 +539,9 @@
// adb remount, snapshot-based updates, and DSUs all create files during
// first-stage init.
- selinux_android_restorecon("/metadata", SELINUX_ANDROID_RESTORECON_RECURSE);
-
selinux_android_restorecon(SnapshotManager::GetGlobalRollbackIndicatorPath().c_str(), 0);
+ selinux_android_restorecon("/metadata/gsi", SELINUX_ANDROID_RESTORECON_RECURSE |
+ SELINUX_ANDROID_RESTORECON_SKIP_SEHASH);
}
int SelinuxKlogCallback(int type, const char* fmt, ...) {
diff --git a/init/service.h b/init/service.h
index d2a4462..cf3f0c2 100644
--- a/init/service.h
+++ b/init/service.h
@@ -27,14 +27,12 @@
#include <vector>
#include <android-base/chrono_utils.h>
-#include <android-base/thread_annotations.h>
#include <cutils/iosched_policy.h>
#include "action.h"
#include "capabilities.h"
#include "keyword_map.h"
#include "parser.h"
-#include "service_lock.h"
#include "service_utils.h"
#include "subcontext.h"
@@ -79,17 +77,17 @@
bool IsRunning() { return (flags_ & SVC_RUNNING) != 0; }
bool IsEnabled() { return (flags_ & SVC_DISABLED) == 0; }
- Result<void> ExecStart() REQUIRES(service_lock);
- Result<void> Start() REQUIRES(service_lock);
- Result<void> StartIfNotDisabled() REQUIRES(service_lock);
- Result<void> StartIfPostData() REQUIRES(service_lock);
- Result<void> Enable() REQUIRES(service_lock);
+ Result<void> ExecStart();
+ Result<void> Start();
+ Result<void> StartIfNotDisabled();
+ Result<void> StartIfPostData();
+ Result<void> Enable();
void Reset();
void ResetIfPostData();
void Stop();
void Terminate();
void Timeout();
- void Restart() REQUIRES(service_lock);
+ void Restart();
void Reap(const siginfo_t& siginfo);
void DumpState() const;
void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
diff --git a/init/service_list.h b/init/service_list.h
index 280a228..3b9018b 100644
--- a/init/service_list.h
+++ b/init/service_list.h
@@ -17,13 +17,9 @@
#pragma once
#include <memory>
-#include <mutex>
#include <vector>
-#include <android-base/thread_annotations.h>
-
#include "service.h"
-#include "service_lock.h"
namespace android {
namespace init {
@@ -36,16 +32,16 @@
ServiceList();
size_t CheckAllCommands();
- void AddService(std::unique_ptr<Service> service) REQUIRES(service_lock);
- void RemoveService(const Service& svc) REQUIRES(service_lock);
+ void AddService(std::unique_ptr<Service> service);
+ void RemoveService(const Service& svc);
template <class UnaryPredicate>
- void RemoveServiceIf(UnaryPredicate predicate) REQUIRES(service_lock) {
+ void RemoveServiceIf(UnaryPredicate predicate) {
services_.erase(std::remove_if(services_.begin(), services_.end(), predicate),
services_.end());
}
template <typename T, typename F = decltype(&Service::name)>
- Service* FindService(T value, F function = &Service::name) const REQUIRES(service_lock) {
+ Service* FindService(T value, F function = &Service::name) const {
auto svc = std::find_if(services_.begin(), services_.end(),
[&function, &value](const std::unique_ptr<Service>& s) {
return std::invoke(function, s) == value;
@@ -56,7 +52,7 @@
return nullptr;
}
- Service* FindInterface(const std::string& interface_name) REQUIRES(service_lock) {
+ Service* FindInterface(const std::string& interface_name) {
for (const auto& svc : services_) {
if (svc->interfaces().count(interface_name) > 0) {
return svc.get();
@@ -66,20 +62,18 @@
return nullptr;
}
- void DumpState() const REQUIRES(service_lock);
+ void DumpState() const;
- auto begin() const REQUIRES(service_lock) { return services_.begin(); }
- auto end() const REQUIRES(service_lock) { return services_.end(); }
- const std::vector<std::unique_ptr<Service>>& services() const REQUIRES(service_lock) {
- return services_;
- }
- const std::vector<Service*> services_in_shutdown_order() const REQUIRES(service_lock);
+ auto begin() const { return services_.begin(); }
+ auto end() const { return services_.end(); }
+ const std::vector<std::unique_ptr<Service>>& services() const { return services_; }
+ const std::vector<Service*> services_in_shutdown_order() const;
void MarkPostData();
bool IsPostData();
- void MarkServicesUpdate() REQUIRES(service_lock);
+ void MarkServicesUpdate();
bool IsServicesUpdated() const { return services_update_finished_; }
- void DelayService(const Service& service) REQUIRES(service_lock);
+ void DelayService(const Service& service);
void ResetState() {
post_data_ = false;
diff --git a/init/service_lock.h b/init/service_lock.h
deleted file mode 100644
index 6b94271..0000000
--- a/init/service_lock.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2020 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 <mutex>
-
-#include <android-base/thread_annotations.h>
-
-namespace android {
-namespace init {
-
-// This class exists to add thread annotations, since they're absent from std::recursive_mutex.
-
-class CAPABILITY("mutex") RecursiveMutex {
- public:
- void lock() ACQUIRE() { mutex_.lock(); }
- void unlock() RELEASE() { mutex_.unlock(); }
-
- private:
- std::recursive_mutex mutex_;
-};
-
-extern RecursiveMutex service_lock;
-
-} // namespace init
-} // namespace android
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index 51f4c97..560f693 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -168,7 +168,6 @@
const std::string fullname = interface_name + "/" + instance_name;
- auto lock = std::lock_guard{service_lock};
for (const auto& svc : *service_list_) {
if (svc->interfaces().count(fullname) > 0) {
return Error() << "Interface '" << fullname << "' redefined in " << service_->name()
@@ -599,7 +598,6 @@
}
}
- auto lock = std::lock_guard{service_lock};
Service* old_service = service_list_->FindService(service_->name());
if (old_service) {
if (!service_->is_override()) {
diff --git a/init/sigchld_handler.cpp b/init/sigchld_handler.cpp
index 064d64d..9b2c7d9 100644
--- a/init/sigchld_handler.cpp
+++ b/init/sigchld_handler.cpp
@@ -64,8 +64,6 @@
std::string wait_string;
Service* service = nullptr;
- auto lock = std::lock_guard{service_lock};
-
if (SubcontextChildReap(pid)) {
name = "Subcontext";
} else {
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 565f2c3..76caadc 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -44,12 +44,20 @@
recovery_available: true,
native_bridge_supported: true,
export_include_dirs: ["include"],
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
}
cc_library {
name: "libbacktrace",
vendor_available: false,
recovery_available: true,
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
vndk: {
enabled: true,
support_system_process: true,
@@ -89,6 +97,9 @@
},
android: {
static_libs: ["libasync_safe"],
+ static: {
+ whole_static_libs: ["libasync_safe"],
+ },
},
vendor: {
cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
diff --git a/libcrypto_utils/Android.bp b/libcrypto_utils/Android.bp
index e47560f..d7175e0 100644
--- a/libcrypto_utils/Android.bp
+++ b/libcrypto_utils/Android.bp
@@ -38,4 +38,8 @@
enabled: true,
},
},
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.adbd",
+ ],
}
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 8e90ddf..dccf588 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -29,6 +29,10 @@
vendor_available: true,
recovery_available: true,
host_supported: true,
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
native_bridge_supported: true,
export_include_dirs: ["include"],
target: {
@@ -45,13 +49,9 @@
}
// Socket specific parts of libcutils that are safe to statically link into an APEX.
-cc_library_static {
+cc_library {
name: "libcutils_sockets",
vendor_available: true,
- vndk: {
- enabled: true,
- support_system_process: true,
- },
recovery_available: true,
host_supported: true,
native_bridge_supported: true,
@@ -62,6 +62,7 @@
export_include_dirs: ["include"],
+ shared_libs: ["liblog"],
srcs: ["sockets.cpp"],
target: {
linux_bionic: {
@@ -137,6 +138,10 @@
},
recovery_available: true,
host_supported: true,
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
native_bridge_supported: true,
srcs: [
"config_utils.cpp",
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index c4e4f85..5805a4d 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -201,6 +201,8 @@
CAP_MASK_LONG(CAP_SETGID),
"system/bin/simpleperf_app_runner" },
{ 00755, AID_ROOT, AID_ROOT, 0, "first_stage_ramdisk/system/bin/e2fsck" },
+ { 00755, AID_ROOT, AID_ROOT, 0, "first_stage_ramdisk/system/bin/tune2fs" },
+ { 00755, AID_ROOT, AID_ROOT, 0, "first_stage_ramdisk/system/bin/resize2fs" },
// generic defaults
{ 00755, AID_ROOT, AID_ROOT, 0, "bin/*" },
{ 00640, AID_ROOT, AID_SHELL, 0, "fstab.*" },
diff --git a/liblog/Android.bp b/liblog/Android.bp
index f1e5118..0b98e1a 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -38,6 +38,10 @@
vendor_available: true,
ramdisk_available: true,
recovery_available: true,
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
native_bridge_supported: true,
export_include_dirs: ["include"],
system_shared_libs: [],
@@ -117,8 +121,12 @@
logtags: ["event.logtags"],
compile_multilib: "both",
apex_available: [
- "//apex_available:anyapex",
"//apex_available:platform",
+ // liblog is exceptionally available to the runtime APEX
+ // because the dynamic linker has to use it statically.
+ // See b/151051671
+ "com.android.runtime",
+ // DO NOT add more apex names here
],
}
diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h
index b9839d6..43a91ab 100644
--- a/liblog/include/android/log.h
+++ b/liblog/include/android/log.h
@@ -56,6 +56,12 @@
#include <stdarg.h>
#include <stddef.h>
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+#if !defined(__BIONIC__) && !defined(__INTRODUCED_IN)
+#define __INTRODUCED_IN(x)
+#endif
#ifdef __cplusplus
extern "C" {
@@ -149,14 +155,11 @@
/** The kernel log buffer. */
LOG_ID_KERNEL = 7,
- LOG_ID_MAX
-} log_id_t;
+ LOG_ID_MAX,
-/**
- * Let the logging function choose the best log target.
- * This is not part of the enum since adding either -1 or 0xFFFFFFFF forces the enum to be signed or
- * unsigned, which breaks unfortunately common arithmetic against LOG_ID_MIN and LOG_ID_MAX. */
-#define LOG_ID_DEFAULT (-1)
+ /** Let the logging function choose the best log target. */
+ LOG_ID_DEFAULT = 0x7FFFFFFF
+} log_id_t;
/**
* Writes the constant string `text` to the log buffer `id`,
@@ -183,14 +186,26 @@
*/
struct __android_logger_data {
size_t struct_size; /* Must be set to sizeof(__android_logger_data) and is used for versioning. */
- int buffer_id; /* log_id_t or -1 to represent 'default'. */
- int priority; /* android_LogPriority values. */
+ int32_t buffer_id; /* log_id_t or -1 to represent 'default'. */
+ int32_t priority; /* android_LogPriority values. */
const char* tag;
const char* file; /* Optional file name, may be set to nullptr. */
- unsigned int line; /* Optional line number, ignore if file is nullptr. */
+ uint32_t line; /* Optional line number, ignore if file is nullptr. */
};
/**
+ * Prototype for the 'logger' function that is called for every log message.
+ */
+typedef void (*__android_logger_function)(const struct __android_logger_data* logger_data,
+ const char* message);
+/**
+ * Prototype for the 'abort' function that is called when liblog will abort due to
+ * __android_log_assert() failures.
+ */
+typedef void (*__android_aborter_function)(const char* abort_message);
+
+#if !defined(__ANDROID__) || __ANDROID_API__ >= 30
+/**
* Writes the log message specified with logger_data and msg to the log. logger_data includes
* additional file name and line number information that a logger may use. logger_data is versioned
* for backwards compatibility.
@@ -199,54 +214,44 @@
* buffers, then pass the message to liblog via this function, and therefore we do not want to
* duplicate the loggability check here.
*/
-void __android_log_write_logger_data(struct __android_logger_data* logger_data, const char* msg);
-
-/**
- * Prototype for the 'logger' function that is called for every log message.
- */
-typedef void (*__android_logger_function)(const struct __android_logger_data* logger_data,
- const char* message);
+void __android_log_write_logger_data(struct __android_logger_data* logger_data, const char* msg)
+ __INTRODUCED_IN(30);
/**
* Sets a user defined logger function. All log messages sent to liblog will be set to the
* function pointer specified by logger for processing.
*/
-void __android_log_set_logger(__android_logger_function logger);
+void __android_log_set_logger(__android_logger_function logger) __INTRODUCED_IN(30);
/**
* Writes the log message to logd. This is an __android_logger_function and can be provided to
* __android_log_set_logger(). It is the default logger when running liblog on a device.
*/
-void __android_log_logd_logger(const struct __android_logger_data* logger_data, const char* msg);
+void __android_log_logd_logger(const struct __android_logger_data* logger_data, const char* msg)
+ __INTRODUCED_IN(30);
/**
* Writes the log message to stderr. This is an __android_logger_function and can be provided to
* __android_log_set_logger(). It is the default logger when running liblog on host.
*/
void __android_log_stderr_logger(const struct __android_logger_data* logger_data,
- const char* message);
-
-/**
- * Prototype for the 'abort' function that is called when liblog will abort due to
- * __android_log_assert() failures.
- */
-typedef void (*__android_aborter_function)(const char* abort_message);
+ const char* message) __INTRODUCED_IN(30);
/**
* Sets a user defined aborter function that is called for __android_log_assert() failures.
*/
-void __android_log_set_aborter(__android_aborter_function aborter);
+void __android_log_set_aborter(__android_aborter_function aborter) __INTRODUCED_IN(30);
/**
* Calls the stored aborter function. This allows for other logging libraries to use the same
* aborter function by calling this function in liblog.
*/
-void __android_log_call_aborter(const char* abort_message);
+void __android_log_call_aborter(const char* abort_message) __INTRODUCED_IN(30);
/**
* Sets android_set_abort_message() on device then aborts(). This is the default aborter.
*/
-void __android_log_default_aborter(const char* abort_message);
+void __android_log_default_aborter(const char* abort_message) __INTRODUCED_IN(30);
/**
* Use the per-tag properties "log.tag.<tagname>" along with the minimum priority from
@@ -260,28 +265,30 @@
*
* prio is ANDROID_LOG_VERBOSE to ANDROID_LOG_FATAL.
*/
-int __android_log_is_loggable(int prio, const char* tag, int default_prio);
-int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio);
+int __android_log_is_loggable(int prio, const char* tag, int default_prio) __INTRODUCED_IN(30);
+int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio)
+ __INTRODUCED_IN(30);
/**
* Sets the minimum priority that will be logged for this process.
*
* This returns the previous set minimum priority, or ANDROID_LOG_DEFAULT if none was set.
*/
-int __android_log_set_minimum_priority(int priority);
+int32_t __android_log_set_minimum_priority(int32_t priority) __INTRODUCED_IN(30);
/**
* Gets the minimum priority that will be logged for this process. If none has been set by a
* previous __android_log_set_minimum_priority() call, this returns ANDROID_LOG_DEFAULT.
*/
-int __android_log_get_minimum_priority(void);
+int32_t __android_log_get_minimum_priority(void) __INTRODUCED_IN(30);
/**
* Sets the default tag if no tag is provided when writing a log message. Defaults to
* getprogname(). This truncates tag to the maximum log message size, though appropriate tags
* should be much smaller.
*/
-void __android_log_set_default_tag(const char* tag);
+void __android_log_set_default_tag(const char* tag) __INTRODUCED_IN(30);
+#endif
#ifdef __cplusplus
}
diff --git a/liblog/logger_name.cpp b/liblog/logger_name.cpp
index 7d676f4..e72290e 100644
--- a/liblog/logger_name.cpp
+++ b/liblog/logger_name.cpp
@@ -41,7 +41,10 @@
}
static_assert(std::is_same<std::underlying_type<log_id_t>::type, uint32_t>::value,
- "log_id_t must be an unsigned int");
+ "log_id_t must be an uint32_t");
+
+static_assert(std::is_same<std::underlying_type<android_LogPriority>::type, uint32_t>::value,
+ "log_id_t must be an uint32_t");
log_id_t android_name_to_log_id(const char* logName) {
const char* b;
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
index 0dbb94f..a8620a0 100644
--- a/liblog/logger_write.cpp
+++ b/liblog/logger_write.cpp
@@ -149,12 +149,12 @@
GetDefaultTag().assign(tag, 0, LOGGER_ENTRY_MAX_PAYLOAD);
}
-static std::atomic_int minimum_log_priority = ANDROID_LOG_DEFAULT;
-int __android_log_set_minimum_priority(int priority) {
+static std::atomic_int32_t minimum_log_priority = ANDROID_LOG_DEFAULT;
+int32_t __android_log_set_minimum_priority(int32_t priority) {
return minimum_log_priority.exchange(priority, std::memory_order_relaxed);
}
-int __android_log_get_minimum_priority() {
+int32_t __android_log_get_minimum_priority() {
return minimum_log_priority;
}
@@ -267,7 +267,7 @@
static const char log_characters[] = "XXVDIWEF";
static_assert(arraysize(log_characters) - 1 == ANDROID_LOG_SILENT,
"Mismatch in size of log_characters and values in android_LogPriority");
- int priority =
+ int32_t priority =
logger_data->priority > ANDROID_LOG_SILENT ? ANDROID_LOG_FATAL : logger_data->priority;
char priority_char = log_characters[priority];
uint64_t tid = GetThreadId();
diff --git a/libpixelflinger/Android.bp b/libpixelflinger/Android.bp
index 76d9444..45a32da 100644
--- a/libpixelflinger/Android.bp
+++ b/libpixelflinger/Android.bp
@@ -93,23 +93,5 @@
"arch-arm64/t32cb16blend.S",
],
},
- mips: {
- mips32r6: {
- srcs: [
- "codeflinger/MIPSAssembler.cpp",
- "codeflinger/mips_disassem.c",
- "arch-mips/t32cb16blend.S",
- ],
- },
- },
- mips64: {
- srcs: [
- "codeflinger/MIPSAssembler.cpp",
- "codeflinger/MIPS64Assembler.cpp",
- "codeflinger/mips64_disassem.c",
- "arch-mips64/col32cb16blend.S",
- "arch-mips64/t32cb16blend.S",
- ],
- },
},
}
diff --git a/libpixelflinger/arch-mips/col32cb16blend.S b/libpixelflinger/arch-mips/col32cb16blend.S
deleted file mode 100644
index 810294c..0000000
--- a/libpixelflinger/arch-mips/col32cb16blend.S
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
-** Copyright 2015, 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.
-*/
-
- .macro pixel dreg src f sR sG sB shift
-
-#if __mips==32 && __mips_isa_rev>=2
- /* extract red */
- ext $t4,\src,\shift+11,5
- mul $t4,$t4,\f
-
- /* extract green */
- ext $t5,\src,\shift+5,6
- mul $t5,$t5,\f
-
- /* extract blue */
- ext $t6,\src,\shift,5
- mul $t6,$t6,\f
-#else
- /* extract red */
- srl $t4,\src,\shift+11
- andi $t4, 0x1f
- mul $t4,$t4,\f
-
- /* extract green */
- srl $t5,\src,\shift+5
- andi $t5, 0x3f
- mul $t5,$t5,\f
-
- /* extract blue */
- srl $t6,\src,\shift
- andi $t6, 0x1f
- mul $t6,$t6,\f
-#endif
-
- srl $t4,$t4,8
- srl $t5,$t5,8
- srl $t6,$t6,8
- addu $t4,$t4,\sR
- addu $t5,$t5,\sG
- addu \dreg,$t6,\sB
- sll $t4,$t4,11
- sll $t5,$t5,5
- or \dreg,\dreg,$t4
- or \dreg,\dreg,$t5
- andi \dreg, 0xffff
- .endm
-
- .text
- .balign 4
-
- .global scanline_col32cb16blend_mips
- .ent scanline_col32cb16blend_mips
-scanline_col32cb16blend_mips:
-
- /* check if count is zero */
- srl $v0,$a1,24 /* sA */
- beqz $a2,done
- li $t4, 0x100
- srl $v1,$v0,7
- addu $v0,$v1,$v0
- subu $v0,$t4,$v0 /* f */
-#if __mips==32 && __mips_isa_rev>=2
- ext $a3,$a1,3,5 /* sR */
- ext $t0,$a1,10,6 /* sG */
- ext $t1,$a1,19,5 /* sB */
-#else
- srl $a3, $a1, 3
- andi $a3, 0x1f /* sR */
- srl $t0, $a1, 10
- andi $t0, 0x3f /* sG */
- srl $t1, $a1, 19
- andi $t1, 0x1f /* sB */
-#endif
-
- /* check if cnt is at least 4 */
- addiu $a2,$a2,-4
- bltz $a2,tail
-
-loop_4pixels:
- lw $t7,0($a0)
- lw $t8,4($a0)
- addiu $a0,$a0,8
- addiu $a2,$a2,-4
- pixel $t2 $t7 $v0 $a3 $t0 $t1 0
- pixel $t3 $t7 $v0 $a3 $t0 $t1 16
-#if __mips==32 && __mips_isa_rev>=2
- ins $t2,$t3,16,16
-#else
- sll $t3, 16
- or $t2, $t2, $t3
-#endif
- pixel $t7 $t8 $v0 $a3 $t0 $t1 0
- pixel $t3 $t8 $v0 $a3 $t0 $t1 16
-#if __mips==32 && __mips_isa_rev>=2
- ins $t7,$t3,16,16
-#else
- sll $t3, 16
- or $t7, $t7, $t3
-#endif
- sw $t2,-8($a0)
- sw $t7,-4($a0)
- bgez $a2, loop_4pixels
-
-tail:
- /* the pixel count underran, restore it now */
- addiu $a2,$a2,4
-
- /* handle the last 0..3 pixels */
- beqz $a2,done
-
-loop_1pixel:
- lhu $t7,0($a0)
- addiu $a0,$a0,2
- addiu $a2,$a2,-1
- pixel $t2 $t7 $v0 $a3 $t0 $t1 0
- sh $t2, -2($a0)
- bnez $a2,loop_1pixel
-
-done:
- j $ra
- .end scanline_col32cb16blend_mips
diff --git a/libpixelflinger/arch-mips/t32cb16blend.S b/libpixelflinger/arch-mips/t32cb16blend.S
deleted file mode 100644
index 1d2fb8f..0000000
--- a/libpixelflinger/arch-mips/t32cb16blend.S
+++ /dev/null
@@ -1,273 +0,0 @@
-/* libs/pixelflinger/t32cb16blend.S
-**
-** Copyright 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.
-*/
-
-#ifdef DEBUG
-#define DBG
-#else
-#define DBG #
-#endif
-
-/*
- * blend one of 2 16bpp RGB pixels held in dreg selected by shift
- * with the 32bpp ABGR pixel held in src and store the result in fb
- *
- * Assumes that the dreg data is little endian and that
- * the the second pixel (shift==16) will be merged into
- * the fb result
- *
- * Uses $t0,$t6,$t7,$t8
- */
-
-#if __mips==32 && __mips_isa_rev>=2
- .macro pixel dreg src fb shift
- /*
- * sA = s >> 24
- * f = 0x100 - (sA + (sA>>7))
- */
-DBG .set noat
-DBG rdhwr $at,$2
-DBG .set at
-
- srl $t7,\src,24
- srl $t6,$t7,7
- addu $t7,$t6
- li $t6,0x100
- subu $t7,$t6,$t7
-
- /* red */
- ext $t8,\dreg,\shift+6+5,5 # dst[\shift:15..11]
- mul $t6,$t8,$t7
- ext $t0,\dreg,\shift+5,6 # start green extraction dst[\shift:10..5]
- ext $t8,\src,3,5 # src[7..3]
- srl $t6,8
- addu $t8,$t6
-.if \shift!=0
- sll $t8,\shift+11
- or \fb,$t8
-.else
- sll \fb,$t8,11
-.endif
-
- /* green */
- mul $t8,$t0,$t7
- ext $t0,\dreg,\shift,5 # start blue extraction dst[\shift:4..0]
- ext $t6,\src,2+8,6 # src[15..10]
- srl $t8,8
- addu $t8,$t6
-
- /* blue */
- mul $t0,$t0,$t7
- sll $t8, $t8, \shift+5
- or \fb, \fb, $t8
- ext $t6,\src,(3+8+8),5
- srl $t8,$t0,8
- addu $t8,$t6
- sll $t8, $t8, \shift
- or \fb, \fb, $t8
-
-DBG .set noat
-DBG rdhwr $t8,$2
-DBG subu $t8,$at
-DBG sltu $at,$t8,$v0
-DBG movn $v0,$t8,$at
-DBG sgtu $at,$t8,$v1
-DBG movn $v1,$t8,$at
-DBG .set at
- .endm
-
-#else
-
- .macro pixel dreg src fb shift
- /*
- * sA = s >> 24
- * f = 0x100 - (sA + (sA>>7))
- */
-DBG .set push
-DBG .set noat
-DBG .set mips32r2
-DBG rdhwr $at,$2
-DBG .set pop
-
- srl $t7,\src,24
- srl $t6,$t7,7
- addu $t7,$t6
- li $t6,0x100
- subu $t7,$t6,$t7
-
- /*
- * red
- * dR = (d >> (6 + 5)) & 0x1f;
- * dR = (f*dR)>>8
- * sR = (s >> ( 3)) & 0x1f;
- * sR += dR
- * fb |= sR << 11
- */
- srl $t8,\dreg,\shift+6+5
-.if \shift==0
- and $t8,0x1f
-.endif
- mul $t8,$t8,$t7
- srl $t6,\src,3
- and $t6,0x1f
- srl $t8,8
- addu $t8,$t6
-.if \shift!=0
- sll $t8,\shift+11
- or \fb,$t8
-.else
- sll \fb,$t8,11
-.endif
-
- /*
- * green
- * dG = (d >> 5) & 0x3f
- * dG = (f*dG) >> 8
- * sG = (s >> ( 8+2))&0x3F;
- */
- srl $t8,\dreg,\shift+5
- and $t8,0x3f
- mul $t8,$t8,$t7
- srl $t6,\src,8+2
- and $t6,0x3f
- srl $t8,8
- addu $t8,$t6
- sll $t8,\shift + 5
- or \fb,$t8
-
- /* blue */
-.if \shift!=0
- srl $t8,\dreg,\shift
- and $t8,0x1f
-.else
- and $t8,\dreg,0x1f
-.endif
- mul $t8,$t8,$t7
- srl $t6,\src,(8+8+3)
- and $t6,0x1f
- srl $t8,8
- addu $t8,$t6
-.if \shift!=0
- sll $t8,\shift
-.endif
- or \fb,$t8
-DBG .set push
-DBG .set noat
-DBG .set mips32r2
-DBG rdhwr $t8,$2
-DBG subu $t8,$at
-DBG sltu $at,$t8,$v0
-DBG movn $v0,$t8,$at
-DBG sgtu $at,$t8,$v1
-DBG movn $v1,$t8,$at
-DBG .set pop
- .endm
-#endif
-
- .text
- .balign 4
-
- .global scanline_t32cb16blend_mips
- .ent scanline_t32cb16blend_mips
-scanline_t32cb16blend_mips:
-DBG li $v0,0xffffffff
-DBG li $v1,0
- /* Align the destination if necessary */
- and $t0,$a0,3
- beqz $t0,aligned
-
- /* as long as there is at least one pixel */
- beqz $a2,done
-
- lw $t4,($a1)
- addu $a0,2
- addu $a1,4
- beqz $t4,1f
- lhu $t3,-2($a0)
- pixel $t3,$t4,$t1,0
- sh $t1,-2($a0)
-1: subu $a2,1
-
-aligned:
- /* Check to see if its worth unrolling the loop */
- subu $a2,4
- bltz $a2,tail
-
- /* Process 4 pixels at a time */
-fourpixels:
- /* 1st pair of pixels */
- lw $t4,0($a1)
- lw $t5,4($a1)
- addu $a0,8
- addu $a1,16
-
- /* both are zero, skip this pair */
- or $t3,$t4,$t5
- beqz $t3,1f
-
- /* load the destination */
- lw $t3,-8($a0)
-
- pixel $t3,$t4,$t1,0
- andi $t1, 0xFFFF
- pixel $t3,$t5,$t1,16
- sw $t1,-8($a0)
-
-1:
- /* 2nd pair of pixels */
- lw $t4,-8($a1)
- lw $t5,-4($a1)
-
- /* both are zero, skip this pair */
- or $t3,$t4,$t5
- beqz $t3,1f
-
- /* load the destination */
- lw $t3,-4($a0)
-
- pixel $t3,$t4,$t1,0
- andi $t1, 0xFFFF
- pixel $t3,$t5,$t1,16
- sw $t1,-4($a0)
-
-1: subu $a2,4
- bgtz $a2,fourpixels
-
-tail:
- /* the pixel count underran, restore it now */
- addu $a2,4
-
- /* handle the last 0..3 pixels */
- beqz $a2,done
-onepixel:
- lw $t4,($a1)
- addu $a0,2
- addu $a1,4
- beqz $t4,1f
- lhu $t3,-2($a0)
- pixel $t3,$t4,$t1,0
- sh $t1,-2($a0)
-1: subu $a2,1
- bnez $a2,onepixel
-done:
-DBG .set push
-DBG .set mips32r2
-DBG rdhwr $a0,$3
-DBG mul $v0,$a0
-DBG mul $v1,$a0
-DBG .set pop
- j $ra
- .end scanline_t32cb16blend_mips
diff --git a/libpixelflinger/arch-mips64/col32cb16blend.S b/libpixelflinger/arch-mips64/col32cb16blend.S
deleted file mode 100644
index 5baffb1..0000000
--- a/libpixelflinger/arch-mips64/col32cb16blend.S
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
-** Copyright 2015, 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.
-*/
-
- .macro pixel dreg src f sR sG sB shift
-
- /* extract red */
-.if \shift < 32
- dext $t0,\src,\shift+11,5
-.else
- dextu $t0,\src,\shift+11,5
-.endif
- mul $t0,$t0,\f
-
- /* extract green */
-.if \shift < 32
- dext $t1,\src,\shift+5,6
-.else
- dextu $t1,\src,\shift+5,6
-.endif
- mul $t1,$t1,\f
-
- /* extract blue */
-.if \shift < 32
- dext $t2,\src,\shift,5
-.else
- dextu $t2,\src,\shift,5
-.endif
- mul $t2,$t2,\f
-
- srl $t0,$t0,8
- srl $t1,$t1,8
- srl $t2,$t2,8
- addu $t0,$t0,\sR
- addu $t1,$t1,\sG
- addu \dreg,$t2,\sB
- sll $t0,$t0,11
- sll $t1,$t1,5
- or \dreg,\dreg,$t0
- or \dreg,\dreg,$t1
- .endm
-
- .text
- .balign 4
-
- .global scanline_col32cb16blend_mips64
- .ent scanline_col32cb16blend_mips64
-scanline_col32cb16blend_mips64:
-
- /* check if count is zero */
- srl $v0,$a1,24 /* sA */
- beqz $a2,done
- li $t0, 0x100
- srl $v1,$v0,7
- addu $v0,$v1,$v0
- subu $v0,$t0,$v0 /* f */
- ext $a3,$a1,3,5 /* sR */
- ext $a4,$a1,10,6 /* sG */
- ext $a5,$a1,19,5 /* sB */
-
- /* check if cnt is at least 4 */
- addiu $a2,$a2,-4
- bltz $a2,tail
-
-loop_4pixels:
- ld $t3,0($a0)
- daddiu $a0,$a0,8
- addiu $a2,$a2,-4
- pixel $a6 $t3 $v0 $a3 $a4 $a5 0
- pixel $a7 $t3 $v0 $a3 $a4 $a5 16
- pixel $t8 $t3 $v0 $a3 $a4 $a5 32
- pixel $t9 $t3 $v0 $a3 $a4 $a5 48
- dins $a6,$a7,16,16
- dinsu $a6,$t8,32,16
- dinsu $a6,$t9,48,16
- sd $a6,-8($a0)
- bgez $a2, loop_4pixels
-
-tail:
- /* the pixel count underran, restore it now */
- addiu $a2,$a2,4
-
- /* handle the last 0..3 pixels */
- beqz $a2,done
-
-loop_1pixel:
- lhu $t3,0($a0)
- daddiu $a0,$a0,2
- addiu $a2,$a2,-1
- pixel $a6 $t3 $v0 $a3 $a4 $a5 0
- sh $a6, -2($a0)
- bnez $a2,loop_1pixel
-
-done:
- j $ra
- .end scanline_col32cb16blend_mips64
diff --git a/libpixelflinger/arch-mips64/t32cb16blend.S b/libpixelflinger/arch-mips64/t32cb16blend.S
deleted file mode 100644
index 3cb5f93..0000000
--- a/libpixelflinger/arch-mips64/t32cb16blend.S
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
-** Copyright 2015, 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.
-*/
-
-#ifdef DEBUG
-#define DBG
-#else
-#define DBG #
-#endif
-
-/*
- * blend one of 2 16bpp RGB pixels held in dreg selected by shift
- * with the 32bpp ABGR pixel held in src and store the result in fb
- *
- * Assumes that the dreg data is little endian and that
- * the the second pixel (shift==16) will be merged into
- * the fb result
- *
- * Uses $a4,$t2,$t3,$t8
- */
-
- .macro pixel dreg src fb shift
- /*
- * sA = s >> 24
- * f = 0x100 - (sA + (sA>>7))
- */
- srl $t3,\src,24
- srl $t2,$t3,7
- addu $t3,$t2
- li $t2,0x100
- subu $t3,$t2,$t3
-
- /* red */
- ext $t8,\dreg,\shift+6+5,5 # dst[\shift:15..11]
- mul $t2,$t8,$t3
- ext $a4,\dreg,\shift+5,6 # start green extraction dst[\shift:10..5]
- ext $t8,\src,3,5 # src[7..3]
- srl $t2,8
- addu $t8,$t2
-.if \shift!=0
- sll $t8,\shift+11 # dst[\shift:15..11]
- or \fb,$t8
-.else
- sll \fb,$t8,11
-.endif
-
- /* green */
- mul $t8,$a4,$t3
- ext $a4,\dreg,\shift,5 # start blue extraction dst[\shift:4..0]
- ext $t2,\src,2+8,6 # src[15..10]
- srl $t8,8
- addu $t8,$t2
-
- /* blue */
- mul $a4,$a4,$t3
- sll $t8, $t8, \shift+5 # finish green insertion dst[\shift:10..5]
- or \fb, \fb, $t8
- ext $t2,\src,(3+8+8),5
- srl $t8,$a4,8
- addu $t8,$t2
- sll $t8, $t8, \shift
- or \fb, \fb, $t8
- .endm
-
- .text
- .balign 4
-
- .global scanline_t32cb16blend_mips64
- .ent scanline_t32cb16blend_mips64
-scanline_t32cb16blend_mips64:
- daddiu $sp, $sp, -40
-DBG li $v0,0xffffffff
-DBG li $v1,0
- /* Align the destination if necessary */
- and $a4,$a0,3
- beqz $a4,aligned
-
- /* as long as there is at least one pixel */
- beqz $a2,done
-
- lw $t0,($a1)
- daddu $a0,2
- daddu $a1,4
- beqz $t0,1f
- lhu $a7,-2($a0)
- pixel $a7,$t0,$a5,0
- sh $a5,-2($a0)
-1: subu $a2,1
-
-aligned:
- /* Check to see if its worth unrolling the loop */
- subu $a2,4
- bltz $a2,tail
-
- /* Process 4 pixels at a time */
-fourpixels:
- /* 1st pair of pixels */
- lw $t0,0($a1)
- lw $t1,4($a1)
- daddu $a0,8
- daddu $a1,16
-
- /* both are zero, skip this pair */
- or $a7,$t0,$t1
- beqz $a7,1f
-
- /* load the destination */
- lw $a7,-8($a0)
-
- pixel $a7,$t0,$a5,0
- andi $a5, 0xFFFF
- pixel $a7,$t1,$a5,16
- sw $a5,-8($a0)
-
-1:
- /* 2nd pair of pixels */
- lw $t0,-8($a1)
- lw $t1,-4($a1)
-
- /* both are zero, skip this pair */
- or $a7,$t0,$t1
- beqz $a7,1f
-
- /* load the destination */
- lw $a7,-4($a0)
-
- pixel $a7,$t0,$a5,0
- andi $a5, 0xFFFF
- pixel $a7,$t1,$a5,16
- sw $a5,-4($a0)
-
-1: subu $a2,4
- bgtz $a2,fourpixels
-
-tail:
- /* the pixel count underran, restore it now */
- addu $a2,4
-
- /* handle the last 0..3 pixels */
- beqz $a2,done
-onepixel:
- lw $t0,($a1)
- daddu $a0,2
- daddu $a1,4
- beqz $t0,1f
- lhu $a7,-2($a0)
- pixel $a7,$t0,$a5,0
- sh $a5,-2($a0)
-1: subu $a2,1
- bnez $a2,onepixel
-done:
-DBG .set push
-DBG .set mips32r2
-DBG rdhwr $a0,$3
-DBG mul $v0,$a0
-DBG mul $v1,$a0
-DBG .set pop
- daddiu $sp, $sp, 40
- j $ra
- .end scanline_t32cb16blend_mips64
diff --git a/libpixelflinger/tests/arch-mips/Android.bp b/libpixelflinger/tests/arch-mips/Android.bp
deleted file mode 100644
index 2ca2721..0000000
--- a/libpixelflinger/tests/arch-mips/Android.bp
+++ /dev/null
@@ -1,11 +0,0 @@
-cc_defaults {
- name: "pixelflinger-tests-mips",
- defaults: ["pixelflinger-tests"],
-
- enabled: false,
- arch: {
- mips: {
- enabled: true,
- },
- },
-}
diff --git a/libpixelflinger/tests/arch-mips/col32cb16blend/Android.bp b/libpixelflinger/tests/arch-mips/col32cb16blend/Android.bp
deleted file mode 100644
index 45bfe29..0000000
--- a/libpixelflinger/tests/arch-mips/col32cb16blend/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-cc_test {
- name: "test-pixelflinger-mips-col32cb16blend",
- defaults: ["pixelflinger-tests-mips"],
-
- srcs: ["col32cb16blend_test.c"],
-}
diff --git a/libpixelflinger/tests/arch-mips/col32cb16blend/col32cb16blend_test.c b/libpixelflinger/tests/arch-mips/col32cb16blend/col32cb16blend_test.c
deleted file mode 100644
index dd0e60f..0000000
--- a/libpixelflinger/tests/arch-mips/col32cb16blend/col32cb16blend_test.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <assert.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-
-
-#define ARGB_8888_MAX 0xFFFFFFFF
-#define ARGB_8888_MIN 0x00000000
-#define RGB_565_MAX 0xFFFF
-#define RGB_565_MIN 0x0000
-
-struct test_t
-{
- char name[256];
- uint32_t src_color;
- uint16_t dst_color;
- size_t count;
-};
-
-struct test_t tests[] =
-{
- {"Count 1, Src=Max, Dst=Min", ARGB_8888_MAX, RGB_565_MIN, 1},
- {"Count 2, Src=Min, Dst=Max", ARGB_8888_MIN, RGB_565_MAX, 2},
- {"Count 3, Src=Max, Dst=Max", ARGB_8888_MAX, RGB_565_MAX, 3},
- {"Count 4, Src=Min, Dst=Min", ARGB_8888_MAX, RGB_565_MAX, 4},
- {"Count 1, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 1},
- {"Count 2, Src=Rand, Dst=Rand", 0xABCDEF12, 0x2345, 2},
- {"Count 3, Src=Rand, Dst=Rand", 0x11111111, 0xEDFE, 3},
- {"Count 4, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 4},
- {"Count 5, Src=Rand, Dst=Rand", 0xEFEFFEFE, 0xFACC, 5},
- {"Count 10, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 10}
-};
-
-void scanline_col32cb16blend_mips(uint16_t *dst, uint32_t src, size_t count);
-void scanline_col32cb16blend_c(uint16_t * dst, uint32_t src, size_t count)
-{
- uint32_t srcAlpha = (src>>24);
- uint32_t f = 0x100 - (srcAlpha + (srcAlpha>>7));
-
- while (count--)
- {
- uint16_t d = *dst;
- int dstR = (d>>11)&0x1f;
- int dstG = (d>>5)&0x3f;
- int dstB = (d)&0x1f;
- int srcR = (src >> ( 3))&0x1F;
- int srcG = (src >> ( 8+2))&0x3F;
- int srcB = (src >> (16+3))&0x1F;
- srcR += (f*dstR)>>8;
- srcG += (f*dstG)>>8;
- srcB += (f*dstB)>>8;
- *dst++ = (uint16_t)((srcR<<11)|(srcG<<5)|srcB);
- }
-}
-
-void scanline_col32cb16blend_test()
-{
- uint16_t dst_c[16], dst_asm[16];
- uint32_t i, j;
-
- for(i = 0; i < sizeof(tests)/sizeof(struct test_t); ++i)
- {
- struct test_t test = tests[i];
-
- printf("Testing - %s:",test.name);
-
- memset(dst_c, 0, sizeof(dst_c));
- memset(dst_asm, 0, sizeof(dst_asm));
-
- for(j = 0; j < test.count; ++j)
- {
- dst_c[j] = test.dst_color;
- dst_asm[j] = test.dst_color;
- }
-
-
- scanline_col32cb16blend_c(dst_c, test.src_color, test.count);
- scanline_col32cb16blend_mips(dst_asm, test.src_color, test.count);
-
- if(memcmp(dst_c, dst_asm, sizeof(dst_c)) == 0)
- printf("Passed\n");
- else
- printf("Failed\n");
-
- for(j = 0; j < test.count; ++j)
- {
- printf("dst_c[%d] = %x, dst_asm[%d] = %x \n", j, dst_c[j], j, dst_asm[j]);
- }
- }
-}
-
-int main()
-{
- scanline_col32cb16blend_test();
- return 0;
-}
diff --git a/libpixelflinger/tests/arch-mips/t32cb16blend/Android.bp b/libpixelflinger/tests/arch-mips/t32cb16blend/Android.bp
deleted file mode 100644
index 069e97c..0000000
--- a/libpixelflinger/tests/arch-mips/t32cb16blend/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-cc_test {
- name: "test-pixelflinger-mips-t32cb16blend",
- defaults: ["pixelflinger-tests-mips"],
-
- srcs: ["t32cb16blend_test.c"],
-}
diff --git a/libpixelflinger/tests/arch-mips/t32cb16blend/t32cb16blend_test.c b/libpixelflinger/tests/arch-mips/t32cb16blend/t32cb16blend_test.c
deleted file mode 100644
index c6d6937..0000000
--- a/libpixelflinger/tests/arch-mips/t32cb16blend/t32cb16blend_test.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <assert.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-
-#define ARGB_8888_MAX 0xFFFFFFFF
-#define ARGB_8888_MIN 0x00000000
-#define RGB_565_MAX 0xFFFF
-#define RGB_565_MIN 0x0000
-
-struct test_t
-{
- char name[256];
- uint32_t src_color;
- uint16_t dst_color;
- size_t count;
-};
-
-struct test_t tests[] =
-{
- {"Count 0", 0, 0, 0},
- {"Count 1, Src=Max, Dst=Min", ARGB_8888_MAX, RGB_565_MIN, 1},
- {"Count 2, Src=Min, Dst=Max", ARGB_8888_MIN, RGB_565_MAX, 2},
- {"Count 3, Src=Max, Dst=Max", ARGB_8888_MAX, RGB_565_MAX, 3},
- {"Count 4, Src=Min, Dst=Min", ARGB_8888_MAX, RGB_565_MAX, 4},
- {"Count 1, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 1},
- {"Count 2, Src=Rand, Dst=Rand", 0xABCDEF12, 0x2345, 2},
- {"Count 3, Src=Rand, Dst=Rand", 0x11111111, 0xEDFE, 3},
- {"Count 4, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 4},
- {"Count 5, Src=Rand, Dst=Rand", 0xEFEFFEFE, 0xFACC, 5},
- {"Count 10, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 10}
-
-};
-
-void scanline_t32cb16blend_mips(uint16_t*, uint32_t*, size_t);
-void scanline_t32cb16blend_c(uint16_t * dst, uint32_t* src, size_t count)
-{
- while (count--)
- {
- uint16_t d = *dst;
- uint32_t s = *src++;
- int dstR = (d>>11)&0x1f;
- int dstG = (d>>5)&0x3f;
- int dstB = (d)&0x1f;
- int srcR = (s >> ( 3))&0x1F;
- int srcG = (s >> ( 8+2))&0x3F;
- int srcB = (s >> (16+3))&0x1F;
- int srcAlpha = (s>>24) & 0xFF;
-
-
- int f = 0x100 - (srcAlpha + ((srcAlpha>>7) & 0x1));
- srcR += (f*dstR)>>8;
- srcG += (f*dstG)>>8;
- srcB += (f*dstB)>>8;
- // srcR = srcR > 0x1F? 0x1F: srcR;
- // srcG = srcG > 0x3F? 0x3F: srcG;
- // srcB = srcB > 0x1F? 0x1F: srcB;
- *dst++ = (uint16_t)((srcR<<11)|(srcG<<5)|srcB);
- }
-}
-
-void scanline_t32cb16blend_test()
-{
- uint16_t dst_c[16], dst_asm[16];
- uint32_t src[16];
- uint32_t i;
- uint32_t j;
-
- for(i = 0; i < sizeof(tests)/sizeof(struct test_t); ++i)
- {
- struct test_t test = tests[i];
-
- printf("Testing - %s:",test.name);
-
- memset(dst_c, 0, sizeof(dst_c));
- memset(dst_asm, 0, sizeof(dst_asm));
-
- for(j = 0; j < test.count; ++j)
- {
- dst_c[j] = test.dst_color;
- dst_asm[j] = test.dst_color;
- src[j] = test.src_color;
- }
-
- scanline_t32cb16blend_c(dst_c,src,test.count);
- scanline_t32cb16blend_mips(dst_asm,src,test.count);
-
-
- if(memcmp(dst_c, dst_asm, sizeof(dst_c)) == 0)
- printf("Passed\n");
- else
- printf("Failed\n");
-
- for(j = 0; j < test.count; ++j)
- {
- printf("dst_c[%d] = %x, dst_asm[%d] = %x \n", j, dst_c[j], j, dst_asm[j]);
- }
- }
-}
-
-int main()
-{
- scanline_t32cb16blend_test();
- return 0;
-}
diff --git a/libpixelflinger/tests/arch-mips64/Android.bp b/libpixelflinger/tests/arch-mips64/Android.bp
deleted file mode 100644
index ba55d62..0000000
--- a/libpixelflinger/tests/arch-mips64/Android.bp
+++ /dev/null
@@ -1,11 +0,0 @@
-cc_defaults {
- name: "pixelflinger-tests-mips64",
- defaults: ["pixelflinger-tests"],
-
- enabled: false,
- arch: {
- mips64: {
- enabled: true,
- },
- },
-}
diff --git a/libpixelflinger/tests/arch-mips64/assembler/Android.bp b/libpixelflinger/tests/arch-mips64/assembler/Android.bp
deleted file mode 100644
index b672053..0000000
--- a/libpixelflinger/tests/arch-mips64/assembler/Android.bp
+++ /dev/null
@@ -1,9 +0,0 @@
-cc_test {
- name: "test-pixelflinger-mips64-assembler-test",
- defaults: ["pixelflinger-tests-mips64"],
-
- srcs: [
- "mips64_assembler_test.cpp",
- "asm_mips_test_jacket.S",
- ],
-}
diff --git a/libpixelflinger/tests/arch-mips64/assembler/asm_mips_test_jacket.S b/libpixelflinger/tests/arch-mips64/assembler/asm_mips_test_jacket.S
deleted file mode 100644
index 705ee9b..0000000
--- a/libpixelflinger/tests/arch-mips64/assembler/asm_mips_test_jacket.S
+++ /dev/null
@@ -1,93 +0,0 @@
-# /*
-# * Copyright (C) 2015 The Android Open Source Project
-# * All rights reserved.
-# *
-# * Redistribution and use in source and binary forms, with or without
-# * modification, are permitted provided that the following conditions
-# * are met:
-# * * Redistributions of source code must retain the above copyright
-# * notice, this list of conditions and the following disclaimer.
-# * * Redistributions in binary form must reproduce the above copyright
-# * notice, this list of conditions and the following disclaimer in
-# * the documentation and/or other materials provided with the
-# * distribution.
-# *
-# * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-# * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-# * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-# * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-# * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
-# * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
-# * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-# * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-# * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-# * SUCH DAMAGE.
-# */
-
- .text
- .balign 8
-
- .global asm_mips_test_jacket
-
- # // Set the register
- # // Calls the asm function
- # // Reads the register values to output register
-
- # // Parameters
- # // a0 - Function to jump
- # // a1 - register values array
- # // a2 - flag values array
-asm_mips_test_jacket:
- # // Save registers to stack
- daddiu $sp, $sp, -96
- sd $s0, 64($sp)
- sd $s1, 72($sp)
- sd $s2, 80($sp)
- sd $ra, 88($sp)
-
- move $s0, $a0
- move $s1, $a1
- move $s2, $a2
-
- ld $v0, 16($s1)
- ld $v1, 24($s1)
- ld $a0, 32($s1)
- ld $a1, 40($s1)
- ld $a2, 48($s1)
- ld $a3, 56($s1)
- ld $a4, 64($s1)
- ld $a5, 72($s1)
- ld $a6, 80($s1)
- ld $a7, 88($s1)
- ld $t0, 96($s1)
- ld $t1, 104($s1)
- ld $t2, 112($s1)
- ld $t3, 120($s1)
-
- jal $s0
-
- sd $v0, 16($s1)
- sd $v1, 24($s1)
- sd $a0, 32($s1)
- sd $a1, 40($s1)
- sd $a2, 48($s1)
- sd $a3, 56($s1)
- sd $a4, 64($s1)
- sd $a5, 72($s1)
- sd $a6, 80($s1)
- sd $a7, 88($s1)
- sd $t0, 96($s1)
- sd $t1, 104($s1)
- sd $t2, 112($s1)
- sd $t3, 120($s1)
-
- ld $s0, 64($sp)
- ld $s1, 72($sp)
- ld $s2, 80($sp)
- ld $ra, 88($sp)
-
- daddiu $sp, $sp, 96
-
- j $ra
diff --git a/libpixelflinger/tests/arch-mips64/assembler/mips64_assembler_test.cpp b/libpixelflinger/tests/arch-mips64/assembler/mips64_assembler_test.cpp
deleted file mode 100644
index 9fb0a28..0000000
--- a/libpixelflinger/tests/arch-mips64/assembler/mips64_assembler_test.cpp
+++ /dev/null
@@ -1,643 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <errno.h>
-#define __STDC_FORMAT_MACROS
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-#include <android/log.h>
-#include <cutils/ashmem.h>
-
-#include "codeflinger/ARMAssemblerInterface.h"
-#include "codeflinger/MIPS64Assembler.h"
-
-using namespace android;
-
-#define TESTS_DATAOP_ENABLE 1
-#define TESTS_DATATRANSFER_ENABLE 1
-#define ASSEMBLY_SCRATCH_SIZE 4096
-
-void *instrMem;
-uint32_t instrMemSize = 128 * 1024;
-char dataMem[8192];
-
-typedef void (*asm_function_t)();
-extern "C" void asm_mips_test_jacket(asm_function_t function,
- int64_t regs[], int32_t flags[]);
-
-#define MAX_32BIT (uint32_t)(((uint64_t)1 << 32) - 1)
-#define MAX_64BIT ((uint64_t)0xFFFFFFFFFFFFFFFF)
-const uint32_t NA = 0;
-const uint32_t NUM_REGS = 32;
-const uint32_t NUM_FLAGS = 16;
-
-enum instr_t
-{
- INSTR_ADD,
- INSTR_SUB,
- INSTR_AND,
- INSTR_ORR,
- INSTR_RSB,
- INSTR_BIC,
- INSTR_CMP,
- INSTR_MOV,
- INSTR_MVN,
- INSTR_MUL,
- INSTR_MLA,
- INSTR_SMULBB,
- INSTR_SMULBT,
- INSTR_SMULTB,
- INSTR_SMULTT,
- INSTR_SMULWB,
- INSTR_SMULWT,
- INSTR_SMLABB,
- INSTR_UXTB16,
- INSTR_UBFX,
- INSTR_ADDR_ADD,
- INSTR_ADDR_SUB,
- INSTR_LDR,
- INSTR_LDRB,
- INSTR_LDRH,
- INSTR_ADDR_LDR,
- INSTR_LDM,
- INSTR_STR,
- INSTR_STRB,
- INSTR_STRH,
- INSTR_ADDR_STR,
- INSTR_STM
-};
-
-enum shift_t
-{
- SHIFT_LSL,
- SHIFT_LSR,
- SHIFT_ASR,
- SHIFT_ROR,
- SHIFT_NONE
-};
-
-enum offset_t
-{
- REG_SCALE_OFFSET,
- REG_OFFSET,
- IMM8_OFFSET,
- IMM12_OFFSET,
- NO_OFFSET
-};
-
-enum cond_t
-{
- EQ, NE, CS, CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV,
- HS = CS,
- LO = CC
-};
-
-const char * cc_code[] =
-{
- "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC",
- "HI", "LS","GE","LT", "GT", "LE", "AL", "NV"
-};
-
-struct condTest_t
-{
- int mode;
- int32_t Rcond1;
- int32_t Rcond2;
- uint64_t Rcond1Value;
- uint64_t Rcond2Value;
-};
-
-
-struct dataOpTest_t
-{
- uint32_t id;
- instr_t op;
- condTest_t preCond;
- cond_t cond;
- bool setFlags;
- uint64_t RnValue;
- uint64_t RsValue;
- bool immediate;
- uint32_t immValue;
- uint64_t RmValue;
- uint32_t shiftMode;
- uint32_t shiftAmount;
- uint64_t RdValue;
- bool checkRd;
- uint64_t postRdValue;
-};
-
-struct dataTransferTest_t
-{
- uint32_t id;
- instr_t op;
- uint32_t preFlag;
- cond_t cond;
- bool setMem;
- uint64_t memOffset;
- uint64_t memValue;
- uint64_t RnValue;
- offset_t offsetType;
- uint64_t RmValue;
- uint32_t immValue;
- bool writeBack;
- bool preIndex;
- bool postIndex;
- uint64_t RdValue;
- uint64_t postRdValue;
- uint64_t postRnValue;
- bool checkMem;
- uint64_t postMemOffset;
- uint32_t postMemLength;
- uint64_t postMemValue;
-};
-
-
-dataOpTest_t dataOpTests [] =
-{
- {0xA000,INSTR_ADD,{0,0,0,0,0},AL,0,1,NA,1,MAX_32BIT,NA,NA,NA,NA,1,0},
- {0xA001,INSTR_ADD,{0,0,0,0,0},AL,0,1,NA,1,MAX_32BIT-1,NA,NA,NA,NA,1,MAX_64BIT},
- {0xA002,INSTR_ADD,{0,0,0,0,0},AL,0,1,NA,0,NA,MAX_32BIT,NA,NA,NA,1,0},
- {0xA003,INSTR_ADD,{0,0,0,0,0},AL,0,1,NA,0,NA,MAX_32BIT-1,NA,NA,NA,1,MAX_64BIT},
- {0xA004,INSTR_ADD,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT,SHIFT_LSL, 0,NA,1,0},
- {0xA005,INSTR_ADD,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT,SHIFT_LSL,31,NA,1,0xFFFFFFFF80000001},
- {0xA006,INSTR_ADD,{0,0,0,0,0},AL,0,1,NA,0,0,3,SHIFT_LSR,1,NA,1,2},
- {0xA007,INSTR_ADD,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT,SHIFT_LSR,31,NA,1,2},
- {0xA008,INSTR_ADD,{0,0,0,0,0},AL,0,0,NA,0,0,3,SHIFT_ASR,1,NA,1,1},
- {0xA009,INSTR_ADD,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_64BIT,SHIFT_ASR,31,NA,1,0},
- {0xA010,INSTR_AND,{0,0,0,0,0},AL,0,1,NA,1,MAX_32BIT,0,0,0,NA,1,1},
- {0xA011,INSTR_AND,{0,0,0,0,0},AL,0,1,NA,1,MAX_32BIT-1,0,0,0,NA,1,0},
- {0xA012,INSTR_AND,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT,0,0,NA,1,1},
- {0xA013,INSTR_AND,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT-1,0,0,NA,1,0},
- {0xA014,INSTR_AND,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT,SHIFT_LSL,0,NA,1,1},
- {0xA015,INSTR_AND,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT,SHIFT_LSL,31,NA,1,0},
- {0xA016,INSTR_AND,{0,0,0,0,0},AL,0,1,NA,0,0,3,SHIFT_LSR,1,NA,1,1},
- {0xA017,INSTR_AND,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT,SHIFT_LSR,31,NA,1,1},
- {0xA018,INSTR_AND,{0,0,0,0,0},AL,0,0,NA,0,0,3,SHIFT_ASR,1,NA,1,0},
- {0xA019,INSTR_AND,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT,SHIFT_ASR,31,NA,1,1},
- {0xA020,INSTR_ORR,{0,0,0,0,0},AL,0,3,NA,1,MAX_32BIT,0,0,0,NA,1,MAX_64BIT},
- {0xA021,INSTR_ORR,{0,0,0,0,0},AL,0,2,NA,1,MAX_32BIT-1,0,0,0,NA,1,MAX_64BIT-1},
- {0xA022,INSTR_ORR,{0,0,0,0,0},AL,0,3,NA,0,0,MAX_32BIT,0,0,NA,1,MAX_64BIT},
- {0xA023,INSTR_ORR,{0,0,0,0,0},AL,0,2,NA,0,0,MAX_32BIT-1,0,0,NA,1,MAX_64BIT-1},
- {0xA024,INSTR_ORR,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT,SHIFT_LSL,0,NA,1,MAX_64BIT},
- {0xA025,INSTR_ORR,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT,SHIFT_LSL,31,NA,1,0xFFFFFFFF80000001},
- {0xA026,INSTR_ORR,{0,0,0,0,0},AL,0,1,NA,0,0,3,SHIFT_LSR,1,NA,1,1},
- {0xA027,INSTR_ORR,{0,0,0,0,0},AL,0,0,NA,0,0,MAX_32BIT,SHIFT_LSR,31,NA,1,1},
- {0xA028,INSTR_ORR,{0,0,0,0,0},AL,0,0,NA,0,0,3,SHIFT_ASR,1,NA,1,1},
- {0xA029,INSTR_ORR,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_64BIT,SHIFT_ASR,31,NA,1,MAX_64BIT},
- {0xA030,INSTR_CMP,{0,0,0,0,0},AL,1,0x10000,NA,1,0x10000,0,0,0,NA,0,0},
- {0xA031,INSTR_MUL,{0,0,0,0,0},AL,0,0,0x10000,0,0,0x10000,0,0,NA,1,0},
- {0xA032,INSTR_MUL,{0,0,0,0,0},AL,0,0,0x1000,0,0,0x10000,0,0,NA,1,0x10000000},
- {0xA033,INSTR_MUL,{0,0,0,0,0},AL,0,0,MAX_32BIT,0,0,1,0,0,NA,1,MAX_64BIT},
- {0xA034,INSTR_MLA,{0,0,0,0,0},AL,0,0x10000,0x10000,0,0,0x10000,0,0,NA,1,0x10000},
- {0xA035,INSTR_MLA,{0,0,0,0,0},AL,0,0x10000,0x1000,0,0,0x10000,0,0,NA,1,0x10010000},
- {0xA036,INSTR_SUB,{1,R_v1,R_a6,2,4},MI,0,2,NA,0,NA,1,NA,NA,2,1,1},
- {0xA037,INSTR_SUB,{2,R_v1,R_a6,2,0},MI,0,2,NA,0,NA,1,NA,NA,2,1,2},
- {0xA038,INSTR_SUB,{1,R_v1,R_a6,4,2},GE,0,2,NA,1,1,NA,NA,NA,2,1,1},
- {0xA039,INSTR_SUB,{1,R_a5,R_a6,2,7},GE,0,2,NA,1,1,NA,NA,NA,2,1,2},
- {0xA040,INSTR_SUB,{1,R_a5,R_a6,1,1},HS,0,2,NA,1,1,NA,NA,NA,2,1,1},
- {0xA041,INSTR_SUB,{1,R_a5,R_a6,0,1},HS,0,2,NA,1,1,NA,NA,NA,2,1,2},
- {0xA042,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,1,1<< 16,0,0,0,NA,1,UINT64_C(1) -(1<<16)},
- {0xA043,INSTR_SUB,{0,0,0,0,0},AL,0,MAX_32BIT,NA,1,1,0,0,0,NA,1,MAX_64BIT-1},
- {0xA044,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,1,1,0,0,0,NA,1,0},
- {0xA045,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,0,NA,1<<16,0,0,NA,1,UINT64_C(1) -(1<<16)},
- {0xA046,INSTR_SUB,{0,0,0,0,0},AL,0,MAX_32BIT,NA,0,NA,1,0,0,NA,1,MAX_64BIT-1},
- {0xA047,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,0,NA,1,0,0,NA,1,0},
- {0xA048,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,0,NA,1,SHIFT_LSL,16,NA,1,UINT64_C(1) -(1<<16)},
- {0xA049,INSTR_SUB,{0,0,0,0,0},AL,0,0x80000001,NA,0,NA,MAX_32BIT,SHIFT_LSL,31,NA,1,1},
- {0xA050,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,0,NA,3,SHIFT_LSR,1,NA,1,0},
- {0xA051,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,0,NA,MAX_32BIT,SHIFT_LSR,31,NA,1,0},
- {0xA052,INSTR_RSB,{1,R_a5,R_a6,4,1},GE,0,2,NA,1,0,NA,NA,NA,2,1,UINT64_C(-2)},
- {0xA053,INSTR_RSB,{1,R_a5,R_a6,UINT64_C(-1),1},GE,0,2,NA,1,0,NA,NA,NA,2,1,2},
- {0xA054,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,1,1<<16,NA,NA,NA,NA,1,(1<<16)-1},
- {0xA055,INSTR_RSB,{0,0,0,0,0},AL,0,MAX_32BIT,NA,1,1,NA,NA,NA,NA,1,UINT64_C(1)-MAX_64BIT},
- {0xA056,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,1,1,NA,NA,NA,NA,1,0},
- {0xA057,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,0,NA,1<<16,0,0,NA,1,(1<<16)-1},
- {0xA058,INSTR_RSB,{0,0,0,0,0},AL,0,MAX_32BIT,NA,0,NA,1,0,0,NA,1,UINT64_C(1)-MAX_64BIT},
- {0xA059,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,0,NA,1,0,0,NA,1,0},
- {0xA060,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,0,NA,1,SHIFT_LSL,16,NA,1,(1<<16)-1},
- {0xA061,INSTR_RSB,{0,0,0,0,0},AL,0,0x80000001,NA,0,NA,MAX_32BIT ,SHIFT_LSL,31,NA,1,UINT64_C(-1)},
- {0xA062,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,0,NA,3,SHIFT_LSR,1,NA,1,0},
- {0xA063,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,0,NA,MAX_32BIT,SHIFT_LSR,31,NA,1,0},
- {0xA064,INSTR_MOV,{0,0,0,0,0},AL,0,NA,NA,1,0x80000001,NA,NA,NA,NA,1,0xFFFFFFFF80000001},
- {0xA065,INSTR_MOV,{0,0,0,0,0},AL,0,NA,NA,0,0,0x80000001,0,0,NA,1,0xFFFFFFFF80000001},
- {0xA066,INSTR_MOV,{0,0,0,0,0},AL,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,1,NA,1,MAX_64BIT-1},
- {0xA067,INSTR_MOV,{0,0,0,0,0},AL,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,31,NA,1,0xFFFFFFFF80000000},
- {0xA068,INSTR_MOV,{0,0,0,0,0},AL,0,NA,NA,0,0,3,SHIFT_LSR,1,NA,1,1},
- {0xA069,INSTR_MOV,{0,0,0,0,0},AL,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSR,31,NA,1,1},
- {0xA070,INSTR_MOV,{0,0,0,0,0},AL,0,NA,NA,0,0,3,SHIFT_ASR,1,NA,1,1},
- {0xA071,INSTR_MOV,{0,0,0,0,0},AL,0,NA,NA,0,0,MAX_64BIT ,SHIFT_ASR,31,NA,1,MAX_64BIT},
- {0xA072,INSTR_MOV,{0,0,0,0,0},AL,0,NA,NA,0,0,3,SHIFT_ROR,1,NA,1,0xFFFFFFFF80000001},
- {0xA073,INSTR_MOV,{0,0,0,0,0},AL,0,NA,NA,0,0,0x80000001,SHIFT_ROR,31,NA,1,3},
- {0xA074,INSTR_MOV,{0,0,0,0,0},AL,1,NA,NA,0,0,MAX_64BIT -1,SHIFT_ASR,1,NA,1,MAX_64BIT},
- {0xA075,INSTR_MOV,{0,0,0,0,0},AL,1,NA,NA,0,0,3,SHIFT_ASR,1,NA,1,1},
- {0xA076,INSTR_MOV,{2,R_a5,R_a6,6,8},MI,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2},
- {0xA077,INSTR_MOV,{2,R_a5,R_a6,UINT64_C(-4),UINT64_C(-8)},MI,0,NA,NA,0,0,0x80000001,0,0,2,1,0xFFFFFFFF80000001},
- {0xA078,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),UINT64_C(-1)},LT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2},
- {0xA079,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),1},LT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0xFFFFFFFF80000001},
- {0xA080,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),UINT64_C(-5)},GE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,1,2,1,MAX_64BIT-1},
- {0xA081,INSTR_MOV,{1,R_a5,R_a6,5,5},GE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,31,2,1,0xFFFFFFFF80000000},
- {0xA082,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),1},GE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,31,2,1,2},
- {0xA083,INSTR_MOV,{1,R_a5,R_a6,4,1},LE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,1,2,1,2},
- {0xA084,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),UINT64_C(-1)},LE,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0xFFFFFFFF80000001},
- {0xA085,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),1},LE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,31,2,1,0xFFFFFFFF80000000},
- {0xA086,INSTR_MOV,{1,R_a5,R_a6,1,1},GT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2},
- {0xA087,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),UINT64_C(-3)},GT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0xFFFFFFFF80000001},
- {0xA088,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),0},GT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2},
- {0xA089,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),UINT64_C(-1)},GT,0,NA,NA,0,0,0x80000001,0,0,2,1,2},
- {0xA090,INSTR_MOV,{1,R_a5,R_a6,6,1},GT,0,NA,NA,0,0,0x80000001,0,0,2,1,0xFFFFFFFF80000001},
- {0xA091,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),1},GT,0,NA,NA,0,0,0x80000001,0,0,2,1,2},
- {0xA092,INSTR_MOV,{1,R_a5,R_a6,1,1},GT,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,1,2,1,2},
- {0xA093,INSTR_MOV,{1,R_a5,R_a6,4,1},GT,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,1,2,1,MAX_64BIT-1},
- {0xA094,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),1},GT,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,1,2,1,2},
- {0xA095,INSTR_MOV,{1,R_a5,R_a6,1,UINT64_C(-1)},HS,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2},
- {0xA096,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),1},HS,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0xFFFFFFFF80000001},
- {0xA097,INSTR_MVN,{1,R_a5,R_a6,1,4},HS,0,NA,NA,1,MAX_32BIT-1,NA,NA,NA,2,1,2},
- {0xA098,INSTR_MVN,{1,R_a5,R_a6,UINT64_C(-1),1},HS,0,NA,NA,1,MAX_32BIT-1,NA,NA,NA,2,1,1},
- {0xA099,INSTR_MVN,{0,0,0,0,0},AL,0,NA,NA,1,0,NA,NA,NA,2,1,MAX_64BIT},
- {0xA100,INSTR_MVN,{0,0,0,0,0},AL,0,NA,NA,0,NA,MAX_32BIT-1,NA,0,2,1,1},
- {0xA101,INSTR_MVN,{0,0,0,0,0},AL,0,NA,NA,0,NA,0x80000001,NA,0,2,1,0x7FFFFFFE},
- {0xA102,INSTR_BIC,{0,0,0,0,0},AL,0,1,NA,1,MAX_32BIT,NA,NA,NA,NA,1,0},
- {0xA103,INSTR_BIC,{0,0,0,0,0},AL,0,1,NA,1,MAX_32BIT-1,NA,NA,NA,NA,1,1},
- {0xA104,INSTR_BIC,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT,0,0,NA,1,0},
- {0xA105,INSTR_BIC,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT-1,0,0,NA,1,1},
- {0xA106,INSTR_BIC,{0,0,0,0,0},AL,0,0xF0,NA,0,0,3,SHIFT_ASR,1,NA,1,0xF0},
- {0xA107,INSTR_BIC,{0,0,0,0,0},AL,0,0xF0,NA,0,0,MAX_64BIT,SHIFT_ASR,31,NA,1,0},
- {0xA108,INSTR_SMULBB,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFABCDFFFF,0,NA,0xFFFFFFFFABCD0001,NA,NA,NA,1,0xFFFFFFFFFFFFFFFF},
- {0xA109,INSTR_SMULBB,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFABCD0001,0,NA,0xFFFFFFFFABCD0FFF,NA,NA,NA,1,0x00000FFF},
- {0xA110,INSTR_SMULBB,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFABCD0001,0,NA,0xFFFFFFFFABCDFFFF,NA,NA,NA,1,0xFFFFFFFFFFFFFFFF},
- {0xA111,INSTR_SMULBB,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFABCDFFFF,0,NA,0xFFFFFFFFABCDFFFF,NA,NA,NA,1,1},
- {0xA112,INSTR_SMULBT,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFFFFFABCD,0,NA,0xFFFFFFFFABCD0001,NA,NA,NA,1,0xFFFFFFFFFFFFFFFF},
- {0xA113,INSTR_SMULBT,{0,0,0,0,0},AL,0,NA,0x000000000001ABCD,0,NA,0xFFFFFFFFABCD0FFF,NA,NA,NA,1,0x00000FFF},
- {0xA114,INSTR_SMULBT,{0,0,0,0,0},AL,0,NA,0x000000000001ABCD,0,NA,0xFFFFFFFFABCDFFFF,NA,NA,NA,1,0xFFFFFFFFFFFFFFFF},
- {0xA115,INSTR_SMULBT,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFFFFFABCD,0,NA,0xFFFFFFFFABCDFFFF,NA,NA,NA,1,1},
- {0xA116,INSTR_SMULTB,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFABCDFFFF,0,NA,0x000000000001ABCD,NA,NA,NA,1,0xFFFFFFFFFFFFFFFF},
- {0xA117,INSTR_SMULTB,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFABCD0001,0,NA,0x000000000FFFABCD,NA,NA,NA,1,0x00000FFF},
- {0xA118,INSTR_SMULTB,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFABCD0001,0,NA,0xFFFFFFFFFFFFABCD,NA,NA,NA,1,0xFFFFFFFFFFFFFFFF},
- {0xA119,INSTR_SMULTB,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFABCDFFFF,0,NA,0xFFFFFFFFFFFFABCD,NA,NA,NA,1,1},
- {0xA120,INSTR_SMULTT,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFFFFFABCD,0,NA,0x000000000001ABCD,NA,NA,NA,1,0xFFFFFFFFFFFFFFFF},
- {0xA121,INSTR_SMULTT,{0,0,0,0,0},AL,0,NA,0x000000000001ABCD,0,NA,0x000000000FFFABCD,NA,NA,NA,1,0x00000FFF},
- {0xA122,INSTR_SMULTT,{0,0,0,0,0},AL,0,NA,0x000000000001ABCD,0,NA,0xFFFFFFFFFFFFABCD,NA,NA,NA,1,0xFFFFFFFFFFFFFFFF},
- {0xA123,INSTR_SMULTT,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFFFFFABCD,0,NA,0xFFFFFFFFFFFFABCD,NA,NA,NA,1,1},
- {0xA124,INSTR_SMULWB,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFABCDFFFF,0,NA,0x000000000001ABCD,NA,NA,NA,1,0xFFFFFFFFFFFFFFFE},
- {0xA125,INSTR_SMULWB,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFABCD0001,0,NA,0x000000000FFFABCD,NA,NA,NA,1,0x00000FFF},
- {0xA126,INSTR_SMULWB,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFABCD0001,0,NA,0xFFFFFFFFFFFFABCD,NA,NA,NA,1,0xFFFFFFFFFFFFFFFF},
- {0xA127,INSTR_SMULWB,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFABCDFFFF,0,NA,0xFFFFFFFFFFFFABCD,NA,NA,NA,1,0},
- {0xA128,INSTR_SMULWT,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFFFFFABCD,0,NA,0x000000000001ABCD,NA,NA,NA,1,0xFFFFFFFFFFFFFFFE},
- {0xA129,INSTR_SMULWT,{0,0,0,0,0},AL,0,NA,0x000000000001ABCD,0,NA,0x000000000FFFABCD,NA,NA,NA,1,0x00000FFF},
- {0xA130,INSTR_SMULWT,{0,0,0,0,0},AL,0,NA,0x000000000001ABCD,0,NA,0xFFFFFFFFFFFFABCD,NA,NA,NA,1,0xFFFFFFFFFFFFFFFF},
- {0xA131,INSTR_SMULWT,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFFFFFABCD,0,NA,0xFFFFFFFFFFFFABCD,NA,NA,NA,1,0},
- {0xA132,INSTR_SMLABB,{0,0,0,0,0},AL,0,1,0xFFFFFFFFABCDFFFF,0,NA,0xFFFFFFFFABCD0001,NA,NA,NA,1,0},
- {0xA133,INSTR_SMLABB,{0,0,0,0,0},AL,0,1,0xFFFFFFFFABCD0001,0,NA,0xFFFFFFFFABCD0FFF,NA,NA,NA,1,0x00001000},
- {0xA134,INSTR_SMLABB,{0,0,0,0,0},AL,0,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFABCD0001,0,NA,0xABCDFFFF,NA,NA,NA,1,0xFFFFFFFFFFFFFFFE},
- {0xA135,INSTR_SMLABB,{0,0,0,0,0},AL,0,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFABCDFFFF,0,NA,0xABCDFFFF,NA,NA,NA,1,0},
- {0xA136,INSTR_UXTB16,{0,0,0,0,0},AL,0,NA,NA,0,NA,0xABCDEF01,SHIFT_ROR,0,NA,1,0x00CD0001},
- {0xA137,INSTR_UXTB16,{0,0,0,0,0},AL,0,NA,NA,0,NA,0xABCDEF01,SHIFT_ROR,1,NA,1,0x00AB00EF},
- {0xA138,INSTR_UXTB16,{0,0,0,0,0},AL,0,NA,NA,0,NA,0xABCDEF01,SHIFT_ROR,2,NA,1,0x000100CD},
- {0xA139,INSTR_UXTB16,{0,0,0,0,0},AL,0,NA,NA,0,NA,0xABCDEF01,SHIFT_ROR,3,NA,1,0x00EF00AB},
- {0xA140,INSTR_ADDR_ADD,{0,0,0,0,0},AL,0,0xCFFFFFFFF,NA,0,NA,0x1,SHIFT_LSL,1,NA,1,0xD00000001},
- {0xA141,INSTR_ADDR_ADD,{0,0,0,0,0},AL,0,0x01,NA,0,NA,0x1,SHIFT_LSL,2,NA,1,0x5},
- {0xA142,INSTR_ADDR_ADD,{0,0,0,0,0},AL,0,0xCFFFFFFFF,NA,0,NA,0x1,NA,0,NA,1,0xD00000000},
- {0xA143,INSTR_ADDR_SUB,{0,0,0,0,0},AL,0,0xD00000001,NA,0,NA,0x010000,SHIFT_LSR,15,NA,1,0xCFFFFFFFF},
- {0xA144,INSTR_ADDR_SUB,{0,0,0,0,0},AL,0,0xCFFFFFFFF,NA,0,NA,0x020000,SHIFT_LSR,15,NA,1,0xCFFFFFFFB},
- {0xA145,INSTR_ADDR_SUB,{0,0,0,0,0},AL,0,3,NA,0,NA,0x010000,SHIFT_LSR,15,NA,1,1},
-};
-
-dataTransferTest_t dataTransferTests [] =
-{
- {0xB000,INSTR_LDR,AL,AL,1,24,0xABCDEF0123456789,0,REG_SCALE_OFFSET,24,NA,NA,NA,NA,NA,0x23456789,0,0,NA,NA,NA},
- {0xB001,INSTR_LDR,AL,AL,1,0,0xABCDEF0123456789,0,IMM12_OFFSET,NA,4,1,0,1,NA,0x23456789,4,0,NA,NA,NA},
- {0xB002,INSTR_LDR,AL,AL,1,0,0xABCDEF0123456789,0,NO_OFFSET,NA,NA,0,0,0,NA,0x23456789,0,0,NA,NA,NA},
- {0xB003,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,0,REG_SCALE_OFFSET,4064,NA,NA,NA,NA,NA,0x89,0,0,NA,NA,NA},
- {0xB004,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,4065,IMM12_OFFSET,NA,0,0,1,0,NA,0x67,4065,0,NA,NA,NA},
- {0xB005,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,4065,IMM12_OFFSET,NA,1,0,1,0,NA,0x45,4065,0,NA,NA,NA},
- {0xB006,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,4065,IMM12_OFFSET,NA,2,0,1,0,NA,0x23,4065,0,NA,NA,NA},
- {0xB007,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,4065,IMM12_OFFSET,NA,1,1,0,1,NA,0x67,4066,0,NA,NA,NA},
- {0xB008,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,0,NO_OFFSET,NA,NA,0,0,0,NA,0x89,0,0,NA,NA,NA},
- {0xB009,INSTR_LDRH,AL,AL,1,0,0xABCDEF0123456789,0,IMM8_OFFSET,NA,2,1,0,1,NA,0x6789,2,0,NA,NA,NA},
- {0xB010,INSTR_LDRH,AL,AL,1,4064,0xABCDEF0123456789,0,REG_OFFSET,4064,0,0,1,0,NA,0x6789,0,0,NA,NA,NA},
- {0xB011,INSTR_LDRH,AL,AL,1,4064,0xABCDEF0123456789,0,REG_OFFSET,4066,0,0,1,0,NA,0x2345,0,0,NA,NA,NA},
- {0xB012,INSTR_LDRH,AL,AL,1,0,0xABCDEF0123456789,0,NO_OFFSET,NA,0,0,0,0,NA,0x6789,0,0,NA,NA,NA},
- {0xB013,INSTR_LDRH,AL,AL,1,0,0xABCDEF0123456789,2,NO_OFFSET,NA,0,0,0,0,NA,0x2345,2,0,NA,NA,NA},
- {0xB014,INSTR_STR,AL,AL,1,2,0xDEADBEEFDEADBEEF,4,IMM12_OFFSET,NA,4,1,0,1,0xABCDEF0123456789,0xABCDEF0123456789,8,1,2,8,0xDEAD23456789BEEF},
- {0xB015,INSTR_STR,AL,AL,1,2,0xDEADBEEFDEADBEEF,4,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4,1,2,8,0xDEAD23456789BEEF},
- {0xB016,INSTR_STRB,AL,AL,1,0,0xDEADBEEFDEADBEEF,1,IMM12_OFFSET,NA,0,0,1,0,0xABCDEF0123456789,0xABCDEF0123456789,1,1,0,8,0xDEADBEEFDEAD89EF},
- {0xB017,INSTR_STRB,AL,AL,1,0,0xDEADBEEFDEADBEEF,1,IMM12_OFFSET,NA,1,0,1,0,0xABCDEF0123456789,0xABCDEF0123456789,1,1,0,8,0xDEADBEEFDE89BEEF},
- {0xB018,INSTR_STRB,AL,AL,1,0,0xDEADBEEFDEADBEEF,1,IMM12_OFFSET,NA,2,0,1,0,0xABCDEF0123456789,0xABCDEF0123456789,1,1,0,8,0xDEADBEEF89ADBEEF},
- {0xB019,INSTR_STRB,AL,AL,1,0,0xDEADBEEFDEADBEEF,1,IMM12_OFFSET,NA,4,1,0,1,0xABCDEF0123456789,0xABCDEF0123456789,5,1,0,8,0xDEADBEEFDEAD89EF},
- {0xB020,INSTR_STRB,AL,AL,1,0,0xDEADBEEFDEADBEEF,1,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,1,1,0,8,0xDEADBEEFDEAD89EF},
- {0xB021,INSTR_STRH,AL,AL,1,4066,0xDEADBEEFDEADBEEF,4070,IMM8_OFFSET,NA,2,1,0,1,0xABCDEF0123456789,0xABCDEF0123456789,4072,1,4066,8,0xDEAD6789DEADBEEF},
- {0xB022,INSTR_STRH,AL,AL,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEAD6789DEADBEEF},
-};
-
-
-void flushcache()
-{
- const long base = long(instrMem);
- const long curr = base + long(instrMemSize);
- __builtin___clear_cache((char*)base, (char*)curr);
-}
-
-void dataOpTest(dataOpTest_t test, ArmToMips64Assembler *a64asm, uint32_t Rd = R_v1,
- uint32_t Rn = R_t0, uint32_t Rm = R_t1, uint32_t Rs = R_t2)
-{
- int64_t regs[NUM_REGS] = {0};
- int32_t flags[NUM_FLAGS] = {0};
- int64_t savedRegs[NUM_REGS] = {0};
- uint32_t i;
- uint32_t op2;
-
- for(i = 0; i < NUM_REGS; ++i)
- {
- regs[i] = i;
- }
-
- regs[Rd] = test.RdValue;
- regs[Rn] = test.RnValue;
- regs[Rs] = test.RsValue;
- a64asm->reset();
- if (test.preCond.mode) {
- a64asm->set_condition(test.preCond.mode, test.preCond.Rcond1, test.preCond.Rcond2);
- regs[test.preCond.Rcond1] = test.preCond.Rcond1Value;
- regs[test.preCond.Rcond2] = test.preCond.Rcond2Value;
- }
- a64asm->prolog();
- if(test.immediate == true)
- {
- op2 = a64asm->imm(test.immValue);
- }
- else if(test.immediate == false && test.shiftAmount == 0)
- {
- op2 = Rm;
- regs[Rm] = (int64_t)((int32_t)(test.RmValue));
- }
- else
- {
- op2 = a64asm->reg_imm(Rm, test.shiftMode, test.shiftAmount);
- regs[Rm] = (int64_t)((int32_t)(test.RmValue));
- }
- switch(test.op)
- {
- case INSTR_ADD: a64asm->ADD(test.cond, test.setFlags, Rd,Rn,op2); break;
- case INSTR_SUB: a64asm->SUB(test.cond, test.setFlags, Rd,Rn,op2); break;
- case INSTR_RSB: a64asm->RSB(test.cond, test.setFlags, Rd,Rn,op2); break;
- case INSTR_AND: a64asm->AND(test.cond, test.setFlags, Rd,Rn,op2); break;
- case INSTR_ORR: a64asm->ORR(test.cond, test.setFlags, Rd,Rn,op2); break;
- case INSTR_BIC: a64asm->BIC(test.cond, test.setFlags, Rd,Rn,op2); break;
- case INSTR_MUL: a64asm->MUL(test.cond, test.setFlags, Rd,Rm,Rs); break;
- case INSTR_MLA: a64asm->MLA(test.cond, test.setFlags, Rd,Rm,Rs,Rn); break;
- case INSTR_CMP: a64asm->CMP(test.cond, Rn,op2); break;
- case INSTR_MOV: a64asm->MOV(test.cond, test.setFlags,Rd,op2); break;
- case INSTR_MVN: a64asm->MVN(test.cond, test.setFlags,Rd,op2); break;
- case INSTR_SMULBB:a64asm->SMULBB(test.cond, Rd,Rm,Rs); break;
- case INSTR_SMULBT:a64asm->SMULBT(test.cond, Rd,Rm,Rs); break;
- case INSTR_SMULTB:a64asm->SMULTB(test.cond, Rd,Rm,Rs); break;
- case INSTR_SMULTT:a64asm->SMULTT(test.cond, Rd,Rm,Rs); break;
- case INSTR_SMULWB:a64asm->SMULWB(test.cond, Rd,Rm,Rs); break;
- case INSTR_SMULWT:a64asm->SMULWT(test.cond, Rd,Rm,Rs); break;
- case INSTR_SMLABB:a64asm->SMLABB(test.cond, Rd,Rm,Rs,Rn); break;
- case INSTR_UXTB16:a64asm->UXTB16(test.cond, Rd,Rm,test.shiftAmount); break;
- case INSTR_ADDR_ADD: a64asm->ADDR_ADD(test.cond, test.setFlags, Rd,Rn,op2); break;
- case INSTR_ADDR_SUB: a64asm->ADDR_SUB(test.cond, test.setFlags, Rd,Rn,op2); break;
- default: printf("Error"); return;
- }
- a64asm->epilog(0);
- a64asm->fix_branches();
- flushcache();
-
- asm_function_t asm_function = (asm_function_t)(instrMem);
-
- for(i = 0; i < NUM_REGS; ++i)
- savedRegs[i] = regs[i];
-
- asm_mips_test_jacket(asm_function, regs, flags);
-
- /* Check if all regs except Rd is same */
- for(i = 0; i < NUM_REGS; ++i)
- {
- if((i == Rd) || i == 2) continue;
- if(regs[i] != savedRegs[i])
- {
- printf("Test %x failed Reg(%d) tampered Expected(0x%" PRIx64 "),"
- "Actual(0x%" PRIx64 ") t\n", test.id, i, savedRegs[i],
- regs[i]);
- exit(0);
- return;
- }
- }
-
- if(test.checkRd == 1 && regs[Rd] != test.postRdValue)
- {
- printf("Test %x failed, Expected(%" PRIx64 "), Actual(%" PRIx64 ")\n",
- test.id, test.postRdValue, regs[Rd]);
- exit(0);
- }
- else
- {
- printf("Test %x passed\n", test.id);
- }
-}
-
-
-void dataTransferTest(dataTransferTest_t test, ARMAssemblerInterface *a64asm,
- uint32_t Rd = R_v1, uint32_t Rn = R_t0,uint32_t Rm = R_t1)
-{
- int64_t regs[NUM_REGS] = {0};
- int64_t savedRegs[NUM_REGS] = {0};
- int32_t flags[NUM_FLAGS] = {0};
- uint32_t i;
- for(i = 0; i < NUM_REGS; ++i)
- {
- regs[i] = i;
- }
-
- uint32_t op2;
-
- regs[Rd] = test.RdValue;
- regs[Rn] = (uint64_t)(&dataMem[test.RnValue]);
- regs[Rm] = test.RmValue;
- flags[test.preFlag] = 1;
-
- if(test.setMem == true)
- {
- unsigned char *mem = (unsigned char *)&dataMem[test.memOffset];
- uint64_t value = test.memValue;
- for(int j = 0; j < 8; ++j)
- {
- mem[j] = value & 0x00FF;
- value >>= 8;
- }
- }
- a64asm->reset();
- a64asm->prolog();
- if(test.offsetType == REG_SCALE_OFFSET)
- {
- op2 = a64asm->reg_scale_pre(Rm);
- }
- else if(test.offsetType == REG_OFFSET)
- {
- op2 = a64asm->reg_pre(Rm);
- }
- else if(test.offsetType == IMM12_OFFSET && test.preIndex == true)
- {
- op2 = a64asm->immed12_pre(test.immValue, test.writeBack);
- }
- else if(test.offsetType == IMM12_OFFSET && test.postIndex == true)
- {
- op2 = a64asm->immed12_post(test.immValue);
- }
- else if(test.offsetType == IMM8_OFFSET && test.preIndex == true)
- {
- op2 = a64asm->immed8_pre(test.immValue, test.writeBack);
- }
- else if(test.offsetType == IMM8_OFFSET && test.postIndex == true)
- {
- op2 = a64asm->immed8_post(test.immValue);
- }
- else if(test.offsetType == NO_OFFSET)
- {
- op2 = a64asm->__immed12_pre(0);
- }
- else
- {
- printf("Error - Unknown offset\n"); return;
- }
-
- switch(test.op)
- {
- case INSTR_LDR: a64asm->LDR(test.cond, Rd,Rn,op2); break;
- case INSTR_LDRB: a64asm->LDRB(test.cond, Rd,Rn,op2); break;
- case INSTR_LDRH: a64asm->LDRH(test.cond, Rd,Rn,op2); break;
- case INSTR_ADDR_LDR: a64asm->ADDR_LDR(test.cond, Rd,Rn,op2); break;
- case INSTR_STR: a64asm->STR(test.cond, Rd,Rn,op2); break;
- case INSTR_STRB: a64asm->STRB(test.cond, Rd,Rn,op2); break;
- case INSTR_STRH: a64asm->STRH(test.cond, Rd,Rn,op2); break;
- case INSTR_ADDR_STR: a64asm->ADDR_STR(test.cond, Rd,Rn,op2); break;
- default: printf("Error"); return;
- }
- a64asm->epilog(0);
- flushcache();
-
- asm_function_t asm_function = (asm_function_t)(instrMem);
-
- for(i = 0; i < NUM_REGS; ++i)
- savedRegs[i] = regs[i];
-
- asm_mips_test_jacket(asm_function, regs, flags);
-
- /* Check if all regs except Rd/Rn are same */
- for(i = 0; i < NUM_REGS; ++i)
- {
- if(i == Rd || i == Rn || i == R_v0) continue;
-
- if(regs[i] != savedRegs[i])
- {
- printf("Test %x failed Reg(%d) tampered"
- " Expected(0x%" PRIx64 "), Actual(0x%" PRIx64 ") t\n",
- test.id, i, savedRegs[i], regs[i]);
- return;
- }
- }
-
- if((uint64_t)regs[Rd] != test.postRdValue)
- {
- printf("Test %x failed, "
- "Expected in Rd(0x%" PRIx64 "), Actual(0x%" PRIx64 ")\n",
- test.id, test.postRdValue, regs[Rd]);
- }
- else if((uint64_t)regs[Rn] != (uint64_t)(&dataMem[test.postRnValue]))
- {
- printf("Test %x failed, "
- "Expected in Rn(0x%" PRIx64 "), Actual(0x%" PRIx64 ")\n",
- test.id, test.postRnValue, regs[Rn] - (uint64_t)dataMem);
- }
- else if(test.checkMem == true)
- {
- unsigned char *addr = (unsigned char *)&dataMem[test.postMemOffset];
- uint64_t value;
- value = 0;
- for(uint32_t j = 0; j < test.postMemLength; ++j)
- value = (value << 8) | addr[test.postMemLength-j-1];
- if(value != test.postMemValue)
- {
- printf("Test %x failed, "
- "Expected in Mem(0x%" PRIx64 "), Actual(0x%" PRIx64 ")\n",
- test.id, test.postMemValue, value);
- }
- else
- {
- printf("Test %x passed\n", test.id);
- }
- }
- else
- {
- printf("Test %x passed\n", test.id);
- }
-}
-
-int main(void)
-{
- uint32_t i;
-
- /* Allocate memory to store instructions generated by ArmToArm64Assembler */
- {
- int fd = ashmem_create_region("code cache", instrMemSize);
- if(fd < 0) {
- printf("IF < 0\n");
- printf("Creating code cache, ashmem_create_region "
- "failed with error '%s'", strerror(errno));
- }
- instrMem = mmap(NULL, instrMemSize,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE, fd, 0);
- }
-
- ArmToMips64Assembler a64asm(instrMem);
-
- if(TESTS_DATAOP_ENABLE)
- {
- printf("Running data processing tests\n");
- for(i = 0; i < sizeof(dataOpTests)/sizeof(dataOpTest_t); ++i) {
- dataOpTest(dataOpTests[i], &a64asm);
- }
- }
-
- if(TESTS_DATATRANSFER_ENABLE)
- {
- printf("Running data transfer tests\n");
- for(i = 0; i < sizeof(dataTransferTests)/sizeof(dataTransferTest_t); ++i)
- dataTransferTest(dataTransferTests[i], &a64asm);
- }
-
- return 0;
-}
diff --git a/libpixelflinger/tests/arch-mips64/col32cb16blend/Android.bp b/libpixelflinger/tests/arch-mips64/col32cb16blend/Android.bp
deleted file mode 100644
index bfc6ae9..0000000
--- a/libpixelflinger/tests/arch-mips64/col32cb16blend/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-cc_test {
- name: "test-pixelflinger-mips64-col32cb16blend",
- defaults: ["pixelflinger-tests-mips64"],
-
- srcs: ["col32cb16blend_test.c"],
-}
diff --git a/libpixelflinger/tests/arch-mips64/col32cb16blend/col32cb16blend_test.c b/libpixelflinger/tests/arch-mips64/col32cb16blend/col32cb16blend_test.c
deleted file mode 100644
index 066eab6..0000000
--- a/libpixelflinger/tests/arch-mips64/col32cb16blend/col32cb16blend_test.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <assert.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-
-
-#define ARGB_8888_MAX 0xFFFFFFFF
-#define ARGB_8888_MIN 0x00000000
-#define RGB_565_MAX 0xFFFF
-#define RGB_565_MIN 0x0000
-
-struct test_t
-{
- char name[256];
- uint32_t src_color;
- uint16_t dst_color;
- size_t count;
-};
-
-struct test_t tests[] =
-{
- {"Count 1, Src=Max, Dst=Min", ARGB_8888_MAX, RGB_565_MIN, 1},
- {"Count 2, Src=Min, Dst=Max", ARGB_8888_MIN, RGB_565_MAX, 2},
- {"Count 3, Src=Max, Dst=Max", ARGB_8888_MAX, RGB_565_MAX, 3},
- {"Count 4, Src=Min, Dst=Min", ARGB_8888_MAX, RGB_565_MAX, 4},
- {"Count 1, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 1},
- {"Count 2, Src=Rand, Dst=Rand", 0xABCDEF12, 0x2345, 2},
- {"Count 3, Src=Rand, Dst=Rand", 0x11111111, 0xEDFE, 3},
- {"Count 4, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 4},
- {"Count 5, Src=Rand, Dst=Rand", 0xEFEFFEFE, 0xFACC, 5},
- {"Count 10, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 10}
-};
-
-void scanline_col32cb16blend_mips64(uint16_t *dst, uint32_t src, size_t count);
-void scanline_col32cb16blend_c(uint16_t * dst, uint32_t src, size_t count)
-{
- uint32_t srcAlpha = (src>>24);
- uint32_t f = 0x100 - (srcAlpha + (srcAlpha>>7));
-
- while (count--)
- {
- uint16_t d = *dst;
- int dstR = (d>>11)&0x1f;
- int dstG = (d>>5)&0x3f;
- int dstB = (d)&0x1f;
- int srcR = (src >> ( 3))&0x1F;
- int srcG = (src >> ( 8+2))&0x3F;
- int srcB = (src >> (16+3))&0x1F;
- srcR += (f*dstR)>>8;
- srcG += (f*dstG)>>8;
- srcB += (f*dstB)>>8;
- *dst++ = (uint16_t)((srcR<<11)|(srcG<<5)|srcB);
- }
-}
-
-void scanline_col32cb16blend_test()
-{
- uint16_t dst_c[16], dst_asm[16];
- uint32_t i, j;
-
- for(i = 0; i < sizeof(tests)/sizeof(struct test_t); ++i)
- {
- struct test_t test = tests[i];
-
- printf("Testing - %s:",test.name);
-
- memset(dst_c, 0, sizeof(dst_c));
- memset(dst_asm, 0, sizeof(dst_asm));
-
- for(j = 0; j < test.count; ++j)
- {
- dst_c[j] = test.dst_color;
- dst_asm[j] = test.dst_color;
- }
-
-
- scanline_col32cb16blend_c(dst_c, test.src_color, test.count);
- scanline_col32cb16blend_mips64(dst_asm, test.src_color, test.count);
-
- if(memcmp(dst_c, dst_asm, sizeof(dst_c)) == 0)
- printf("Passed\n");
- else
- printf("Failed\n");
-
- for(j = 0; j < test.count; ++j)
- {
- printf("dst_c[%d] = %x, dst_asm[%d] = %x \n", j, dst_c[j], j, dst_asm[j]);
- }
- }
-}
-
-int main()
-{
- scanline_col32cb16blend_test();
- return 0;
-}
diff --git a/libpixelflinger/tests/arch-mips64/disassembler/Android.bp b/libpixelflinger/tests/arch-mips64/disassembler/Android.bp
deleted file mode 100644
index 96bf9e9..0000000
--- a/libpixelflinger/tests/arch-mips64/disassembler/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-cc_test {
- name: "test-pixelflinger-mips64-disassembler-test",
- defaults: ["pixelflinger-tests-mips64"],
-
- srcs: ["mips64_disassembler_test.cpp"],
-}
diff --git a/libpixelflinger/tests/arch-mips64/disassembler/mips64_disassembler_test.cpp b/libpixelflinger/tests/arch-mips64/disassembler/mips64_disassembler_test.cpp
deleted file mode 100644
index 22efa9f..0000000
--- a/libpixelflinger/tests/arch-mips64/disassembler/mips64_disassembler_test.cpp
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-#include <stdio.h>
-#include <inttypes.h>
-#include <string.h>
-#include "../../../codeflinger/mips64_disassem.h"
-
-//typedef uint64_t db_addr_t;
-//db_addr_t mips_disassem(db_addr_t loc, char *di_buffer, int alt_format);
-
-struct test_table_entry_t
-{
- uint32_t code;
- const char *instr;
-};
-
-static test_table_entry_t test_table [] =
-{
- { 0x00011020, "add\tv0,zero,at" },
- { 0x00832820, "add\ta1,a0,v1" },
- { 0x00c74020, "add\ta4,a2,a3" },
- { 0x012a5820, "add\ta7,a5,a6" },
- { 0x258dffff, "addiu\tt1,t0,-1" },
- { 0x25cf0004, "addiu\tt3,t2,4" },
- { 0x02119021, "addu\ts2,s0,s1" },
- { 0x0274a821, "addu\ts5,s3,s4" },
- { 0x02d7c024, "and\tt8,s6,s7" },
- { 0x333aff00, "andi\tk0,t9,0xff00" },
- { 0x3f7cffff, "aui\tgp,k1,-1" },
- { 0x3c1dffff, "lui\tsp,0xffff" },
- { 0x00e04051, "clo\ta4,a3" },
- { 0x01205050, "clz\ta6,a5" },
- { 0x016c682c, "dadd\tt1,a7,t0" },
- { 0x65cf0008, "daddiu\tt3,t2,8" },
- { 0x0211902d, "daddu\ts2,s0,s1" },
- { 0x7e741403, "dext\ts4,s3,16,3" },
- { 0x7eb6f801, "dextm\ts6,s5,0,64" },
- { 0x7ef87c02, "dextu\tt8,s7,48,16" },
- { 0x7f3a8207, "dins\tk0,t9,8,9" },
- { 0x7f7c0005, "dinsm\tgp,k1,0,33" },
- { 0x7fbe0806, "dinsu\ts8,sp,32,2" },
- { 0x03e1102e, "dsub\tv0,ra,at" },
- { 0x0064282f, "dsubu\ta1,v1,a0" },
- { 0x7cc77a00, "ext\ta3,a2,8,16" },
- { 0x7d09fc04, "ins\ta5,a4,16,16" },
- { 0x00200009, "jr\tat" },
- { 0x00201009, "jalr\tv0,at" },
- { 0x0020f809, "jalr\tat" },
- { 0x8082fff0, "lb\tv0,-16(a0)" },
- { 0x916c0008, "lbu\tt0,8(a7)" },
- { 0xdfa3ffe8, "ld\tv1,-24(sp)" },
- { 0x84850080, "lh\ta1,128(a0)" },
- { 0x94c7ff80, "lhu\ta3,-128(a2)" },
- { 0x8d09000c, "lw\ta5,12(a4)" },
- { 0x9d4bfff4, "lwu\ta7,-12(a6)" },
- { 0x00620898, "mul\tat,v1,v0" },
- { 0x006208d8, "muh\tat,v1,v0" },
- { 0x00620899, "mulu\tat,v1,v0" },
- { 0x006208d9, "muhu\tat,v1,v0" },
- { 0x00000000, "nop" },
- { 0x02329827, "nor\ts3,s1,s2" },
- { 0x0295b025, "or\ts6,s4,s5" },
- { 0x36f0ff00, "ori\ts0,s7,0xff00" },
- { 0x7c03103b, "rdhwr\tv0,v1" },
- { 0x00242a02, "rotr\ta1,a0,8" },
- { 0x00c74046, "rotrv\ta4,a3,a2" },
- { 0xa12afff0, "sb\ta6,-16(a5)" },
- { 0xfd6c0100, "sd\tt0,256(a7)" },
- { 0x7c0d7420, "seb\tt2,t1" },
- { 0x7c0f8620, "seh\ts0,t3" },
- { 0x02329835, "seleqz\ts3,s1,s2" },
- { 0x0295b037, "selnez\ts6,s4,s5" },
- { 0xa6f84000, "sh\tt8,16384(s7)" },
- { 0x0019d100, "sll\tk0,t9,4" },
- { 0x037ce804, "sllv\tsp,gp,k1" },
- { 0x03df082a, "slt\tat,s8,ra" },
- { 0x28430007, "slti\tv1,v0,7" },
- { 0x2c850020, "sltiu\ta1,a0,32" },
- { 0x00c7402b, "sltu\ta4,a2,a3" },
- { 0x00095103, "sra\ta6,a5,4" },
- { 0x016c6807, "srav\tt1,t0,a7" },
- { 0x000e7a02, "srl\tt3,t2,8" },
- { 0x02119006, "srlv\ts2,s1,s0" },
- { 0x0274a822, "sub\ts5,s3,s4" },
- { 0x02d7c023, "subu\tt8,s6,s7" },
- { 0xaf3afffc, "sw\tk0,-4(t9)" },
- { 0x7c1be0a0, "wsbh\tgp,k1" },
- { 0x03bef826, "xor\tra,sp,s8" },
- { 0x3801ffff, "li\tat,0xffff" },
- { 0x3843ffff, "xori\tv1,v0,0xffff" },
-};
-
-struct test_branches_table_entry_t
-{
- uint32_t code;
- const char *instr;
- int16_t offset;
-};
-
-static test_branches_table_entry_t test_branches_table [] = {
- { 0x1000ffff, "b\t", static_cast<int16_t>(0xffff) },
- { 0x13df0008, "beq\ts8,ra,", 0x8 },
- { 0x042100ff, "bgez\tat,", 0xff },
- { 0x1c40ff00, "bgtz\tv0,", static_cast<int16_t>(0xff00) },
- { 0x18605555, "blez\tv1,", 0x5555 },
- { 0x0480aaaa, "bltz\ta0,", static_cast<int16_t>(0xaaaa) },
- { 0x14a68888, "bne\ta1,a2,", static_cast<int16_t>(0x8888) },
-};
-
-struct test_jump_table_entry_t
-{
- uint32_t code;
- const char *instr;
- int32_t offset;
-};
-
-static test_jump_table_entry_t test_jump_table [] = {
- { 0x0956ae66, "j\t", 0x156ae66 },
- { 0x0d56ae66, "jal\t", 0x156ae66 },
-};
-
-int main()
-{
- char instr[256];
- uint32_t failed = 0;
-
- for(uint32_t i = 0; i < sizeof(test_table)/sizeof(test_table_entry_t); ++i)
- {
- test_table_entry_t *test;
- test = &test_table[i];
- mips_disassem(&test->code, instr, 0);
- if(strcmp(instr, test->instr) != 0)
- {
- printf("Test Failed \n"
- "Code : 0x%0x\n"
- "Expected : %s\n"
- "Actual : %s\n", test->code, test->instr, instr);
- failed++;
- }
- }
- for(uint32_t i = 0; i < sizeof(test_branches_table)/sizeof(test_branches_table_entry_t); ++i)
- {
- test_branches_table_entry_t *test;
- test = &test_branches_table[i];
- mips_disassem(&test->code, instr, 0);
- //printf("DBG code address: %lx\n", (uint64_t)(&test->code));
- uint64_t loc = (uint64_t)test + 4 + (test->offset << 2);
- //printf("DBG loc: %lx\n", loc);
- char temp[256], address[16];
- strcpy(temp, test->instr);
- sprintf(address, "0x%lx", loc);
- strcat(temp, address);
- if(strcmp(instr, temp) != 0)
- {
- printf("Test Failed \n"
- "Code : 0x%0x\n"
- "Expected : %s\n"
- "Actual : %s\n", test->code, temp, instr);
- failed++;
- }
- }
- for(uint32_t i = 0; i < sizeof(test_jump_table)/sizeof(test_jump_table_entry_t); ++i)
- {
- test_jump_table_entry_t *test;
- test = &test_jump_table[i];
- mips_disassem(&test->code, instr, 0);
- //printf("DBG code address: %lx\n", (uint64_t)(&test->code));
- uint64_t loc = ((uint64_t)test & 0xfffffffff0000000) | (test->offset << 2);
- //printf("DBG loc: %lx\n", loc);
- char temp[256], address[16];
- strcpy(temp, test->instr);
- sprintf(address, "0x%08lx", loc);
- strcat(temp, address);
- if(strcmp(instr, temp) != 0)
- {
- printf("Test Failed \n"
- "Code : 0x%0x\n"
- "Expected : '%s'\n"
- "Actual : '%s'\n", test->code, temp, instr);
- failed++;
- }
- }
- if(failed == 0)
- {
- printf("All tests PASSED\n");
- return 0;
- }
- else
- {
- printf("%d tests FAILED\n", failed);
- return -1;
- }
-}
diff --git a/libprocessgroup/profiles/Android.bp b/libprocessgroup/profiles/Android.bp
index e05a690..12474f1 100644
--- a/libprocessgroup/profiles/Android.bp
+++ b/libprocessgroup/profiles/Android.bp
@@ -106,3 +106,7 @@
},
},
}
+
+vts_config {
+ name: "VtsProcessgroupValidateTest",
+}
diff --git a/libprocessgroup/profiles/Android.mk b/libprocessgroup/profiles/Android.mk
deleted file mode 100644
index eab96d4..0000000
--- a/libprocessgroup/profiles/Android.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-#
-# 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 := VtsProcessgroupValidateTest
--include test/vts/tools/build/Android.host_config.mk
diff --git a/libstats/push_compat/Android.bp b/libstats/push_compat/Android.bp
index 465c05a..fcd8c83 100644
--- a/libstats/push_compat/Android.bp
+++ b/libstats/push_compat/Android.bp
@@ -35,6 +35,8 @@
header_libs: ["libstatssocket_headers"],
static_libs: [
"libbase",
+ ],
+ shared_libs: [
"liblog",
"libutils",
],
diff --git a/libsystem/Android.bp b/libsystem/Android.bp
index b265b61..ff886fd 100644
--- a/libsystem/Android.bp
+++ b/libsystem/Android.bp
@@ -4,6 +4,10 @@
recovery_available: true,
host_supported: true,
native_bridge_supported: true,
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
export_include_dirs: ["include"],
target: {
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 9ddbedf..3ab619b 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -18,6 +18,10 @@
recovery_available: true,
host_supported: true,
native_bridge_supported: true,
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
header_libs: [
"liblog_headers",
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 1bbffaf..3d4e86e 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -60,6 +60,7 @@
srcs: [
"zip_archive.cc",
"zip_archive_stream_entry.cc",
+ "zip_cd_entry_map.cc",
"zip_writer.cc",
],
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 68837cc..2648c59 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -85,76 +85,6 @@
* of the string length into the hash table entry.
*/
-/*
- * Round up to the next highest power of 2.
- *
- * Found on http://graphics.stanford.edu/~seander/bithacks.html.
- */
-static uint32_t RoundUpPower2(uint32_t val) {
- val--;
- val |= val >> 1;
- val |= val >> 2;
- val |= val >> 4;
- val |= val >> 8;
- val |= val >> 16;
- val++;
-
- return val;
-}
-
-static uint32_t ComputeHash(std::string_view name) {
- return static_cast<uint32_t>(std::hash<std::string_view>{}(name));
-}
-
-/*
- * Convert a ZipEntry to a hash table index, verifying that it's in a
- * valid range.
- */
-static int64_t EntryToIndex(const ZipStringOffset* hash_table, const uint32_t hash_table_size,
- std::string_view name, const uint8_t* start) {
- const uint32_t hash = ComputeHash(name);
-
- // NOTE: (hash_table_size - 1) is guaranteed to be non-negative.
- uint32_t ent = hash & (hash_table_size - 1);
- while (hash_table[ent].name_offset != 0) {
- if (hash_table[ent].ToStringView(start) == name) {
- return ent;
- }
- ent = (ent + 1) & (hash_table_size - 1);
- }
-
- ALOGV("Zip: Unable to find entry %.*s", static_cast<int>(name.size()), name.data());
- return kEntryNotFound;
-}
-
-/*
- * Add a new entry to the hash table.
- */
-static int32_t AddToHash(ZipStringOffset* hash_table, const uint32_t hash_table_size,
- std::string_view name, const uint8_t* start) {
- const uint64_t hash = ComputeHash(name);
- uint32_t ent = hash & (hash_table_size - 1);
-
- /*
- * We over-allocated the table, so we're guaranteed to find an empty slot.
- * Further, we guarantee that the hashtable size is not 0.
- */
- while (hash_table[ent].name_offset != 0) {
- if (hash_table[ent].ToStringView(start) == name) {
- // We've found a duplicate entry. We don't accept duplicates.
- ALOGW("Zip: Found duplicate entry %.*s", static_cast<int>(name.size()), name.data());
- return kDuplicateEntry;
- }
- ent = (ent + 1) & (hash_table_size - 1);
- }
-
- // `name` has already been validated before entry.
- const char* start_char = reinterpret_cast<const char*>(start);
- hash_table[ent].name_offset = static_cast<uint32_t>(name.data() - start_char);
- hash_table[ent].name_length = static_cast<uint16_t>(name.size());
- return 0;
-}
-
#if defined(__BIONIC__)
uint64_t GetOwnerTag(const ZipArchive* archive) {
return android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_ZIPARCHIVE,
@@ -168,9 +98,7 @@
directory_offset(0),
central_directory(),
directory_map(),
- num_entries(0),
- hash_table_size(0),
- hash_table(nullptr) {
+ num_entries(0) {
#if defined(__BIONIC__)
if (assume_ownership) {
android_fdsan_exchange_owner_tag(fd, 0, GetOwnerTag(this));
@@ -184,9 +112,7 @@
directory_offset(0),
central_directory(),
directory_map(),
- num_entries(0),
- hash_table_size(0),
- hash_table(nullptr) {}
+ num_entries(0) {}
ZipArchive::~ZipArchive() {
if (close_file && mapped_zip.GetFileDescriptor() >= 0) {
@@ -196,8 +122,6 @@
close(mapped_zip.GetFileDescriptor());
#endif
}
-
- free(hash_table);
}
static int32_t MapCentralDirectory0(const char* debug_file_name, ZipArchive* archive,
@@ -339,17 +263,13 @@
const size_t cd_length = archive->central_directory.GetMapLength();
const uint16_t num_entries = archive->num_entries;
- /*
- * Create hash table. We have a minimum 75% load factor, possibly as
- * low as 50% after we round off to a power of 2. There must be at
- * least one unused entry to avoid an infinite loop during creation.
- */
- archive->hash_table_size = RoundUpPower2(1 + (num_entries * 4) / 3);
- archive->hash_table =
- reinterpret_cast<ZipStringOffset*>(calloc(archive->hash_table_size, sizeof(ZipStringOffset)));
- if (archive->hash_table == nullptr) {
- ALOGW("Zip: unable to allocate the %u-entry hash_table, entry size: %zu",
- archive->hash_table_size, sizeof(ZipStringOffset));
+ // TODO(xunchang) parse the zip64 Eocd
+ if (num_entries > UINT16_MAX) {
+ archive->cd_entry_map = CdEntryMapZip64::Create();
+ } else {
+ archive->cd_entry_map = CdEntryMapZip32::Create(num_entries);
+ }
+ if (archive->cd_entry_map == nullptr) {
return kAllocationFailed;
}
@@ -401,9 +321,9 @@
// Add the CDE filename to the hash table.
std::string_view entry_name{reinterpret_cast<const char*>(file_name), file_name_length};
- const int add_result = AddToHash(archive->hash_table, archive->hash_table_size, entry_name,
- archive->central_directory.GetBasePtr());
- if (add_result != 0) {
+ if (auto add_result =
+ archive->cd_entry_map->AddToMap(entry_name, archive->central_directory.GetBasePtr());
+ add_result != 0) {
ALOGW("Zip: Error adding entry to hash table %d", add_result);
return add_result;
}
@@ -514,14 +434,13 @@
return 0;
}
-static int32_t FindEntry(const ZipArchive* archive, const int32_t ent, ZipEntry* data) {
- const uint16_t nameLen = archive->hash_table[ent].name_length;
-
+static int32_t FindEntry(const ZipArchive* archive, std::string_view entryName,
+ const uint64_t nameOffset, ZipEntry* data) {
// Recover the start of the central directory entry from the filename
// pointer. The filename is the first entry past the fixed-size data,
// so we can just subtract back from that.
const uint8_t* base_ptr = archive->central_directory.GetBasePtr();
- const uint8_t* ptr = base_ptr + archive->hash_table[ent].name_offset;
+ const uint8_t* ptr = base_ptr + nameOffset;
ptr -= sizeof(CentralDirectoryRecord);
// This is the base of our mmapped region, we have to sanity check that
@@ -627,8 +546,11 @@
// Check that the local file header name matches the declared
// name in the central directory.
+ CHECK_LE(entryName.size(), UINT16_MAX);
+ auto nameLen = static_cast<uint16_t>(entryName.size());
if (lfh->file_name_length != nameLen) {
- ALOGW("Zip: lfh name length did not match central directory");
+ ALOGW("Zip: lfh name length did not match central directory for %s: %" PRIu16 " %" PRIu16,
+ std::string(entryName).c_str(), lfh->file_name_length, nameLen);
return kInconsistentInformation;
}
const off64_t name_offset = local_header_offset + sizeof(LocalFileHeader);
@@ -641,9 +563,7 @@
ALOGW("Zip: failed reading lfh name from offset %" PRId64, static_cast<int64_t>(name_offset));
return kIoError;
}
- const std::string_view entry_name =
- archive->hash_table[ent].ToStringView(archive->central_directory.GetBasePtr());
- if (memcmp(entry_name.data(), name_buf.data(), nameLen) != 0) {
+ if (memcmp(entryName.data(), name_buf.data(), nameLen) != 0) {
ALOGW("Zip: lfh name did not match central directory");
return kInconsistentInformation;
}
@@ -689,7 +609,7 @@
int32_t StartIteration(ZipArchiveHandle archive, void** cookie_ptr,
const std::string_view optional_prefix,
const std::string_view optional_suffix) {
- if (archive == NULL || archive->hash_table == NULL) {
+ if (archive == nullptr || archive->cd_entry_map == nullptr) {
ALOGW("Zip: Invalid ZipArchiveHandle");
return kInvalidHandle;
}
@@ -700,6 +620,7 @@
return kInvalidEntryName;
}
+ archive->cd_entry_map->ResetIteration();
*cookie_ptr = new IterationHandle(archive, optional_prefix, optional_suffix);
return 0;
}
@@ -715,14 +636,14 @@
return kInvalidEntryName;
}
- const int64_t ent = EntryToIndex(archive->hash_table, archive->hash_table_size, entryName,
- archive->central_directory.GetBasePtr());
- if (ent < 0) {
+ const auto [result, offset] =
+ archive->cd_entry_map->GetCdEntryOffset(entryName, archive->central_directory.GetBasePtr());
+ if (result != 0) {
ALOGV("Zip: Could not find entry %.*s", static_cast<int>(entryName.size()), entryName.data());
- return static_cast<int32_t>(ent); // kEntryNotFound is safe to truncate.
+ return static_cast<int32_t>(result); // kEntryNotFound is safe to truncate.
}
// We know there are at most hash_table_size entries, safe to truncate.
- return FindEntry(archive, static_cast<uint32_t>(ent), data);
+ return FindEntry(archive, entryName, offset, data);
}
int32_t Next(void* cookie, ZipEntry* data, std::string* name) {
@@ -736,35 +657,32 @@
int32_t Next(void* cookie, ZipEntry* data, std::string_view* name) {
IterationHandle* handle = reinterpret_cast<IterationHandle*>(cookie);
- if (handle == NULL) {
+ if (handle == nullptr) {
ALOGW("Zip: Null ZipArchiveHandle");
return kInvalidHandle;
}
ZipArchive* archive = handle->archive;
- if (archive == NULL || archive->hash_table == NULL) {
+ if (archive == nullptr || archive->cd_entry_map == nullptr) {
ALOGW("Zip: Invalid ZipArchiveHandle");
return kInvalidHandle;
}
- const uint32_t currentOffset = handle->position;
- const uint32_t hash_table_length = archive->hash_table_size;
- const ZipStringOffset* hash_table = archive->hash_table;
- for (uint32_t i = currentOffset; i < hash_table_length; ++i) {
- const std::string_view entry_name =
- hash_table[i].ToStringView(archive->central_directory.GetBasePtr());
- if (hash_table[i].name_offset != 0 && (android::base::StartsWith(entry_name, handle->prefix) &&
- android::base::EndsWith(entry_name, handle->suffix))) {
- handle->position = (i + 1);
- const int error = FindEntry(archive, i, data);
+ auto entry = archive->cd_entry_map->Next(archive->central_directory.GetBasePtr());
+ while (entry != std::pair<std::string_view, uint64_t>()) {
+ const auto [entry_name, offset] = entry;
+ if (android::base::StartsWith(entry_name, handle->prefix) &&
+ android::base::EndsWith(entry_name, handle->suffix)) {
+ const int error = FindEntry(archive, entry_name, offset, data);
if (!error && name) {
*name = entry_name;
}
return error;
}
+ entry = archive->cd_entry_map->Next(archive->central_directory.GetBasePtr());
}
- handle->position = 0;
+ archive->cd_entry_map->ResetIteration();
return kIterationEnd;
}
diff --git a/libziparchive/zip_archive_private.h b/libziparchive/zip_archive_private.h
index 1d05fc7..536894c 100644
--- a/libziparchive/zip_archive_private.h
+++ b/libziparchive/zip_archive_private.h
@@ -23,76 +23,13 @@
#include <unistd.h>
#include <memory>
+#include <utility>
#include <vector>
#include "android-base/macros.h"
#include "android-base/mapped_file.h"
-
-static const char* kErrorMessages[] = {
- "Success",
- "Iteration ended",
- "Zlib error",
- "Invalid file",
- "Invalid handle",
- "Duplicate entries in archive",
- "Empty archive",
- "Entry not found",
- "Invalid offset",
- "Inconsistent information",
- "Invalid entry name",
- "I/O error",
- "File mapping failed",
- "Allocation failed",
-};
-
-enum ErrorCodes : int32_t {
- kIterationEnd = -1,
-
- // We encountered a Zlib error when inflating a stream from this file.
- // Usually indicates file corruption.
- kZlibError = -2,
-
- // The input file cannot be processed as a zip archive. Usually because
- // it's too small, too large or does not have a valid signature.
- kInvalidFile = -3,
-
- // An invalid iteration / ziparchive handle was passed in as an input
- // argument.
- kInvalidHandle = -4,
-
- // The zip archive contained two (or possibly more) entries with the same
- // name.
- kDuplicateEntry = -5,
-
- // The zip archive contains no entries.
- kEmptyArchive = -6,
-
- // The specified entry was not found in the archive.
- kEntryNotFound = -7,
-
- // The zip archive contained an invalid local file header pointer.
- kInvalidOffset = -8,
-
- // The zip archive contained inconsistent entry information. This could
- // be because the central directory & local file header did not agree, or
- // if the actual uncompressed length or crc32 do not match their declared
- // values.
- kInconsistentInformation = -9,
-
- // An invalid entry name was encountered.
- kInvalidEntryName = -10,
-
- // An I/O related system call (read, lseek, ftruncate, map) failed.
- kIoError = -11,
-
- // We were not able to mmap the central directory or entry contents.
- kMmapFailed = -12,
-
- // An allocation failed.
- kAllocationFailed = -13,
-
- kLastErrorCode = kAllocationFailed,
-};
+#include "zip_cd_entry_map.h"
+#include "zip_error.h"
class MappedZipFile {
public:
@@ -140,26 +77,6 @@
size_t length_;
};
-/**
- * More space efficient string representation of strings in an mmaped zipped
- * file than std::string_view. Using std::string_view as an entry in the
- * ZipArchive hash table wastes space. std::string_view stores a pointer to a
- * string (on 64 bit, 8 bytes) and the length to read from that pointer,
- * 2 bytes. Because of alignment, the structure consumes 16 bytes, wasting
- * 6 bytes.
- *
- * ZipStringOffset stores a 4 byte offset from a fixed location in the memory
- * mapped file instead of the entire address, consuming 8 bytes with alignment.
- */
-struct ZipStringOffset {
- uint32_t name_offset;
- uint16_t name_length;
-
- const std::string_view ToStringView(const uint8_t* start) const {
- return std::string_view{reinterpret_cast<const char*>(start + name_offset), name_length};
- }
-};
-
struct ZipArchive {
// open Zip archive
mutable MappedZipFile mapped_zip;
@@ -172,13 +89,7 @@
// number of entries in the Zip archive
uint16_t num_entries;
-
- // We know how many entries are in the Zip archive, so we can have a
- // fixed-size hash table. We define a load factor of 0.75 and over
- // allocate so the maximum number entries can never be higher than
- // ((4 * UINT16_MAX) / 3 + 1) which can safely fit into a uint32_t.
- uint32_t hash_table_size;
- ZipStringOffset* hash_table;
+ std::unique_ptr<CdEntryMapInterface> cd_entry_map;
ZipArchive(const int fd, bool assume_ownership);
ZipArchive(const void* address, size_t length);
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 0916304..523d4c5 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -24,11 +24,14 @@
#include <unistd.h>
#include <memory>
+#include <set>
+#include <string_view>
#include <vector>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/mapped_file.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <gtest/gtest.h>
#include <ziparchive/zip_archive.h>
@@ -53,6 +56,76 @@
return OpenArchive(abs_path.c_str(), handle);
}
+class CdEntryMapTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ names_ = {
+ "a.txt", "b.txt", "b/", "b/c.txt", "b/d.txt",
+ };
+ separator_ = "separator";
+ header_ = "metadata";
+ joined_names_ = header_ + android::base::Join(names_, separator_);
+ base_ptr_ = reinterpret_cast<uint8_t*>(&joined_names_[0]);
+
+ entry_maps_.emplace_back(CdEntryMapZip32::Create(static_cast<uint16_t>(names_.size())));
+ entry_maps_.emplace_back(CdEntryMapZip64::Create());
+ for (auto& cd_map : entry_maps_) {
+ ASSERT_NE(nullptr, cd_map);
+ size_t offset = header_.size();
+ for (const auto& name : names_) {
+ auto status = cd_map->AddToMap(
+ std::string_view{joined_names_.c_str() + offset, name.size()}, base_ptr_);
+ ASSERT_EQ(0, status);
+ offset += name.size() + separator_.size();
+ }
+ }
+ }
+
+ std::vector<std::string> names_;
+ // A continuous region of memory serves as a mock of the central directory.
+ std::string joined_names_;
+ // We expect some metadata at the beginning of the central directory and between filenames.
+ std::string header_;
+ std::string separator_;
+
+ std::vector<std::unique_ptr<CdEntryMapInterface>> entry_maps_;
+ uint8_t* base_ptr_{nullptr}; // Points to the start of the central directory.
+};
+
+TEST_F(CdEntryMapTest, AddDuplicatedEntry) {
+ for (auto& cd_map : entry_maps_) {
+ std::string_view name = "b.txt";
+ ASSERT_NE(0, cd_map->AddToMap(name, base_ptr_));
+ }
+}
+
+TEST_F(CdEntryMapTest, FindEntry) {
+ for (auto& cd_map : entry_maps_) {
+ uint64_t expected_offset = header_.size();
+ for (const auto& name : names_) {
+ auto [status, offset] = cd_map->GetCdEntryOffset(name, base_ptr_);
+ ASSERT_EQ(status, kSuccess);
+ ASSERT_EQ(offset, expected_offset);
+ expected_offset += name.size() + separator_.size();
+ }
+ }
+}
+
+TEST_F(CdEntryMapTest, Iteration) {
+ std::set<std::string_view> expected(names_.begin(), names_.end());
+ for (auto& cd_map : entry_maps_) {
+ cd_map->ResetIteration();
+ std::set<std::string_view> entry_set;
+ auto ret = cd_map->Next(base_ptr_);
+ while (ret != std::pair<std::string_view, uint64_t>{}) {
+ auto [it, insert_status] = entry_set.insert(ret.first);
+ ASSERT_TRUE(insert_status);
+ ret = cd_map->Next(base_ptr_);
+ }
+ ASSERT_EQ(expected, entry_set);
+ }
+}
+
TEST(ziparchive, Open) {
ZipArchiveHandle handle;
ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
diff --git a/libziparchive/zip_cd_entry_map.cc b/libziparchive/zip_cd_entry_map.cc
new file mode 100644
index 0000000..f187c06
--- /dev/null
+++ b/libziparchive/zip_cd_entry_map.cc
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2020 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 "zip_cd_entry_map.h"
+
+#include <android-base/logging.h>
+#include <log/log.h>
+
+/*
+ * Round up to the next highest power of 2.
+ *
+ * Found on http://graphics.stanford.edu/~seander/bithacks.html.
+ */
+static uint32_t RoundUpPower2(uint32_t val) {
+ val--;
+ val |= val >> 1;
+ val |= val >> 2;
+ val |= val >> 4;
+ val |= val >> 8;
+ val |= val >> 16;
+ val++;
+
+ return val;
+}
+
+static uint32_t ComputeHash(std::string_view name) {
+ return static_cast<uint32_t>(std::hash<std::string_view>{}(name));
+}
+
+// Convert a ZipEntry to a hash table index, verifying that it's in a valid range.
+std::pair<ZipError, uint64_t> CdEntryMapZip32::GetCdEntryOffset(std::string_view name,
+ const uint8_t* start) const {
+ const uint32_t hash = ComputeHash(name);
+
+ // NOTE: (hash_table_size - 1) is guaranteed to be non-negative.
+ uint32_t ent = hash & (hash_table_size_ - 1);
+ while (hash_table_[ent].name_offset != 0) {
+ if (hash_table_[ent].ToStringView(start) == name) {
+ return {kSuccess, hash_table_[ent].name_offset};
+ }
+ ent = (ent + 1) & (hash_table_size_ - 1);
+ }
+
+ ALOGV("Zip: Unable to find entry %.*s", static_cast<int>(name.size()), name.data());
+ return {kEntryNotFound, 0};
+}
+
+ZipError CdEntryMapZip32::AddToMap(std::string_view name, const uint8_t* start) {
+ const uint64_t hash = ComputeHash(name);
+ uint32_t ent = hash & (hash_table_size_ - 1);
+
+ /*
+ * We over-allocated the table, so we're guaranteed to find an empty slot.
+ * Further, we guarantee that the hashtable size is not 0.
+ */
+ while (hash_table_[ent].name_offset != 0) {
+ if (hash_table_[ent].ToStringView(start) == name) {
+ // We've found a duplicate entry. We don't accept duplicates.
+ ALOGW("Zip: Found duplicate entry %.*s", static_cast<int>(name.size()), name.data());
+ return kDuplicateEntry;
+ }
+ ent = (ent + 1) & (hash_table_size_ - 1);
+ }
+
+ // `name` has already been validated before entry.
+ const char* start_char = reinterpret_cast<const char*>(start);
+ hash_table_[ent].name_offset = static_cast<uint32_t>(name.data() - start_char);
+ hash_table_[ent].name_length = static_cast<uint16_t>(name.size());
+ return kSuccess;
+}
+
+void CdEntryMapZip32::ResetIteration() {
+ current_position_ = 0;
+}
+
+std::pair<std::string_view, uint64_t> CdEntryMapZip32::Next(const uint8_t* cd_start) {
+ while (current_position_ < hash_table_size_) {
+ const auto& entry = hash_table_[current_position_];
+ current_position_ += 1;
+
+ if (entry.name_offset != 0) {
+ return {entry.ToStringView(cd_start), entry.name_offset};
+ }
+ }
+ // We have reached the end of the hash table.
+ return {};
+}
+
+CdEntryMapZip32::CdEntryMapZip32(uint16_t num_entries) {
+ /*
+ * Create hash table. We have a minimum 75% load factor, possibly as
+ * low as 50% after we round off to a power of 2. There must be at
+ * least one unused entry to avoid an infinite loop during creation.
+ */
+ hash_table_size_ = RoundUpPower2(1 + (num_entries * 4) / 3);
+ hash_table_ = {
+ reinterpret_cast<ZipStringOffset*>(calloc(hash_table_size_, sizeof(ZipStringOffset))), free};
+}
+
+std::unique_ptr<CdEntryMapInterface> CdEntryMapZip32::Create(uint16_t num_entries) {
+ auto entry_map = new CdEntryMapZip32(num_entries);
+ CHECK(entry_map->hash_table_ != nullptr)
+ << "Zip: unable to allocate the " << entry_map->hash_table_size_
+ << " entry hash_table, entry size: " << sizeof(ZipStringOffset);
+ return std::unique_ptr<CdEntryMapInterface>(entry_map);
+}
+
+std::unique_ptr<CdEntryMapInterface> CdEntryMapZip64::Create() {
+ return std::unique_ptr<CdEntryMapInterface>(new CdEntryMapZip64());
+}
+
+ZipError CdEntryMapZip64::AddToMap(std::string_view name, const uint8_t* start) {
+ const auto [it, added] =
+ entry_table_.insert({name, name.data() - reinterpret_cast<const char*>(start)});
+ if (!added) {
+ ALOGW("Zip: Found duplicate entry %.*s", static_cast<int>(name.size()), name.data());
+ return kDuplicateEntry;
+ }
+ return kSuccess;
+}
+
+std::pair<ZipError, uint64_t> CdEntryMapZip64::GetCdEntryOffset(std::string_view name,
+ const uint8_t* /*cd_start*/) const {
+ const auto it = entry_table_.find(name);
+ if (it == entry_table_.end()) {
+ ALOGV("Zip: Could not find entry %.*s", static_cast<int>(name.size()), name.data());
+ return {kEntryNotFound, 0};
+ }
+
+ return {kSuccess, it->second};
+}
+
+void CdEntryMapZip64::ResetIteration() {
+ iterator_ = entry_table_.begin();
+}
+
+std::pair<std::string_view, uint64_t> CdEntryMapZip64::Next(const uint8_t* /*cd_start*/) {
+ if (iterator_ == entry_table_.end()) {
+ return {};
+ }
+
+ return *iterator_++;
+}
diff --git a/libziparchive/zip_cd_entry_map.h b/libziparchive/zip_cd_entry_map.h
new file mode 100644
index 0000000..4957f75
--- /dev/null
+++ b/libziparchive/zip_cd_entry_map.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <string_view>
+#include <utility>
+
+#include "zip_error.h"
+
+// This class is the interface of the central directory entries map. The map
+// helps to locate a particular cd entry based on the filename.
+class CdEntryMapInterface {
+ public:
+ virtual ~CdEntryMapInterface() = default;
+ // Adds an entry to the map. The |name| should internally points to the
+ // filename field of a cd entry. And |start| points to the beginning of the
+ // central directory. Returns 0 on success.
+ virtual ZipError AddToMap(std::string_view name, const uint8_t* start) = 0;
+ // For the zip entry |entryName|, finds the offset of its filename field in
+ // the central directory. Returns a pair of [status, offset]. The value of
+ // the status is 0 on success.
+ virtual std::pair<ZipError, uint64_t> GetCdEntryOffset(std::string_view name,
+ const uint8_t* cd_start) const = 0;
+ // Resets the iterator to the beginning of the map.
+ virtual void ResetIteration() = 0;
+ // Returns the [name, cd offset] of the current element. Also increments the
+ // iterator to points to the next element. Returns an empty pair we have read
+ // past boundary.
+ virtual std::pair<std::string_view, uint64_t> Next(const uint8_t* cd_start) = 0;
+};
+
+/**
+ * More space efficient string representation of strings in an mmaped zipped
+ * file than std::string_view. Using std::string_view as an entry in the
+ * ZipArchive hash table wastes space. std::string_view stores a pointer to a
+ * string (on 64 bit, 8 bytes) and the length to read from that pointer,
+ * 2 bytes. Because of alignment, the structure consumes 16 bytes, wasting
+ * 6 bytes.
+ *
+ * ZipStringOffset stores a 4 byte offset from a fixed location in the memory
+ * mapped file instead of the entire address, consuming 8 bytes with alignment.
+ */
+struct ZipStringOffset {
+ uint32_t name_offset;
+ uint16_t name_length;
+
+ const std::string_view ToStringView(const uint8_t* start) const {
+ return std::string_view{reinterpret_cast<const char*>(start + name_offset), name_length};
+ }
+};
+
+// This implementation of CdEntryMap uses an array hash table. It uses less
+// memory than std::map; and it's used as the default implementation for zip
+// archives without zip64 extension.
+class CdEntryMapZip32 : public CdEntryMapInterface {
+ public:
+ static std::unique_ptr<CdEntryMapInterface> Create(uint16_t num_entries);
+
+ ZipError AddToMap(std::string_view name, const uint8_t* start) override;
+ std::pair<ZipError, uint64_t> GetCdEntryOffset(std::string_view name,
+ const uint8_t* cd_start) const override;
+ void ResetIteration() override;
+ std::pair<std::string_view, uint64_t> Next(const uint8_t* cd_start) override;
+
+ private:
+ explicit CdEntryMapZip32(uint16_t num_entries);
+
+ // We know how many entries are in the Zip archive, so we can have a
+ // fixed-size hash table. We define a load factor of 0.75 and over
+ // allocate so the maximum number entries can never be higher than
+ // ((4 * UINT16_MAX) / 3 + 1) which can safely fit into a uint32_t.
+ uint32_t hash_table_size_{0};
+ std::unique_ptr<ZipStringOffset[], decltype(&free)> hash_table_{nullptr, free};
+
+ // The position of element for the current iteration.
+ uint32_t current_position_{0};
+};
+
+// This implementation of CdEntryMap uses a std::map
+class CdEntryMapZip64 : public CdEntryMapInterface {
+ public:
+ static std::unique_ptr<CdEntryMapInterface> Create();
+
+ ZipError AddToMap(std::string_view name, const uint8_t* start) override;
+ std::pair<ZipError, uint64_t> GetCdEntryOffset(std::string_view name,
+ const uint8_t* cd_start) const override;
+ void ResetIteration() override;
+ std::pair<std::string_view, uint64_t> Next(const uint8_t* cd_start) override;
+
+ private:
+ CdEntryMapZip64() = default;
+
+ std::map<std::string_view, uint64_t> entry_table_;
+
+ std::map<std::string_view, uint64_t>::iterator iterator_;
+};
diff --git a/libziparchive/zip_error.h b/libziparchive/zip_error.h
new file mode 100644
index 0000000..44d7221
--- /dev/null
+++ b/libziparchive/zip_error.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+static const char* kErrorMessages[] = {
+ "Success",
+ "Iteration ended",
+ "Zlib error",
+ "Invalid file",
+ "Invalid handle",
+ "Duplicate entries in archive",
+ "Empty archive",
+ "Entry not found",
+ "Invalid offset",
+ "Inconsistent information",
+ "Invalid entry name",
+ "I/O error",
+ "File mapping failed",
+ "Allocation failed",
+};
+
+enum ZipError : int32_t {
+ kSuccess = 0,
+
+ kIterationEnd = -1,
+
+ // We encountered a Zlib error when inflating a stream from this file.
+ // Usually indicates file corruption.
+ kZlibError = -2,
+
+ // The input file cannot be processed as a zip archive. Usually because
+ // it's too small, too large or does not have a valid signature.
+ kInvalidFile = -3,
+
+ // An invalid iteration / ziparchive handle was passed in as an input
+ // argument.
+ kInvalidHandle = -4,
+
+ // The zip archive contained two (or possibly more) entries with the same
+ // name.
+ kDuplicateEntry = -5,
+
+ // The zip archive contains no entries.
+ kEmptyArchive = -6,
+
+ // The specified entry was not found in the archive.
+ kEntryNotFound = -7,
+
+ // The zip archive contained an invalid local file header pointer.
+ kInvalidOffset = -8,
+
+ // The zip archive contained inconsistent entry information. This could
+ // be because the central directory & local file header did not agree, or
+ // if the actual uncompressed length or crc32 do not match their declared
+ // values.
+ kInconsistentInformation = -9,
+
+ // An invalid entry name was encountered.
+ kInvalidEntryName = -10,
+
+ // An I/O related system call (read, lseek, ftruncate, map) failed.
+ kIoError = -11,
+
+ // We were not able to mmap the central directory or entry contents.
+ kMmapFailed = -12,
+
+ // An allocation failed.
+ kAllocationFailed = -13,
+
+ kLastErrorCode = kAllocationFailed,
+};
diff --git a/rootdir/init.rc b/rootdir/init.rc
index fdc9d32..5ebffab 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -16,6 +16,11 @@
# Disable sysrq from keyboard
write /proc/sys/kernel/sysrq 0
+ # Android doesn't need kernel module autoloading, and it causes SELinux
+ # denials. So disable it by setting modprobe to the empty string. Note: to
+ # explicitly set a sysctl to an empty string, a trailing newline is needed.
+ write /proc/sys/kernel/modprobe \n
+
# Set the security context of /adb_keys if present.
restorecon /adb_keys