Compare commits

...

12 Commits

Author SHA1 Message Date
topjohnwu
12bbc7fd6b Update v7.3.1 changelog 2019-06-17 22:15:38 -07:00
topjohnwu
bf9ac8252b Cleanup UpdateInfo 2019-06-16 16:47:30 -07:00
topjohnwu
4a3f5dc619 Cleanups 2019-06-16 14:35:51 -07:00
Viktor De Pasquale
ca156befbd Fixed mapping generic pairs to policy crashing when no policy is found
The policy (app) is now deleted when found invalid (uninstalled)
2019-06-16 16:50:08 -04:00
Viktor De Pasquale
4db41e2ac4 Added attempted fix for parsing data off default thread 2019-06-16 16:50:08 -04:00
Viktor De Pasquale
982a43fce1 Moved diff computation of policy list to the background thread 2019-06-16 16:50:08 -04:00
Viktor De Pasquale
dd76a74e1c Fixed fast scroll button crashing while scrolling to undefined position 2019-06-16 16:50:08 -04:00
Viktor De Pasquale
70cb52b2c7 Fixed fast scroll button being visible when log is empty 2019-06-16 16:50:08 -04:00
topjohnwu
5c7f69acaa Separate SAR and legacy implementation 2019-06-16 12:45:32 -07:00
topjohnwu
f1d9015e5f Move load kernel info out of class 2019-06-15 22:25:09 -07:00
topjohnwu
e8d900c58e Fix typo 2019-06-15 18:12:12 -07:00
topjohnwu
a6241ae912 Fix magiskboot unpack option parsing 2019-06-15 16:15:12 -07:00
33 changed files with 317 additions and 296 deletions

View File

@@ -1,26 +1,20 @@
package com.topjohnwu.magisk; package com.topjohnwu.magisk;
import androidx.annotation.NonNull;
import com.topjohnwu.magisk.model.entity.UpdateInfo;
import com.topjohnwu.superuser.Shell; import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.ShellUtils; import com.topjohnwu.superuser.ShellUtils;
public final class Info { public final class Info {
public static int magiskVersionCode = -1; public static int magiskVersionCode = -1;
// Current status
public static String magiskVersionString = "";
// Update Info
public static String remoteMagiskVersionString = "";
public static int remoteMagiskVersionCode = -1;
public static String magiskLink = "";
public static String magiskNoteLink = "";
public static String magiskMD5 = "";
public static String remoteManagerVersionString = "";
public static int remoteManagerVersionCode = -1;
public static String managerLink = "";
public static String managerNoteLink = "";
public static String uninstallerLink = "";
// Install flags @NonNull
public static String magiskVersionString = "";
public static UpdateInfo remote = new UpdateInfo();
public static boolean keepVerity = false; public static boolean keepVerity = false;
public static boolean keepEnc = false; public static boolean keepEnc = false;
public static boolean recovery = false; public static boolean recovery = false;

View File

@@ -8,6 +8,7 @@ import com.topjohnwu.magisk.model.entity.MagiskPolicy
import com.topjohnwu.magisk.model.entity.toMap import com.topjohnwu.magisk.model.entity.toMap
import com.topjohnwu.magisk.model.entity.toPolicy import com.topjohnwu.magisk.model.entity.toPolicy
import com.topjohnwu.magisk.utils.now import com.topjohnwu.magisk.utils.now
import timber.log.Timber
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@@ -47,12 +48,7 @@ class PolicyDao(
condition { condition {
equals("uid", uid) equals("uid", uid)
} }
}.map { it.firstOrNull()?.toPolicy(context.packageManager) } }.map { it.first().toPolicySafe() }
.doOnError {
if (it is PackageManager.NameNotFoundException) {
delete(uid).subscribe()
}
}
fun update(policy: MagiskPolicy) = query<Replace> { fun update(policy: MagiskPolicy) = query<Replace> {
values(policy.toMap()) values(policy.toMap())
@@ -62,8 +58,24 @@ class PolicyDao(
condition { condition {
equals("uid/100000", Const.USER_ID) equals("uid/100000", Const.USER_ID)
} }
}.flattenAsFlowable { it } }.map { it.mapNotNull { it.toPolicySafe() } }
.map { it.toPolicy(context.packageManager) }
.toList()
private fun Map<String, String>.toPolicySafe(): MagiskPolicy? {
val taskResult = runCatching { toPolicy(context.packageManager) }
val result = taskResult.getOrNull()
val exception = taskResult.exceptionOrNull()
Timber.e(exception)
when (exception) {
is PackageManager.NameNotFoundException -> {
val uid = getOrElse("uid") { null } ?: return null
delete(uid).subscribe()
}
}
return result
}
} }

View File

