Reboot using sui

This commit is contained in:
tehcneko 2021-01-28 14:59:12 +08:00
parent fd6a3f9a93
commit 5e95d0c540
8 changed files with 172 additions and 88 deletions

View File

@ -69,7 +69,9 @@ dependencies {
implementation 'com.google.android.material:material:1.2.1'
implementation 'com.takisoft.preferencex:preferencex:1.1.0'
implementation 'com.takisoft.preferencex:preferencex-colorpicker:1.1.0'
implementation "rikka.shizuku:api:11.0.1"
implementation 'tech.rectifier.preferencex-android:preferencex-simplemenu:88f93154b2'
implementation 'me.zhanghai.android.appiconloader:appiconloader-glide:1.2.0'
implementation 'me.zhanghai.android.fastscroll:library:1.1.5'
compileOnly project(":hiddenapi-stubs")
}

View File

@ -18,6 +18,7 @@ import org.meowcat.edxposed.manager.adapters.AppHelper;
import org.meowcat.edxposed.manager.ui.activity.CrashReportActivity;
import org.meowcat.edxposed.manager.util.ModuleUtil;
import org.meowcat.edxposed.manager.util.NotificationUtil;
import org.meowcat.edxposed.manager.util.RebootUtil;
import java.io.File;
import java.io.PrintWriter;
@ -28,6 +29,11 @@ import java.util.Collection;
import java.util.Date;
import java.util.Objects;
import rikka.shizuku.Shizuku;
import rikka.sui.Sui;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
public class App extends Application implements Application.ActivityLifecycleCallbacks {
public static final String TAG = "EdXposedManager";
@SuppressLint("StaticFieldLeak")
@ -38,6 +44,36 @@ public class App extends Application implements Application.ActivityLifecycleCal
//private AppCompatActivity currentActivity = null;
private boolean isUiLoaded = false;
private final Shizuku.OnRequestPermissionResultListener REQUEST_PERMISSION_RESULT_LISTENER = this::onRequestPermissionsResult;
static {
Sui.init(BuildConfig.APPLICATION_ID);
}
private void onRequestPermissionsResult(int requestCode, int grantResult) {
if (requestCode < 10) {
RebootUtil.onRequestPermissionsResult(requestCode, grantResult);
}
}
public static boolean checkPermission(int code) {
try {
if (!Shizuku.isPreV11() && Shizuku.getVersion() >= 11) {
if (Shizuku.checkSelfPermission() == PERMISSION_GRANTED) {
return true;
} else if (Shizuku.shouldShowRequestPermissionRationale()) {
return false;
} else {
Shizuku.requestPermission(code);
return false;
}
}
} catch (Throwable e) {
e.printStackTrace();
}
return false;
}
public static App getInstance() {
return instance;
}
@ -109,6 +145,8 @@ public class App extends Application implements Application.ActivityLifecycleCal
@SuppressLint("SimpleDateFormat") DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
Date date = new Date();
Shizuku.addRequestPermissionResultListener(REQUEST_PERMISSION_RESULT_LISTENER);
if (!Objects.requireNonNull(pref.getString("date", "")).equals(dateFormat.format(date))) {
pref.edit().putString("date", dateFormat.format(date)).apply();

View File

@ -6,11 +6,7 @@ import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.os.Build;
import android.os.Bundle;
import android.os.Looper;
import android.os.PowerManager;
import android.text.TextUtils;
import android.view.MenuItem;
import android.widget.Toast;
@ -29,9 +25,8 @@ import org.meowcat.edxposed.manager.R;
import org.meowcat.edxposed.manager.util.CustomThemeColor;
import org.meowcat.edxposed.manager.util.CustomThemeColors;
import org.meowcat.edxposed.manager.util.NavUtil;
import org.meowcat.edxposed.manager.util.RebootUtil;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
public class BaseActivity extends AppCompatActivity {
@ -157,65 +152,6 @@ public class BaseActivity extends AppCompatActivity {
.show();
}
void softReboot() {
if (!Shell.rootAccess()) {
showAlert(getString(R.string.root_failed));
return;
}
String command;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && ((PowerManager) getSystemService(Context.POWER_SERVICE)).isRebootingUserspaceSupported()) {
command = "/system/bin/svc power reboot userspace";
} else {
command = "setprop ctl.restart surfaceflinger; setprop ctl.restart zygote";
}
List<String> messages = new LinkedList<>();
Shell.Result result = Shell.su(command).exec();
if (result.getCode() != 0) {
messages.add(result.getOut().toString());
messages.add("");
messages.add(getString(R.string.reboot_failed));
showAlert(TextUtils.join("\n", messages).trim());
}
}
void showAlert(final String result) {
if (Looper.myLooper() != Looper.getMainLooper()) {
runOnUiThread(() -> showAlert(result));
return;
}
new MaterialAlertDialogBuilder(this)
.setMessage(result)
.setPositiveButton(android.R.string.ok, null)
.show();
}
void reboot(String mode) {
if (!Shell.rootAccess()) {
showAlert(getString(R.string.root_failed));
return;
}
List<String> messages = new LinkedList<>();
String command = "/system/bin/svc power reboot";
if (mode != null) {
command += " " + mode;
if (mode.equals("recovery"))
// create a flag used by some kernels to boot into recovery
Shell.su("touch /cache/recovery/boot").exec();
}
Shell.Result result = Shell.su(command).exec();
if (result.getCode() != 0) {
messages.add(result.getOut().toString());
messages.add("");
messages.add(getString(R.string.reboot_failed));
showAlert(TextUtils.join("\n", messages).trim());
}
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
int itemId = item.getItemId();
@ -266,17 +202,17 @@ public class BaseActivity extends AppCompatActivity {
};
});
} else if (itemId == R.id.reboot) {
areYouSure(R.string.reboot, (dialog, which) -> reboot(null));
areYouSure(R.string.reboot, (dialog, which) -> RebootUtil.reboot(RebootUtil.RebootType.NORMAL));
} else if (itemId == R.id.soft_reboot) {
areYouSure(R.string.soft_reboot, (dialog, which) -> softReboot());
areYouSure(R.string.soft_reboot, (dialog, which) -> RebootUtil.reboot(RebootUtil.RebootType.USERSPACE));
} else if (itemId == R.id.reboot_recovery) {
areYouSure(R.string.reboot_recovery, (dialog, which) -> reboot("recovery"));
areYouSure(R.string.reboot_recovery, (dialog, which) -> RebootUtil.reboot(RebootUtil.RebootType.RECOVERY));
} else if (itemId == R.id.reboot_bootloader) {
areYouSure(R.string.reboot_bootloader, (dialog, which) -> reboot("bootloader"));
areYouSure(R.string.reboot_bootloader, (dialog, which) -> RebootUtil.reboot(RebootUtil.RebootType.BOOTLOADER));
} else if (itemId == R.id.reboot_download) {
areYouSure(R.string.reboot_download, (dialog, which) -> reboot("download"));
areYouSure(R.string.reboot_download, (dialog, which) -> RebootUtil.reboot(RebootUtil.RebootType.DOWNLOAD));
} else if (itemId == R.id.reboot_edl) {
areYouSure(R.string.reboot_edl, (dialog, which) -> reboot("edl"));
areYouSure(R.string.reboot_edl, (dialog, which) -> RebootUtil.reboot(RebootUtil.RebootType.EDL));
}
return super.onOptionsItemSelected(item);

