Fallback if dex2oat wrapper crashes (#1810)

* Fallback if dex2oat wrapper crashes

* Update daemon/src/main/java/org/lsposed/lspd/service/Dex2OatService.java

Co-authored-by: 残页 <31466456+canyie@users.noreply.github.com>

* Update

Co-authored-by: 残页 <31466456+canyie@users.noreply.github.com>
This commit is contained in:
Nullptr 2022-04-05 09:14:28 +08:00 committed by GitHub
parent a884c1b2ba
commit ee2c1a3320
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 102 additions and 34 deletions

View File

@ -359,4 +359,13 @@ public class ConfigManager {
return false; return false;
} }
} }
public static boolean dex2oatWrapperAlive() {
try {
return LSPManagerServiceHolder.getService().dex2oatWrapperAlive();
} catch (RemoteException e) {
Log.e(App.TAG, Log.getStackTraceString(e));
return false;
}
}
} }

View File

@ -107,7 +107,8 @@ public class HomeFragment extends BaseFragment {
} else { } else {
binding.updateCard.setVisibility(View.GONE); binding.updateCard.setVisibility(View.GONE);
} }
if (!ConfigManager.isSepolicyLoaded() || !ConfigManager.systemServerRequested() || !ConfigManager.dex2oatFlagsLoaded()) { boolean dex2oatAbnormal = !ConfigManager.dex2oatWrapperAlive() && !ConfigManager.dex2oatFlagsLoaded();
if (!ConfigManager.isSepolicyLoaded() || !ConfigManager.systemServerRequested() || 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);
@ -119,14 +120,9 @@ public class HomeFragment extends BaseFragment {
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));
} }
if (!ConfigManager.dex2oatFlagsLoaded()) { if (dex2oatAbnormal) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { binding.warningTitle.setText(R.string.system_prop_incorrect_summary);
binding.warningTitle.setText(R.string.dex2oat_service_crashed_summary); binding.warningSummary.setText(HtmlCompat.fromHtml(getString(R.string.system_prop_incorrect), HtmlCompat.FROM_HTML_MODE_LEGACY));
binding.warningSummary.setText(HtmlCompat.fromHtml(getString(R.string.dex2oat_service_crashed), HtmlCompat.FROM_HTML_MODE_LEGACY));
} else {
binding.warningTitle.setText(R.string.system_prop_incorrect_summary);
binding.warningSummary.setText(HtmlCompat.fromHtml(getString(R.string.system_prop_incorrect), HtmlCompat.FROM_HTML_MODE_LEGACY));
}
} }
} else { } else {
binding.warningCard.setVisibility(View.GONE); binding.warningCard.setVisibility(View.GONE);
@ -161,6 +157,13 @@ public class HomeFragment extends BaseFragment {
binding.apiVersion.setText(String.valueOf(ConfigManager.getXposedApiVersion())); binding.apiVersion.setText(String.valueOf(ConfigManager.getXposedApiVersion()));
binding.api.setText(ConfigManager.getApi()); binding.api.setText(ConfigManager.getApi());
binding.frameworkVersion.setText(String.format(LocaleDelegate.getDefaultLocale(), "%1$s (%2$d)", ConfigManager.getXposedVersionName(), ConfigManager.getXposedVersionCode())); binding.frameworkVersion.setText(String.format(LocaleDelegate.getDefaultLocale(), "%1$s (%2$d)", ConfigManager.getXposedVersionName(), ConfigManager.getXposedVersionCode()));
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
binding.dex2oatWrapper.setText(R.string.unsupported_android_version);
} else if (ConfigManager.dex2oatWrapperAlive()) {
binding.dex2oatWrapper.setText(R.string.supported);
} else {
binding.dex2oatWrapper.setText(R.string.unsupported_crashed);
}
} else { } else {
binding.apiVersion.setText(R.string.not_installed); binding.apiVersion.setText(R.string.not_installed);
binding.api.setText(R.string.not_installed); binding.api.setText(R.string.not_installed);

View File

@ -253,6 +253,19 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/not_installed" /> android:text="@string/not_installed" />
<com.google.android.material.textview.MaterialTextView
style="@style/DeviceInfoDialogLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/info_dex2oat_wrapper" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/dex2oat_wrapper"
style="@style/DeviceInfoDialogValue"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/not_installed" />
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
style="@style/DeviceInfoDialogLabel" style="@style/DeviceInfoDialogLabel"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -51,8 +51,6 @@
<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[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="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="dex2oat_service_crashed_summary">Dex optimizer service crashed</string>
<string name="dex2oat_service_crashed"><![CDATA[LSPosed dex2oat wrapper crashed.<br/>Modules may invalidate occasionally or applications may become laggy.]]></string>
<string name="system_prop_incorrect_summary">System prop incorrect</string> <string name="system_prop_incorrect_summary">System prop incorrect</string>
<string name="system_prop_incorrect"><![CDATA[Some necessary system properties deleted or modified.<br/>Modules may invalidate occasionally.]]></string> <string name="system_prop_incorrect"><![CDATA[Some necessary system properties deleted or modified.<br/>Modules may invalidate occasionally.]]></string>
<string name="need_update">Need to update</string> <string name="need_update">Need to update</string>
@ -65,6 +63,10 @@
<string name="info_device">Device</string> <string name="info_device">Device</string>
<string name="info_system_abi">System ABI</string> <string name="info_system_abi">System ABI</string>
<string name="info_api">Injection Interface</string> <string name="info_api">Injection Interface</string>
<string name="info_dex2oat_wrapper">Optimizer Wrapper</string>
<string name="supported">Supported</string>
<string name="unsupported_android_version">Unsupported (Android version unsatisfied)</string>
<string name="unsupported_crashed">Unsupported (Crashed)</string>
<string name="parasitic_recommend">Parasitic Manager Recommended</string> <string name="parasitic_recommend">Parasitic Manager Recommended</string>
<string name="parasitic_recommend_summary">LSPosed now supports system parasitization to avoid detection. You can safely uninstall the manager after successfully creating a shortcut of the parasitic manager. In any case you can install the manager back from /data/adb/lspd/manager.apk.</string> <string name="parasitic_recommend_summary">LSPosed now supports system parasitization to avoid detection. You can safely uninstall the manager after successfully creating a shortcut of the parasitic manager. In any case you can install the manager back from /data/adb/lspd/manager.apk.</string>
<string name="create_shortcut">Create shortcut</string> <string name="create_shortcut">Create shortcut</string>

View File

@ -22,6 +22,9 @@ package org.lsposed.lspd.service;
import android.net.LocalServerSocket; import android.net.LocalServerSocket;
import android.net.LocalSocket; import android.net.LocalSocket;
import android.net.LocalSocketAddress; import android.net.LocalSocketAddress;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.SELinux; import android.os.SELinux;
import android.system.ErrnoException; import android.system.ErrnoException;
import android.system.Os; import android.system.Os;
@ -29,8 +32,11 @@ import android.system.OsConstants;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import androidx.annotation.RequiresApi;
import java.io.File; import java.io.File;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InterruptedIOException; import java.io.InterruptedIOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
@ -38,33 +44,36 @@ import java.util.Locale;
public class Dex2OatService { public class Dex2OatService {
private static final String TAG = "Dex2OatService"; public static final String PROP_NAME = "dalvik.vm.dex2oat-flags";
public static final String PROP_VALUE = "--inline-max-code-units=0";
private static final String TAG = "LSPosedDex2Oat";
private static final String DEX2OAT_32 = "/apex/com.android.art/bin/dex2oat32"; private static final String DEX2OAT_32 = "/apex/com.android.art/bin/dex2oat32";
private static final String DEX2OAT_64 = "/apex/com.android.art/bin/dex2oat64"; private static final String DEX2OAT_64 = "/apex/com.android.art/bin/dex2oat64";
private Thread thread = null; private final Thread thread;
private LocalSocket serverSocket = null; private LocalSocket serverSocket = null;
private LocalServerSocket server = null; private LocalServerSocket server = null;
private FileDescriptor stockFd32 = null, stockFd64 = null; private FileDescriptor stockFd32 = null, stockFd64 = null;
public void start() { @RequiresApi(Build.VERSION_CODES.Q)
public Dex2OatService() {
thread = new Thread(() -> { thread = new Thread(() -> {
var devPath = Paths.get(getDevPath());
var sockPath = devPath.resolve("dex2oat.sock");
try { try {
Log.i(TAG, "dex2oat daemon start"); Log.i(TAG, "dex2oat daemon start");
if (setSocketCreateContext("u:r:dex2oat:s0")) { if (setSocketCreateContext("u:r:dex2oat:s0")) {
Log.d(TAG, "set socket context to u:r:dex2oat:s0"); Log.d(TAG, "set socket context to u:r:dex2oat:s0");
} else { } else {
Log.e(TAG, "failed to set socket context"); throw new IOException("failed to set socket context");
} }
var devPath = getDevPath(); Files.createDirectories(devPath);
var sockPath = devPath + "/dex2oat.sock";
Files.createDirectories(Paths.get(devPath));
Log.d(TAG, "dev path: " + devPath); Log.d(TAG, "dev path: " + devPath);
serverSocket = new LocalSocket(LocalSocket.SOCKET_STREAM); serverSocket = new LocalSocket(LocalSocket.SOCKET_STREAM);
serverSocket.bind(new LocalSocketAddress(sockPath, LocalSocketAddress.Namespace.FILESYSTEM)); serverSocket.bind(new LocalSocketAddress(sockPath.toString(), LocalSocketAddress.Namespace.FILESYSTEM));
server = new LocalServerSocket(serverSocket.getFileDescriptor()); server = new LocalServerSocket(serverSocket.getFileDescriptor());
SELinux.setFileContext(sockPath, "u:object_r:magisk_file:s0"); SELinux.setFileContext(sockPath.toString(), "u:object_r:magisk_file:s0");
if (new File(DEX2OAT_32).exists()) stockFd32 = Os.open(DEX2OAT_32, OsConstants.O_RDONLY, 0); if (new File(DEX2OAT_32).exists()) stockFd32 = Os.open(DEX2OAT_32, OsConstants.O_RDONLY, 0);
if (new File(DEX2OAT_64).exists()) stockFd64 = Os.open(DEX2OAT_64, OsConstants.O_RDONLY, 0); if (new File(DEX2OAT_64).exists()) stockFd64 = Os.open(DEX2OAT_64, OsConstants.O_RDONLY, 0);
@ -79,19 +88,33 @@ public class Dex2OatService {
Log.d(TAG, "sent fd" + lp); Log.d(TAG, "sent fd" + lp);
} }
} }
} catch (Exception e) { } catch (Throwable e) {
Log.e(TAG, "dex2oat daemon crashed", e); Log.e(TAG, "dex2oat daemon crashed", e);
try {
server.close();
Files.delete(sockPath);
} catch (IOException ignored) {
}
try {
if (stockFd32 != null && stockFd32.valid()) Os.close(stockFd32);
if (stockFd64 != null && stockFd64.valid()) Os.close(stockFd64);
} catch (ErrnoException ignored) {
}
new Handler(Looper.getMainLooper()).post(Dex2OatService::fallback);
} }
}); });
thread.start(); thread.start();
} }
@RequiresApi(Build.VERSION_CODES.Q)
public boolean isAlive() { public boolean isAlive() {
return thread.isAlive(); return thread.isAlive();
} }
private static native String getDevPath(); private static native String getDevPath();
private static native void fallback();
private boolean setSocketCreateContext(String context) { private boolean setSocketCreateContext(String context) {
FileDescriptor fd = null; FileDescriptor fd = null;
try { try {

View File

@ -84,8 +84,6 @@ import hidden.HiddenApiBridge;
import io.github.xposed.xposedservice.utils.ParceledListSlice; import io.github.xposed.xposedservice.utils.ParceledListSlice;
public class LSPManagerService extends ILSPManagerService.Stub { public class LSPManagerService extends ILSPManagerService.Stub {
private static final String PROP_NAME = "dalvik.vm.dex2oat-flags";
private static final String PROP_VALUE = "--inline-max-code-units=0";
// this maybe useful when obtaining the manager binder // this maybe useful when obtaining the manager binder
private static String RANDOM_UUID = null; private static String RANDOM_UUID = null;
private static final String SHORTCUT_ID = "org.lsposed.manager.shortcut"; private static final String SHORTCUT_ID = "org.lsposed.manager.shortcut";
@ -688,11 +686,7 @@ public class LSPManagerService extends ILSPManagerService.Stub {
@Override @Override
public boolean dex2oatFlagsLoaded() { public boolean dex2oatFlagsLoaded() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { return SystemProperties.get(Dex2OatService.PROP_NAME).contains(Dex2OatService.PROP_VALUE);
return ServiceManager.getDex2OatService().isAlive();
} else {
return SystemProperties.get(PROP_NAME).contains(PROP_VALUE);
}
} }
@Override @Override
@ -783,4 +777,13 @@ public class LSPManagerService extends ILSPManagerService.Stub {
public void setDexObfuscate(boolean enabled) { public void setDexObfuscate(boolean enabled) {
ConfigManager.getInstance().setDexObfuscate(enabled); ConfigManager.getInstance().setDexObfuscate(enabled);
} }
@Override
public boolean dex2oatWrapperAlive() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
return ServiceManager.getDex2OatService().isAlive();
} else {
return false;
}
}
} }

View File

@ -29,6 +29,8 @@ import android.os.Looper;
import android.os.Process; import android.os.Process;
import android.util.Log; import android.util.Log;
import androidx.annotation.RequiresApi;
import com.android.internal.os.BinderInternal; import com.android.internal.os.BinderInternal;
import org.lsposed.daemon.BuildConfig; import org.lsposed.daemon.BuildConfig;
@ -54,6 +56,7 @@ public class ServiceManager {
private static final ExecutorService executorService = Executors.newCachedThreadPool(); private static final ExecutorService executorService = Executors.newCachedThreadPool();
@RequiresApi(Build.VERSION_CODES.Q)
public static Dex2OatService getDex2OatService() { public static Dex2OatService getDex2OatService() {
return dex2OatService; return dex2OatService;
} }
@ -104,11 +107,6 @@ public class ServiceManager {
logcatService = new LogcatService(); logcatService = new LogcatService();
logcatService.start(); logcatService.start();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
dex2OatService = new Dex2OatService();
dex2OatService.start();
}
Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND); Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
Looper.prepareMainLooper(); Looper.prepareMainLooper();
@ -117,6 +115,9 @@ public class ServiceManager {
applicationService = new LSPApplicationService(); applicationService = new LSPApplicationService();
managerService = new LSPManagerService(); managerService = new LSPManagerService();
systemServerService = new LSPSystemServerService(systemServerMaxRetry); systemServerService = new LSPSystemServerService(systemServerMaxRetry);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
dex2OatService = new Dex2OatService();
}
systemServerService.putBinderForSystemServer(); systemServerService.putBinderForSystemServer();

View File

@ -22,6 +22,11 @@
// //
#include <jni.h> #include <jni.h>
#include <sys/system_properties.h>
#include <unistd.h>
#include <stdlib.h>
#include "logging.h"
char kTmpDir[] = "placeholder_/dev/0123456789abcdef"; char kTmpDir[] = "placeholder_/dev/0123456789abcdef";
@ -29,3 +34,10 @@ JNIEXPORT jstring JNICALL
Java_org_lsposed_lspd_service_Dex2OatService_getDevPath(JNIEnv *env, jclass clazz) { Java_org_lsposed_lspd_service_Dex2OatService_getDevPath(JNIEnv *env, jclass clazz) {
return (*env)->NewStringUTF(env, kTmpDir + 12); return (*env)->NewStringUTF(env, kTmpDir + 12);
} }
JNIEXPORT void JNICALL
Java_org_lsposed_lspd_service_Dex2OatService_fallback(JNIEnv *env, jclass clazz) {
LOGI("do fallback");
system("nsenter -m -t 1 umount /apex/com.android.art/bin/dex2oat*");
__system_property_set("dalvik.vm.dex2oat-flags", "--inline-max-code-units=0");
}

View File

@ -3,7 +3,7 @@
#include <android/log.h> #include <android/log.h>
#ifndef LOG_TAG #ifndef LOG_TAG
#define LOG_TAG "dex2oat-wrapper" #define LOG_TAG "LSPosedDex2Oat"
#endif #endif
#ifdef LOG_DISABLED #ifdef LOG_DISABLED

View File

@ -79,4 +79,6 @@ interface ILSPManagerService {
boolean getDexObfuscate() = 42; boolean getDexObfuscate() = 42;
void setDexObfuscate(boolean enable) = 43; void setDexObfuscate(boolean enable) = 43;
boolean dex2oatWrapperAlive() = 44;
} }