@@ -1,7 +1,7 @@
package com.topjohnwu.magisk.data.network package com.topjohnwu.magisk.data.network
import com.topjohnwu.magisk.Const import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.model.entity.MagiskConfig import com.topjohnwu.magisk.model.entity.UpdateInfo
import io.reactivex.Single import io.reactivex.Single
import okhttp3.ResponseBody import okhttp3.ResponseBody
import retrofit2.http.GET import retrofit2.http.GET
@@ -15,19 +15,19 @@ interface GithubRawApiServices {
//region topjohnwu/magisk_files //region topjohnwu/magisk_files
@GET("$MAGISK_FILES/master/stable.json") @GET("$MAGISK_FILES/master/stable.json")
fun fetchStableUpdate(): Single<MagiskConfig> fun fetchStableUpdate(): Single<UpdateInfo>
@GET("$MAGISK_FILES/master/beta.json") @GET("$MAGISK_FILES/master/beta.json")
fun fetchBetaUpdate(): Single<MagiskConfig> fun fetchBetaUpdate(): Single<UpdateInfo>
@GET("$MAGISK_FILES/master/canary_builds/release.json") @GET("$MAGISK_FILES/master/canary_builds/release.json")
fun fetchCanaryUpdate(): Single<MagiskConfig> fun fetchCanaryUpdate(): Single<UpdateInfo>
@GET("$MAGISK_FILES/master/canary_builds/canary.json") @GET("$MAGISK_FILES/master/canary_builds/canary.json")
fun fetchCanaryDebugUpdate(): Single<MagiskConfig> fun fetchCanaryDebugUpdate(): Single<UpdateInfo>
@GET @GET
fun fetchCustomUpdate(@Url url: String): Single<MagiskConfig> fun fetchCustomUpdate(@Url url: String): Single<UpdateInfo>
@GET("$MAGISK_FILES/{$REVISION}/snet.apk") @GET("$MAGISK_FILES/{$REVISION}/snet.apk")
@Streaming @Streaming

View File

@@ -7,7 +7,6 @@ import com.topjohnwu.magisk.model.entity.MagiskLog
import com.topjohnwu.magisk.model.entity.WrappedMagiskLog import com.topjohnwu.magisk.model.entity.WrappedMagiskLog
import com.topjohnwu.magisk.utils.toSingle import com.topjohnwu.magisk.utils.toSingle
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import timber.log.Timber
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@@ -21,7 +20,6 @@ class LogRepository(
fun fetchMagiskLogs() = "tail -n 5000 ${Const.MAGISK_LOG}".suRaw() fun fetchMagiskLogs() = "tail -n 5000 ${Const.MAGISK_LOG}".suRaw()
.filter { it.isNotEmpty() } .filter { it.isNotEmpty() }
.map { Timber.i(it.toString()); it }
fun clearLogs() = logDao.deleteAll() fun clearLogs() = logDao.deleteAll()
fun clearOutdated() = logDao.deleteOutdated() fun clearOutdated() = logDao.deleteOutdated()

View File

@@ -50,27 +50,14 @@ class MagiskRepository(
else -> throw IllegalArgumentException() else -> throw IllegalArgumentException()
}.flatMap { }.flatMap {
// If remote version is lower than current installed, try switching to beta // If remote version is lower than current installed, try switching to beta
if (it.magisk.versionCode.toIntOrNull() ?: -1 < Info.magiskVersionCode if (it.magisk.versionCode < Info.magiskVersionCode
&& Config.updateChannel == Config.Value.DEFAULT_CHANNEL) { && Config.updateChannel == Config.Value.DEFAULT_CHANNEL) {
Config.updateChannel = Config.Value.BETA_CHANNEL Config.updateChannel = Config.Value.BETA_CHANNEL
apiRaw.fetchBetaUpdate() apiRaw.fetchBetaUpdate()
} else { } else {
Single.just(it) Single.just(it)
} }
}.doOnSuccess { }.map { Info.remote = it; it }
Info.remoteMagiskVersionString = it.magisk.version
Info.remoteMagiskVersionCode = it.magisk.versionCode.toIntOrNull() ?: -1
Info.magiskLink = it.magisk.link
Info.magiskNoteLink = it.magisk.note
Info.magiskMD5 = it.magisk.hash
Info.remoteManagerVersionString = it.app.version
Info.remoteManagerVersionCode = it.app.versionCode.toIntOrNull() ?: -1
Info.managerLink = it.app.link
Info.managerNoteLink = it.app.note
Info.uninstallerLink = it.uninstaller.link
}
fun fetchApps() = fun fetchApps() =
Single.fromCallable { packageManager.getInstalledApplications(0) } Single.fromCallable { packageManager.getInstalledApplications(0) }

View File

@@ -1,11 +0,0 @@
package com.topjohnwu.magisk.model.entity
import se.ansman.kotshi.JsonSerializable
@JsonSerializable
data class MagiskApp(
val version: String,
val versionCode: String,
val link: String,
val note: String
)

View File

@@ -1,10 +0,0 @@
package com.topjohnwu.magisk.model.entity
import se.ansman.kotshi.JsonSerializable
@JsonSerializable
data class MagiskConfig(
val app: MagiskApp,
val uninstaller: MagiskLink,
val magisk: MagiskFlashable
)

View File

@@ -1,13 +0,0 @@
package com.topjohnwu.magisk.model.entity
import com.squareup.moshi.Json
import se.ansman.kotshi.JsonSerializable
@JsonSerializable
data class MagiskFlashable(
val version: String,
val versionCode: String,
val link: String,
val note: String,
@Json(name = "md5") val hash: String
)

View File

@@ -1,8 +0,0 @@
package com.topjohnwu.magisk.model.entity
import se.ansman.kotshi.JsonSerializable
@JsonSerializable
data class MagiskLink(
val link: String
)

View File

@@ -0,0 +1,33 @@
package com.topjohnwu.magisk.model.entity
import com.squareup.moshi.Json
import se.ansman.kotshi.JsonSerializable
@JsonSerializable
data class UpdateInfo(
val app: ManagerJson = ManagerJson(),
val uninstaller: UninstallerJson = UninstallerJson(),
val magisk: MagiskJson = MagiskJson()
)
@JsonSerializable
data class UninstallerJson(
val link: String = ""
)
@JsonSerializable
data class MagiskJson(
val version: String = "",
val versionCode: Int = -1,
val link: String = "",
val note: String = "",
@Json(name = "md5") val hash: String = ""
)
@JsonSerializable
data class ManagerJson(
val version: String = "",
val versionCode: Int = -1,
val link: String = "",
val note: String = ""
)

View File

@@ -73,7 +73,8 @@ open class GeneralReceiver : BroadcastReceiver() {
} }
Intent.ACTION_LOCALE_CHANGED -> Shortcuts.setup(context) Intent.ACTION_LOCALE_CHANGED -> Shortcuts.setup(context)
Const.Key.BROADCAST_MANAGER_UPDATE -> { Const.Key.BROADCAST_MANAGER_UPDATE -> {
Info.managerLink = intent.getStringExtra(Const.Key.INTENT_SET_LINK) Info.remote = Info.remote.copy(app = Info.remote.app.copy(
link = intent.getStringExtra(Const.Key.INTENT_SET_LINK) ?: ""))
DownloadApp.upgrade(intent.getStringExtra(Const.Key.INTENT_SET_NAME)) DownloadApp.upgrade(intent.getStringExtra(Const.Key.INTENT_SET_NAME))
} }
Const.Key.BROADCAST_REBOOT -> reboot() Const.Key.BROADCAST_REBOOT -> reboot()

View File

