From 5e95d0c540c8e4004ec6117e367d39a55be35dc0 Mon Sep 17 00:00:00 2001 From: tehcneko <7764726+tehcneko@users.noreply.github.com> Date: Thu, 28 Jan 2021 14:59:12 +0800 Subject: [PATCH] Reboot using sui --- app/build.gradle | 2 + .../org/meowcat/edxposed/manager/App.java | 38 ++++++++ .../manager/ui/activity/BaseActivity.java | 78 ++-------------- .../manager/util/NotificationUtil.java | 18 +--- .../edxposed/manager/util/RebootUtil.java | 93 +++++++++++++++++++ .../edxposed/manager/util/Singleton.java | 17 ++++ build.gradle | 1 + .../main/java/android/os/IPowerManager.java | 13 +++ 8 files changed, 172 insertions(+), 88 deletions(-) create mode 100644 app/src/main/java/org/meowcat/edxposed/manager/util/RebootUtil.java create mode 100644 app/src/main/java/org/meowcat/edxposed/manager/util/Singleton.java create mode 100644 hiddenapi-stubs/src/main/java/android/os/IPowerManager.java diff --git a/app/build.gradle b/app/build.gradle index 2c88c58c..ecf2230a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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") } diff --git a/app/src/main/java/org/meowcat/edxposed/manager/App.java b/app/src/main/java/org/meowcat/edxposed/manager/App.java index e40cb573..59ce6f50 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/App.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/App.java @@ -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(); diff --git a/app/src/main/java/org/meowcat/edxposed/manager/ui/activity/BaseActivity.java b/app/src/main/java/org/meowcat/edxposed/manager/ui/activity/BaseActivity.java index 118d9274..1880e0a4 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/ui/activity/BaseActivity.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/ui/activity/BaseActivity.java @@ -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 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 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); diff --git a/app/src/main/java/org/meowcat/edxposed/manager/util/NotificationUtil.java b/app/src/main/java/org/meowcat/edxposed/manager/util/NotificationUtil.java index b402f772..0f3ccee4 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/util/NotificationUtil.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/util/NotificationUtil.java @@ -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); } } } \ No newline at end of file diff --git a/app/src/main/java/org/meowcat/edxposed/manager/util/RebootUtil.java b/app/src/main/java/org/meowcat/edxposed/manager/util/RebootUtil.java new file mode 100644 index 00000000..090e7f48 --- /dev/null +++ b/app/src/main/java/org/meowcat/edxposed/manager/util/RebootUtil.java @@ -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 POWER_MANAGER = new Singleton() { + @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(); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/meowcat/edxposed/manager/util/Singleton.java b/app/src/main/java/org/meowcat/edxposed/manager/util/Singleton.java new file mode 100644 index 00000000..1dd14bc0 --- /dev/null +++ b/app/src/main/java/org/meowcat/edxposed/manager/util/Singleton.java @@ -0,0 +1,17 @@ +package org.meowcat.edxposed.manager.util; + +public abstract class Singleton { + + private T mInstance; + + protected abstract T create(); + + public final T get() { + synchronized (this) { + if (mInstance == null) { + mInstance = create(); + } + return mInstance; + } + } +} \ No newline at end of file diff --git a/build.gradle b/build.gradle index ff255ed1..d5e1d424 100644 --- a/build.gradle +++ b/build.gradle @@ -45,6 +45,7 @@ allprojects { google() jcenter() maven { url 'https://jitpack.io' } + maven { url 'https://dl.bintray.com/rikkaw/Libraries' } } } diff --git a/hiddenapi-stubs/src/main/java/android/os/IPowerManager.java b/hiddenapi-stubs/src/main/java/android/os/IPowerManager.java new file mode 100644 index 00000000..56bf154e --- /dev/null +++ b/hiddenapi-stubs/src/main/java/android/os/IPowerManager.java @@ -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(); + } + } +}