diff --git a/dex2oat/src/main/cpp/dex2oat.cpp b/dex2oat/src/main/cpp/dex2oat.cpp
index a3e4863d3..f55fe0122 100644
--- a/dex2oat/src/main/cpp/dex2oat.cpp
+++ b/dex2oat/src/main/cpp/dex2oat.cpp
@@ -1,29 +1,9 @@
-/*
- * This file is part of LSPosed.
- *
- * LSPosed is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LSPosed is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with LSPosed. If not, see .
- *
- * Copyright (C) 2022 LSPosed Contributors
- */
-
-//
-// Created by Nullptr on 2022/4/1.
-//
-
-#include
-#include
-#include
+#include
+#include
+#include
+#include
+
+// POSIX/Linux headers
#include
#include
#include
@@ -36,79 +16,84 @@
#define LP_SELECT(lp32, lp64) lp32
#endif
-#define ID_VEC(is64, is_debug) (((is64) << 1) | (is_debug))
+constexpr int id_vec(bool is64, bool is_debug) { return ((is64 << 1) | is_debug); }
+
+// An anonymous namespace is used to limit the scope of helper functions and constants
+// to this file, which is the C++ equivalent of the `static` keyword for free functions.
+namespace {
+// The abstract socket name for communication.
const char kSockName[] = "5291374ceda0aef7c5d86cd2a4f6a3ac\0";
-static ssize_t xrecvmsg(int sockfd, struct msghdr *msg, int flags) {
- int rec = recvmsg(sockfd, msg, flags);
+ssize_t xrecvmsg(int sockfd, struct msghdr* msg, int flags) {
+ ssize_t rec = recvmsg(sockfd, msg, flags);
if (rec < 0) {
PLOGE("recvmsg");
}
return rec;
}
-static void *recv_fds(int sockfd, char *cmsgbuf, size_t bufsz, int cnt) {
- struct iovec iov = {
- .iov_base = &cnt,
- .iov_len = sizeof(cnt),
- };
+void* recv_fds(int sockfd, char* cmsgbuf, size_t bufsz, int cnt) {
+ struct iovec iov = {.iov_base = &cnt, .iov_len = sizeof(cnt)};
struct msghdr msg = {
.msg_iov = &iov, .msg_iovlen = 1, .msg_control = cmsgbuf, .msg_controllen = bufsz};
xrecvmsg(sockfd, &msg, MSG_WAITALL);
- struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
+ struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
- if (msg.msg_controllen != bufsz || cmsg == NULL ||
+ if (msg.msg_controllen != bufsz || cmsg == nullptr ||
cmsg->cmsg_len != CMSG_LEN(sizeof(int) * cnt) || cmsg->cmsg_level != SOL_SOCKET ||
cmsg->cmsg_type != SCM_RIGHTS) {
- return NULL;
+ return nullptr;
}
return CMSG_DATA(cmsg);
}
-static int recv_fd(int sockfd) {
+int recv_fd(int sockfd) {
char cmsgbuf[CMSG_SPACE(sizeof(int))];
- void *data = recv_fds(sockfd, cmsgbuf, sizeof(cmsgbuf), 1);
- if (data == NULL) return -1;
+ void* data = recv_fds(sockfd, cmsgbuf, sizeof(cmsgbuf), 1);
+ if (data == nullptr) return -1;
int result;
memcpy(&result, data, sizeof(int));
return result;
}
-static int read_int(int fd) {
+int read_int(int fd) {
int val;
if (read(fd, &val, sizeof(val)) != sizeof(val)) return -1;
return val;
}
-static void write_int(int fd, int val) {
+void write_int(int fd, int val) {
if (fd < 0) return;
write(fd, &val, sizeof(val));
}
-int main(int argc, char **argv) {
+} // namespace
+
+int main(int argc, char** argv) {
LOGD("dex2oat wrapper ppid=%d", getppid());
- struct sockaddr_un sock = {};
+
+ struct sockaddr_un sock{};
sock.sun_family = AF_UNIX;
strlcpy(sock.sun_path + 1, kSockName, sizeof(sock.sun_path) - 1);
int sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
size_t len = sizeof(sa_family_t) + strlen(sock.sun_path + 1) + 1;
- if (connect(sock_fd, (struct sockaddr *)&sock, len)) {
+ if (connect(sock_fd, reinterpret_cast(&sock), len)) {
PLOGE("failed to connect to %s", sock.sun_path + 1);
return 1;
}
- write_int(sock_fd, ID_VEC(LP_SELECT(0, 1), strstr(argv[0], "dex2oatd") != NULL));
+ write_int(sock_fd, id_vec(LP_SELECT(0, 1), strstr(argv[0], "dex2oatd") != nullptr));
int stock_fd = recv_fd(sock_fd);
read_int(sock_fd);
close(sock_fd);
sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (connect(sock_fd, (struct sockaddr *)&sock, len)) {
+ if (connect(sock_fd, reinterpret_cast(&sock), len)) {
PLOGE("failed to connect to %s", sock.sun_path + 1);
return 1;
}
@@ -122,27 +107,34 @@ int main(int argc, char **argv) {
}
LOGD("sock: %s %d", sock.sun_path + 1, stock_fd);
- const char *new_argv[argc + 2];
- for (int i = 0; i < argc; i++) new_argv[i] = argv[i];
- new_argv[argc] = "--inline-max-code-units=0";
- new_argv[argc + 1] = NULL;
+ // Use std::vector for safer and more flexible argument list management.
+ std::vector new_argv;
+ for (int i = 0; i < argc; ++i) {
+ new_argv.push_back(argv[i]);
+ }
+ new_argv.push_back("--inline-max-code-units=0");
+ new_argv.push_back(nullptr); // execve requires a null-terminated array.
- if (getenv("LD_LIBRARY_PATH") == NULL) {
- char const *libenv = LP_SELECT(
+ if (getenv("LD_LIBRARY_PATH") == nullptr) {
+ const char* libenv = LP_SELECT(
"LD_LIBRARY_PATH=/apex/com.android.art/lib:/apex/com.android.os.statsd/lib",
"LD_LIBRARY_PATH=/apex/com.android.art/lib64:/apex/com.android.os.statsd/lib64");
- putenv((char *)libenv);
+ // The putenv function is a legacy C API that requires a char*.
+ // A const_cast is necessary here.
+ putenv(const_cast(libenv));
}
- // Set LD_PRELOAD to load liboat_hook.so
- const int STRING_BUFFER = 50;
- char env_str[STRING_BUFFER];
- snprintf(env_str, STRING_BUFFER, "LD_PRELOAD=/proc/%d/fd/%d", getpid(), hooker_fd);
- putenv(env_str);
- LOGD("Set env %s", env_str);
+ // Use std::string for safe and easy string construction.
+ std::string ld_preload_env =
+ "LD_PRELOAD=/proc/" + std::to_string(getpid()) + "/fd/" + std::to_string(hooker_fd);
+ // putenv(const_cast(ld_preload_env.c_str()));
+ LOGD("[dry_run] Set env %s", ld_preload_env.c_str());
- fexecve(stock_fd, (char **)new_argv, environ);
+ // fexecve requires a non-const char* array. We must use const_cast to match the
+ // required signature, as is common when interfacing modern C++ with older C APIs.
+ fexecve(stock_fd, const_cast(new_argv.data()), environ);
+ // This part is only reached if fexecve fails.
PLOGE("fexecve failed");
return 2;
}