@@ -18,9 +18,9 @@ class UpdateCheckService : DelegateWorker() {
Shell.getShell() Shell.getShell()
return runCatching { return runCatching {
magiskRepo.fetchUpdate().blockingGet() magiskRepo.fetchUpdate().blockingGet()
if (BuildConfig.VERSION_CODE < Info.remoteManagerVersionCode) if (BuildConfig.VERSION_CODE < Info.remote.app.versionCode)
Notifications.managerUpdate() Notifications.managerUpdate()
else if (Info.magiskVersionCode < Info.remoteMagiskVersionCode) else if (Info.magiskVersionCode < Info.remote.magisk.versionCode)
Notifications.magiskUpdate() Notifications.magiskUpdate()
ListenableWorker.Result.success() ListenableWorker.Result.success()
}.getOrElse { }.getOrElse {

View File

@@ -123,9 +123,9 @@ public abstract class MagiskInstaller {
File zip = new File(App.self.getCacheDir(), "magisk.zip"); File zip = new File(App.self.getCacheDir(), "magisk.zip");
if (!ShellUtils.checkSum("MD5", zip, Info.magiskMD5)) { if (!ShellUtils.checkSum("MD5", zip, Info.remote.getMagisk().getHash())) {
console.add("- Downloading zip"); console.add("- Downloading zip");
Networking.get(Info.magiskLink) Networking.get(Info.remote.getMagisk().getLink())
.setDownloadProgressListener(new ProgressLog()) .setDownloadProgressListener(new ProgressLog())
.execForFile(zip); .execForFile(zip);
} else { } else {

View File

@@ -3,8 +3,6 @@ package com.topjohnwu.magisk.tasks;
import android.database.Cursor; import android.database.Cursor;
import android.util.Pair; import android.util.Pair;
import androidx.annotation.NonNull;
import com.topjohnwu.magisk.App; import com.topjohnwu.magisk.App;
import com.topjohnwu.magisk.Config; import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.Const; import com.topjohnwu.magisk.Const;
@@ -20,7 +18,6 @@ import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.text.DateFormat;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Collections; import java.util.Collections;
@@ -33,16 +30,11 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import androidx.annotation.NonNull;
import io.reactivex.Single; import io.reactivex.Single;
@Deprecated @Deprecated
public class UpdateRepos { public class UpdateRepos {
private static final DateFormat DATE_FORMAT;
static {
DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
}
@NonNull @NonNull
private final RepoDatabaseHelper repoDB; private final RepoDatabaseHelper repoDB;
@@ -71,6 +63,17 @@ public class UpdateRepos {
} }
} }
/**
* Static instance of (Simple)DateFormat is not threadsafe so in order to make it safe it needs
* to be created beforehand on the same thread where it'll be used.
* See https://stackoverflow.com/a/18383395
*/
private static SimpleDateFormat getDateFormat() {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("UTC"));
return format;
}
/* We sort repos by last push, which means that we only need to check whether the /* We sort repos by last push, which means that we only need to check whether the
* first page is updated to determine whether the online repo database is changed * first page is updated to determine whether the online repo database is changed
*/ */
@@ -95,10 +98,12 @@ public class UpdateRepos {
return true; return true;
try { try {
SimpleDateFormat dateFormat = getDateFormat();
for (int i = 0; i < res.getResult().length(); i++) { for (int i = 0; i < res.getResult().length(); i++) {
JSONObject rawRepo = res.getResult().getJSONObject(i); JSONObject rawRepo = res.getResult().getJSONObject(i);
String id = rawRepo.getString("name"); String id = rawRepo.getString("name");
Date date = DATE_FORMAT.parse(rawRepo.getString("pushed_at")); Date date = dateFormat.parse(rawRepo.getString("pushed_at"));
moduleQueue.offer(new Pair<>(id, date)); moduleQueue.offer(new Pair<>(id, date));
} }
} catch (JSONException | ParseException e) { } catch (JSONException | ParseException e) {

View File

@@ -5,14 +5,11 @@ import android.os.Bundle
import android.text.TextUtils import android.text.TextUtils
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.skoumal.teanity.extensions.subscribeK
import com.topjohnwu.magisk.* import com.topjohnwu.magisk.*
import com.topjohnwu.magisk.data.database.SettingsDao import com.topjohnwu.magisk.data.database.SettingsDao
import com.topjohnwu.magisk.tasks.UpdateRepos
import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.magisk.view.Shortcuts import com.topjohnwu.magisk.view.Shortcuts
import com.topjohnwu.net.Networking
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import org.koin.android.ext.android.get import org.koin.android.ext.android.get
@@ -61,14 +58,6 @@ open class SplashActivity : AppCompatActivity() {
// Setup shortcuts // Setup shortcuts
Shortcuts.setup(this) Shortcuts.setup(this)
// Magisk working as expected
if (Shell.rootAccess() && Info.magiskVersionCode > 0) {
// Load repos
if (Networking.checkNetworkStatus(this)) {
get<UpdateRepos>().exec().subscribeK()
}
}
val intent = Intent(this, ClassMap[MainActivity::class.java]) val intent = Intent(this, ClassMap[MainActivity::class.java])
intent.putExtra(Const.Key.OPEN_SECTION, getIntent().getStringExtra(Const.Key.OPEN_SECTION)) intent.putExtra(Const.Key.OPEN_SECTION, getIntent().getStringExtra(Const.Key.OPEN_SECTION))
DONE = true DONE = true

View File

@@ -56,7 +56,7 @@ class HomeFragment : MagiskFragment<HomeViewModel, FragmentMagiskBinding>(),
private fun installMagisk() { private fun installMagisk() {
// Show Manager update first // Show Manager update first
if (Info.remoteManagerVersionCode > BuildConfig.VERSION_CODE) { if (Info.remote.app.versionCode > BuildConfig.VERSION_CODE) {
installManager() installManager()
return return
} }

View File

@@ -172,7 +172,7 @@ class HomeViewModel(
state = State.LOADED state = State.LOADED
magiskState.value = when (Info.magiskVersionCode) { magiskState.value = when (Info.magiskVersionCode) {
in Int.MIN_VALUE until 0 -> MagiskState.NOT_INSTALLED in Int.MIN_VALUE until 0 -> MagiskState.NOT_INSTALLED
!in Info.remoteMagiskVersionCode..Int.MAX_VALUE -> MagiskState.OBSOLETE !in Info.remote.magisk.versionCode..Int.MAX_VALUE -> MagiskState.OBSOLETE
else -> MagiskState.UP_TO_DATE else -> MagiskState.UP_TO_DATE
} }
@@ -183,9 +183,9 @@ class HomeViewModel(
} }
magiskLatestVersion.value = version magiskLatestVersion.value = version
.format(Info.remoteMagiskVersionString, Info.remoteMagiskVersionCode) .format(Info.remote.magisk.version, Info.remote.magisk.versionCode)
managerState.value = when (Info.remoteManagerVersionCode) { managerState.value = when (Info.remote.app.versionCode) {
in Int.MIN_VALUE until 0 -> MagiskState.NOT_INSTALLED //wrong update channel in Int.MIN_VALUE until 0 -> MagiskState.NOT_INSTALLED //wrong update channel
in (BuildConfig.VERSION_CODE + 1)..Int.MAX_VALUE -> MagiskState.OBSOLETE in (BuildConfig.VERSION_CODE + 1)..Int.MAX_VALUE -> MagiskState.OBSOLETE
else -> MagiskState.UP_TO_DATE else -> MagiskState.UP_TO_DATE
@@ -195,7 +195,7 @@ class HomeViewModel(
.format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE) .format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)
managerLatestVersion.value = version managerLatestVersion.value = version
.format(Info.remoteManagerVersionString, Info.remoteManagerVersionCode) .format(Info.remote.app.version, Info.remote.app.versionCode)
} }
private fun ensureEnv() { private fun ensureEnv() {

View File

@@ -61,9 +61,10 @@ class SuperuserViewModel(
{ it.item.packageName } { it.item.packageName }
)) ))
} }
.map { it to items.calculateDiff(it) }
.applySchedulers() .applySchedulers()
.applyViewModel(this) .applyViewModel(this)
.subscribeK { items.update(it) } .subscribeK { items.update(it.first, it.second) }
.add() .add()
} }

View File

@@ -186,9 +186,17 @@ fun setHidden(view: FloatingActionButton, hide: Boolean) {
} }
@BindingAdapter("scrollPosition", "scrollPositionSmooth", requireAll = false) @BindingAdapter("scrollPosition", "scrollPositionSmooth", requireAll = false)
fun setScrollPosition(view: RecyclerView, position: Int, smoothScroll: Boolean) = when { fun setScrollPosition(view: RecyclerView, position: Int, smoothScroll: Boolean) {
smoothScroll -> view.smoothScrollToPosition(position) val adapterItemCount = view.adapter?.itemCount ?: -1
else -> view.scrollToPosition(position) if (position !in 0 until adapterItemCount) {
// the position is not in adapter bounds, adapter will throw exception for invalid positions
return
}
when {
smoothScroll -> view.smoothScrollToPosition(position)
else -> view.scrollToPosition(position)
}
} }
@BindingAdapter("recyclerScrollEvent") @BindingAdapter("recyclerScrollEvent")

View File

@@ -26,7 +26,7 @@ public class DownloadApp {
public static void restore() { public static void restore() {
String name = Utils.INSTANCE.fmt("MagiskManager v%s(%d)", String name = Utils.INSTANCE.fmt("MagiskManager v%s(%d)",
Info.remoteManagerVersionString, Info.remoteManagerVersionCode); Info.remote.getApp().getVersion(), Info.remote.getApp().getVersionCode());
dlInstall(name, new RestoreManager()); dlInstall(name, new RestoreManager());
} }
@@ -34,7 +34,7 @@ public class DownloadApp {
File apk = new File(App.self.getCacheDir(), "manager.apk"); File apk = new File(App.self.getCacheDir(), "manager.apk");
ProgressNotification progress = new ProgressNotification(name); ProgressNotification progress = new ProgressNotification(name);
listener.progress = progress; listener.progress = progress;
Networking.get(Info.managerLink) Networking.get(Info.remote.getApp().getLink())
.setExecutor(App.THREAD_POOL) .setExecutor(App.THREAD_POOL)
.setDownloadProgressListener(progress) .setDownloadProgressListener(progress)
.setErrorHandler((conn, e) -> progress.dlFail()) .setErrorHandler((conn, e) -> progress.dlFail())

View File

@@ -63,11 +63,11 @@ public class Notifications {
public static void managerUpdate() { public static void managerUpdate() {
App app = App.self; App app = App.self;
String name = Utils.INSTANCE.fmt("MagiskManager v%s(%d)", String name = Utils.INSTANCE.fmt("MagiskManager v%s(%d)",
Info.remoteManagerVersionString, Info.remoteManagerVersionCode); Info.remote.getApp().getVersion(), Info.remote.getApp().getVersionCode());
Intent intent = new Intent(app, ClassMap.get(GeneralReceiver.class)); Intent intent = new Intent(app, ClassMap.get(GeneralReceiver.class));
intent.setAction(Const.Key.BROADCAST_MANAGER_UPDATE); intent.setAction(Const.Key.BROADCAST_MANAGER_UPDATE);
intent.putExtra(Const.Key.INTENT_SET_LINK, Info.managerLink); intent.putExtra(Const.Key.INTENT_SET_LINK, Info.remote.getApp().getLink());
intent.putExtra(Const.Key.INTENT_SET_NAME, name); intent.putExtra(Const.Key.INTENT_SET_NAME, name);
PendingIntent pendingIntent = PendingIntent.getBroadcast(app, PendingIntent pendingIntent = PendingIntent.getBroadcast(app,
Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT); Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT);

View File

@@ -57,11 +57,11 @@ internal class InstallMethodDialog(activity: MagiskActivity<*, *>, options: List
private fun downloadOnly(activity: MagiskActivity<*, *>) { private fun downloadOnly(activity: MagiskActivity<*, *>) {
activity.withExternalRW { activity.withExternalRW {
onSuccess { onSuccess {
val filename = "Magisk-v${Info.remoteMagiskVersionString}" + val filename = "Magisk-v${Info.remote.magisk.version}" +
"(${Info.remoteMagiskVersionCode}).zip" "(${Info.remote.magisk.versionCode}).zip"
val zip = File(Const.EXTERNAL_PATH, filename) val zip = File(Const.EXTERNAL_PATH, filename)
val progress = ProgressNotification(filename) val progress = ProgressNotification(filename)
Networking.get(Info.magiskLink) Networking.get(Info.remote.magisk.link)
.setDownloadProgressListener(progress) .setDownloadProgressListener(progress)
.setErrorHandler { _, _ -> progress.dlFail() } .setErrorHandler { _, _ -> progress.dlFail() }
.getAsFile(zip) { .getAsFile(zip) {

View File

@@ -1,7 +1,6 @@
package com.topjohnwu.magisk.view.dialogs package com.topjohnwu.magisk.view.dialogs
import android.net.Uri import android.net.Uri
import android.text.TextUtils
import com.topjohnwu.magisk.Info import com.topjohnwu.magisk.Info
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.ui.base.MagiskActivity import com.topjohnwu.magisk.ui.base.MagiskActivity
@@ -13,8 +12,8 @@ import java.util.*
class MagiskInstallDialog(a: MagiskActivity<*, *>) : CustomAlertDialog(a) { class MagiskInstallDialog(a: MagiskActivity<*, *>) : CustomAlertDialog(a) {
init { init {
val filename = "Magisk v${Info.remoteMagiskVersionString}" + val filename = "Magisk v${Info.remote.magisk.version}" +
"(${Info.remoteMagiskVersionCode})" "(${Info.remote.magisk.versionCode})"
setTitle(a.getString(R.string.repo_install_title, a.getString(R.string.magisk))) setTitle(a.getString(R.string.repo_install_title, a.getString(R.string.magisk)))
setMessage(a.getString(R.string.repo_install_msg, filename)) setMessage(a.getString(R.string.repo_install_msg, filename))
setCancelable(true) setCancelable(true)
@@ -31,13 +30,13 @@ class MagiskInstallDialog(a: MagiskActivity<*, *>) : CustomAlertDialog(a) {
} }
InstallMethodDialog(a, options).show() InstallMethodDialog(a, options).show()
} }
if (!TextUtils.isEmpty(Info.magiskNoteLink)) { if (Info.remote.magisk.note.isNotEmpty()) {
setNeutralButton(R.string.release_notes) { _, _ -> setNeutralButton(R.string.release_notes) { _, _ ->
if (Info.magiskNoteLink.contains("forum.xda-developers")) { if (Info.remote.magisk.note.contains("forum.xda-developers")) {
// Open forum links in browser // Open forum links in browser
Utils.openLink(a, Uri.parse(Info.magiskNoteLink)) Utils.openLink(a, Uri.parse(Info.remote.magisk.note))
} else { } else {
MarkDownWindow.show(a, null, Info.magiskNoteLink) MarkDownWindow.show(a, null, Info.remote.magisk.note)
} }
} }
} }

View File

@@ -9,15 +9,15 @@ import com.topjohnwu.magisk.view.MarkDownWindow
class ManagerInstallDialog(a: Activity) : CustomAlertDialog(a) { class ManagerInstallDialog(a: Activity) : CustomAlertDialog(a) {
init { init {
val name = "MagiskManager v${Info.remoteManagerVersionString}" + val name = "MagiskManager v${Info.remote.app.version}" +
"(${Info.remoteManagerVersionCode})" "(${Info.remote.app.versionCode})"
setTitle(a.getString(R.string.repo_install_title, a.getString(R.string.app_name))) setTitle(a.getString(R.string.repo_install_title, a.getString(R.string.app_name)))
setMessage(a.getString(R.string.repo_install_msg, name)) setMessage(a.getString(R.string.repo_install_msg, name))
setCancelable(true) setCancelable(true)
setPositiveButton(R.string.install) { _, _ -> DownloadApp.upgrade(name) } setPositiveButton(R.string.install) { _, _ -> DownloadApp.upgrade(name) }
if (Info.managerNoteLink.isNotEmpty()) { if (Info.remote.app.note.isNotEmpty()) {
setNeutralButton(R.string.app_changelog) { _, _ -> setNeutralButton(R.string.app_changelog) { _, _ ->
MarkDownWindow.show(a, null, Info.managerNoteLink) } MarkDownWindow.show(a, null, Info.remote.app.note) }
} }
} }
} }

View File

@@ -4,9 +4,7 @@ import android.app.Activity
import android.app.ProgressDialog import android.app.ProgressDialog
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.text.TextUtils
import android.widget.Toast import android.widget.Toast
import com.topjohnwu.magisk.ClassMap import com.topjohnwu.magisk.ClassMap
import com.topjohnwu.magisk.Const import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.Info import com.topjohnwu.magisk.Info
@@ -16,7 +14,6 @@ import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.view.ProgressNotification import com.topjohnwu.magisk.view.ProgressNotification
import com.topjohnwu.net.Networking import com.topjohnwu.net.Networking
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import java.io.File import java.io.File
class UninstallDialog(activity: Activity) : CustomAlertDialog(activity) { class UninstallDialog(activity: Activity) : CustomAlertDialog(activity) {
@@ -37,11 +34,11 @@ class UninstallDialog(activity: Activity) : CustomAlertDialog(activity) {
} }
} }
} }
if (!TextUtils.isEmpty(Info.uninstallerLink)) { if (Info.remote.uninstaller.link.isNotEmpty()) {
setPositiveButton(R.string.complete_uninstall) { d, i -> setPositiveButton(R.string.complete_uninstall) { d, i ->
val zip = File(activity.filesDir, "uninstaller.zip") val zip = File(activity.filesDir, "uninstaller.zip")
val progress = ProgressNotification(zip.name) val progress = ProgressNotification(zip.name)
Networking.get(Info.uninstallerLink) Networking.get(Info.remote.uninstaller.link)
.setDownloadProgressListener(progress) .setDownloadProgressListener(progress)
.setErrorHandler { _, _ -> progress.dlFail() } .setErrorHandler { _, _ -> progress.dlFail() }
.getAsFile(zip) { f -> .getAsFile(zip) { f ->

View File

@@ -38,7 +38,7 @@
</HorizontalScrollView> </HorizontalScrollView>
<com.google.android.material.floatingactionbutton.FloatingActionButton <com.google.android.material.floatingactionbutton.FloatingActionButton
hide="@{viewModel.scrollPosition == item.items.size - 1}" hide="@{viewModel.scrollPosition == item.items.size - 1 || item.items.size == 0}"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="bottom|end" android:layout_gravity="bottom|end"

View File

@@ -1,4 +1,4 @@
# v7.3.0 # v7.3.1
- **HUGE** code base modernization, thanks @diareuse! - Fix blank Superuser fragment under some circumstances
- Reboot device using proper API (no more abrupt reboot) - Fix incomplete repo database bug: if you experience this issue from the old version, go to Settings → Clear Repo Cache and refresh the Download fragment
- New floating button in Magisk logs to go to bottom - Fix crashing when pressing fast scrolling button when logs are empty

View File

@@ -5,6 +5,7 @@
#include <utils.h> #include <utils.h>
#include <logging.h> #include <logging.h>
#include <selinux.h>
#include "init.h" #include "init.h"
@@ -73,17 +74,17 @@ static void setup_block(const char *partname, char *block_dev) {
} }
} }
bool MagiskInit::read_dt_fstab(const char *name, char *partname, char *fstype) { bool BaseInit::read_dt_fstab(const char *name, char *partname, char *fstype) {
char path[128]; char path[128];
int fd; int fd;
sprintf(path, "%s/fstab/%s/dev", cmd.dt_dir, name); sprintf(path, "%s/fstab/%s/dev", cmd->dt_dir, name);
if ((fd = xopen(path, O_RDONLY | O_CLOEXEC)) >= 0) { if ((fd = xopen(path, O_RDONLY | O_CLOEXEC)) >= 0) {
read(fd, path, sizeof(path)); read(fd, path, sizeof(path));
close(fd); close(fd);
// Some custom treble use different names, so use what we read // Some custom treble use different names, so use what we read
char *part = rtrim(strrchr(path, '/') + 1); char *part = rtrim(strrchr(path, '/') + 1);
sprintf(partname, "%s%s", part, strend(part, cmd.slot) ? cmd.slot : ""); sprintf(partname, "%s%s", part, strend(part, cmd->slot) ? cmd->slot : "");
sprintf(path, "%s/fstab/%s/type", cmd.dt_dir, name); sprintf(path, "%s/fstab/%s/type", cmd->dt_dir, name);
if ((fd = xopen(path, O_RDONLY | O_CLOEXEC)) >= 0) { if ((fd = xopen(path, O_RDONLY | O_CLOEXEC)) >= 0) {
read(fd, fstype, 32); read(fd, fstype, 32);
close(fd); close(fd);
@@ -106,38 +107,57 @@ if (!is_lnk("/" #name) && read_dt_fstab(#name, partname, fstype)) { \
mnt_##name = true; \ mnt_##name = true; \
} }
void MagiskInit::early_mount() { void LegacyInit::early_mount() {
char partname[32]; char partname[32];
char fstype[32]; char fstype[32];
char block_dev[64]; char block_dev[64];
if (cmd.system_as_root) { mount_root(system);
LOGD("Early mount system_root\n");
sprintf(partname, "system%s", cmd.slot);
setup_block(partname, block_dev);
xmkdir("/system_root", 0755);
if (xmount(block_dev, "/system_root", "ext4", MS_RDONLY, nullptr))
xmount(block_dev, "/system_root", "erofs", MS_RDONLY, nullptr);
xmkdir("/system", 0755);
xmount("/system_root/system", "/system", nullptr, MS_BIND, nullptr);
// Android Q
if (is_lnk("/system_root/init"))
load_sepol = true;
// System-as-root with monolithic sepolicy
if (access("/system_root/sepolicy", F_OK) == 0)
cp_afc("/system_root/sepolicy", "/sepolicy");
// Copy if these partitions are symlinks
link_root("/vendor");
link_root("/product");
link_root("/odm");
} else {
mount_root(system);
}
mount_root(vendor); mount_root(vendor);
mount_root(product); mount_root(product);
mount_root(odm); mount_root(odm);
} }
void SARInit::early_mount() {
char partname[32];
char fstype[32];
char block_dev[64];
LOGD("Early mount system_root\n");
sprintf(partname, "system%s", cmd->slot);
setup_block(partname, block_dev);
xmkdir("/system_root", 0755);
if (xmount(block_dev, "/system_root", "ext4", MS_RDONLY, nullptr))
xmount(block_dev, "/system_root", "erofs", MS_RDONLY, nullptr);
xmkdir("/system", 0755);
xmount("/system_root/system", "/system", nullptr, MS_BIND, nullptr);
// Android Q
if (is_lnk("/system_root/init"))
load_sepol = true;
// System-as-root with monolithic sepolicy
if (access("/system_root/sepolicy", F_OK) == 0)
cp_afc("/system_root/sepolicy", "/sepolicy");
link_root("/vendor");
link_root("/product");
link_root("/odm");
mount_root(vendor);
mount_root(product);
mount_root(odm);
}
#define umount_root(name) \
if (mnt_##name) \
umount("/" #name);
void BaseInit::cleanup() {
umount(SELINUX_MNT);
umount("/sys");
umount("/proc");
umount_root(system);
umount_root(vendor);
umount_root(product);
umount_root(odm);
}

View File

@@ -92,7 +92,7 @@ static bool check_key_combo() {
return false; return false;
} }
void MagiskInit::load_kernel_info() { void load_kernel_info(cmdline *cmd) {
// Communicate with kernel using procfs and sysfs // Communicate with kernel using procfs and sysfs
xmkdir("/proc", 0755); xmkdir("/proc", 0755);
xmount("proc", "/proc", "proc", 0, nullptr); xmount("proc", "/proc", "proc", 0, nullptr);
@@ -106,14 +106,14 @@ void MagiskInit::load_kernel_info() {
parse_cmdline([&](auto key, auto value) -> void { parse_cmdline([&](auto key, auto value) -> void {
LOGD("cmdline: [%s]=[%s]\n", key.data(), value); LOGD("cmdline: [%s]=[%s]\n", key.data(), value);
if (key == "androidboot.slot_suffix") { if (key == "androidboot.slot_suffix") {
strcpy(cmd.slot, value); strcpy(cmd->slot, value);
} else if (key == "androidboot.slot") { } else if (key == "androidboot.slot") {
cmd.slot[0] = '_'; cmd->slot[0] = '_';
strcpy(cmd.slot + 1, value); strcpy(cmd->slot + 1, value);
} else if (key == "skip_initramfs") { } else if (key == "skip_initramfs") {
cmd.system_as_root = true; cmd->system_as_root = true;
} else if (key == "androidboot.android_dt_dir") { } else if (key == "androidboot.android_dt_dir") {
strcpy(cmd.dt_dir, value); strcpy(cmd->dt_dir, value);
} else if (key == "enter_recovery") { } else if (key == "enter_recovery") {
enter_recovery = value[0] == '1'; enter_recovery = value[0] == '1';
} else if (key == "androidboot.hardware") { } else if (key == "androidboot.hardware") {
@@ -140,13 +140,13 @@ void MagiskInit::load_kernel_info() {
if (recovery_mode) { if (recovery_mode) {
LOGD("Running in recovery mode, waiting for key...\n"); LOGD("Running in recovery mode, waiting for key...\n");
cmd.system_as_root = !check_key_combo(); cmd->system_as_root = !check_key_combo();
} }
if (cmd.dt_dir[0] == '\0') if (cmd->dt_dir[0] == '\0')
strcpy(cmd.dt_dir, DEFAULT_DT_DIR); strcpy(cmd->dt_dir, DEFAULT_DT_DIR);
LOGD("system_as_root=[%d]\n", cmd.system_as_root); LOGD("system_as_root=[%d]\n", cmd->system_as_root);
LOGD("slot=[%s]\n", cmd.slot); LOGD("slot=[%s]\n", cmd->slot);
LOGD("dt_dir=[%s]\n", cmd.dt_dir); LOGD("dt_dir=[%s]\n", cmd->dt_dir);
} }

View File

@@ -6,13 +6,11 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <dirent.h>
#include <fcntl.h> #include <fcntl.h>
#include <libgen.h> #include <libgen.h>
#include <xz.h> #include <xz.h>
#include <magisk.h> #include <magisk.h>
#include <selinux.h>
#include <cpio.h> #include <cpio.h>
#include <utils.h> #include <utils.h>
#include <flags.h> #include <flags.h>
@@ -48,12 +46,10 @@ static void setup_klog() {
#define setup_klog(...) #define setup_klog(...)
#endif #endif
static int test_main(int argc, char *argv[]);
constexpr const char *init_applet[] = constexpr const char *init_applet[] =
{ "magiskpolicy", "supolicy", "init_test", nullptr }; { "magiskpolicy", "supolicy", nullptr };
constexpr int (*init_applet_main[])(int, char *[]) = constexpr int (*init_applet_main[])(int, char *[]) =
{ magiskpolicy_main, magiskpolicy_main, test_main, nullptr }; { magiskpolicy_main, magiskpolicy_main, nullptr };
static bool unxz(int fd, const uint8_t *buf, size_t size) { static bool unxz(int fd, const uint8_t *buf, size_t size) {
uint8_t out[8192]; uint8_t out[8192];
@@ -117,50 +113,27 @@ static int dump_manager(const char *path, mode_t mode) {
return 0; return 0;
} }
void MagiskInit::preset() { void BaseInit::re_exec_init() {
root = open("/", O_RDONLY | O_CLOEXEC);
if (cmd.system_as_root) {
// Clear rootfs
LOGD("Cleaning rootfs\n");
frm_rf(root, { "overlay", "proc", "sys" });
} else {
decompress_ramdisk();
// Revert original init binary
rename("/.backup/init", "/init");
rm_rf("/.backup");
// Do not go further if device is booting into recovery
if (access("/sbin/recovery", F_OK) == 0) {
LOGD("Ramdisk is recovery, abort\n");
re_exec_init();
}
}
}
#define umount_root(name) \
if (mnt_##name) \
umount("/" #name);
void MagiskInit::cleanup() {
umount(SELINUX_MNT);
umount("/sys");
umount("/proc");
umount_root(system);
umount_root(vendor);
umount_root(product);
umount_root(odm);
}
void MagiskInit::re_exec_init() {
LOGD("Re-exec /init\n"); LOGD("Re-exec /init\n");
cleanup(); cleanup();
execv("/init", argv); execv("/init", argv);
exit(1); exit(1);
} }
void MagiskInit::start() { void LegacyInit::preset() {
LOGD("Reverting /init\n");
root = open("/", O_RDONLY | O_CLOEXEC);
rename("/.backup/init", "/init");
rm_rf("/.backup");
}
void SARInit::preset() {
LOGD("Cleaning rootfs\n");
root = open("/", O_RDONLY | O_CLOEXEC);
frm_rf(root, { "overlay", "proc", "sys" });
}
void BaseInit::start() {
// Prevent file descriptor confusion // Prevent file descriptor confusion
mknod("/null", S_IFCHR | 0666, makedev(1, 3)); mknod("/null", S_IFCHR | 0666, makedev(1, 3));
int null = open("/null", O_RDWR | O_CLOEXEC); int null = open("/null", O_RDWR | O_CLOEXEC);
@@ -171,10 +144,6 @@ void MagiskInit::start() {
if (null > STDERR_FILENO) if (null > STDERR_FILENO)
close(null); close(null);
setup_klog();
load_kernel_info();
full_read("/init", &self.buf, &self.sz); full_read("/init", &self.buf, &self.sz);
full_read("/.backup/.magisk", &config.buf, &config.sz); full_read("/.backup/.magisk", &config.buf, &config.sz);
@@ -184,26 +153,27 @@ void MagiskInit::start() {
re_exec_init(); re_exec_init();
} }
void MagiskInit::test() { class RecoveryInit : public BaseInit {
cmdline_logging(); public:
log_cb.ex = nop_ex; RecoveryInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {};
void start() override {
LOGD("Ramdisk is recovery, abort\n");
rename("/.backup/init", "/init");
rm_rf("/.backup");
re_exec_init();
}
};
chdir(dirname(argv[0])); class TestInit : public SARInit {
chroot("."); public:
chdir("/"); TestInit(char *argv[], cmdline *cmd) : SARInit(argv, cmd) {};
void start() override {
load_kernel_info(); preset();
preset(); early_mount();
early_mount(); setup_rootfs();
setup_rootfs(); cleanup();
cleanup(); }
} };
static int test_main(int, char *argv[]) {
MagiskInit init(argv);
init.test();
return 0;
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
umask(0); umask(0);
@@ -220,11 +190,40 @@ int main(int argc, char *argv[]) {
return dump_manager(argv[3], 0644); return dump_manager(argv[3], 0644);
} }
if (getpid() != 1) #ifdef MAGISK_DEBUG
return 1; bool run_test = getenv("INIT_TEST") != nullptr;
#else
constexpr bool run_test = false;
#endif
MagiskInit init(argv); if (run_test) {
chdir(dirname(argv[0]));
chroot(".");
chdir("/");
cmdline_logging();
log_cb.ex = nop_ex;
} else {
if (getpid() != 1)
return 1;
setup_klog();
}
cmdline cmd{};
load_kernel_info(&cmd);
unique_ptr<BaseInit> init;
if (run_test) {
init = make_unique<TestInit>(argv, &cmd);
} else if (cmd.system_as_root) {
init = make_unique<SARInit>(argv, &cmd);
} else {
decompress_ramdisk();
if (access("/sbin/recovery", F_OK) == 0)
init = make_unique<RecoveryInit>(argv, &cmd);
else
init = make_unique<LegacyInit>(argv, &cmd);
}
// Run the main routine // Run the main routine
init.start(); init->start();
} }

View File

@@ -11,22 +11,21 @@ struct raw_data {
size_t sz; size_t sz;
}; };
class MagiskInit { class BaseInit {
private: protected:
cmdline cmd{}; cmdline *cmd;
raw_data self{}; raw_data self{};
raw_data config{}; raw_data config{};
int root = -1;
char **argv; char **argv;
int root = -1;
bool load_sepol = false; bool load_sepol = false;
bool mnt_system = false; bool mnt_system = false;
bool mnt_vendor = false; bool mnt_vendor = false;
bool mnt_product = false; bool mnt_product = false;
bool mnt_odm = false; bool mnt_odm = false;
void load_kernel_info(); virtual void preset() {};
void preset(); virtual void early_mount() {}
void early_mount();
void setup_rootfs(); void setup_rootfs();
bool read_dt_fstab(const char *name, char *partname, char *fstype); bool read_dt_fstab(const char *name, char *partname, char *fstype);
bool patch_sepolicy(); bool patch_sepolicy();
@@ -34,9 +33,25 @@ private:
void re_exec_init(); void re_exec_init();
public: public:
explicit MagiskInit(char *argv[]) : argv(argv) {} BaseInit(char *argv[], cmdline *cmd) : cmd(cmd), argv(argv) {}
void start(); virtual ~BaseInit() = default;
void test(); virtual void start();
};
class LegacyInit : public BaseInit {
protected:
void preset() override;
void early_mount() override;
public:
LegacyInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {};
};
class SARInit : public BaseInit {
protected:
void preset() override;
void early_mount() override;
public:
SARInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {};
}; };
static inline bool is_lnk(const char *name) { static inline bool is_lnk(const char *name) {
@@ -46,4 +61,5 @@ static inline bool is_lnk(const char *name) {
return S_ISLNK(st.st_mode); return S_ISLNK(st.st_mode);
} }
void load_kernel_info(cmdline *cmd);
int dump_magisk(const char *path, mode_t mode); int dump_magisk(const char *path, mode_t mode);

View File

@@ -37,10 +37,10 @@ constexpr const char wrapper[] =
"exec /sbin/magisk.bin \"$0\" \"$@\"\n" "exec /sbin/magisk.bin \"$0\" \"$@\"\n"
; ;
void MagiskInit::setup_rootfs() { void BaseInit::setup_rootfs() {
bool patch_init = patch_sepolicy(); bool patch_init = patch_sepolicy();
if (cmd.system_as_root) { if (cmd->system_as_root) {
// Clone rootfs // Clone rootfs
LOGD("Clone root dir from system to rootfs\n"); LOGD("Clone root dir from system to rootfs\n");
int system_root = xopen("/system_root", O_RDONLY | O_CLOEXEC); int system_root = xopen("/system_root", O_RDONLY | O_CLOEXEC);
@@ -173,7 +173,7 @@ void MagiskInit::setup_rootfs() {
close(sbin); close(sbin);
} }
bool MagiskInit::patch_sepolicy() { bool BaseInit::patch_sepolicy() {
bool patch_init = false; bool patch_init = false;
if (access(SPLIT_PLAT_CIL, R_OK) == 0) { if (access(SPLIT_PLAT_CIL, R_OK) == 0) {

View File

@@ -12,6 +12,8 @@
#include "magiskboot.h" #include "magiskboot.h"
#include "compress.h" #include "compress.h"
using namespace std;
static void usage(char *arg0) { static void usage(char *arg0) {
fprintf(stderr, fprintf(stderr,
FULL_VER(MagiskBoot) " - Boot Image Modification Tool\n" FULL_VER(MagiskBoot) " - Boot Image Modification Tool\n"
@@ -114,10 +116,11 @@ int main(int argc, char *argv[]) {
usage(argv[0]); usage(argv[0]);
// Skip '--' for backwards compatibility // Skip '--' for backwards compatibility
if (strncmp(argv[1], "--", 2) == 0) string_view action(argv[1]);
argv[1] += 2; if (str_starts(action, "--"))
action = argv[1] + 2;
if (strcmp(argv[1], "cleanup") == 0) { if (action == "cleanup") {
fprintf(stderr, "Cleaning up...\n"); fprintf(stderr, "Cleaning up...\n");
unlink(HEADER_FILE); unlink(HEADER_FILE);
unlink(KERNEL_FILE); unlink(KERNEL_FILE);
@@ -127,7 +130,7 @@ int main(int argc, char *argv[]) {
unlink(EXTRA_FILE); unlink(EXTRA_FILE);
unlink(RECV_DTBO_FILE); unlink(RECV_DTBO_FILE);
unlink(DTB_FILE); unlink(DTB_FILE);
} else if (argc > 2 && strcmp(argv[1], "sha1") == 0) { } else if (argc > 2 && action == "sha1") {
uint8_t sha1[SHA_DIGEST_SIZE]; uint8_t sha1[SHA_DIGEST_SIZE];
void *buf; void *buf;
size_t size; size_t size;
@@ -137,34 +140,35 @@ int main(int argc, char *argv[]) {
printf("%02x", i); printf("%02x", i);
printf("\n"); printf("\n");
munmap(buf, size); munmap(buf, size);
} else if (argc > 2 && strcmp(argv[1], "unpack") == 0) { } else if (argc > 2 && action == "unpack") {
if (strcmp(argv[2], "-h") == 0) { if (argv[2] == "-h"sv) {
if (argc == 3) if (argc == 3)
usage(argv[0]); usage(argv[0]);
return unpack(argv[3], true); return unpack(argv[3], true);
} else { } else {
return unpack(argv[2]); return unpack(argv[2]);
} }
} else if (argc > 2 && strcmp(argv[1], "repack") == 0) { } else if (argc > 2 && action == "repack") {
if (strcmp(argv[2], "-n") == 0) { if (argv[2] == "-n"sv) {
if (argc == 4) if (argc == 3)
usage(argv[0]); usage(argv[0]);
repack(argv[3], argv[4] ? argv[4] : NEW_BOOT, true); repack(argv[3], argv[4] ? argv[4] : NEW_BOOT, true);
} else { } else {
repack(argv[2], argv[3] ? argv[3] : NEW_BOOT); repack(argv[2], argv[3] ? argv[3] : NEW_BOOT);
} }
} else if (argc > 2 && strcmp(argv[1], "decompress") == 0) { } else if (argc > 2 && action == "decompress") {
decompress(argv[2], argv[3]); decompress(argv[2], argv[3]);
} else if (argc > 2 && strncmp(argv[1], "compress", 8) == 0) { } else if (argc > 2 && str_starts(action, "compress")) {
compress(argv[1][8] == '=' ? &argv[1][9] : "gzip", argv[2], argv[3]); compress(action[8] == '=' ? &action[9] : "gzip", argv[2], argv[3]);
} else if (argc > 4 && strcmp(argv[1], "hexpatch") == 0) { } else if (argc > 4 && action == "hexpatch") {
return hexpatch(argv[2], argv[3], argv[4]); return hexpatch(argv[2], argv[3], argv[4]);
} else if (argc > 2 && strcmp(argv[1], "cpio") == 0) { } else if (argc > 2 && action == "cpio"sv) {
if (cpio_commands(argc - 2, argv + 2)) usage(argv[0]); if (cpio_commands(argc - 2, argv + 2))
} else if (argc > 2 && strncmp(argv[1], "dtb", 3) == 0) {
if (argv[1][3] != '-')
usage(argv[0]); usage(argv[0]);
if (dtb_commands(&argv[1][4], argc - 2, argv + 2)) } else if (argc > 2 && str_starts(action, "dtb")) {
if (action[3] != '-')
usage(argv[0]);
if (dtb_commands(&action[4], argc - 2, argv + 2))
usage(argv[0]); usage(argv[0]);
} else { } else {
usage(argv[0]); usage(argv[0]);