mirror of
				https://github.com/topjohnwu/Magisk
				synced 2025-10-31 10:40:52 +01:00 
			
		
		
		
	Compare commits
	
		
			239 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | c1602d2554 | ||
|   | 9f8d4e1022 | ||
|   | d1dfda405f | ||
|   | 28efded624 | ||
|   | 06c86ee267 | ||
|   | 5892780871 | ||
|   | 4fcdcd9a8a | ||
|   | 80d834fb55 | ||
|   | 4122ebe18f | ||
|   | 7d87777bf8 | ||
|   | 4a73d634e0 | ||
|   | 373dc10a40 | ||
|   | ed43ec8ea2 | ||
|   | 7918fc3528 | ||
|   | bf58205b0a | ||
|   | c0d1ce96d1 | ||
|   | b31d3802eb | ||
|   | be1228c3b4 | ||
|   | 15c94c6b34 | ||
|   | 202d23426a | ||
|   | fc26de48b2 | ||
|   | 76c88913f9 | ||
|   | a3a1aed723 | ||
|   | 81aa56f60f | ||
|   | 73bb850209 | ||
|   | 8dfec12330 | ||
|   | ae24397793 | ||
|   | 3b0f888407 | ||
|   | 845d1e02b0 | ||
|   | 5d357bc41f | ||
|   | 6a54672b13 | ||
|   | 3d9a15df44 | ||
|   | 449c7fda2f | ||
|   | 8b7b05da68 | ||
|   | 92400ebcab | ||
|   | 23d3e56967 | ||
|   | 6785dc4967 | ||
|   | dad20f6a2d | ||
|   | bb15671046 | ||
|   | 21984fac8b | ||
|   | f392afe87f | ||
|   | 6a243ec7bc | ||
|   | 8cd3b603df | ||
|   | 6e1aefe6d8 | ||
|   | 1c90b6eca3 | ||
|   | c33cf9f878 | ||
|   | 27cb40eec9 | ||
|   | c06081b75d | ||
|   | a7eec2f0a0 | ||
|   | 4fd0fe3194 | ||
|   | cc74593ddd | ||
|   | fdb7c5dba1 | ||
|   | 77470c7cfa | ||
|   | f0a734fdab | ||
|   | 75405b2b25 | ||
|   | 90ed4b3c49 | ||
|   | 290a17a764 | ||
|   | aaabd836e4 | ||
|   | 076e5cea3b | ||
|   | 8515971ccf | ||
|   | d86fb033ea | ||
|   | 99d7d8ddbc | ||
|   | df78fd2d41 | ||
|   | dabe6267b9 | ||
|   | 0119ebddbe | ||
|   | 3216ef9f47 | ||
|   | b79d1bcded | ||
|   | 17e234f9d5 | ||
|   | ea1f75f80e | ||
|   | 8c40db5730 | ||
|   | 6fe03d2795 | ||
|   | c595a87ccf | ||
|   | fac07c3913 | ||
|   | c63fdbbc6b | ||
|   | 2ff5d9606b | ||
|   | ed43452c1a | ||
|   | 8f28d4028f | ||
|   | b54543b18c | ||
|   | 966d6593ca | ||
|   | ad95b1c9d1 | ||
|   | 3bfa38c60a | ||
|   | 0bdbcad8be | ||
|   | 80855e89ec | ||
|   | 0850401dc4 | ||
|   | 337fda2023 | ||
|   | 64f238191e | ||
|   | eb169cb133 | ||
|   | 80cd85b061 | ||
|   | 89275270f3 | ||
|   | e7339ba619 | ||
|   | d9ad7d522c | ||
|   | 92789c3113 | ||
|   | c1c677e161 | ||
|   | 2fe917ff82 | ||
|   | 0e6c205732 | ||
|   | 125ae0a173 | ||
|   | 0245e13591 | ||
|   | d546733287 | ||
|   | c275326d59 | ||
|   | d4561507b8 | ||
|   | ef0e22cc41 | ||
|   | 62db65bf18 | ||
|   | d5371f752c | ||
|   | a5f5e94115 | ||
|   | 2624706c69 | ||
|   | d39d885ec2 | ||
|   | d83c744725 | ||
|   | 843995cdb9 | ||
|   | 9491ba77e0 | ||
|   | 58a449d437 | ||
|   | 7f55e0f05b | ||
|   | 67c3f40adb | ||
|   | ff7a0ba599 | ||
|   | b152c63102 | ||
|   | 415ff23be5 | ||
|   | b0d6de783e | ||
|   | ac28e6e5ca | ||
|   | 4f9e8d2e8a | ||
|   | 21be2f46f3 | ||
|   | a6e7680212 | ||
|   | e79e744e08 | ||
|   | 7abdac72a4 | ||
|   | 90d85eaf7d | ||
|   | e65f9740fb | ||
|   | 7538f89b56 | ||
|   | 7c755a3991 | ||
|   | 10e903c9fc | ||
|   | b018124226 | ||
|   | a9350f50c9 | ||
|   | ed7babcbf1 | ||
|   | 61ebc335c4 | ||
|   | 0167bd76f1 | ||
|   | 79d704008b | ||
|   | 0a703585b0 | ||
|   | 5d632d0d90 | ||
|   | 4eecaea601 | ||
|   | 63055818ec | ||
|   | 0beb08b687 | ||
|   | b27801a27c | ||
|   | a0cfce7cbc | ||
|   | 8b7144c986 | ||
|   | d3f5f5ee59 | ||
|   | a2a3c7f438 | ||
|   | 4496f82d5b | ||
|   | 09d531557d | ||
|   | 7fee82f731 | ||
|   | 475054c48a | ||
|   | a743d05751 | ||
|   | d1ed502e03 | ||
|   | 37744c7ab6 | ||
|   | bbc9e60a12 | ||
|   | 6c975ecc4c | ||
|   | 23e8a4ce4b | ||
|   | 50134a2f9b | ||
|   | 628b37c4fa | ||
|   | 1b4ae70a43 | ||
|   | b25c49725f | ||
|   | b245782c7e | ||
|   | a9f32baae0 | ||
|   | e7ef71865d | ||
|   | 88c4f72b37 | ||
|   | abbcdf91a5 | ||
|   | b876df6e21 | ||
|   | 4bb81f35d7 | ||
|   | ff20267b3f | ||
|   | 2c9586d811 | ||
|   | 2813d2031a | ||
|   | 065051a360 | ||
|   | db218407b0 | ||
|   | d52210dd90 | ||
|   | f3cd9a096a | ||
|   | e426090a18 | ||
|   | cbe64fd559 | ||
|   | 63ea7a70bd | ||
|   | fb0998f7a2 | ||
|   | a9b00dd537 | ||
|   | 52eb059515 | ||
|   | 7640246255 | ||
|   | 52c83b2916 | ||
|   | d9cded0fc9 | ||
|   | 750c42caf1 | ||
|   | bbf650c6cf | ||
|   | a25dace7e0 | ||
|   | 14ff22fbcd | ||
|   | 07eb7dda2d | ||
|   | d4058175b4 | ||
|   | 2de984ae24 | ||
|   | 761a8bf2a9 | ||
|   | 6df7006b36 | ||
|   | aceb3ee863 | ||
|   | 11d716a3c8 | ||
|   | 7cc8c014eb | ||
|   | f21241d944 | ||
|   | a181fa0652 | ||
|   | 3f748b4d2a | ||
|   | 683450f9c6 | ||
|   | adbd47a36c | ||
|   | ce693aa5e9 | ||
|   | ad80804461 | ||
|   | 2d55632430 | ||
|   | e81f00ef1a | ||
|   | 93fb0e3d74 | ||
|   | 71ce0de606 | ||
|   | 0407062c1d | ||
|   | cda14af208 | ||
|   | 258f170cd7 | ||
|   | f76015d714 | ||
|   | 7e5e14163c | ||
|   | bcd1064e94 | ||
|   | 8a8441c875 | ||
|   | 15aa813416 | ||
|   | 605faccffd | ||
|   | 79f2d08c81 | ||
|   | 0568ae5391 | ||
|   | 5330dda9f8 | ||
|   | ebab126579 | ||
|   | 0e5417a13e | ||
|   | 9a968e0584 | ||
|   | ffec64d209 | ||
|   | f332746188 | ||
|   | b2fa5b551e | ||
|   | 36e83edddc | ||
|   | 6b045eadef | ||
|   | 147264822c | ||
|   | 36e4ccd800 | ||
|   | 796c16237d | ||
|   | 861ad9881c | ||
|   | 3101c538e9 | ||
|   | 42adc7382f | ||
|   | 9bb4dfad13 | ||
|   | bd00ae8ede | ||
|   | f309522268 | ||
|   | 0efaddff23 | ||
|   | 94ba7cb0c5 | ||
|   | 2d58c725e0 | ||
|   | e035523eb8 | ||
|   | bea5308ab7 | ||
|   | f006a85fec | ||
|   | ea93013ebc | 
| @@ -1,6 +1,6 @@ | ||||
| apply plugin: 'com.android.application' | ||||
| apply plugin: 'kotlin-android-extensions' | ||||
| apply plugin: 'kotlin-android' | ||||
| apply plugin: 'kotlin-android-extensions' | ||||
| apply plugin: 'kotlin-kapt' | ||||
|  | ||||
| kapt { | ||||
| @@ -16,20 +16,37 @@ android { | ||||
|     defaultConfig { | ||||
|         applicationId 'com.topjohnwu.magisk' | ||||
|         vectorDrawables.useSupportLibrary = true | ||||
|         multiDexEnabled true | ||||
|         versionName configProps['appVersion'] | ||||
|         versionCode configProps['appVersionCode'] as Integer | ||||
|         javaCompileOptions { | ||||
|             annotationProcessorOptions { | ||||
|                 argument('butterknife.debuggable', 'false') | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     buildTypes { | ||||
|         release { | ||||
|             proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' | ||||
|             minifyEnabled true | ||||
|             shrinkResources true | ||||
|             proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), | ||||
|                     'proguard-rules.pro', 'proguard-kotlin.pro' | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     dataBinding { | ||||
|         enabled = true | ||||
|     } | ||||
|  | ||||
|     packagingOptions { | ||||
|         exclude '/META-INF/*.version' | ||||
|         exclude '/META-INF/*.kotlin_module' | ||||
|         exclude '/META-INF/rxkotlin.properties' | ||||
|         exclude '/androidsupportmultidexversion.txt' | ||||
|         exclude '/org/**' | ||||
|         exclude '/kotlin/**' | ||||
|         exclude '/kotlinx/**' | ||||
|     } | ||||
| } | ||||
|  | ||||
| androidExtensions { | ||||
|     experimental = true | ||||
| } | ||||
|  | ||||
| dependencies { | ||||
| @@ -37,30 +54,49 @@ dependencies { | ||||
|     implementation project(':net') | ||||
|     implementation project(':shared') | ||||
|     implementation project(':signing') | ||||
|  | ||||
|     implementation 'com.github.topjohnwu:jtar:1.0.0' | ||||
|     implementation 'net.sourceforge.streamsupport:android-retrostreams:1.7.0' | ||||
|     implementation 'com.github.sevar83:indeterminate-checkbox:1.0.5' | ||||
|     implementation 'com.jakewharton.timber:timber:4.7.1' | ||||
|     implementation 'com.github.skoumalcz:teanity:0.3.3' | ||||
|     implementation 'com.ncapdevi:frag-nav:3.2.0' | ||||
|  | ||||
|     def markwonVersion = '3.0.0' | ||||
|     implementation "ru.noties.markwon:core:${markwonVersion}" | ||||
|     implementation "ru.noties.markwon:html:${markwonVersion}" | ||||
|     implementation "ru.noties.markwon:image-svg:${markwonVersion}" | ||||
|     def vMarkwon = '3.0.1' | ||||
|     implementation "ru.noties.markwon:core:${vMarkwon}" | ||||
|     implementation "ru.noties.markwon:html:${vMarkwon}" | ||||
|     implementation "ru.noties.markwon:image-svg:${vMarkwon}" | ||||
|  | ||||
|     def vLibsu = '2.5.0' | ||||
|     implementation "com.github.topjohnwu.libsu:core:${vLibsu}" | ||||
|     implementation "com.github.topjohnwu.libsu:io:${vLibsu}" | ||||
|  | ||||
|     def vKoin = "2.0.1" | ||||
|     implementation "org.koin:koin-core:${vKoin}" | ||||
|     implementation "org.koin:koin-android:${vKoin}" | ||||
|     implementation "org.koin:koin-androidx-viewmodel:${vKoin}" | ||||
|  | ||||
|     def vRetrofit = "2.5.0" | ||||
|     implementation "com.squareup.retrofit2:retrofit:${vRetrofit}" | ||||
|     implementation "com.squareup.retrofit2:converter-moshi:${vRetrofit}" | ||||
|     implementation "com.squareup.retrofit2:adapter-rxjava2:${vRetrofit}" | ||||
|  | ||||
|     def vOkHttp = "3.12.0" | ||||
|     implementation "com.squareup.okhttp3:okhttp:${vOkHttp}" | ||||
|     implementation "com.squareup.okhttp3:logging-interceptor:${vOkHttp}" | ||||
|  | ||||
|     def vMoshi = "1.8.0" | ||||
|     implementation "com.squareup.moshi:moshi:${vMoshi}" | ||||
|  | ||||
|     def vKotshi = "2.0.1" | ||||
|     implementation "se.ansman.kotshi:api:${vKotshi}" | ||||
|     kapt "se.ansman.kotshi:compiler:${vKotshi}" | ||||
|  | ||||
|     def androidXVersion = "1.0.0" | ||||
|     implementation 'androidx.constraintlayout:constraintlayout:1.1.3' | ||||
|     implementation 'androidx.appcompat:appcompat:1.0.2' | ||||
|     implementation "androidx.preference:preference:${androidXVersion}" | ||||
|     implementation "androidx.recyclerview:recyclerview:${androidXVersion}" | ||||
|     implementation "androidx.cardview:cardview:${androidXVersion}" | ||||
|     implementation "com.google.android.material:material:${androidXVersion}" | ||||
|     implementation 'androidx.browser:browser:1.0.0' | ||||
|     implementation 'androidx.preference:preference:1.0.0' | ||||
|     implementation 'androidx.recyclerview:recyclerview:1.1.0-alpha05' | ||||
|     implementation 'androidx.cardview:cardview:1.0.0' | ||||
|     implementation 'androidx.work:work-runtime:2.0.1' | ||||
|     implementation 'androidx.transition:transition:1.1.0-beta01' | ||||
|  | ||||
|     def libsuVersion = '2.5.0' | ||||
|     implementation "com.github.topjohnwu.libsu:core:${libsuVersion}" | ||||
|     implementation "com.github.topjohnwu.libsu:io:${libsuVersion}" | ||||
|  | ||||
|     def butterKnifeVersion = '10.1.0' | ||||
|     implementation "com.jakewharton:butterknife-runtime:${butterKnifeVersion}" | ||||
|     kapt "com.jakewharton:butterknife-compiler:${butterKnifeVersion}" | ||||
|     implementation 'androidx.transition:transition:1.2.0-alpha01' | ||||
|     implementation 'androidx.multidex:multidex:2.0.1' | ||||
|     implementation 'com.google.android.material:material:1.1.0-alpha06' | ||||
| } | ||||
|   | ||||
							
								
								
									
										20
									
								
								app/proguard-kotlin.pro
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								app/proguard-kotlin.pro
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| ## So every class is case insensitive to avoid some bizare problems | ||||
| -dontusemixedcaseclassnames | ||||
|  | ||||
| ## If reflection issues come up uncomment this, that should temporarily fix it | ||||
| #-keep class kotlin.** { *; } | ||||
| #-keep class kotlin.Metadata { *; } | ||||
| #-keepclassmembers class kotlin.Metadata { | ||||
| #    public <methods>; | ||||
| #} | ||||
|  | ||||
| ## Never warn about Kotlin, it should work as-is | ||||
| -dontwarn kotlin.** | ||||
|  | ||||
| ## Removes runtime null checks - doesn't really matter if it crashes on kotlin or java NPE | ||||
| -assumenosideeffects class kotlin.jvm.internal.Intrinsics { | ||||
|     static void checkParameterIsNotNull(java.lang.Object, java.lang.String); | ||||
| } | ||||
|  | ||||
| ## Useless option for dex | ||||
| -dontpreverify | ||||
							
								
								
									
										19
									
								
								app/proguard-rules.pro
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								app/proguard-rules.pro
									
									
									
									
										vendored
									
									
								
							| @@ -16,11 +16,8 @@ | ||||
| #   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.** | ||||
| # Retrofit classes | ||||
| -keep,allowobfuscation class com.topjohnwu.magisk.data.network.* | ||||
|  | ||||
| # Snet | ||||
| -keepclassmembers class com.topjohnwu.magisk.utils.ISafetyNetHelper { *; } | ||||
| @@ -29,19 +26,19 @@ | ||||
|   void onResponse(int); | ||||
| } | ||||
|  | ||||
| # Keep all fragment constructors | ||||
| -keepclassmembers class * extends androidx.fragment.app.Fragment { | ||||
|   public <init>(...); | ||||
| } | ||||
|  | ||||
| # DelegateWorker | ||||
| -keep,allowobfuscation class * extends com.topjohnwu.magisk.model.worker.DelegateWorker | ||||
|  | ||||
| # BootSigner | ||||
| -keepclassmembers class com.topjohnwu.signing.BootSigner { *; } | ||||
|  | ||||
| # SVG | ||||
| -dontwarn com.caverock.androidsvg.SVGAndroidRenderer | ||||
|  | ||||
| # RetroStreams | ||||
| -dontwarn java9.** | ||||
|  | ||||
| # Strip logging | ||||
| -assumenosideeffects class timber.log.Timber.Tree { *; } | ||||
| -assumenosideeffects class com.topjohnwu.magisk.utils.Logger { | ||||
|   public *** debug(...); | ||||
| } | ||||
|   | ||||
| @@ -11,7 +11,7 @@ | ||||
|     <application | ||||
|         android:allowBackup="true" | ||||
|         android:name="a.e" | ||||
|         android:theme="@style/AppTheme" | ||||
|         android:theme="@style/MagiskTheme" | ||||
|         android:usesCleartextTraffic="true" | ||||
|         tools:ignore="UnusedAttribute,GoogleAppIndexingWarning"> | ||||
|  | ||||
| @@ -35,7 +35,7 @@ | ||||
|             android:name="a.f" | ||||
|             android:configChanges="keyboardHidden|orientation|screenSize" | ||||
|             android:screenOrientation="nosensor" | ||||
|             android:theme="@style/AppTheme.NoDrawer" /> | ||||
|             android:theme="@style/MagiskTheme.Flashing" /> | ||||
|  | ||||
|         <!-- Superuser --> | ||||
|  | ||||
| @@ -44,7 +44,7 @@ | ||||
|             android:exported="false" | ||||
|             android:directBootAware="true" | ||||
|             android:excludeFromRecents="true" | ||||
|             android:theme="@style/SuRequest" /> | ||||
|             android:theme="@style/MagiskTheme.SU" /> | ||||
|  | ||||
|         <!-- Receiver --> | ||||
|  | ||||
| @@ -74,4 +74,4 @@ | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
| </manifest> | ||||
|   | ||||
| @@ -1,101 +0,0 @@ | ||||
| package com.topjohnwu.magisk; | ||||
|  | ||||
| import android.app.Activity; | ||||
| import android.app.Application; | ||||
| import android.content.Context; | ||||
| import android.content.SharedPreferences; | ||||
| import android.content.res.Configuration; | ||||
| import android.os.AsyncTask; | ||||
| import android.os.Build; | ||||
| import android.os.Bundle; | ||||
| import android.preference.PreferenceManager; | ||||
|  | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.appcompat.app.AppCompatDelegate; | ||||
|  | ||||
| import com.topjohnwu.magisk.data.database.MagiskDB; | ||||
| import com.topjohnwu.magisk.data.database.RepoDatabaseHelper; | ||||
| import com.topjohnwu.magisk.ui.base.BaseActivity; | ||||
| import com.topjohnwu.magisk.utils.LocaleManager; | ||||
| import com.topjohnwu.magisk.utils.RootUtils; | ||||
| import com.topjohnwu.net.Networking; | ||||
| import com.topjohnwu.superuser.Shell; | ||||
|  | ||||
| import java.util.concurrent.ThreadPoolExecutor; | ||||
|  | ||||
| public class App extends Application implements Application.ActivityLifecycleCallbacks { | ||||
|  | ||||
|     public static App self; | ||||
|     public static Context deContext; | ||||
|     public static ThreadPoolExecutor THREAD_POOL; | ||||
|  | ||||
|     // Global resources | ||||
|     public SharedPreferences prefs; | ||||
|     public MagiskDB mDB; | ||||
|     public RepoDatabaseHelper repoDB; | ||||
|     private volatile BaseActivity foreground; | ||||
|  | ||||
|     static { | ||||
|         AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); | ||||
|         Shell.Config.setFlags(Shell.FLAG_MOUNT_MASTER | Shell.FLAG_USE_MAGISK_BUSYBOX); | ||||
|         Shell.Config.verboseLogging(BuildConfig.DEBUG); | ||||
|         Shell.Config.addInitializers(RootUtils.class); | ||||
|         Shell.Config.setTimeout(2); | ||||
|         THREAD_POOL = (ThreadPoolExecutor) AsyncTask.THREAD_POOL_EXECUTOR; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void attachBaseContext(Context base) { | ||||
|         super.attachBaseContext(base); | ||||
|         self = this; | ||||
|         deContext = base; | ||||
|         registerActivityLifecycleCallbacks(this); | ||||
|  | ||||
|         if (Build.VERSION.SDK_INT >= 24) { | ||||
|             deContext = base.createDeviceProtectedStorageContext(); | ||||
|             deContext.moveSharedPreferencesFrom(base, | ||||
|                     PreferenceManager.getDefaultSharedPreferencesName(base)); | ||||
|         } | ||||
|         prefs = PreferenceManager.getDefaultSharedPreferences(deContext); | ||||
|         mDB = new MagiskDB(base); | ||||
|  | ||||
|         Networking.init(base); | ||||
|         LocaleManager.setLocale(this); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onConfigurationChanged(@NonNull Configuration newConfig) { | ||||
|         super.onConfigurationChanged(newConfig); | ||||
|         LocaleManager.setLocale(this); | ||||
|     } | ||||
|  | ||||
|     public static BaseActivity foreground() { | ||||
|         return self.foreground; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle bundle) {} | ||||
|  | ||||
|     @Override | ||||
|     public void onActivityStarted(@NonNull Activity activity) {} | ||||
|  | ||||
|     @Override | ||||
|     public synchronized void onActivityResumed(@NonNull Activity activity) { | ||||
|         foreground = (BaseActivity) activity; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public synchronized void onActivityPaused(@NonNull Activity activity) { | ||||
|         foreground = null; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onActivityStopped(@NonNull Activity activity) {} | ||||
|  | ||||
|     @Override | ||||
|     public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle bundle) {} | ||||
|  | ||||
|     @Override | ||||
|     public void onActivityDestroyed(@NonNull Activity activity) {} | ||||
| } | ||||
							
								
								
									
										119
									
								
								app/src/main/java/com/topjohnwu/magisk/App.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								app/src/main/java/com/topjohnwu/magisk/App.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,119 @@ | ||||
| package com.topjohnwu.magisk | ||||
|  | ||||
| import android.annotation.SuppressLint | ||||
| import android.app.Activity | ||||
| import android.app.Application | ||||
| import android.content.Context | ||||
| import android.content.res.Configuration | ||||
| import android.os.AsyncTask | ||||
| import android.os.Build | ||||
| import android.os.Bundle | ||||
| import androidx.appcompat.app.AppCompatDelegate | ||||
| import androidx.multidex.MultiDex | ||||
| import com.topjohnwu.magisk.di.koinModules | ||||
| import com.topjohnwu.magisk.utils.LocaleManager | ||||
| import com.topjohnwu.magisk.utils.RootUtils | ||||
| import com.topjohnwu.magisk.utils.inject | ||||
| import com.topjohnwu.net.Networking | ||||
| import com.topjohnwu.superuser.Shell | ||||
| import org.koin.android.ext.koin.androidContext | ||||
| import org.koin.core.context.startKoin | ||||
| import timber.log.Timber | ||||
| import java.util.concurrent.ThreadPoolExecutor | ||||
|  | ||||
| open class App : Application(), Application.ActivityLifecycleCallbacks { | ||||
|  | ||||
|     lateinit var protectedContext: Context | ||||
|  | ||||
|     @Volatile | ||||
|     private var foreground: Activity? = null | ||||
|  | ||||
|     override fun attachBaseContext(base: Context) { | ||||
|         super.attachBaseContext(base) | ||||
|         if (BuildConfig.DEBUG) | ||||
|             MultiDex.install(base) | ||||
|         Timber.plant(Timber.DebugTree()) | ||||
|  | ||||
|         startKoin { | ||||
|             androidContext(this@App) | ||||
|             modules(koinModules) | ||||
|         } | ||||
|  | ||||
|         protectedContext = baseContext | ||||
|         self = this | ||||
|         deContext = base | ||||
|  | ||||
|         if (Build.VERSION.SDK_INT >= 24) { | ||||
|             protectedContext = base.createDeviceProtectedStorageContext() | ||||
|             deContext = protectedContext | ||||
|             deContext.moveSharedPreferencesFrom(base, base.defaultPrefsName) | ||||
|         } | ||||
|  | ||||
|         registerActivityLifecycleCallbacks(this) | ||||
|  | ||||
|         Networking.init(base) | ||||
|         LocaleManager.setLocale(this) | ||||
|     } | ||||
|  | ||||
|     override fun onConfigurationChanged(newConfig: Configuration) { | ||||
|         super.onConfigurationChanged(newConfig) | ||||
|         LocaleManager.setLocale(this) | ||||
|     } | ||||
|  | ||||
|     //region ActivityLifecycleCallbacks | ||||
|     override fun onActivityCreated(activity: Activity, bundle: Bundle?) {} | ||||
|  | ||||
|     override fun onActivityStarted(activity: Activity) {} | ||||
|  | ||||
|     @Synchronized | ||||
|     override fun onActivityResumed(activity: Activity) { | ||||
|         foreground = activity | ||||
|     } | ||||
|  | ||||
|     @Synchronized | ||||
|     override fun onActivityPaused(activity: Activity) { | ||||
|         foreground = null | ||||
|     } | ||||
|  | ||||
|     override fun onActivityStopped(activity: Activity) {} | ||||
|  | ||||
|     override fun onActivitySaveInstanceState(activity: Activity, bundle: Bundle) {} | ||||
|  | ||||
|     override fun onActivityDestroyed(activity: Activity) {} | ||||
|     //endregion | ||||
|  | ||||
|     private val Context.defaultPrefsName get() = "${packageName}_preferences" | ||||
|  | ||||
|     companion object { | ||||
|  | ||||
|         @SuppressLint("StaticFieldLeak") | ||||
|         @Deprecated("Use dependency injection") | ||||
|         @JvmStatic | ||||
|         lateinit var self: App | ||||
|  | ||||
|         @SuppressLint("StaticFieldLeak") | ||||
|         @Deprecated("Use dependency injection; replace with protectedContext") | ||||
|         @JvmStatic | ||||
|         lateinit var deContext: Context | ||||
|  | ||||
|         @Deprecated("Use Rx or similar") | ||||
|         @JvmField | ||||
|         var THREAD_POOL: ThreadPoolExecutor | ||||
|  | ||||
|         init { | ||||
|             AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) | ||||
|             Shell.Config.setFlags(Shell.FLAG_MOUNT_MASTER or Shell.FLAG_USE_MAGISK_BUSYBOX) | ||||
|             Shell.Config.verboseLogging(BuildConfig.DEBUG) | ||||
|             Shell.Config.addInitializers(RootUtils::class.java) | ||||
|             Shell.Config.setTimeout(2) | ||||
|             THREAD_POOL = AsyncTask.THREAD_POOL_EXECUTOR as ThreadPoolExecutor | ||||
|         } | ||||
|  | ||||
|         @Deprecated("") | ||||
|         @JvmStatic | ||||
|         fun foreground(): Activity? { | ||||
|             val app: App by inject() | ||||
|             return app.foreground | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,31 +0,0 @@ | ||||
| package com.topjohnwu.magisk; | ||||
|  | ||||
| import com.topjohnwu.magisk.model.download.DownloadModuleService; | ||||
| import com.topjohnwu.magisk.model.receiver.GeneralReceiver; | ||||
| import com.topjohnwu.magisk.model.update.UpdateCheckService; | ||||
| import com.topjohnwu.magisk.ui.MainActivity; | ||||
| import com.topjohnwu.magisk.ui.SplashActivity; | ||||
| import com.topjohnwu.magisk.ui.flash.FlashActivity; | ||||
| import com.topjohnwu.magisk.ui.surequest.SuRequestActivity; | ||||
|  | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
|  | ||||
| public class ClassMap { | ||||
|     private static Map<Class, Class> classMap = new HashMap<>(); | ||||
|  | ||||
|     static { | ||||
|         classMap.put(App.class, a.e.class); | ||||
|         classMap.put(MainActivity.class, a.b.class); | ||||
|         classMap.put(SplashActivity.class, a.c.class); | ||||
|         classMap.put(FlashActivity.class, a.f.class); | ||||
|         classMap.put(UpdateCheckService.class, a.g.class); | ||||
|         classMap.put(GeneralReceiver.class, a.h.class); | ||||
|         classMap.put(DownloadModuleService.class, a.j.class); | ||||
|         classMap.put(SuRequestActivity.class, a.m.class); | ||||
|     } | ||||
|      | ||||
|     public static <T> Class<T> get(Class c) { | ||||
|         return classMap.get(c); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										27
									
								
								app/src/main/java/com/topjohnwu/magisk/ClassMap.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								app/src/main/java/com/topjohnwu/magisk/ClassMap.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| package com.topjohnwu.magisk | ||||
|  | ||||
| import com.topjohnwu.magisk.model.download.DownloadModuleService | ||||
| import com.topjohnwu.magisk.model.receiver.GeneralReceiver | ||||
| import com.topjohnwu.magisk.model.update.UpdateCheckService | ||||
| import com.topjohnwu.magisk.ui.MainActivity | ||||
| import com.topjohnwu.magisk.ui.SplashActivity | ||||
| import com.topjohnwu.magisk.ui.flash.FlashActivity | ||||
| import com.topjohnwu.magisk.ui.surequest.SuRequestActivity | ||||
|  | ||||
| object ClassMap { | ||||
|     private val map = mapOf( | ||||
|         App::class.java to a.e::class.java, | ||||
|         MainActivity::class.java to a.b::class.java, | ||||
|         SplashActivity::class.java to a.c::class.java, | ||||
|         FlashActivity::class.java to a.f::class.java, | ||||
|         UpdateCheckService::class.java to a.g::class.java, | ||||
|         GeneralReceiver::class.java to a.h::class.java, | ||||
|         DownloadModuleService::class.java to a.j::class.java, | ||||
|         SuRequestActivity::class.java to a.m::class.java | ||||
|     ) | ||||
|  | ||||
|     @JvmStatic | ||||
|     operator fun get(c: Class<*>): Class<*>? { | ||||
|         return map.getOrElse(c) { null } //as? Class<T> | ||||
|     } | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										52
									
								
								app/src/main/java/com/topjohnwu/magisk/ConfigLeanback.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								app/src/main/java/com/topjohnwu/magisk/ConfigLeanback.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| package com.topjohnwu.magisk | ||||
|  | ||||
| import android.content.Context | ||||
| import android.content.SharedPreferences | ||||
| import androidx.annotation.AnyThread | ||||
| import androidx.annotation.WorkerThread | ||||
| import com.skoumal.teanity.extensions.subscribeK | ||||
| import com.topjohnwu.magisk.data.repository.SettingRepository | ||||
| import com.topjohnwu.magisk.data.repository.StringRepository | ||||
| import com.topjohnwu.magisk.di.Protected | ||||
| import com.topjohnwu.magisk.utils.inject | ||||
|  | ||||
| object ConfigLeanback { | ||||
|  | ||||
|     @JvmStatic | ||||
|     val protectedContext: Context by inject(Protected) | ||||
|     @JvmStatic | ||||
|     val prefs: SharedPreferences by inject() | ||||
|  | ||||
|     private val settingRepo: SettingRepository by inject() | ||||
|     private val stringRepo: StringRepository by inject() | ||||
|  | ||||
|     @JvmStatic | ||||
|     @AnyThread | ||||
|     fun put(key: String, value: Int) { | ||||
|         settingRepo.put(key, value).subscribeK() | ||||
|     } | ||||
|  | ||||
|     @JvmStatic | ||||
|     @WorkerThread | ||||
|     fun get(key: String, defaultValue: Int): Int = | ||||
|         settingRepo.fetch(key, defaultValue).blockingGet() | ||||
|  | ||||
|     @JvmStatic | ||||
|     @AnyThread | ||||
|     fun put(key: String, value: String?) { | ||||
|         val task = value?.let { stringRepo.put(key, it) } ?: stringRepo.delete(key) | ||||
|         task.subscribeK() | ||||
|     } | ||||
|  | ||||
|     @JvmStatic | ||||
|     @WorkerThread | ||||
|     fun get(key: String, defaultValue: String?): String = | ||||
|         stringRepo.fetch(key, defaultValue.orEmpty()).blockingGet() | ||||
|  | ||||
|     @JvmStatic | ||||
|     @AnyThread | ||||
|     fun delete(key: String) { | ||||
|         settingRepo.delete(key).subscribeK() | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,99 +0,0 @@ | ||||
| package com.topjohnwu.magisk; | ||||
|  | ||||
| import android.os.Environment; | ||||
| import android.os.Process; | ||||
|  | ||||
| import java.io.File; | ||||
|  | ||||
| public class Const { | ||||
|  | ||||
|     public static final String DEBUG_TAG = "MagiskManager"; | ||||
|  | ||||
|     // APK content | ||||
|     public static final String ANDROID_MANIFEST = "AndroidManifest.xml"; | ||||
|  | ||||
|     public static final String SU_KEYSTORE_KEY = "su_key"; | ||||
|  | ||||
|     // Paths | ||||
|     public static final String MAGISK_PATH = "/sbin/.magisk/img"; | ||||
|     public static final File EXTERNAL_PATH; | ||||
|     public static File MAGISK_DISABLE_FILE; | ||||
|  | ||||
|     static { | ||||
|         MAGISK_DISABLE_FILE = new File("xxx"); | ||||
|         EXTERNAL_PATH = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); | ||||
|         EXTERNAL_PATH.mkdirs(); | ||||
|     } | ||||
|  | ||||
|     public static final String TMP_FOLDER_PATH = "/dev/tmp"; | ||||
|     public static final String MAGISK_LOG = "/cache/magisk.log"; | ||||
|     public static final String MANAGER_CONFIGS = ".tmp.magisk.config"; | ||||
|  | ||||
|     // Versions | ||||
|     public static final int UPDATE_SERVICE_VER = 1; | ||||
|     public static final int SNET_EXT_VER = 12; | ||||
|  | ||||
|     public static final int USER_ID = Process.myUid() / 100000; | ||||
|  | ||||
|     public static final class MAGISK_VER { | ||||
|         public static final int MIN_SUPPORT = 18000; | ||||
|     } | ||||
|  | ||||
|     public static class ID { | ||||
|         public static final int FETCH_ZIP = 2; | ||||
|         public static final int SELECT_BOOT = 3; | ||||
|  | ||||
|         // notifications | ||||
|         public static final int MAGISK_UPDATE_NOTIFICATION_ID = 4; | ||||
|         public static final int APK_UPDATE_NOTIFICATION_ID = 5; | ||||
|         public static final int DTBO_NOTIFICATION_ID = 7; | ||||
|         public static final int HIDE_MANAGER_NOTIFICATION_ID = 8; | ||||
|         public static final String UPDATE_NOTIFICATION_CHANNEL = "update"; | ||||
|         public static final String PROGRESS_NOTIFICATION_CHANNEL = "progress"; | ||||
|         public static final String CHECK_MAGISK_UPDATE_WORKER_ID = "magisk_update"; | ||||
|     } | ||||
|  | ||||
|     public static class Url { | ||||
|         private static String getRaw(String where, String name) { | ||||
|             return String.format("https://raw.githubusercontent.com/topjohnwu/magisk_files/%s/%s", where, name); | ||||
|         } | ||||
|         public static final String STABLE_URL = getRaw("master", "stable.json"); | ||||
|         public static final String BETA_URL = getRaw("master", "beta.json"); | ||||
|         public static final String CANARY_URL = getRaw("master", "canary_builds/release.json"); | ||||
|         public static final String CANARY_DEBUG_URL = getRaw("master", "canary_builds/canary.json"); | ||||
|         public static final String REPO_URL = "https://api.github.com/users/Magisk-Modules-Repo/repos?per_page=100&sort=pushed&page=%d"; | ||||
|         public static final String FILE_URL = "https://raw.githubusercontent.com/Magisk-Modules-Repo/%s/master/%s"; | ||||
|         public static final String ZIP_URL = "https://github.com/Magisk-Modules-Repo/%s/archive/master.zip"; | ||||
|         public static final String MODULE_INSTALLER = "https://raw.githubusercontent.com/topjohnwu/Magisk/master/scripts/module_installer.sh"; | ||||
|         public static final String PAYPAL_URL = "https://www.paypal.me/topjohnwu"; | ||||
|         public static final String PATREON_URL = "https://www.patreon.com/topjohnwu"; | ||||
|         public static final String TWITTER_URL = "https://twitter.com/topjohnwu"; | ||||
|         public static final String XDA_THREAD = "http://forum.xda-developers.com/showthread.php?t=3432382"; | ||||
|         public static final String SOURCE_CODE_URL = "https://github.com/topjohnwu/Magisk"; | ||||
|         public static final String SNET_URL = getRaw("b66b1a914978e5f4c4bbfd74a59f4ad371bac107", "snet.apk"); | ||||
|         public static final String BOOTCTL_URL = getRaw("9c5dfc1b8245c0b5b524901ef0ff0f8335757b77", "bootctl"); | ||||
|     } | ||||
|  | ||||
|     public static class Key { | ||||
|         // others | ||||
|         public static final String LINK_KEY = "Link"; | ||||
|         public static final String IF_NONE_MATCH = "If-None-Match"; | ||||
|         // intents | ||||
|         public static final String OPEN_SECTION = "section"; | ||||
|         public static final String INTENT_SET_NAME = "filename"; | ||||
|         public static final String INTENT_SET_LINK = "link"; | ||||
|         public static final String FLASH_ACTION = "action"; | ||||
|         public static final String BROADCAST_MANAGER_UPDATE = "manager_update"; | ||||
|         public static final String BROADCAST_REBOOT = "reboot"; | ||||
|     } | ||||
|  | ||||
|     public static class Value { | ||||
|         public static final String FLASH_ZIP = "flash"; | ||||
|         public static final String PATCH_FILE = "patch"; | ||||
|         public static final String FLASH_MAGISK = "magisk"; | ||||
|         public static final String FLASH_INACTIVE_SLOT = "slot"; | ||||
|         public static final String UNINSTALL = "uninstall"; | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
							
								
								
									
										105
									
								
								app/src/main/java/com/topjohnwu/magisk/Const.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								app/src/main/java/com/topjohnwu/magisk/Const.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,105 @@ | ||||
| package com.topjohnwu.magisk | ||||
|  | ||||
| import android.os.Environment | ||||
| import android.os.Process | ||||
|  | ||||
| import java.io.File | ||||
|  | ||||
| object Const { | ||||
|  | ||||
|     const val DEBUG_TAG = "MagiskManager" | ||||
|  | ||||
|     // APK content | ||||
|     const val ANDROID_MANIFEST = "AndroidManifest.xml" | ||||
|  | ||||
|     const val SU_KEYSTORE_KEY = "su_key" | ||||
|  | ||||
|     // Paths | ||||
|     const val MAGISK_PATH = "/sbin/.magisk/img" | ||||
|     @JvmField | ||||
|     val EXTERNAL_PATH: File = | ||||
|         Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) | ||||
|     @JvmField | ||||
|     var MAGISK_DISABLE_FILE: File = File("xxx") | ||||
|  | ||||
|     const val TMP_FOLDER_PATH = "/dev/tmp" | ||||
|     const val MAGISK_LOG = "/cache/magisk.log" | ||||
|     const val MANAGER_CONFIGS = ".tmp.magisk.config" | ||||
|  | ||||
|     // Versions | ||||
|     const val UPDATE_SERVICE_VER = 1 | ||||
|     const val SNET_EXT_VER = 12 | ||||
|  | ||||
|     @JvmField | ||||
|     val USER_ID = Process.myUid() / 100000 | ||||
|  | ||||
|     // Generic | ||||
|     const val MAGISK_INSTALL_LOG_FILENAME = "magisk_install_log_%s.log" | ||||
|  | ||||
|     init { | ||||
|         EXTERNAL_PATH.mkdirs() | ||||
|     } | ||||
|  | ||||
|     object MagiskVersion { | ||||
|         const val MIN_SUPPORT = 18000 | ||||
|     } | ||||
|  | ||||
|     object ID { | ||||
|         const val FETCH_ZIP = 2 | ||||
|         const val SELECT_BOOT = 3 | ||||
|  | ||||
|         // notifications | ||||
|         const val MAGISK_UPDATE_NOTIFICATION_ID = 4 | ||||
|         const val APK_UPDATE_NOTIFICATION_ID = 5 | ||||
|         const val DTBO_NOTIFICATION_ID = 7 | ||||
|         const val HIDE_MANAGER_NOTIFICATION_ID = 8 | ||||
|         const val UPDATE_NOTIFICATION_CHANNEL = "update" | ||||
|         const val PROGRESS_NOTIFICATION_CHANNEL = "progress" | ||||
|         const val CHECK_MAGISK_UPDATE_WORKER_ID = "magisk_update" | ||||
|     } | ||||
|  | ||||
|     object Url { | ||||
|         @Deprecated("This shouldn't be used. There's literally no need for it") | ||||
|         const val REPO_URL = | ||||
|             "https://api.github.com/users/Magisk-Modules-Repo/repos?per_page=100&sort=pushed&page=%d" | ||||
|         const val FILE_URL = "https://raw.githubusercontent.com/Magisk-Modules-Repo/%s/master/%s" | ||||
|         const val ZIP_URL = "https://github.com/Magisk-Modules-Repo/%s/archive/master.zip" | ||||
|         const val MODULE_INSTALLER = | ||||
|             "https://raw.githubusercontent.com/topjohnwu/Magisk/master/scripts/module_installer.sh" | ||||
|         const val PAYPAL_URL = "https://www.paypal.me/topjohnwu" | ||||
|         const val PATREON_URL = "https://www.patreon.com/topjohnwu" | ||||
|         const val TWITTER_URL = "https://twitter.com/topjohnwu" | ||||
|         const val XDA_THREAD = "http://forum.xda-developers.com/showthread.php?t=3432382" | ||||
|         const val SOURCE_CODE_URL = "https://github.com/topjohnwu/Magisk" | ||||
|         @JvmField | ||||
|         val SNET_URL = getRaw("b66b1a914978e5f4c4bbfd74a59f4ad371bac107", "snet.apk") | ||||
|         @JvmField | ||||
|         val BOOTCTL_URL = getRaw("9c5dfc1b8245c0b5b524901ef0ff0f8335757b77", "bootctl") | ||||
|  | ||||
|         private fun getRaw(where: String, name: String) = | ||||
|             "https://raw.githubusercontent.com/topjohnwu/magisk_files/%s/%s".format(where, name) | ||||
|     } | ||||
|  | ||||
|     object Key { | ||||
|         // others | ||||
|         const val LINK_KEY = "Link" | ||||
|         const val IF_NONE_MATCH = "If-None-Match" | ||||
|         // intents | ||||
|         const val OPEN_SECTION = "section" | ||||
|         const val INTENT_SET_NAME = "filename" | ||||
|         const val INTENT_SET_LINK = "link" | ||||
|         const val FLASH_ACTION = "action" | ||||
|         const val BROADCAST_MANAGER_UPDATE = "manager_update" | ||||
|         const val BROADCAST_REBOOT = "reboot" | ||||
|     } | ||||
|  | ||||
|     object Value { | ||||
|         const val FLASH_ZIP = "flash" | ||||
|         const val PATCH_FILE = "patch" | ||||
|         const val FLASH_MAGISK = "magisk" | ||||
|         const val FLASH_INACTIVE_SLOT = "slot" | ||||
|         const val UNINSTALL = "uninstall" | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
							
								
								
									
										20
									
								
								app/src/main/java/com/topjohnwu/magisk/Constants.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								app/src/main/java/com/topjohnwu/magisk/Constants.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| package com.topjohnwu.magisk | ||||
|  | ||||
| import android.os.Process | ||||
|  | ||||
| object Constants { | ||||
|  | ||||
|     // Paths | ||||
|     val MAGISK_PATH = "/sbin/.magisk/img" | ||||
|     val MAGISK_LOG = "/cache/magisk.log" | ||||
|  | ||||
|     val USER_ID get() = Process.myUid() / 100000 | ||||
|  | ||||
|     const val SNET_REVISION = "b66b1a914978e5f4c4bbfd74a59f4ad371bac107" | ||||
|     const val BOOTCTL_REVISION = "9c5dfc1b8245c0b5b524901ef0ff0f8335757b77" | ||||
|  | ||||
|     const val GITHUB_URL = "https://github.com/" | ||||
|     const val GITHUB_API_URL = "https://api.github.com/" | ||||
|     const val GITHUB_RAW_API_URL = "https://raw.githubusercontent.com/" | ||||
|  | ||||
| } | ||||
							
								
								
									
										47
									
								
								app/src/main/java/com/topjohnwu/magisk/KConfig.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								app/src/main/java/com/topjohnwu/magisk/KConfig.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| package com.topjohnwu.magisk | ||||
|  | ||||
| import android.content.Context | ||||
| import com.topjohnwu.magisk.KConfig.UpdateChannel.STABLE | ||||
| import com.topjohnwu.magisk.di.Protected | ||||
| import com.topjohnwu.magisk.model.preference.PreferenceModel | ||||
| import com.topjohnwu.magisk.utils.inject | ||||
|  | ||||
| object KConfig : PreferenceModel() { | ||||
|  | ||||
|     override val context: Context by inject(Protected) | ||||
|     override val fileName: String = "${context.packageName}_preferences" | ||||
|  | ||||
|     private var internalUpdateChannel by preference(Config.Key.UPDATE_CHANNEL, STABLE.id.toString()) | ||||
|     var useCustomTabs by preference("useCustomTabs", true) | ||||
|     @JvmStatic | ||||
|     var customUpdateChannel by preference(Config.Key.CUSTOM_CHANNEL, "") | ||||
|  | ||||
|     @JvmStatic | ||||
|     var updateChannel: UpdateChannel | ||||
|         get() = UpdateChannel.byId(internalUpdateChannel.toIntOrNull() ?: STABLE.id) | ||||
|         set(value) { | ||||
|             internalUpdateChannel = value.id.toString() | ||||
|         } | ||||
|  | ||||
|     internal const val DEFAULT_CHANNEL = "topjohnwu/magisk_files" | ||||
|  | ||||
|     enum class UpdateChannel(val id: Int) { | ||||
|  | ||||
|         STABLE(Config.Value.STABLE_CHANNEL), | ||||
|         BETA(Config.Value.BETA_CHANNEL), | ||||
|         CANARY(Config.Value.CANARY_CHANNEL), | ||||
|         CANARY_DEBUG(Config.Value.CANARY_DEBUG_CHANNEL), | ||||
|         CUSTOM(Config.Value.CUSTOM_CHANNEL); | ||||
|  | ||||
|         companion object { | ||||
|             fun byId(id: Int) = when (id) { | ||||
|                 Config.Value.STABLE_CHANNEL -> STABLE | ||||
|                 Config.Value.BETA_CHANNEL -> BETA | ||||
|                 Config.Value.CUSTOM_CHANNEL -> CUSTOM | ||||
|                 Config.Value.CANARY_CHANNEL -> CANARY | ||||
|                 Config.Value.CANARY_DEBUG_CHANNEL -> CANARY_DEBUG | ||||
|                 else -> STABLE | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,34 @@ | ||||
| package com.topjohnwu.magisk.data.database | ||||
|  | ||||
| import com.topjohnwu.magisk.Config | ||||
| import com.topjohnwu.magisk.data.database.base.* | ||||
| import com.topjohnwu.magisk.model.entity.MagiskLog | ||||
| import com.topjohnwu.magisk.model.entity.toLog | ||||
| import com.topjohnwu.magisk.model.entity.toMap | ||||
| import java.util.concurrent.TimeUnit | ||||
|  | ||||
| class LogDao : BaseDao() { | ||||
|  | ||||
|     override val table = DatabaseDefinition.Table.LOG | ||||
|  | ||||
|     fun deleteOutdated( | ||||
|         suTimeout: Long = Config.suLogTimeout * TimeUnit.DAYS.toMillis(1) | ||||
|     ) = query<Delete> { | ||||
|         condition { | ||||
|             lessThan("time", suTimeout.toString()) | ||||
|         } | ||||
|     }.ignoreElement() | ||||
|  | ||||
|     fun deleteAll() = query<Delete> {}.ignoreElement() | ||||
|  | ||||
|     fun fetchAll() = query<Select> { | ||||
|         orderBy("time", Order.DESC) | ||||
|     }.flattenAsFlowable { it } | ||||
|         .map { it.toLog() } | ||||
|         .toList() | ||||
|  | ||||
|     fun put(log: MagiskLog) = query<Insert> { | ||||
|         values(log.toMap()) | ||||
|     }.ignoreElement() | ||||
|  | ||||
| } | ||||
| @@ -1,190 +0,0 @@ | ||||
| package com.topjohnwu.magisk.data.database; | ||||
|  | ||||
| import android.content.ContentValues; | ||||
| import android.content.Context; | ||||
| import android.content.pm.PackageManager; | ||||
| import android.text.TextUtils; | ||||
|  | ||||
| import com.topjohnwu.magisk.Config; | ||||
| import com.topjohnwu.magisk.Const; | ||||
| import com.topjohnwu.magisk.model.entity.Policy; | ||||
| import com.topjohnwu.magisk.model.entity.SuLogEntry; | ||||
| import com.topjohnwu.magisk.utils.LocaleManager; | ||||
| import com.topjohnwu.magisk.utils.Utils; | ||||
| import com.topjohnwu.superuser.Shell; | ||||
|  | ||||
| import java.text.DateFormat; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.Date; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
|  | ||||
| public class MagiskDB { | ||||
|  | ||||
|     private static final String POLICY_TABLE = "policies"; | ||||
|     private static final String LOG_TABLE = "logs"; | ||||
|     private static final String SETTINGS_TABLE = "settings"; | ||||
|     private static final String STRINGS_TABLE = "strings"; | ||||
|  | ||||
|     private PackageManager pm; | ||||
|  | ||||
|     public MagiskDB(Context context) { | ||||
|         pm = context.getPackageManager(); | ||||
|     } | ||||
|  | ||||
|     public void deletePolicy(Policy policy) { | ||||
|         deletePolicy(policy.uid); | ||||
|     } | ||||
|  | ||||
|     private List<String> rawSQL(String fmt, Object... args) { | ||||
|         return Shell.su("magisk --sqlite '" + Utils.fmt(fmt, args) + "'").exec().getOut(); | ||||
|     } | ||||
|  | ||||
|     private List<ContentValues> SQL(String fmt, Object... args) { | ||||
|         List<ContentValues> list = new ArrayList<>(); | ||||
|         for (String raw : rawSQL(fmt, args)) { | ||||
|             ContentValues values = new ContentValues(); | ||||
|             String[] cols = raw.split("\\|"); | ||||
|             for (String col : cols) { | ||||
|                 String[] pair = col.split("=", 2); | ||||
|                 if (pair.length != 2) | ||||
|                     continue; | ||||
|                 values.put(pair[0], pair[1]); | ||||
|             } | ||||
|             list.add(values); | ||||
|         } | ||||
|         return list; | ||||
|     } | ||||
|  | ||||
|     private String toSQL(ContentValues values) { | ||||
|         StringBuilder keys = new StringBuilder(), vals = new StringBuilder(); | ||||
|         keys.append('('); | ||||
|         vals.append("VALUES("); | ||||
|         boolean first = true; | ||||
|         for (Map.Entry<String, Object> entry : values.valueSet()) { | ||||
|             if (!first) { | ||||
|                 keys.append(','); | ||||
|                 vals.append(','); | ||||
|             } else { | ||||
|                 first = false; | ||||
|             } | ||||
|             keys.append(entry.getKey()); | ||||
|             vals.append('"'); | ||||
|             vals.append(entry.getValue()); | ||||
|             vals.append('"'); | ||||
|         } | ||||
|         keys.append(')'); | ||||
|         vals.append(')'); | ||||
|         keys.append(vals); | ||||
|         return keys.toString(); | ||||
|     } | ||||
|  | ||||
|     public void clearOutdated() { | ||||
|         rawSQL( | ||||
|                 "DELETE FROM %s WHERE until > 0 AND until < %d;" + | ||||
|                         "DELETE FROM %s WHERE time < %d", | ||||
|                 POLICY_TABLE, System.currentTimeMillis() / 1000, | ||||
|                 LOG_TABLE, System.currentTimeMillis() - Config.suLogTimeout * 86400000 | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     public void deletePolicy(String pkg) { | ||||
|         rawSQL("DELETE FROM %s WHERE package_name=\"%s\"", POLICY_TABLE, pkg); | ||||
|     } | ||||
|  | ||||
|     public void deletePolicy(int uid) { | ||||
|         rawSQL("DELETE FROM %s WHERE uid=%d", POLICY_TABLE, uid); | ||||
|     } | ||||
|  | ||||
|     public Policy getPolicy(int uid) { | ||||
|         List<ContentValues> res = | ||||
|                 SQL("SELECT * FROM %s WHERE uid=%d", POLICY_TABLE, uid); | ||||
|         if (!res.isEmpty()) { | ||||
|             try { | ||||
|                 return new Policy(res.get(0), pm); | ||||
|             } catch (PackageManager.NameNotFoundException e) { | ||||
|                 deletePolicy(uid); | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     public void updatePolicy(Policy policy) { | ||||
|         rawSQL("REPLACE INTO %s %s", POLICY_TABLE, toSQL(policy.getContentValues())); | ||||
|     } | ||||
|  | ||||
|     public List<Policy> getPolicyList() { | ||||
|         List<Policy> list = new ArrayList<>(); | ||||
|         for (ContentValues values : SQL("SELECT * FROM %s WHERE uid/100000=%d", POLICY_TABLE, Const.USER_ID)) { | ||||
|             try { | ||||
|                 list.add(new Policy(values, pm)); | ||||
|             } catch (PackageManager.NameNotFoundException e) { | ||||
|                 deletePolicy(values.getAsInteger("uid")); | ||||
|             } | ||||
|         } | ||||
|         Collections.sort(list); | ||||
|         return list; | ||||
|     } | ||||
|  | ||||
|     public List<List<SuLogEntry>> getLogs() { | ||||
|         List<List<SuLogEntry>> ret = new ArrayList<>(); | ||||
|         List<SuLogEntry> list = null; | ||||
|         String dateString = null, newString; | ||||
|         for (ContentValues values : SQL("SELECT * FROM %s ORDER BY time DESC", LOG_TABLE)) { | ||||
|             Date date = new Date(values.getAsLong("time")); | ||||
|             newString = DateFormat.getDateInstance(DateFormat.MEDIUM, LocaleManager.locale).format(date); | ||||
|             if (!TextUtils.equals(dateString, newString)) { | ||||
|                 dateString = newString; | ||||
|                 list = new ArrayList<>(); | ||||
|                 ret.add(list); | ||||
|             } | ||||
|             list.add(new SuLogEntry(values)); | ||||
|         } | ||||
|         return ret; | ||||
|     } | ||||
|  | ||||
|     public void addLog(SuLogEntry log) { | ||||
|         rawSQL("INSERT INTO %s %s", LOG_TABLE, toSQL(log.getContentValues())); | ||||
|     } | ||||
|  | ||||
|     public void clearLogs() { | ||||
|         rawSQL("DELETE FROM %s", LOG_TABLE); | ||||
|     } | ||||
|  | ||||
|     public void rmSettings(String key) { | ||||
|         rawSQL("DELETE FROM %s WHERE key=\"%s\"", SETTINGS_TABLE, key); | ||||
|     } | ||||
|  | ||||
|     public void setSettings(String key, int value) { | ||||
|         ContentValues data = new ContentValues(); | ||||
|         data.put("key", key); | ||||
|         data.put("value", value); | ||||
|         rawSQL("REPLACE INTO %s %s", SETTINGS_TABLE, toSQL(data)); | ||||
|     } | ||||
|  | ||||
|     public int getSettings(String key, int defaultValue) { | ||||
|         List<ContentValues> res = SQL("SELECT value FROM %s WHERE key=\"%s\"", SETTINGS_TABLE, key); | ||||
|         if (res.isEmpty()) | ||||
|             return defaultValue; | ||||
|         return res.get(0).getAsInteger("value"); | ||||
|     } | ||||
|  | ||||
|     public void setStrings(String key, String value) { | ||||
|         if (value == null) { | ||||
|             rawSQL("DELETE FROM %s WHERE key=\"%s\"", STRINGS_TABLE, key); | ||||
|             return; | ||||
|         } | ||||
|         ContentValues data = new ContentValues(); | ||||
|         data.put("key", key); | ||||
|         data.put("value", value); | ||||
|         rawSQL("REPLACE INTO %s %s", STRINGS_TABLE, toSQL(data)); | ||||
|     } | ||||
|  | ||||
|     public String getStrings(String key, String defaultValue) { | ||||
|         List<ContentValues> res = SQL("SELECT value FROM %s WHERE key=\"%s\"", STRINGS_TABLE, key); | ||||
|         if (res.isEmpty()) | ||||
|             return defaultValue; | ||||
|         return res.get(0).getAsString("value"); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,69 @@ | ||||
| package com.topjohnwu.magisk.data.database | ||||
|  | ||||
| import android.content.Context | ||||
| import android.content.pm.PackageManager | ||||
| import com.topjohnwu.magisk.Constants | ||||
| import com.topjohnwu.magisk.data.database.base.* | ||||
| import com.topjohnwu.magisk.model.entity.MagiskPolicy | ||||
| import com.topjohnwu.magisk.model.entity.toMap | ||||
| import com.topjohnwu.magisk.model.entity.toPolicy | ||||
| import com.topjohnwu.magisk.utils.now | ||||
| import java.util.concurrent.TimeUnit | ||||
|  | ||||
|  | ||||
| class PolicyDao( | ||||
|     private val context: Context | ||||
| ) : BaseDao() { | ||||
|  | ||||
|     override val table: String = DatabaseDefinition.Table.POLICY | ||||
|  | ||||
|     fun deleteOutdated( | ||||
|         nowSeconds: Long = TimeUnit.MILLISECONDS.toSeconds(now) | ||||
|     ) = query<Delete> { | ||||
|         condition { | ||||
|             greaterThan("until", "0") | ||||
|             and { | ||||
|                 lessThan("until", nowSeconds.toString()) | ||||
|             } | ||||
|             or { | ||||
|                 lessThan("until", "0") | ||||
|             } | ||||
|         } | ||||
|     }.ignoreElement() | ||||
|  | ||||
|     fun delete(packageName: String) = query<Delete> { | ||||
|         condition { | ||||
|             equals("package_name", packageName) | ||||
|         } | ||||
|     }.ignoreElement() | ||||
|  | ||||
|     fun delete(uid: Int) = query<Delete> { | ||||
|         condition { | ||||
|             equals("uid", uid) | ||||
|         } | ||||
|     }.ignoreElement() | ||||
|  | ||||
|     fun fetch(uid: Int) = query<Select> { | ||||
|         condition { | ||||
|             equals("uid", uid) | ||||
|         } | ||||
|     }.map { it.firstOrNull()?.toPolicy(context.packageManager) } | ||||
|         .doOnError { | ||||
|             if (it is PackageManager.NameNotFoundException) { | ||||
|                 delete(uid).subscribe() | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     fun update(policy: MagiskPolicy) = query<Replace> { | ||||
|         values(policy.toMap()) | ||||
|     }.ignoreElement() | ||||
|  | ||||
|     fun fetchAll() = query<Select> { | ||||
|         condition { | ||||
|             equals("uid/100000", Constants.USER_ID) | ||||
|         } | ||||
|     }.flattenAsFlowable { it } | ||||
|         .map { it.toPolicy(context.packageManager) } | ||||
|         .toList() | ||||
|  | ||||
| } | ||||
| @@ -11,13 +11,15 @@ import com.topjohnwu.magisk.model.entity.Repo; | ||||
| import java.util.HashSet; | ||||
| import java.util.Set; | ||||
|  | ||||
| @Deprecated | ||||
| public class RepoDatabaseHelper extends SQLiteOpenHelper { | ||||
|  | ||||
|     private static final int DATABASE_VER = 5; | ||||
|     private static final String TABLE_NAME = "repos"; | ||||
|  | ||||
|     private SQLiteDatabase mDb; | ||||
|     private final SQLiteDatabase mDb; | ||||
|  | ||||
|     @Deprecated | ||||
|     public RepoDatabaseHelper(Context context) { | ||||
|         super(context, "repo.db", null, DATABASE_VER); | ||||
|         mDb = getWritableDatabase(); | ||||
| @@ -46,32 +48,38 @@ public class RepoDatabaseHelper extends SQLiteOpenHelper { | ||||
|         onUpgrade(db, 0, DATABASE_VER); | ||||
|     } | ||||
|  | ||||
|     @Deprecated | ||||
|     public void clearRepo() { | ||||
|         mDb.delete(TABLE_NAME, null, null); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     @Deprecated | ||||
|     public void removeRepo(String id) { | ||||
|         mDb.delete(TABLE_NAME, "id=?", new String[] { id }); | ||||
|         mDb.delete(TABLE_NAME, "id=?", new String[]{id}); | ||||
|     } | ||||
|  | ||||
|     @Deprecated | ||||
|     public void removeRepo(Repo repo) { | ||||
|         removeRepo(repo.getId()); | ||||
|     } | ||||
|  | ||||
|     @Deprecated | ||||
|     public void removeRepo(Iterable<String> list) { | ||||
|         for (String id : list) { | ||||
|             if (id == null) continue; | ||||
|             mDb.delete(TABLE_NAME, "id=?", new String[] { id }); | ||||
|             mDb.delete(TABLE_NAME, "id=?", new String[]{id}); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Deprecated | ||||
|     public void addRepo(Repo repo) { | ||||
|         mDb.replace(TABLE_NAME, null, repo.getContentValues()); | ||||
|     } | ||||
|  | ||||
|     @Deprecated | ||||
|     public Repo getRepo(String id) { | ||||
|         try (Cursor c = mDb.query(TABLE_NAME, null, "id=?", new String[] { id }, null, null, null)) { | ||||
|         try (Cursor c = mDb.query(TABLE_NAME, null, "id=?", new String[]{id}, null, null, null)) { | ||||
|             if (c.moveToNext()) { | ||||
|                 return new Repo(c); | ||||
|             } | ||||
| @@ -79,10 +87,12 @@ public class RepoDatabaseHelper extends SQLiteOpenHelper { | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     @Deprecated | ||||
|     public Cursor getRawCursor() { | ||||
|         return mDb.query(TABLE_NAME, null, null, null, null, null, null); | ||||
|     } | ||||
|  | ||||
|     @Deprecated | ||||
|     public Cursor getRepoCursor() { | ||||
|         String orderBy = null; | ||||
|         switch ((int) Config.get(Config.Key.REPO_ORDER)) { | ||||
| @@ -95,6 +105,7 @@ public class RepoDatabaseHelper extends SQLiteOpenHelper { | ||||
|         return mDb.query(TABLE_NAME, null, null, null, null, null, orderBy); | ||||
|     } | ||||
|  | ||||
|     @Deprecated | ||||
|     public Set<String> getRepoIDSet() { | ||||
|         HashSet<String> set = new HashSet<>(300); | ||||
|         try (Cursor c = mDb.query(TABLE_NAME, null, null, null, null, null, null)) { | ||||
|   | ||||
| @@ -0,0 +1,21 @@ | ||||
| package com.topjohnwu.magisk.data.database | ||||
|  | ||||
| import com.topjohnwu.magisk.data.database.base.* | ||||
|  | ||||
| class SettingsDao : BaseDao() { | ||||
|  | ||||
|     override val table = DatabaseDefinition.Table.SETTINGS | ||||
|  | ||||
|     fun delete(key: String) = query<Delete> { | ||||
|         condition { equals("key", key) } | ||||
|     }.ignoreElement() | ||||
|  | ||||
|     fun put(key: String, value: Int) = query<Insert> { | ||||
|         values(key to value.toString()) | ||||
|     }.ignoreElement() | ||||
|  | ||||
|     fun fetch(key: String, default: Int = -1) = query<Select> { | ||||
|         condition { equals("key", key) } | ||||
|     }.map { it.firstOrNull()?.values?.firstOrNull()?.toIntOrNull() ?: default } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,22 @@ | ||||
| package com.topjohnwu.magisk.data.database | ||||
|  | ||||
| import com.topjohnwu.magisk.data.database.base.* | ||||
|  | ||||
| class StringDao : BaseDao() { | ||||
|  | ||||
|     override val table = DatabaseDefinition.Table.STRINGS | ||||
|  | ||||
|     fun delete(key: String) = query<Delete> { | ||||
|         condition { equals("key", key) } | ||||
|     }.ignoreElement() | ||||
|  | ||||
|     fun put(key: String, value: String) = query<Insert> { | ||||
|         values(key to value) | ||||
|     }.ignoreElement() | ||||
|  | ||||
|     fun fetch(key: String, default: String = "") = query<Select> { | ||||
|         fields("value") | ||||
|         condition { equals("key", key) } | ||||
|     }.map { it.firstOrNull()?.values?.firstOrNull() ?: default } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,15 @@ | ||||
| package com.topjohnwu.magisk.data.database.base | ||||
|  | ||||
| abstract class BaseDao { | ||||
|  | ||||
|     abstract val table: String | ||||
|  | ||||
|     inline fun <reified Builder : MagiskQueryBuilder> query(builder: Builder.() -> Unit) = | ||||
|         Builder::class.java.newInstance() | ||||
|             .apply { table = this@BaseDao.table } | ||||
|             .apply(builder) | ||||
|             .toString() | ||||
|             .let { MagiskQuery(it) } | ||||
|             .query() | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,30 @@ | ||||
| package com.topjohnwu.magisk.data.database.base | ||||
|  | ||||
| import androidx.annotation.AnyThread | ||||
| import com.topjohnwu.superuser.Shell | ||||
| import io.reactivex.Single | ||||
|  | ||||
| object DatabaseDefinition { | ||||
|  | ||||
|     object Table { | ||||
|         const val POLICY = "policies" | ||||
|         const val LOG = "logs" | ||||
|         const val SETTINGS = "settings" | ||||
|         const val STRINGS = "strings" | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| @AnyThread | ||||
| fun MagiskQuery.query() = query.su() | ||||
|  | ||||
| fun String.suRaw() = Single.fromCallable { Shell.su(this).exec().out } | ||||
| fun String.su() = suRaw().map { it.toMap() } | ||||
|  | ||||
| fun List<String>.toMap() = map { it.split(Regex("\\|")) } | ||||
|     .map { it.toMapInternal() } | ||||
|  | ||||
| private fun List<String>.toMapInternal() = map { it.split("=", limit = 2) } | ||||
|     .filter { it.size == 2 } | ||||
|     .map { Pair(it[0], it[1]) } | ||||
|     .toMap() | ||||
| @@ -0,0 +1,5 @@ | ||||
| package com.topjohnwu.magisk.data.database.base | ||||
|  | ||||
| inline class MagiskQuery(private val _query: String) { | ||||
|     val query get() = "magisk --sqlite '$_query'" | ||||
| } | ||||
| @@ -0,0 +1,163 @@ | ||||
| package com.topjohnwu.magisk.data.database.base | ||||
|  | ||||
| import androidx.annotation.StringDef | ||||
| import com.topjohnwu.magisk.data.database.base.Order.Companion.ASC | ||||
| import com.topjohnwu.magisk.data.database.base.Order.Companion.DESC | ||||
|  | ||||
| interface MagiskQueryBuilder { | ||||
|  | ||||
|     val requestType: String | ||||
|     var table: String | ||||
|  | ||||
|     companion object { | ||||
|         inline operator fun <reified Builder : MagiskQueryBuilder> invoke(builder: Builder.() -> Unit): MagiskQuery = | ||||
|             Builder::class.java.newInstance() | ||||
|                 .apply(builder) | ||||
|                 .toString() | ||||
|                 .let { | ||||
|                     MagiskQuery(it) | ||||
|                 } | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| class Delete : MagiskQueryBuilder { | ||||
|     override val requestType: String = "DELETE FROM" | ||||
|     override var table = "" | ||||
|  | ||||
|     private var condition = "" | ||||
|  | ||||
|     fun condition(builder: Condition.() -> Unit) { | ||||
|         condition = Condition().apply(builder).toString() | ||||
|     } | ||||
|  | ||||
|     override fun toString(): String { | ||||
|         return StringBuilder() | ||||
|             .appendln(requestType) | ||||
|             .appendln(table) | ||||
|             .appendln(condition) | ||||
|             .toString() | ||||
|     } | ||||
| } | ||||
|  | ||||
| class Select : MagiskQueryBuilder { | ||||
|     override val requestType: String get() = "SELECT $fields FROM" | ||||
|     override lateinit var table: String | ||||
|  | ||||
|     private var fields = "*" | ||||
|     private var condition = "" | ||||
|     private var orderField = "" | ||||
|  | ||||
|     fun fields(vararg newFields: String) { | ||||
|         if (newFields.isEmpty()) { | ||||
|             fields = "*" | ||||
|             return | ||||
|         } | ||||
|         fields = newFields.joinToString(", ") | ||||
|     } | ||||
|  | ||||
|     fun condition(builder: Condition.() -> Unit) { | ||||
|         condition = Condition().apply(builder).toString() | ||||
|     } | ||||
|  | ||||
|     fun orderBy(field: String, @OrderStrict order: String) { | ||||
|         orderField = "ORDER BY $field $order" | ||||
|     } | ||||
|  | ||||
|     override fun toString(): String { | ||||
|         return StringBuilder() | ||||
|             .appendln(requestType) | ||||
|             .appendln(table) | ||||
|             .appendln(condition) | ||||
|             .appendln(orderField) | ||||
|             .toString() | ||||
|             .replace("\n", " ") | ||||
|     } | ||||
| } | ||||
|  | ||||
| class Replace : Insert() { | ||||
|     override val requestType: String = "REPLACE INTO" | ||||
| } | ||||
|  | ||||
| open class Insert : MagiskQueryBuilder { | ||||
|     override val requestType: String = "INSERT INTO" | ||||
|     override lateinit var table: String | ||||
|  | ||||
|     private val keys get() = _values.keys.joinToString(",") | ||||
|     private val values get() = _values.values.joinToString(",") { "\"$it\"" } | ||||
|     private var _values: Map<String, String> = mapOf() | ||||
|  | ||||
|     fun values(vararg pairs: Pair<String, String>) { | ||||
|         _values = pairs.toMap() | ||||
|     } | ||||
|  | ||||
|     fun values(values: Map<String, String>) { | ||||
|         _values = values | ||||
|     } | ||||
|  | ||||
|     override fun toString(): String { | ||||
|         return StringBuilder() | ||||
|             .appendln(requestType) | ||||
|             .appendln(table) | ||||
|             .appendln("($keys) VALUES($values)") | ||||
|             .toString() | ||||
|     } | ||||
| } | ||||
|  | ||||
| class Condition { | ||||
|  | ||||
|     private val conditionWord = "WHERE %s" | ||||
|     private var condition: String = "" | ||||
|  | ||||
|     fun equals(field: String, value: Any) { | ||||
|         condition = when (value) { | ||||
|             is String -> "$field=\"$value\"" | ||||
|             else -> "$field=$value" | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun greaterThan(field: String, value: String) { | ||||
|         condition = "$field > $value" | ||||
|     } | ||||
|  | ||||
|     fun lessThan(field: String, value: String) { | ||||
|         condition = "$field < $value" | ||||
|     } | ||||
|  | ||||
|     fun greaterOrEqualTo(field: String, value: String) { | ||||
|         condition = "$field >= $value" | ||||
|     } | ||||
|  | ||||
|     fun lessOrEqualTo(field: String, value: String) { | ||||
|         condition = "$field <= $value" | ||||
|     } | ||||
|  | ||||
|     fun and(builder: Condition.() -> Unit) { | ||||
|         condition = "($condition AND ${Condition().apply(builder).condition})" | ||||
|     } | ||||
|  | ||||
|     fun or(builder: Condition.() -> Unit) { | ||||
|         condition = "($condition OR ${Condition().apply(builder).condition})" | ||||
|     } | ||||
|  | ||||
|     override fun toString(): String { | ||||
|         return conditionWord.format(condition) | ||||
|     } | ||||
| } | ||||
|  | ||||
| class Order { | ||||
|  | ||||
|     @set:OrderStrict | ||||
|     var order = DESC | ||||
|     var field = "" | ||||
|  | ||||
|     companion object { | ||||
|         const val ASC = "ASC" | ||||
|         const val DESC = "DESC" | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| @StringDef(ASC, DESC) | ||||
| @Retention(AnnotationRetention.SOURCE) | ||||
| annotation class OrderStrict | ||||
| @@ -0,0 +1,63 @@ | ||||
| package com.topjohnwu.magisk.data.network | ||||
|  | ||||
| import com.topjohnwu.magisk.Constants | ||||
| import com.topjohnwu.magisk.KConfig | ||||
| import com.topjohnwu.magisk.model.entity.MagiskConfig | ||||
| import io.reactivex.Single | ||||
| import okhttp3.ResponseBody | ||||
| import retrofit2.http.GET | ||||
| import retrofit2.http.Path | ||||
| import retrofit2.http.Streaming | ||||
| import retrofit2.http.Url | ||||
|  | ||||
|  | ||||
| interface GithubRawApiServices { | ||||
|  | ||||
|     //region topjohnwu/magisk_files | ||||
|  | ||||
|     @GET("$MAGISK_FILES/master/stable.json") | ||||
|     fun fetchConfig(): Single<MagiskConfig> | ||||
|  | ||||
|     @GET("$MAGISK_FILES/master/beta.json") | ||||
|     fun fetchBetaConfig(): Single<MagiskConfig> | ||||
|  | ||||
|     @GET("$MAGISK_FILES/master/canary_builds/release.json") | ||||
|     fun fetchCanaryConfig(): Single<MagiskConfig> | ||||
|  | ||||
|     @GET("$MAGISK_FILES/master/canary_builds/canary.json") | ||||
|     fun fetchCanaryDebugConfig(): Single<MagiskConfig> | ||||
|  | ||||
|     @GET | ||||
|     fun fetchCustomConfig(@Url url: String): Single<MagiskConfig> | ||||
|  | ||||
|     @GET("$MAGISK_FILES/{$REVISION}/snet.apk") | ||||
|     @Streaming | ||||
|     fun fetchSafetynet(@Path(REVISION) revision: String = Constants.SNET_REVISION): Single<ResponseBody> | ||||
|  | ||||
|     @GET("$MAGISK_FILES/{$REVISION}/bootctl") | ||||
|     @Streaming | ||||
|     fun fetchBootctl(@Path(REVISION) revision: String = Constants.BOOTCTL_REVISION): Single<ResponseBody> | ||||
|  | ||||
|     //endregion | ||||
|  | ||||
|     /** | ||||
|      * This method shall be used exclusively for fetching files from urls from previous requests. | ||||
|      * Him, who uses it in a wrong way, shall die in an eternal flame. | ||||
|      * */ | ||||
|     @GET | ||||
|     @Streaming | ||||
|     fun fetchFile(@Url url: String): Single<ResponseBody> | ||||
|  | ||||
|  | ||||
|     companion object { | ||||
|         private const val REVISION = "revision" | ||||
|         private const val MODULE = "module" | ||||
|         private const val FILE = "file" | ||||
|  | ||||
|  | ||||
|         private const val MAGISK_FILES = KConfig.DEFAULT_CHANNEL | ||||
|         private const val MAGISK_MASTER = "topjohnwu/Magisk/master" | ||||
|         private const val MAGISK_MODULES = "Magisk-Modules-Repo" | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,15 @@ | ||||
| package com.topjohnwu.magisk.data.repository | ||||
|  | ||||
| import com.topjohnwu.magisk.data.database.PolicyDao | ||||
| import com.topjohnwu.magisk.model.entity.MagiskPolicy | ||||
|  | ||||
| class AppRepository(private val policyDao: PolicyDao) { | ||||
|  | ||||
|     fun deleteOutdated() = policyDao.deleteOutdated() | ||||
|     fun delete(packageName: String) = policyDao.delete(packageName) | ||||
|     fun delete(uid: Int) = policyDao.delete(uid) | ||||
|     fun fetch(uid: Int) = policyDao.fetch(uid) | ||||
|     fun fetchAll() = policyDao.fetchAll() | ||||
|     fun update(policy: MagiskPolicy) = policyDao.update(policy) | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,43 @@ | ||||
| package com.topjohnwu.magisk.data.repository | ||||
|  | ||||
| import com.topjohnwu.magisk.Const | ||||
| import com.topjohnwu.magisk.Constants | ||||
| import com.topjohnwu.magisk.data.database.LogDao | ||||
| import com.topjohnwu.magisk.data.database.base.suRaw | ||||
| import com.topjohnwu.magisk.model.entity.MagiskLog | ||||
| import com.topjohnwu.magisk.model.entity.WrappedMagiskLog | ||||
| import com.topjohnwu.magisk.utils.toSingle | ||||
| import com.topjohnwu.superuser.Shell | ||||
| import timber.log.Timber | ||||
| import java.util.concurrent.TimeUnit | ||||
|  | ||||
|  | ||||
| class LogRepository( | ||||
|     private val logDao: LogDao | ||||
| ) { | ||||
|  | ||||
|     fun fetchLogs() = logDao.fetchAll() | ||||
|         .map { it.sortByDescending { it.date.time }; it } | ||||
|         .map { it.wrap() } | ||||
|  | ||||
|     fun fetchMagiskLogs() = "tail -n 5000 ${Constants.MAGISK_LOG}".suRaw() | ||||
|         .filter { it.isNotEmpty() } | ||||
|         .map { Timber.i(it.toString()); it } | ||||
|  | ||||
|     fun clearLogs() = logDao.deleteAll() | ||||
|     fun clearOutdated() = logDao.deleteOutdated() | ||||
|  | ||||
|     fun clearMagiskLogs() = Shell.su("echo -n > " + Const.MAGISK_LOG) | ||||
|         .toSingle() | ||||
|         .map { it.exec() } | ||||
|  | ||||
|     fun put(log: MagiskLog) = logDao.put(log) | ||||
|  | ||||
|     private fun List<MagiskLog>.wrap(): List<WrappedMagiskLog> { | ||||
|         val day = TimeUnit.DAYS.toMillis(1) | ||||
|         return groupBy { it.date.time / day } | ||||
|             .map { WrappedMagiskLog(it.key * day, it.value) } | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,130 @@ | ||||
| package com.topjohnwu.magisk.data.repository | ||||
|  | ||||
| import android.content.Context | ||||
| import android.content.pm.PackageManager | ||||
| import com.topjohnwu.magisk.App | ||||
| import com.topjohnwu.magisk.Config | ||||
| import com.topjohnwu.magisk.KConfig | ||||
| import com.topjohnwu.magisk.data.database.base.su | ||||
| import com.topjohnwu.magisk.data.database.base.suRaw | ||||
| import com.topjohnwu.magisk.data.network.GithubRawApiServices | ||||
| import com.topjohnwu.magisk.model.entity.HideAppInfo | ||||
| import com.topjohnwu.magisk.model.entity.HideTarget | ||||
| import com.topjohnwu.magisk.model.entity.Version | ||||
| import com.topjohnwu.magisk.utils.Utils | ||||
| import com.topjohnwu.magisk.utils.inject | ||||
| import com.topjohnwu.magisk.utils.toSingle | ||||
| import com.topjohnwu.magisk.utils.writeToFile | ||||
| import com.topjohnwu.superuser.Shell | ||||
| import io.reactivex.Single | ||||
| import io.reactivex.functions.BiFunction | ||||
|  | ||||
| class MagiskRepository( | ||||
|     private val context: Context, | ||||
|     private val apiRaw: GithubRawApiServices, | ||||
|     private val packageManager: PackageManager | ||||
| ) { | ||||
|  | ||||
|     fun fetchMagisk() = fetchConfig() | ||||
|         .flatMap { apiRaw.fetchFile(it.magisk.link) } | ||||
|         .map { it.writeToFile(context, FILE_MAGISK_ZIP) } | ||||
|  | ||||
|     fun fetchManager() = fetchConfig() | ||||
|         .flatMap { apiRaw.fetchFile(it.app.link) } | ||||
|         .map { it.writeToFile(context, FILE_MAGISK_APK) } | ||||
|  | ||||
|     fun fetchUninstaller() = fetchConfig() | ||||
|         .flatMap { apiRaw.fetchFile(it.uninstaller.link) } | ||||
|         .map { it.writeToFile(context, FILE_UNINSTALLER_ZIP) } | ||||
|  | ||||
|     fun fetchSafetynet() = apiRaw | ||||
|         .fetchSafetynet() | ||||
|         .map { it.writeToFile(context, FILE_SAFETY_NET_APK) } | ||||
|  | ||||
|     fun fetchBootctl() = apiRaw | ||||
|         .fetchBootctl() | ||||
|         .map { it.writeToFile(context, FILE_BOOTCTL_SH) } | ||||
|  | ||||
|  | ||||
|     fun fetchConfig() = when (KConfig.updateChannel) { | ||||
|         KConfig.UpdateChannel.STABLE -> apiRaw.fetchConfig() | ||||
|         KConfig.UpdateChannel.BETA -> apiRaw.fetchBetaConfig() | ||||
|         KConfig.UpdateChannel.CANARY -> apiRaw.fetchCanaryConfig() | ||||
|         KConfig.UpdateChannel.CANARY_DEBUG -> apiRaw.fetchCanaryDebugConfig() | ||||
|         KConfig.UpdateChannel.CUSTOM -> apiRaw.fetchCustomConfig(KConfig.customUpdateChannel) | ||||
|     } | ||||
|     .doOnSuccess { | ||||
|         Config.remoteMagiskVersionCode = it.magisk.versionCode.toIntOrNull() ?: -1 | ||||
|         Config.magiskLink = it.magisk.link | ||||
|         Config.magiskNoteLink = it.magisk.note | ||||
|         Config.magiskMD5 = it.magisk.hash | ||||
|         Config.remoteManagerVersionCode = it.app.versionCode.toIntOrNull() ?: -1 | ||||
|         Config.remoteManagerVersionString = it.app.version | ||||
|         Config.managerLink = it.app.link | ||||
|         Config.managerNoteLink = it.app.note | ||||
|         Config.uninstallerLink = it.uninstaller.link | ||||
|     } | ||||
|  | ||||
|  | ||||
|     fun fetchMagiskVersion(): Single<Version> = Single.zip( | ||||
|         fetchMagiskVersionName(), | ||||
|         fetchMagiskVersionCode(), | ||||
|         BiFunction { versionName, versionCode -> | ||||
|             Version(versionName, versionCode) | ||||
|         } | ||||
|     ) | ||||
|  | ||||
|  | ||||
|     fun fetchApps() = | ||||
|         Single.fromCallable { packageManager.getInstalledApplications(0) } | ||||
|             .flattenAsFlowable { it } | ||||
|             .filter { it.enabled && !blacklist.contains(it.packageName) } | ||||
|             .map { | ||||
|                 val label = Utils.getAppLabel(it, packageManager) | ||||
|                 val icon = it.loadIcon(packageManager) | ||||
|                 HideAppInfo(it, label, icon) | ||||
|             } | ||||
|             .filter { it.processes.isNotEmpty() } | ||||
|             .toList() | ||||
|  | ||||
|     fun fetchHideTargets() = Shell.su("magiskhide --ls").toSingle() | ||||
|         .map { it.exec().out } | ||||
|         .flattenAsFlowable { it } | ||||
|         .map { HideTarget(it) } | ||||
|         .toList() | ||||
|  | ||||
|     private fun fetchMagiskVersionName() = "magisk -v".suRaw() | ||||
|         .map { it.first() } | ||||
|         .map { it.substring(0 until it.indexOf(":")) } | ||||
|         .onErrorReturn { "Unknown" } | ||||
|  | ||||
|     private fun fetchMagiskVersionCode() = "magisk -V".suRaw() | ||||
|         .map { it.first() } | ||||
|         .map { it.toIntOrNull() ?: -1 } | ||||
|         .onErrorReturn { -1 } | ||||
|  | ||||
|     fun toggleHide(isEnabled: Boolean, packageName: String, process: String) = | ||||
|         "magiskhide --%s %s %s".format(isEnabled.state, packageName, process).su().ignoreElement() | ||||
|  | ||||
|     private val Boolean.state get() = if (this) "add" else "rm" | ||||
|  | ||||
|     companion object { | ||||
|         const val FILE_MAGISK_ZIP = "magisk.zip" | ||||
|         const val FILE_MAGISK_APK = "magisk.apk" | ||||
|         const val FILE_UNINSTALLER_ZIP = "uninstaller.zip" | ||||
|         const val FILE_SAFETY_NET_APK = "safetynet.apk" | ||||
|         const val FILE_BOOTCTL_SH = "bootctl" | ||||
|  | ||||
|         private val blacklist = listOf( | ||||
|             let { val app: App by inject(); app }.packageName, | ||||
|             "android", | ||||
|             "com.android.chrome", | ||||
|             "com.chrome.beta", | ||||
|             "com.chrome.dev", | ||||
|             "com.chrome.canary", | ||||
|             "com.android.webview", | ||||
|             "com.google.android.webview" | ||||
|         ) | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,11 @@ | ||||
| package com.topjohnwu.magisk.data.repository | ||||
|  | ||||
| import com.topjohnwu.magisk.data.database.SettingsDao | ||||
|  | ||||
| class SettingRepository(private val settingsDao: SettingsDao) { | ||||
|  | ||||
|     fun fetch(key: String, default: Int) = settingsDao.fetch(key, default) | ||||
|     fun put(key: String, value: Int) = settingsDao.put(key, value) | ||||
|     fun delete(key: String) = settingsDao.delete(key) | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,11 @@ | ||||
| package com.topjohnwu.magisk.data.repository | ||||
|  | ||||
| import com.topjohnwu.magisk.data.database.StringDao | ||||
|  | ||||
| class StringRepository(private val stringDao: StringDao) { | ||||
|  | ||||
|     fun fetch(key: String, default: String) = stringDao.fetch(key, default) | ||||
|     fun put(key: String, value: String) = stringDao.put(key, value) | ||||
|     fun delete(key: String) = stringDao.delete(key) | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,18 @@ | ||||
| package com.topjohnwu.magisk.di | ||||
|  | ||||
| import android.content.Context | ||||
| import androidx.preference.PreferenceManager | ||||
| import com.skoumal.teanity.rxbus.RxBus | ||||
| import com.topjohnwu.magisk.App | ||||
| import org.koin.dsl.module | ||||
|  | ||||
|  | ||||
| val applicationModule = module { | ||||
|     single { RxBus() } | ||||
|     factory { get<Context>().resources } | ||||
|     factory { get<Context>() as App } | ||||
|     factory { get<Context>().packageManager } | ||||
|     factory(Protected) { get<App>().protectedContext } | ||||
|     single(SUTimeout) { get<Context>(Protected).getSharedPreferences("su_timeout", 0) } | ||||
|     single { PreferenceManager.getDefaultSharedPreferences(get<Context>(Protected)) } | ||||
| } | ||||
							
								
								
									
										15
									
								
								app/src/main/java/com/topjohnwu/magisk/di/DatabaseModule.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								app/src/main/java/com/topjohnwu/magisk/di/DatabaseModule.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| package com.topjohnwu.magisk.di | ||||
|  | ||||
| import com.topjohnwu.magisk.data.database.* | ||||
| import com.topjohnwu.magisk.tasks.UpdateRepos | ||||
| import org.koin.dsl.module | ||||
|  | ||||
|  | ||||
| val databaseModule = module { | ||||
|     single { LogDao() } | ||||
|     single { PolicyDao(get()) } | ||||
|     single { SettingsDao() } | ||||
|     single { StringDao() } | ||||
|     single { RepoDatabaseHelper(get()) } | ||||
|     single { UpdateRepos(get()) } | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user