diff --git a/api/src/main/java/moe/shizuku/api/ShizukuSystemProperties.java b/api/src/main/java/moe/shizuku/api/ShizukuSystemProperties.java index 39fcd8876..398199f3f 100644 --- a/api/src/main/java/moe/shizuku/api/ShizukuSystemProperties.java +++ b/api/src/main/java/moe/shizuku/api/ShizukuSystemProperties.java @@ -6,6 +6,9 @@ import moe.shizuku.server.IShizukuService; +/** + * @since added from version 9 + */ public class ShizukuSystemProperties { @NonNull diff --git a/build.gradle b/build.gradle index d219ca0ed..59234ac04 100644 --- a/build.gradle +++ b/build.gradle @@ -2,6 +2,7 @@ apply plugin: 'idea' idea.module { excludeDirs += file('out') + resourceDirs += file('magisk-shizuku-starter') } buildscript { diff --git a/magisk-shizuku-starter/.gitattributes b/magisk-shizuku-starter/.gitattributes new file mode 100644 index 000000000..11e33e9b1 --- /dev/null +++ b/magisk-shizuku-starter/.gitattributes @@ -0,0 +1,10 @@ +# Declare files that will always have LF line endings on checkout. +META-INF/** text eol=lf +*.prop text eol=lf +*.sh text eol=lf +*.md text eol=lf +sepolicy.rule text eol=lf + +# Denote all files that are truly binary and should not be modified. +system/** binary +system_x86/** binary \ No newline at end of file diff --git a/magisk-shizuku-starter/META-INF/com/google/android/update-binary b/magisk-shizuku-starter/META-INF/com/google/android/update-binary new file mode 100644 index 000000000..abc7aebdc --- /dev/null +++ b/magisk-shizuku-starter/META-INF/com/google/android/update-binary @@ -0,0 +1,173 @@ +#!/sbin/sh + +################# +# Initialization +################# + +umask 022 + +# Global vars +TMPDIR=/dev/tmp +PERSISTDIR=/sbin/.magisk/mirror/persist + +rm -rf $TMPDIR 2>/dev/null +mkdir -p $TMPDIR + +# echo before loading util_functions +ui_print() { echo "$1"; } + +require_new_magisk() { + ui_print "*******************************" + ui_print " Please install Magisk v19.0+! " + ui_print "*******************************" + exit 1 +} + +is_legacy_script() { + unzip -l "$ZIPFILE" install.sh | grep -q install.sh + return $? +} + +print_modname() { + local len + len=$(echo -n $MODNAME | wc -c) + len=$((len + 2)) + local pounds=$(printf "%${len}s" | tr ' ' '*') + ui_print "$pounds" + ui_print " $MODNAME " + ui_print "$pounds" + ui_print "*******************" + ui_print " Powered by Magisk " + ui_print "*******************" +} + +############## +# Environment +############## + +OUTFD=$2 +ZIPFILE=$3 + +mount /data 2>/dev/null + +# Load utility functions +[ -f /data/adb/magisk/util_functions.sh ] || require_new_magisk +. /data/adb/magisk/util_functions.sh +[ $MAGISK_VER_CODE -gt 18100 ] || require_new_magisk + +# Preperation for flashable zips +setup_flashable + +# Mount partitions +mount_partitions + +# Detect version and architecture +api_level_arch_detect + +# Setup busybox and binaries +$BOOTMODE && boot_actions || recovery_actions + +############## +# Preparation +############## + +# Extract prop file +unzip -o "$ZIPFILE" module.prop -d $TMPDIR >&2 +[ ! -f $TMPDIR/module.prop ] && abort "! Unable to extract zip file!" + +$BOOTMODE && MODDIRNAME=modules_update || MODDIRNAME=modules +MODULEROOT=$NVBASE/$MODDIRNAME +MODID=$(grep_prop id $TMPDIR/module.prop) +MODPATH=$MODULEROOT/$MODID +MODNAME=$(grep_prop name $TMPDIR/module.prop) + +# Create mod paths +rm -rf $MODPATH 2>/dev/null +mkdir -p $MODPATH + +########## +# Install +########## + +if is_legacy_script; then + unzip -oj "$ZIPFILE" module.prop install.sh uninstall.sh 'common/*' -d $TMPDIR >&2 + + # Load install script + . $TMPDIR/install.sh + + # Callbacks + print_modname + on_install + + # Custom uninstaller + [ -f $TMPDIR/uninstall.sh ] && cp -af $TMPDIR/uninstall.sh $MODPATH/uninstall.sh + + # Skip mount + $SKIPMOUNT && touch $MODPATH/skip_mount + + # prop file + $PROPFILE && cp -af $TMPDIR/system.prop $MODPATH/system.prop + + # Module info + cp -af $TMPDIR/module.prop $MODPATH/module.prop + + # post-fs-data scripts + $POSTFSDATA && cp -af $TMPDIR/post-fs-data.sh $MODPATH/post-fs-data.sh + + # service scripts + $LATESTARTSERVICE && cp -af $TMPDIR/service.sh $MODPATH/service.sh + + ui_print "- Setting permissions" + set_permissions +else + print_modname + + unzip -o "$ZIPFILE" customize.sh -d $MODPATH >&2 + + if ! grep -q '^SKIPUNZIP=1$' $MODPATH/customize.sh 2>/dev/null; then + ui_print "- Extracting module files" + unzip -o "$ZIPFILE" -x 'META-INF/*' -d $MODPATH >&2 + + # Default permissions + set_perm_recursive $MODPATH 0 0 0755 0644 + fi + + # Load customization script + [ -f $MODPATH/customize.sh ] && . $MODPATH/customize.sh +fi + +# Handle replace folders +for TARGET in $REPLACE; do + ui_print "- Replace target: $TARGET" + mktouch $MODPATH$TARGET/.replace +done + +if $BOOTMODE; then + # Update info for Magisk Manager + mktouch $NVBASE/modules/$MODID/update + cp -af $MODPATH/module.prop $NVBASE/modules/$MODID/module.prop +fi + +# Copy over custom sepolicy rules +if [ -f $MODPATH/sepolicy.rule -a -e $PERSISTDIR ]; then + ui_print "- Installing custom sepolicy patch" + PERSISTMOD=$PERSISTDIR/magisk/$MODID + mkdir -p $PERSISTMOD + cp -af $MODPATH/sepolicy.rule $PERSISTMOD/sepolicy.rule +fi + +# Remove stuffs that don't belong to modules +rm -rf \ + $MODPATH/system/placeholder $MODPATH/customize.sh \ + $MODPATH/README.md $MODPATH/.git* 2>/dev/null + +############## +# Finalizing +############## + +cd / +$BOOTMODE || recovery_cleanup +rm -rf $TMPDIR + +ui_print "- Done" +exit 0 diff --git a/magisk-shizuku-starter/META-INF/com/google/android/updater-script b/magisk-shizuku-starter/META-INF/com/google/android/updater-script new file mode 100644 index 000000000..11d5c96e0 --- /dev/null +++ b/magisk-shizuku-starter/META-INF/com/google/android/updater-script @@ -0,0 +1 @@ +#MAGISK diff --git a/magisk-shizuku-starter/README.md b/magisk-shizuku-starter/README.md new file mode 100644 index 000000000..142090fab --- /dev/null +++ b/magisk-shizuku-starter/README.md @@ -0,0 +1,7 @@ +# Starter for Shizuku + +A simple module do nothing but start Shizuku on boot. + +On some highly customized systems, it's hard or impossible to guarantee the app to start on boot. + +This module is for those systems. \ No newline at end of file diff --git a/magisk-shizuku-starter/module.prop b/magisk-shizuku-starter/module.prop new file mode 100644 index 000000000..a742f26ea --- /dev/null +++ b/magisk-shizuku-starter/module.prop @@ -0,0 +1,6 @@ +id=shizuku-starter +name=Shizuku Starter +version=v1.0 +versionCode=1 +author=Rikka +description=A simple module do nothing but start Shizuku on boot. On some highly customized systems, it's hard or impossible to guarantee the app to start on boot. \ No newline at end of file diff --git a/magisk-shizuku-starter/service.sh b/magisk-shizuku-starter/service.sh new file mode 100644 index 000000000..9d1455386 --- /dev/null +++ b/magisk-shizuku-starter/service.sh @@ -0,0 +1,16 @@ +#!/system/bin/sh + +# maybe it's better to start after emulated storage is setup +while [ ! -d "/storage/emulated/0/Android" ]; do + sleep 3 +done + +if [ -f "/data/user_de/0/moe.shizuku.privileged.api/start.sh" ]; then + (sh "/data/user_de/0/moe.shizuku.privileged.api/start.sh")& + exit 0 +fi + +if [ -f "/data/user/0/moe.shizuku.privileged.api/start.sh" ]; then + (sh "/data/user/0/moe.shizuku.privileged.api/start.sh")& + exit 0 +fi \ No newline at end of file diff --git a/manager/src/main/java/moe/shizuku/manager/Helps.java b/manager/src/main/java/moe/shizuku/manager/Helps.java index 2f600b093..9b0186739 100644 --- a/manager/src/main/java/moe/shizuku/manager/Helps.java +++ b/manager/src/main/java/moe/shizuku/manager/Helps.java @@ -8,6 +8,7 @@ public class Helps { public static final MultiLocaleEntity ADB_ANDROID11 = new MultiLocaleEntity(); public static final MultiLocaleEntity APPS = new MultiLocaleEntity(); public static final MultiLocaleEntity HOME = new MultiLocaleEntity(); + public static final MultiLocaleEntity DOWNLOAD = new MultiLocaleEntity(); static { ADB.put("zh-CN", "https://shizuku.rikka.app/zh-hans/guide/setup.html"); @@ -25,5 +26,9 @@ public class Helps { HOME.put("zh-CN", "https://shizuku.rikka.app/zh-hans/"); HOME.put("zh-TW", "https://shizuku.rikka.app/zh-hant/"); HOME.put("en", "https://shizuku.rikka.app/"); + + DOWNLOAD.put("zh-CN", "https://shizuku.rikka.app/zh-hans/download.html"); + DOWNLOAD.put("zh-TW", "https://shizuku.rikka.app/zh-hant/download.html"); + DOWNLOAD.put("en", "https://shizuku.rikka.app/download.html"); } } diff --git a/manager/src/main/java/moe/shizuku/manager/ShizukuSettings.java b/manager/src/main/java/moe/shizuku/manager/ShizukuSettings.java index ab6332c79..35a4ae2e3 100644 --- a/manager/src/main/java/moe/shizuku/manager/ShizukuSettings.java +++ b/manager/src/main/java/moe/shizuku/manager/ShizukuSettings.java @@ -24,6 +24,7 @@ public class ShizukuSettings { public static final String NIGHT_MODE = "night_mode"; public static final String LANGUAGE = "language"; public static final String KEEP_SU_CONTEXT = "keep_su_context"; + public static final String KEEP_START_ON_BOOT = "start_on_boot"; private static SharedPreferences sPreferences; diff --git a/manager/src/main/java/moe/shizuku/manager/home/HomeAdapter.kt b/manager/src/main/java/moe/shizuku/manager/home/HomeAdapter.kt index 758d7d608..4d4e2b149 100644 --- a/manager/src/main/java/moe/shizuku/manager/home/HomeAdapter.kt +++ b/manager/src/main/java/moe/shizuku/manager/home/HomeAdapter.kt @@ -19,20 +19,14 @@ class HomeAdapter(private val homeModel: HomeViewModel, private val appsModel: A fun updateData() { val status = homeModel.serviceStatus.value?.data ?: return val grantedCount = appsModel.grantedCount.value?.data ?: 0 - val v3 = ShizukuService.pingBinder() + val running = ShizukuService.pingBinder() clear() addItem(ServerStatusViewHolder.CREATOR, status, 0) addItem(ManageAppsViewHolder.CREATOR, grantedCount, 1) if (Process.myUid() / 100000 == 0) { val root = ShizukuSettings.getLastLaunchMode() == LaunchMethod.ROOT - var rootRestart = status.uid == 0 - if (v3) { - try { - rootRestart = rootRestart || ShizukuService.getUid() == 0 - } catch (ignored: Throwable) { - } - } + val rootRestart = running && status.uid == 0 when { root && BuildUtils.atLeast30 -> { addItem(StartRootViewHolder.CREATOR, rootRestart, 3) diff --git a/manager/src/main/java/moe/shizuku/manager/home/StartRootViewHolder.kt b/manager/src/main/java/moe/shizuku/manager/home/StartRootViewHolder.kt index aded2bdbd..430b4ba62 100644 --- a/manager/src/main/java/moe/shizuku/manager/home/StartRootViewHolder.kt +++ b/manager/src/main/java/moe/shizuku/manager/home/StartRootViewHolder.kt @@ -5,11 +5,10 @@ import android.text.method.LinkMovementMethod import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.Checkable import androidx.appcompat.app.AlertDialog -import androidx.core.view.isVisible +import moe.shizuku.api.ShizukuService +import moe.shizuku.manager.Helps import moe.shizuku.manager.R -import moe.shizuku.manager.ShizukuSettings import moe.shizuku.manager.databinding.HomeStartRootBinding import moe.shizuku.manager.ktx.toHtml import moe.shizuku.manager.starter.StarterActivity @@ -33,7 +32,6 @@ class StartRootViewHolder(private val binding: HomeStartRootBinding) : BaseViewH start.setOnClickListener(listener) restart.setOnClickListener(listener) binding.text1.movementMethod = LinkMovementMethod.getInstance() - binding.text1.text = context.getString(R.string.home_root_description, "Don\'t kill my app!").toHtml(HtmlCompat.FROM_HTML_OPTION_TRIM_WHITESPACE) } private fun onStartClicked(v: View) { @@ -54,6 +52,14 @@ class StartRootViewHolder(private val binding: HomeStartRootBinding) : BaseViewH start.visibility = View.VISIBLE restart.visibility = View.GONE } + + val sb = StringBuilder() + .append(context.getString(R.string.home_root_description, "Don\'t kill my app!")) + if (ShizukuService.pingBinder()) { + sb.append("
").append(context.getString(R.string.home_root_description_magisk, "${context.getString(R.string.magisk_module)}"))
+ }
+
+ binding.text1.text = sb.toHtml(HtmlCompat.FROM_HTML_OPTION_TRIM_WHITESPACE)
}
override fun onRecycle() {
diff --git a/manager/src/main/java/moe/shizuku/manager/ktx/PackageManager.kt b/manager/src/main/java/moe/shizuku/manager/ktx/PackageManager.kt
new file mode 100644
index 000000000..c9e78c7bf
--- /dev/null
+++ b/manager/src/main/java/moe/shizuku/manager/ktx/PackageManager.kt
@@ -0,0 +1,22 @@
+package moe.shizuku.manager.ktx
+
+import android.content.ComponentName
+import android.content.pm.PackageManager
+
+fun PackageManager.setComponentEnabled(componentName: ComponentName, enabled: Boolean) {
+ val oldState = getComponentEnabledSetting(componentName)
+ val newState = if (enabled) PackageManager.COMPONENT_ENABLED_STATE_ENABLED else PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+ if (newState != oldState) {
+ val flags = PackageManager.DONT_KILL_APP
+ setComponentEnabledSetting(componentName, newState, flags)
+ }
+}
+
+fun PackageManager.isComponentEnabled(componentName: ComponentName, defaultValue: Boolean = true): Boolean {
+ return when (getComponentEnabledSetting(componentName)) {
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED -> false
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED -> true
+ PackageManager.COMPONENT_ENABLED_STATE_DEFAULT -> defaultValue
+ else -> false
+ }
+}
\ No newline at end of file
diff --git a/manager/src/main/java/moe/shizuku/manager/settings/SettingsFragment.kt b/manager/src/main/java/moe/shizuku/manager/settings/SettingsFragment.kt
index b80cd5e22..8e98e2bce 100644
--- a/manager/src/main/java/moe/shizuku/manager/settings/SettingsFragment.kt
+++ b/manager/src/main/java/moe/shizuku/manager/settings/SettingsFragment.kt
@@ -1,5 +1,6 @@
package moe.shizuku.manager.settings
+import android.content.ComponentName
import android.content.Context
import android.os.Bundle
import android.text.TextUtils
@@ -9,7 +10,11 @@ import android.widget.FrameLayout
import androidx.recyclerview.widget.RecyclerView
import moe.shizuku.manager.R
import moe.shizuku.manager.ShizukuSettings
+import moe.shizuku.manager.ShizukuSettings.KEEP_START_ON_BOOT
import moe.shizuku.manager.app.ThemeHelper.KEY_BLACK_NIGHT_THEME
+import moe.shizuku.manager.ktx.isComponentEnabled
+import moe.shizuku.manager.ktx.setComponentEnabled
+import moe.shizuku.manager.starter.BootCompleteReceiver
import moe.shizuku.manager.utils.CustomTabsHelper
import moe.shizuku.preference.*
import rikka.core.util.ResourceUtils
@@ -36,6 +41,7 @@ class SettingsFragment : PreferenceFragment() {
private lateinit var nightModePreference: Preference
private lateinit var blackNightThemePreference: SwitchPreference
private lateinit var keepSuContextPreference: SwitchPreference
+ private lateinit var startOnBootPreference: SwitchPreference
private lateinit var startupPreference: PreferenceCategory
private lateinit var translationPreference: Preference
private lateinit var translationContributorsPreference: Preference
@@ -52,13 +58,22 @@ class SettingsFragment : PreferenceFragment() {
nightModePreference = findPreference(KEY_NIGHT_MODE)
blackNightThemePreference = findPreference(KEY_BLACK_NIGHT_THEME) as SwitchPreference
keepSuContextPreference = findPreference(KEY_KEEP_SU_CONTEXT) as SwitchPreference
+ startOnBootPreference = findPreference(KEEP_START_ON_BOOT) as SwitchPreference
startupPreference = findPreference("startup") as PreferenceCategory
translationPreference = findPreference("translation")
translationContributorsPreference = findPreference("translation_contributors")
keepSuContextPreference.isVisible = false
- startupPreference.isVisible = false
+ val componentName = ComponentName(context.packageName, BootCompleteReceiver::class.java.name)
+
+ startOnBootPreference.isChecked = context.packageManager.isComponentEnabled(componentName)
+ startOnBootPreference.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any ->
+ if (newValue is Boolean) {
+ context.packageManager.setComponentEnabled(componentName, newValue)
+ context.packageManager.isComponentEnabled(componentName) == newValue
+ } else false
+ }
languagePreference.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any ->
if (newValue is String) {
val locale: Locale = if ("SYSTEM" == newValue) {
diff --git a/manager/src/main/res/values-zh-rCN/strings.xml b/manager/src/main/res/values-zh-rCN/strings.xml
index d951f5bab..7864aabd4 100644
--- a/manager/src/main/res/values-zh-rCN/strings.xml
+++ b/manager/src/main/res/values-zh-rCN/strings.xml
@@ -13,6 +13,8 @@