From 2bd3287fc28dfc0b0bbc0efbc798082defc762c1 Mon Sep 17 00:00:00 2001 From: JingMatrix Date: Sat, 16 Aug 2025 01:37:57 +0200 Subject: [PATCH 1/2] Update to cpp syntax --- dex2oat/src/main/cpp/dex2oat.cpp | 114 ++++++++++++++----------------- 1 file changed, 53 insertions(+), 61 deletions(-) diff --git a/dex2oat/src/main/cpp/dex2oat.cpp b/dex2oat/src/main/cpp/dex2oat.cpp index a3e4863d3..e8ba24b0d 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("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; } From 6a21b935398a327b6e4fd0168e744dfbdb89cac3 Mon Sep 17 00:00:00 2001 From: JingMatrix Date: Wed, 3 Sep 2025 17:54:54 +0200 Subject: [PATCH 2/2] Temporally disable oat hook for debugging We need testers to confirm if recent problems of `dex2oat` are caused by the `oat` hook. --- dex2oat/src/main/cpp/dex2oat.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dex2oat/src/main/cpp/dex2oat.cpp b/dex2oat/src/main/cpp/dex2oat.cpp index e8ba24b0d..f55fe0122 100644 --- a/dex2oat/src/main/cpp/dex2oat.cpp +++ b/dex2oat/src/main/cpp/dex2oat.cpp @@ -127,8 +127,8 @@ int main(int argc, char** argv) { // 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("Set env %s", ld_preload_env.c_str()); + // putenv(const_cast(ld_preload_env.c_str())); + LOGD("[dry_run] Set env %s", ld_preload_env.c_str()); // 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.