From a5f5e94115eae08786dd3800016cc50e5b487661 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 11 May 2019 01:50:01 -0700 Subject: [PATCH 1/8] Always reload string from resource --- .../java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt | 8 ++++---- app/src/main/res/layout/fragment_magisk.xml | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt index c56830aaf..b7e329ad5 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt @@ -63,7 +63,7 @@ class HomeViewModel( "" } - val safetyNetTitle = KObservableField(R.string.safetyNet_check_text.res()) + val safetyNetTitle = KObservableField(R.string.safetyNet_check_text) val ctsState = KObservableField(SafetyNetState.IDLE) val basicIntegrityState = KObservableField(SafetyNetState.IDLE) val safetyNetState = Observer(ctsState, basicIntegrityState) { @@ -124,7 +124,7 @@ class HomeViewModel( fun safetyNetPressed() { ctsState.value = SafetyNetState.LOADING basicIntegrityState.value = SafetyNetState.LOADING - safetyNetTitle.value = R.string.checking_safetyNet_status.res() + safetyNetTitle.value = R.string.checking_safetyNet_status UpdateSafetyNetEvent().publish() } @@ -133,7 +133,7 @@ class HomeViewModel( response and 0x0F == 0 -> { val hasCtsPassed = response and ISafetyNetHelper.CTS_PASS != 0 val hasBasicIntegrityPassed = response and ISafetyNetHelper.BASIC_PASS != 0 - safetyNetTitle.value = R.string.safetyNet_check_success.res() + safetyNetTitle.value = R.string.safetyNet_check_success ctsState.value = if (hasCtsPassed) { SafetyNetState.PASS } else { @@ -155,7 +155,7 @@ class HomeViewModel( safetyNetTitle.value = when (response) { ISafetyNetHelper.RESPONSE_ERR -> R.string.safetyNet_res_invalid else -> R.string.safetyNet_api_error - }.res() + } } } diff --git a/app/src/main/res/layout/fragment_magisk.xml b/app/src/main/res/layout/fragment_magisk.xml index f46cf786f..0dfc0e192 100644 --- a/app/src/main/res/layout/fragment_magisk.xml +++ b/app/src/main/res/layout/fragment_magisk.xml @@ -15,6 +15,8 @@ + + @@ -225,7 +227,7 @@ android:layout_marginRight="@dimen/margin_generic" android:gravity="center" android:maxLines="1" - android:text="@{viewModel.safetyNetTitle}" + android:text="@{XStringKt.res(viewModel.safetyNetTitle)}" android:textStyle="bold" app:autoSizeMaxTextSize="14sp" app:autoSizeTextType="uniform" From d5371f752c747290d0ff76cceeb4ce5e7e32bb20 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 11 May 2019 01:53:37 -0700 Subject: [PATCH 2/8] Sort hide targets by app name --- app/src/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt index 2e60d5d5a..d88f78f8e 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt @@ -74,7 +74,7 @@ class HideViewModel( .map { HideRvItem(it, hideTargets.blockingGet()) } .toList() .map { it.sortWith(compareBy( - {it.isHiddenState.value}, {it.item.info.name}, {it.packageName})); it } + {it.isHiddenState.value}, {it.item.name}, {it.packageName})); it } .doOnSuccess { allItems.update(it) } .flatMap { queryRaw() } .applyViewModel(this) From 62db65bf183cfde3d2b946a01d48e80d9b389322 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 11 May 2019 01:55:44 -0700 Subject: [PATCH 3/8] Reset SafetyNet status on refresh --- .../main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt index b7e329ad5..507f37268 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt @@ -163,6 +163,9 @@ class HomeViewModel( state = State.LOADING magiskState.value = MagiskState.LOADING managerState.value = MagiskState.LOADING + ctsState.value = SafetyNetState.IDLE + basicIntegrityState.value = SafetyNetState.IDLE + safetyNetTitle.value = R.string.safetyNet_check_text Event.reset(this) Config.remoteMagiskVersionString = null Config.remoteMagiskVersionCode = -1 From ef0e22cc41d01bf5f2bddae76daecb221cfef0f3 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 11 May 2019 02:29:13 -0700 Subject: [PATCH 4/8] Slightly update scripts --- app/src/main/res/raw/nonroot_utils.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/raw/nonroot_utils.sh b/app/src/main/res/raw/nonroot_utils.sh index a62f89039..7c8ae1812 100644 --- a/app/src/main/res/raw/nonroot_utils.sh +++ b/app/src/main/res/raw/nonroot_utils.sh @@ -1,9 +1,12 @@ mount_partitions() { - [ "`getprop ro.build.ab_update`" = "true" ] && SLOT=`getprop ro.boot.slot_suffix` || SLOT= + [ "`getprop ro.build.ab_update`" = "true" ] && SLOT=`getprop ro.boot.slot_suffix` [ "`getprop ro.build.system_root_image`" = "true" ] && SYSTEM_ROOT=true || SYSTEM_ROOT=false } get_flags() { $SYSTEM_ROOT && KEEPVERITY=true || KEEPVERITY=false [ "`getprop ro.crypto.state`" = "encrypted" ] && KEEPFORCEENCRYPT=true || KEEPFORCEENCRYPT=false + RECOVERYMODE=false } + +run_migrations() { return; } From d9ad7d522c40e710a671c36f36eadde9f89336a0 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sun, 12 May 2019 13:42:53 -0700 Subject: [PATCH 5/8] Update dependencies --- app/build.gradle | 9 ++++----- signing/build.gradle | 6 ++++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 68be34143..eb360f4ea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -58,7 +58,7 @@ dependencies { implementation 'com.github.skoumalcz:teanity:0.3.3' implementation 'com.ncapdevi:frag-nav:3.2.0' - def markwonVersion = '3.0.0' + def markwonVersion = '3.0.1' implementation "ru.noties.markwon:core:${markwonVersion}" implementation "ru.noties.markwon:html:${markwonVersion}" implementation "ru.noties.markwon:image-svg:${markwonVersion}" @@ -73,12 +73,11 @@ dependencies { implementation "org.koin:koin-androidx-viewmodel:${koin}" implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'androidx.preference:preference:1.0.0' - implementation 'androidx.recyclerview:recyclerview:1.1.0-alpha04' + implementation 'androidx.recyclerview:recyclerview:1.1.0-alpha05' implementation 'androidx.cardview:cardview:1.0.0' - implementation 'com.google.android.material:material:1.1.0-alpha05' + implementation 'com.google.android.material:material:1.1.0-alpha06' implementation 'androidx.work:work-runtime:2.0.1' - implementation 'androidx.transition:transition:1.1.0-beta01' + implementation 'androidx.transition:transition:1.2.0-alpha01' implementation 'androidx.multidex:multidex:2.0.1' } diff --git a/signing/build.gradle b/signing/build.gradle index 339e21088..0cd1953aa 100644 --- a/signing/build.gradle +++ b/signing/build.gradle @@ -33,6 +33,8 @@ repositories { dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation 'org.bouncycastle:bcprov-jdk15on:1.60' - implementation 'org.bouncycastle:bcpkix-jdk15on:1.60' + + def bcVer = '1.61' + implementation "org.bouncycastle:bcprov-jdk15on:${bcVer}" + implementation "org.bouncycastle:bcpkix-jdk15on:${bcVer}" } From e7339ba61920aaac14d3b35a71aa5b007b2f5b1f Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sun, 12 May 2019 16:06:22 -0700 Subject: [PATCH 6/8] We don't need BouncyCastle provider on Android --- app/proguard-rules.pro | 12 ------------ signing/build.gradle | 4 ++-- .../src/main/java/com/topjohnwu/signing/JarMap.java | 7 +++++-- .../src/main/java/com/topjohnwu/signing/SignAPK.java | 8 +------- .../main/java/com/topjohnwu/signing/SignBoot.java | 6 ------ .../main/java/com/topjohnwu/signing/ZipSigner.java | 5 +++++ 6 files changed, 13 insertions(+), 29 deletions(-) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 33f347808..86a43f8dd 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -16,12 +16,6 @@ # public *; #} -# BouncyCastle --keep,allowoptimization class org.bouncycastle.jcajce.provider.asymmetric.rsa.**SHA1** { *; } --keep,allowoptimization class org.bouncycastle.jcajce.provider.asymmetric.RSA** { *; } --keep,allowoptimization class org.bouncycastle.jcajce.provider.digest.SHA1** { *; } --dontwarn javax.naming.** - # Snet -keepclassmembers class com.topjohnwu.magisk.utils.ISafetyNetHelper { *; } -keep,allowobfuscation interface com.topjohnwu.magisk.utils.ISafetyNetHelper$Callback @@ -40,12 +34,6 @@ # BootSigner -keepclassmembers class com.topjohnwu.signing.BootSigner { *; } -# SVG --dontwarn com.caverock.androidsvg.SVGAndroidRenderer - -# RetroStreams --dontwarn java9.** - # Strip logging -assumenosideeffects class com.topjohnwu.magisk.utils.Logger { public *** debug(...); diff --git a/signing/build.gradle b/signing/build.gradle index 0cd1953aa..f8ebecd19 100644 --- a/signing/build.gradle +++ b/signing/build.gradle @@ -35,6 +35,6 @@ dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') def bcVer = '1.61' - implementation "org.bouncycastle:bcprov-jdk15on:${bcVer}" - implementation "org.bouncycastle:bcpkix-jdk15on:${bcVer}" + api "org.bouncycastle:bcprov-jdk15on:${bcVer}" + api "org.bouncycastle:bcpkix-jdk15on:${bcVer}" } diff --git a/signing/src/main/java/com/topjohnwu/signing/JarMap.java b/signing/src/main/java/com/topjohnwu/signing/JarMap.java index 44e61e11b..e9677e7e0 100644 --- a/signing/src/main/java/com/topjohnwu/signing/JarMap.java +++ b/signing/src/main/java/com/topjohnwu/signing/JarMap.java @@ -23,7 +23,7 @@ import java.util.zip.ZipFile; * On the other hand, when a JarFile is provided, it simply works as a wrapper. * */ -public class JarMap implements Closeable, AutoCloseable { +public class JarMap implements Closeable { private JarFile jarFile; private JarInputStream jis; @@ -119,7 +119,10 @@ public class JarMap implements Closeable, AutoCloseable { @Override public void close() throws IOException { - (jarFile == null ? jis : jarFile).close(); + if (jarFile != null) + jarFile.close(); + else + jis.close(); } private static class JarMapEntry extends JarEntry { diff --git a/signing/src/main/java/com/topjohnwu/signing/SignAPK.java b/signing/src/main/java/com/topjohnwu/signing/SignAPK.java index 711256cc5..f218f0a48 100644 --- a/signing/src/main/java/com/topjohnwu/signing/SignAPK.java +++ b/signing/src/main/java/com/topjohnwu/signing/SignAPK.java @@ -11,7 +11,6 @@ import org.bouncycastle.cms.CMSSignedData; import org.bouncycastle.cms.CMSSignedDataGenerator; import org.bouncycastle.cms.CMSTypedData; import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder; -import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; @@ -60,16 +59,11 @@ public class SignAPK { private static final String CERT_SF_NAME = "META-INF/CERT.SF"; private static final String CERT_SIG_NAME = "META-INF/CERT.%s"; - private static Provider sBouncyCastleProvider; + private static Provider sBouncyCastleProvider = Security.getProvider("BC"); // bitmasks for which hash algorithms we need the manifest to include. private static final int USE_SHA1 = 1; private static final int USE_SHA256 = 2; - static { - sBouncyCastleProvider = new BouncyCastleProvider(); - Security.insertProviderAt(sBouncyCastleProvider, 1); - } - public static void sign(JarMap input, OutputStream output) throws Exception { sign(SignAPK.class.getResourceAsStream("/keys/testkey.x509.pem"), SignAPK.class.getResourceAsStream("/keys/testkey.pk8"), input, output); diff --git a/signing/src/main/java/com/topjohnwu/signing/SignBoot.java b/signing/src/main/java/com/topjohnwu/signing/SignBoot.java index 2a877e14d..11ed30bc1 100644 --- a/signing/src/main/java/com/topjohnwu/signing/SignBoot.java +++ b/signing/src/main/java/com/topjohnwu/signing/SignBoot.java @@ -12,7 +12,6 @@ import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERPrintableString; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.jce.provider.BouncyCastleProvider; import java.io.ByteArrayInputStream; import java.io.FilterInputStream; @@ -23,7 +22,6 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.security.PrivateKey; import java.security.PublicKey; -import java.security.Security; import java.security.Signature; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateFactory; @@ -32,10 +30,6 @@ import java.util.Arrays; public class SignBoot { - static { - Security.addProvider(new BouncyCastleProvider()); - } - private static class PushBackRWStream extends FilterInputStream { private OutputStream out; private int pos = 0; diff --git a/signing/src/main/java/com/topjohnwu/signing/ZipSigner.java b/signing/src/main/java/com/topjohnwu/signing/ZipSigner.java index cb437f9bf..8e68de715 100644 --- a/signing/src/main/java/com/topjohnwu/signing/ZipSigner.java +++ b/signing/src/main/java/com/topjohnwu/signing/ZipSigner.java @@ -1,9 +1,12 @@ package com.topjohnwu.signing; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; +import java.security.Security; public class ZipSigner { @@ -22,6 +25,8 @@ public class ZipSigner { if (args.length != 2 && args.length != 4 && args.length != 6) usage(); + Security.insertProviderAt(new BouncyCastleProvider(), 1); + try (JarMap in = new JarMap(args[args.length - 2], false); OutputStream out = new FileOutputStream(args[args.length - 1])) { if (args.length == 2) { From 89275270f3fe61ab88fe0fc40283a1501e7ac39a Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sun, 12 May 2019 16:19:27 -0700 Subject: [PATCH 7/8] Fix code to install GMS_Conscrypt --- net/src/main/java/com/topjohnwu/net/Networking.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/src/main/java/com/topjohnwu/net/Networking.java b/net/src/main/java/com/topjohnwu/net/Networking.java index 2b7c3bbc6..c06faa382 100644 --- a/net/src/main/java/com/topjohnwu/net/Networking.java +++ b/net/src/main/java/com/topjohnwu/net/Networking.java @@ -43,7 +43,7 @@ public class Networking { gms.getClassLoader() .loadClass("com.google.android.gms.common.security.ProviderInstallerImpl") .getMethod("insertProvider", Context.class) - .invoke(null, context); + .invoke(null, gms); } catch (Exception e) { // Failed to update SSL provider, use NoSSLv3SocketFactory on SDK < 21 if (Build.VERSION.SDK_INT < 21) From 80cd85b061376d533202265c0db443a6a85ec051 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Mon, 13 May 2019 02:01:10 -0700 Subject: [PATCH 8/8] Try to use broadcast for su logging and notify In commit 8d4c407, native Magisk always launches an activity for communicating with Magisk Manager. While this works extremely well, since it also workaround stupid OEMs that blocks broadcasts, it has a problem: launching an activity will claim the focus of the device, which could be super annoying in some circumstances. This commit adds a new feature to run a broadcast test on boot complete. If Magisk Manager successfully receives the broadcast, it will toggle a setting in magiskd so all future su loggings and notifies will always use broadcasts instead of launching activities. Fix #1412 --- .../model/receiver/GeneralReceiver.java | 84 ------------------- .../magisk/model/receiver/GeneralReceiver.kt | 80 ++++++++++++++++++ .../magisk/ui/surequest/SuRequestActivity.kt | 13 +-- native/jni/core/bootstages.cpp | 3 + native/jni/core/daemon.cpp | 5 ++ native/jni/core/db.cpp | 2 +- native/jni/core/magisk.cpp | 35 ++++---- native/jni/include/daemon.h | 4 +- native/jni/include/db.h | 2 +- native/jni/su/connect.cpp | 74 +++++++++++----- native/jni/su/su.h | 2 +- native/jni/su/su_daemon.cpp | 2 +- 12 files changed, 173 insertions(+), 133 deletions(-) delete mode 100644 app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.java create mode 100644 app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.kt diff --git a/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.java b/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.java deleted file mode 100644 index 0a7432c4d..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.topjohnwu.magisk.model.receiver; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; - -import com.topjohnwu.magisk.App; -import com.topjohnwu.magisk.ClassMap; -import com.topjohnwu.magisk.Config; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.ui.surequest.SuRequestActivity; -import com.topjohnwu.magisk.utils.DownloadApp; -import com.topjohnwu.magisk.utils.SuLogger; -import com.topjohnwu.magisk.view.Notifications; -import com.topjohnwu.magisk.view.Shortcuts; -import com.topjohnwu.superuser.Shell; - -public class GeneralReceiver extends BroadcastReceiver { - - private String getPkg(Intent i) { - return i.getData() == null ? "" : i.getData().getEncodedSchemeSpecificPart(); - } - - @Override - public void onReceive(Context context, Intent intent) { - App app = App.self; - if (intent == null) - return; - String action = intent.getAction(); - if (action == null) - return; - switch (action) { - case Intent.ACTION_REBOOT: - case Intent.ACTION_BOOT_COMPLETED: - action = intent.getStringExtra("action"); - if (action == null) { - // Actual boot completed event - Shell.su("mm_patch_dtbo").submit(result -> { - if (result.isSuccess()) - Notifications.dtboPatched(); - }); - break; - } - switch (action) { - case SuRequestActivity.REQUEST: - Intent i = new Intent(app, ClassMap.get(SuRequestActivity.class)) - .setAction(action) - .putExtra("socket", intent.getStringExtra("socket")) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - .addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); - app.startActivity(i); - break; - case SuRequestActivity.LOG: - SuLogger.handleLogs(intent); - break; - case SuRequestActivity.NOTIFY: - SuLogger.handleNotify(intent); - break; - } - break; - case Intent.ACTION_PACKAGE_REPLACED: - // This will only work pre-O - if (Config.get(Config.Key.SU_REAUTH)) { - app.getDB().deletePolicy(getPkg(intent)); - } - break; - case Intent.ACTION_PACKAGE_FULLY_REMOVED: - String pkg = getPkg(intent); - app.getDB().deletePolicy(pkg); - Shell.su("magiskhide --rm " + pkg).submit(); - break; - case Intent.ACTION_LOCALE_CHANGED: - Shortcuts.setup(context); - break; - case Const.Key.BROADCAST_MANAGER_UPDATE: - Config.managerLink = intent.getStringExtra(Const.Key.INTENT_SET_LINK); - DownloadApp.upgrade(intent.getStringExtra(Const.Key.INTENT_SET_NAME)); - break; - case Const.Key.BROADCAST_REBOOT: - Shell.su("/system/bin/reboot").submit(); - break; - } - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.kt b/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.kt new file mode 100644 index 000000000..8024d39e0 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.kt @@ -0,0 +1,80 @@ +package com.topjohnwu.magisk.model.receiver + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import com.topjohnwu.magisk.ClassMap +import com.topjohnwu.magisk.Config +import com.topjohnwu.magisk.Const +import com.topjohnwu.magisk.data.database.MagiskDB +import com.topjohnwu.magisk.ui.surequest.SuRequestActivity +import com.topjohnwu.magisk.utils.DownloadApp +import com.topjohnwu.magisk.utils.RootUtils +import com.topjohnwu.magisk.utils.SuLogger +import com.topjohnwu.magisk.utils.get +import com.topjohnwu.magisk.view.Notifications +import com.topjohnwu.magisk.view.Shortcuts +import com.topjohnwu.superuser.Shell + +open class GeneralReceiver : BroadcastReceiver() { + + companion object { + const val REQUEST = "request" + const val LOG = "log" + const val NOTIFY = "notify" + const val TEST = "test" + } + + private fun getPkg(intent: Intent): String { + return intent.data?.encodedSchemeSpecificPart ?: "" + } + + override fun onReceive(context: Context, intent: Intent?) { + if (intent == null) + return + val mDB: MagiskDB = get() + var action: String? = intent.action ?: return + when (action) { + Intent.ACTION_REBOOT, Intent.ACTION_BOOT_COMPLETED -> { + action = intent.getStringExtra("action") + if (action == null) { + // Actual boot completed event + Shell.su("mm_patch_dtbo").submit { result -> + if (result.isSuccess) + Notifications.dtboPatched() + } + return + } + when (action) { + REQUEST -> { + val i = Intent(context, ClassMap.get(SuRequestActivity::class.java)) + .setAction(action) + .putExtra("socket", intent.getStringExtra("socket")) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK) + context.startActivity(i) + } + LOG -> SuLogger.handleLogs(intent) + NOTIFY -> SuLogger.handleNotify(intent) + TEST -> Shell.su("magisk --use-broadcast").submit() + } + } + Intent.ACTION_PACKAGE_REPLACED -> + // This will only work pre-O + if (Config.get(Config.Key.SU_REAUTH)!!) { + mDB.deletePolicy(getPkg(intent)) + } + Intent.ACTION_PACKAGE_FULLY_REMOVED -> { + val pkg = getPkg(intent) + mDB.deletePolicy(pkg) + Shell.su("magiskhide --rm $pkg").submit() + } + Intent.ACTION_LOCALE_CHANGED -> Shortcuts.setup(context) + Const.Key.BROADCAST_MANAGER_UPDATE -> { + Config.managerLink = intent.getStringExtra(Const.Key.INTENT_SET_LINK) + DownloadApp.upgrade(intent.getStringExtra(Const.Key.INTENT_SET_NAME)) + } + Const.Key.BROADCAST_REBOOT -> RootUtils.reboot() + } + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestActivity.kt b/app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestActivity.kt index 9ad1b2f62..dddf4d75a 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestActivity.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestActivity.kt @@ -10,6 +10,7 @@ import com.topjohnwu.magisk.R import com.topjohnwu.magisk.databinding.ActivityRequestBinding import com.topjohnwu.magisk.model.entity.Policy import com.topjohnwu.magisk.model.events.DieEvent +import com.topjohnwu.magisk.model.receiver.GeneralReceiver import com.topjohnwu.magisk.ui.base.MagiskActivity import com.topjohnwu.magisk.utils.SuLogger import org.koin.androidx.viewmodel.ext.android.viewModel @@ -31,15 +32,15 @@ open class SuRequestActivity : MagiskActivity%li)", uid, time(nullptr)); diff --git a/native/jni/core/magisk.cpp b/native/jni/core/magisk.cpp index 3468728cd..b14300f9f 100644 --- a/native/jni/core/magisk.cpp +++ b/native/jni/core/magisk.cpp @@ -12,6 +12,8 @@ #include #include +using namespace std::literals; + [[noreturn]] static void usage() { fprintf(stderr, FULL_VER(Magisk) " multi-call binary\n" @@ -33,6 +35,7 @@ " --clone-attr SRC DEST clone permission, owner, and selinux context\n" " --clone SRC DEST clone SRC to DEST\n" " --sqlite SQL exec SQL to Magisk database\n" + " --use-broadcast use broadcast for su logging and notify\n" "\n" "Supported init triggers:\n" " post-fs-data, service, boot-complete\n" @@ -48,66 +51,70 @@ int magisk_main(int argc, char *argv[]) { if (argc < 2) usage(); - if (strcmp(argv[1], "-c") == 0) { + if (argv[1] == "-c"sv) { printf(MAGISK_VERSION ":MAGISK (" str(MAGISK_VER_CODE) ")\n"); return 0; - } else if (strcmp(argv[1], "-v") == 0) { + } else if (argv[1] == "-v"sv) { int fd = connect_daemon(); write_int(fd, CHECK_VERSION); char *v = read_string(fd); printf("%s\n", v); free(v); return 0; - } else if (strcmp(argv[1], "-V") == 0) { + } else if (argv[1] == "-V"sv) { int fd = connect_daemon(); write_int(fd, CHECK_VERSION_CODE); printf("%d\n", read_int(fd)); return 0; - } else if (strcmp(argv[1], "--list") == 0) { + } else if (argv[1] == "--list"sv) { for (int i = 0; applet_names[i]; ++i) printf("%s\n", applet_names[i]); return 0; - } else if (strcmp(argv[1], "--unlock-blocks") == 0) { + } else if (argv[1] == "--unlock-blocks"sv) { unlock_blocks(); return 0; - } else if (strcmp(argv[1], "--restorecon") == 0) { + } else if (argv[1] == "--restorecon"sv) { restore_rootcon(); restorecon(); return 0; - } else if (strcmp(argv[1], "--clone-attr") == 0) { + } else if (argv[1] == "--clone-attr"sv) { if (argc < 4) usage(); clone_attr(argv[2], argv[3]); return 0; - } else if (strcmp(argv[1], "--clone") == 0) { + } else if (argv[1] == "--clone"sv) { if (argc < 4) usage(); cp_afc(argv[2], argv[3]); return 0; - } else if (strcmp(argv[1], "--daemon") == 0) { + } else if (argv[1] == "--daemon"sv) { int fd = connect_daemon(true); write_int(fd, DO_NOTHING); return 0; - } else if (strcmp(argv[1], "--post-fs-data") == 0) { + } else if (argv[1] == "--post-fs-data"sv) { int fd = connect_daemon(true); write_int(fd, POST_FS_DATA); return read_int(fd); - } else if (strcmp(argv[1], "--service") == 0) { + } else if (argv[1] == "--service"sv) { int fd = connect_daemon(true); write_int(fd, LATE_START); return read_int(fd); - } else if (strcmp(argv[1], "--boot-complete") == 0) { + } else if (argv[1] == "--boot-complete"sv) { int fd = connect_daemon(true); write_int(fd, BOOT_COMPLETE); return read_int(fd); - } else if (strcmp(argv[1], "--sqlite") == 0) { + } else if (argv[1] == "--sqlite"sv) { int fd = connect_daemon(); write_int(fd, SQLITE_CMD); write_string(fd, argv[2]); send_fd(fd, STDOUT_FILENO); return read_int(fd); + } else if (argv[1] == "--use-broadcast"sv) { + int fd = connect_daemon(); + write_int(fd, BROADCAST_ACK); + return 0; } #if 0 /* Entry point for testing stuffs */ - else if (strcmp(argv[1], "--test") == 0) { + else if (argv[1] == "--test"sv) { return 0; } #endif diff --git a/native/jni/include/daemon.h b/native/jni/include/daemon.h index 41baeb9c8..bfc45041c 100644 --- a/native/jni/include/daemon.h +++ b/native/jni/include/daemon.h @@ -17,7 +17,7 @@ enum { BOOT_COMPLETE, MAGISKHIDE, SQLITE_CMD, - ZYGOTE_NOTIFY, + BROADCAST_ACK, }; // Return codes for daemon @@ -82,6 +82,8 @@ void magiskhide_handler(int client); *************/ void su_daemon_handler(int client, struct ucred *credential); +void broadcast_test(); extern int SDK_INT; extern bool RECOVERY_MODE; +extern bool CONNECT_BROADCAST; diff --git a/native/jni/include/db.h b/native/jni/include/db.h index 50f8605ca..7b5726e0a 100644 --- a/native/jni/include/db.h +++ b/native/jni/include/db.h @@ -154,7 +154,7 @@ typedef std::function db_row_cb; int get_db_settings(db_settings &cfg, int key = -1); int get_db_strings(db_strings &str, int key = -1); -int get_uid_policy(int uid, su_access &su); +int get_uid_policy(su_access &su, int uid); int validate_manager(std::string &alt_pkg, int userid, struct stat *st); void exec_sql(int client); char *db_exec(const char *sql); diff --git a/native/jni/su/connect.cpp b/native/jni/su/connect.cpp index f68997f18..4cf8720f1 100644 --- a/native/jni/su/connect.cpp +++ b/native/jni/su/connect.cpp @@ -11,12 +11,21 @@ #include "su.h" +bool CONNECT_BROADCAST; + #define START_ACTIVITY \ "/system/bin/app_process", "/system/bin", "com.android.commands.am.Am", \ "start", "-n", nullptr, "--user", nullptr, "-f", "0x18000020", "-a" // 0x18000020 = FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_MULTIPLE_TASK|FLAG_INCLUDE_STOPPED_PACKAGES +#define START_BROADCAST \ +"/system/bin/app_process", "/system/bin", "com.android.commands.am.Am", \ +"broadcast", "-n", nullptr, "--user", nullptr, "-f", "0x00000020", \ +"-a", "android.intent.action.REBOOT", "--es", "action" + +// 0x00000020 = FLAG_INCLUDE_STOPPED_PACKAGES + static inline const char *get_command(const su_request *to) { if (to->command[0]) return to->command; @@ -39,9 +48,9 @@ static inline void get_uid(char *uid, su_info *info) { : info->uid); } -static void silent_run(const char **args, su_info *info) { +static void exec_am_cmd(const char **args, su_info *info) { char component[128]; - sprintf(component, "%s/a.m", info->str[SU_MANAGER].data()); + sprintf(component, "%s/%s", info->str[SU_MANAGER].data(), args[3][0] == 'b' ? "a.h" : "a.m"); char user[8]; get_user(user, info); @@ -62,6 +71,16 @@ static void silent_run(const char **args, su_info *info) { exec_command(exec); } +#define LOG_BODY \ +"log", \ +"--ei", "from.uid", fromUid, \ +"--ei", "to.uid", toUid, \ +"--ei", "pid", pid, \ +"--ei", "policy", policy, \ +"--es", "command", get_command(&ctx->req), \ +"--ez", "notify", ctx->info->access.notify ? "true" : "false", \ +nullptr + void app_log(su_context *ctx) { char fromUid[8]; get_uid(fromUid, ctx->info); @@ -75,19 +94,21 @@ void app_log(su_context *ctx) { char policy[2]; sprintf(policy, "%d", ctx->info->access.policy); - const char *cmd[] = { - START_ACTIVITY, "log", - "--ei", "from.uid", fromUid, - "--ei", "to.uid", toUid, - "--ei", "pid", pid, - "--ei", "policy", policy, - "--es", "command", get_command(&ctx->req), - "--ez", "notify", ctx->info->access.notify ? "true" : "false", - nullptr - }; - silent_run(cmd, ctx->info); + if (CONNECT_BROADCAST) { + const char *cmd[] = { START_BROADCAST, LOG_BODY }; + exec_am_cmd(cmd, ctx->info); + } else { + const char *cmd[] = { START_ACTIVITY, LOG_BODY }; + exec_am_cmd(cmd, ctx->info); + } } +#define NOTIFY_BODY \ +"notify", \ +"--ei", "from.uid", fromUid, \ +"--ei", "policy", policy, \ +nullptr + void app_notify(su_context *ctx) { char fromUid[8]; get_uid(fromUid, ctx->info); @@ -95,13 +116,14 @@ void app_notify(su_context *ctx) { char policy[2]; sprintf(policy, "%d", ctx->info->access.policy); - const char *cmd[] = { - START_ACTIVITY, "notify", - "--ei", "from.uid", fromUid, - "--ei", "policy", policy, - nullptr - }; - silent_run(cmd, ctx->info); + if (CONNECT_BROADCAST) { + const char *cmd[] = { START_BROADCAST, NOTIFY_BODY }; + exec_am_cmd(cmd, ctx->info); + } else { + const char *cmd[] = { START_ACTIVITY, NOTIFY_BODY }; + exec_am_cmd(cmd, ctx->info); + } + } void app_connect(const char *socket, su_info *info) { @@ -110,7 +132,17 @@ void app_connect(const char *socket, su_info *info) { "--es", "socket", socket, nullptr }; - silent_run(cmd, info); + exec_am_cmd(cmd, info); +} + +void broadcast_test() { + su_info info; + get_db_settings(info.cfg); + get_db_strings(info.str); + validate_manager(info.str[SU_MANAGER], 0, &info.mgr_st); + + const char *cmd[] = { START_BROADCAST, "test", nullptr }; + exec_am_cmd(cmd, &info); } void socket_send_request(int fd, su_info *info) { diff --git a/native/jni/su/su.h b/native/jni/su/su.h index 4d7822c02..33672da7e 100644 --- a/native/jni/su/su.h +++ b/native/jni/su/su.h @@ -32,7 +32,7 @@ public: int ref; time_t timestamp; - su_info(unsigned uid); + su_info(unsigned uid = 0); ~su_info(); void lock(); void unlock(); diff --git a/native/jni/su/su_daemon.cpp b/native/jni/su/su_daemon.cpp index 3d69bddda..d9f022e4d 100644 --- a/native/jni/su/su_daemon.cpp +++ b/native/jni/su/su_daemon.cpp @@ -83,7 +83,7 @@ static void database_check(su_info *info) { } if (uid > 0) - get_uid_policy(uid, info->access); + get_uid_policy(info->access, uid); // We need to check our manager if (info->access.log || info->access.notify)