[core] Delete native config manager

This commit is contained in:
LoveSy 2021-02-16 20:09:51 +08:00 committed by tehcneko
parent 2890aec54f
commit 374c8cac11
53 changed files with 403 additions and 1273 deletions

View File

@ -3,9 +3,17 @@ package io.github.lsposed.lspd.service;
interface ILSPApplicationService {
void registerHeartBeat(IBinder handle) = 1;
int getVariant() = 2;
IBinder requestModuleBinder() = 2;
IBinder requestModuleBinder() = 3;
IBinder requestManagerBinder() = 3;
IBinder requestManagerBinder() = 4;
int getVariant() = 4;
boolean isResourcesHookEnabled() = 5;
List<String> getModulesList() = 6;
String getPrefsPath(String packageName) = 7;
String getCachePath(String fileName) = 8;
}

View File

@ -21,7 +21,6 @@
#pragma once
#include <base/object.h>
#include <config_manager.h>
namespace art {

View File

@ -51,6 +51,7 @@ inline constexpr bool is64 = Is64();
static const auto kEntryClassName = "io.github.lsposed.lspd.core.Main"s;
static const auto kClassLinkerClassName = "io.github.lsposed.lspd.nativebridge.ClassLinker"s;
static const auto kBridgeServiceClassName = "io.github.lsposed.lspd.service.BridgeService"s;
static const auto kDexPath = "/data/adb/lspd/framework/lspd.dex"s;
static const auto kSandHookClassName = "com.swift.sandhook.SandHook"s;
static const auto kSandHookNeverCallClassName = "com.swift.sandhook.ClassNeverCall"s;

View File

@ -1,355 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* Copyright (C) 2020 EdXposed Contributors
* Copyright (C) 2021 LSPosed Contributors
*/
#include <cstdio>
#include <dirent.h>
#include <unistd.h>
#include <jni.h>
#include <cstdlib>
#include <array>
#include <thread>
#include <vector>
#include <string>
#include <logging.h>
#include <climits>
#include <fstream>
#include <sstream>
#include "art/runtime/native/native_util.h"
#include "config_manager.h"
#include "utils.h"
#include "rirud_socket.h"
/*
* Logic:
* check if /data/adb/lspd exists and is readable, if so, read misc_path and the config base path is
* /data/misc/$misc_path; if not so, fall back to the installer's path
* config manager is const. and it should be updated if the module list is updated
* each user owns one config manager
* before the process started, update current user
* module list and modules scopes are preloaded
* can get app module list by call a const function
* for installer's pkg name, it's retrieved by /data/misc/$misc_path/$uid/conf/installer.
*
* Permission:
* /data/adb/lspd should be accessible by zygote by sepolicy
* /data/misc/$misc_path is random path, and mounted by magisk
* it should have context `u:object_r:magisk_file:s0`, which should be readable by normal app
* and zygote
*
* /data/misc/$misc_path's owner should be root:root, with permission 771
* so does /data/misc/$misc_path/$uid
* /data/misc/$misc_path/$uid/conf should be um:root, with permission 770
* where um is the user of manager
* /data/misc/$misc_path/$uid/prefs should be root:root, with permission 771
* /data/misc/$misc_path/$uid/prefs/$pkg should be up:root, with permission 771
* this path is used for XSharePreference, where up is the user of package $pkg
* other's permission is 5 because it should be read by all the other apps but not writable
* it's only writeable by $pkg itself
* root group's 7 permission's for updating the permission & deleting it
*
* Initialization:
* This is only done for config path in /data/misc
* check if /data/misc/$misc_path/$uid exists. if not create one with 771
* check if /data/misc/$misc_path/$uid/conf exists. if not create one with 770
* check if /data/misc/$misc_path/$uid/prefs exists. if not create one with 771
*
*
* when the launching app is installer, change the user owner of /data/misc/$misc_path/$uid/conf
* to be the installer, and change the permission to be 770
*
* when the launching app is in the module lists, ensure existence of
* /data/misc/$misc_path/$uid/prefs/$pkg
* with the owner the user of the pkg and permission 774
* if this paths exists but with different owner, delete it recursively and create a new one
* this is when package reinstalled
* but I heard that some devices change uid when upgrading system, so I didn't do this
*
* Side effect:
* data exists if the module uninstalled
* One way to release the storage space is to uninstall lspd
* because /data/misc/$misc_path is mounted by magisk.
*
* lspd works without manager
*
* uninstall removes all configs (this can be restored if manager store another copy
* of the conf on its own data dir)
*
*/
namespace lspd {
namespace fs = std::filesystem;
fs::path ConfigManager::RetrieveBaseConfigPath() const {
if (!misc_path_.empty()) {
return misc_path_ / std::to_string(user_);
} else {
return {};
}
}
std::string ConfigManager::RetrieveInstallerPkgName() const {
std::string installer_pkg_name_path = GetConfigPath("installer");
if (!path_exists<true>(installer_pkg_name_path)) {
LOGW("installer not set, using default one %s", kPrimaryInstallerPkgName.c_str());
return kPrimaryInstallerPkgName;
}
std::ifstream ifs(installer_pkg_name_path);
if (!ifs.good()) {
LOGW("cannot access %s, using default one %s", installer_pkg_name_path.c_str(),
kPrimaryInstallerPkgName.c_str());
return kPrimaryInstallerPkgName;
}
return {std::istream_iterator<char>(ifs), std::istream_iterator<char>()};
}
std::string ConfigManager::GetPackageNameFromBaseApkPath(const fs::path &path) {
std::vector<std::string> paths(path.begin(), path.end());
if (paths.empty()) return {};
auto base_apk = paths.back(); // base.apk
if (base_apk != "base.apk") return {};
paths.pop_back();
auto pkg_name_with_obfuscation = paths.back();
if (auto pos = pkg_name_with_obfuscation.find('-'); pos != std::string::npos) {
return pkg_name_with_obfuscation.substr(0, pos);
}
return {};
}
ConfigManager::ConfigManager(uid_t user, bool initialized) :
user_(user),
data_path_prefix_(fs::path("/data/user_de") /
std::to_string(user_)),
base_config_path_(RetrieveBaseConfigPath()),
initialized_(initialized || InitConfigPath()),
installer_pkg_name_(RetrieveInstallerPkgName()),
no_module_log_enabled_(path_exists(GetConfigPath("disable_modules_log"))),
resources_hook_enabled_(path_exists(GetConfigPath("enable_resources"))),
modules_list_(GetModuleList()),
last_write_time_(GetLastWriteTime()),
variant_(ReadInt(GetVariantPath())),
selinux_permissive_(ReadInt(GetSelinuxStatusPath()) != 1) {
LOGI("base config path: %s", base_config_path_.c_str());
LOGI(" using installer package name: %s", installer_pkg_name_.c_str());
LOGI(" no module log: %s", BoolToString(no_module_log_enabled_));
LOGI(" resources hook: %s", BoolToString(resources_hook_enabled_));
LOGI(" selinux permissive: %s", BoolToString(selinux_permissive_));
LOGI(" module list: \n %s", ([this]() {
std::ostringstream join;
std::vector<std::string> module_list;
std::transform(modules_list_.begin(), modules_list_.end(),
std::back_inserter(module_list),
[](auto i) { return i.first; });
std::copy(module_list.begin(), module_list.end(),
std::ostream_iterator<std::string>(join, "\n"));
return join.str();
})().c_str());
}
int ConfigManager::ReadInt(const fs::path &dir) {
if (!path_exists(dir)) {
return 0;
}
std::ifstream ifs(dir);
if (!ifs.good()) {
return 0;
}
int result;
ifs >> result;
return result;
}
auto ConfigManager::GetModuleList() -> std::remove_const_t<decltype(modules_list_)> {
std::remove_const_t<decltype(modules_list_)> modules_list;
auto global_modules_list = GetConfigPath("modules.list");
if (!path_exists(global_modules_list)) {
LOGE("Cannot access path %s", global_modules_list.c_str());
return modules_list;
}
std::ifstream ifs(global_modules_list);
if (!ifs.good()) {
LOGE("Cannot access path %s", global_modules_list.c_str());
return modules_list;
}
std::string module;
while (std::getline(ifs, module)) {
const auto &module_pkg_name = GetPackageNameFromBaseApkPath(module);
auto &[module_path, scope] = modules_list[module_pkg_name];
scope.insert(module_pkg_name); // Always add module itself
module_path.assign(std::move(module));
const auto &module_scope_conf = GetConfigPath(module_pkg_name + ".conf");
if (!path_exists<true>(module_scope_conf)) {
LOGD("module scope is not set for %s", module_pkg_name.c_str());
continue;
}
std::ifstream ifs_c(module_scope_conf);
if (!ifs_c.good()) {
LOGE("Cannot access path %s", module_scope_conf.c_str());
continue;
}
std::string app_pkg_name;
while (std::getline(ifs_c, app_pkg_name)) {
if (!app_pkg_name.empty())
scope.emplace(std::move(app_pkg_name));
}
if (IsInstaller(module_pkg_name)) scope.erase("android");
LOGI("scope of %s is:\n %s", module_pkg_name.c_str(), ([&scope = scope]() {
std::ostringstream join;
std::copy(scope.begin(), scope.end(),
std::ostream_iterator<std::string>(join, "\n "));
return join.str();
})().c_str());
}
return modules_list;
}
std::vector<std::string> ConfigManager::GetAppModuleList(const std::string &pkg_name) const {
std::vector<std::string> app_modules_list;
for (const auto&[module, scope]: modules_list_) {
if (scope.second.count(pkg_name))
app_modules_list.push_back(scope.first);
}
return app_modules_list;
}
fs::file_time_type ConfigManager::GetLastWriteTime() const {
auto last_write_time = [](std::string_view path) __attribute__((always_inline)) {
return path_exists<true>(path) ? fs::last_write_time(path) : fs::file_time_type{};
};
std::string config_path = GetConfigPath();
std::string list_path = GetConfigPath("modules.list");
std::string variant_path = GetVariantPath();
return std::max({
last_write_time(config_path),
last_write_time(list_path),
last_write_time(variant_path)
});
}
bool ConfigManager::InitConfigPath() const {
if (base_config_path_.empty()) return false;
try {
fs::create_directories(base_config_path_);
fs::permissions(misc_path_,
fs::perms::owner_all | fs::perms::group_all | fs::perms::others_exec);
fs::permissions(base_config_path_,
fs::perms::owner_all | fs::perms::group_all | fs::perms::others_exec);
fs::create_directories(GetLogPath());
fs::permissions(GetLogPath(),
fs::perms::owner_all | fs::perms::group_all | fs::perms::others_exec);
fs::create_directories(GetConfigPath());
fs::permissions(GetConfigPath(), fs::perms::owner_all | fs::perms::group_all);
fs::create_directories(GetPrefsPath(""));
fs::permissions(GetPrefsPath(""),
fs::perms::owner_all | fs::perms::group_all | fs::perms::others_exec);
auto log_path = GetLogPath();
auto modules_log_path = GetModulesLogPath();
if (!fs::is_directory(log_path)) {
fs::remove(log_path);
}
if (!path_exists(log_path)) {
fs::create_directories(modules_log_path);
}
if (!path_exists<true>(modules_log_path)) {
std::ofstream(modules_log_path, std::ios::out);
}
fs::permissions(log_path,
fs::perms::owner_all | fs::perms::group_all | fs::perms::others_all);
recursive_permissions(log_path,
fs::perms::owner_read | fs::perms::owner_write |
fs::perms::group_read |
fs::perms::group_write | fs::perms::others_read |
fs::perms::others_write, fs::perm_options::add);
} catch (const fs::filesystem_error &e) {
LOGE("init: %s", e.what());
return false;
}
return true;
}
void ConfigManager::EnsurePermission(const std::string &pkg_name, uid_t uid) const {
if (!initialized_) return;
try {
if (modules_list_.count(pkg_name)) {
auto prefs_path = GetPrefsPath(pkg_name);
if (!path_exists<true>(prefs_path)) {
fs::create_directories(prefs_path);
} else {
const auto &[r_uid, r_gid] = path_own(prefs_path);
if (r_uid != uid) {
fs::remove_all(prefs_path);
fs::create_directories(prefs_path);
}
}
fs::permissions(prefs_path, fs::perms::owner_all | fs::perms::group_all |
fs::perms::others_exec | fs::perms::set_gid);
if (const auto &[r_uid, r_gid] = path_own(prefs_path);
(uid != -1 && r_uid != uid) || r_gid != 1000u) {
path_chown(prefs_path, uid, 1000u, false);
}
}
if (IsInstaller(pkg_name) || pkg_name == "android") {
auto conf_path = GetConfigPath();
if (!path_exists<true>(conf_path)) {
fs::create_directories(conf_path);
}
recursive_permissions(conf_path, fs::perms::owner_all | fs::perms::group_all |
fs::perms::set_gid);
if (pkg_name == "android") uid = -1;
path_chown(conf_path, uid, 1000u, true);
if (current_user_ == 0) {
auto variant = GetVariantPath();
fs::permissions(variant, fs::perms::owner_all | fs::perms::group_all);
path_chown(variant, uid, 1000u);
auto disable_verbose_log = misc_path_ / "disable_verbose_log";
fs::permissions(disable_verbose_log,
fs::perms::owner_all | fs::perms::group_all);
path_chown(disable_verbose_log, uid, 1000u);
}
if (pkg_name == kPrimaryInstallerPkgName) {
umask(0007);
auto installer_pkg_name_path = GetConfigPath("installer");
if (path_exists<true>(installer_pkg_name_path)) {
fs::remove(installer_pkg_name_path);
}
}
}
} catch (const fs::filesystem_error &e) {
LOGE("%s", e.what());
}
}
void ConfigManager::Init() {
fs::path misc_path("/data/adb/lspd/misc_path");
try {
RirudSocket rirud_socket{};
auto path = rirud_socket.ReadFile(misc_path);
path.erase(std::find_if(path.rbegin(), path.rend(), [](unsigned char ch) {
return !std::isspace(ch);
}).base(), path.end());
misc_path_ = fs::path("/data/misc") / path;
inject_dex_path_ = GetFrameworkPath(kXposedInjectDexPath);
LOGI("Got base config path: %s", misc_path_.c_str());
} catch (const RirudSocket::RirudSocketException &e) {
LOGE("%s", e.what());
}
}
}

View File

@ -1,172 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* Copyright (C) 2020 EdXposed Contributors
* Copyright (C) 2021 LSPosed Contributors
*/
#pragma once
#include <vector>
#include <string>
#include "JNIHelper.h"
#include <utility>
#include <art/runtime/native/native_util.h>
#include <filesystem>
#include <unordered_set>
#include <unordered_map>
#include "config.h"
#include "utils.h"
namespace lspd {
class ConfigManager {
private:
inline static const auto kPrimaryInstallerPkgName = "io.github.lsposed.manager"s;
inline static const auto kXposedInjectDexPath = "lspd.dex";
public:
static void Init();
inline static ConfigManager *GetInstance() {
return instances_[current_user_].get();
}
inline auto IsInitialized() const { return initialized_; }
inline static void SetCurrentUser(uid_t user) {
if (auto instance = instances_.find(user);
instance == instances_.end() || !instance->second) {
instances_[user] = std::make_unique<ConfigManager>(user);
} else if (instance->second->NeedUpdateConfig()) {
instances_[user] = std::make_unique<ConfigManager>(user,
instance->second->IsInitialized());
}
current_user_ = user;
}
inline static auto ReleaseInstances() {
return std::move(instances_);
}
inline const auto &GetVariant() const { return variant_; }
inline const auto &IsResourcesHookEnabled() const { return resources_hook_enabled_; }
inline const auto &IsNoModuleLogEnabled() const { return no_module_log_enabled_; }
inline const auto &GetInstallerPackageName() const { return installer_pkg_name_; }
inline const auto &GetDataPathPrefix() const { return data_path_prefix_; }
inline static const auto &GetMiscPath() { return misc_path_; }
inline static auto GetFrameworkPath(const std::string &suffix = {}) {
return misc_path_ / "framework" / suffix;
}
inline static auto GetCachePath(const std::string &suffix = {}) {
return misc_path_ / "cache" / suffix;
}
inline auto GetConfigPath(const std::string &suffix = {}) const {
return base_config_path_ / "conf" / suffix;
}
inline static auto GetLogPath(const std::string &suffix = {}) {
return misc_path_ / "log" / suffix;
}
inline const auto &GetBaseConfigPath() const { return base_config_path_; }
inline auto GetPrefsPath(const std::string &pkg_name) const {
return base_config_path_ / "prefs" / pkg_name;
}
inline static auto GetVariantPath() {
return misc_path_ / "variant";
}
inline static std::filesystem::path GetSelinuxStatusPath() {
return "/sys/fs/selinux/enforce";
}
inline static auto GetModulesLogPath() {
return GetLogPath("modules.log");
}
std::vector<std::string> GetAppModuleList(const std::string &pkg_name) const;
bool NeedUpdateConfig() const {
return last_write_time_ < GetLastWriteTime();
}
void EnsurePermission(const std::string &pkg_name, uid_t uid) const;
static const auto &GetInjectDexPath() { return inject_dex_path_; };
bool IsInstaller(const std::string &pkg_name) const {
return pkg_name == installer_pkg_name_ || pkg_name == kPrimaryInstallerPkgName;
}
bool IsPermissive() const {
return selinux_permissive_;
}
private:
inline static std::unordered_map<uid_t, std::unique_ptr<ConfigManager>> instances_{};
inline static uid_t current_user_ = 0u;
inline static std::filesystem::path misc_path_; // /data/misc/lspd_xxxx
inline static std::filesystem::path inject_dex_path_;
const uid_t user_;
const int variant_;
const std::filesystem::path data_path_prefix_; // /data/user_de/{user}
const std::filesystem::path base_config_path_; // /data/misc/lspd_xxxx/{user}
const bool initialized_ = false;
const std::filesystem::path installer_pkg_name_;
const bool no_module_log_enabled_ = false;
const bool resources_hook_enabled_ = false;
const bool selinux_permissive_ = false;
const std::unordered_map<std::string, std::pair<std::string, std::unordered_set<std::string>>> modules_list_;
const std::filesystem::file_time_type last_write_time_;
ConfigManager(uid_t uid, bool initialized = false);
std::string RetrieveInstallerPkgName() const;
static std::string GetPackageNameFromBaseApkPath(const std::filesystem::path &path);
std::remove_const_t<decltype(modules_list_)> GetModuleList();
std::filesystem::file_time_type GetLastWriteTime() const;
bool InitConfigPath() const;
friend std::unique_ptr<ConfigManager> std::make_unique<ConfigManager>(uid_t &);
friend std::unique_ptr<ConfigManager> std::make_unique<ConfigManager>(uid_t &, bool &&);
std::filesystem::path RetrieveBaseConfigPath() const;
static int ReadInt(const std::filesystem::path &dir);
};
} // namespace lspd

View File

@ -21,7 +21,6 @@
#include <jni.h>
#include <android-base/macros.h>
#include "JNIHelper.h"
#include "jni/config_manager.h"
#include "jni/art_class_linker.h"
#include "jni/yahfa.h"
#include "jni/resources_hook.h"
@ -32,12 +31,13 @@
#include <sandhook.h>
#include <fstream>
#include <sstream>
#include <nativehelper/scoped_local_ref.h>
#include "context.h"
#include "config_manager.h"
#include "native_hook.h"
#include "jni/logger.h"
#include "jni/native_api.h"
#include "service.h"
#include "rirud_socket.h"
namespace lspd {
namespace fs = std::filesystem;
@ -66,13 +66,14 @@ namespace lspd {
void Context::PreLoadDex(const fs::path &dex_path) {
if (LIKELY(!dex.empty())) return;
std::ifstream is(dex_path, std::ios::binary);
if (!is.good()) {
LOGE("Cannot load path %s", dex_path.c_str());
try {
RirudSocket socket;
auto dex_content = socket.ReadFile(dex_path);
dex.assign(dex_content.begin(), dex_content.end());
} catch (RirudSocket::RirudSocketException &e) {
LOGE("%s", e.what());
return;
}
dex.assign(std::istreambuf_iterator<char>(is),
std::istreambuf_iterator<char>());
LOGI("Loaded %s with size %zu", dex_path.c_str(), dex.size());
}
@ -108,9 +109,6 @@ namespace lspd {
env->DeleteLocalRef(my_cl);
env->GetJavaVM(&vm_);
// Make sure config manager is always working
RegisterConfigManagerMethods(env);
}
void Context::Init(JNIEnv *env) {
@ -193,7 +191,6 @@ namespace lspd {
void
Context::OnNativeForkSystemServerPre(JNIEnv *env) {
Service::instance()->InitService(env);
PreLoadDex(ConfigManager::GetInjectDexPath());
skip_ = false;
}
@ -226,7 +223,6 @@ namespace lspd {
jstring nice_name,
jboolean is_child_zygote,
jstring app_data_dir) {
PreLoadDex(ConfigManager::GetInjectDexPath());
Service::instance()->InitService(env);
const auto app_id = uid % PER_USER_RANGE;
nice_name_ = nice_name;

View File

@ -64,6 +64,7 @@ namespace lspd {
void OnNativeForkSystemServerPre(JNIEnv *env);
void PreLoadDex(const std::filesystem::path &dex_paths);
private:
inline static std::unique_ptr<Context> instance_ = std::make_unique<Context>();
@ -79,8 +80,6 @@ namespace lspd {
Context() {}
void PreLoadDex(const std::filesystem::path &dex_paths);
void LoadDex(JNIEnv *env);
void Init(JNIEnv *env);

View File

@ -24,6 +24,7 @@
#include <nativehelper/jni_macros.h>
#include <vector>
#include <HookMain.h>
#include <unordered_set>
#include "art_class_linker.h"
namespace lspd {

View File

@ -1,103 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* Copyright (C) 2020 EdXposed Contributors
* Copyright (C) 2021 LSPosed Contributors
*/
#include <config_manager.h>
#include <nativehelper/jni_macros.h>
#include <native_util.h>
#include <sstream>
#include "config_manager.h"
namespace lspd {
LSP_DEF_NATIVE_METHOD(jboolean, ConfigManager, isResourcesHookEnabled) {
return (jboolean) ConfigManager::GetInstance()->IsResourcesHookEnabled();
}
LSP_DEF_NATIVE_METHOD(jstring, ConfigManager, getInstallerPackageName) {
return env->NewStringUTF(ConfigManager::GetInstance()->GetInstallerPackageName().c_str());
}
LSP_DEF_NATIVE_METHOD(jstring, ConfigManager, getDataPathPrefix) {
return env->NewStringUTF(ConfigManager::GetInstance()->GetDataPathPrefix().c_str());
}
LSP_DEF_NATIVE_METHOD(jstring, ConfigManager, getLogPath) {
return env->NewStringUTF(ConfigManager::GetLogPath().c_str());
}
LSP_DEF_NATIVE_METHOD(jstring, ConfigManager, getConfigPath, jstring jSuffix) {
const char *suffix = env->GetStringUTFChars(jSuffix, JNI_FALSE);
auto result = ConfigManager::GetInstance()->GetConfigPath(suffix);
env->ReleaseStringUTFChars(jSuffix, suffix);
return env->NewStringUTF(result.c_str());
}
LSP_DEF_NATIVE_METHOD(jstring, ConfigManager, getPrefsPath, jstring jSuffix) {
const char *suffix = env->GetStringUTFChars(jSuffix, JNI_FALSE);
auto result = ConfigManager::GetInstance()->GetPrefsPath(suffix);
env->ReleaseStringUTFChars(jSuffix, suffix);
return env->NewStringUTF(result.c_str());
}
LSP_DEF_NATIVE_METHOD(jstring, ConfigManager, getCachePath, jstring jSuffix) {
const char *suffix = env->GetStringUTFChars(jSuffix, JNI_FALSE);
auto result = ConfigManager::GetCachePath(suffix);
env->ReleaseStringUTFChars(jSuffix, suffix);
return env->NewStringUTF(result.c_str());
}
LSP_DEF_NATIVE_METHOD(jstring, ConfigManager, getBaseConfigPath) {
auto result = ConfigManager::GetInstance()->GetBaseConfigPath();
return env->NewStringUTF(result.c_str());
}
LSP_DEF_NATIVE_METHOD(jstring, ConfigManager, getMiscPath) {
auto result = ConfigManager::GetMiscPath();
return env->NewStringUTF(result.c_str());
}
LSP_DEF_NATIVE_METHOD(jstring, ConfigManager, getModulesList) {
return nullptr;
}
LSP_DEF_NATIVE_METHOD(jboolean, ConfigManager, isPermissive) {
return ConfigManager::GetInstance()->IsPermissive();
}
static JNINativeMethod gMethods[] = {
LSP_NATIVE_METHOD(ConfigManager, isResourcesHookEnabled, "()Z"),
LSP_NATIVE_METHOD(ConfigManager, getInstallerPackageName, "()Ljava/lang/String;"),
LSP_NATIVE_METHOD(ConfigManager, getDataPathPrefix, "()Ljava/lang/String;"),
LSP_NATIVE_METHOD(ConfigManager, getMiscPath, "()Ljava/lang/String;"),
LSP_NATIVE_METHOD(ConfigManager, getLogPath, "()Ljava/lang/String;"),
LSP_NATIVE_METHOD(ConfigManager, getPrefsPath,
"(Ljava/lang/String;)Ljava/lang/String;"),
LSP_NATIVE_METHOD(ConfigManager, getCachePath,
"(Ljava/lang/String;)Ljava/lang/String;"),
LSP_NATIVE_METHOD(ConfigManager, getBaseConfigPath, "()Ljava/lang/String;"),
LSP_NATIVE_METHOD(ConfigManager, getModulesList, "()Ljava/lang/String;"),
LSP_NATIVE_METHOD(ConfigManager, isPermissive, "()Z"),
};
void RegisterConfigManagerMethods(JNIEnv *env) {
REGISTER_LSP_NATIVE_METHODS(ConfigManager);
}
}

View File

@ -1,29 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* Copyright (C) 2020 EdXposed Contributors
* Copyright (C) 2021 LSPosed Contributors
*/
#pragma once
#include "jni.h"
namespace lspd {
void RegisterConfigManagerMethods(JNIEnv *env);
}

View File

@ -22,22 +22,22 @@
#include "nativehelper/jni_macros.h"
#include "native_util.h"
#include "JNIHelper.h"
#include "../config_manager.h"
#include <fstream>
#include <fcntl.h>
namespace lspd {
LSP_DEF_NATIVE_METHOD(void, Logger, nativeLog, jstring jstr) {
static int fd = open(ConfigManager::GetModulesLogPath().c_str(), O_APPEND | O_WRONLY);
if (fd < 0) {
LOGD("Logger fail: %s", strerror(errno));
return;
}
JUTFString str(env, jstr);
int res = write(fd, str.get(), std::strlen(str.get()));
if (res < 0) {
LOGD("Logger fail: %s", strerror(errno));
}
// TODO: get log path
// static int fd = open(ConfigManager::GetModulesLogPath().c_str(), O_APPEND | O_WRONLY);
// if (fd < 0) {
// LOGD("Logger fail: %s", strerror(errno));
// return;
// }
// JUTFString str(env, jstr);
// int res = write(fd, str.get(), std::strlen(str.get()));
// if (res < 0) {
// LOGD("Logger fail: %s", strerror(errno));
// }
}
static JNINativeMethod gMethods[] = {

View File

@ -26,15 +26,14 @@
#include "config.h"
#include "context.h"
#include <riru.h>
#include "config_manager.h"
#include "symbol_cache.h"
namespace lspd {
static void onModuleLoaded() {
LOGI("onModuleLoaded: welcome to LSPosed!");
// rirud must be used in onModuleLoaded
Context::GetInstance()->PreLoadDex(kDexPath);
InitSymbolCache();
ConfigManager::Init();
}
static int shouldSkipUid(int) {

View File

@ -21,7 +21,6 @@
#include <dlfcn.h>
#include <string>
#include <vector>
#include <config_manager.h>
#include <art/runtime/runtime.h>
#include <dl_util.h>
#include <art/runtime/jni_env_ext.h>

View File

@ -152,8 +152,10 @@ namespace lspd {
jobject service = nullptr;
if (res) {
JNI_CallVoidMethod(env, reply, readExceptionMethod_);
service = JNI_CallObjectMethod(env, reply, readStrongBinderMethod_);
env->CallVoidMethod(reply, readExceptionMethod_);
if (!ClearException(env)) {
service = JNI_CallObjectMethod(env, reply, readStrongBinderMethod_);
}
}
JNI_CallVoidMethod(env, data, recycleMethod_);
JNI_CallVoidMethod(env, reply, recycleMethod_);

View File

@ -52,6 +52,8 @@ import java.util.Set;
import de.robv.android.xposed.services.FileResult;
import static io.github.lsposed.lspd.config.LSPApplicationServiceClient.serviceClient;
/**
* This class is basically the same as SharedPreferencesImpl from AOSP, but
* read-only and without listeners support. Instead, it is made to be
@ -180,8 +182,9 @@ public final class XSharedPreferences implements SharedPreferences {
newModule = isModule && (xposedminversion > 92 || xposedsharedprefs);
}
}
if (newModule && XposedInit.prefsBasePath != null) {
mFile = new File(XposedInit.prefsBasePath, packageName + "/" + prefFileName + ".xml");
if (newModule) {
mFile = new File(serviceClient.getPrefsPath( packageName ), prefFileName + ".xml");
} else {
mFile = new File(Environment.getDataDirectory(), "data/" + packageName + "/shared_prefs/" + prefFileName + ".xml");
}
@ -198,7 +201,8 @@ public final class XSharedPreferences implements SharedPreferences {
Path path = mFile.toPath();
try {
if (sWatcher == null) {
sWatcher = new File(XposedInit.prefsBasePath).toPath().getFileSystem().newWatchService();
// TODO
// sWatcher = new File(XposedInit.prefsBasePath).toPath().getFileSystem().newWatchService();
if (BuildConfig.DEBUG) Log.d(TAG, "Created WatchService instance");
}
mWatchKey = path.getParent().register(sWatcher, StandardWatchEventKinds.ENTRY_CREATE,

View File

@ -25,7 +25,6 @@ import android.content.res.TypedArray;
import android.util.Log;
import io.github.lsposed.lspd.BuildConfig;
import io.github.lsposed.lspd.nativebridge.ConfigManager;
import io.github.lsposed.lspd.config.LSPdConfigGlobal;
import java.lang.reflect.AccessibleObject;
@ -98,15 +97,6 @@ public final class XposedBridge {
private XposedBridge() {}
/**
* Called when native methods and other things are initialized, but before preloading classes etc.
* @hide
*/
@SuppressWarnings("deprecation")
public static void main(String[] args) {
// ed: moved
}
/** @hide */
// protected static final class ToolEntryPoint {
// protected static void main(String[] args) {

View File

@ -34,7 +34,6 @@ import android.util.Log;
import com.android.internal.os.ZygoteInit;
import io.github.lsposed.lspd.nativebridge.ConfigManager;
import io.github.lsposed.lspd.config.LSPdConfigGlobal;
import java.io.BufferedReader;
@ -49,6 +48,7 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
@ -77,6 +77,7 @@ import static de.robv.android.xposed.XposedHelpers.getParameterIndexByType;
import static de.robv.android.xposed.XposedHelpers.setStaticBooleanField;
import static de.robv.android.xposed.XposedHelpers.setStaticLongField;
import static de.robv.android.xposed.XposedHelpers.setStaticObjectField;
import static io.github.lsposed.lspd.config.LSPApplicationServiceClient.serviceClient;
public final class XposedInit {
private static final String TAG = XposedBridge.TAG;
@ -86,7 +87,6 @@ public final class XposedInit {
private static final String INSTANT_RUN_CLASS = "com.android.tools.fd.runtime.BootstrapApplication";
public static volatile boolean disableResources = false;
private static final String[] XRESOURCES_CONFLICTING_PACKAGES = {"com.sygic.aura"};
public static String prefsBasePath = null;
private XposedInit() {
}
@ -113,7 +113,7 @@ public final class XposedInit {
@ApiSensitive(Level.MIDDLE)
private static void hookResources() throws Throwable {
if (!ConfigManager.isResourcesHookEnabled() || disableResources) {
if (!serviceClient.isResourcesHookEnabled() || disableResources) {
return;
}
@ -353,12 +353,9 @@ public final class XposedInit {
topClassLoader = parent;
}
String moduleList = ConfigManager.getModulesList();
InputStream stream = new ByteArrayInputStream(moduleList.getBytes());
BufferedReader apks = new BufferedReader(new InputStreamReader(stream));
List<String> moduleList = serviceClient.getModulesList();
ArraySet<String> newLoadedApk = new ArraySet<>();
String apk;
while ((apk = apks.readLine()) != null) {
for (String apk : moduleList)
if (loadedModules.contains(apk)) {
newLoadedApk.add(apk);
} else {
@ -368,10 +365,9 @@ public final class XposedInit {
newLoadedApk.add(apk);
}
}
}
loadedModules.clear();
loadedModules.addAll(newLoadedApk);
apks.close();
// refresh callback according to current loaded module list
pruneCallbacks(loadedModules);

View File

@ -0,0 +1,121 @@
package io.github.lsposed.lspd.config;
import android.os.IBinder;
import android.os.RemoteException;
import java.io.File;
import java.util.Collections;
import java.util.List;
import io.github.lsposed.lspd.service.ILSPApplicationService;
import io.github.lsposed.lspd.util.Utils;
public class LSPApplicationServiceClient implements ILSPApplicationService {
static ILSPApplicationService service = null;
static IBinder serviceBinder = null;
static String baseCachePath = null;
static String basePrefsPath = null;
public static LSPApplicationServiceClient serviceClient = null;
public static void Init(IBinder binder) {
if (serviceClient == null && binder != null && serviceBinder == null && service == null) {
serviceBinder = binder;
try {
serviceBinder.linkToDeath(() -> {
serviceBinder = null;
service = null;
}, 0);
} catch (RemoteException e) {
Utils.logE("link to death error: ", e);
}
service = ILSPApplicationService.Stub.asInterface(binder);
serviceClient = new LSPApplicationServiceClient();
}
}
@Override
public void registerHeartBeat(IBinder handle) {
if (service == null || serviceBinder == null) {
Utils.logE("Register Failed: service is null");
}
try {
service.registerHeartBeat(handle);
} catch (RemoteException e) {
Utils.logE("register heart beat failed", e);
}
}
@Override
public IBinder requestModuleBinder() {
try {
return service.requestModuleBinder();
} catch (RemoteException | NullPointerException ignored) {
}
return null;
}
@Override
public IBinder requestManagerBinder() {
try {
return service.requestManagerBinder();
} catch (RemoteException | NullPointerException ignored) {
}
return null;
}
@Override
public int getVariant() {
try {
return service.getVariant();
} catch (RemoteException | NullPointerException ignored) {
}
return -1;
}
@Override
public boolean isResourcesHookEnabled() {
try {
return service.isResourcesHookEnabled();
} catch (RemoteException | NullPointerException ignored) {
}
return false;
}
@Override
public List<String> getModulesList() {
try {
return service.getModulesList();
} catch (RemoteException | NullPointerException ignored) {
}
return Collections.emptyList();
}
@Override
public String getPrefsPath(String packageName) {
try {
if (basePrefsPath == null)
basePrefsPath = service.getPrefsPath("");
return basePrefsPath + File.separator + packageName;
} catch (RemoteException | NullPointerException ignored) {
}
return null;
}
@Override
public String getCachePath(String fileName) {
try {
if (baseCachePath == null)
baseCachePath = service.getCachePath("");
return baseCachePath + File.separator + fileName;
} catch (RemoteException | NullPointerException ignored) {
}
return null;
}
@Override
public IBinder asBinder() {
return serviceBinder;
}
}

View File

@ -29,12 +29,14 @@ import android.util.Log;
import android.ddm.DdmHandleAppName;
import io.github.lsposed.common.KeepAll;
import io.github.lsposed.lspd.config.LSPApplicationServiceClient;
import io.github.lsposed.lspd.service.ILSPApplicationService;
import io.github.lsposed.lspd.service.ServiceManager;
import io.github.lsposed.lspd.util.Utils;
import java.util.concurrent.atomic.AtomicReference;
import static io.github.lsposed.lspd.config.LSPApplicationServiceClient.serviceClient;
import static io.github.lsposed.lspd.service.ServiceManager.TAG;
@SuppressLint("DefaultLocale")
@ -43,15 +45,9 @@ public class Main implements KeepAll {
private static final Binder heartBeatBinder = new Binder();
public static void forkAndSpecializePost(String appDataDir, String niceName, IBinder binder) {
ILSPApplicationService service = ILSPApplicationService.Stub.asInterface(binder);
final int variant;
try {
service.registerHeartBeat(heartBeatBinder);
variant = service.getVariant();
} catch (RemoteException e) {
Utils.logW("Register fail", e);
return;
}
LSPApplicationServiceClient.Init(binder);
serviceClient.registerHeartBeat(heartBeatBinder);
final int variant = serviceClient.getVariant();
EdxpImpl lspd = getEdxpImpl(variant);
if (lspd == null || !lspd.isInitialized()) {
Utils.logE("Not started up");
@ -61,15 +57,9 @@ public class Main implements KeepAll {
}
public static void forkSystemServerPost(IBinder binder) {
ILSPApplicationService service = ILSPApplicationService.Stub.asInterface(binder);
final int variant;
try {
service.registerHeartBeat(heartBeatBinder);
variant = service.getVariant();
} catch (RemoteException e) {
Utils.logW("Register fail", e);
return;
}
LSPApplicationServiceClient.Init(binder);
serviceClient.registerHeartBeat(heartBeatBinder);
final int variant = serviceClient.getVariant();
EdxpImpl lspd = getEdxpImpl(variant);
if (lspd == null || !lspd.isInitialized()) {
return;

View File

@ -22,7 +22,6 @@ package io.github.lsposed.lspd.deopt;
import android.text.TextUtils;
import io.github.lsposed.lspd.nativebridge.ConfigManager;
import io.github.lsposed.lspd.config.LSPdConfigGlobal;
import io.github.lsposed.lspd.util.Utils;
@ -30,6 +29,7 @@ import java.util.Arrays;
import de.robv.android.xposed.XposedHelpers;
import static io.github.lsposed.lspd.config.LSPApplicationServiceClient.serviceClient;
import static io.github.lsposed.lspd.deopt.InlinedMethodCallers.KEY_BOOT_IMAGE;
import static io.github.lsposed.lspd.deopt.InlinedMethodCallers.KEY_BOOT_IMAGE_MIUI_RES;
import static io.github.lsposed.lspd.deopt.InlinedMethodCallers.KEY_SYSTEM_SERVER;
@ -62,7 +62,7 @@ public class PrebuiltMethodsDeopter {
// todo check if has been done before
deoptMethods(KEY_BOOT_IMAGE, null);
if (!TextUtils.isEmpty(Utils.getSysProp("ro.miui.ui.version.code"))
&& ConfigManager.isResourcesHookEnabled()) {
&& serviceClient.isResourcesHookEnabled()) {
//deopt these only for MIUI with resources hook enabled
deoptMethods(KEY_BOOT_IMAGE_MIUI_RES, null);
}

View File

@ -18,7 +18,7 @@
* Copyright (C) 2021 LSPosed Contributors
*/
package io.github.lsposed.lspd._hooker.impl;
package io.github.lsposed.lspd.hooker;
import android.annotation.SuppressLint;
import android.app.ActivityThread;
@ -30,7 +30,6 @@ import android.content.pm.ApplicationInfo;
import android.content.res.CompatibilityInfo;
import android.content.res.XResources;
import io.github.lsposed.lspd.nativebridge.ConfigManager;
import io.github.lsposed.lspd.util.Hookers;
import io.github.lsposed.lspd.util.MetaDataReader;
import io.github.lsposed.lspd.util.Utils;
@ -46,8 +45,15 @@ import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.XposedInit;
import static io.github.lsposed.lspd.config.LSPApplicationServiceClient.serviceClient;
// normal process initialization (for new Activity, Service, BroadcastReceiver etc.)
public class HandleBindApp extends XC_MethodHook {
public class HandleBindAppHooker extends XC_MethodHook {
String appDataDir = null;
public HandleBindAppHooker(String appDataDir) {
this.appDataDir = appDataDir;
}
@Override
protected void beforeHookedMethod(MethodHookParam param) {
@ -57,10 +63,10 @@ public class HandleBindApp extends XC_MethodHook {
Object bindData = param.args[0];
final ApplicationInfo appInfo = (ApplicationInfo) XposedHelpers.getObjectField(bindData, "appInfo");
// save app process name here for later use
ConfigManager.appProcessName = (String) XposedHelpers.getObjectField(bindData, "processName");
String appProcessName = (String) XposedHelpers.getObjectField(bindData, "processName");
String reportedPackageName = appInfo.packageName.equals("android") ? "system" : appInfo.packageName;
Utils.logD("processName=" + ConfigManager.appProcessName +
", packageName=" + reportedPackageName + ", appDataDir=" + ConfigManager.appDataDir);
Utils.logD("processName=" + appProcessName +
", packageName=" + reportedPackageName + ", appDataDir=" + appDataDir);
ComponentName instrumentationName = (ComponentName) XposedHelpers.getObjectField(bindData, "instrumentationName");
if (instrumentationName != null) {
@ -118,7 +124,7 @@ public class HandleBindApp extends XC_MethodHook {
XposedHelpers.findAndHookMethod(ContextImpl.class, "getPreferencesDir", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) {
File newDir = new File(ConfigManager.getPrefsPath(appInfo.packageName));
File newDir = new File(serviceClient.getPrefsPath(appInfo.packageName));
if (migratePrefs) {
File oldDir = (File) param.getResult();
for (File oldFile : oldDir.listFiles()) {
@ -143,7 +149,7 @@ public class HandleBindApp extends XC_MethodHook {
}
});
}
LoadedApkGetCL hook = new LoadedApkGetCL(loadedApk, reportedPackageName,
LoadedApkGetCLHooker hook = new LoadedApkGetCLHooker(loadedApk, reportedPackageName,
processName, true);
hook.setUnhook(XposedHelpers.findAndHookMethod(
LoadedApk.class, "getClassLoader", hook));

View File

@ -18,7 +18,7 @@
* Copyright (C) 2021 LSPosed Contributors
*/
package io.github.lsposed.lspd._hooker.impl;
package io.github.lsposed.lspd.hooker;
import android.app.AndroidAppHelper;
import android.app.LoadedApk;
@ -33,7 +33,7 @@ import de.robv.android.xposed.XposedInit;
// when a package is loaded for an existing process, trigger the callbacks as well
// ed: remove resources related hooking
public class LoadedApkCstr extends XC_MethodHook {
public class LoadedApkCstrHooker extends XC_MethodHook {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
@ -70,7 +70,7 @@ public class LoadedApkCstr extends XC_MethodHook {
return;
}
LoadedApkGetCL hook = new LoadedApkGetCL(loadedApk, packageName,
LoadedApkGetCLHooker hook = new LoadedApkGetCLHooker(loadedApk, packageName,
AndroidAppHelper.currentProcessName(), false);
hook.setUnhook(XposedHelpers.findAndHookMethod(
LoadedApk.class, "getClassLoader", hook));

View File

@ -18,20 +18,22 @@
* Copyright (C) 2021 LSPosed Contributors
*/
package io.github.lsposed.lspd._hooker.impl;
package io.github.lsposed.lspd.hooker;
import android.app.LoadedApk;
import android.os.IBinder;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import io.github.lsposed.lspd.hooker.XposedInstallerHooker;
import io.github.lsposed.lspd.nativebridge.ConfigManager;
import io.github.lsposed.lspd.util.Hookers;
import io.github.lsposed.lspd.util.InstallerVerifier;
public class LoadedApkGetCL extends XC_MethodHook {
import static io.github.lsposed.lspd.config.LSPApplicationServiceClient.serviceClient;
public class LoadedApkGetCLHooker extends XC_MethodHook {
private final LoadedApk loadedApk;
private final String packageName;
@ -39,8 +41,8 @@ public class LoadedApkGetCL extends XC_MethodHook {
private final boolean isFirstApplication;
private Unhook unhook;
public LoadedApkGetCL(LoadedApk loadedApk, String packageName, String processName,
boolean isFirstApplication) {
public LoadedApkGetCLHooker(LoadedApk loadedApk, String packageName, String processName,
boolean isFirstApplication) {
this.loadedApk = loadedApk;
this.packageName = packageName;
this.processName = processName;
@ -76,9 +78,10 @@ public class LoadedApkGetCL extends XC_MethodHook {
lpparam.appInfo = loadedApk.getApplicationInfo();
lpparam.isFirstApplication = this.isFirstApplication;
if (packageName.equals(ConfigManager.getInstallerPackageName())) {
IBinder binder = serviceClient.requestManagerBinder();
if (binder != null) {
if (InstallerVerifier.verifyInstallerSignature(loadedApk.getApplicationInfo())) {
XposedInstallerHooker.hookXposedInstaller(lpparam.classLoader);
XposedInstallerHooker.hookXposedInstaller(lpparam.classLoader, binder);
} else {
InstallerVerifier.hookXposedInstaller(classLoader);
}

View File

@ -18,7 +18,7 @@
* Copyright (C) 2021 LSPosed Contributors
*/
package io.github.lsposed.lspd._hooker.impl;
package io.github.lsposed.lspd.hooker;
import android.os.Build;
@ -34,7 +34,7 @@ import de.robv.android.xposed.callbacks.XC_LoadPackage;
import static io.github.lsposed.lspd.util.Utils.logD;
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
public class StartBootstrapServices extends XC_MethodHook {
public class StartBootstrapServicesHooker extends XC_MethodHook {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
@ -50,7 +50,7 @@ public class StartBootstrapServices extends XC_MethodHook {
XC_LoadPackage.LoadPackageParam lpparam = new XC_LoadPackage.LoadPackageParam(XposedBridge.sLoadedPackageCallbacks);
lpparam.packageName = "android";
lpparam.processName = "android"; // it's actually system_server, but other functions return this as well
lpparam.classLoader = SystemMain.systemServerCL;
lpparam.classLoader = SystemMainHooker.systemServerCL;
lpparam.appInfo = null;
lpparam.isFirstApplication = true;
XC_LoadPackage.callAll(lpparam);
@ -58,14 +58,14 @@ public class StartBootstrapServices extends XC_MethodHook {
// Huawei
try {
findAndHookMethod("com.android.server.pm.HwPackageManagerService",
SystemMain.systemServerCL, "isOdexMode",
SystemMainHooker.systemServerCL, "isOdexMode",
XC_MethodReplacement.returnConstant(false));
} catch (XposedHelpers.ClassNotFoundError | NoSuchMethodError ignored) {
}
try {
String className = "com.android.server.pm." + (Build.VERSION.SDK_INT >= 23 ? "PackageDexOptimizer" : "PackageManagerService");
findAndHookMethod(className, SystemMain.systemServerCL,
findAndHookMethod(className, SystemMainHooker.systemServerCL,
"dexEntryExists", String.class,
XC_MethodReplacement.returnConstant(true));
} catch (XposedHelpers.ClassNotFoundError | NoSuchMethodError ignored) {

View File

@ -18,7 +18,7 @@
* Copyright (C) 2021 LSPosed Contributors
*/
package io.github.lsposed.lspd._hooker.impl;
package io.github.lsposed.lspd.hooker;
import io.github.lsposed.lspd.core.Main;
import io.github.lsposed.lspd.deopt.PrebuiltMethodsDeopter;
@ -29,7 +29,7 @@ import de.robv.android.xposed.XposedBridge;
// system_server initialization
// ed: only support sdk >= 21 for now
public class SystemMain extends XC_MethodHook {
public class SystemMainHooker extends XC_MethodHook {
public static volatile ClassLoader systemServerCL;

View File

@ -20,19 +20,16 @@
package io.github.lsposed.lspd.hooker;
import de.robv.android.xposed.XC_MethodReplacement;
import de.robv.android.xposed.XposedBridge;
import android.os.IBinder;
import de.robv.android.xposed.XposedHelpers;
import io.github.lsposed.lspd.BuildConfig;
import io.github.lsposed.lspd.nativebridge.ConfigManager;
import io.github.lsposed.lspd.core.EdxpImpl;
import io.github.lsposed.lspd.core.Main;
import io.github.lsposed.lspd.service.BridgeService;
import io.github.lsposed.lspd.util.Utils;
public class XposedInstallerHooker {
public static void hookXposedInstaller(final ClassLoader classLoader) {
public static void hookXposedInstaller(final ClassLoader classLoader, IBinder binder) {
final String variant;
switch (Main.getEdxpVariant()) {
case EdxpImpl.YAHFA:
@ -51,72 +48,8 @@ public class XposedInstallerHooker {
// LSPosed Manager R
try {
Class<?> ConstantsClass = XposedHelpers.findClass("io.github.lsposed.manager.Constants", classLoader);
try {
XposedHelpers.setStaticIntField(ConstantsClass, "xposedApiVersion", XposedBridge.getXposedVersion());
XposedHelpers.setStaticObjectField(ConstantsClass, "xposedVersion", BuildConfig.VERSION_NAME);
XposedHelpers.setStaticIntField(ConstantsClass, "xposedVersionCode", BuildConfig.VERSION_CODE);
XposedHelpers.setStaticObjectField(ConstantsClass, "xposedVariant", variant);
XposedHelpers.setStaticObjectField(ConstantsClass, "baseDir", ConfigManager.getBaseConfigPath() + "/");
XposedHelpers.setStaticObjectField(ConstantsClass, "logDir", ConfigManager.getLogPath());
XposedHelpers.setStaticObjectField(ConstantsClass, "miscDir", ConfigManager.getMiscPath());
XposedHelpers.setStaticBooleanField(ConstantsClass, "permissive", ConfigManager.isPermissive());
Utils.logI("Hooked LSPosed Manager");
return;
} catch (Throwable ignored) {
// fallback
}
XposedHelpers.findAndHookMethod(ConstantsClass, "getXposedApiVersion", new XC_MethodReplacement() {
@Override
protected Object replaceHookedMethod(MethodHookParam param) {
return XposedBridge.getXposedVersion();
}
});
XposedHelpers.findAndHookMethod(ConstantsClass, "getXposedVersion", new XC_MethodReplacement() {
@Override
protected Object replaceHookedMethod(MethodHookParam param) {
return BuildConfig.VERSION_NAME;
}
});
XposedHelpers.findAndHookMethod(ConstantsClass, "getXposedVersionCode", new XC_MethodReplacement() {
@Override
protected Object replaceHookedMethod(MethodHookParam param) {
return BuildConfig.VERSION_CODE;
}
});
XposedHelpers.findAndHookMethod(ConstantsClass, "getXposedVariant", new XC_MethodReplacement() {
@Override
protected Object replaceHookedMethod(MethodHookParam param) {
return variant;
}
});
XposedHelpers.findAndHookMethod(ConstantsClass, "getBaseDir", new XC_MethodReplacement() {
@Override
protected Object replaceHookedMethod(MethodHookParam param) {
return ConfigManager.getBaseConfigPath() + "/";
}
});
XposedHelpers.findAndHookMethod(ConstantsClass, "isPermissive", new XC_MethodReplacement() {
@Override
protected Object replaceHookedMethod(MethodHookParam param) {
return ConfigManager.isPermissive();
}
});
XposedHelpers.findAndHookMethod(ConstantsClass, "getLogDir", new XC_MethodReplacement() {
@Override
protected Object replaceHookedMethod(MethodHookParam param) {
return ConfigManager.getLogPath();
}
});
XposedHelpers.findAndHookMethod(ConstantsClass, "getMiscDir", new XC_MethodReplacement() {
@Override
protected Object replaceHookedMethod(MethodHookParam param) {
return ConfigManager.getMiscPath();
}
});
Class<?> serviceClass = XposedHelpers.findClass("io.github.lsposed.manager.receivers.LSPosedManagerServiceClient", classLoader);
// XposedHelpers.setStaticObjectField(serviceClass, "binder", BridgeService.requireBinder());
XposedHelpers.setStaticObjectField(serviceClass, "binder", binder);
Utils.logI("Hooked LSPosed Manager");
} catch (Throwable t) {

View File

@ -1,48 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* Copyright (C) 2020 EdXposed Contributors
* Copyright (C) 2021 LSPosed Contributors
*/
package io.github.lsposed.lspd.nativebridge;
public class ConfigManager {
public static String appDataDir = "";
public static String niceName = "";
public static String appProcessName = "";
public static native boolean isResourcesHookEnabled();
public static native String getInstallerPackageName();
public static native String getPrefsPath(String suffix);
public static native String getCachePath(String suffix);
public static native String getLogPath();
public static native String getMiscPath();
public static native String getBaseConfigPath();
public static native String getDataPathPrefix();
public static native String getModulesList();
public static native boolean isPermissive();
}

View File

@ -25,10 +25,10 @@ import android.content.pm.ApplicationInfo;
import android.content.res.CompatibilityInfo;
import android.text.TextUtils;
import io.github.lsposed.lspd._hooker.impl.HandleBindApp;
import io.github.lsposed.lspd._hooker.impl.LoadedApkCstr;
import io.github.lsposed.lspd._hooker.impl.StartBootstrapServices;
import io.github.lsposed.lspd._hooker.impl.SystemMain;
import io.github.lsposed.lspd.hooker.HandleBindAppHooker;
import io.github.lsposed.lspd.hooker.LoadedApkCstrHooker;
import io.github.lsposed.lspd.hooker.StartBootstrapServicesHooker;
import io.github.lsposed.lspd.hooker.SystemMainHooker;
import io.github.lsposed.lspd.util.Utils;
import io.github.lsposed.lspd.util.Versions;
@ -53,13 +53,13 @@ public abstract class BaseRouter implements Router {
XposedInit.startsSystemServer = isSystem;
}
public void installBootstrapHooks(boolean isSystem) {
public void installBootstrapHooks(boolean isSystem, String appDataDir) {
// Initialize the Xposed framework
try {
if (!bootstrapHooked.compareAndSet(false, true)) {
return;
}
startBootstrapHook(isSystem);
startBootstrapHook(isSystem, appDataDir);
XposedInit.initForZygote(isSystem);
} catch (Throwable t) {
Utils.logE("error during Xposed initialization", t);
@ -88,30 +88,30 @@ public abstract class BaseRouter implements Router {
@ApiSensitive(Level.LOW)
public void startBootstrapHook(boolean isSystem) {
public void startBootstrapHook(boolean isSystem, String appDataDir) {
Utils.logD("startBootstrapHook starts: isSystem = " + isSystem);
ClassLoader classLoader = BaseRouter.class.getClassLoader();
if (isSystem) {
XposedHelpers.findAndHookMethod("android.app.ActivityThread", classLoader,
"systemMain", new SystemMain());
"systemMain", new SystemMainHooker());
}
XposedHelpers.findAndHookMethod("android.app.ActivityThread", classLoader,
"handleBindApplication",
"android.app.ActivityThread$AppBindData",
new HandleBindApp());
new HandleBindAppHooker(appDataDir));
XposedHelpers.findAndHookConstructor("android.app.LoadedApk", classLoader,
ActivityThread.class, ApplicationInfo.class, CompatibilityInfo.class,
ClassLoader.class, boolean.class, boolean.class, boolean.class,
new LoadedApkCstr());
new LoadedApkCstrHooker());
}
public void startSystemServerHook() {
StartBootstrapServices sbsHooker = new StartBootstrapServices();
StartBootstrapServicesHooker sbsHooker = new StartBootstrapServicesHooker();
Object[] paramTypesAndCallback = Versions.hasR() ?
new Object[]{"com.android.server.utils.TimingsTraceAndSlog", sbsHooker} :
new Object[]{sbsHooker};
XposedHelpers.findAndHookMethod("com.android.server.SystemServer",
SystemMain.systemServerCL,
SystemMainHooker.systemServerCL,
"startBootstrapServices", paramTypesAndCallback);
}
}

View File

@ -20,15 +20,16 @@
package io.github.lsposed.lspd.proxy;
import io.github.lsposed.lspd.nativebridge.ConfigManager;
import android.os.Environment;
import java.io.File;
import io.github.lsposed.lspd.deopt.PrebuiltMethodsDeopter;
import io.github.lsposed.lspd.util.Utils;
import de.robv.android.xposed.SELinuxHelper;
import de.robv.android.xposed.XposedInit;
import static io.github.lsposed.lspd.util.FileUtils.getDataPathPrefix;
public class NormalProxy extends BaseProxy {
public NormalProxy(Router router) {
@ -41,7 +42,7 @@ public class NormalProxy extends BaseProxy {
public void forkSystemServerPost() {
forkPostCommon(true,
getDataPathPrefix() + "android", "system_server");
new File(Environment.getDataDirectory(), "android").toString(), "system_server");
}
@ -50,10 +51,7 @@ public class NormalProxy extends BaseProxy {
mRouter.initResourcesHook();
mRouter.prepare(isSystem);
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for secondary zygote
ConfigManager.appDataDir = appDataDir;
ConfigManager.niceName = niceName;
mRouter.installBootstrapHooks(isSystem);
XposedInit.prefsBasePath = ConfigManager.getPrefsPath("");
mRouter.installBootstrapHooks(isSystem, appDataDir);
mRouter.onEnterChildProcess();
Utils.logI("Loading modules for " + niceName);
mRouter.loadModulesSafely(true);

View File

@ -26,13 +26,11 @@ public interface Router {
void prepare(boolean isSystem);
String parsePackageName(String appDataDir);
void installBootstrapHooks(boolean isSystem);
void installBootstrapHooks(boolean isSystem, String appDataDir);
void loadModulesSafely(boolean callInitZygote);
void startBootstrapHook(boolean isSystem);
void startBootstrapHook(boolean isSystem, String appDataDir);
void startSystemServerHook();

View File

@ -23,45 +23,13 @@ package io.github.lsposed.lspd.sandhook.core;
import io.github.lsposed.lspd.config.LSPdConfigGlobal;
import io.github.lsposed.lspd.proxy.BaseRouter;
import io.github.lsposed.lspd.sandhook.config.SandHookProvider;
import io.github.lsposed.lspd.sandhook.entry.AppBootstrapHookInfo;
import io.github.lsposed.lspd.sandhook.entry.SysBootstrapHookInfo;
import io.github.lsposed.lspd.sandhook.entry.SysInnerHookInfo;
import io.github.lsposed.lspd.sandhook.hooker.SystemMainHooker;
import io.github.lsposed.lspd.util.Utils;
import com.swift.sandhook.xposedcompat.XposedCompat;
import com.swift.sandhook.xposedcompat.methodgen.SandHookXposedBridge;
import de.robv.android.xposed.XposedBridge;
public class SandHookRouter extends BaseRouter {
public SandHookRouter() {
}
private static boolean useSandHook = false;
public void startBootstrapHook(boolean isSystem) {
if (useSandHook) {
Utils.logD("startBootstrapHook starts: isSystem = " + isSystem);
ClassLoader classLoader = XposedBridge.BOOTCLASSLOADER;
if (isSystem) {
XposedCompat.addHookers(classLoader, SysBootstrapHookInfo.hookItems);
} else {
XposedCompat.addHookers(classLoader, AppBootstrapHookInfo.hookItems);
}
} else {
super.startBootstrapHook(isSystem);
}
}
public void startSystemServerHook() {
if (useSandHook) {
XposedCompat.addHookers(SystemMainHooker.systemServerCL, SysInnerHookInfo.hookItems);
} else {
super.startSystemServerHook();
}
}
public void onEnterChildProcess() {
SandHookXposedBridge.onForkPost();
//enable compile in child process

View File

@ -1,37 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* Copyright (C) 2020 EdXposed Contributors
* Copyright (C) 2021 LSPosed Contributors
*/
package io.github.lsposed.lspd.sandhook.entry;
import io.github.lsposed.common.KeepMembers;
import io.github.lsposed.lspd.sandhook.hooker.HandleBindAppHooker;
import io.github.lsposed.lspd.sandhook.hooker.LoadedApkConstructorHooker;
public class AppBootstrapHookInfo implements KeepMembers {
public static String[] hookItemNames = {
HandleBindAppHooker.class.getName(),
LoadedApkConstructorHooker.class.getName(),
};
public static Class[] hookItems = {
HandleBindAppHooker.class,
LoadedApkConstructorHooker.class,
};
}

View File

@ -1,40 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* Copyright (C) 2020 EdXposed Contributors
* Copyright (C) 2021 LSPosed Contributors
*/
package io.github.lsposed.lspd.sandhook.entry;
import io.github.lsposed.common.KeepMembers;
import io.github.lsposed.lspd.sandhook.hooker.HandleBindAppHooker;
import io.github.lsposed.lspd.sandhook.hooker.LoadedApkConstructorHooker;
import io.github.lsposed.lspd.sandhook.hooker.SystemMainHooker;
public class SysBootstrapHookInfo implements KeepMembers {
public static String[] hookItemNames = {
HandleBindAppHooker.class.getName(),
SystemMainHooker.class.getName(),
LoadedApkConstructorHooker.class.getName()
};
public static Class[] hookItems = {
HandleBindAppHooker.class,
SystemMainHooker.class,
LoadedApkConstructorHooker.class,
};
}

View File

@ -1,43 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* Copyright (C) 2020 EdXposed Contributors
* Copyright (C) 2021 LSPosed Contributors
*/
package io.github.lsposed.lspd.sandhook.entry;
import io.github.lsposed.common.KeepMembers;
import io.github.lsposed.lspd.sandhook.hooker.StartBootstrapServicesHooker;
import io.github.lsposed.lspd.sandhook.hooker.StartBootstrapServicesHooker11;
import io.github.lsposed.lspd.util.Versions;
public class SysInnerHookInfo implements KeepMembers {
public static Class<?> getSysInnerHookerClass() {
return Versions.hasR() ?
StartBootstrapServicesHooker11.class :
StartBootstrapServicesHooker.class;
}
public static String[] hookItemNames = {
getSysInnerHookerClass().getName()
};
public static Class[] hookItems = {
getSysInnerHookerClass()
};
}

View File

@ -1,69 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*
* Copyright (C) 2020 EdXposed Contributors
* Copyright (C) 2021 LSPosed Contributors
*/
package io.github.lsposed.lspd.sandhook.hooker;
import android.app.ActivityThread;
import io.github.lsposed.common.KeepMembers;
import io.github.lsposed.lspd._hooker.impl.HandleBindApp;
import com.swift.sandhook.SandHook;
import com.swift.sandhook.annotation.HookClass;
import com.swift.sandhook.annotation.HookMethod;
import com.swift.sandhook.annotation.HookMethodBackup;
import com.swift.sandhook.annotation.Param;
import com.swift.sandhook.annotation.SkipParamCheck;
import com.swift.sandhook.annotation.ThisObject;
import java.lang.reflect.Method;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.annotation.ApiSensitive;
import de.robv.android.xposed.annotation.Level;
@ApiSensitive(Level.LOW)
@HookClass(ActivityThread.class)
public class HandleBindAppHooker implements KeepMembers {
public static String className = "android.app.ActivityThread";
public static String methodName = "handleBindApplication";
public static String methodSig = "(Landroid/app/ActivityThread$AppBindData;)V";
@HookMethodBackup("handleBindApplication")
@SkipParamCheck
static Method backup;
@HookMethod("handleBindApplication")
public static void hook(@ThisObject ActivityThread thiz, @Param("android.app.ActivityThread$AppBindData") Object bindData) throws Throwable {
final XC_MethodHook methodHook = new HandleBindApp();
final XC_MethodHook.MethodHookParam param = new XC_MethodHook.MethodHookParam();
param.thisObject = thiz;
param.args = new Object[]{bindData};
methodHook.callBeforeHookedMethod(param);
if (!param.returnEarly) {
backup(thiz, bindData);
}
methodHook.callAfterHookedMethod(param);
}
public static void backup(Object thiz, Object bindData) throws Throwable {
SandHook.callOriginByBackup(backup, thiz, bindData);
}
}

View File

@ -26,7 +26,7 @@ import android.content.pm.ApplicationInfo;
import android.content.res.CompatibilityInfo;
import io.github.lsposed.common.KeepMembers;
import io.github.lsposed.lspd._hooker.impl.LoadedApkCstr;
import io.github.lsposed.lspd.hooker.LoadedApkCstrHooker;
import com.swift.sandhook.SandHook;
import com.swift.sandhook.annotation.HookClass;
import com.swift.sandhook.annotation.HookMethod;
@ -59,7 +59,7 @@ public class LoadedApkConstructorHooker implements KeepMembers {
ApplicationInfo aInfo, CompatibilityInfo compatInfo,
ClassLoader baseLoader, boolean securityViolation,
boolean includeCode, boolean registerPackage) throws Throwable {
final XC_MethodHook methodHook = new LoadedApkCstr();
final XC_MethodHook methodHook = new LoadedApkCstrHooker();
final XC_MethodHook.MethodHookParam param = new XC_MethodHook.MethodHookParam();
param.thisObject = thiz;
param.args = new Object[]{activityThread, aInfo, compatInfo, baseLoader, securityViolation,

View File

@ -21,7 +21,7 @@
package io.github.lsposed.lspd.sandhook.hooker;
import io.github.lsposed.common.KeepMembers;
import io.github.lsposed.lspd._hooker.impl.StartBootstrapServices;
import com.swift.sandhook.SandHook;
import com.swift.sandhook.annotation.HookMethod;
import com.swift.sandhook.annotation.HookMethodBackup;
@ -45,7 +45,7 @@ public class StartBootstrapServicesHooker implements KeepMembers {
@HookMethod("startBootstrapServices")
public static void hook(@ThisObject Object systemServer) throws Throwable {
final XC_MethodHook methodHook = new StartBootstrapServices();
final XC_MethodHook methodHook = new io.github.lsposed.lspd.hooker.StartBootstrapServicesHooker();
final XC_MethodHook.MethodHookParam param = new XC_MethodHook.MethodHookParam();
param.thisObject = systemServer;
param.args = new Object[]{};

View File

@ -21,7 +21,7 @@
package io.github.lsposed.lspd.sandhook.hooker;
import io.github.lsposed.common.KeepMembers;
import io.github.lsposed.lspd._hooker.impl.StartBootstrapServices;
import io.github.lsposed.lspd.hooker.StartBootstrapServicesHooker;
import com.swift.sandhook.SandHook;
import com.swift.sandhook.annotation.HookMethod;
import com.swift.sandhook.annotation.HookMethodBackup;
@ -49,7 +49,7 @@ public class StartBootstrapServicesHooker11 implements KeepMembers {
@HookMethod("startBootstrapServices")
public static void hook(@ThisObject Object systemServer, @Param("com.android.server.utils.TimingsTraceAndSlog") Object traceAndSlog) throws Throwable {
final XC_MethodHook methodHook = new StartBootstrapServices();
final XC_MethodHook methodHook = new StartBootstrapServicesHooker();
final XC_MethodHook.MethodHookParam param = new XC_MethodHook.MethodHookParam();
param.thisObject = systemServer;
param.args = new Object[]{traceAndSlog};

View File

@ -23,7 +23,7 @@ package io.github.lsposed.lspd.sandhook.hooker;
import android.app.ActivityThread;
import io.github.lsposed.common.KeepMembers;
import io.github.lsposed.lspd._hooker.impl.SystemMain;
import com.swift.sandhook.SandHook;
import com.swift.sandhook.annotation.HookClass;
import com.swift.sandhook.annotation.HookMethod;
@ -53,7 +53,7 @@ public class SystemMainHooker implements KeepMembers {
@HookMethod("systemMain")
public static ActivityThread hook() throws Throwable {
final XC_MethodHook methodHook = new SystemMain();
final XC_MethodHook methodHook = new io.github.lsposed.lspd.hooker.SystemMainHooker();
final XC_MethodHook.MethodHookParam param = new XC_MethodHook.MethodHookParam();
param.thisObject = null;
param.args = new Object[]{};

View File

@ -29,7 +29,6 @@ import static io.github.lsposed.lspd.service.ServiceManager.TAG;
// This config manager assume uid won't change when our service is off.
// Otherwise, user should maintain it manually.
// TODO: manager package name supports
public class ConfigManager {
static ConfigManager instance = null;
@ -52,6 +51,9 @@ public class ConfigManager {
private String manager = null;
private int managerUid = -1;
final private File miscFile = new File(basePath, "misc_path");
private String miscPath = null;
final private File selinuxPath = new File("/sys/fs/selinux/enforce");
// only check on boot
final private boolean isPermissive;
@ -69,7 +71,7 @@ public class ConfigManager {
};
private String readText(@NonNull File file) throws IOException {
return new String(Files.readAllBytes(file.toPath()));
return new String(Files.readAllBytes(file.toPath())).trim();
}
private String readText(@NonNull File file, String defaultValue) {
@ -108,6 +110,7 @@ public class ConfigManager {
resourceHook = resourceHookSwitch.exists();
variant = readInt(variantSwitch, -1);
verboseLog = readInt(verboseLogSwitch, 0) == 1;
miscPath = "/data/misc/" + readText(miscFile, "lspd");
updateManager();
}
@ -333,4 +336,12 @@ public class ConfigManager {
public boolean isManager(int uid) {
return uid == managerUid;
}
public String getCachePath(String fileName) {
return miscPath + File.separator + "cache" + File.separator + fileName;
}
public String getPrefsPath(String fileName) {
return miscPath + File.separator + "prefs" + File.separator + fileName;
}
}

View File

@ -6,6 +6,7 @@ import android.os.RemoteException;
import android.util.Log;
import android.util.Pair;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@ -35,6 +36,30 @@ public class LSPApplicationService extends ILSPApplicationService.Stub {
return ConfigManager.getInstance().variant();
}
@Override
public boolean isResourcesHookEnabled() throws RemoteException {
ensureRegistered();
return ConfigManager.getInstance().resourceHook();
}
@Override
public List<String> getModulesList() throws RemoteException {
ensureRegistered();
return ConfigManager.getInstance().getModulesPathForUid(Binder.getCallingUid());
}
@Override
public String getPrefsPath(String packageName) throws RemoteException {
ensureRegistered();
return ConfigManager.getInstance().getPrefsPath(packageName);
}
@Override
public String getCachePath(String fileName) throws RemoteException {
ensureRegistered();
return ConfigManager.getInstance().getCachePath(fileName);
}
// TODO: check if module
@Override
public IBinder requestModuleBinder() throws RemoteException {
@ -42,7 +67,6 @@ public class LSPApplicationService extends ILSPApplicationService.Stub {
return ServiceManager.getModuleService();
}
// TODO: check if manager
@Override
public IBinder requestManagerBinder() throws RemoteException {
ensureRegistered();

View File

@ -36,7 +36,6 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.widget.Toast;
import io.github.lsposed.lspd.nativebridge.ConfigManager;
import io.github.lsposed.lspd.util.Utils;
import java.io.File;
@ -78,63 +77,65 @@ public class PackageReceiver {
private Map<String, String> loadEnabledModules(int uid) {
HashMap<String, String> result = new HashMap<>();
try {
File enabledModules = new File(ConfigManager.getMiscPath(), uid + "/" + ENABLED_MODULES_LIST_FILENAME);
if (!enabledModules.exists()) return result;
Scanner scanner = new Scanner(enabledModules);
while (scanner.hasNextLine()) {
String packageName = scanner.nextLine();
PackageInfo info = getPackageInfo(packageName, 0);
if (info != null && isXposedModule(info.applicationInfo))
result.put(packageName, info.applicationInfo.sourceDir);
else if (info == null)
result.put(packageName, null);
}
} catch (Throwable e) {
Utils.logE("Unable to read enabled modules", e);
}
// TODO: FIXME
// try {
// File enabledModules = new File(ConfigManager.getMiscPath(), uid + "/" + ENABLED_MODULES_LIST_FILENAME);
// if (!enabledModules.exists()) return result;
// Scanner scanner = new Scanner(enabledModules);
// while (scanner.hasNextLine()) {
// String packageName = scanner.nextLine();
// PackageInfo info = getPackageInfo(packageName, 0);
// if (info != null && isXposedModule(info.applicationInfo))
// result.put(packageName, info.applicationInfo.sourceDir);
// else if (info == null)
// result.put(packageName, null);
// }
// } catch (Throwable e) {
// Utils.logE("Unable to read enabled modules", e);
// }
return result;
}
private boolean updateModuleList(int uid, String packageName) {
Map<String, String> enabledModules = loadEnabledModules(uid);
if (!enabledModules.containsKey(packageName)) return false;
try {
File moduleListFile = new File(ConfigManager.getMiscPath(), uid + "/" + MODULES_LIST_FILENAME);
File enabledModuleListFile = new File(ConfigManager.getMiscPath(), uid + "/" + ENABLED_MODULES_LIST_FILENAME);
if (moduleListFile.exists() && !moduleListFile.canWrite()) {
moduleListFile.delete();
moduleListFile.createNewFile();
}
if (enabledModuleListFile.exists() && !enabledModuleListFile.canWrite()) {
enabledModuleListFile.delete();
enabledModuleListFile.createNewFile();
}
PrintWriter modulesList = new PrintWriter(moduleListFile);
PrintWriter enabledModulesList = new PrintWriter(enabledModuleListFile);
for (Map.Entry<String, String> module : enabledModules.entrySet()) {
String apkPath = module.getValue();
if (apkPath != null) {
modulesList.println(module.getValue());
enabledModulesList.println(module.getKey());
} else {
Utils.logI(String.format("remove obsolete package %s", packageName));
File prefsDir = new File(ConfigManager.getMiscPath(), uid + "/prefs/" + packageName);
File[] fileList = prefsDir.listFiles();
if (fileList != null) {
for (File childFile : fileList) {
childFile.delete();
}
}
}
}
modulesList.close();
enabledModulesList.close();
} catch (Throwable e) {
Utils.logE("Fail to update module list", e);
}
// TODO: FIXME
//
// if (!enabledModules.containsKey(packageName)) return false;
//
// try {
// File moduleListFile = new File(ConfigManager.getMiscPath(), uid + "/" + MODULES_LIST_FILENAME);
// File enabledModuleListFile = new File(ConfigManager.getMiscPath(), uid + "/" + ENABLED_MODULES_LIST_FILENAME);
// if (moduleListFile.exists() && !moduleListFile.canWrite()) {
// moduleListFile.delete();
// moduleListFile.createNewFile();
// }
// if (enabledModuleListFile.exists() && !enabledModuleListFile.canWrite()) {
// enabledModuleListFile.delete();
// enabledModuleListFile.createNewFile();
// }
// PrintWriter modulesList = new PrintWriter(moduleListFile);
// PrintWriter enabledModulesList = new PrintWriter(enabledModuleListFile);
// for (Map.Entry<String, String> module : enabledModules.entrySet()) {
// String apkPath = module.getValue();
// if (apkPath != null) {
// modulesList.println(module.getValue());
// enabledModulesList.println(module.getKey());
// } else {
// Utils.logI(String.format("remove obsolete package %s", packageName));
// File prefsDir = new File(ConfigManager.getMiscPath(), uid + "/prefs/" + packageName);
// File[] fileList = prefsDir.listFiles();
// if (fileList != null) {
// for (File childFile : fileList) {
// childFile.delete();
// }
// }
// }
// }
// modulesList.close();
// enabledModulesList.close();
// } catch (Throwable e) {
// Utils.logE("Fail to update module list", e);
// }
return true;
}
@ -168,36 +169,37 @@ public class PackageReceiver {
PackageInfo pkgInfo = getPackageInfo(packageName, intent.getIntExtra(Intent.EXTRA_USER, 0));
if (pkgInfo != null && !isXposedModule(pkgInfo.applicationInfo)) return;
try {
for (int uid : UserService.getUsers()) {
Utils.logI("updating uid: " + uid);
boolean activated = updateModuleList(uid, packageName);
UserHandle userHandle = null;
try {
userHandle = (UserHandle) XposedHelpers.callStaticMethod(UserHandle.class, "of", uid);
} catch (Throwable t) {
Utils.logW("get user handle failed", t);
}
if (userHandle != null) {
try {
Intent broadCast = new Intent(activated ? MODULE_UPDATED : MODULE_NOT_ACTIVATAED);
broadCast.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES | 0x01000000);
broadCast.setData(intent.getData());
broadCast.setPackage(ConfigManager.getInstallerPackageName());
XposedHelpers.callMethod(context, "sendBroadcastAsUser", broadCast, userHandle);
Utils.logI("broadcast to " + ConfigManager.getInstallerPackageName());
} catch (Throwable t) {
Utils.logW("send broadcast failed", t);
Toast.makeText(context, "LSPosed: Updated " + packageName, Toast.LENGTH_SHORT).show();
}
} else if (activated) {
Toast.makeText(context, "LSPosed: Updated " + packageName, Toast.LENGTH_SHORT).show();
}
}
} catch (Throwable e) {
Utils.logW("update failed", e);
}
// TODO: FIXME
//
// try {
// for (int uid : UserService.getUsers()) {
// Utils.logI("updating uid: " + uid);
// boolean activated = updateModuleList(uid, packageName);
// UserHandle userHandle = null;
// try {
// userHandle = (UserHandle) XposedHelpers.callStaticMethod(UserHandle.class, "of", uid);
// } catch (Throwable t) {
// Utils.logW("get user handle failed", t);
// }
// if (userHandle != null) {
// try {
// Intent broadCast = new Intent(activated ? MODULE_UPDATED : MODULE_NOT_ACTIVATAED);
// broadCast.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES | 0x01000000);
// broadCast.setData(intent.getData());
// broadCast.setPackage(ConfigManager.getInstallerPackageName());
// XposedHelpers.callMethod(context, "sendBroadcastAsUser", broadCast, userHandle);
// Utils.logI("broadcast to " + ConfigManager.getInstallerPackageName());
// } catch (Throwable t) {
// Utils.logW("send broadcast failed", t);
// Toast.makeText(context, "LSPosed: Updated " + packageName, Toast.LENGTH_SHORT).show();
// }
// } else if (activated) {
// Toast.makeText(context, "LSPosed: Updated " + packageName, Toast.LENGTH_SHORT).show();
// }
// }
// } catch (Throwable e) {
// Utils.logW("update failed", e);
// }
}
};

View File

@ -8,7 +8,6 @@ import android.os.ServiceManager;
import java.util.ArrayList;
import io.github.lsposed.lspd.nativebridge.ConfigManager;
import io.github.lsposed.lspd.utils.ParceledListSlice;
public class PackageService {
@ -35,15 +34,6 @@ public class PackageService {
return pm.getPackagesForUid(uid);
}
public static boolean isInstaller(int uid) throws RemoteException {
boolean res = false;
String InstallerPackageName = ConfigManager.getInstallerPackageName();
for (String pkg : getPackagesForUid(uid)) {
res = res || InstallerPackageName.equals(pkg);
}
return res;
}
public static ParceledListSlice<PackageInfo> getInstalledPackagesFromAllUsers(int flags) throws RemoteException {
ArrayList<PackageInfo> res = new ArrayList<>();
IPackageManager pm = getPackageManager();

View File

@ -22,8 +22,6 @@ package io.github.lsposed.lspd.util;
import android.text.TextUtils;
import io.github.lsposed.lspd.nativebridge.ConfigManager;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
@ -90,8 +88,4 @@ public class FileUtils {
}
return dataDir.substring(lastIndex + 1);
}
public static String getDataPathPrefix() {
return ConfigManager.getDataPathPrefix() + "/";
}
}

View File

@ -20,7 +20,6 @@
package io.github.lsposed.lspd.yahfa.dexmaker;
import io.github.lsposed.lspd.nativebridge.ConfigManager;
import io.github.lsposed.lspd.util.Utils;
import java.io.File;
@ -33,15 +32,17 @@ import external.com.android.dx.Code;
import external.com.android.dx.Local;
import external.com.android.dx.TypeId;
import static io.github.lsposed.lspd.config.LSPApplicationServiceClient.serviceClient;
@SuppressWarnings({"rawtypes", "unchecked"})
public class DexMakerUtils {
public static boolean canCache = true;
static {
File cacheDir = new File(ConfigManager.getCachePath(""));
File cacheDir = new File(serviceClient.getCachePath(""));
if(!cacheDir.canRead() || !cacheDir.canWrite()) {
Utils.logW("Cache disabled");
Utils.logW("Cache disabled with path " + cacheDir.getAbsolutePath());
canCache = false;
}
}

View File

@ -24,7 +24,6 @@ import android.annotation.TargetApi;
import android.os.Build;
import io.github.lsposed.lspd.BuildConfig;
import io.github.lsposed.lspd.nativebridge.ConfigManager;
import io.github.lsposed.lspd.core.yahfa.HookMain;
import io.github.lsposed.lspd.util.ProxyClassLoader;
@ -46,6 +45,7 @@ import external.com.android.dx.Local;
import external.com.android.dx.MethodId;
import external.com.android.dx.TypeId;
import static io.github.lsposed.lspd.config.LSPApplicationServiceClient.serviceClient;
import static io.github.lsposed.lspd.yahfa.dexmaker.DexMakerUtils.autoBoxIfNecessary;
import static io.github.lsposed.lspd.yahfa.dexmaker.DexMakerUtils.autoUnboxIfNecessary;
import static io.github.lsposed.lspd.yahfa.dexmaker.DexMakerUtils.canCache;
@ -167,17 +167,17 @@ public class HookerDexMaker {
String suffix = DexMakerUtils.getSha1Hex(mMember.toString());
className = className + suffix;
String dexFileName = className + ".jar";
File dexFile = new File(ConfigManager.getCachePath(dexFileName));
File dexFile = new File(serviceClient.getCachePath(dexFileName));
if (!dexFile.exists()) {
// if file exists, reuse it and skip generating
DexLog.d("Generating " + dexFileName);
doGenerate(className);
loader = mDexMaker.generateAndLoad(mAppClassLoader, new File(ConfigManager.getCachePath("")), dexFileName, false);
loader = mDexMaker.generateAndLoad(mAppClassLoader, new File(serviceClient.getCachePath("")), dexFileName, false);
dexFile.setWritable(true, false);
dexFile.setReadable(true, false);
} else {
DexLog.d("Using cache " + dexFileName);
loader = mDexMaker.loadClassDirect(mAppClassLoader, new File(ConfigManager.getCachePath("")), dexFileName);
loader = mDexMaker.loadClassDirect(mAppClassLoader, new File(serviceClient.getCachePath("")), dexFileName);
}
usedCache = true;
} catch (Throwable ignored) {}

View File

@ -3,7 +3,6 @@ package com.swift.sandhook.xposedcompat;
import android.os.Process;
import android.text.TextUtils;
import io.github.lsposed.lspd.nativebridge.ConfigManager;
import io.github.lsposed.lspd.util.FileUtils;
import io.github.lsposed.lspd.util.ProcessUtils;
import io.github.lsposed.lspd.util.ProxyClassLoader;
@ -16,8 +15,6 @@ import java.lang.reflect.Member;
import de.robv.android.xposed.XposedBridge;
import static io.github.lsposed.lspd.util.FileUtils.getDataPathPrefix;
public class XposedCompat {
// TODO initialize these variables
@ -49,11 +46,12 @@ public class XposedCompat {
}
public static File getCacheDir() {
if (cacheDir == null) {
String fixedAppDataDir = getDataPathPrefix() + getPackageName(ConfigManager.appDataDir) + "/";
cacheDir = new File(fixedAppDataDir, "/cache/sandhook/"
+ ProcessUtils.getProcessName(Process.myPid()).replace(":", "_") + "/");
}
// TODO: cache path?
// if (cacheDir == null) {
// String fixedAppDataDir = getDataPathPrefix() + getPackageName(ConfigManager.appDataDir) + "/";
// cacheDir = new File(fixedAppDataDir, "/cache/sandhook/"
// + ProcessUtils.getProcessName(Process.myPid()).replace(":", "_") + "/");
// }
return cacheDir;
}

View File

@ -1,6 +1,5 @@
package com.swift.sandhook.xposedcompat.methodgen;
import io.github.lsposed.lspd.nativebridge.ConfigManager;
import com.swift.sandhook.SandHook;
import com.swift.sandhook.SandHookMethodResolver;
import com.swift.sandhook.wrapper.HookWrapper;
@ -34,6 +33,7 @@ import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.canCache;
import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.createResultLocals;
import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.getObjTypeIdIfPrimitive;
import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.getSha1Hex;
import static io.github.lsposed.lspd.config.LSPApplicationServiceClient.serviceClient;
public class HookerDexMaker implements HookMaker {
@ -187,7 +187,7 @@ public class HookerDexMaker implements HookMaker {
HookWrapper.HookEntity hookEntity = null;
//try load cache first
try {
ClassLoader loader = mDexMaker.loadClassDirect(mAppClassLoader, new File(ConfigManager.getCachePath("")), dexName);
ClassLoader loader = mDexMaker.loadClassDirect(mAppClassLoader, new File(serviceClient.getCachePath("")), dexName);
if (loader != null) {
hookEntity = loadHookerClass(loader, className);
}
@ -215,8 +215,8 @@ public class HookerDexMaker implements HookMaker {
ClassLoader loader;
if (canCache) {
loader = mDexMaker.generateAndLoad(mAppClassLoader, new File(ConfigManager.getCachePath("")), dexName, true);
File dexFile = new File(ConfigManager.getCachePath(dexName));
loader = mDexMaker.generateAndLoad(mAppClassLoader, new File(serviceClient.getCachePath("")), dexName, true);
File dexFile = new File(serviceClient.getCachePath(dexName));
dexFile.setWritable(true, false);
dexFile.setReadable(true, false);
} else {

View File

@ -1,6 +1,5 @@
package com.swift.sandhook.xposedcompat.methodgen;
import io.github.lsposed.lspd.nativebridge.ConfigManager;
import com.swift.sandhook.SandHook;
import com.swift.sandhook.wrapper.HookWrapper;
import com.swift.sandhook.xposedcompat.hookstub.HookStubManager;
@ -30,6 +29,7 @@ import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.canCache;
import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.createResultLocals;
import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.getObjTypeIdIfPrimitive;
import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.getSha1Hex;
import static io.github.lsposed.lspd.config.LSPApplicationServiceClient.serviceClient;
public class HookerDexMakerNew implements HookMaker {
@ -148,7 +148,7 @@ public class HookerDexMakerNew implements HookMaker {
HookWrapper.HookEntity hookEntity = null;
//try load cache first
try {
ClassLoader loader = mDexMaker.loadClassDirect(mAppClassLoader, new File(ConfigManager.getCachePath("")), dexName);
ClassLoader loader = mDexMaker.loadClassDirect(mAppClassLoader, new File(serviceClient.getCachePath("")), dexName);
if (loader != null) {
hookEntity = loadHookerClass(loader, className);
}
@ -176,8 +176,8 @@ public class HookerDexMakerNew implements HookMaker {
}
// Create the dex file and load it.
try {
loader = mDexMaker.generateAndLoad(mAppClassLoader, new File(ConfigManager.getCachePath("")), dexName, true);
File dexFile = new File(ConfigManager.getCachePath(dexName));
loader = mDexMaker.generateAndLoad(mAppClassLoader, new File(serviceClient.getCachePath("")), dexName, true);
File dexFile = new File(serviceClient.getCachePath(dexName));
dexFile.setWritable(true, false);
dexFile.setReadable(true, false);
} catch (IOException e) {

View File

@ -4,7 +4,6 @@ import android.os.Build;
import android.os.Process;
import android.os.Trace;
import io.github.lsposed.lspd.nativebridge.ConfigManager;
import io.github.lsposed.lspd.nativebridge.Yahfa;
import io.github.lsposed.lspd.util.ClassLoaderUtils;
import io.github.lsposed.lspd.util.FileUtils;

View File

@ -1,5 +1,4 @@
package com.swift.sandhook.xposedcompat.utils;
import io.github.lsposed.lspd.nativebridge.ConfigManager;
import io.github.lsposed.lspd.util.Utils;
import java.io.File;
@ -15,12 +14,14 @@ import external.com.android.dx.Code;
import external.com.android.dx.Local;
import external.com.android.dx.TypeId;
import static io.github.lsposed.lspd.config.LSPApplicationServiceClient.serviceClient;
public class DexMakerUtils {
public static boolean canCache = true;
static {
File cacheDir = new File(ConfigManager.getCachePath(""));
File cacheDir = new File(serviceClient.getCachePath(""));
if(!cacheDir.canRead() || !cacheDir.canWrite()) {
Utils.logW("Cache disabled");
canCache = false;

View File

@ -223,6 +223,10 @@ else
fi
fi
touch /data/adb/lspd/new_install || abortC "! ${LANG_CUST_ERR_CONF_FIRST}"
ui_print "- ${LANG_CUST_INST_COPY_LIB}"
mkdir -p /data/adb/lspd/config
rm -rf "/data/adb/lspd/framework"
mv "${MODPATH}/system/framework" "/data/adb/lspd/framework"
set_perm_recursive /data/adb/lspd root root 0700 0600 "u:object_r:magisk_file:s0" || abortC "! ${LANG_CUST_ERR_PERM}"
mkdir -p /data/misc/$MISC_PATH/0/conf/ || abortC "! ${LANG_CUST_ERR_CONF_CREATE}"
set_perm /data/misc/$MISC_PATH root root 0771 "u:object_r:magisk_file:s0" || abortC "! ${LANG_CUST_ERR_PERM}"
@ -230,9 +234,9 @@ echo "rm -rf /data/misc/$MISC_PATH" >> "${MODPATH}/uninstall.sh" || abortC "! ${
echo "[[ -f /data/adb/lspd/new_install ]] || rm -rf /data/adb/lspd" >> "${MODPATH}/uninstall.sh" || abortC "! ${LANG_CUST_ERR_CONF_UNINST}"
if [ $VARIANT == 17 ]; then # YAHFA
echo "1" > /data/misc/$MISC_PATH/variant
echo "1" > /data/adb/lspd/config/variant
elif [ $VARIANT == 18 ]; then # SandHook
echo "2" > /data/misc/$MISC_PATH/variant
echo "2" > /data/adb/lspd/config/variant
else
abortC "${LANG_UTIL_ERR_VARIANT_UNSUPPORT} ${VARIANT}"
fi
@ -241,12 +245,6 @@ if [[ ! -e /data/misc/$MISC_PATH/disable_verbose_log ]]; then
echo "1" > /data/misc/$MISC_PATH/disable_verbose_log
fi
ui_print "- ${LANG_CUST_INST_COPY_LIB}"
rm -rf "/data/misc/$MISC_PATH/framework"
mv "${MODPATH}/system/framework" "/data/misc/$MISC_PATH/framework"
set_perm_recursive /data/misc/$MISC_PATH/framework root root 0755 0644 "u:object_r:magisk_file:s0" || abortC "! ${LANG_CUST_ERR_PERM}"
mkdir -p /data/misc/$MISC_PATH/cache
rm /data/misc/$MISC_PATH/cache/*

View File

@ -27,7 +27,4 @@ if [[ -f "${MODDIR}/reboot_twice_flag" ]]; then
reboot
fi
MISC_PATH=$(cat /data/adb/lspd/misc_path)
BASE_PATH="/data/misc/$MISC_PATH"
/system/bin/app_process -Djava.class.path=${BASE_PATH}/framework/lspd.dex /system/bin --nice-name=lspd io.github.lsposed.lspd.core.Main
/system/bin/app_process -Djava.class.path=/data/adb/lspd/framework/lspd.dex /system/bin --nice-name=lspd io.github.lsposed.lspd.core.Main