View File

@ -6,8 +6,6 @@ import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.PowerManager;
import android.util.Log;
import android.widget.Toast;
@ -172,21 +170,7 @@ public final class NotificationUtil {
}
boolean softReboot = intent.getBooleanExtra(EXTRA_SOFT_REBOOT, false);
String command;
if (softReboot) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).isRebootingUserspaceSupported()) {
command = "/system/bin/svc power reboot userspace";
} else {
command = "setprop ctl.restart surfaceflinger; setprop ctl.restart zygote";
}
} else {
command = "/system/bin/svc power reboot";
}
int returnCode = Shell.su(command).exec().getCode();
if (returnCode != 0) {
Log.e(App.TAG, "NotificationUtil -> Could not reboot");
}
RebootUtil.reboot(softReboot ? RebootUtil.RebootType.USERSPACE : RebootUtil.RebootType.NORMAL);
}
}
}

View File

@ -0,0 +1,93 @@
package org.meowcat.edxposed.manager.util;
import android.content.Context;
import android.os.Build;
import android.os.IPowerManager;
import android.os.PowerManager;
import android.os.RemoteException;
import com.topjohnwu.superuser.Shell;
import org.meowcat.edxposed.manager.App;
import org.meowcat.edxposed.manager.BuildConfig;
import rikka.shizuku.ShizukuBinderWrapper;
import rikka.shizuku.ShizukuSystemProperties;
import rikka.shizuku.SystemServiceHelper;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
public class RebootUtil {
public enum RebootType {
NORMAL,
USERSPACE,
RECOVERY,
BOOTLOADER,
DOWNLOAD,
EDL;
@Override
public String toString() {
return super.toString().toLowerCase();
}
}
public static void onRequestPermissionsResult(int requestCode, int grantResult) {
RebootType mode = RebootType.values()[requestCode];
if (grantResult == PERMISSION_GRANTED) {
try {
if (mode == RebootType.USERSPACE && !supportUserspaceReboot()) {
ShizukuSystemProperties.set("ctl.restart", "surfaceflinger");
ShizukuSystemProperties.set("ctl.restart", "zygote");
} else {
POWER_MANAGER.get().reboot(BuildConfig.DEBUG, mode.toString(), false);
}
} catch (RemoteException e) {
e.printStackTrace();
rebootWithShell(mode);
}
} else {
rebootWithShell(mode);
}
}
private static final Singleton<IPowerManager> POWER_MANAGER = new Singleton<IPowerManager>() {
@Override
protected IPowerManager create() {
return IPowerManager.Stub.asInterface(new ShizukuBinderWrapper(SystemServiceHelper.getSystemService(Context.POWER_SERVICE)));
}
};
public static void reboot(RebootType mode) {
if (App.checkPermission(mode.ordinal())) {
onRequestPermissionsResult(mode.ordinal(), PERMISSION_GRANTED);
}
}
private static void rebootWithShell(RebootType mode) {
if (!Shell.rootAccess()) {
return;
}
String command;
if (mode == RebootType.USERSPACE) {
if (supportUserspaceReboot()) {
command = "/system/bin/svc power reboot userspace";
} else {
command = "setprop ctl.restart surfaceflinger; setprop ctl.restart zygote";
}
} else if (mode == RebootType.NORMAL) {
command = "/system/bin/svc power reboot";
} else if (mode == RebootType.RECOVERY) {
Shell.su("touch /cache/recovery/boot").exec();
command = "/system/bin/svc power recovery";
} else {
command = "/system/bin/svc power reboot " + mode.toString();
}
Shell.su(command).exec();
}
private static boolean supportUserspaceReboot() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && ((PowerManager) App.getInstance().getSystemService(Context.POWER_SERVICE)).isRebootingUserspaceSupported();
}
}

View File

@ -0,0 +1,17 @@
package org.meowcat.edxposed.manager.util;
public abstract class Singleton<T> {
private T mInstance;
protected abstract T create();
public final T get() {
synchronized (this) {
if (mInstance == null) {
mInstance = create();
}
return mInstance;
}
}
}

View File

@ -45,6 +45,7 @@ allprojects {
google()
jcenter()
maven { url 'https://jitpack.io' }
maven { url 'https://dl.bintray.com/rikkaw/Libraries' }
}
}

View File

@ -0,0 +1,13 @@
package android.os;
public interface IPowerManager extends IInterface {
void reboot(boolean confirm, String reason, boolean wait) throws RemoteException;
abstract class Stub extends Binder implements IPowerManager {
public static IPowerManager asInterface(IBinder obj) {
throw new UnsupportedOperationException();
}
}
}