Make dex2oat wrapper more compatible (#2372)
This commit is contained in:
parent
e3b06ba5a6
commit
3d11c2f0f7
|
|
@ -151,7 +151,7 @@ dependencies {
|
||||||
implementation("androidx.recyclerview:recyclerview:1.2.1")
|
implementation("androidx.recyclerview:recyclerview:1.2.1")
|
||||||
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.2.0-alpha01")
|
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.2.0-alpha01")
|
||||||
implementation("com.github.bumptech.glide:glide:$glideVersion")
|
implementation("com.github.bumptech.glide:glide:$glideVersion")
|
||||||
implementation("com.google.android.material:material:1.7.0")
|
implementation("com.google.android.material:material:1.8.0")
|
||||||
implementation("com.google.code.gson:gson:2.10.1")
|
implementation("com.google.code.gson:gson:2.10.1")
|
||||||
implementation(platform("com.squareup.okhttp3:okhttp-bom:4.10.0"))
|
implementation(platform("com.squareup.okhttp3:okhttp-bom:4.10.0"))
|
||||||
implementation("com.squareup.okhttp3:okhttp")
|
implementation("com.squareup.okhttp3:okhttp")
|
||||||
|
|
|
||||||
|
|
@ -109,15 +109,17 @@ public class HomeFragment extends BaseFragment {
|
||||||
binding.updateCard.setVisibility(View.GONE);
|
binding.updateCard.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
boolean dex2oatAbnormal = ConfigManager.getDex2OatWrapperCompatibility() != ILSPManagerService.DEX2OAT_OK && !ConfigManager.dex2oatFlagsLoaded();
|
boolean dex2oatAbnormal = ConfigManager.getDex2OatWrapperCompatibility() != ILSPManagerService.DEX2OAT_OK && !ConfigManager.dex2oatFlagsLoaded();
|
||||||
if (!ConfigManager.isSepolicyLoaded() || !ConfigManager.systemServerRequested() || dex2oatAbnormal) {
|
var sepolicyAbnormal = !ConfigManager.isSepolicyLoaded();
|
||||||
|
var systemServerAbnormal = !ConfigManager.systemServerRequested();
|
||||||
|
if (sepolicyAbnormal || systemServerAbnormal || dex2oatAbnormal) {
|
||||||
binding.statusTitle.setText(R.string.partial_activated);
|
binding.statusTitle.setText(R.string.partial_activated);
|
||||||
binding.statusIcon.setImageResource(R.drawable.ic_round_warning_24);
|
binding.statusIcon.setImageResource(R.drawable.ic_round_warning_24);
|
||||||
binding.warningCard.setVisibility(View.VISIBLE);
|
binding.warningCard.setVisibility(View.VISIBLE);
|
||||||
if (!ConfigManager.isSepolicyLoaded()) {
|
if (sepolicyAbnormal) {
|
||||||
binding.warningTitle.setText(R.string.selinux_policy_not_loaded_summary);
|
binding.warningTitle.setText(R.string.selinux_policy_not_loaded_summary);
|
||||||
binding.warningSummary.setText(HtmlCompat.fromHtml(getString(R.string.selinux_policy_not_loaded), HtmlCompat.FROM_HTML_MODE_LEGACY));
|
binding.warningSummary.setText(HtmlCompat.fromHtml(getString(R.string.selinux_policy_not_loaded), HtmlCompat.FROM_HTML_MODE_LEGACY));
|
||||||
}
|
}
|
||||||
if (!ConfigManager.systemServerRequested()) {
|
if (systemServerAbnormal) {
|
||||||
binding.warningTitle.setText(R.string.system_inject_fail_summary);
|
binding.warningTitle.setText(R.string.system_inject_fail_summary);
|
||||||
binding.warningSummary.setText(HtmlCompat.fromHtml(getString(R.string.system_inject_fail), HtmlCompat.FROM_HTML_MODE_LEGACY));
|
binding.warningSummary.setText(HtmlCompat.fromHtml(getString(R.string.system_inject_fail), HtmlCompat.FROM_HTML_MODE_LEGACY));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@
|
||||||
<string name="activated">Activated</string>
|
<string name="activated">Activated</string>
|
||||||
<string name="partial_activated">Partially activated</string>
|
<string name="partial_activated">Partially activated</string>
|
||||||
<string name="selinux_policy_not_loaded_summary">SEPolicy is not loaded properly</string>
|
<string name="selinux_policy_not_loaded_summary">SEPolicy is not loaded properly</string>
|
||||||
<string name="selinux_policy_not_loaded"><![CDATA[Modules that hook System Framework will not work.<br/>Please report this to <a href="https://github.com/topjohnwu/Magisk/issues"><b>Magisk</b></a> developer.]]></string>
|
<string name="selinux_policy_not_loaded"><![CDATA[Some features will not work.<br/>Please report this to <a href="https://github.com/topjohnwu/Magisk/issues"><b>Magisk</b></a> developer.]]></string>
|
||||||
<string name="system_inject_fail_summary">System Framework injection failed</string>
|
<string name="system_inject_fail_summary">System Framework injection failed</string>
|
||||||
<string name="system_inject_fail"><![CDATA[This is rare and may be caused by <b>Magisk</b> or some low-quality Magisk modules.<br/>Please try to disable Magisk modules other than Riru and LSPosed or submit full log to developers.]]></string>
|
<string name="system_inject_fail"><![CDATA[This is rare and may be caused by <b>Magisk</b> or some low-quality Magisk modules.<br/>Please try to disable Magisk modules other than Riru and LSPosed or submit full log to developers.]]></string>
|
||||||
<string name="system_prop_incorrect_summary">System prop incorrect</string>
|
<string name="system_prop_incorrect_summary">System prop incorrect</string>
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@ import com.android.build.api.variant.ApplicationAndroidComponentsExtension
|
||||||
import com.android.build.gradle.BaseExtension
|
import com.android.build.gradle.BaseExtension
|
||||||
import org.eclipse.jgit.api.Git
|
import org.eclipse.jgit.api.Git
|
||||||
import org.eclipse.jgit.storage.file.FileRepositoryBuilder
|
import org.eclipse.jgit.storage.file.FileRepositoryBuilder
|
||||||
import java.nio.file.Paths
|
|
||||||
import org.gradle.internal.os.OperatingSystem
|
import org.gradle.internal.os.OperatingSystem
|
||||||
|
import java.nio.file.Paths
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("com.android.application") apply false
|
id("com.android.application") apply false
|
||||||
|
|
@ -122,7 +122,7 @@ fun Project.configureBaseExtension() {
|
||||||
"-DINJECTED_AID=$injectedPackageUid",
|
"-DINJECTED_AID=$injectedPackageUid",
|
||||||
)
|
)
|
||||||
cppFlags("-std=c++20", *flags)
|
cppFlags("-std=c++20", *flags)
|
||||||
cFlags("-std=c18", *flags)
|
cFlags("-std=c2x", *flags)
|
||||||
arguments(
|
arguments(
|
||||||
"-DANDROID_STL=none",
|
"-DANDROID_STL=none",
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -104,8 +104,6 @@ public class ConfigManager {
|
||||||
private long lastScopeCacheTime = 0;
|
private long lastScopeCacheTime = 0;
|
||||||
private long requestScopeCacheTime = 0;
|
private long requestScopeCacheTime = 0;
|
||||||
|
|
||||||
private boolean sepolicyLoaded = true;
|
|
||||||
|
|
||||||
private String api = "(???)";
|
private String api = "(???)";
|
||||||
|
|
||||||
static class ProcessScope {
|
static class ProcessScope {
|
||||||
|
|
@ -184,7 +182,6 @@ public class ConfigManager {
|
||||||
// for system server, cache is not yet ready, we need to query database for it
|
// for system server, cache is not yet ready, we need to query database for it
|
||||||
public boolean shouldSkipSystemServer() {
|
public boolean shouldSkipSystemServer() {
|
||||||
if (!SELinux.checkSELinuxAccess("u:r:system_server:s0", "u:r:system_server:s0", "process", "execmem")) {
|
if (!SELinux.checkSELinuxAccess("u:r:system_server:s0", "u:r:system_server:s0", "process", "execmem")) {
|
||||||
sepolicyLoaded = false;
|
|
||||||
Log.e(TAG, "skip injecting into android because sepolicy was not loaded properly");
|
Log.e(TAG, "skip injecting into android because sepolicy was not loaded properly");
|
||||||
return true; // skip
|
return true; // skip
|
||||||
}
|
}
|
||||||
|
|
@ -1021,10 +1018,6 @@ public class ConfigManager {
|
||||||
ConfigFileManager.deleteFolderIfExists(path);
|
ConfigFileManager.deleteFolderIfExists(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSepolicyLoaded() {
|
|
||||||
return sepolicyLoaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getDenyListPackages() {
|
public List<String> getDenyListPackages() {
|
||||||
List<String> result = new ArrayList<>();
|
List<String> result = new ArrayList<>();
|
||||||
if (!getApi().equals("Zygisk")) return result;
|
if (!getApi().equals("Zygisk")) return result;
|
||||||
|
|
|
||||||
|
|
@ -26,247 +26,194 @@ import static org.lsposed.lspd.ILSPManagerService.DEX2OAT_SELINUX_PERMISSIVE;
|
||||||
import static org.lsposed.lspd.ILSPManagerService.DEX2OAT_SEPOLICY_INCORRECT;
|
import static org.lsposed.lspd.ILSPManagerService.DEX2OAT_SEPOLICY_INCORRECT;
|
||||||
|
|
||||||
import android.net.LocalServerSocket;
|
import android.net.LocalServerSocket;
|
||||||
import android.net.LocalSocket;
|
|
||||||
import android.net.LocalSocketAddress;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.FileObserver;
|
import android.os.FileObserver;
|
||||||
import android.os.SELinux;
|
import android.os.SELinux;
|
||||||
import android.system.ErrnoException;
|
import android.system.ErrnoException;
|
||||||
import android.system.Os;
|
import android.system.Os;
|
||||||
import android.system.OsConstants;
|
import android.system.OsConstants;
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.RequiresApi;
|
import androidx.annotation.RequiresApi;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InterruptedIOException;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.Arrays;
|
import java.util.ArrayList;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class Dex2OatService {
|
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.Q)
|
||||||
|
public class Dex2OatService implements Runnable {
|
||||||
public static final String PROP_NAME = "dalvik.vm.dex2oat-flags";
|
public static final String PROP_NAME = "dalvik.vm.dex2oat-flags";
|
||||||
public static final String PROP_VALUE = "--inline-max-code-units=0";
|
public static final String PROP_VALUE = "--inline-max-code-units=0";
|
||||||
private static final String TAG = "LSPosedDex2Oat";
|
private static final String TAG = "LSPosedDex2Oat";
|
||||||
|
private static final String WRAPPER32 = "bin/dex2oat32";
|
||||||
|
private static final String WRAPPER64 = "bin/dex2oat64";
|
||||||
|
|
||||||
private String devTmpDir, magiskPath, fakeBin32, fakeBin64;
|
private final String[] dex2oatArray = new String[4];
|
||||||
private String[] dex2oatBinaries;
|
private final FileDescriptor[] fdArray = new FileDescriptor[4];
|
||||||
private FileDescriptor[] stockFds;
|
private final FileObserver selinuxObserver;
|
||||||
private LocalSocket serverSocket = null;
|
|
||||||
private LocalServerSocket server = null;
|
|
||||||
private int compatibility = DEX2OAT_OK;
|
private int compatibility = DEX2OAT_OK;
|
||||||
|
|
||||||
private final FileObserver selinuxObserver = new FileObserver("/sys/fs/selinux/enforce", FileObserver.MODIFY) {
|
private void openDex2oat(int id, String path) {
|
||||||
@Override
|
try {
|
||||||
public void onEvent(int i, @Nullable String s) {
|
var fd = Os.open(path, OsConstants.O_RDONLY, 0);
|
||||||
Log.d(TAG, "SELinux status changed");
|
dex2oatArray[id] = path;
|
||||||
synchronized (this) {
|
fdArray[id] = fd;
|
||||||
if (compatibility == DEX2OAT_CRASHED) stopWatching();
|
} catch (ErrnoException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dex2OatService() {
|
||||||
|
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
|
||||||
|
openDex2oat(0, "/apex/com.android.runtime/bin/dex2oat");
|
||||||
|
openDex2oat(1, "/apex/com.android.runtime/bin/dex2oatd");
|
||||||
|
} else {
|
||||||
|
openDex2oat(0, "/apex/com.android.art/bin/dex2oat32");
|
||||||
|
openDex2oat(1, "/apex/com.android.art/bin/dex2oatd32");
|
||||||
|
openDex2oat(2, "/apex/com.android.art/bin/dex2oat64");
|
||||||
|
openDex2oat(3, "/apex/com.android.art/bin/dex2oatd64");
|
||||||
|
}
|
||||||
|
|
||||||
|
var enforce = Paths.get("/sys/fs/selinux/enforce");
|
||||||
|
var policy = Paths.get("/sys/fs/selinux/policy");
|
||||||
|
var list = new ArrayList<File>();
|
||||||
|
list.add(enforce.toFile());
|
||||||
|
list.add(policy.toFile());
|
||||||
|
selinuxObserver = new FileObserver(list, FileObserver.CLOSE_WRITE) {
|
||||||
|
@Override
|
||||||
|
public synchronized void onEvent(int i, @Nullable String s) {
|
||||||
|
Log.d(TAG, "SELinux status changed");
|
||||||
|
if (compatibility == DEX2OAT_CRASHED) {
|
||||||
|
stopWatching();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
boolean enforcing = false;
|
boolean enforcing = false;
|
||||||
try (var is = Files.newInputStream(Paths.get("/sys/fs/selinux/enforce"))) {
|
try (var is = Files.newInputStream(enforce)) {
|
||||||
enforcing = is.read() == '1';
|
enforcing = is.read() == '1';
|
||||||
} catch (IOException ignored) {
|
} catch (IOException ignored) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!enforcing) {
|
if (!enforcing) {
|
||||||
if (compatibility == DEX2OAT_OK) setEnabled(false);
|
if (compatibility == DEX2OAT_OK) doMount(false);
|
||||||
compatibility = DEX2OAT_SELINUX_PERMISSIVE;
|
compatibility = DEX2OAT_SELINUX_PERMISSIVE;
|
||||||
} else if (SELinux.checkSELinuxAccess("u:r:untrusted_app:s0", "u:object_r:dex2oat_exec:s0", "file", "execute")
|
} else if (SELinux.checkSELinuxAccess("u:r:untrusted_app:s0",
|
||||||
|| SELinux.checkSELinuxAccess("u:r:untrusted_app:s0", "u:object_r:dex2oat_exec:s0", "file", "execute_no_trans")) {
|
"u:object_r:dex2oat_exec:s0", "file", "execute")
|
||||||
if (compatibility == DEX2OAT_OK) setEnabled(false);
|
|| SELinux.checkSELinuxAccess("u:r:untrusted_app:s0",
|
||||||
|
"u:object_r:dex2oat_exec:s0", "file", "execute_no_trans")) {
|
||||||
|
if (compatibility == DEX2OAT_OK) doMount(false);
|
||||||
compatibility = DEX2OAT_SEPOLICY_INCORRECT;
|
compatibility = DEX2OAT_SEPOLICY_INCORRECT;
|
||||||
} else {
|
} else if (compatibility != DEX2OAT_OK) {
|
||||||
if (compatibility != DEX2OAT_OK) {
|
doMount(true);
|
||||||
setEnabled(true);
|
if (notMounted()) {
|
||||||
if (checkMount()) compatibility = DEX2OAT_OK;
|
doMount(false);
|
||||||
else {
|
compatibility = DEX2OAT_MOUNT_FAILED;
|
||||||
setEnabled(false);
|
stopWatching();
|
||||||
compatibility = DEX2OAT_MOUNT_FAILED;
|
} else {
|
||||||
stopWatching();
|
compatibility = DEX2OAT_OK;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stopWatching() {
|
public void stopWatching() {
|
||||||
super.stopWatching();
|
super.stopWatching();
|
||||||
Log.w(TAG, "SELinux observer stopped");
|
Log.w(TAG, "SELinux observer stopped");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.Q)
|
private boolean notMounted() {
|
||||||
public Dex2OatService() {
|
for (int i = 0; i < dex2oatArray.length; i++) {
|
||||||
initNative();
|
var bin = dex2oatArray[i];
|
||||||
try {
|
if (bin == null) continue;
|
||||||
Files.walk(Paths.get(magiskPath).resolve("dex2oat")).forEach(path -> SELinux.setFileContext(path.toString(), "u:object_r:magisk_file:s0"));
|
try {
|
||||||
} catch (IOException e) {
|
var apex = Os.stat("/proc/1/root" + bin);
|
||||||
Log.e(TAG, "Error setting sepolicy", e);
|
var wrapper = Os.stat(i < 2 ? WRAPPER32 : WRAPPER64);
|
||||||
}
|
if (apex.st_dev != wrapper.st_dev || apex.st_ino != wrapper.st_ino) {
|
||||||
if (Arrays.stream(dex2oatBinaries).noneMatch(Objects::nonNull)) {
|
Log.w(TAG, "Check mount failed for " + bin);
|
||||||
Log.e(TAG, "Failed to find dex2oat binaries");
|
return true;
|
||||||
compatibility = DEX2OAT_MOUNT_FAILED;
|
}
|
||||||
return;
|
} catch (ErrnoException e) {
|
||||||
|
Log.e(TAG, "Check mount failed for " + bin, e);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Log.d(TAG, "Check mount succeeded");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!checkMount()) { // Already mounted when restart daemon
|
private void doMount(boolean enabled) {
|
||||||
setEnabled(true);
|
doMountNative(enabled, dex2oatArray[0], dex2oatArray[1], dex2oatArray[2], dex2oatArray[3]);
|
||||||
if (!checkMount()) {
|
}
|
||||||
setEnabled(false);
|
|
||||||
|
public void start() {
|
||||||
|
if (notMounted()) { // Already mounted when restart daemon
|
||||||
|
doMount(true);
|
||||||
|
if (notMounted()) {
|
||||||
|
doMount(false);
|
||||||
compatibility = DEX2OAT_MOUNT_FAILED;
|
compatibility = DEX2OAT_MOUNT_FAILED;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread daemonThread = new Thread(() -> {
|
var thread = new Thread(this);
|
||||||
var devPath = Paths.get(devTmpDir);
|
thread.setName("dex2oat");
|
||||||
var sockPath = devPath.resolve("dex2oat.sock");
|
thread.start();
|
||||||
try {
|
|
||||||
Log.i(TAG, "Dex2oat wrapper daemon start");
|
|
||||||
if (setSocketCreateContext("u:r:dex2oat:s0")) {
|
|
||||||
Log.d(TAG, "Set socket context to u:r:dex2oat:s0");
|
|
||||||
} else {
|
|
||||||
throw new IOException("Failed to set socket context");
|
|
||||||
}
|
|
||||||
Files.createDirectories(devPath);
|
|
||||||
Log.d(TAG, "Dev path: " + devPath);
|
|
||||||
|
|
||||||
serverSocket = new LocalSocket(LocalSocket.SOCKET_STREAM);
|
|
||||||
serverSocket.bind(new LocalSocketAddress(sockPath.toString(), LocalSocketAddress.Namespace.FILESYSTEM));
|
|
||||||
server = new LocalServerSocket(serverSocket.getFileDescriptor());
|
|
||||||
SELinux.setFileContext(sockPath.toString(), "u:object_r:magisk_file:s0");
|
|
||||||
stockFds = new FileDescriptor[dex2oatBinaries.length];
|
|
||||||
for (int i = 0; i < dex2oatBinaries.length; i++) {
|
|
||||||
if (dex2oatBinaries[i] != null) {
|
|
||||||
stockFds[i] = Os.open(dex2oatBinaries[i], OsConstants.O_RDONLY, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
var client = server.accept();
|
|
||||||
try (var is = client.getInputStream();
|
|
||||||
var os = client.getOutputStream()) {
|
|
||||||
var id = is.read();
|
|
||||||
client.setFileDescriptorsForSend(new FileDescriptor[]{stockFds[id]});
|
|
||||||
os.write(1);
|
|
||||||
Log.d(TAG, String.format("Sent stock fd: is64 = %b, isDebug = %b", (id & 0b10) != 0, (id & 0b01) != 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
Log.e(TAG, "Dex2oat wrapper daemon crashed", e);
|
|
||||||
try {
|
|
||||||
server.close();
|
|
||||||
Files.delete(sockPath);
|
|
||||||
} catch (IOException ignored) {
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
for (var fd : stockFds) {
|
|
||||||
if (fd != null && fd.valid()) Os.close(fd);
|
|
||||||
}
|
|
||||||
} catch (ErrnoException ignored) {
|
|
||||||
}
|
|
||||||
synchronized (this) {
|
|
||||||
selinuxObserver.stopWatching();
|
|
||||||
if (compatibility == DEX2OAT_OK) {
|
|
||||||
setEnabled(false);
|
|
||||||
compatibility = DEX2OAT_CRASHED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
daemonThread.start();
|
|
||||||
selinuxObserver.startWatching();
|
selinuxObserver.startWatching();
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.Q)
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Log.i(TAG, "Dex2oat wrapper daemon start");
|
||||||
|
var sockPath = getSockPath();
|
||||||
|
Log.d(TAG, "wrapper path: " + sockPath);
|
||||||
|
var magisk_file = "u:object_r:magisk_file:s0";
|
||||||
|
var dex2oat_exec = "u:object_r:dex2oat_exec:s0";
|
||||||
|
if (SELinux.checkSELinuxAccess("u:r:dex2oat:s0", dex2oat_exec,
|
||||||
|
"file", "execute_no_trans")) {
|
||||||
|
SELinux.setFileContext(WRAPPER32, dex2oat_exec);
|
||||||
|
SELinux.setFileContext(WRAPPER64, dex2oat_exec);
|
||||||
|
setSockCreateContext("u:r:dex2oat:s0");
|
||||||
|
} else {
|
||||||
|
SELinux.setFileContext(WRAPPER32, magisk_file);
|
||||||
|
SELinux.setFileContext(WRAPPER64, magisk_file);
|
||||||
|
setSockCreateContext("u:r:installd:s0");
|
||||||
|
}
|
||||||
|
try (var server = new LocalServerSocket(sockPath)) {
|
||||||
|
setSockCreateContext(null);
|
||||||
|
while (true) {
|
||||||
|
try (var client = server.accept();
|
||||||
|
var is = client.getInputStream();
|
||||||
|
var os = client.getOutputStream()) {
|
||||||
|
var id = is.read();
|
||||||
|
var fd = new FileDescriptor[]{fdArray[id]};
|
||||||
|
client.setFileDescriptorsForSend(fd);
|
||||||
|
os.write(1);
|
||||||
|
Log.d(TAG, "Sent stock fd: is64 = " + ((id & 0b10) != 0) +
|
||||||
|
", isDebug = " + ((id & 0b01) != 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Dex2oat wrapper daemon crashed", e);
|
||||||
|
if (compatibility == DEX2OAT_OK) {
|
||||||
|
doMount(false);
|
||||||
|
compatibility = DEX2OAT_CRASHED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public int getCompatibility() {
|
public int getCompatibility() {
|
||||||
return compatibility;
|
return compatibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
private native void initNative();
|
private native void doMountNative(boolean enabled,
|
||||||
|
String r32, String d32, String r64, String d64);
|
||||||
|
|
||||||
private native void setEnabled(boolean enabled);
|
private static native boolean setSockCreateContext(String context);
|
||||||
|
|
||||||
private boolean checkMount() {
|
private native String getSockPath();
|
||||||
for (int i = 0; i < dex2oatBinaries.length; i++) {
|
|
||||||
var bin = dex2oatBinaries[i];
|
|
||||||
if (bin == null) continue;
|
|
||||||
try {
|
|
||||||
var apex = Os.stat("/proc/1/root" + bin);
|
|
||||||
var fake = Os.stat(i < 2 ? fakeBin32 : fakeBin64);
|
|
||||||
if (apex.st_ino != fake.st_ino) {
|
|
||||||
Log.w(TAG, "Check mount failed for " + bin);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (ErrnoException e) {
|
|
||||||
Log.e(TAG, "Check mount failed for " + bin, e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Log.d(TAG, "Check mount succeeded");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean setSocketCreateContext(String context) {
|
|
||||||
FileDescriptor fd = null;
|
|
||||||
try {
|
|
||||||
fd = Os.open("/proc/thread-self/attr/sockcreate", OsConstants.O_RDWR, 0);
|
|
||||||
} catch (ErrnoException e) {
|
|
||||||
if (e.errno == OsConstants.ENOENT) {
|
|
||||||
int tid = Os.gettid();
|
|
||||||
try {
|
|
||||||
fd = Os.open(String.format(Locale.ENGLISH, "/proc/self/task/%d/attr/sockcreate", tid), OsConstants.O_RDWR, 0);
|
|
||||||
} catch (ErrnoException ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fd == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] bytes;
|
|
||||||
int length;
|
|
||||||
int remaining;
|
|
||||||
if (!TextUtils.isEmpty(context)) {
|
|
||||||
byte[] stringBytes = context.getBytes();
|
|
||||||
bytes = new byte[stringBytes.length + 1];
|
|
||||||
System.arraycopy(stringBytes, 0, bytes, 0, stringBytes.length);
|
|
||||||
bytes[stringBytes.length] = '\0';
|
|
||||||
|
|
||||||
length = bytes.length;
|
|
||||||
remaining = bytes.length;
|
|
||||||
} else {
|
|
||||||
bytes = null;
|
|
||||||
length = 0;
|
|
||||||
remaining = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
try {
|
|
||||||
remaining -= Os.write(fd, bytes, length - remaining, remaining);
|
|
||||||
if (remaining <= 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} catch (ErrnoException e) {
|
|
||||||
break;
|
|
||||||
} catch (InterruptedIOException e) {
|
|
||||||
remaining -= e.bytesTransferred;
|
|
||||||
}
|
|
||||||
} while (true);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Os.close(fd);
|
|
||||||
} catch (ErrnoException e) {
|
|
||||||
Log.w(TAG, Log.getStackTraceString(e));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -469,7 +469,8 @@ public class LSPManagerService extends ILSPManagerService.Stub {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSepolicyLoaded() {
|
public boolean isSepolicyLoaded() {
|
||||||
return ConfigManager.getInstance().isSepolicyLoaded();
|
return SELinux.checkSELinuxAccess("u:r:dex2oat:s0", "u:object_r:dex2oat_exec:s0",
|
||||||
|
"file", "execute_no_trans");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,7 @@ public class ServiceManager {
|
||||||
systemServerService = new LSPSystemServerService(systemServerMaxRetry);
|
systemServerService = new LSPSystemServerService(systemServerMaxRetry);
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
dex2OatService = new Dex2OatService();
|
dex2OatService = new Dex2OatService();
|
||||||
|
dex2OatService.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
systemServerService.putBinderForSystemServer();
|
systemServerService.putBinderForSystemServer();
|
||||||
|
|
|
||||||
|
|
@ -14,131 +14,105 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2022 LSPosed Contributors
|
* Copyright (C) 2023 LSPosed Contributors
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//
|
|
||||||
// Created by Nullptr on 2022/4/2.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include <sched.h>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
|
||||||
#include <sys/inotify.h>
|
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#include <sys/sendfile.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/system_properties.h>
|
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
using namespace std::string_literals;
|
|
||||||
|
|
||||||
const char *kDex2oat32Path, *kDex2oatDebug32Path;
|
|
||||||
const char *kDex2oat64Path, *kDex2oatDebug64Path;
|
|
||||||
|
|
||||||
char kFakeBin32[PATH_MAX], kFakeBin64[PATH_MAX];
|
|
||||||
char kTmpDir[] = "placeholder_/dev/0123456789abcdef\0";
|
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_org_lsposed_lspd_service_Dex2OatService_initNative(JNIEnv *env, jobject thiz) {
|
Java_org_lsposed_lspd_service_Dex2OatService_doMountNative(JNIEnv *env, jobject,
|
||||||
char magisk_path[PATH_MAX], cwd[PATH_MAX], *module_name;
|
jboolean enabled,
|
||||||
FILE *fp = popen("magisk --path", "r");
|
jstring r32, jstring d32,
|
||||||
fscanf(fp, "%s", magisk_path);
|
jstring r64, jstring d64) {
|
||||||
fclose(fp);
|
char dex2oat32[PATH_MAX], dex2oat64[PATH_MAX];
|
||||||
getcwd(cwd, PATH_MAX);
|
realpath("bin/dex2oat32", dex2oat32);
|
||||||
module_name = cwd + std::string_view(cwd).find_last_of('/') + 1;
|
realpath("bin/dex2oat64", dex2oat64);
|
||||||
sprintf(kFakeBin32, "%s/.magisk/modules/%s/bin/dex2oat32", magisk_path, module_name);
|
|
||||||
sprintf(kFakeBin64, "%s/.magisk/modules/%s/bin/dex2oat64", magisk_path, module_name);
|
|
||||||
|
|
||||||
if (GetAndroidApiLevel() == 29) {
|
|
||||||
kDex2oat32Path = "/apex/com.android.runtime/bin/dex2oat";
|
|
||||||
kDex2oatDebug32Path = "/apex/com.android.runtime/bin/dex2oatd";
|
|
||||||
} else {
|
|
||||||
kDex2oat32Path = "/apex/com.android.art/bin/dex2oat32";
|
|
||||||
kDex2oatDebug32Path = "/apex/com.android.art/bin/dex2oatd32";
|
|
||||||
kDex2oat64Path = "/apex/com.android.art/bin/dex2oat64";
|
|
||||||
kDex2oatDebug64Path = "/apex/com.android.art/bin/dex2oatd64";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string copy_dir = magisk_path + "/dex2oat"s;
|
|
||||||
mkdir(copy_dir.c_str(), 0755);
|
|
||||||
auto CopyAndMount = [&](const char *src, const std::string &target) -> bool {
|
|
||||||
int stock = open(src, O_RDONLY);
|
|
||||||
if (stock == -1) return false;
|
|
||||||
struct stat st{};
|
|
||||||
fstat(stock, &st);
|
|
||||||
int copy = open(target.c_str(), O_WRONLY | O_CREAT, st.st_mode);
|
|
||||||
sendfile(copy, stock, nullptr, st.st_size);
|
|
||||||
close(stock);
|
|
||||||
close(copy);
|
|
||||||
mount(target.c_str(), src, nullptr, MS_BIND, nullptr);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
bool done[4] = {false};
|
|
||||||
done[0] = CopyAndMount(kDex2oat32Path, copy_dir + "/dex2oat32");
|
|
||||||
done[1] = CopyAndMount(kDex2oatDebug32Path, copy_dir + "/dex2oatd32");
|
|
||||||
if (GetAndroidApiLevel() >= 30) {
|
|
||||||
done[2] = CopyAndMount(kDex2oat64Path, copy_dir + "/dex2oat64");
|
|
||||||
done[3] = CopyAndMount(kDex2oatDebug64Path, copy_dir + "/dex2oatd64");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto clazz = env->GetObjectClass(thiz);
|
|
||||||
auto dev_path_field = env->GetFieldID(clazz, "devTmpDir", "Ljava/lang/String;");
|
|
||||||
auto magisk_path_field = env->GetFieldID(clazz, "magiskPath", "Ljava/lang/String;");
|
|
||||||
auto fake_bin32_field = env->GetFieldID(clazz, "fakeBin32", "Ljava/lang/String;");
|
|
||||||
auto fake_bin64_field = env->GetFieldID(clazz, "fakeBin64", "Ljava/lang/String;");
|
|
||||||
auto binaries_field = env->GetFieldID(clazz, "dex2oatBinaries", "[Ljava/lang/String;");
|
|
||||||
env->SetObjectField(thiz, dev_path_field, env->NewStringUTF(kTmpDir + 12));
|
|
||||||
env->SetObjectField(thiz, magisk_path_field, env->NewStringUTF(magisk_path));
|
|
||||||
env->SetObjectField(thiz, fake_bin32_field, env->NewStringUTF(kFakeBin32));
|
|
||||||
env->SetObjectField(thiz, fake_bin64_field, env->NewStringUTF(kFakeBin64));
|
|
||||||
auto arr = env->NewObjectArray(4, env->FindClass("java/lang/String"), nullptr);
|
|
||||||
if (done[0]) env->SetObjectArrayElement(arr, 0, env->NewStringUTF(kDex2oat32Path));
|
|
||||||
if (done[1]) env->SetObjectArrayElement(arr, 1, env->NewStringUTF(kDex2oatDebug32Path));
|
|
||||||
if (GetAndroidApiLevel() >= 30) {
|
|
||||||
if (done[2]) env->SetObjectArrayElement(arr, 2, env->NewStringUTF(kDex2oat64Path));
|
|
||||||
if (done[3]) env->SetObjectArrayElement(arr, 3, env->NewStringUTF(kDex2oatDebug64Path));
|
|
||||||
}
|
|
||||||
env->SetObjectField(thiz, binaries_field, arr);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
JNIEXPORT void JNICALL
|
|
||||||
Java_org_lsposed_lspd_service_Dex2OatService_setEnabled(JNIEnv *env, jobject thiz, jboolean enabled) {
|
|
||||||
if (pid_t pid = fork(); pid > 0) { // parent
|
if (pid_t pid = fork(); pid > 0) { // parent
|
||||||
waitpid(pid, nullptr, 0);
|
waitpid(pid, nullptr, 0);
|
||||||
} else { // child
|
} else { // child
|
||||||
int ns = open("/proc/1/ns/mnt", O_RDONLY);
|
int ns = open("/proc/1/ns/mnt", O_RDONLY);
|
||||||
setns(ns, CLONE_NEWNS);
|
setns(ns, CLONE_NEWNS);
|
||||||
close(ns);
|
close(ns);
|
||||||
|
|
||||||
|
const char *r32p, *d32p, *r64p, *d64p;
|
||||||
|
if (r32) r32p = env->GetStringUTFChars(r32, nullptr);
|
||||||
|
if (d32) d32p = env->GetStringUTFChars(d32, nullptr);
|
||||||
|
if (r64) r64p = env->GetStringUTFChars(r64, nullptr);
|
||||||
|
if (d64) d64p = env->GetStringUTFChars(d64, nullptr);
|
||||||
|
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
LOGI("Enable dex2oat wrapper");
|
LOGI("Enable dex2oat wrapper");
|
||||||
mount(kFakeBin32, kDex2oat32Path, nullptr, MS_BIND, nullptr);
|
if (r32) {
|
||||||
mount(kFakeBin32, kDex2oatDebug32Path, nullptr, MS_BIND, nullptr);
|
mount(dex2oat32, r32p, nullptr, MS_BIND, nullptr);
|
||||||
if (GetAndroidApiLevel() >= 30) {
|
mount(nullptr, r32p, nullptr, MS_BIND | MS_REMOUNT | MS_RDONLY, nullptr);
|
||||||
mount(kFakeBin64, kDex2oat64Path, nullptr, MS_BIND, nullptr);
|
}
|
||||||
mount(kFakeBin64, kDex2oatDebug64Path, nullptr, MS_BIND, nullptr);
|
if (d32) {
|
||||||
|
mount(dex2oat32, d32p, nullptr, MS_BIND, nullptr);
|
||||||
|
mount(nullptr, d32p, nullptr, MS_BIND | MS_REMOUNT | MS_RDONLY, nullptr);
|
||||||
|
}
|
||||||
|
if (r64) {
|
||||||
|
mount(dex2oat64, r64p, nullptr, MS_BIND, nullptr);
|
||||||
|
mount(nullptr, r64p, nullptr, MS_BIND | MS_REMOUNT | MS_RDONLY, nullptr);
|
||||||
|
}
|
||||||
|
if (d64) {
|
||||||
|
mount(dex2oat64, d64p, nullptr, MS_BIND, nullptr);
|
||||||
|
mount(nullptr, d64p, nullptr, MS_BIND | MS_REMOUNT | MS_RDONLY, nullptr);
|
||||||
}
|
}
|
||||||
execlp("resetprop", "resetprop", "--delete", "dalvik.vm.dex2oat-flags", nullptr);
|
execlp("resetprop", "resetprop", "--delete", "dalvik.vm.dex2oat-flags", nullptr);
|
||||||
} else {
|
} else {
|
||||||
LOGI("Disable dex2oat wrapper");
|
LOGI("Disable dex2oat wrapper");
|
||||||
umount(kDex2oat32Path);
|
if (r32) umount(r32p);
|
||||||
umount(kDex2oatDebug32Path);
|
if (d32) umount(d32p);
|
||||||
if (GetAndroidApiLevel() >= 30) {
|
if (r64) umount(r64p);
|
||||||
umount(kDex2oat64Path);
|
if (d64) umount(d64p);
|
||||||
umount(kDex2oatDebug64Path);
|
execlp("resetprop", "resetprop", "dalvik.vm.dex2oat-flags", "--inline-max-code-units=0",
|
||||||
}
|
nullptr);
|
||||||
execlp("resetprop", "resetprop", "dalvik.vm.dex2oat-flags", "--inline-max-code-units=0", nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PLOGE("Failed to resetprop");
|
PLOGE("Failed to resetprop");
|
||||||
exit(0);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int setsockcreatecon_raw(const char *context) {
|
||||||
|
std::string path = "/proc/self/task/" + std::to_string(gettid()) + "/attr/sockcreate";
|
||||||
|
int fd = open(path.c_str(), O_RDWR | O_CLOEXEC);
|
||||||
|
if (fd < 0) return -1;
|
||||||
|
int ret;
|
||||||
|
if (context) {
|
||||||
|
do {
|
||||||
|
ret = write(fd, context, strlen(context) + 1);
|
||||||
|
} while (ret < 0 && errno == EINTR);
|
||||||
|
} else {
|
||||||
|
do {
|
||||||
|
ret = write(fd, nullptr, 0); // clear
|
||||||
|
} while (ret < 0 && errno == EINTR);
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
return ret < 0 ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_org_lsposed_lspd_service_Dex2OatService_setSockCreateContext(JNIEnv *env, jclass,
|
||||||
|
jstring contextStr) {
|
||||||
|
const char *context = env->GetStringUTFChars(contextStr, nullptr);
|
||||||
|
int ret = setsockcreatecon_raw(context);
|
||||||
|
env->ReleaseStringUTFChars(contextStr, context);
|
||||||
|
return ret == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT jstring JNICALL
|
||||||
|
Java_org_lsposed_lspd_service_Dex2OatService_getSockPath(JNIEnv *env, jobject) {
|
||||||
|
return env->NewStringUTF("5291374ceda0aef7c5d86cd2a4f6a3ac\0");
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,35 +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) 2022 LSPosed Contributors
|
|
||||||
*/
|
|
||||||
|
|
||||||
//
|
|
||||||
// Created by Nullptr on 2022/4/20.
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
inline int32_t GetAndroidApiLevel() {
|
|
||||||
static int32_t api_level = []() {
|
|
||||||
char prop_value[PROP_VALUE_MAX];
|
|
||||||
__system_property_get("ro.build.version.sdk", prop_value);
|
|
||||||
int base = atoi(prop_value);
|
|
||||||
__system_property_get("ro.build.version.preview_sdk", prop_value);
|
|
||||||
return base + atoi(prop_value);
|
|
||||||
}();
|
|
||||||
return api_level;
|
|
||||||
}
|
|
||||||
|
|
@ -38,7 +38,7 @@
|
||||||
|
|
||||||
#define ID_VEC(is64, is_debug) (((is64) << 1) | (is_debug))
|
#define ID_VEC(is64, is_debug) (((is64) << 1) | (is_debug))
|
||||||
|
|
||||||
char kTmpDir[] = "placeholder_/dev/0123456789abcdef";
|
const char kSockName[] = "5291374ceda0aef7c5d86cd2a4f6a3ac\0";
|
||||||
|
|
||||||
static ssize_t xrecvmsg(int sockfd, struct msghdr *msg, int flags) {
|
static ssize_t xrecvmsg(int sockfd, struct msghdr *msg, int flags) {
|
||||||
int rec = recvmsg(sockfd, msg, flags);
|
int rec = recvmsg(sockfd, msg, flags);
|
||||||
|
|
@ -99,20 +99,21 @@ static void write_int(int fd, int val) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
LOGD("dex2oat wrapper");
|
LOGD("dex2oat wrapper ppid=%d", getppid());
|
||||||
struct sockaddr_un sock;
|
struct sockaddr_un sock = {};
|
||||||
sock.sun_family = AF_UNIX;
|
sock.sun_family = AF_UNIX;
|
||||||
snprintf(sock.sun_path, sizeof(sock.sun_path), "%s/dex2oat.sock", kTmpDir + 12);
|
strlcpy(sock.sun_path + 1, kSockName, sizeof(sock.sun_path) - 1);
|
||||||
int sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
int sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
if (-1 == connect(sock_fd, (struct sockaddr *) &sock, sizeof(sock))) {
|
size_t len = sizeof(sa_family_t) + strlen(sock.sun_path + 1) + 1;
|
||||||
PLOGE("failed to connect to %s", sock.sun_path);
|
if (connect(sock_fd, (struct sockaddr *) &sock, len)) {
|
||||||
|
PLOGE("failed to connect to %s", sock.sun_path + 1);
|
||||||
return 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") != NULL));
|
||||||
int stock_fd = recv_fd(sock_fd);
|
int stock_fd = recv_fd(sock_fd);
|
||||||
read_int(sock_fd);
|
read_int(sock_fd);
|
||||||
close(sock_fd);
|
close(sock_fd);
|
||||||
LOGD("sock: %s %d", sock.sun_path, stock_fd);
|
LOGD("sock: %s %d", sock.sun_path + 1, stock_fd);
|
||||||
|
|
||||||
const char *new_argv[argc + 2];
|
const char *new_argv[argc + 2];
|
||||||
for (int i = 0; i < argc; i++) new_argv[i] = argv[i];
|
for (int i = 0; i < argc; i++) new_argv[i] = argv[i];
|
||||||
|
|
|
||||||
|
|
@ -20,4 +20,4 @@ android.useAndroidX=true
|
||||||
|
|
||||||
agpVersion=7.4.1
|
agpVersion=7.4.1
|
||||||
navVersion=2.5.3
|
navVersion=2.5.3
|
||||||
kotlinVersion=1.8.0
|
kotlinVersion=1.8.10
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import org.apache.tools.ant.filters.FixCrLfFilter
|
||||||
import org.apache.tools.ant.filters.ReplaceTokens
|
import org.apache.tools.ant.filters.ReplaceTokens
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.util.*
|
import java.util.Locale
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("com.android.application")
|
id("com.android.application")
|
||||||
|
|
@ -87,7 +87,6 @@ android {
|
||||||
arguments += "-DAPI=${name.toLowerCase()}"
|
arguments += "-DAPI=${name.toLowerCase()}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buildConfigField("String", "API", """"$name"""")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
create("Riru") {
|
create("Riru") {
|
||||||
|
|
@ -148,7 +147,7 @@ fun afterEval() = android.applicationVariants.forEach { variant ->
|
||||||
into(magiskDir)
|
into(magiskDir)
|
||||||
from("${rootProject.projectDir}/README.md")
|
from("${rootProject.projectDir}/README.md")
|
||||||
from("$projectDir/magisk_module") {
|
from("$projectDir/magisk_module") {
|
||||||
exclude("riru.sh", "module.prop", "customize.sh", "sepolicy.rule", "daemon")
|
exclude("riru.sh", "module.prop", "customize.sh", "daemon")
|
||||||
}
|
}
|
||||||
from("$projectDir/magisk_module") {
|
from("$projectDir/magisk_module") {
|
||||||
include("module.prop")
|
include("module.prop")
|
||||||
|
|
@ -178,7 +177,7 @@ fun afterEval() = android.applicationVariants.forEach { variant ->
|
||||||
}
|
}
|
||||||
if (flavorLowered == "riru") {
|
if (flavorLowered == "riru") {
|
||||||
from("${projectDir}/magisk_module") {
|
from("${projectDir}/magisk_module") {
|
||||||
include("riru.sh", "sepolicy.rule")
|
include("riru.sh")
|
||||||
val tokens = mapOf(
|
val tokens = mapOf(
|
||||||
"RIRU_MODULE_LIB_NAME" to "lspd",
|
"RIRU_MODULE_LIB_NAME" to "lspd",
|
||||||
"RIRU_MODULE_API_VERSION" to moduleMaxRiruApiVersion.toString(),
|
"RIRU_MODULE_API_VERSION" to moduleMaxRiruApiVersion.toString(),
|
||||||
|
|
@ -294,7 +293,7 @@ val reRunDaemon = task<Exec>("reRunDaemon") {
|
||||||
dependsOn(pushDaemon, pushDaemonNative, killLspd)
|
dependsOn(pushDaemon, pushDaemonNative, killLspd)
|
||||||
// tricky to pass a minus number to avoid the injection warning
|
// tricky to pass a minus number to avoid the injection warning
|
||||||
commandLine(
|
commandLine(
|
||||||
adb, "shell", "ASH_STANDALONE=1", "su", "-pc",
|
adb, "shell", "ASH_STANDALONE=1", "su", "-mm", "-pc",
|
||||||
"/data/adb/magisk/busybox sh /data/adb/modules/*_lsposed/service.sh --system-server-max-retry=-1&"
|
"/data/adb/magisk/busybox sh /data/adb/modules/*_lsposed/service.sh --system-server-max-retry=-1&"
|
||||||
)
|
)
|
||||||
isIgnoreExitValue = true
|
isIgnoreExitValue = true
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ extract "$ZIPFILE" 'module.prop' "$MODPATH"
|
||||||
extract "$ZIPFILE" 'post-fs-data.sh' "$MODPATH"
|
extract "$ZIPFILE" 'post-fs-data.sh' "$MODPATH"
|
||||||
extract "$ZIPFILE" 'service.sh' "$MODPATH"
|
extract "$ZIPFILE" 'service.sh' "$MODPATH"
|
||||||
extract "$ZIPFILE" 'uninstall.sh' "$MODPATH"
|
extract "$ZIPFILE" 'uninstall.sh' "$MODPATH"
|
||||||
|
extract "$ZIPFILE" 'sepolicy.rule' "$MODPATH"
|
||||||
extract "$ZIPFILE" 'framework/lspd.dex' "$MODPATH"
|
extract "$ZIPFILE" 'framework/lspd.dex' "$MODPATH"
|
||||||
extract "$ZIPFILE" 'daemon.apk' "$MODPATH"
|
extract "$ZIPFILE" 'daemon.apk' "$MODPATH"
|
||||||
extract "$ZIPFILE" 'daemon' "$MODPATH"
|
extract "$ZIPFILE" 'daemon' "$MODPATH"
|
||||||
|
|
@ -110,7 +111,6 @@ if [ "$FLAVOR" == "zygisk" ]; then
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
elif [ "$FLAVOR" == "riru" ]; then
|
elif [ "$FLAVOR" == "riru" ]; then
|
||||||
extract "$ZIPFILE" 'sepolicy.rule' "$MODPATH"
|
|
||||||
mkdir "$MODPATH/riru"
|
mkdir "$MODPATH/riru"
|
||||||
mkdir "$MODPATH/riru/lib"
|
mkdir "$MODPATH/riru/lib"
|
||||||
mkdir "$MODPATH/riru/lib64"
|
mkdir "$MODPATH/riru/lib64"
|
||||||
|
|
@ -172,19 +172,16 @@ if [ "$API" -ge 29 ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ui_print "- Patching binaries"
|
ui_print "- Patching binaries"
|
||||||
DEV_PATH=$(tr -dc 'a-f0-9' < /dev/urandom | head -c 16)
|
DEV_PATH=$(tr -dc 'a-z0-9' < /dev/urandom | head -c 32)
|
||||||
while [ -d "/dev/$DEV_PATH" ]; do
|
sed -i "s/5291374ceda0aef7c5d86cd2a4f6a3ac/$DEV_PATH/g" "$MODPATH/daemon.apk"
|
||||||
DEV_PATH=$(tr -dc 'a-f0-9' < /dev/urandom | head -c 16)
|
sed -i "s/5291374ceda0aef7c5d86cd2a4f6a3ac/$DEV_PATH/" "$MODPATH/bin/dex2oat32"
|
||||||
done
|
sed -i "s/5291374ceda0aef7c5d86cd2a4f6a3ac/$DEV_PATH/" "$MODPATH/bin/dex2oat64"
|
||||||
sed -i "s/placeholder_\/dev\/................/placeholder_\/dev\/$DEV_PATH/g" "$MODPATH/daemon.apk"
|
|
||||||
sed -i "s/placeholder_\/dev\/................/placeholder_\/dev\/$DEV_PATH/" "$MODPATH/bin/dex2oat32"
|
|
||||||
sed -i "s/placeholder_\/dev\/................/placeholder_\/dev\/$DEV_PATH/" "$MODPATH/bin/dex2oat64"
|
|
||||||
else
|
else
|
||||||
extract "$ZIPFILE" 'system.prop' "$MODPATH"
|
extract "$ZIPFILE" 'system.prop' "$MODPATH"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
set_perm_recursive "$MODPATH" 0 0 0755 0644
|
set_perm_recursive "$MODPATH" 0 0 0755 0644
|
||||||
set_perm_recursive "$MODPATH/bin" 0 2000 0755 0755 u:object_r:dex2oat_exec:s0
|
set_perm_recursive "$MODPATH/bin" 0 2000 0755 0755 u:object_r:magisk_file:s0
|
||||||
chmod 0744 "$MODPATH/daemon"
|
chmod 0744 "$MODPATH/daemon"
|
||||||
|
|
||||||
if [ "$(grep_prop ro.maple.enable)" == "1" ] && [ "$FLAVOR" == "zygisk" ]; then
|
if [ "$(grep_prop ro.maple.enable)" == "1" ] && [ "$FLAVOR" == "zygisk" ]; then
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
#!/system/bin/sh
|
#!/system/bin/sh
|
||||||
|
|
||||||
dir=${0%/*}
|
dir=${0%/*}
|
||||||
magiskPath=$(magisk --path)
|
|
||||||
tmpLspdApk="/data/local/tmp/daemon.apk"
|
tmpLspdApk="/data/local/tmp/daemon.apk"
|
||||||
debug=@DEBUG@
|
debug=@DEBUG@
|
||||||
flavor=@FLAVOR@
|
flavor=@FLAVOR@
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
allow system_server system_server process execmem
|
allow dex2oat dex2oat_exec file execute_no_trans
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ public class BridgeService {
|
||||||
try {
|
try {
|
||||||
IApplicationThread at = ActivityThread.currentActivityThread().getApplicationThread();
|
IApplicationThread at = ActivityThread.currentActivityThread().getApplicationThread();
|
||||||
Context ctx = ActivityThread.currentActivityThread().getSystemContext();
|
Context ctx = ActivityThread.currentActivityThread().getSystemContext();
|
||||||
service.dispatchSystemServerContext(at.asBinder(), Context_getActivityToken(ctx), BuildConfig.API);
|
service.dispatchSystemServerContext(at.asBinder(), Context_getActivityToken(ctx), BuildConfig.FLAVOR);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
Log.e(TAG, "dispatch context: ", e);
|
Log.e(TAG, "dispatch context: ", e);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue