mirror of
				https://github.com/topjohnwu/Magisk
				synced 2025-10-31 10:40:52 +01:00 
			
		
		
		
	Compare commits
	
		
			247 Commits
		
	
	
		
			manager-v5
			...
			manager-v5
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 0c782edf21 | ||
|   | e3948d295e | ||
|   | 5f2c742a5c | ||
|   | b30c77aab9 | ||
|   | a5916b9c49 | ||
|   | 453180e30b | ||
|   | 8bd432d391 | ||
|   | c9d3e20aef | ||
|   | d5408d1f09 | ||
|   | f334532aba | ||
|   | be77c09f3d | ||
|   | 7de6a92753 | ||
|   | 36f76f5a14 | ||
|   | b84523d557 | ||
|   | 2c78c415e9 | ||
|   | 79ccb30dd2 | ||
|   | 3c566becf6 | ||
|   | 151ca593af | ||
|   | 4132eacba0 | ||
|   | 06e6151816 | ||
|   | 70277d4edd | ||
|   | d21d2f1a9c | ||
|   | 74a7be996f | ||
|   | 3f38579529 | ||
|   | 4d5a9f6e15 | ||
|   | 41f47acd76 | ||
|   | 821dcaa7c7 | ||
|   | 7135d26419 | ||
|   | f7fd354dce | ||
|   | 0c69a65bc4 | ||
|   | 2f2ca5eab4 | ||
|   | df9c40c035 | ||
|   | 25b67017e4 | ||
|   | bc9c3346f3 | ||
|   | 1db7e19fe8 | ||
|   | 102c03ce2b | ||
|   | ec19eb4455 | ||
|   | 6d9924d50e | ||
|   | 16c4d74274 | ||
|   | e4af5fd36a | ||
|   | 702775493a | ||
|   | b2ae826066 | ||
|   | cc3e9990fa | ||
|   | 271cbddd5e | ||
|   | c1423ca9ad | ||
|   | 74379150a1 | ||
|   | c840a30c30 | ||
|   | ae5277a898 | ||
|   | bffa837825 | ||
|   | b9e7d0faea | ||
|   | 860b08d9ed | ||
|   | 691dc1d49e | ||
|   | 9d6886d367 | ||
|   | 9589b68f5a | ||
|   | 28d88af1af | ||
|   | 8b5acd1849 | ||
|   | 33dc63a7fd | ||
|   | d0a86385b7 | ||
|   | 50a49e2c8c | ||
|   | c60adb113e | ||
|   | aee015e8f6 | ||
|   | bf6af29205 | ||
|   | 329905d472 | ||
|   | 00d450d262 | ||
|   | 2365d1bd20 | ||
|   | 5b385c18e5 | ||
|   | 98c0434ec0 | ||
|   | f318d0a3bc | ||
|   | 27f5b410c0 | ||
|   | 3f55be9676 | ||
|   | b05d2d3a2d | ||
|   | 19af5f9e0b | ||
|   | f37f330670 | ||
|   | 40082d4571 | ||
|   | 00d655f346 | ||
|   | 821726e7c0 | ||
|   | 759e905c3c | ||
|   | 8bf7e42913 | ||
|   | 0dcd073554 | ||
|   | 2fe35d578d | ||
|   | 8d139e156e | ||
|   | 7c2849356a | ||
|   | 0025ffd1c0 | ||
|   | 2ef7146642 | ||
|   | 1b27e69e40 | ||
|   | 8e7b757efd | ||
|   | 1ab543cea1 | ||
|   | a3f86903e4 | ||
|   | c239c305ab | ||
|   | 2e02af994e | ||
|   | 836d9afe17 | ||
|   | 007a352742 | ||
|   | e526e5659e | ||
|   | 4a5227c7bf | ||
|   | c2c151ec4c | ||
|   | 452096e7e4 | ||
|   | 50c2a9859e | ||
|   | 677b667307 | ||
|   | 1adf331268 | ||
|   | 349b3e961b | ||
|   | 96650c06f0 | ||
|   | 26038a0a07 | ||
|   | 6a148b5dd9 | ||
|   | 0e109ef979 | ||
|   | de2285d5e9 | ||
|   | b2483ba437 | ||
|   | a82a5e5a49 | ||
|   | d161a02e71 | ||
|   | d2b6a700b1 | ||
|   | af203cef24 | ||
|   | 673e917e76 | ||
|   | a3bd41db54 | ||
|   | 0d9527921a | ||
|   | f0e4aec0af | ||
|   | b0d65b5edd | ||
|   | 75532ef591 | ||
|   | 9a6d1bd700 | ||
|   | a7ed6c15d3 | ||
|   | 5ee49ba065 | ||
|   | d34bd47bea | ||
|   | f17792380b | ||
|   | c11920110e | ||
|   | ec5a993fea | ||
|   | d250c2cc89 | ||
|   | 767e73f40c | ||
|   | 3f699c9d2f | ||
|   | 50dbd9befd | ||
|   | 760e01bf92 | ||
|   | 543f435b1e | ||
|   | 91337218b3 | ||
|   | afff3c0a49 | ||
|   | a1871e4bc3 | ||
|   | 3aa0294cd4 | ||
|   | 310b266251 | ||
|   | 21b1b5098e | ||
|   | a3a4a5d8a5 | ||
|   | 270536f33c | ||
|   | 66bb433cc6 | ||
|   | bd4ef1a03a | ||
|   | aa2d9a3bf1 | ||
|   | fd6cbb138c | ||
|   | aa75c8e5e4 | ||
|   | c461fc6daa | ||
|   | 96eaa833f5 | ||
|   | 863b13a694 | ||
|   | e6fea4e6dd | ||
|   | 83bfc13056 | ||
|   | bc4f09209b | ||
|   | 967ca17238 | ||
|   | 595c72147c | ||
|   | f3c3b5a649 | ||
|   | 1cd2c5e653 | ||
|   | b2873dd44b | ||
|   | bb80ab4026 | ||
|   | 80cabb338b | ||
|   | 2c69e2c151 | ||
|   | c1dd23f5e0 | ||
|   | f93624a41c | ||
|   | 9f4559a059 | ||
|   | fd05cad303 | ||
|   | d58b06e493 | ||
|   | 2f0b549027 | ||
|   | 87dbd7e541 | ||
|   | 96e5da36be | ||
|   | 43745edac0 | ||
|   | f5ceee547c | ||
|   | b612bce779 | ||
|   | 2e88e5e9c7 | ||
|   | 9a7aa25c90 | ||
|   | c4420fe932 | ||
|   | a5260f3a95 | ||
|   | 47ccf4b1f5 | ||
|   | a356b21895 | ||
|   | 614a36c888 | ||
|   | f520fe36bd | ||
|   | 7273a1c34d | ||
|   | dc45cbce37 | ||
|   | 708d8f75c0 | ||
|   | bd37d90228 | ||
|   | b1ad691464 | ||
|   | f4e7baf31e | ||
|   | c0e60c41f2 | ||
|   | c8dad43e00 | ||
|   | a8f124704d | ||
|   | eed2816491 | ||
|   | a6334b3e35 | ||
|   | 334beebfeb | ||
|   | 13dad848bd | ||
|   | e518f4cef8 | ||
|   | c8fd5da2da | ||
|   | 3a74729ecc | ||
|   | 49c672ac4d | ||
|   | b570cb5b77 | ||
|   | 97bf388471 | ||
|   | 1a32aaea6f | ||
|   | 4635883dec | ||
|   | 3ba6db4a50 | ||
|   | 2f1de25747 | ||
|   | f60fd42ac0 | ||
|   | ecc8f9c792 | ||
|   | e295dfdcf7 | ||
|   | fc42c25390 | ||
|   | 27d5858e06 | ||
|   | e1ef732b60 | ||
|   | 9840b95c21 | ||
|   | a6f8446d81 | ||
|   | c1c844c830 | ||
|   | 389299afd1 | ||
|   | 826543a291 | ||
|   | 4ac83cfded | ||
|   | 64c363ce53 | ||
|   | cca4347bf9 | ||
|   | 3ae3d4926a | ||
|   | 36025d6d9f | ||
|   | e171362e3e | ||
|   | 3e0bf2ae15 | ||
|   | 07aa9f4b8b | ||
|   | b2d9f3fc64 | ||
|   | 5fb3e9167e | ||
|   | 99c74b31be | ||
|   | ce5b13824e | ||
|   | c39170c42e | ||
|   | fd19fbf300 | ||
|   | 166469827f | ||
|   | a34ed538b6 | ||
|   | 5f22d3e055 | ||
|   | fdd700f3e5 | ||
|   | adf930f126 | ||
|   | 05f41928cd | ||
|   | 2ee0829871 | ||
|   | 743560825d | ||
|   | e3d84ac349 | ||
|   | 266c832b30 | ||
|   | f5374a024e | ||
|   | 4956d826fb | ||
|   | f5cc2af5d0 | ||
|   | 5880d4a6ec | ||
|   | ae05dce958 | ||
|   | 9ebe372a9a | ||
|   | e6e04cc5b3 | ||
|   | 12352510fd | ||
|   | 2b3d927937 | ||
|   | a8890740f5 | ||
|   | f60d7ee54b | ||
|   | 896ca2ef6b | ||
|   | c036f6d529 | ||
|   | 6f457c0c59 | 
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -5,8 +5,8 @@ | ||||
| /build | ||||
| app/release | ||||
| *.hprof | ||||
| app/.externalNativeBuild/ | ||||
| *.sh | ||||
| .externalNativeBuild/ | ||||
| src/main/assets | ||||
| public.certificate.x509.pem | ||||
| private.key.pk8 | ||||
| *.apk | ||||
|   | ||||
| @@ -1,7 +1,2 @@ | ||||
| # Magisk Manager | ||||
| This is one of the submodules used in Magisk. The project is licensed under GPL v3 (or newer). | ||||
| More info are written in the [Magisk Main Repo](https://github.com/topjohnwu/Magisk) | ||||
|  | ||||
| ## Building Notes | ||||
| You need to install CMake and NDK to build the zipadjust library. | ||||
| There are several files required to let Magisk Manager work properly, and they can be copied by using the build script in the [Magisk Main Repo](https://github.com/topjohnwu/Magisk). These files are: `magisk_uninstaller.sh`, `util_functions.sh`, `public.certificate.x509.pem`, and `private.key.pk8` under the `app/src/main/assets` folder. | ||||
| This repo is no longer an independent component. It is a submodule of the [Magisk Project](https://github.com/topjohnwu/Magisk). | ||||
|   | ||||
							
								
								
									
										1
									
								
								app/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								app/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1 +0,0 @@ | ||||
| /build | ||||
| @@ -1,66 +0,0 @@ | ||||
| apply plugin: 'com.android.application' | ||||
|  | ||||
| android { | ||||
|     compileSdkVersion 26 | ||||
|     buildToolsVersion "26.0.2" | ||||
|  | ||||
|     defaultConfig { | ||||
|         applicationId "com.topjohnwu.magisk" | ||||
|         minSdkVersion 21 | ||||
|         targetSdkVersion 26 | ||||
|         versionCode 57 | ||||
|         versionName "5.4.0" | ||||
|         ndk { | ||||
|             moduleName 'zipadjust' | ||||
|             abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a' | ||||
|         } | ||||
|         javaCompileOptions { | ||||
|             annotationProcessorOptions { | ||||
|                 argument('butterknife.debuggable', 'false') | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     buildTypes { | ||||
|         release { | ||||
|             minifyEnabled true | ||||
|             shrinkResources true | ||||
|             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | ||||
|         } | ||||
|     } | ||||
|     compileOptions { | ||||
|         sourceCompatibility JavaVersion.VERSION_1_8 | ||||
|         targetCompatibility JavaVersion.VERSION_1_8 | ||||
|     } | ||||
|     dexOptions { | ||||
|         preDexLibraries true | ||||
|         javaMaxHeapSize "2g" | ||||
|     } | ||||
|     externalNativeBuild { | ||||
|         cmake { | ||||
|             path 'src/main/jni/CMakeLists.txt' | ||||
|         } | ||||
|     } | ||||
|     lintOptions { | ||||
|         disable 'MissingTranslation' | ||||
|     } | ||||
| } | ||||
| repositories { | ||||
|     jcenter() | ||||
|     maven { url "https://jitpack.io" } | ||||
|     maven { url "https://maven.google.com" } | ||||
| } | ||||
|  | ||||
| dependencies { | ||||
|     implementation fileTree(include: ['*.jar'], dir: 'libs') | ||||
|     implementation project(':common') | ||||
|     implementation project(':jarsigner') | ||||
|     implementation 'com.android.support:recyclerview-v7:26.1.0' | ||||
|     implementation 'com.android.support:cardview-v7:26.1.0' | ||||
|     implementation 'com.android.support:design:26.1.0' | ||||
|     implementation 'com.android.support:support-v4:26.1.0' | ||||
|     implementation 'com.jakewharton:butterknife:8.8.1' | ||||
|     implementation 'com.atlassian.commonmark:commonmark:0.10.0' | ||||
|     implementation 'org.kamranzafar:jtar:2.3' | ||||
|     annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1' | ||||
| } | ||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 73 KiB | 
| @@ -1,134 +0,0 @@ | ||||
| package com.topjohnwu.magisk; | ||||
|  | ||||
| import android.content.Intent; | ||||
| import android.net.Uri; | ||||
| import android.os.Bundle; | ||||
| import android.support.annotation.Nullable; | ||||
| import android.support.v7.app.ActionBar; | ||||
| import android.support.v7.app.AlertDialog; | ||||
| import android.support.v7.widget.Toolbar; | ||||
| import android.text.Html; | ||||
| import android.text.Spanned; | ||||
| import android.text.TextUtils; | ||||
| import android.text.method.LinkMovementMethod; | ||||
| import android.view.View; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import com.topjohnwu.magisk.components.AboutCardRow; | ||||
| import com.topjohnwu.magisk.components.Activity; | ||||
| import com.topjohnwu.magisk.components.AlertDialogBuilder; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.util.Locale; | ||||
|  | ||||
| import butterknife.BindView; | ||||
| import butterknife.ButterKnife; | ||||
|  | ||||
| public class AboutActivity extends Activity { | ||||
|  | ||||
|     private static final String DONATION_URL = "https://www.paypal.me/topjohnwu"; | ||||
|     private static final String XDA_THREAD = "http://forum.xda-developers.com/showthread.php?t=3432382"; | ||||
|     private static final String SOURCE_CODE_URL = "https://github.com/topjohnwu/MagiskManager"; | ||||
|  | ||||
|     @BindView(R.id.toolbar) Toolbar toolbar; | ||||
|     @BindView(R.id.app_version_info) AboutCardRow appVersionInfo; | ||||
|     @BindView(R.id.app_changelog) AboutCardRow appChangelog; | ||||
|     @BindView(R.id.app_developers) AboutCardRow appDevelopers; | ||||
|     @BindView(R.id.app_translators) AboutCardRow appTranslators; | ||||
|     @BindView(R.id.app_source_code) AboutCardRow appSourceCode; | ||||
|     @BindView(R.id.support_thread) AboutCardRow supportThread; | ||||
|     @BindView(R.id.donation) AboutCardRow donation; | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(@Nullable Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         if (getMagiskManager().isDarkTheme) { | ||||
|             setTheme(R.style.AppTheme_Transparent_Dark); | ||||
|         } | ||||
|         setContentView(R.layout.activity_about); | ||||
|         ButterKnife.bind(this); | ||||
|  | ||||
|         setSupportActionBar(toolbar); | ||||
|         toolbar.setNavigationOnClickListener(view -> finish()); | ||||
|  | ||||
|         ActionBar ab = getSupportActionBar(); | ||||
|         if (ab != null) { | ||||
|             ab.setTitle(R.string.about); | ||||
|             ab.setDisplayHomeAsUpEnabled(true); | ||||
|         } | ||||
|  | ||||
|         appVersionInfo.setSummary(String.format(Locale.US, "%s (%d)", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)); | ||||
|  | ||||
|         String changes = null; | ||||
|         try (InputStream is = getAssets().open("changelog.html")) { | ||||
|             int size = is.available(); | ||||
|  | ||||
|             byte[] buffer = new byte[size]; | ||||
|             is.read(buffer); | ||||
|  | ||||
|             changes = new String(buffer); | ||||
|         } catch (IOException ignored) { | ||||
|         } | ||||
|  | ||||
|         appChangelog.removeSummary(); | ||||
|         if (changes == null) { | ||||
|             appChangelog.setVisibility(View.GONE); | ||||
|         } else { | ||||
|             Spanned result; | ||||
|             if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { | ||||
|                 result = Html.fromHtml(changes, Html.TO_HTML_PARAGRAPH_LINES_CONSECUTIVE); | ||||
|             } else { | ||||
|                 result = Html.fromHtml(changes); | ||||
|             } | ||||
|             appChangelog.setOnClickListener(v -> { | ||||
|                 AlertDialog d = new AlertDialogBuilder(this) | ||||
|                         .setTitle(R.string.app_changelog) | ||||
|                         .setMessage(result) | ||||
|                         .setPositiveButton(android.R.string.ok, null) | ||||
|                         .show(); | ||||
|  | ||||
|                 //noinspection ConstantConditions | ||||
|                 ((TextView) d.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         appDevelopers.removeSummary(); | ||||
|         appDevelopers.setOnClickListener(view -> { | ||||
|             Spanned result; | ||||
|             if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { | ||||
|                 result = Html.fromHtml(getString(R.string.app_developers_), Html.TO_HTML_PARAGRAPH_LINES_CONSECUTIVE); | ||||
|             } else { | ||||
|                 result = Html.fromHtml(getString(R.string.app_developers_)); | ||||
|             } | ||||
|             AlertDialog d = new AlertDialogBuilder(this) | ||||
|                     .setTitle(R.string.app_developers) | ||||
|                     .setMessage(result) | ||||
|                     .setPositiveButton(android.R.string.ok, null) | ||||
|                     .create(); | ||||
|  | ||||
|             d.show(); | ||||
|             //noinspection ConstantConditions | ||||
|             ((TextView) d.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); | ||||
|         }); | ||||
|  | ||||
|         String translators = getString(R.string.translators); | ||||
|         if (TextUtils.isEmpty(translators)) { | ||||
|             appTranslators.setVisibility(View.GONE); | ||||
|         } else { | ||||
|             appTranslators.setSummary(translators); | ||||
|         } | ||||
|  | ||||
|         appSourceCode.removeSummary(); | ||||
|         appSourceCode.setOnClickListener(view -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(SOURCE_CODE_URL)))); | ||||
|  | ||||
|         supportThread.removeSummary(); | ||||
|         supportThread.setOnClickListener(view -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(XDA_THREAD)))); | ||||
|  | ||||
|         donation.removeSummary(); | ||||
|         donation.setOnClickListener(view -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(DONATION_URL)))); | ||||
|  | ||||
|         setFloating(); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,153 +0,0 @@ | ||||
| package com.topjohnwu.magisk; | ||||
|  | ||||
| import android.content.Intent; | ||||
| import android.net.Uri; | ||||
| import android.os.Bundle; | ||||
| import android.support.v7.app.ActionBar; | ||||
| import android.support.v7.widget.RecyclerView; | ||||
| import android.support.v7.widget.Toolbar; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.Button; | ||||
| import android.widget.LinearLayout; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import com.topjohnwu.magisk.asyncs.FlashZip; | ||||
| import com.topjohnwu.magisk.asyncs.InstallMagisk; | ||||
| import com.topjohnwu.magisk.components.Activity; | ||||
| import com.topjohnwu.magisk.container.AdaptiveList; | ||||
| import com.topjohnwu.magisk.utils.Shell; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| import butterknife.BindView; | ||||
| import butterknife.ButterKnife; | ||||
| import butterknife.OnClick; | ||||
|  | ||||
| public class FlashActivity extends Activity { | ||||
|  | ||||
|     public static final String SET_ACTION = "action"; | ||||
|     public static final String SET_BOOT = "boot"; | ||||
|     public static final String SET_ENC = "enc"; | ||||
|     public static final String SET_VERITY = "verity"; | ||||
|  | ||||
|     public static final String FLASH_ZIP = "flash"; | ||||
|     public static final String PATCH_BOOT = "patch"; | ||||
|     public static final String FLASH_MAGISK = "magisk"; | ||||
|  | ||||
|     @BindView(R.id.toolbar) Toolbar toolbar; | ||||
|     @BindView(R.id.flash_logs) RecyclerView flashLogs; | ||||
|     @BindView(R.id.button_panel) LinearLayout buttonPanel; | ||||
|     @BindView(R.id.reboot) Button reboot; | ||||
|  | ||||
|     @OnClick(R.id.no_thanks) | ||||
|     public void dismiss() { | ||||
|         finish(); | ||||
|     } | ||||
|  | ||||
|     @OnClick(R.id.reboot) | ||||
|     public void reboot() { | ||||
|         getShell().su_raw("reboot"); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_flash); | ||||
|         ButterKnife.bind(this); | ||||
|         AdaptiveList<String> rootShellOutput = new AdaptiveList<>(flashLogs); | ||||
|         setSupportActionBar(toolbar); | ||||
|         ActionBar ab = getSupportActionBar(); | ||||
|         if (ab != null) { | ||||
|             ab.setTitle(R.string.flashing); | ||||
|         } | ||||
|         setFloating(); | ||||
|         setFinishOnTouchOutside(false); | ||||
|         if (!Shell.rootAccess()) | ||||
|             reboot.setVisibility(View.GONE); | ||||
|  | ||||
|         flashLogs.setAdapter(new FlashLogAdapter(rootShellOutput)); | ||||
|  | ||||
|         // We must receive a Uri of the target zip | ||||
|         Intent intent = getIntent(); | ||||
|         Uri uri = intent.getData(); | ||||
|  | ||||
|         boolean keepEnc = intent.getBooleanExtra(SET_ENC, false); | ||||
|         boolean keepVerity = intent.getBooleanExtra(SET_VERITY, false); | ||||
|  | ||||
|         switch (getIntent().getStringExtra(SET_ACTION)) { | ||||
|             case FLASH_ZIP: | ||||
|                 new FlashZip(this, uri, rootShellOutput) | ||||
|                         .setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE)) | ||||
|                         .exec(); | ||||
|                 break; | ||||
|             case PATCH_BOOT: | ||||
|                 new InstallMagisk(this, rootShellOutput, uri, keepEnc, keepVerity, (Uri) intent.getParcelableExtra(SET_BOOT)) | ||||
|                         .setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE)) | ||||
|                         .exec(); | ||||
|                 break; | ||||
|             case FLASH_MAGISK: | ||||
|                 String boot = intent.getStringExtra(SET_BOOT); | ||||
|                 if (getMagiskManager().remoteMagiskVersionCode < 1370) { | ||||
|                     // Use legacy installation method | ||||
|                     getShell().su_raw( | ||||
|                             "echo \"BOOTIMAGE=" + boot + "\" > /dev/.magisk", | ||||
|                             "echo \"KEEPFORCEENCRYPT=" + keepEnc + "\" >> /dev/.magisk", | ||||
|                             "echo \"KEEPVERITY=" + keepVerity + "\" >> /dev/.magisk" | ||||
|                     ); | ||||
|                     new FlashZip(this, uri, rootShellOutput) | ||||
|                             .setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE)) | ||||
|                             .exec(); | ||||
|                 } else { | ||||
|                     // Use new installation method | ||||
|                     new InstallMagisk(this, rootShellOutput, uri, keepEnc, keepVerity, boot) | ||||
|                             .setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE)) | ||||
|                             .exec(); | ||||
|                 } | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onBackPressed() { | ||||
|         // Prevent user accidentally press back button | ||||
|     } | ||||
|  | ||||
|     private static class FlashLogAdapter extends RecyclerView.Adapter<ViewHolder> { | ||||
|  | ||||
|         private List<String> mList; | ||||
|  | ||||
|         FlashLogAdapter(List<String> list) { | ||||
|             mList = list; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { | ||||
|             View view = LayoutInflater.from(parent.getContext()) | ||||
|                     .inflate(R.layout.list_item_flashlog, parent, false); | ||||
|             return new ViewHolder(view); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onBindViewHolder(ViewHolder holder, int position) { | ||||
|             holder.text.setText(mList.get(position)); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public int getItemCount() { | ||||
|             return mList.size(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static class ViewHolder extends RecyclerView.ViewHolder { | ||||
|  | ||||
|         @BindView(R.id.textView) TextView text; | ||||
|  | ||||
|         public ViewHolder(View itemView) { | ||||
|             super(itemView); | ||||
|             ButterKnife.bind(this, itemView); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,24 +0,0 @@ | ||||
| package com.topjohnwu.magisk; | ||||
|  | ||||
| import android.content.Intent; | ||||
| import android.os.Bundle; | ||||
|  | ||||
| import com.topjohnwu.magisk.components.Activity; | ||||
|  | ||||
| public class SplashActivity extends Activity { | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|  | ||||
|         getMagiskManager().startup(); | ||||
|  | ||||
|         Intent intent = new Intent(this, MainActivity.class); | ||||
|         String section = getIntent().getStringExtra(MagiskManager.INTENT_SECTION); | ||||
|         if (section != null) { | ||||
|             intent.putExtra(MagiskManager.INTENT_SECTION, section); | ||||
|         } | ||||
|         startActivity(intent); | ||||
|         finish(); | ||||
|     } | ||||
| } | ||||
| @@ -1,84 +0,0 @@ | ||||
| package com.topjohnwu.magisk.asyncs; | ||||
|  | ||||
| import android.support.v4.app.FragmentActivity; | ||||
|  | ||||
| import com.topjohnwu.jarsigner.ByteArrayStream; | ||||
| import com.topjohnwu.magisk.MagiskManager; | ||||
| import com.topjohnwu.magisk.utils.WebService; | ||||
|  | ||||
| import java.io.BufferedOutputStream; | ||||
| import java.io.File; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.OutputStream; | ||||
| import java.lang.reflect.Proxy; | ||||
| import java.net.HttpURLConnection; | ||||
|  | ||||
| import dalvik.system.DexClassLoader; | ||||
|  | ||||
| public class CheckSafetyNet extends ParallelTask<Void, Void, Exception> { | ||||
|  | ||||
|     public static final int SNET_VER = 2; | ||||
|  | ||||
|     private static final String SNET_URL = "https://github.com/topjohnwu/MagiskManager/releases/download/v5.4.0/snet.apk"; | ||||
|     private static final String PKG = "com.topjohnwu.snet"; | ||||
|  | ||||
|     private File dexPath; | ||||
|     private DexClassLoader loader; | ||||
|  | ||||
|     public CheckSafetyNet(FragmentActivity activity) { | ||||
|         super(activity); | ||||
|         dexPath = new File(activity.getCacheDir().getParent() + "/snet", "snet.apk"); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onPreExecute() { | ||||
|         MagiskManager mm = getMagiskManager(); | ||||
|         if (mm.snet_version != CheckSafetyNet.SNET_VER) { | ||||
|             getShell().sh("rm -rf " + dexPath.getParent()); | ||||
|         } | ||||
|         mm.snet_version = CheckSafetyNet.SNET_VER; | ||||
|         mm.prefs.edit().putInt("snet_version", CheckSafetyNet.SNET_VER).apply(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected Exception doInBackground(Void... voids) { | ||||
|         try { | ||||
|             if (!dexPath.exists()) { | ||||
|                 HttpURLConnection conn = WebService.request(SNET_URL, null); | ||||
|                 ByteArrayStream bas = new ByteArrayStream(); | ||||
|                 bas.readFrom(conn.getInputStream()); | ||||
|                 conn.disconnect(); | ||||
|                 dexPath.getParentFile().mkdir(); | ||||
|                 try (OutputStream out = new BufferedOutputStream(new FileOutputStream(dexPath))) { | ||||
|                     bas.writeTo(out); | ||||
|                     out.flush(); | ||||
|                 } | ||||
|             } | ||||
|             loader = new DexClassLoader(dexPath.toString(), dexPath.getParent(), | ||||
|                     null, ClassLoader.getSystemClassLoader()); | ||||
|         } catch (Exception e) { | ||||
|             return e; | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onPostExecute(Exception err) { | ||||
|         try { | ||||
|             if (err != null) throw err; | ||||
|             Class<?> helperClazz = loader.loadClass(PKG + ".SafetyNetHelper"); | ||||
|             Class<?> callbackClazz = loader.loadClass(PKG + ".SafetyNetCallback"); | ||||
|             Object helper = helperClazz.getConstructors()[0].newInstance( | ||||
|                     getActivity(), Proxy.newProxyInstance( | ||||
|                             loader, new Class[] { callbackClazz }, (proxy, method, args) -> { | ||||
|                                 getMagiskManager().safetyNetDone.publish(false, args[0]); | ||||
|                                 return null; | ||||
|                             })); | ||||
|             helperClazz.getMethod("attest").invoke(helper); | ||||
|         } catch (Exception e) { | ||||
|             e.printStackTrace(); | ||||
|             getMagiskManager().safetyNetDone.publish(false, -1); | ||||
|         } | ||||
|         super.onPostExecute(err); | ||||
|     } | ||||
| } | ||||
| @@ -1,64 +0,0 @@ | ||||
| package com.topjohnwu.magisk.asyncs; | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.os.Build; | ||||
|  | ||||
| import com.topjohnwu.magisk.MagiskManager; | ||||
| import com.topjohnwu.magisk.utils.Utils; | ||||
| import com.topjohnwu.magisk.utils.WebService; | ||||
|  | ||||
| import java.io.BufferedInputStream; | ||||
| import java.io.File; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.net.HttpURLConnection; | ||||
|  | ||||
| public class DownloadBusybox extends ParallelTask<Void, Void, Void> { | ||||
|  | ||||
|     private static final String BUSYBOX_ARM = "https://github.com/topjohnwu/ndk-busybox/releases/download/1.27.2/busybox-arm"; | ||||
|     private static final String BUSYBOX_X86 = "https://github.com/topjohnwu/ndk-busybox/releases/download/1.27.2/busybox-x86"; | ||||
|  | ||||
|     private File busybox; | ||||
|  | ||||
|     public DownloadBusybox(Context context) { | ||||
|         super(context); | ||||
|         busybox = new File(context.getCacheDir(), "busybox"); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected Void doInBackground(Void... voids) { | ||||
|         Context context = getMagiskManager(); | ||||
|         Utils.removeItem(getShell(), context.getApplicationInfo().dataDir + "/busybox"); | ||||
|         try { | ||||
|             FileOutputStream out  = new FileOutputStream(busybox); | ||||
|             HttpURLConnection conn = WebService.request( | ||||
|                     Build.SUPPORTED_32_BIT_ABIS[0].contains("x86") ? | ||||
|                             BUSYBOX_X86 : | ||||
|                             BUSYBOX_ARM, | ||||
|                     null | ||||
|             ); | ||||
|             if (conn == null) throw new IOException(); | ||||
|             BufferedInputStream bis = new BufferedInputStream(conn.getInputStream()); | ||||
|             byte[] buffer = new byte[4096]; | ||||
|             int len; | ||||
|             while ((len = bis.read(buffer)) != -1) { | ||||
|                 out.write(buffer, 0, len); | ||||
|             } | ||||
|             out.close(); | ||||
|             conn.disconnect(); | ||||
|         } catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|         if (busybox.exists()) { | ||||
|             getShell().su( | ||||
|                     "rm -rf " + MagiskManager.BUSYBOXPATH, | ||||
|                     "mkdir -p " + MagiskManager.BUSYBOXPATH, | ||||
|                     "cp " + busybox + " " + MagiskManager.BUSYBOXPATH, | ||||
|                     "chmod -R 755 " + MagiskManager.BUSYBOXPATH, | ||||
|                     MagiskManager.BUSYBOXPATH + "/busybox --install -s " + MagiskManager.BUSYBOXPATH | ||||
|             ); | ||||
|             busybox.delete(); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
| } | ||||
| @@ -1,115 +0,0 @@ | ||||
| package com.topjohnwu.magisk.asyncs; | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.content.pm.PackageManager; | ||||
| import android.os.Environment; | ||||
| import android.widget.Toast; | ||||
|  | ||||
| import com.topjohnwu.jarsigner.JarMap; | ||||
| import com.topjohnwu.magisk.MagiskManager; | ||||
| import com.topjohnwu.magisk.R; | ||||
| import com.topjohnwu.magisk.container.Policy; | ||||
| import com.topjohnwu.magisk.utils.Utils; | ||||
| import com.topjohnwu.magisk.utils.ZipUtils; | ||||
|  | ||||
| import java.io.File; | ||||
| import java.util.List; | ||||
| import java.util.jar.JarEntry; | ||||
|  | ||||
| public class HideManager extends ParallelTask<Void, Void, Boolean> { | ||||
|  | ||||
|     private static final String UNHIDE_APK = "unhide.apk"; | ||||
|     private static final String ANDROID_MANIFEST = "AndroidManifest.xml"; | ||||
|     private static final byte[] UNHIDE_PKG_NAME = "com.topjohnwu.unhide\0".getBytes(); | ||||
|  | ||||
|     public HideManager(Context context) { | ||||
|         super(context); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onPreExecute() { | ||||
|         getMagiskManager().toast(R.string.hide_manager_toast, Toast.LENGTH_SHORT); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected Boolean doInBackground(Void... voids) { | ||||
|         MagiskManager mm = getMagiskManager(); | ||||
|         if (mm == null) | ||||
|             return false; | ||||
|  | ||||
|         // Generate a new unhide app with random package name | ||||
|         File unhideAPK = new File(Environment.getExternalStorageDirectory() + "/MagiskManager", "unhide.apk"); | ||||
|         unhideAPK.getParentFile().mkdirs(); | ||||
|         String pkg; | ||||
|  | ||||
|         try { | ||||
|             JarMap asset = new JarMap(mm.getAssets().open(UNHIDE_APK)); | ||||
|             JarEntry je = new JarEntry(ANDROID_MANIFEST); | ||||
|             byte xml[] = asset.getRawData(je); | ||||
|             int offset = -1; | ||||
|  | ||||
|             // Linear search pattern offset | ||||
|             for (int i = 0; i < xml.length - UNHIDE_PKG_NAME.length; ++i) { | ||||
|                 boolean match = true; | ||||
|                 for (int j = 0; j < UNHIDE_PKG_NAME.length; ++j) { | ||||
|                     if (xml[i + j] != UNHIDE_PKG_NAME[j]) { | ||||
|                         match = false; | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|                 if (match) { | ||||
|                     offset = i; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|             if (offset < 0) | ||||
|                 return false; | ||||
|  | ||||
|             // Patch binary XML with new package name | ||||
|             pkg = Utils.genPackageName("com.", UNHIDE_PKG_NAME.length - 1); | ||||
|             System.arraycopy(pkg.getBytes(), 0, xml, offset, pkg.length()); | ||||
|             asset.getOutputStream(je).write(xml); | ||||
|  | ||||
|             // Sign the APK | ||||
|             ZipUtils.signZip(mm, asset, unhideAPK, false); | ||||
|         } catch (Exception e) { | ||||
|             e.printStackTrace(); | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         // Install the application | ||||
|         List<String> ret = getShell().su("pm install " + unhideAPK + ">/dev/null && echo true || echo false"); | ||||
|         unhideAPK.delete(); | ||||
|         if (!Utils.isValidShellResponse(ret) || !Boolean.parseBoolean(ret.get(0))) | ||||
|             return false; | ||||
|  | ||||
|         try { | ||||
|             // Allow the application to gain root by default | ||||
|             PackageManager pm = mm.getPackageManager(); | ||||
|             int uid = pm.getApplicationInfo(pkg, 0).uid; | ||||
|             Policy policy = new Policy(uid, pm); | ||||
|             policy.policy = Policy.ALLOW; | ||||
|             policy.notification = false; | ||||
|             policy.logging = false; | ||||
|             mm.suDB.addPolicy(policy); | ||||
|         } catch (PackageManager.NameNotFoundException e) { | ||||
|             e.printStackTrace(); | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         // Hide myself! | ||||
|         getShell().su_raw("pm hide " + mm.getPackageName()); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onPostExecute(Boolean b) { | ||||
|         MagiskManager mm = getMagiskManager(); | ||||
|         if (mm == null) | ||||
|             return; | ||||
|         if (!b) { | ||||
|             mm.toast(R.string.hide_manager_fail_toast, Toast.LENGTH_LONG); | ||||
|         } | ||||
|         super.onPostExecute(b); | ||||
|     } | ||||
| } | ||||
| @@ -1,230 +0,0 @@ | ||||
| package com.topjohnwu.magisk.asyncs; | ||||
|  | ||||
| import android.app.Activity; | ||||
| import android.net.Uri; | ||||
| import android.os.Build; | ||||
| import android.os.Environment; | ||||
| import android.text.TextUtils; | ||||
|  | ||||
| import com.topjohnwu.magisk.MagiskManager; | ||||
| import com.topjohnwu.magisk.container.AdaptiveList; | ||||
| import com.topjohnwu.magisk.container.TarEntry; | ||||
| import com.topjohnwu.magisk.utils.Shell; | ||||
| import com.topjohnwu.magisk.utils.Utils; | ||||
| import com.topjohnwu.magisk.utils.ZipUtils; | ||||
|  | ||||
| import org.kamranzafar.jtar.TarInputStream; | ||||
| import org.kamranzafar.jtar.TarOutputStream; | ||||
|  | ||||
| import java.io.BufferedInputStream; | ||||
| import java.io.BufferedOutputStream; | ||||
| import java.io.File; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.FileNotFoundException; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.OutputStream; | ||||
| import java.util.Arrays; | ||||
| import java.util.List; | ||||
|  | ||||
| public class InstallMagisk extends ParallelTask<Void, Void, Boolean> { | ||||
|  | ||||
|     private static final int PATCH_MODE = 0; | ||||
|     private static final int DIRECT_MODE = 1; | ||||
|  | ||||
|     private Uri mBootImg, mZip; | ||||
|     private AdaptiveList<String> mList; | ||||
|     private String mBootLocation; | ||||
|     private boolean mKeepEnc, mKeepVerity; | ||||
|     private int mode; | ||||
|  | ||||
|     private InstallMagisk(Activity context, AdaptiveList<String> list, Uri zip, boolean enc, boolean verity) { | ||||
|         super(context); | ||||
|         mList = list; | ||||
|         mZip = zip; | ||||
|         mKeepEnc = enc; | ||||
|         mKeepVerity = verity; | ||||
|     } | ||||
|  | ||||
|     public InstallMagisk(Activity context, AdaptiveList<String> list, Uri zip, boolean enc, boolean verity, Uri boot) { | ||||
|         this(context, list, zip, enc, verity); | ||||
|         mBootImg = boot; | ||||
|         mode = PATCH_MODE; | ||||
|     } | ||||
|  | ||||
|     public InstallMagisk(Activity context, AdaptiveList<String> list, Uri zip, boolean enc, boolean verity, String boot) { | ||||
|         this(context, list, zip, enc, verity); | ||||
|         mBootLocation = boot; | ||||
|         mode = DIRECT_MODE; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onPreExecute() { | ||||
|         // UI updates must run in the UI thread | ||||
|         mList.setCallback(this::publishProgress); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onProgressUpdate(Void... values) { | ||||
|         mList.updateView(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected Boolean doInBackground(Void... voids) { | ||||
|         MagiskManager mm = getMagiskManager(); | ||||
|         if (mm == null) return false; | ||||
|  | ||||
|         File install = new File(Utils.getEncContext(mm).getFilesDir().getParent(), "install"); | ||||
|         getShell().sh_raw("rm -rf " + install); | ||||
|  | ||||
|         List<String> abis = Arrays.asList(Build.SUPPORTED_ABIS); | ||||
|         String arch; | ||||
|         if (abis.contains("x86_64")) arch = "x64"; | ||||
|         else if (abis.contains("arm64-v8a")) arch = "arm64"; | ||||
|         else if (abis.contains("x86")) arch = "x86"; | ||||
|         else arch = "arm"; | ||||
|         mList.add("- Device platform: " + arch); | ||||
|  | ||||
|         try { | ||||
|             // Unzip files | ||||
|             mList.add("- Extracting files"); | ||||
|             try (InputStream in = mm.getContentResolver().openInputStream(mZip)) { | ||||
|                 if (in == null) throw new FileNotFoundException(); | ||||
|                 BufferedInputStream buf = new BufferedInputStream(in); | ||||
|                 buf.mark(Integer.MAX_VALUE); | ||||
|                 ZipUtils.unzip(buf, install, arch + "/", true); | ||||
|                 buf.reset(); | ||||
|                 ZipUtils.unzip(buf, install, "common/", true); | ||||
|                 buf.reset(); | ||||
|                 ZipUtils.unzip(buf, install, "chromeos/", false); | ||||
|                 buf.reset(); | ||||
|                 ZipUtils.unzip(buf, install, "META-INF/com/google/android/update-binary", true); | ||||
|             } catch (FileNotFoundException e) { | ||||
|                 mList.add("! Invalid Uri"); | ||||
|                 throw e; | ||||
|             } catch (Exception e) { | ||||
|                 mList.add("! Cannot unzip zip"); | ||||
|                 throw e; | ||||
|             } | ||||
|  | ||||
|             File boot; | ||||
|             switch (mode) { | ||||
|                 case PATCH_MODE: | ||||
|                     boot = new File(install, "boot.img"); | ||||
|                     // Copy boot image to local | ||||
|                     try ( | ||||
|                         InputStream in = mm.getContentResolver().openInputStream(mBootImg); | ||||
|                         OutputStream out = new FileOutputStream(boot) | ||||
|                     ) { | ||||
|                         InputStream source; | ||||
|                         if (in == null) throw new FileNotFoundException(); | ||||
|  | ||||
|                         if (Utils.getNameFromUri(mm, mBootImg).endsWith(".tar")) { | ||||
|                             // Extract boot.img from tar | ||||
|                             TarInputStream tar = new TarInputStream(new BufferedInputStream(in)); | ||||
|                             org.kamranzafar.jtar.TarEntry entry; | ||||
|                             while ((entry = tar.getNextEntry()) != null) { | ||||
|                                 if (entry.getName().equals("boot.img")) | ||||
|                                     break; | ||||
|                             } | ||||
|                             source = tar; | ||||
|                         } else { | ||||
|                             // Direct copy raw image | ||||
|                             source = new BufferedInputStream(in); | ||||
|                         } | ||||
|                         byte buffer[] = new byte[1024]; | ||||
|                         int length; | ||||
|                         while ((length = source.read(buffer)) > 0) | ||||
|                             out.write(buffer, 0, length); | ||||
|                     } catch (FileNotFoundException e) { | ||||
|                         mList.add("! Invalid Uri"); | ||||
|                         throw e; | ||||
|                     } catch (IOException e) { | ||||
|                         mList.add("! Copy failed"); | ||||
|                         throw e; | ||||
|                     } | ||||
|                     break; | ||||
|                 case DIRECT_MODE: | ||||
|                     boot = new File(mBootLocation); | ||||
|                     break; | ||||
|                 default: | ||||
|                     return false; | ||||
|             } | ||||
|  | ||||
|             mList.add("- Use boot image: " + boot); | ||||
|  | ||||
|             Shell shell; | ||||
|             if (mode == PATCH_MODE && Shell.rootAccess()) { | ||||
|                 // Force non-root shell | ||||
|                 shell = Shell.getShell("sh"); | ||||
|              } else { | ||||
|                 shell = getShell(); | ||||
|             } | ||||
|  | ||||
|             // Patch boot image | ||||
|             shell.sh(mList, | ||||
|                     "cd " + install, | ||||
|                     "KEEPFORCEENCRYPT=" + mKeepEnc + " KEEPVERITY=" + mKeepVerity + " sh " + | ||||
|                             "update-binary indep boot_patch.sh " + boot + | ||||
|                             " && echo 'Success!' || echo 'Failed!'" | ||||
|             ); | ||||
|  | ||||
|             if (!TextUtils.equals(mList.get(mList.size() - 1), "Success!")) | ||||
|                 return false; | ||||
|  | ||||
|             File patched_boot = new File(install, "new-boot.img"); | ||||
|             mList.add(""); | ||||
|             switch (mode) { | ||||
|                 case PATCH_MODE: | ||||
|                     File dest = new File(Environment.getExternalStorageDirectory() + "/MagiskManager/patched_boot" + mm.bootFormat); | ||||
|                     dest.getParentFile().mkdirs(); | ||||
|                     switch (mm.bootFormat) { | ||||
|                         case ".img": | ||||
|                             getShell().sh_raw("cp -f " + patched_boot + " " + dest); | ||||
|                             break; | ||||
|                         case ".img.tar": | ||||
|                             TarOutputStream tar = new TarOutputStream(new BufferedOutputStream(new FileOutputStream(dest))); | ||||
|                             tar.putNextEntry(new TarEntry(patched_boot, "boot.img")); | ||||
|                             byte buffer[] = new byte[4096]; | ||||
|                             BufferedInputStream in = new BufferedInputStream(new FileInputStream(patched_boot)); | ||||
|                             int len; | ||||
|                             while ((len = in.read(buffer)) != -1) { | ||||
|                                 tar.write(buffer, 0, len); | ||||
|                             } | ||||
|                             tar.flush(); | ||||
|                             tar.close(); | ||||
|                             in.close(); | ||||
|                             break; | ||||
|                     } | ||||
|                     mList.add("*********************************"); | ||||
|                     mList.add(" Patched Boot Image is placed in "); | ||||
|                     mList.add(" " + dest + " "); | ||||
|                     mList.add("*********************************"); | ||||
|                     break; | ||||
|                 case DIRECT_MODE: | ||||
|                     // Direct flash boot image | ||||
|                     getShell().su(mList, "flash_boot_image " + patched_boot + " " + mBootLocation); | ||||
|                     break; | ||||
|                 default: | ||||
|                     return false; | ||||
|             } | ||||
|  | ||||
|             // Finals | ||||
|             getShell().sh_raw( | ||||
|                     "cd " + install, | ||||
|                     "mv bin/busybox busybox", | ||||
|                     "rm -rf bin *.img update-binary", | ||||
|                     "cd /"); | ||||
|         } catch (Exception e) { | ||||
|             e.printStackTrace(); | ||||
|             return false; | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onPostExecute(Boolean result) { | ||||
|         super.onPostExecute(result); | ||||
|     } | ||||
| } | ||||
| @@ -1,47 +0,0 @@ | ||||
| package com.topjohnwu.magisk.asyncs; | ||||
|  | ||||
| import android.app.Activity; | ||||
| import android.support.v7.app.AlertDialog; | ||||
| import android.webkit.WebView; | ||||
|  | ||||
| import com.topjohnwu.magisk.R; | ||||
| import com.topjohnwu.magisk.utils.WebService; | ||||
|  | ||||
| import org.commonmark.node.Node; | ||||
| import org.commonmark.parser.Parser; | ||||
| import org.commonmark.renderer.html.HtmlRenderer; | ||||
|  | ||||
| public class MarkDownWindow extends ParallelTask<Void, Void, String> { | ||||
|  | ||||
|     private String mTitle, mUrl; | ||||
|  | ||||
|     public MarkDownWindow(Activity context, String title, String url) { | ||||
|         super(context); | ||||
|         mTitle = title; | ||||
|         mUrl = url; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected String doInBackground(Void... voids) { | ||||
|         String md = WebService.getString(mUrl); | ||||
|         Parser parser = Parser.builder().build(); | ||||
|         HtmlRenderer renderer = HtmlRenderer.builder().build(); | ||||
|         Node doc = parser.parse(md); | ||||
|         return String.format( | ||||
|                 "<link rel='stylesheet' type='text/css' href='file:///android_asset/%s.css'/> %s", | ||||
|                 getMagiskManager().isDarkTheme ? "dark" : "light", renderer.render(doc)); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onPostExecute(String html) { | ||||
|         AlertDialog.Builder alert = new AlertDialog.Builder(getActivity()); | ||||
|         alert.setTitle(mTitle); | ||||
|  | ||||
|         WebView wv = new WebView(getActivity()); | ||||
|         wv.loadDataWithBaseURL("fake://", html, "text/html", "UTF-8", null); | ||||
|  | ||||
|         alert.setView(wv); | ||||
|         alert.setNegativeButton(R.string.close, (dialog, id) -> dialog.dismiss()); | ||||
|         alert.show(); | ||||
|     } | ||||
| } | ||||
| @@ -1,40 +0,0 @@ | ||||
| package com.topjohnwu.magisk.asyncs; | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.widget.Toast; | ||||
|  | ||||
| import com.topjohnwu.magisk.R; | ||||
| import com.topjohnwu.magisk.utils.Utils; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| public class RestoreStockBoot extends ParallelTask<Void, Void, Boolean> { | ||||
|  | ||||
|     private String mBoot; | ||||
|  | ||||
|     public RestoreStockBoot(Context context, String boot) { | ||||
|         super(context); | ||||
|         mBoot = boot; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected Boolean doInBackground(Void... voids) { | ||||
|         List<String> ret = getShell().su("cat /init.magisk.rc | grep STOCKSHA1"); | ||||
|         if (!Utils.isValidShellResponse(ret)) | ||||
|             return false; | ||||
|         String stock_boot = "/data/stock_boot_" + ret.get(0).substring(ret.get(0).indexOf('=') + 1) + ".img.gz"; | ||||
|         if (!Utils.itemExist(getShell(), stock_boot)) | ||||
|             return false; | ||||
|         getShell().su_raw("flash_boot_image " + stock_boot + " " + mBoot); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onPostExecute(Boolean result) { | ||||
|         if (result) { | ||||
|             getMagiskManager().toast(R.string.restore_done, Toast.LENGTH_SHORT); | ||||
|         } else { | ||||
|             getMagiskManager().toast(R.string.restore_fail, Toast.LENGTH_LONG); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,79 +0,0 @@ | ||||
| package com.topjohnwu.magisk.components; | ||||
|  | ||||
| import android.content.pm.PackageManager; | ||||
| import android.content.res.Configuration; | ||||
| import android.os.Bundle; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.support.annotation.Nullable; | ||||
| import android.support.v7.app.AppCompatActivity; | ||||
| import android.view.WindowManager; | ||||
|  | ||||
| import com.topjohnwu.magisk.MagiskManager; | ||||
| import com.topjohnwu.magisk.R; | ||||
| import com.topjohnwu.magisk.utils.Shell; | ||||
| import com.topjohnwu.magisk.utils.Topic; | ||||
|  | ||||
| public class Activity extends AppCompatActivity { | ||||
|  | ||||
|     private Runnable permissionGrantCallback; | ||||
|  | ||||
|     public Activity() { | ||||
|         super(); | ||||
|         Configuration configuration = new Configuration(); | ||||
|         configuration.setLocale(MagiskManager.locale); | ||||
|         applyOverrideConfiguration(configuration); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(@Nullable Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         if (this instanceof Topic.Subscriber) { | ||||
|             ((Topic.Subscriber) this).subscribeTopics(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onDestroy() { | ||||
|         if (this instanceof Topic.Subscriber) { | ||||
|             ((Topic.Subscriber) this).unsubscribeTopics(); | ||||
|         } | ||||
|         super.onDestroy(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { | ||||
|         if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { | ||||
|             if (permissionGrantCallback != null) { | ||||
|                 permissionGrantCallback.run(); | ||||
|             } | ||||
|         } | ||||
|         permissionGrantCallback = null; | ||||
|     } | ||||
|  | ||||
|     public void setPermissionGrantCallback(Runnable callback) { | ||||
|         permissionGrantCallback = callback; | ||||
|     } | ||||
|  | ||||
|     public MagiskManager getMagiskManager() { | ||||
|         return (MagiskManager) super.getApplicationContext(); | ||||
|     } | ||||
|  | ||||
|     public Shell getShell() { | ||||
|         return Shell.getShell(this); | ||||
|     } | ||||
|  | ||||
|     protected void setFloating() { | ||||
|         boolean isTablet = getResources().getBoolean(R.bool.isTablet); | ||||
|         if (isTablet) { | ||||
|             WindowManager.LayoutParams params = getWindow().getAttributes(); | ||||
|             params.height = getResources().getDimensionPixelSize(R.dimen.floating_height); | ||||
|             params.width = getResources().getDimensionPixelSize(R.dimen.floating_width); | ||||
|             params.alpha = 1.0f; | ||||
|             params.dimAmount = 0.6f; | ||||
|             params.flags |= 2; | ||||
|             getWindow().setAttributes(params); | ||||
|             setFinishOnTouchOutside(true); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,36 +0,0 @@ | ||||
| package com.topjohnwu.magisk.container; | ||||
|  | ||||
| import android.support.v7.widget.RecyclerView; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
|  | ||||
| public class AdaptiveList<E> extends ArrayList<E> { | ||||
|  | ||||
|     private Runnable callback; | ||||
|     private RecyclerView mView; | ||||
|  | ||||
|     public AdaptiveList(RecyclerView v) { | ||||
|         mView = v; | ||||
|     } | ||||
|  | ||||
|     public void updateView() { | ||||
|         mView.getAdapter().notifyDataSetChanged(); | ||||
|         mView.scrollToPosition(mView.getAdapter().getItemCount() - 1); | ||||
|     } | ||||
|  | ||||
|     public void setCallback(Runnable cb) { | ||||
|         callback = cb; | ||||
|     } | ||||
|  | ||||
|     public boolean add(E e) { | ||||
|         boolean ret = super.add(e); | ||||
|         if (ret) { | ||||
|             if (callback == null) { | ||||
|                 updateView(); | ||||
|             } else { | ||||
|                 callback.run(); | ||||
|             } | ||||
|         } | ||||
|         return ret; | ||||
|     } | ||||
| } | ||||
| @@ -1,59 +0,0 @@ | ||||
| package com.topjohnwu.magisk.container; | ||||
|  | ||||
| import android.support.annotation.NonNull; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
|  | ||||
| public class InputStreamWrapper extends InputStream { | ||||
|     private InputStream in; | ||||
|  | ||||
|     public InputStreamWrapper(InputStream in) { | ||||
|         this.in = in; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int available() throws IOException { | ||||
|         return in.available(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void close() throws IOException { | ||||
|         in.close(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public synchronized void mark(int readlimit) { | ||||
|         in.mark(readlimit); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean markSupported() { | ||||
|         return in.markSupported(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public synchronized int read() throws IOException { | ||||
|         return in.read(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int read(@NonNull byte[] b) throws IOException { | ||||
|         return read(b, 0, b.length); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public synchronized int read(@NonNull byte[] b, int off, int len) throws IOException { | ||||
|         return in.read(b, off, len); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public synchronized void reset() throws IOException { | ||||
|         in.reset(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public long skip(long n) throws IOException { | ||||
|         return in.skip(n); | ||||
|     } | ||||
| } | ||||
| @@ -1,67 +0,0 @@ | ||||
| package com.topjohnwu.magisk.container; | ||||
|  | ||||
| import com.topjohnwu.magisk.utils.Shell; | ||||
| import com.topjohnwu.magisk.utils.Utils; | ||||
|  | ||||
| public class Module extends BaseModule { | ||||
|  | ||||
|     private String mRemoveFile, mDisableFile, mUpdateFile; | ||||
|     private boolean mEnable, mRemove, mUpdated; | ||||
|  | ||||
|     public Module(Shell shell, String path) { | ||||
|  | ||||
|         try { | ||||
|             parseProps(Utils.readFile(shell, path + "/module.prop")); | ||||
|         } catch (NumberFormatException ignored) {} | ||||
|  | ||||
|         mRemoveFile = path + "/remove"; | ||||
|         mDisableFile = path + "/disable"; | ||||
|         mUpdateFile = path + "/update"; | ||||
|  | ||||
|         if (getId() == null) { | ||||
|             int sep = path.lastIndexOf('/'); | ||||
|             setId(path.substring(sep + 1)); | ||||
|         } | ||||
|  | ||||
|         if (getName() == null) { | ||||
|             setName(getId()); | ||||
|         } | ||||
|  | ||||
|         mEnable = !Utils.itemExist(shell, mDisableFile); | ||||
|         mRemove = Utils.itemExist(shell, mRemoveFile); | ||||
|         mUpdated = Utils.itemExist(shell, mUpdateFile); | ||||
|     } | ||||
|  | ||||
|     public void createDisableFile(Shell shell) { | ||||
|         mEnable = false; | ||||
|         Utils.createFile(shell, mDisableFile); | ||||
|     } | ||||
|  | ||||
|     public void removeDisableFile(Shell shell) { | ||||
|         mEnable = true; | ||||
|         Utils.removeItem(shell, mDisableFile); | ||||
|     } | ||||
|  | ||||
|     public boolean isEnabled() { | ||||
|         return mEnable; | ||||
|     } | ||||
|  | ||||
|     public void createRemoveFile(Shell shell) { | ||||
|         mRemove = true; | ||||
|         Utils.createFile(shell, mRemoveFile); | ||||
|     } | ||||
|  | ||||
|     public void deleteRemoveFile(Shell shell) { | ||||
|         mRemove = false; | ||||
|         Utils.removeItem(shell, mRemoveFile); | ||||
|     } | ||||
|  | ||||
|     public boolean willBeRemoved() { | ||||
|         return mRemove; | ||||
|     } | ||||
|  | ||||
|     public boolean isUpdated() { | ||||
|         return mUpdated; | ||||
|     } | ||||
|  | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,40 +0,0 @@ | ||||
| package com.topjohnwu.magisk.receivers; | ||||
|  | ||||
| import android.content.BroadcastReceiver; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
|  | ||||
| import com.topjohnwu.magisk.MagiskManager; | ||||
| import com.topjohnwu.magisk.container.Policy; | ||||
| import com.topjohnwu.magisk.utils.Utils; | ||||
|  | ||||
| public class PackageReceiver extends BroadcastReceiver { | ||||
|     @Override | ||||
|     public void onReceive(Context context, Intent intent) { | ||||
|         MagiskManager magiskManager = Utils.getMagiskManager(context); | ||||
|  | ||||
|         String pkg = intent.getData().getEncodedSchemeSpecificPart(); | ||||
|         Policy policy = magiskManager.suDB.getPolicy(pkg); | ||||
|         if (policy == null) | ||||
|             return; | ||||
|  | ||||
|         switch (intent.getAction()) { | ||||
|             case Intent.ACTION_PACKAGE_REPLACED: | ||||
|                 // This will only work pre-O | ||||
|                 if (magiskManager.suReauth) { | ||||
|                     magiskManager.suDB.deletePolicy(policy); | ||||
|                 } else { | ||||
|                     int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); | ||||
|                     // Update the UID if available | ||||
|                     if (uid > 0) { | ||||
|                         policy.uid = uid % 100000; | ||||
|                     } | ||||
|                     magiskManager.suDB.updatePolicy(policy); | ||||
|                 } | ||||
|                 break; | ||||
|             case Intent.ACTION_PACKAGE_FULLY_REMOVED: | ||||
|                 magiskManager.suDB.deletePolicy(policy); | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,34 +0,0 @@ | ||||
| package com.topjohnwu.magisk.services; | ||||
|  | ||||
| import android.app.IntentService; | ||||
| import android.content.Intent; | ||||
| import android.os.Build; | ||||
| import android.support.v7.app.NotificationCompat; | ||||
|  | ||||
| import com.topjohnwu.magisk.R; | ||||
|  | ||||
| public class OnBootIntentService extends IntentService { | ||||
|  | ||||
|     private static final int ONBOOT_NOTIFICATION_ID = 3; | ||||
|  | ||||
|     public OnBootIntentService() { | ||||
|         super("OnBootIntentService"); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | ||||
|             NotificationCompat.Builder builder = new NotificationCompat.Builder(this); | ||||
|             builder.setSmallIcon(R.drawable.ic_magisk) | ||||
|                     .setContentTitle("onBoot") | ||||
|                     .setContentText("Running onBoot operations..."); | ||||
|             startForeground(ONBOOT_NOTIFICATION_ID, builder.build()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onHandleIntent(Intent intent) { | ||||
|         // Currently nothing to do | ||||
|     } | ||||
| } | ||||
| @@ -1,24 +0,0 @@ | ||||
| package com.topjohnwu.magisk.superuser; | ||||
|  | ||||
| import android.content.Intent; | ||||
| import android.os.Bundle; | ||||
|  | ||||
| import com.topjohnwu.magisk.components.Activity; | ||||
|  | ||||
| public class RequestActivity extends Activity { | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|  | ||||
|         Intent intent = getIntent(); | ||||
|         if (intent == null) { | ||||
|             finish(); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK).setClass(this, SuRequestActivity.class); | ||||
|         startActivity(intent); | ||||
|         finish(); | ||||
|     } | ||||
| } | ||||
| @@ -1,225 +0,0 @@ | ||||
| package com.topjohnwu.magisk.utils; | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.text.TextUtils; | ||||
|  | ||||
| import com.topjohnwu.magisk.MagiskManager; | ||||
|  | ||||
| import java.io.BufferedReader; | ||||
| import java.io.DataInputStream; | ||||
| import java.io.DataOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.InputStreamReader; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collection; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * Modified by topjohnwu, based on Chainfire's libsuperuser | ||||
|  */ | ||||
|  | ||||
| public class Shell { | ||||
|  | ||||
|     // -1 = problematic/unknown issue; 0 = not rooted; 1 = properly rooted | ||||
|     public static int rootStatus; | ||||
|  | ||||
|     private final Process shellProcess; | ||||
|     private final DataOutputStream STDIN; | ||||
|     private final DataInputStream STDOUT; | ||||
|  | ||||
|     private boolean isValid; | ||||
|  | ||||
|     private void testRootShell(DataOutputStream in, DataInputStream out) throws IOException { | ||||
|         in.write(("id\n").getBytes("UTF-8")); | ||||
|         in.flush(); | ||||
|         String s = new BufferedReader(new InputStreamReader(out)).readLine(); | ||||
|         if (TextUtils.isEmpty(s) || !s.contains("uid=0")) { | ||||
|             in.close(); | ||||
|             out.close(); | ||||
|             throw new IOException(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private Shell() { | ||||
|         rootStatus = 1; | ||||
|         Process process = null; | ||||
|         DataOutputStream in = null; | ||||
|         DataInputStream out = null; | ||||
|  | ||||
|         try { | ||||
|             // Try getting global namespace | ||||
|             process = Runtime.getRuntime().exec("su --mount-master"); | ||||
|             in = new DataOutputStream(process.getOutputStream()); | ||||
|             out = new DataInputStream(process.getInputStream()); | ||||
|             testRootShell(in, out); | ||||
|         } catch (IOException e) { | ||||
|             // Feature not implemented, normal root shell | ||||
|             try { | ||||
|                 process = Runtime.getRuntime().exec("su"); | ||||
|                 in = new DataOutputStream(process.getOutputStream()); | ||||
|                 out = new DataInputStream(process.getInputStream()); | ||||
|                 testRootShell(in, out); | ||||
|             } catch (IOException e1) { | ||||
|                 rootStatus = 0; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (!rootAccess()) { | ||||
|             // Try to gain non-root sh | ||||
|             try { | ||||
|                 process = Runtime.getRuntime().exec("sh"); | ||||
|                 in = new DataOutputStream(process.getOutputStream()); | ||||
|                 out = new DataInputStream(process.getInputStream()); | ||||
|             } catch (IOException e) { | ||||
|                 // Nothing works.... | ||||
|                 shellProcess = null; | ||||
|                 STDIN = null; | ||||
|                 STDOUT = null; | ||||
|                 isValid = false; | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         isValid = true; | ||||
|         shellProcess = process; | ||||
|         STDIN = in; | ||||
|         STDOUT = out; | ||||
|         sh_raw("umask 022"); | ||||
|     } | ||||
|  | ||||
|     private Shell(String command) { | ||||
|         Process process; | ||||
|         DataOutputStream in; | ||||
|         DataInputStream out; | ||||
|  | ||||
|         try { | ||||
|             process = Runtime.getRuntime().exec(command); | ||||
|             in = new DataOutputStream(process.getOutputStream()); | ||||
|             out = new DataInputStream(process.getInputStream()); | ||||
|         } catch (IOException e) { | ||||
|             // Nothing works.... | ||||
|             shellProcess = null; | ||||
|             STDIN = null; | ||||
|             STDOUT = null; | ||||
|             isValid = false; | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         isValid = true; | ||||
|         shellProcess = process; | ||||
|         STDIN = in; | ||||
|         STDOUT = out; | ||||
|     } | ||||
|  | ||||
|     public static Shell getShell() { | ||||
|         return new Shell(); | ||||
|     } | ||||
|  | ||||
|     public static Shell getShell(String command) { | ||||
|         return new Shell(command); | ||||
|     } | ||||
|  | ||||
|     public static Shell getShell(Context context) { | ||||
|         MagiskManager magiskManager = Utils.getMagiskManager(context); | ||||
|         if (magiskManager.shell == null || !magiskManager.shell.isValid) { | ||||
|             // Get new shell if needed | ||||
|             magiskManager.shell = getShell(); | ||||
|         } | ||||
|         return magiskManager.shell; | ||||
|     } | ||||
|  | ||||
|     public static boolean rootAccess() { | ||||
|         return rootStatus > 0; | ||||
|     } | ||||
|  | ||||
|     public void loadInputStream(InputStream in) { | ||||
|         try { | ||||
|             int read; | ||||
|             byte[] bytes = new byte[4096]; | ||||
|             while ((read = in.read(bytes)) != -1) { | ||||
|                 STDIN.write(bytes, 0, read); | ||||
|             } | ||||
|             STDIN.flush(); | ||||
|         } catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public List<String> sh(String... commands) { | ||||
|         List<String> res = new ArrayList<>(); | ||||
|         if (!isValid) return res; | ||||
|         sh(res, commands); | ||||
|         return res; | ||||
|     } | ||||
|  | ||||
|     public void sh_raw(String... commands) { | ||||
|         sh_raw(false, commands); | ||||
|     } | ||||
|  | ||||
|     public void sh_raw(boolean stdout, String... commands) { | ||||
|         if (!isValid) return; | ||||
|         synchronized (shellProcess) { | ||||
|             try { | ||||
|                 for (String command : commands) { | ||||
|                     Logger.shell(command); | ||||
|                     STDIN.write((command + (stdout ? "\n" : " >/dev/null\n")).getBytes("UTF-8")); | ||||
|                     STDIN.flush(); | ||||
|                 } | ||||
|             } catch (IOException e) { | ||||
|                 e.printStackTrace(); | ||||
|                 shellProcess.destroy(); | ||||
|                 isValid = false; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void sh(Collection<String> output, String... commands) { | ||||
|         if (!isValid) return; | ||||
|         try { | ||||
|             shellProcess.exitValue(); | ||||
|             isValid = false; | ||||
|             return;  // The process is dead, return | ||||
|         } catch (IllegalThreadStateException ignored) { | ||||
|             // This should be the expected result | ||||
|         } | ||||
|         synchronized (shellProcess) { | ||||
|             StreamGobbler out = new StreamGobbler(STDOUT, output); | ||||
|             out.start(); | ||||
|             sh_raw(true, commands); | ||||
|             sh_raw(true, "echo \'-shell-done-\'"); | ||||
|             try { out.join(); } catch (InterruptedException ignored) {} | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public List<String> su(String... commands) { | ||||
|         if (!rootAccess()) return sh(); | ||||
|         return sh(commands); | ||||
|     } | ||||
|  | ||||
|     public void su_raw(String... commands) { | ||||
|         if (!rootAccess()) return; | ||||
|         sh_raw(commands); | ||||
|     } | ||||
|  | ||||
|     public void su(Collection<String> output, String... commands) { | ||||
|         if (!rootAccess()) return; | ||||
|         sh(output, commands); | ||||
|     } | ||||
|  | ||||
|     public static abstract class AbstractList<E> extends java.util.AbstractList<E> { | ||||
|  | ||||
|         @Override | ||||
|         public abstract boolean add(E e); | ||||
|  | ||||
|         @Override | ||||
|         public E get(int i) { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public int size() { | ||||
|             return 0; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,62 +0,0 @@ | ||||
| package com.topjohnwu.magisk.utils; | ||||
|  | ||||
| import android.text.TextUtils; | ||||
|  | ||||
| import java.io.BufferedReader; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.InputStreamReader; | ||||
| import java.util.Collection; | ||||
|  | ||||
| /** | ||||
|  * Modified by topjohnwu, based on Chainfire's libsuperuser | ||||
|  */ | ||||
|  | ||||
| public class StreamGobbler extends Thread { | ||||
|  | ||||
|     private BufferedReader reader = null; | ||||
|     private Collection<String> writer = null; | ||||
|  | ||||
|     /** | ||||
|      * <p>StreamGobbler constructor</p> | ||||
|      * | ||||
|      * <p>We use this class because sh STDOUT and STDERR should be read as quickly as | ||||
|      * possible to prevent a deadlock from occurring, or Process.waitFor() never | ||||
|      * returning (as the buffer is full, pausing the native process)</p> | ||||
|      * | ||||
|      * @param inputStream InputStream to read from | ||||
|      * @param outputList  {@literal List<String>} to write to, or null | ||||
|      */ | ||||
|     public StreamGobbler(InputStream inputStream, Collection<String> outputList) { | ||||
|         try { | ||||
|             while (inputStream.available() != 0) { | ||||
|                 inputStream.skip(inputStream.available()); | ||||
|             } | ||||
|         } catch (IOException ignored) {} | ||||
|         reader = new BufferedReader(new InputStreamReader(inputStream)); | ||||
|         writer = outputList; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void run() { | ||||
|         // keep reading the InputStream until it ends (or an error occurs) | ||||
|         try { | ||||
|             String line; | ||||
|             while ((line = reader.readLine()) != null) { | ||||
|                 if (TextUtils.equals(line, "-shell-done-")) | ||||
|                     return; | ||||
|                 writer.add(line); | ||||
|                 Logger.shell(line); | ||||
|             } | ||||
|         } catch (IOException e) { | ||||
|             // reader probably closed, expected exit condition | ||||
|         } | ||||
|  | ||||
|         // make sure our stream is closed and resources will be freed | ||||
|         try { | ||||
|             reader.close(); | ||||
|         } catch (IOException e) { | ||||
|             // read already closed | ||||
|         } | ||||
|     } | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,80 +0,0 @@ | ||||
| package com.topjohnwu.magisk.utils; | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.content.res.AssetManager; | ||||
|  | ||||
| import com.topjohnwu.jarsigner.JarMap; | ||||
| import com.topjohnwu.jarsigner.SignAPK; | ||||
|  | ||||
| import java.io.BufferedInputStream; | ||||
| import java.io.File; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.InputStream; | ||||
| import java.util.jar.JarEntry; | ||||
| import java.util.jar.JarInputStream; | ||||
|  | ||||
| public class ZipUtils { | ||||
|     // File name in assets | ||||
|     private static final String PUBLIC_KEY_NAME = "public.certificate.x509.pem"; | ||||
|     private static final String PRIVATE_KEY_NAME = "private.key.pk8"; | ||||
|  | ||||
|     static { | ||||
|         System.loadLibrary("zipadjust"); | ||||
|     } | ||||
|  | ||||
|     public native static void zipAdjust(String filenameIn, String filenameOut); | ||||
|  | ||||
|     public static void unzip(File zip, File folder, String path, boolean junkPath) throws Exception { | ||||
|         InputStream in = new BufferedInputStream(new FileInputStream(zip)); | ||||
|         unzip(in, folder, path, junkPath); | ||||
|         in.close(); | ||||
|     } | ||||
|  | ||||
|     public static void unzip(InputStream zip, File folder, String path, boolean junkPath) throws Exception { | ||||
|         byte data[] = new byte[4096]; | ||||
|         try { | ||||
|             JarInputStream zipfile = new JarInputStream(zip); | ||||
|             JarEntry entry; | ||||
|             while ((entry = zipfile.getNextJarEntry()) != null) { | ||||
|                 if (!entry.getName().startsWith(path) || entry.isDirectory()){ | ||||
|                     // Ignore directories, only create files | ||||
|                     continue; | ||||
|                 } | ||||
|                 String name; | ||||
|                 if (junkPath) { | ||||
|                     name = entry.getName().substring(entry.getName().lastIndexOf('/') + 1); | ||||
|                 } else { | ||||
|                     name = entry.getName(); | ||||
|                 } | ||||
|                 File dest = new File(folder, name); | ||||
|                 dest.getParentFile().mkdirs(); | ||||
|                 FileOutputStream out = new FileOutputStream(dest); | ||||
|                 int count; | ||||
|                 while ((count = zipfile.read(data)) != -1) { | ||||
|                     out.write(data, 0, count); | ||||
|                 } | ||||
|                 out.flush(); | ||||
|                 out.close(); | ||||
|             } | ||||
|         } catch(Exception e) { | ||||
|             e.printStackTrace(); | ||||
|             throw e; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static void signZip(Context context, InputStream is, File output, boolean minSign) throws Exception { | ||||
|         signZip(context, new JarMap(is, false), output, minSign); | ||||
|     } | ||||
|  | ||||
|     public static void signZip(Context context, File input, File output, boolean minSign) throws Exception { | ||||
|         signZip(context, new JarMap(input, false), output, minSign); | ||||
|     } | ||||
|  | ||||
|     public static void signZip(Context context, JarMap input, File output, boolean minSign) throws Exception { | ||||
|         AssetManager assets = context.getAssets(); | ||||
|         SignAPK.signZip( | ||||
|                 assets.open(PUBLIC_KEY_NAME), assets.open(PRIVATE_KEY_NAME), | ||||
|                 input, output, minSign); | ||||
|     } | ||||
| } | ||||
| @@ -1,7 +0,0 @@ | ||||
| cmake_minimum_required(VERSION 3.6) | ||||
| add_library(zipadjust SHARED | ||||
|                 jni_glue.c | ||||
|                 zipadjust.c) | ||||
| find_library(libz z) | ||||
| find_library(liblog log) | ||||
| target_link_libraries(zipadjust ${libz} ${liblog}) | ||||
| @@ -1,19 +0,0 @@ | ||||
| // | ||||
| // Java entry point | ||||
| // | ||||
|  | ||||
| #include <jni.h> | ||||
| #include "zipadjust.h" | ||||
|  | ||||
| JNIEXPORT void JNICALL | ||||
| Java_com_topjohnwu_magisk_utils_ZipUtils_zipAdjust(JNIEnv *env, jclass type, jstring filenameIn_, | ||||
|                                                     jstring filenameOut_) { | ||||
|     const char *filenameIn = (*env)->GetStringUTFChars(env, filenameIn_, 0); | ||||
|     const char *filenameOut = (*env)->GetStringUTFChars(env, filenameOut_, 0); | ||||
|  | ||||
|     // TODO | ||||
|     zipadjust(filenameIn, filenameOut, 0); | ||||
|  | ||||
|     (*env)->ReleaseStringUTFChars(env, filenameIn_, filenameIn); | ||||
|     (*env)->ReleaseStringUTFChars(env, filenameOut_, filenameOut); | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,13 +0,0 @@ | ||||
| #ifndef MAGISKMANAGER_ZIPADJUST_H_H | ||||
| #define MAGISKMANAGER_ZIPADJUST_H_H | ||||
|  | ||||
| #include <android/log.h> | ||||
|  | ||||
| int zipadjust(const char* filenameIn, const char* filenameOut, int decompress); | ||||
|  | ||||
| #define  LOG_TAG    "zipadjust" | ||||
|  | ||||
| #define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) | ||||
| #define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) | ||||
|  | ||||
| #endif //MAGISKMANAGER_ZIPADJUST_H_H | ||||
| @@ -1,86 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
|  | ||||
| <android.support.v7.widget.CardView | ||||
|     xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:card_view="http://schemas.android.com/apk/res-auto" | ||||
|     android:layout_width="fill_parent" | ||||
|     android:layout_height="wrap_content" | ||||
|     android:layout_gravity="center" | ||||
|     android:layout_marginBottom="@dimen/card_vertical_margin" | ||||
|     android:layout_marginEnd="@dimen/card_horizontal_margin" | ||||
|     android:layout_marginStart="@dimen/card_horizontal_margin" | ||||
|     android:layout_marginTop="@dimen/card_vertical_margin" | ||||
|     style="?attr/cardStyle" | ||||
|     android:minHeight="?android:attr/listPreferredItemHeight" | ||||
|     card_view:cardCornerRadius="@dimen/card_corner_radius" | ||||
|     card_view:cardElevation="@dimen/card_elevation"> | ||||
|  | ||||
|     <RelativeLayout | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="fill_parent" | ||||
|         android:layout_gravity="center_vertical" | ||||
|         android:padding="@dimen/card_layout_padding"> | ||||
|  | ||||
|         <ImageView | ||||
|             android:id="@+id/app_icon" | ||||
|             android:layout_width="@dimen/card_appicon_size" | ||||
|             android:layout_height="@dimen/card_appicon_size" | ||||
|             android:layout_centerVertical="true" | ||||
|             android:scaleType="centerCrop"/> | ||||
|  | ||||
|         <LinearLayout | ||||
|             android:layout_width="fill_parent" | ||||
|             android:layout_height="fill_parent" | ||||
|             android:layout_alignBottom="@+id/app_icon" | ||||
|             android:gravity="center_horizontal" | ||||
|             android:orientation="vertical" | ||||
|             android:paddingEnd="@dimen/card_appicon_size" | ||||
|             android:paddingStart="65dp" | ||||
|             android:weightSum="1"> | ||||
|  | ||||
|  | ||||
|             <TextView | ||||
|                 android:id="@+id/app_name" | ||||
|                 android:layout_width="fill_parent" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:layout_weight="1" | ||||
|                 android:maxLines="1" | ||||
|                 android:paddingEnd="3dp" | ||||
|                 android:paddingStart="3dp" | ||||
|                 android:textStyle="bold"/> | ||||
|  | ||||
|             <TextView | ||||
|                 android:id="@+id/app_package" | ||||
|                 android:layout_width="fill_parent" | ||||
|                 android:layout_height="25dp" | ||||
|                 android:ellipsize="marquee" | ||||
|                 android:gravity="center_vertical" | ||||
|                 android:marqueeRepeatLimit="marquee_forever" | ||||
|                 android:paddingEnd="3dp" | ||||
|                 android:paddingStart="3dp" | ||||
|                 android:singleLine="true"/> | ||||
|         </LinearLayout> | ||||
|  | ||||
|         <LinearLayout | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_alignParentEnd="true" | ||||
|             android:layout_centerVertical="true"> | ||||
|  | ||||
|             <CheckBox | ||||
|                 android:id="@+id/checkbox" | ||||
|                 android:layout_width="wrap_content" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:focusable="false" | ||||
|                 android:gravity="center" | ||||
|                 android:src="@drawable/ic_menu_overflow_material" | ||||
|                 android:checked="false" /> | ||||
|  | ||||
|         </LinearLayout> | ||||
|  | ||||
|     </RelativeLayout> | ||||
|  | ||||
|  | ||||
| </android.support.v7.widget.CardView> | ||||
|  | ||||
|  | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user